1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2022 NVIDIA Corporation & Affiliates 3 */ 4 5 #include "mlx5dr_internal.h" 6 7 enum mlx5dr_matcher_rtc_type { 8 DR_MATCHER_RTC_TYPE_MATCH, 9 DR_MATCHER_RTC_TYPE_STE_ARRAY, 10 DR_MATCHER_RTC_TYPE_MAX, 11 }; 12 13 static const char * const mlx5dr_matcher_rtc_type_str[] = { 14 [DR_MATCHER_RTC_TYPE_MATCH] = "MATCH", 15 [DR_MATCHER_RTC_TYPE_STE_ARRAY] = "STE_ARRAY", 16 [DR_MATCHER_RTC_TYPE_MAX] = "UNKNOWN", 17 }; 18 19 static const char *mlx5dr_matcher_rtc_type_to_str(enum mlx5dr_matcher_rtc_type rtc_type) 20 { 21 if (rtc_type > DR_MATCHER_RTC_TYPE_MAX) 22 rtc_type = DR_MATCHER_RTC_TYPE_MAX; 23 return mlx5dr_matcher_rtc_type_str[rtc_type]; 24 } 25 26 static bool mlx5dr_matcher_requires_col_tbl(uint8_t log_num_of_rules) 27 { 28 /* Collision table concatenation is done only for large rule tables */ 29 return log_num_of_rules > MLX5DR_MATCHER_ASSURED_RULES_TH; 30 } 31 32 static uint8_t mlx5dr_matcher_rules_to_tbl_depth(uint8_t log_num_of_rules) 33 { 34 if (mlx5dr_matcher_requires_col_tbl(log_num_of_rules)) 35 return MLX5DR_MATCHER_ASSURED_MAIN_TBL_DEPTH; 36 37 /* For small rule tables we use a single deep table to assure insertion */ 38 return RTE_MIN(log_num_of_rules, MLX5DR_MATCHER_ASSURED_COL_TBL_DEPTH); 39 } 40 41 static void mlx5dr_matcher_destroy_end_ft(struct mlx5dr_matcher *matcher) 42 { 43 mlx5dr_table_destroy_default_ft(matcher->tbl, matcher->end_ft); 44 } 45 46 static int mlx5dr_matcher_free_rtc_pointing(struct mlx5dr_context *ctx, 47 uint32_t fw_ft_type, 48 enum mlx5dr_table_type type, 49 struct mlx5dr_devx_obj *devx_obj) 50 { 51 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 52 int ret; 53 54 if (type != MLX5DR_TABLE_TYPE_FDB && !mlx5dr_context_shared_gvmi_used(ctx)) 55 return 0; 56 57 ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID; 58 ft_attr.type = fw_ft_type; 59 ft_attr.rtc_id_0 = 0; 60 ft_attr.rtc_id_1 = 0; 61 62 ret = mlx5dr_cmd_flow_table_modify(devx_obj, &ft_attr); 63 if (ret) { 64 DR_LOG(ERR, "Failed to disconnect previous RTC"); 65 return ret; 66 } 67 68 return 0; 69 } 70 71 static int mlx5dr_matcher_shared_point_end_ft(struct mlx5dr_matcher *matcher) 72 { 73 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 74 int ret; 75 76 mlx5dr_cmd_set_attr_connect_miss_tbl(matcher->tbl->ctx, 77 matcher->tbl->fw_ft_type, 78 matcher->tbl->type, 79 &ft_attr); 80 81 ret = mlx5dr_cmd_flow_table_modify(matcher->end_ft, &ft_attr); 82 if (ret) { 83 DR_LOG(ERR, "Failed to connect new matcher to default miss alias RTC"); 84 return ret; 85 } 86 87 ret = mlx5dr_matcher_free_rtc_pointing(matcher->tbl->ctx, 88 matcher->tbl->fw_ft_type, 89 matcher->tbl->type, 90 matcher->end_ft); 91 92 return ret; 93 } 94 95 static int mlx5dr_matcher_shared_create_alias_rtc(struct mlx5dr_matcher *matcher) 96 { 97 struct mlx5dr_context *ctx = matcher->tbl->ctx; 98 int ret; 99 100 ret = mlx5dr_matcher_create_aliased_obj(ctx, 101 ctx->ibv_ctx, 102 ctx->local_ibv_ctx, 103 ctx->caps->shared_vhca_id, 104 matcher->match_ste.rtc_0->id, 105 MLX5_GENERAL_OBJ_TYPE_RTC, 106 &matcher->match_ste.aliased_rtc_0); 107 if (ret) { 108 DR_LOG(ERR, "Failed to allocate alias RTC"); 109 return ret; 110 } 111 return 0; 112 } 113 114 static int mlx5dr_matcher_create_init_shared(struct mlx5dr_matcher *matcher) 115 { 116 if (!mlx5dr_context_shared_gvmi_used(matcher->tbl->ctx)) 117 return 0; 118 119 if (mlx5dr_matcher_shared_point_end_ft(matcher)) { 120 DR_LOG(ERR, "Failed to point shared matcher end flow table"); 121 return rte_errno; 122 } 123 124 if (mlx5dr_matcher_shared_create_alias_rtc(matcher)) { 125 DR_LOG(ERR, "Failed to create alias RTC"); 126 return rte_errno; 127 } 128 129 return 0; 130 } 131 132 static void mlx5dr_matcher_create_uninit_shared(struct mlx5dr_matcher *matcher) 133 { 134 if (!mlx5dr_context_shared_gvmi_used(matcher->tbl->ctx)) 135 return; 136 137 if (matcher->match_ste.aliased_rtc_0) { 138 mlx5dr_cmd_destroy_obj(matcher->match_ste.aliased_rtc_0); 139 matcher->match_ste.aliased_rtc_0 = NULL; 140 } 141 } 142 143 static int mlx5dr_matcher_create_end_ft(struct mlx5dr_matcher *matcher) 144 { 145 struct mlx5dr_table *tbl = matcher->tbl; 146 147 matcher->end_ft = mlx5dr_table_create_default_ft(tbl->ctx->ibv_ctx, tbl); 148 if (!matcher->end_ft) { 149 DR_LOG(ERR, "Failed to create matcher end flow table"); 150 return rte_errno; 151 } 152 return 0; 153 } 154 155 static uint32_t 156 mlx5dr_matcher_connect_get_rtc0(struct mlx5dr_matcher *matcher) 157 { 158 if (!matcher->match_ste.aliased_rtc_0) 159 return matcher->match_ste.rtc_0->id; 160 else 161 return matcher->match_ste.aliased_rtc_0->id; 162 } 163 164 /* The function updates tbl->local_ft to the first RTC or 0 if no more matchers */ 165 static int mlx5dr_matcher_shared_update_local_ft(struct mlx5dr_table *tbl) 166 { 167 struct mlx5dr_cmd_ft_modify_attr cur_ft_attr = {0}; 168 struct mlx5dr_matcher *first_matcher; 169 int ret; 170 171 if (!mlx5dr_context_shared_gvmi_used(tbl->ctx)) 172 return 0; 173 174 first_matcher = LIST_FIRST(&tbl->head); 175 if (!first_matcher) { 176 /* local ft no longer points to any RTC, drop refcount */ 177 ret = mlx5dr_matcher_free_rtc_pointing(tbl->ctx, 178 tbl->fw_ft_type, 179 tbl->type, 180 tbl->local_ft); 181 if (ret) 182 DR_LOG(ERR, "Failed to clear local FT to prev alias RTC"); 183 184 return ret; 185 } 186 187 /* point local_ft to the first RTC */ 188 cur_ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID; 189 cur_ft_attr.type = tbl->fw_ft_type; 190 cur_ft_attr.rtc_id_0 = mlx5dr_matcher_connect_get_rtc0(first_matcher); 191 192 ret = mlx5dr_cmd_flow_table_modify(tbl->local_ft, &cur_ft_attr); 193 if (ret) { 194 DR_LOG(ERR, "Failed to point local FT to alias RTC"); 195 return ret; 196 } 197 198 return 0; 199 } 200 201 static int mlx5dr_matcher_connect(struct mlx5dr_matcher *matcher) 202 { 203 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 204 struct mlx5dr_table *tbl = matcher->tbl; 205 struct mlx5dr_matcher *prev = NULL; 206 struct mlx5dr_matcher *next = NULL; 207 struct mlx5dr_matcher *tmp_matcher; 208 struct mlx5dr_devx_obj *ft; 209 int ret; 210 211 /* Find location in matcher list */ 212 if (LIST_EMPTY(&tbl->head)) { 213 LIST_INSERT_HEAD(&tbl->head, matcher, next); 214 goto connect; 215 } 216 217 LIST_FOREACH(tmp_matcher, &tbl->head, next) { 218 if (tmp_matcher->attr.priority > matcher->attr.priority) { 219 next = tmp_matcher; 220 break; 221 } 222 prev = tmp_matcher; 223 } 224 225 if (next) 226 LIST_INSERT_BEFORE(next, matcher, next); 227 else 228 LIST_INSERT_AFTER(prev, matcher, next); 229 230 connect: 231 ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID; 232 ft_attr.type = tbl->fw_ft_type; 233 234 /* Connect to next */ 235 if (next) { 236 if (next->match_ste.rtc_0) 237 ft_attr.rtc_id_0 = next->match_ste.rtc_0->id; 238 if (next->match_ste.rtc_1) 239 ft_attr.rtc_id_1 = next->match_ste.rtc_1->id; 240 241 ret = mlx5dr_cmd_flow_table_modify(matcher->end_ft, &ft_attr); 242 if (ret) { 243 DR_LOG(ERR, "Failed to connect new matcher to next RTC"); 244 goto remove_from_list; 245 } 246 } 247 248 /* Connect to previous */ 249 ft = prev ? prev->end_ft : tbl->ft; 250 251 if (matcher->match_ste.rtc_0) 252 ft_attr.rtc_id_0 = matcher->match_ste.rtc_0->id; 253 if (matcher->match_ste.rtc_1) 254 ft_attr.rtc_id_1 = matcher->match_ste.rtc_1->id; 255 256 ret = mlx5dr_cmd_flow_table_modify(ft, &ft_attr); 257 if (ret) { 258 DR_LOG(ERR, "Failed to connect new matcher to previous FT"); 259 goto remove_from_list; 260 } 261 262 ret = mlx5dr_matcher_shared_update_local_ft(tbl); 263 if (ret) { 264 DR_LOG(ERR, "Failed to update local_ft anchor in shared table"); 265 goto remove_from_list; 266 } 267 268 return 0; 269 270 remove_from_list: 271 LIST_REMOVE(matcher, next); 272 return ret; 273 } 274 275 static int mlx5dr_matcher_disconnect(struct mlx5dr_matcher *matcher) 276 { 277 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 278 struct mlx5dr_table *tbl = matcher->tbl; 279 struct mlx5dr_matcher *tmp_matcher; 280 struct mlx5dr_devx_obj *prev_ft; 281 struct mlx5dr_matcher *next; 282 int ret; 283 284 prev_ft = matcher->tbl->ft; 285 LIST_FOREACH(tmp_matcher, &tbl->head, next) { 286 if (tmp_matcher == matcher) 287 break; 288 289 prev_ft = tmp_matcher->end_ft; 290 } 291 292 next = matcher->next.le_next; 293 294 ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID; 295 ft_attr.type = matcher->tbl->fw_ft_type; 296 297 if (next) { 298 /* Connect previous end FT to next RTC if exists */ 299 if (next->match_ste.rtc_0) 300 ft_attr.rtc_id_0 = next->match_ste.rtc_0->id; 301 if (next->match_ste.rtc_1) 302 ft_attr.rtc_id_1 = next->match_ste.rtc_1->id; 303 } else { 304 /* Matcher is last, point prev end FT to default miss */ 305 mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx, 306 tbl->fw_ft_type, 307 tbl->type, 308 &ft_attr); 309 } 310 311 ret = mlx5dr_cmd_flow_table_modify(prev_ft, &ft_attr); 312 if (ret) { 313 DR_LOG(ERR, "Failed to disconnect matcher"); 314 return ret; 315 } 316 317 LIST_REMOVE(matcher, next); 318 319 if (!next) { 320 /* ft no longer points to any RTC, drop refcount */ 321 ret = mlx5dr_matcher_free_rtc_pointing(tbl->ctx, 322 tbl->fw_ft_type, 323 tbl->type, 324 prev_ft); 325 if (ret) { 326 DR_LOG(ERR, "Failed to reset last RTC refcount"); 327 return ret; 328 } 329 } 330 331 ret = mlx5dr_matcher_shared_update_local_ft(tbl); 332 if (ret) { 333 DR_LOG(ERR, "Failed to update local_ft in shared table"); 334 return ret; 335 } 336 337 if (!next) { 338 /* ft no longer points to any RTC, drop refcount */ 339 ret = mlx5dr_matcher_free_rtc_pointing(tbl->ctx, 340 tbl->fw_ft_type, 341 tbl->type, 342 prev_ft); 343 if (ret) { 344 DR_LOG(ERR, "Failed to reset last RTC refcount"); 345 return ret; 346 } 347 } 348 349 return 0; 350 } 351 352 static bool mlx5dr_matcher_supp_fw_wqe(struct mlx5dr_matcher *matcher) 353 { 354 struct mlx5dr_cmd_query_caps *caps = matcher->tbl->ctx->caps; 355 356 if (matcher->flags & MLX5DR_MATCHER_FLAGS_HASH_DEFINER) { 357 if (matcher->hash_definer->type == MLX5DR_DEFINER_TYPE_MATCH && 358 !IS_BIT_SET(caps->supp_ste_format_gen_wqe, MLX5_IFC_RTC_STE_FORMAT_8DW)) { 359 DR_LOG(ERR, "Gen WQE MATCH format not supported"); 360 return false; 361 } 362 363 if (matcher->hash_definer->type == MLX5DR_DEFINER_TYPE_JUMBO) { 364 DR_LOG(ERR, "Gen WQE JUMBO format not supported"); 365 return false; 366 } 367 } 368 369 if (matcher->attr.insert_mode != MLX5DR_MATCHER_INSERT_BY_HASH || 370 matcher->attr.distribute_mode != MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) { 371 DR_LOG(ERR, "Gen WQE must be inserted and distribute by hash"); 372 return false; 373 } 374 375 if ((matcher->flags & MLX5DR_MATCHER_FLAGS_RANGE_DEFINER) && 376 !IS_BIT_SET(caps->supp_ste_format_gen_wqe, MLX5_IFC_RTC_STE_FORMAT_RANGE)) { 377 DR_LOG(INFO, "Extended match gen wqe RANGE format not supported"); 378 return false; 379 } 380 381 if (!(caps->supp_type_gen_wqe & MLX5_GENERATE_WQE_TYPE_FLOW_UPDATE)) { 382 DR_LOG(ERR, "Gen WQE command not supporting GTA"); 383 return false; 384 } 385 386 if (!caps->rtc_max_hash_def_gen_wqe) { 387 DR_LOG(ERR, "Hash definer not supported"); 388 return false; 389 } 390 391 return true; 392 } 393 394 static void mlx5dr_matcher_set_rtc_attr_sz(struct mlx5dr_matcher *matcher, 395 struct mlx5dr_cmd_rtc_create_attr *rtc_attr, 396 enum mlx5dr_matcher_rtc_type rtc_type, 397 bool is_mirror) 398 { 399 enum mlx5dr_matcher_flow_src flow_src = matcher->attr.optimize_flow_src; 400 bool is_match_rtc = rtc_type == DR_MATCHER_RTC_TYPE_MATCH; 401 struct mlx5dr_pool_chunk *ste = &matcher->action_ste.ste; 402 403 if ((flow_src == MLX5DR_MATCHER_FLOW_SRC_VPORT && !is_mirror) || 404 (flow_src == MLX5DR_MATCHER_FLOW_SRC_WIRE && is_mirror)) { 405 /* Optimize FDB RTC */ 406 rtc_attr->log_size = 0; 407 rtc_attr->log_depth = 0; 408 } else { 409 /* Keep original values */ 410 rtc_attr->log_size = is_match_rtc ? matcher->attr.table.sz_row_log : ste->order; 411 rtc_attr->log_depth = is_match_rtc ? matcher->attr.table.sz_col_log : 0; 412 } 413 } 414 415 int mlx5dr_matcher_create_aliased_obj(struct mlx5dr_context *ctx, 416 struct ibv_context *ibv_owner, 417 struct ibv_context *ibv_allowed, 418 uint16_t vhca_id_to_be_accessed, 419 uint32_t aliased_object_id, 420 uint16_t object_type, 421 struct mlx5dr_devx_obj **obj) 422 { 423 struct mlx5dr_cmd_allow_other_vhca_access_attr allow_attr = {0}; 424 struct mlx5dr_cmd_alias_obj_create_attr alias_attr = {0}; 425 char key[ACCESS_KEY_LEN]; 426 int ret; 427 int i; 428 429 if (!mlx5dr_context_shared_gvmi_used(ctx)) 430 return 0; 431 432 for (i = 0; i < ACCESS_KEY_LEN; i++) 433 key[i] = rte_rand() & 0xFF; 434 435 memcpy(allow_attr.access_key, key, ACCESS_KEY_LEN); 436 allow_attr.obj_type = object_type; 437 allow_attr.obj_id = aliased_object_id; 438 439 ret = mlx5dr_cmd_allow_other_vhca_access(ibv_owner, &allow_attr); 440 if (ret) { 441 DR_LOG(ERR, "Failed to allow RTC to be aliased"); 442 return ret; 443 } 444 445 memcpy(alias_attr.access_key, key, ACCESS_KEY_LEN); 446 alias_attr.obj_id = aliased_object_id; 447 alias_attr.obj_type = object_type; 448 alias_attr.vhca_id = vhca_id_to_be_accessed; 449 *obj = mlx5dr_cmd_alias_obj_create(ibv_allowed, &alias_attr); 450 if (!*obj) { 451 DR_LOG(ERR, "Failed to create alias object"); 452 return rte_errno; 453 } 454 455 return 0; 456 } 457 458 static int mlx5dr_matcher_create_rtc(struct mlx5dr_matcher *matcher, 459 enum mlx5dr_matcher_rtc_type rtc_type) 460 { 461 struct mlx5dr_matcher_attr *attr = &matcher->attr; 462 struct mlx5dr_cmd_rtc_create_attr rtc_attr = {0}; 463 struct mlx5dr_match_template *mt = matcher->mt; 464 struct mlx5dr_context *ctx = matcher->tbl->ctx; 465 struct mlx5dr_action_default_stc *default_stc; 466 struct mlx5dr_table *tbl = matcher->tbl; 467 struct mlx5dr_devx_obj **rtc_0, **rtc_1; 468 struct mlx5dr_pool *ste_pool, *stc_pool; 469 struct mlx5dr_devx_obj *devx_obj; 470 struct mlx5dr_pool_chunk *ste; 471 int ret; 472 473 switch (rtc_type) { 474 case DR_MATCHER_RTC_TYPE_MATCH: 475 rtc_0 = &matcher->match_ste.rtc_0; 476 rtc_1 = &matcher->match_ste.rtc_1; 477 ste_pool = matcher->match_ste.pool; 478 ste = &matcher->match_ste.ste; 479 ste->order = attr->table.sz_col_log + attr->table.sz_row_log; 480 481 /* Add additional rows due to additional range STE */ 482 if (mlx5dr_matcher_mt_is_range(mt)) 483 ste->order++; 484 485 rtc_attr.log_size = attr->table.sz_row_log; 486 rtc_attr.log_depth = attr->table.sz_col_log; 487 rtc_attr.is_frst_jumbo = mlx5dr_matcher_mt_is_jumbo(mt); 488 rtc_attr.is_scnd_range = mlx5dr_matcher_mt_is_range(mt); 489 rtc_attr.miss_ft_id = matcher->end_ft->id; 490 491 if (attr->insert_mode == MLX5DR_MATCHER_INSERT_BY_HASH) { 492 /* The usual Hash Table */ 493 rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH; 494 495 if (matcher->hash_definer) { 496 /* Specify definer_id_0 is used for hashing */ 497 rtc_attr.fw_gen_wqe = true; 498 rtc_attr.num_hash_definer = 1; 499 rtc_attr.match_definer_0 = 500 mlx5dr_definer_get_id(matcher->hash_definer); 501 } else { 502 /* The first mt is used since all share the same definer */ 503 rtc_attr.match_definer_0 = mlx5dr_definer_get_id(mt->definer); 504 505 /* This is tricky, instead of passing two definers for 506 * match and range, we specify that this RTC uses a hash 507 * definer, this will allow us to use any range definer 508 * since only first STE is used for hashing anyways. 509 */ 510 if (matcher->flags & MLX5DR_MATCHER_FLAGS_RANGE_DEFINER) { 511 rtc_attr.fw_gen_wqe = true; 512 rtc_attr.num_hash_definer = 1; 513 } 514 } 515 } else if (attr->insert_mode == MLX5DR_MATCHER_INSERT_BY_INDEX) { 516 rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; 517 rtc_attr.num_hash_definer = 1; 518 519 if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) { 520 /* Hash Split Table */ 521 rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH; 522 rtc_attr.match_definer_0 = mlx5dr_definer_get_id(mt->definer); 523 } else if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_LINEAR) { 524 /* Linear Lookup Table */ 525 rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR; 526 rtc_attr.match_definer_0 = ctx->caps->linear_match_definer; 527 } 528 } 529 530 /* Match pool requires implicit allocation */ 531 ret = mlx5dr_pool_chunk_alloc(ste_pool, ste); 532 if (ret) { 533 DR_LOG(ERR, "Failed to allocate STE for %s RTC", 534 mlx5dr_matcher_rtc_type_to_str(rtc_type)); 535 return ret; 536 } 537 break; 538 539 case DR_MATCHER_RTC_TYPE_STE_ARRAY: 540 rtc_0 = &matcher->action_ste.rtc_0; 541 rtc_1 = &matcher->action_ste.rtc_1; 542 ste_pool = matcher->action_ste.pool; 543 ste = &matcher->action_ste.ste; 544 ste->order = rte_log2_u32(matcher->action_ste.max_stes) + 545 attr->table.sz_row_log; 546 rtc_attr.log_size = ste->order; 547 rtc_attr.log_depth = 0; 548 rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; 549 /* The action STEs use the default always hit definer */ 550 rtc_attr.match_definer_0 = ctx->caps->trivial_match_definer; 551 rtc_attr.is_frst_jumbo = false; 552 rtc_attr.miss_ft_id = 0; 553 break; 554 555 default: 556 DR_LOG(ERR, "HWS Invalid RTC type"); 557 rte_errno = EINVAL; 558 return rte_errno; 559 } 560 561 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(ste_pool, ste); 562 563 rtc_attr.pd = ctx->pd_num; 564 rtc_attr.ste_base = devx_obj->id; 565 rtc_attr.ste_offset = ste->offset; 566 rtc_attr.table_type = mlx5dr_table_get_res_fw_ft_type(tbl->type, false); 567 mlx5dr_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, false); 568 569 /* STC is a single resource (devx_obj), use any STC for the ID */ 570 stc_pool = ctx->stc_pool[tbl->type]; 571 default_stc = ctx->common_res[tbl->type].default_stc; 572 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, &default_stc->default_hit); 573 rtc_attr.stc_base = devx_obj->id; 574 575 *rtc_0 = mlx5dr_cmd_rtc_create(ctx->ibv_ctx, &rtc_attr); 576 if (!*rtc_0) { 577 DR_LOG(ERR, "Failed to create matcher RTC of type %s", 578 mlx5dr_matcher_rtc_type_to_str(rtc_type)); 579 goto free_ste; 580 } 581 582 if (tbl->type == MLX5DR_TABLE_TYPE_FDB) { 583 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(ste_pool, ste); 584 rtc_attr.ste_base = devx_obj->id; 585 rtc_attr.table_type = mlx5dr_table_get_res_fw_ft_type(tbl->type, true); 586 587 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, &default_stc->default_hit); 588 rtc_attr.stc_base = devx_obj->id; 589 mlx5dr_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, true); 590 591 *rtc_1 = mlx5dr_cmd_rtc_create(ctx->ibv_ctx, &rtc_attr); 592 if (!*rtc_1) { 593 DR_LOG(ERR, "Failed to create peer matcher RTC of type %s", 594 mlx5dr_matcher_rtc_type_to_str(rtc_type)); 595 goto destroy_rtc_0; 596 } 597 } 598 599 return 0; 600 601 destroy_rtc_0: 602 mlx5dr_cmd_destroy_obj(*rtc_0); 603 free_ste: 604 if (rtc_type == DR_MATCHER_RTC_TYPE_MATCH) 605 mlx5dr_pool_chunk_free(ste_pool, ste); 606 return rte_errno; 607 } 608 609 static void mlx5dr_matcher_destroy_rtc(struct mlx5dr_matcher *matcher, 610 enum mlx5dr_matcher_rtc_type rtc_type) 611 { 612 struct mlx5dr_table *tbl = matcher->tbl; 613 struct mlx5dr_devx_obj *rtc_0, *rtc_1; 614 struct mlx5dr_pool_chunk *ste; 615 struct mlx5dr_pool *ste_pool; 616 617 switch (rtc_type) { 618 case DR_MATCHER_RTC_TYPE_MATCH: 619 rtc_0 = matcher->match_ste.rtc_0; 620 rtc_1 = matcher->match_ste.rtc_1; 621 ste_pool = matcher->match_ste.pool; 622 ste = &matcher->match_ste.ste; 623 break; 624 case DR_MATCHER_RTC_TYPE_STE_ARRAY: 625 rtc_0 = matcher->action_ste.rtc_0; 626 rtc_1 = matcher->action_ste.rtc_1; 627 ste_pool = matcher->action_ste.pool; 628 ste = &matcher->action_ste.ste; 629 break; 630 default: 631 return; 632 } 633 634 if (tbl->type == MLX5DR_TABLE_TYPE_FDB) 635 mlx5dr_cmd_destroy_obj(rtc_1); 636 637 mlx5dr_cmd_destroy_obj(rtc_0); 638 if (rtc_type == DR_MATCHER_RTC_TYPE_MATCH) 639 mlx5dr_pool_chunk_free(ste_pool, ste); 640 } 641 642 static int 643 mlx5dr_matcher_check_attr_sz(struct mlx5dr_cmd_query_caps *caps, 644 struct mlx5dr_matcher_attr *attr) 645 { 646 if (attr->table.sz_col_log > caps->rtc_log_depth_max) { 647 DR_LOG(ERR, "Matcher depth exceeds limit %d", caps->rtc_log_depth_max); 648 goto not_supported; 649 } 650 651 if (attr->table.sz_col_log + attr->table.sz_row_log > caps->ste_alloc_log_max) { 652 DR_LOG(ERR, "Total matcher size exceeds limit %d", caps->ste_alloc_log_max); 653 goto not_supported; 654 } 655 656 if (attr->table.sz_col_log + attr->table.sz_row_log < caps->ste_alloc_log_gran) { 657 DR_LOG(ERR, "Total matcher size below limit %d", caps->ste_alloc_log_gran); 658 goto not_supported; 659 } 660 661 return 0; 662 663 not_supported: 664 rte_errno = EOPNOTSUPP; 665 return rte_errno; 666 } 667 668 static void mlx5dr_matcher_set_pool_attr(struct mlx5dr_pool_attr *attr, 669 struct mlx5dr_matcher *matcher) 670 { 671 switch (matcher->attr.optimize_flow_src) { 672 case MLX5DR_MATCHER_FLOW_SRC_VPORT: 673 attr->opt_type = MLX5DR_POOL_OPTIMIZE_ORIG; 674 break; 675 case MLX5DR_MATCHER_FLOW_SRC_WIRE: 676 attr->opt_type = MLX5DR_POOL_OPTIMIZE_MIRROR; 677 break; 678 default: 679 break; 680 } 681 } 682 683 static int mlx5dr_matcher_bind_at(struct mlx5dr_matcher *matcher) 684 { 685 bool is_jumbo = mlx5dr_matcher_mt_is_jumbo(matcher->mt); 686 struct mlx5dr_cmd_stc_modify_attr stc_attr = {0}; 687 struct mlx5dr_table *tbl = matcher->tbl; 688 struct mlx5dr_pool_attr pool_attr = {0}; 689 struct mlx5dr_context *ctx = tbl->ctx; 690 uint32_t required_stes; 691 int i, ret; 692 bool valid; 693 694 for (i = 0; i < matcher->num_of_at; i++) { 695 struct mlx5dr_action_template *at = &matcher->at[i]; 696 697 /* Check if action combinabtion is valid */ 698 valid = mlx5dr_action_check_combo(at->action_type_arr, matcher->tbl->type); 699 if (!valid) { 700 DR_LOG(ERR, "Invalid combination in action template %d", i); 701 return rte_errno; 702 } 703 704 /* Process action template to setters */ 705 ret = mlx5dr_action_template_process(at); 706 if (ret) { 707 DR_LOG(ERR, "Failed to process action template %d", i); 708 return rte_errno; 709 } 710 711 required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term); 712 matcher->action_ste.max_stes = RTE_MAX(matcher->action_ste.max_stes, required_stes); 713 714 /* Future: Optimize reparse */ 715 } 716 717 /* There are no additioanl STEs required for matcher */ 718 if (!matcher->action_ste.max_stes) 719 return 0; 720 721 if (mlx5dr_matcher_req_fw_wqe(matcher)) { 722 DR_LOG(ERR, "FW extended matcher cannot be binded to complex at"); 723 rte_errno = ENOTSUP; 724 return rte_errno; 725 } 726 727 /* Allocate action STE mempool */ 728 pool_attr.table_type = tbl->type; 729 pool_attr.pool_type = MLX5DR_POOL_TYPE_STE; 730 pool_attr.flags = MLX5DR_POOL_FLAGS_FOR_STE_ACTION_POOL; 731 pool_attr.alloc_log_sz = rte_log2_u32(matcher->action_ste.max_stes) + 732 matcher->attr.table.sz_row_log; 733 mlx5dr_matcher_set_pool_attr(&pool_attr, matcher); 734 matcher->action_ste.pool = mlx5dr_pool_create(ctx, &pool_attr); 735 if (!matcher->action_ste.pool) { 736 DR_LOG(ERR, "Failed to create action ste pool"); 737 return rte_errno; 738 } 739 740 /* Allocate action RTC */ 741 ret = mlx5dr_matcher_create_rtc(matcher, DR_MATCHER_RTC_TYPE_STE_ARRAY); 742 if (ret) { 743 DR_LOG(ERR, "Failed to create action RTC"); 744 goto free_ste_pool; 745 } 746 747 /* Allocate STC for jumps to STE */ 748 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT; 749 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE; 750 stc_attr.ste_table.ste = matcher->action_ste.ste; 751 stc_attr.ste_table.ste_pool = matcher->action_ste.pool; 752 stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer; 753 754 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl->type, 755 &matcher->action_ste.stc); 756 if (ret) { 757 DR_LOG(ERR, "Failed to create action jump to table STC"); 758 goto free_rtc; 759 } 760 761 return 0; 762 763 free_rtc: 764 mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_STE_ARRAY); 765 free_ste_pool: 766 mlx5dr_pool_destroy(matcher->action_ste.pool); 767 return rte_errno; 768 } 769 770 static void mlx5dr_matcher_unbind_at(struct mlx5dr_matcher *matcher) 771 { 772 struct mlx5dr_table *tbl = matcher->tbl; 773 774 if (!matcher->action_ste.max_stes) 775 return; 776 777 mlx5dr_action_free_single_stc(tbl->ctx, tbl->type, &matcher->action_ste.stc); 778 mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_STE_ARRAY); 779 mlx5dr_pool_destroy(matcher->action_ste.pool); 780 } 781 782 static int mlx5dr_matcher_bind_mt(struct mlx5dr_matcher *matcher) 783 { 784 struct mlx5dr_context *ctx = matcher->tbl->ctx; 785 struct mlx5dr_pool_attr pool_attr = {0}; 786 int ret; 787 788 /* Calculate match, range and hash definers */ 789 ret = mlx5dr_definer_matcher_init(ctx, matcher); 790 if (ret) { 791 DR_LOG(ERR, "Failed to set matcher templates with match definers"); 792 return ret; 793 } 794 795 if (mlx5dr_matcher_req_fw_wqe(matcher) && 796 !mlx5dr_matcher_supp_fw_wqe(matcher)) { 797 DR_LOG(ERR, "Matcher requires FW WQE which is not supported"); 798 rte_errno = ENOTSUP; 799 ret = rte_errno; 800 goto uninit_match_definer; 801 } 802 803 /* Create an STE pool per matcher*/ 804 pool_attr.table_type = matcher->tbl->type; 805 pool_attr.pool_type = MLX5DR_POOL_TYPE_STE; 806 pool_attr.flags = MLX5DR_POOL_FLAGS_FOR_MATCHER_STE_POOL; 807 pool_attr.alloc_log_sz = matcher->attr.table.sz_col_log + 808 matcher->attr.table.sz_row_log; 809 /* Add additional rows due to additional range STE */ 810 if (matcher->flags & MLX5DR_MATCHER_FLAGS_RANGE_DEFINER) 811 pool_attr.alloc_log_sz++; 812 mlx5dr_matcher_set_pool_attr(&pool_attr, matcher); 813 814 matcher->match_ste.pool = mlx5dr_pool_create(ctx, &pool_attr); 815 if (!matcher->match_ste.pool) { 816 DR_LOG(ERR, "Failed to allocate matcher STE pool"); 817 ret = ENOTSUP; 818 goto uninit_match_definer; 819 } 820 821 return 0; 822 823 uninit_match_definer: 824 mlx5dr_definer_matcher_uninit(matcher); 825 return ret; 826 } 827 828 static void mlx5dr_matcher_unbind_mt(struct mlx5dr_matcher *matcher) 829 { 830 mlx5dr_pool_destroy(matcher->match_ste.pool); 831 mlx5dr_definer_matcher_uninit(matcher); 832 } 833 834 static int 835 mlx5dr_matcher_validate_insert_mode(struct mlx5dr_cmd_query_caps *caps, 836 struct mlx5dr_matcher *matcher, 837 bool is_root) 838 { 839 struct mlx5dr_matcher_attr *attr = &matcher->attr; 840 841 if (is_root) { 842 if (attr->mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE) { 843 DR_LOG(ERR, "Root matcher supports only rule resource mode"); 844 goto not_supported; 845 } 846 if (attr->insert_mode != MLX5DR_MATCHER_INSERT_BY_HASH) { 847 DR_LOG(ERR, "Root matcher supports only insert by hash mode"); 848 goto not_supported; 849 } 850 if (attr->distribute_mode != MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) { 851 DR_LOG(ERR, "Root matcher supports only distribute by hash mode"); 852 goto not_supported; 853 } 854 if (attr->optimize_flow_src) { 855 DR_LOG(ERR, "Root matcher can't specify FDB direction"); 856 goto not_supported; 857 } 858 } 859 860 switch (attr->insert_mode) { 861 case MLX5DR_MATCHER_INSERT_BY_HASH: 862 if (matcher->attr.distribute_mode != MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) { 863 DR_LOG(ERR, "Invalid matcher distribute mode"); 864 goto not_supported; 865 } 866 break; 867 868 case MLX5DR_MATCHER_INSERT_BY_INDEX: 869 if (attr->table.sz_col_log) { 870 DR_LOG(ERR, "Matcher with INSERT_BY_INDEX supports only Nx1 table size"); 871 goto not_supported; 872 } 873 874 if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) { 875 /* Hash Split Table */ 876 if (!caps->rtc_hash_split_table) { 877 DR_LOG(ERR, "FW doesn't support insert by index and hash distribute"); 878 goto not_supported; 879 } 880 } else if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_LINEAR) { 881 /* Linear Lookup Table */ 882 if (!caps->rtc_linear_lookup_table || 883 !IS_BIT_SET(caps->access_index_mode, 884 MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR)) { 885 DR_LOG(ERR, "FW doesn't support insert by index and linear distribute"); 886 goto not_supported; 887 } 888 889 if (attr->table.sz_row_log > MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX) { 890 DR_LOG(ERR, "Matcher with linear distribute: rows exceed limit %d", 891 MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX); 892 goto not_supported; 893 } 894 } else { 895 DR_LOG(ERR, "Matcher has unsupported distribute mode"); 896 goto not_supported; 897 } 898 break; 899 900 default: 901 DR_LOG(ERR, "Matcher has unsupported insert mode"); 902 goto not_supported; 903 } 904 905 return 0; 906 907 not_supported: 908 rte_errno = EOPNOTSUPP; 909 return rte_errno; 910 } 911 912 static int 913 mlx5dr_matcher_process_attr(struct mlx5dr_cmd_query_caps *caps, 914 struct mlx5dr_matcher *matcher, 915 bool is_root) 916 { 917 struct mlx5dr_matcher_attr *attr = &matcher->attr; 918 919 if (mlx5dr_matcher_validate_insert_mode(caps, matcher, is_root)) 920 goto not_supported; 921 922 if (is_root) { 923 if (attr->optimize_flow_src) { 924 DR_LOG(ERR, "Root matcher can't specify FDB direction"); 925 goto not_supported; 926 } 927 return 0; 928 } 929 930 if (matcher->tbl->type != MLX5DR_TABLE_TYPE_FDB && attr->optimize_flow_src) { 931 DR_LOG(ERR, "NIC domain doesn't support flow_src"); 932 goto not_supported; 933 } 934 935 /* Convert number of rules to the required depth */ 936 if (attr->mode == MLX5DR_MATCHER_RESOURCE_MODE_RULE && 937 attr->insert_mode == MLX5DR_MATCHER_INSERT_BY_HASH) 938 attr->table.sz_col_log = mlx5dr_matcher_rules_to_tbl_depth(attr->rule.num_log); 939 940 return mlx5dr_matcher_check_attr_sz(caps, attr); 941 942 not_supported: 943 rte_errno = EOPNOTSUPP; 944 return rte_errno; 945 } 946 947 static int mlx5dr_matcher_create_and_connect(struct mlx5dr_matcher *matcher) 948 { 949 int ret; 950 951 /* Select and create the definers for current matcher */ 952 ret = mlx5dr_matcher_bind_mt(matcher); 953 if (ret) 954 return ret; 955 956 /* Calculate and verify action combination */ 957 ret = mlx5dr_matcher_bind_at(matcher); 958 if (ret) 959 goto unbind_mt; 960 961 /* Create matcher end flow table anchor */ 962 ret = mlx5dr_matcher_create_end_ft(matcher); 963 if (ret) 964 goto unbind_at; 965 966 /* Allocate the RTC for the new matcher */ 967 ret = mlx5dr_matcher_create_rtc(matcher, DR_MATCHER_RTC_TYPE_MATCH); 968 if (ret) 969 goto destroy_end_ft; 970 971 /* Allocate and set shared resources */ 972 ret = mlx5dr_matcher_create_init_shared(matcher); 973 if (ret) 974 goto destroy_rtc; 975 976 /* Connect the matcher to the matcher list */ 977 ret = mlx5dr_matcher_connect(matcher); 978 if (ret) 979 goto destroy_shared; 980 981 return 0; 982 983 destroy_shared: 984 mlx5dr_matcher_create_uninit_shared(matcher); 985 destroy_rtc: 986 mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_MATCH); 987 destroy_end_ft: 988 mlx5dr_matcher_destroy_end_ft(matcher); 989 unbind_at: 990 mlx5dr_matcher_unbind_at(matcher); 991 unbind_mt: 992 mlx5dr_matcher_unbind_mt(matcher); 993 return ret; 994 } 995 996 static void mlx5dr_matcher_destroy_and_disconnect(struct mlx5dr_matcher *matcher) 997 { 998 mlx5dr_matcher_disconnect(matcher); 999 mlx5dr_matcher_create_uninit_shared(matcher); 1000 mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_MATCH); 1001 mlx5dr_matcher_destroy_end_ft(matcher); 1002 mlx5dr_matcher_unbind_at(matcher); 1003 mlx5dr_matcher_unbind_mt(matcher); 1004 } 1005 1006 static int 1007 mlx5dr_matcher_create_col_matcher(struct mlx5dr_matcher *matcher) 1008 { 1009 struct mlx5dr_context *ctx = matcher->tbl->ctx; 1010 struct mlx5dr_matcher *col_matcher; 1011 int ret; 1012 1013 if (matcher->attr.mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE || 1014 matcher->attr.insert_mode == MLX5DR_MATCHER_INSERT_BY_INDEX) 1015 return 0; 1016 1017 if (!mlx5dr_matcher_requires_col_tbl(matcher->attr.rule.num_log)) 1018 return 0; 1019 1020 col_matcher = simple_calloc(1, sizeof(*matcher)); 1021 if (!col_matcher) { 1022 rte_errno = ENOMEM; 1023 return rte_errno; 1024 } 1025 1026 col_matcher->tbl = matcher->tbl; 1027 col_matcher->mt = matcher->mt; 1028 col_matcher->at = matcher->at; 1029 col_matcher->num_of_at = matcher->num_of_at; 1030 col_matcher->num_of_mt = matcher->num_of_mt; 1031 col_matcher->hash_definer = matcher->hash_definer; 1032 col_matcher->attr.priority = matcher->attr.priority; 1033 col_matcher->flags = matcher->flags; 1034 col_matcher->flags |= MLX5DR_MATCHER_FLAGS_COLLISION; 1035 col_matcher->attr.mode = MLX5DR_MATCHER_RESOURCE_MODE_HTABLE; 1036 col_matcher->attr.optimize_flow_src = matcher->attr.optimize_flow_src; 1037 col_matcher->attr.table.sz_row_log = matcher->attr.rule.num_log; 1038 col_matcher->attr.table.sz_col_log = MLX5DR_MATCHER_ASSURED_COL_TBL_DEPTH; 1039 if (col_matcher->attr.table.sz_row_log > MLX5DR_MATCHER_ASSURED_ROW_RATIO) 1040 col_matcher->attr.table.sz_row_log -= MLX5DR_MATCHER_ASSURED_ROW_RATIO; 1041 1042 ret = mlx5dr_matcher_process_attr(ctx->caps, col_matcher, false); 1043 if (ret) 1044 goto free_col_matcher; 1045 1046 ret = mlx5dr_matcher_create_and_connect(col_matcher); 1047 if (ret) 1048 goto free_col_matcher; 1049 1050 matcher->col_matcher = col_matcher; 1051 1052 return 0; 1053 1054 free_col_matcher: 1055 simple_free(col_matcher); 1056 DR_LOG(ERR, "Failed to create assured collision matcher"); 1057 return ret; 1058 } 1059 1060 static void 1061 mlx5dr_matcher_destroy_col_matcher(struct mlx5dr_matcher *matcher) 1062 { 1063 if (matcher->attr.mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE || 1064 matcher->attr.insert_mode == MLX5DR_MATCHER_INSERT_BY_INDEX) 1065 return; 1066 1067 if (matcher->col_matcher) { 1068 mlx5dr_matcher_destroy_and_disconnect(matcher->col_matcher); 1069 simple_free(matcher->col_matcher); 1070 } 1071 } 1072 1073 static int mlx5dr_matcher_init(struct mlx5dr_matcher *matcher) 1074 { 1075 struct mlx5dr_context *ctx = matcher->tbl->ctx; 1076 int ret; 1077 1078 pthread_spin_lock(&ctx->ctrl_lock); 1079 1080 /* Allocate matcher resource and connect to the packet pipe */ 1081 ret = mlx5dr_matcher_create_and_connect(matcher); 1082 if (ret) 1083 goto unlock_err; 1084 1085 /* Create additional matcher for collision handling */ 1086 ret = mlx5dr_matcher_create_col_matcher(matcher); 1087 if (ret) 1088 goto destory_and_disconnect; 1089 1090 pthread_spin_unlock(&ctx->ctrl_lock); 1091 1092 return 0; 1093 1094 destory_and_disconnect: 1095 mlx5dr_matcher_destroy_and_disconnect(matcher); 1096 unlock_err: 1097 pthread_spin_unlock(&ctx->ctrl_lock); 1098 return ret; 1099 } 1100 1101 static int mlx5dr_matcher_uninit(struct mlx5dr_matcher *matcher) 1102 { 1103 struct mlx5dr_context *ctx = matcher->tbl->ctx; 1104 1105 pthread_spin_lock(&ctx->ctrl_lock); 1106 mlx5dr_matcher_destroy_col_matcher(matcher); 1107 mlx5dr_matcher_destroy_and_disconnect(matcher); 1108 pthread_spin_unlock(&ctx->ctrl_lock); 1109 1110 return 0; 1111 } 1112 1113 static int mlx5dr_matcher_init_root(struct mlx5dr_matcher *matcher) 1114 { 1115 enum mlx5dr_table_type type = matcher->tbl->type; 1116 struct mlx5dr_context *ctx = matcher->tbl->ctx; 1117 struct mlx5dv_flow_matcher_attr attr = {0}; 1118 struct mlx5dv_flow_match_parameters *mask; 1119 struct mlx5_flow_attr flow_attr = {0}; 1120 struct rte_flow_error rte_error; 1121 uint8_t match_criteria; 1122 int ret; 1123 1124 #ifdef HAVE_MLX5DV_FLOW_MATCHER_FT_TYPE 1125 attr.comp_mask = MLX5DV_FLOW_MATCHER_MASK_FT_TYPE; 1126 1127 switch (type) { 1128 case MLX5DR_TABLE_TYPE_NIC_RX: 1129 attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 1130 break; 1131 case MLX5DR_TABLE_TYPE_NIC_TX: 1132 attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX; 1133 break; 1134 case MLX5DR_TABLE_TYPE_FDB: 1135 attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 1136 break; 1137 default: 1138 assert(0); 1139 break; 1140 } 1141 #endif 1142 1143 if (matcher->attr.priority > UINT16_MAX) { 1144 DR_LOG(ERR, "Root matcher priority exceeds allowed limit"); 1145 rte_errno = EINVAL; 1146 return rte_errno; 1147 } 1148 1149 mask = simple_calloc(1, MLX5_ST_SZ_BYTES(fte_match_param) + 1150 offsetof(struct mlx5dv_flow_match_parameters, match_buf)); 1151 if (!mask) { 1152 rte_errno = ENOMEM; 1153 return rte_errno; 1154 } 1155 1156 flow_attr.tbl_type = type; 1157 1158 /* On root table matcher, only a single match template is supported */ 1159 ret = flow_dv_translate_items_hws(matcher->mt[0].items, 1160 &flow_attr, mask->match_buf, 1161 MLX5_SET_MATCHER_HS_M, NULL, 1162 &match_criteria, 1163 &rte_error); 1164 if (ret) { 1165 DR_LOG(ERR, "Failed to convert items to PRM [%s]", rte_error.message); 1166 goto free_mask; 1167 } 1168 1169 mask->match_sz = MLX5_ST_SZ_BYTES(fte_match_param); 1170 attr.match_mask = mask; 1171 attr.match_criteria_enable = match_criteria; 1172 attr.type = IBV_FLOW_ATTR_NORMAL; 1173 attr.priority = matcher->attr.priority; 1174 1175 matcher->dv_matcher = 1176 mlx5_glue->dv_create_flow_matcher_root(mlx5dr_context_get_local_ibv(ctx), 1177 &attr); 1178 if (!matcher->dv_matcher) { 1179 DR_LOG(ERR, "Failed to create DV flow matcher"); 1180 rte_errno = errno; 1181 goto free_mask; 1182 } 1183 1184 simple_free(mask); 1185 1186 pthread_spin_lock(&ctx->ctrl_lock); 1187 LIST_INSERT_HEAD(&matcher->tbl->head, matcher, next); 1188 pthread_spin_unlock(&ctx->ctrl_lock); 1189 1190 return 0; 1191 1192 free_mask: 1193 simple_free(mask); 1194 return rte_errno; 1195 } 1196 1197 static int mlx5dr_matcher_uninit_root(struct mlx5dr_matcher *matcher) 1198 { 1199 struct mlx5dr_context *ctx = matcher->tbl->ctx; 1200 int ret; 1201 1202 pthread_spin_lock(&ctx->ctrl_lock); 1203 LIST_REMOVE(matcher, next); 1204 pthread_spin_unlock(&ctx->ctrl_lock); 1205 1206 ret = mlx5_glue->dv_destroy_flow_matcher_root(matcher->dv_matcher); 1207 if (ret) { 1208 DR_LOG(ERR, "Failed to Destroy DV flow matcher"); 1209 rte_errno = errno; 1210 } 1211 1212 return ret; 1213 } 1214 1215 static int 1216 mlx5dr_matcher_set_templates(struct mlx5dr_matcher *matcher, 1217 struct mlx5dr_match_template *mt[], 1218 uint8_t num_of_mt, 1219 struct mlx5dr_action_template *at[], 1220 uint8_t num_of_at) 1221 { 1222 bool is_root = mlx5dr_table_is_root(matcher->tbl); 1223 int i; 1224 1225 if (!num_of_mt || !num_of_at) { 1226 DR_LOG(ERR, "Number of action/match template cannot be zero"); 1227 rte_errno = ENOTSUP; 1228 return rte_errno; 1229 } 1230 1231 if (is_root && num_of_mt > MLX5DR_MATCHER_MAX_MT_ROOT) { 1232 DR_LOG(ERR, "Number of match templates exceeds limit"); 1233 rte_errno = ENOTSUP; 1234 return rte_errno; 1235 } 1236 1237 matcher->mt = simple_calloc(num_of_mt, sizeof(*matcher->mt)); 1238 if (!matcher->mt) { 1239 DR_LOG(ERR, "Failed to allocate match template array"); 1240 rte_errno = ENOMEM; 1241 return rte_errno; 1242 } 1243 1244 matcher->at = simple_calloc(num_of_at, sizeof(*matcher->at)); 1245 if (!matcher->at) { 1246 DR_LOG(ERR, "Failed to allocate action template array"); 1247 rte_errno = ENOMEM; 1248 goto free_mt; 1249 } 1250 1251 for (i = 0; i < num_of_mt; i++) 1252 matcher->mt[i] = *mt[i]; 1253 1254 for (i = 0; i < num_of_at; i++) 1255 matcher->at[i] = *at[i]; 1256 1257 matcher->num_of_mt = num_of_mt; 1258 matcher->num_of_at = num_of_at; 1259 1260 return 0; 1261 1262 free_mt: 1263 simple_free(matcher->mt); 1264 return rte_errno; 1265 } 1266 1267 static void 1268 mlx5dr_matcher_unset_templates(struct mlx5dr_matcher *matcher) 1269 { 1270 simple_free(matcher->at); 1271 simple_free(matcher->mt); 1272 } 1273 1274 struct mlx5dr_matcher * 1275 mlx5dr_matcher_create(struct mlx5dr_table *tbl, 1276 struct mlx5dr_match_template *mt[], 1277 uint8_t num_of_mt, 1278 struct mlx5dr_action_template *at[], 1279 uint8_t num_of_at, 1280 struct mlx5dr_matcher_attr *attr) 1281 { 1282 bool is_root = mlx5dr_table_is_root(tbl); 1283 struct mlx5dr_matcher *matcher; 1284 int ret; 1285 1286 matcher = simple_calloc(1, sizeof(*matcher)); 1287 if (!matcher) { 1288 rte_errno = ENOMEM; 1289 return NULL; 1290 } 1291 1292 matcher->tbl = tbl; 1293 matcher->attr = *attr; 1294 1295 ret = mlx5dr_matcher_process_attr(tbl->ctx->caps, matcher, is_root); 1296 if (ret) 1297 goto free_matcher; 1298 1299 ret = mlx5dr_matcher_set_templates(matcher, mt, num_of_mt, at, num_of_at); 1300 if (ret) 1301 goto free_matcher; 1302 1303 if (is_root) 1304 ret = mlx5dr_matcher_init_root(matcher); 1305 else 1306 ret = mlx5dr_matcher_init(matcher); 1307 1308 if (ret) { 1309 DR_LOG(ERR, "Failed to initialise matcher: %d", ret); 1310 goto unset_templates; 1311 } 1312 1313 return matcher; 1314 1315 unset_templates: 1316 mlx5dr_matcher_unset_templates(matcher); 1317 free_matcher: 1318 simple_free(matcher); 1319 return NULL; 1320 } 1321 1322 int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher) 1323 { 1324 if (mlx5dr_table_is_root(matcher->tbl)) 1325 mlx5dr_matcher_uninit_root(matcher); 1326 else 1327 mlx5dr_matcher_uninit(matcher); 1328 1329 mlx5dr_matcher_unset_templates(matcher); 1330 simple_free(matcher); 1331 return 0; 1332 } 1333 1334 struct mlx5dr_match_template * 1335 mlx5dr_match_template_create(const struct rte_flow_item items[], 1336 enum mlx5dr_match_template_flags flags) 1337 { 1338 struct mlx5dr_match_template *mt; 1339 struct rte_flow_error error; 1340 int ret, len; 1341 1342 if (flags > MLX5DR_MATCH_TEMPLATE_FLAG_RELAXED_MATCH) { 1343 DR_LOG(ERR, "Unsupported match template flag provided"); 1344 rte_errno = EINVAL; 1345 return NULL; 1346 } 1347 1348 mt = simple_calloc(1, sizeof(*mt)); 1349 if (!mt) { 1350 DR_LOG(ERR, "Failed to allocate match template"); 1351 rte_errno = ENOMEM; 1352 return NULL; 1353 } 1354 1355 mt->flags = flags; 1356 1357 /* Duplicate the user given items */ 1358 ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN, NULL, 0, items, &error); 1359 if (ret <= 0) { 1360 DR_LOG(ERR, "Unable to process items (%s): %s", 1361 error.message ? error.message : "unspecified", 1362 strerror(rte_errno)); 1363 goto free_template; 1364 } 1365 1366 len = RTE_ALIGN(ret, 16); 1367 mt->items = simple_calloc(1, len); 1368 if (!mt->items) { 1369 DR_LOG(ERR, "Failed to allocate item copy"); 1370 rte_errno = ENOMEM; 1371 goto free_template; 1372 } 1373 1374 ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN, mt->items, ret, items, &error); 1375 if (ret <= 0) 1376 goto free_dst; 1377 1378 return mt; 1379 1380 free_dst: 1381 simple_free(mt->items); 1382 free_template: 1383 simple_free(mt); 1384 return NULL; 1385 } 1386 1387 int mlx5dr_match_template_destroy(struct mlx5dr_match_template *mt) 1388 { 1389 simple_free(mt->items); 1390 simple_free(mt); 1391 return 0; 1392 } 1393