1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2022 NVIDIA Corporation & Affiliates 3 */ 4 5 #include "mlx5dr_internal.h" 6 7 static bool mlx5dr_matcher_requires_col_tbl(uint8_t log_num_of_rules) 8 { 9 /* Collision table concatenation is done only for large rule tables */ 10 return log_num_of_rules > MLX5DR_MATCHER_ASSURED_RULES_TH; 11 } 12 13 static uint8_t mlx5dr_matcher_rules_to_tbl_depth(uint8_t log_num_of_rules) 14 { 15 if (mlx5dr_matcher_requires_col_tbl(log_num_of_rules)) 16 return MLX5DR_MATCHER_ASSURED_MAIN_TBL_DEPTH; 17 18 /* For small rule tables we use a single deep table to assure insertion */ 19 return RTE_MIN(log_num_of_rules, MLX5DR_MATCHER_ASSURED_COL_TBL_DEPTH); 20 } 21 22 static int mlx5dr_matcher_create_end_ft(struct mlx5dr_matcher *matcher) 23 { 24 struct mlx5dr_table *tbl = matcher->tbl; 25 26 matcher->end_ft = mlx5dr_table_create_default_ft(tbl); 27 if (!matcher->end_ft) { 28 DR_LOG(ERR, "Failed to create matcher end flow table"); 29 return rte_errno; 30 } 31 return 0; 32 } 33 34 static void mlx5dr_matcher_destroy_end_ft(struct mlx5dr_matcher *matcher) 35 { 36 mlx5dr_table_destroy_default_ft(matcher->tbl, matcher->end_ft); 37 } 38 39 static int mlx5dr_matcher_connect(struct mlx5dr_matcher *matcher) 40 { 41 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 42 struct mlx5dr_table *tbl = matcher->tbl; 43 struct mlx5dr_matcher *prev = NULL; 44 struct mlx5dr_matcher *next = NULL; 45 struct mlx5dr_matcher *tmp_matcher; 46 struct mlx5dr_devx_obj *ft; 47 int ret; 48 49 /* Find location in matcher list */ 50 if (LIST_EMPTY(&tbl->head)) { 51 LIST_INSERT_HEAD(&tbl->head, matcher, next); 52 goto connect; 53 } 54 55 LIST_FOREACH(tmp_matcher, &tbl->head, next) { 56 if (tmp_matcher->attr.priority > matcher->attr.priority) { 57 next = tmp_matcher; 58 break; 59 } 60 prev = tmp_matcher; 61 } 62 63 if (next) 64 LIST_INSERT_BEFORE(next, matcher, next); 65 else 66 LIST_INSERT_AFTER(prev, matcher, next); 67 68 connect: 69 ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID; 70 ft_attr.type = tbl->fw_ft_type; 71 72 /* Connect to next */ 73 if (next) { 74 if (next->match_ste.rtc_0) 75 ft_attr.rtc_id_0 = next->match_ste.rtc_0->id; 76 if (next->match_ste.rtc_1) 77 ft_attr.rtc_id_1 = next->match_ste.rtc_1->id; 78 79 ret = mlx5dr_cmd_flow_table_modify(matcher->end_ft, &ft_attr); 80 if (ret) { 81 DR_LOG(ERR, "Failed to connect new matcher to next RTC"); 82 goto remove_from_list; 83 } 84 } 85 86 /* Connect to previous */ 87 ft = prev ? prev->end_ft : tbl->ft; 88 89 if (matcher->match_ste.rtc_0) 90 ft_attr.rtc_id_0 = matcher->match_ste.rtc_0->id; 91 if (matcher->match_ste.rtc_1) 92 ft_attr.rtc_id_1 = matcher->match_ste.rtc_1->id; 93 94 ret = mlx5dr_cmd_flow_table_modify(ft, &ft_attr); 95 if (ret) { 96 DR_LOG(ERR, "Failed to connect new matcher to previous FT"); 97 goto remove_from_list; 98 } 99 100 return 0; 101 102 remove_from_list: 103 LIST_REMOVE(matcher, next); 104 return ret; 105 } 106 107 static int mlx5dr_matcher_disconnect(struct mlx5dr_matcher *matcher) 108 { 109 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 110 struct mlx5dr_table *tbl = matcher->tbl; 111 struct mlx5dr_matcher *tmp_matcher; 112 struct mlx5dr_devx_obj *prev_ft; 113 struct mlx5dr_matcher *next; 114 int ret; 115 116 prev_ft = matcher->tbl->ft; 117 LIST_FOREACH(tmp_matcher, &tbl->head, next) { 118 if (tmp_matcher == matcher) 119 break; 120 121 prev_ft = tmp_matcher->end_ft; 122 } 123 124 next = matcher->next.le_next; 125 126 ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID; 127 ft_attr.type = matcher->tbl->fw_ft_type; 128 129 if (next) { 130 /* Connect previous end FT to next RTC if exists */ 131 if (next->match_ste.rtc_0) 132 ft_attr.rtc_id_0 = next->match_ste.rtc_0->id; 133 if (next->match_ste.rtc_1) 134 ft_attr.rtc_id_1 = next->match_ste.rtc_1->id; 135 } else { 136 /* Matcher is last, point prev end FT to default miss */ 137 mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx, 138 tbl->fw_ft_type, 139 tbl->type, 140 &ft_attr); 141 } 142 143 ret = mlx5dr_cmd_flow_table_modify(prev_ft, &ft_attr); 144 if (ret) { 145 DR_LOG(ERR, "Failed to disconnect matcher"); 146 return ret; 147 } 148 149 LIST_REMOVE(matcher, next); 150 151 return 0; 152 } 153 154 static void mlx5dr_matcher_set_rtc_attr_sz(struct mlx5dr_matcher *matcher, 155 struct mlx5dr_cmd_rtc_create_attr *rtc_attr, 156 bool is_match_rtc, 157 bool is_mirror) 158 { 159 enum mlx5dr_matcher_flow_src flow_src = matcher->attr.optimize_flow_src; 160 struct mlx5dr_pool_chunk *ste = &matcher->action_ste.ste; 161 162 if ((flow_src == MLX5DR_MATCHER_FLOW_SRC_VPORT && !is_mirror) || 163 (flow_src == MLX5DR_MATCHER_FLOW_SRC_WIRE && is_mirror)) { 164 /* Optimize FDB RTC */ 165 rtc_attr->log_size = 0; 166 rtc_attr->log_depth = 0; 167 } else { 168 /* Keep original values */ 169 rtc_attr->log_size = is_match_rtc ? matcher->attr.table.sz_row_log : ste->order; 170 rtc_attr->log_depth = is_match_rtc ? matcher->attr.table.sz_col_log : 0; 171 } 172 } 173 174 static int mlx5dr_matcher_create_rtc(struct mlx5dr_matcher *matcher, 175 bool is_match_rtc) 176 { 177 const char *rtc_type_str = is_match_rtc ? "match" : "action"; 178 struct mlx5dr_cmd_rtc_create_attr rtc_attr = {0}; 179 struct mlx5dr_context *ctx = matcher->tbl->ctx; 180 struct mlx5dr_action_default_stc *default_stc; 181 struct mlx5dr_table *tbl = matcher->tbl; 182 struct mlx5dr_devx_obj **rtc_0, **rtc_1; 183 struct mlx5dr_pool *ste_pool, *stc_pool; 184 struct mlx5dr_devx_obj *devx_obj; 185 struct mlx5dr_pool_chunk *ste; 186 int ret; 187 188 if (is_match_rtc) { 189 rtc_0 = &matcher->match_ste.rtc_0; 190 rtc_1 = &matcher->match_ste.rtc_1; 191 ste_pool = matcher->match_ste.pool; 192 ste = &matcher->match_ste.ste; 193 ste->order = matcher->attr.table.sz_col_log + 194 matcher->attr.table.sz_row_log; 195 rtc_attr.log_size = matcher->attr.table.sz_row_log; 196 rtc_attr.log_depth = matcher->attr.table.sz_col_log; 197 rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH; 198 /* The first match template is used since all share the same definer */ 199 rtc_attr.definer_id = mlx5dr_definer_get_id(matcher->mt[0]->definer); 200 rtc_attr.is_jumbo = mlx5dr_definer_is_jumbo(matcher->mt[0]->definer); 201 rtc_attr.miss_ft_id = matcher->end_ft->id; 202 /* Match pool requires implicit allocation */ 203 ret = mlx5dr_pool_chunk_alloc(ste_pool, ste); 204 if (ret) { 205 DR_LOG(ERR, "Failed to allocate STE for %s RTC", rtc_type_str); 206 return ret; 207 } 208 } else { 209 rtc_0 = &matcher->action_ste.rtc_0; 210 rtc_1 = &matcher->action_ste.rtc_1; 211 ste_pool = matcher->action_ste.pool; 212 ste = &matcher->action_ste.ste; 213 ste->order = rte_log2_u32(matcher->action_ste.max_stes) + 214 matcher->attr.table.sz_row_log; 215 rtc_attr.log_size = ste->order; 216 rtc_attr.log_depth = 0; 217 rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; 218 /* The action STEs use the default always hit definer */ 219 rtc_attr.definer_id = ctx->caps->trivial_match_definer; 220 rtc_attr.is_jumbo = false; 221 rtc_attr.miss_ft_id = 0; 222 } 223 224 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(ste_pool, ste); 225 226 rtc_attr.pd = ctx->pd_num; 227 rtc_attr.ste_base = devx_obj->id; 228 rtc_attr.ste_offset = ste->offset; 229 rtc_attr.table_type = mlx5dr_table_get_res_fw_ft_type(tbl->type, false); 230 mlx5dr_matcher_set_rtc_attr_sz(matcher, &rtc_attr, is_match_rtc, false); 231 232 /* STC is a single resource (devx_obj), use any STC for the ID */ 233 stc_pool = ctx->stc_pool[tbl->type]; 234 default_stc = ctx->common_res[tbl->type].default_stc; 235 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, &default_stc->default_hit); 236 rtc_attr.stc_base = devx_obj->id; 237 238 *rtc_0 = mlx5dr_cmd_rtc_create(ctx->ibv_ctx, &rtc_attr); 239 if (!*rtc_0) { 240 DR_LOG(ERR, "Failed to create matcher %s RTC", rtc_type_str); 241 goto free_ste; 242 } 243 244 if (tbl->type == MLX5DR_TABLE_TYPE_FDB) { 245 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(ste_pool, ste); 246 rtc_attr.ste_base = devx_obj->id; 247 rtc_attr.table_type = mlx5dr_table_get_res_fw_ft_type(tbl->type, true); 248 249 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, &default_stc->default_hit); 250 rtc_attr.stc_base = devx_obj->id; 251 mlx5dr_matcher_set_rtc_attr_sz(matcher, &rtc_attr, is_match_rtc, true); 252 253 *rtc_1 = mlx5dr_cmd_rtc_create(ctx->ibv_ctx, &rtc_attr); 254 if (!*rtc_1) { 255 DR_LOG(ERR, "Failed to create peer matcher %s RTC0", rtc_type_str); 256 goto destroy_rtc_0; 257 } 258 } 259 260 return 0; 261 262 destroy_rtc_0: 263 mlx5dr_cmd_destroy_obj(*rtc_0); 264 free_ste: 265 if (is_match_rtc) 266 mlx5dr_pool_chunk_free(ste_pool, ste); 267 return rte_errno; 268 } 269 270 static void mlx5dr_matcher_destroy_rtc(struct mlx5dr_matcher *matcher, 271 bool is_match_rtc) 272 { 273 struct mlx5dr_table *tbl = matcher->tbl; 274 struct mlx5dr_devx_obj *rtc_0, *rtc_1; 275 struct mlx5dr_pool_chunk *ste; 276 struct mlx5dr_pool *ste_pool; 277 278 if (is_match_rtc) { 279 rtc_0 = matcher->match_ste.rtc_0; 280 rtc_1 = matcher->match_ste.rtc_1; 281 ste_pool = matcher->match_ste.pool; 282 ste = &matcher->match_ste.ste; 283 } else { 284 rtc_0 = matcher->action_ste.rtc_0; 285 rtc_1 = matcher->action_ste.rtc_1; 286 ste_pool = matcher->action_ste.pool; 287 ste = &matcher->action_ste.ste; 288 } 289 290 if (tbl->type == MLX5DR_TABLE_TYPE_FDB) 291 mlx5dr_cmd_destroy_obj(rtc_1); 292 293 mlx5dr_cmd_destroy_obj(rtc_0); 294 if (is_match_rtc) 295 mlx5dr_pool_chunk_free(ste_pool, ste); 296 } 297 298 static void mlx5dr_matcher_set_pool_attr(struct mlx5dr_pool_attr *attr, 299 struct mlx5dr_matcher *matcher) 300 { 301 switch (matcher->attr.optimize_flow_src) { 302 case MLX5DR_MATCHER_FLOW_SRC_VPORT: 303 attr->opt_type = MLX5DR_POOL_OPTIMIZE_ORIG; 304 break; 305 case MLX5DR_MATCHER_FLOW_SRC_WIRE: 306 attr->opt_type = MLX5DR_POOL_OPTIMIZE_MIRROR; 307 break; 308 default: 309 break; 310 } 311 } 312 313 static int mlx5dr_matcher_bind_at(struct mlx5dr_matcher *matcher) 314 { 315 bool is_jumbo = mlx5dr_definer_is_jumbo(matcher->mt[0]->definer); 316 struct mlx5dr_cmd_stc_modify_attr stc_attr = {0}; 317 struct mlx5dr_table *tbl = matcher->tbl; 318 struct mlx5dr_pool_attr pool_attr = {0}; 319 struct mlx5dr_context *ctx = tbl->ctx; 320 uint32_t required_stes; 321 int i, ret; 322 bool valid; 323 324 for (i = 0; i < matcher->num_of_at; i++) { 325 struct mlx5dr_action_template *at = matcher->at[i]; 326 327 /* Check if action combinabtion is valid */ 328 valid = mlx5dr_action_check_combo(at->action_type_arr, matcher->tbl->type); 329 if (!valid) { 330 DR_LOG(ERR, "Invalid combination in action template %d", i); 331 return rte_errno; 332 } 333 334 /* Process action template to setters */ 335 ret = mlx5dr_action_template_process(at); 336 if (ret) { 337 DR_LOG(ERR, "Failed to process action template %d", i); 338 return rte_errno; 339 } 340 341 required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term); 342 matcher->action_ste.max_stes = RTE_MAX(matcher->action_ste.max_stes, required_stes); 343 344 /* Future: Optimize reparse */ 345 } 346 347 /* There are no additioanl STEs required for matcher */ 348 if (!matcher->action_ste.max_stes) 349 return 0; 350 351 /* Allocate action STE mempool */ 352 pool_attr.table_type = tbl->type; 353 pool_attr.pool_type = MLX5DR_POOL_TYPE_STE; 354 pool_attr.flags = MLX5DR_POOL_FLAGS_FOR_STE_ACTION_POOL; 355 pool_attr.alloc_log_sz = rte_log2_u32(matcher->action_ste.max_stes) + 356 matcher->attr.table.sz_row_log; 357 mlx5dr_matcher_set_pool_attr(&pool_attr, matcher); 358 matcher->action_ste.pool = mlx5dr_pool_create(ctx, &pool_attr); 359 if (!matcher->action_ste.pool) { 360 DR_LOG(ERR, "Failed to create action ste pool"); 361 return rte_errno; 362 } 363 364 /* Allocate action RTC */ 365 ret = mlx5dr_matcher_create_rtc(matcher, false); 366 if (ret) { 367 DR_LOG(ERR, "Failed to create action RTC"); 368 goto free_ste_pool; 369 } 370 371 /* Allocate STC for jumps to STE */ 372 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT; 373 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE; 374 stc_attr.ste_table.ste = matcher->action_ste.ste; 375 stc_attr.ste_table.ste_pool = matcher->action_ste.pool; 376 stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer; 377 378 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl->type, 379 &matcher->action_ste.stc); 380 if (ret) { 381 DR_LOG(ERR, "Failed to create action jump to table STC"); 382 goto free_rtc; 383 } 384 385 return 0; 386 387 free_rtc: 388 mlx5dr_matcher_destroy_rtc(matcher, false); 389 free_ste_pool: 390 mlx5dr_pool_destroy(matcher->action_ste.pool); 391 return rte_errno; 392 } 393 394 static void mlx5dr_matcher_unbind_at(struct mlx5dr_matcher *matcher) 395 { 396 struct mlx5dr_table *tbl = matcher->tbl; 397 398 if (!matcher->action_ste.max_stes) 399 return; 400 401 mlx5dr_action_free_single_stc(tbl->ctx, tbl->type, &matcher->action_ste.stc); 402 mlx5dr_matcher_destroy_rtc(matcher, false); 403 mlx5dr_pool_destroy(matcher->action_ste.pool); 404 } 405 406 static int mlx5dr_matcher_bind_mt(struct mlx5dr_matcher *matcher) 407 { 408 struct mlx5dr_context *ctx = matcher->tbl->ctx; 409 struct mlx5dr_pool_attr pool_attr = {0}; 410 int i, created = 0; 411 int ret = -1; 412 413 for (i = 0; i < matcher->num_of_mt; i++) { 414 /* Get a definer for each match template */ 415 ret = mlx5dr_definer_get(ctx, matcher->mt[i]); 416 if (ret) 417 goto definer_put; 418 419 created++; 420 421 /* Verify all templates produce the same definer */ 422 if (i == 0) 423 continue; 424 425 ret = mlx5dr_definer_compare(matcher->mt[i]->definer, 426 matcher->mt[i - 1]->definer); 427 if (ret) { 428 DR_LOG(ERR, "Match templates cannot be used on the same matcher"); 429 rte_errno = ENOTSUP; 430 goto definer_put; 431 } 432 } 433 434 /* Create an STE pool per matcher*/ 435 pool_attr.pool_type = MLX5DR_POOL_TYPE_STE; 436 pool_attr.flags = MLX5DR_POOL_FLAGS_FOR_MATCHER_STE_POOL; 437 pool_attr.table_type = matcher->tbl->type; 438 pool_attr.alloc_log_sz = matcher->attr.table.sz_col_log + 439 matcher->attr.table.sz_row_log; 440 mlx5dr_matcher_set_pool_attr(&pool_attr, matcher); 441 442 matcher->match_ste.pool = mlx5dr_pool_create(ctx, &pool_attr); 443 if (!matcher->match_ste.pool) { 444 DR_LOG(ERR, "Failed to allocate matcher STE pool"); 445 goto definer_put; 446 } 447 448 return 0; 449 450 definer_put: 451 while (created--) 452 mlx5dr_definer_put(matcher->mt[created]); 453 454 return ret; 455 } 456 457 static void mlx5dr_matcher_unbind_mt(struct mlx5dr_matcher *matcher) 458 { 459 int i; 460 461 for (i = 0; i < matcher->num_of_mt; i++) 462 mlx5dr_definer_put(matcher->mt[i]); 463 464 mlx5dr_pool_destroy(matcher->match_ste.pool); 465 } 466 467 static int 468 mlx5dr_matcher_process_attr(struct mlx5dr_cmd_query_caps *caps, 469 struct mlx5dr_matcher *matcher, 470 bool is_root) 471 { 472 struct mlx5dr_matcher_attr *attr = &matcher->attr; 473 474 if (matcher->tbl->type != MLX5DR_TABLE_TYPE_FDB && attr->optimize_flow_src) { 475 DR_LOG(ERR, "NIC domain doesn't support flow_src"); 476 goto not_supported; 477 } 478 479 if (is_root) { 480 if (attr->mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE) { 481 DR_LOG(ERR, "Root matcher supports only rule resource mode"); 482 goto not_supported; 483 } 484 if (attr->optimize_flow_src) { 485 DR_LOG(ERR, "Root matcher can't specify FDB direction"); 486 goto not_supported; 487 } 488 return 0; 489 } 490 491 /* Convert number of rules to the required depth */ 492 if (attr->mode == MLX5DR_MATCHER_RESOURCE_MODE_RULE) 493 attr->table.sz_col_log = mlx5dr_matcher_rules_to_tbl_depth(attr->rule.num_log); 494 495 if (attr->table.sz_col_log > caps->rtc_log_depth_max) { 496 DR_LOG(ERR, "Matcher depth exceeds limit %d", caps->rtc_log_depth_max); 497 goto not_supported; 498 } 499 500 if (attr->table.sz_col_log + attr->table.sz_row_log > caps->ste_alloc_log_max) { 501 DR_LOG(ERR, "Total matcher size exceeds limit %d", caps->ste_alloc_log_max); 502 goto not_supported; 503 } 504 505 if (attr->table.sz_col_log + attr->table.sz_row_log < caps->ste_alloc_log_gran) { 506 DR_LOG(ERR, "Total matcher size below limit %d", caps->ste_alloc_log_gran); 507 goto not_supported; 508 } 509 510 return 0; 511 512 not_supported: 513 rte_errno = EOPNOTSUPP; 514 return rte_errno; 515 } 516 517 static int mlx5dr_matcher_create_and_connect(struct mlx5dr_matcher *matcher) 518 { 519 int ret; 520 521 /* Select and create the definers for current matcher */ 522 ret = mlx5dr_matcher_bind_mt(matcher); 523 if (ret) 524 return ret; 525 526 /* Calculate and verify action combination */ 527 ret = mlx5dr_matcher_bind_at(matcher); 528 if (ret) 529 goto unbind_mt; 530 531 /* Create matcher end flow table anchor */ 532 ret = mlx5dr_matcher_create_end_ft(matcher); 533 if (ret) 534 goto unbind_at; 535 536 /* Allocate the RTC for the new matcher */ 537 ret = mlx5dr_matcher_create_rtc(matcher, true); 538 if (ret) 539 goto destroy_end_ft; 540 541 /* Connect the matcher to the matcher list */ 542 ret = mlx5dr_matcher_connect(matcher); 543 if (ret) 544 goto destroy_rtc; 545 546 return 0; 547 548 destroy_rtc: 549 mlx5dr_matcher_destroy_rtc(matcher, true); 550 destroy_end_ft: 551 mlx5dr_matcher_destroy_end_ft(matcher); 552 unbind_at: 553 mlx5dr_matcher_unbind_at(matcher); 554 unbind_mt: 555 mlx5dr_matcher_unbind_mt(matcher); 556 return ret; 557 } 558 559 static void mlx5dr_matcher_destroy_and_disconnect(struct mlx5dr_matcher *matcher) 560 { 561 mlx5dr_matcher_disconnect(matcher); 562 mlx5dr_matcher_destroy_rtc(matcher, true); 563 mlx5dr_matcher_destroy_end_ft(matcher); 564 mlx5dr_matcher_unbind_at(matcher); 565 mlx5dr_matcher_unbind_mt(matcher); 566 } 567 568 static int 569 mlx5dr_matcher_create_col_matcher(struct mlx5dr_matcher *matcher) 570 { 571 struct mlx5dr_context *ctx = matcher->tbl->ctx; 572 struct mlx5dr_matcher *col_matcher; 573 int ret; 574 575 if (matcher->attr.mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE) 576 return 0; 577 578 if (!mlx5dr_matcher_requires_col_tbl(matcher->attr.rule.num_log)) 579 return 0; 580 581 col_matcher = simple_calloc(1, sizeof(*matcher)); 582 if (!col_matcher) { 583 rte_errno = ENOMEM; 584 return rte_errno; 585 } 586 587 col_matcher->tbl = matcher->tbl; 588 col_matcher->num_of_mt = matcher->num_of_mt; 589 memcpy(col_matcher->mt, matcher->mt, matcher->num_of_mt * sizeof(*matcher->mt)); 590 col_matcher->num_of_at = matcher->num_of_at; 591 memcpy(col_matcher->at, matcher->at, matcher->num_of_at * sizeof(*matcher->at)); 592 593 col_matcher->attr.priority = matcher->attr.priority; 594 col_matcher->attr.mode = MLX5DR_MATCHER_RESOURCE_MODE_HTABLE; 595 col_matcher->attr.optimize_flow_src = matcher->attr.optimize_flow_src; 596 col_matcher->attr.table.sz_row_log = matcher->attr.rule.num_log; 597 col_matcher->attr.table.sz_col_log = MLX5DR_MATCHER_ASSURED_COL_TBL_DEPTH; 598 if (col_matcher->attr.table.sz_row_log > MLX5DR_MATCHER_ASSURED_ROW_RATIO) 599 col_matcher->attr.table.sz_row_log -= MLX5DR_MATCHER_ASSURED_ROW_RATIO; 600 601 ret = mlx5dr_matcher_process_attr(ctx->caps, col_matcher, false); 602 if (ret) 603 goto free_col_matcher; 604 605 ret = mlx5dr_matcher_create_and_connect(col_matcher); 606 if (ret) 607 goto free_col_matcher; 608 609 matcher->col_matcher = col_matcher; 610 611 return 0; 612 613 free_col_matcher: 614 simple_free(col_matcher); 615 DR_LOG(ERR, "Failed to create assured collision matcher"); 616 return ret; 617 } 618 619 static void 620 mlx5dr_matcher_destroy_col_matcher(struct mlx5dr_matcher *matcher) 621 { 622 if (matcher->attr.mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE) 623 return; 624 625 if (matcher->col_matcher) { 626 mlx5dr_matcher_destroy_and_disconnect(matcher->col_matcher); 627 simple_free(matcher->col_matcher); 628 } 629 } 630 631 static int mlx5dr_matcher_init(struct mlx5dr_matcher *matcher) 632 { 633 struct mlx5dr_context *ctx = matcher->tbl->ctx; 634 int ret; 635 636 pthread_spin_lock(&ctx->ctrl_lock); 637 638 /* Allocate matcher resource and connect to the packet pipe */ 639 ret = mlx5dr_matcher_create_and_connect(matcher); 640 if (ret) 641 goto unlock_err; 642 643 /* Create additional matcher for collision handling */ 644 ret = mlx5dr_matcher_create_col_matcher(matcher); 645 if (ret) 646 goto destory_and_disconnect; 647 648 pthread_spin_unlock(&ctx->ctrl_lock); 649 650 return 0; 651 652 destory_and_disconnect: 653 mlx5dr_matcher_destroy_and_disconnect(matcher); 654 unlock_err: 655 pthread_spin_unlock(&ctx->ctrl_lock); 656 return ret; 657 } 658 659 static int mlx5dr_matcher_uninit(struct mlx5dr_matcher *matcher) 660 { 661 struct mlx5dr_context *ctx = matcher->tbl->ctx; 662 663 pthread_spin_lock(&ctx->ctrl_lock); 664 mlx5dr_matcher_destroy_col_matcher(matcher); 665 mlx5dr_matcher_destroy_and_disconnect(matcher); 666 pthread_spin_unlock(&ctx->ctrl_lock); 667 668 return 0; 669 } 670 671 static int mlx5dr_matcher_init_root(struct mlx5dr_matcher *matcher) 672 { 673 enum mlx5dr_table_type type = matcher->tbl->type; 674 struct mlx5dr_context *ctx = matcher->tbl->ctx; 675 struct mlx5dv_flow_matcher_attr attr = {0}; 676 struct mlx5dv_flow_match_parameters *mask; 677 struct mlx5_flow_attr flow_attr = {0}; 678 struct rte_flow_error rte_error; 679 uint8_t match_criteria; 680 int ret; 681 682 #ifdef HAVE_MLX5DV_FLOW_MATCHER_FT_TYPE 683 attr.comp_mask = MLX5DV_FLOW_MATCHER_MASK_FT_TYPE; 684 685 switch (type) { 686 case MLX5DR_TABLE_TYPE_NIC_RX: 687 attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 688 break; 689 case MLX5DR_TABLE_TYPE_NIC_TX: 690 attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX; 691 break; 692 case MLX5DR_TABLE_TYPE_FDB: 693 attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 694 break; 695 default: 696 assert(0); 697 break; 698 } 699 #endif 700 701 if (matcher->attr.priority > UINT16_MAX) { 702 DR_LOG(ERR, "Root matcher priority exceeds allowed limit"); 703 rte_errno = EINVAL; 704 return rte_errno; 705 } 706 707 mask = simple_calloc(1, MLX5_ST_SZ_BYTES(fte_match_param) + 708 offsetof(struct mlx5dv_flow_match_parameters, match_buf)); 709 if (!mask) { 710 rte_errno = ENOMEM; 711 return rte_errno; 712 } 713 714 flow_attr.tbl_type = type; 715 716 /* On root table matcher, only a single match template is supported */ 717 ret = flow_dv_translate_items_hws(matcher->mt[0]->items, 718 &flow_attr, mask->match_buf, 719 MLX5_SET_MATCHER_HS_M, NULL, 720 &match_criteria, 721 &rte_error); 722 if (ret) { 723 DR_LOG(ERR, "Failed to convert items to PRM [%s]", rte_error.message); 724 goto free_mask; 725 } 726 727 mask->match_sz = MLX5_ST_SZ_BYTES(fte_match_param); 728 attr.match_mask = mask; 729 attr.match_criteria_enable = match_criteria; 730 attr.type = IBV_FLOW_ATTR_NORMAL; 731 attr.priority = matcher->attr.priority; 732 733 matcher->dv_matcher = 734 mlx5_glue->dv_create_flow_matcher_root(ctx->ibv_ctx, &attr); 735 if (!matcher->dv_matcher) { 736 DR_LOG(ERR, "Failed to create DV flow matcher"); 737 rte_errno = errno; 738 goto free_mask; 739 } 740 741 simple_free(mask); 742 743 pthread_spin_lock(&ctx->ctrl_lock); 744 LIST_INSERT_HEAD(&matcher->tbl->head, matcher, next); 745 pthread_spin_unlock(&ctx->ctrl_lock); 746 747 return 0; 748 749 free_mask: 750 simple_free(mask); 751 return rte_errno; 752 } 753 754 static int mlx5dr_matcher_uninit_root(struct mlx5dr_matcher *matcher) 755 { 756 struct mlx5dr_context *ctx = matcher->tbl->ctx; 757 int ret; 758 759 pthread_spin_lock(&ctx->ctrl_lock); 760 LIST_REMOVE(matcher, next); 761 pthread_spin_unlock(&ctx->ctrl_lock); 762 763 ret = mlx5_glue->dv_destroy_flow_matcher_root(matcher->dv_matcher); 764 if (ret) { 765 DR_LOG(ERR, "Failed to Destroy DV flow matcher"); 766 rte_errno = errno; 767 } 768 769 return ret; 770 } 771 772 static int 773 mlx5dr_matcher_check_template(uint8_t num_of_mt, uint8_t num_of_at, bool is_root) 774 { 775 uint8_t max_num_of_mt; 776 777 max_num_of_mt = is_root ? 778 MLX5DR_MATCHER_MAX_MT_ROOT : 779 MLX5DR_MATCHER_MAX_MT; 780 781 if (!num_of_mt || !num_of_at) { 782 DR_LOG(ERR, "Number of action/match template cannot be zero"); 783 goto out_not_sup; 784 } 785 786 if (num_of_at > MLX5DR_MATCHER_MAX_AT) { 787 DR_LOG(ERR, "Number of action templates exceeds limit"); 788 goto out_not_sup; 789 } 790 791 if (num_of_mt > max_num_of_mt) { 792 DR_LOG(ERR, "Number of match templates exceeds limit"); 793 goto out_not_sup; 794 } 795 796 return 0; 797 798 out_not_sup: 799 rte_errno = ENOTSUP; 800 return rte_errno; 801 } 802 803 struct mlx5dr_matcher * 804 mlx5dr_matcher_create(struct mlx5dr_table *tbl, 805 struct mlx5dr_match_template *mt[], 806 uint8_t num_of_mt, 807 struct mlx5dr_action_template *at[], 808 uint8_t num_of_at, 809 struct mlx5dr_matcher_attr *attr) 810 { 811 bool is_root = mlx5dr_table_is_root(tbl); 812 struct mlx5dr_matcher *matcher; 813 int ret; 814 815 ret = mlx5dr_matcher_check_template(num_of_mt, num_of_at, is_root); 816 if (ret) 817 return NULL; 818 819 matcher = simple_calloc(1, sizeof(*matcher)); 820 if (!matcher) { 821 rte_errno = ENOMEM; 822 return NULL; 823 } 824 825 matcher->tbl = tbl; 826 matcher->attr = *attr; 827 matcher->num_of_mt = num_of_mt; 828 memcpy(matcher->mt, mt, num_of_mt * sizeof(*mt)); 829 matcher->num_of_at = num_of_at; 830 memcpy(matcher->at, at, num_of_at * sizeof(*at)); 831 832 ret = mlx5dr_matcher_process_attr(tbl->ctx->caps, matcher, is_root); 833 if (ret) 834 goto free_matcher; 835 836 if (is_root) 837 ret = mlx5dr_matcher_init_root(matcher); 838 else 839 ret = mlx5dr_matcher_init(matcher); 840 841 if (ret) { 842 DR_LOG(ERR, "Failed to initialise matcher: %d", ret); 843 goto free_matcher; 844 } 845 846 return matcher; 847 848 free_matcher: 849 simple_free(matcher); 850 return NULL; 851 } 852 853 int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher) 854 { 855 if (mlx5dr_table_is_root(matcher->tbl)) 856 mlx5dr_matcher_uninit_root(matcher); 857 else 858 mlx5dr_matcher_uninit(matcher); 859 860 simple_free(matcher); 861 return 0; 862 } 863 864 struct mlx5dr_match_template * 865 mlx5dr_match_template_create(const struct rte_flow_item items[], 866 enum mlx5dr_match_template_flags flags) 867 { 868 struct mlx5dr_match_template *mt; 869 struct rte_flow_error error; 870 int ret, len; 871 872 if (flags > MLX5DR_MATCH_TEMPLATE_FLAG_RELAXED_MATCH) { 873 DR_LOG(ERR, "Unsupported match template flag provided"); 874 rte_errno = EINVAL; 875 return NULL; 876 } 877 878 mt = simple_calloc(1, sizeof(*mt)); 879 if (!mt) { 880 DR_LOG(ERR, "Failed to allocate match template"); 881 rte_errno = ENOMEM; 882 return NULL; 883 } 884 885 mt->flags = flags; 886 887 /* Duplicate the user given items */ 888 ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN, NULL, 0, items, &error); 889 if (ret <= 0) { 890 DR_LOG(ERR, "Unable to process items (%s): %s", 891 error.message ? error.message : "unspecified", 892 strerror(rte_errno)); 893 goto free_template; 894 } 895 896 len = RTE_ALIGN(ret, 16); 897 mt->items = simple_calloc(1, len); 898 if (!mt->items) { 899 DR_LOG(ERR, "Failed to allocate item copy"); 900 rte_errno = ENOMEM; 901 goto free_template; 902 } 903 904 ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN, mt->items, ret, items, &error); 905 if (ret <= 0) 906 goto free_dst; 907 908 return mt; 909 910 free_dst: 911 simple_free(mt->items); 912 free_template: 913 simple_free(mt); 914 return NULL; 915 } 916 917 int mlx5dr_match_template_destroy(struct mlx5dr_match_template *mt) 918 { 919 assert(!mt->refcount); 920 simple_free(mt->items); 921 simple_free(mt); 922 return 0; 923 } 924