1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2022 NVIDIA Corporation & Affiliates 3 */ 4 5 #include "mlx5dr_internal.h" 6 7 static void mlx5dr_table_init_next_ft_attr(struct mlx5dr_table *tbl, 8 struct mlx5dr_cmd_ft_create_attr *ft_attr) 9 { 10 ft_attr->type = tbl->fw_ft_type; 11 if (tbl->type == MLX5DR_TABLE_TYPE_FDB) 12 ft_attr->level = tbl->ctx->caps->fdb_ft.max_level - 1; 13 else 14 ft_attr->level = tbl->ctx->caps->nic_ft.max_level - 1; 15 ft_attr->rtc_valid = true; 16 } 17 18 /* Call this under ctx->ctrl_lock */ 19 static int 20 mlx5dr_table_up_default_fdb_miss_tbl(struct mlx5dr_table *tbl) 21 { 22 struct mlx5dr_cmd_ft_create_attr ft_attr = {0}; 23 struct mlx5dr_cmd_set_fte_attr fte_attr = {0}; 24 struct mlx5dr_cmd_forward_tbl *default_miss; 25 struct mlx5dr_cmd_set_fte_dest dest = {0}; 26 struct mlx5dr_context *ctx = tbl->ctx; 27 uint8_t tbl_type = tbl->type; 28 29 if (tbl->type != MLX5DR_TABLE_TYPE_FDB) 30 return 0; 31 32 if (ctx->common_res[tbl_type].default_miss) { 33 ctx->common_res[tbl_type].default_miss->refcount++; 34 return 0; 35 } 36 37 ft_attr.type = tbl->fw_ft_type; 38 ft_attr.level = tbl->ctx->caps->fdb_ft.max_level; /* The last level */ 39 ft_attr.rtc_valid = false; 40 41 dest.destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT; 42 dest.destination_id = ctx->caps->eswitch_manager_vport_number; 43 fte_attr.action_flags = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 44 fte_attr.dests_num = 1; 45 fte_attr.dests = &dest; 46 47 default_miss = mlx5dr_cmd_forward_tbl_create(mlx5dr_context_get_local_ibv(ctx), 48 &ft_attr, &fte_attr); 49 if (!default_miss) { 50 DR_LOG(ERR, "Failed to default miss table type: 0x%x", tbl_type); 51 return rte_errno; 52 } 53 54 ctx->common_res[tbl_type].default_miss = default_miss; 55 ctx->common_res[tbl_type].default_miss->refcount++; 56 return 0; 57 } 58 59 /* Called under pthread_spin_lock(&ctx->ctrl_lock) */ 60 static void mlx5dr_table_down_default_fdb_miss_tbl(struct mlx5dr_table *tbl) 61 { 62 struct mlx5dr_cmd_forward_tbl *default_miss; 63 struct mlx5dr_context *ctx = tbl->ctx; 64 uint8_t tbl_type = tbl->type; 65 66 if (tbl->type != MLX5DR_TABLE_TYPE_FDB) 67 return; 68 69 default_miss = ctx->common_res[tbl_type].default_miss; 70 if (--default_miss->refcount) 71 return; 72 73 mlx5dr_cmd_forward_tbl_destroy(default_miss); 74 ctx->common_res[tbl_type].default_miss = NULL; 75 } 76 77 static int 78 mlx5dr_table_connect_to_default_miss_tbl(struct mlx5dr_table *tbl, 79 struct mlx5dr_devx_obj *ft) 80 { 81 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 82 int ret; 83 84 assert(tbl->type == MLX5DR_TABLE_TYPE_FDB); 85 86 mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx, 87 tbl->fw_ft_type, 88 tbl->type, 89 &ft_attr); 90 91 /* Connect to next */ 92 ret = mlx5dr_cmd_flow_table_modify(ft, &ft_attr); 93 if (ret) { 94 DR_LOG(ERR, "Failed to connect FT to default FDB FT"); 95 return ret; 96 } 97 98 return 0; 99 } 100 101 struct mlx5dr_devx_obj * 102 mlx5dr_table_create_default_ft(struct ibv_context *ibv, 103 struct mlx5dr_table *tbl) 104 { 105 struct mlx5dr_cmd_ft_create_attr ft_attr = {0}; 106 struct mlx5dr_devx_obj *ft_obj; 107 int ret; 108 109 mlx5dr_table_init_next_ft_attr(tbl, &ft_attr); 110 111 ft_obj = mlx5dr_cmd_flow_table_create(ibv, &ft_attr); 112 if (ft_obj && tbl->type == MLX5DR_TABLE_TYPE_FDB) { 113 /* Take/create ref over the default miss */ 114 ret = mlx5dr_table_up_default_fdb_miss_tbl(tbl); 115 if (ret) { 116 DR_LOG(ERR, "Failed to get default fdb miss"); 117 goto free_ft_obj; 118 } 119 ret = mlx5dr_table_connect_to_default_miss_tbl(tbl, ft_obj); 120 if (ret) { 121 DR_LOG(ERR, "Failed connecting to default miss tbl"); 122 goto down_miss_tbl; 123 } 124 } 125 126 return ft_obj; 127 128 down_miss_tbl: 129 mlx5dr_table_down_default_fdb_miss_tbl(tbl); 130 free_ft_obj: 131 mlx5dr_cmd_destroy_obj(ft_obj); 132 return NULL; 133 } 134 135 static int 136 mlx5dr_table_init_check_hws_support(struct mlx5dr_context *ctx, 137 struct mlx5dr_table *tbl) 138 { 139 if (!(ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT)) { 140 DR_LOG(ERR, "HWS not supported, cannot create mlx5dr_table"); 141 rte_errno = EOPNOTSUPP; 142 return rte_errno; 143 } 144 145 if (mlx5dr_context_shared_gvmi_used(ctx) && tbl->type == MLX5DR_TABLE_TYPE_FDB) { 146 DR_LOG(ERR, "FDB with shared port resources is not supported"); 147 rte_errno = EOPNOTSUPP; 148 return rte_errno; 149 } 150 151 return 0; 152 } 153 154 static int 155 mlx5dr_table_shared_gvmi_resource_create(struct mlx5dr_context *ctx, 156 enum mlx5dr_table_type type, 157 struct mlx5dr_context_shared_gvmi_res *gvmi_res) 158 { 159 struct mlx5dr_cmd_ft_create_attr ft_attr = {0}; 160 uint32_t calculated_ft_id; 161 int ret; 162 163 if (!mlx5dr_context_shared_gvmi_used(ctx)) 164 return 0; 165 166 ft_attr.type = mlx5dr_table_get_res_fw_ft_type(type, false); 167 ft_attr.level = ctx->caps->nic_ft.max_level - 1; 168 ft_attr.rtc_valid = true; 169 170 gvmi_res->end_ft = 171 mlx5dr_cmd_flow_table_create(mlx5dr_context_get_local_ibv(ctx), 172 &ft_attr); 173 if (!gvmi_res->end_ft) { 174 DR_LOG(ERR, "Failed to create end-ft"); 175 return rte_errno; 176 } 177 178 calculated_ft_id = 179 mlx5dr_table_get_res_fw_ft_type(type, false) << FT_ID_FT_TYPE_OFFSET; 180 calculated_ft_id |= gvmi_res->end_ft->id; 181 182 /* create alias to that FT */ 183 ret = mlx5dr_matcher_create_aliased_obj(ctx, 184 ctx->local_ibv_ctx, 185 ctx->ibv_ctx, 186 ctx->caps->vhca_id, 187 calculated_ft_id, 188 MLX5_GENERAL_OBJ_TYPE_FT_ALIAS, 189 &gvmi_res->aliased_end_ft); 190 if (ret) { 191 DR_LOG(ERR, "Failed to create alias end-ft"); 192 goto free_end_ft; 193 } 194 195 return 0; 196 197 free_end_ft: 198 mlx5dr_cmd_destroy_obj(gvmi_res->end_ft); 199 200 return rte_errno; 201 } 202 203 static void 204 mlx5dr_table_shared_gvmi_resourse_destroy(struct mlx5dr_context *ctx, 205 struct mlx5dr_context_shared_gvmi_res *gvmi_res) 206 { 207 if (!mlx5dr_context_shared_gvmi_used(ctx)) 208 return; 209 210 if (gvmi_res->aliased_end_ft) { 211 mlx5dr_cmd_destroy_obj(gvmi_res->aliased_end_ft); 212 gvmi_res->aliased_end_ft = NULL; 213 } 214 if (gvmi_res->end_ft) { 215 mlx5dr_cmd_destroy_obj(gvmi_res->end_ft); 216 gvmi_res->end_ft = NULL; 217 } 218 } 219 220 /* called under spinlock ctx->ctrl_lock */ 221 static struct mlx5dr_context_shared_gvmi_res * 222 mlx5dr_table_get_shared_gvmi_res(struct mlx5dr_context *ctx, enum mlx5dr_table_type type) 223 { 224 int ret; 225 226 if (!mlx5dr_context_shared_gvmi_used(ctx)) 227 return NULL; 228 229 if (ctx->gvmi_res[type].aliased_end_ft) { 230 ctx->gvmi_res[type].refcount++; 231 return &ctx->gvmi_res[type]; 232 } 233 234 ret = mlx5dr_table_shared_gvmi_resource_create(ctx, type, &ctx->gvmi_res[type]); 235 if (ret) { 236 DR_LOG(ERR, "Failed to create shared gvmi res for type: %d", type); 237 goto out; 238 } 239 240 ctx->gvmi_res[type].refcount = 1; 241 242 return &ctx->gvmi_res[type]; 243 244 out: 245 return NULL; 246 } 247 248 /* called under spinlock ctx->ctrl_lock */ 249 static void mlx5dr_table_put_shared_gvmi_res(struct mlx5dr_table *tbl) 250 { 251 struct mlx5dr_context *ctx = tbl->ctx; 252 253 if (!mlx5dr_context_shared_gvmi_used(ctx)) 254 return; 255 256 if (--ctx->gvmi_res[tbl->type].refcount) 257 return; 258 259 mlx5dr_table_shared_gvmi_resourse_destroy(ctx, &ctx->gvmi_res[tbl->type]); 260 } 261 262 static void mlx5dr_table_uninit_shared_ctx_res(struct mlx5dr_table *tbl) 263 { 264 struct mlx5dr_context *ctx = tbl->ctx; 265 266 if (!mlx5dr_context_shared_gvmi_used(ctx)) 267 return; 268 269 mlx5dr_cmd_destroy_obj(tbl->local_ft); 270 271 mlx5dr_table_put_shared_gvmi_res(tbl); 272 } 273 274 /* called under spin_lock ctx->ctrl_lock */ 275 static int mlx5dr_table_init_shared_ctx_res(struct mlx5dr_context *ctx, struct mlx5dr_table *tbl) 276 { 277 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 278 int ret; 279 280 if (!mlx5dr_context_shared_gvmi_used(ctx)) 281 return 0; 282 283 /* create local-ft for root access */ 284 tbl->local_ft = 285 mlx5dr_table_create_default_ft(mlx5dr_context_get_local_ibv(ctx), tbl); 286 if (!tbl->local_ft) { 287 DR_LOG(ERR, "Failed to create local-ft"); 288 return rte_errno; 289 } 290 291 if (!mlx5dr_table_get_shared_gvmi_res(tbl->ctx, tbl->type)) { 292 DR_LOG(ERR, "Failed to shared gvmi resources"); 293 goto clean_local_ft; 294 } 295 296 /* On shared gvmi the default behavior is jump to alias end ft */ 297 mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx, 298 tbl->fw_ft_type, 299 tbl->type, 300 &ft_attr); 301 302 ret = mlx5dr_cmd_flow_table_modify(tbl->ft, &ft_attr); 303 if (ret) { 304 DR_LOG(ERR, "Failed to point table to its default miss"); 305 goto clean_shared_res; 306 } 307 308 return 0; 309 310 clean_shared_res: 311 mlx5dr_table_put_shared_gvmi_res(tbl); 312 clean_local_ft: 313 mlx5dr_table_destroy_default_ft(tbl, tbl->local_ft); 314 return rte_errno; 315 } 316 317 void mlx5dr_table_destroy_default_ft(struct mlx5dr_table *tbl, 318 struct mlx5dr_devx_obj *ft_obj) 319 { 320 mlx5dr_cmd_destroy_obj(ft_obj); 321 mlx5dr_table_down_default_fdb_miss_tbl(tbl); 322 } 323 324 static int mlx5dr_table_init(struct mlx5dr_table *tbl) 325 { 326 struct mlx5dr_context *ctx = tbl->ctx; 327 int ret; 328 329 if (mlx5dr_table_is_root(tbl)) 330 return 0; 331 332 ret = mlx5dr_table_init_check_hws_support(ctx, tbl); 333 if (ret) 334 return ret; 335 336 switch (tbl->type) { 337 case MLX5DR_TABLE_TYPE_NIC_RX: 338 tbl->fw_ft_type = FS_FT_NIC_RX; 339 break; 340 case MLX5DR_TABLE_TYPE_NIC_TX: 341 tbl->fw_ft_type = FS_FT_NIC_TX; 342 break; 343 case MLX5DR_TABLE_TYPE_FDB: 344 tbl->fw_ft_type = FS_FT_FDB; 345 break; 346 default: 347 assert(0); 348 break; 349 } 350 351 pthread_spin_lock(&ctx->ctrl_lock); 352 tbl->ft = mlx5dr_table_create_default_ft(tbl->ctx->ibv_ctx, tbl); 353 if (!tbl->ft) { 354 DR_LOG(ERR, "Failed to create flow table devx object"); 355 pthread_spin_unlock(&ctx->ctrl_lock); 356 return rte_errno; 357 } 358 359 ret = mlx5dr_table_init_shared_ctx_res(ctx, tbl); 360 if (ret) 361 goto tbl_destroy; 362 363 ret = mlx5dr_action_get_default_stc(ctx, tbl->type); 364 if (ret) 365 goto free_shared_ctx; 366 367 pthread_spin_unlock(&ctx->ctrl_lock); 368 369 return 0; 370 371 free_shared_ctx: 372 mlx5dr_table_uninit_shared_ctx_res(tbl); 373 tbl_destroy: 374 mlx5dr_table_destroy_default_ft(tbl, tbl->ft); 375 pthread_spin_unlock(&ctx->ctrl_lock); 376 return rte_errno; 377 } 378 379 static void mlx5dr_table_uninit(struct mlx5dr_table *tbl) 380 { 381 if (mlx5dr_table_is_root(tbl)) 382 return; 383 pthread_spin_lock(&tbl->ctx->ctrl_lock); 384 mlx5dr_action_put_default_stc(tbl->ctx, tbl->type); 385 mlx5dr_table_uninit_shared_ctx_res(tbl); 386 mlx5dr_table_destroy_default_ft(tbl, tbl->ft); 387 pthread_spin_unlock(&tbl->ctx->ctrl_lock); 388 } 389 390 struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_context *ctx, 391 struct mlx5dr_table_attr *attr) 392 { 393 struct mlx5dr_table *tbl; 394 int ret; 395 396 if (attr->type > MLX5DR_TABLE_TYPE_FDB) { 397 DR_LOG(ERR, "Invalid table type %d", attr->type); 398 return NULL; 399 } 400 401 tbl = simple_calloc(1, sizeof(*tbl)); 402 if (!tbl) { 403 rte_errno = ENOMEM; 404 return NULL; 405 } 406 407 tbl->ctx = ctx; 408 tbl->type = attr->type; 409 tbl->level = attr->level; 410 411 ret = mlx5dr_table_init(tbl); 412 if (ret) { 413 DR_LOG(ERR, "Failed to initialise table"); 414 goto free_tbl; 415 } 416 417 pthread_spin_lock(&ctx->ctrl_lock); 418 LIST_INSERT_HEAD(&ctx->head, tbl, next); 419 pthread_spin_unlock(&ctx->ctrl_lock); 420 421 return tbl; 422 423 free_tbl: 424 simple_free(tbl); 425 return NULL; 426 } 427 428 int mlx5dr_table_destroy(struct mlx5dr_table *tbl) 429 { 430 struct mlx5dr_context *ctx = tbl->ctx; 431 pthread_spin_lock(&ctx->ctrl_lock); 432 if (!LIST_EMPTY(&tbl->head) || !LIST_EMPTY(&tbl->isolated_matchers)) { 433 DR_LOG(ERR, "Cannot destroy table containing matchers"); 434 rte_errno = EBUSY; 435 goto unlock_err; 436 } 437 438 if (!LIST_EMPTY(&tbl->default_miss.head)) { 439 DR_LOG(ERR, "Cannot destroy table pointed by default miss"); 440 rte_errno = EBUSY; 441 goto unlock_err; 442 } 443 444 LIST_REMOVE(tbl, next); 445 pthread_spin_unlock(&ctx->ctrl_lock); 446 mlx5dr_table_uninit(tbl); 447 simple_free(tbl); 448 449 return 0; 450 451 unlock_err: 452 pthread_spin_unlock(&ctx->ctrl_lock); 453 return -rte_errno; 454 } 455 456 static struct mlx5dr_devx_obj * 457 mlx5dr_table_get_last_ft(struct mlx5dr_table *tbl) 458 { 459 struct mlx5dr_devx_obj *last_ft = tbl->ft; 460 struct mlx5dr_matcher *matcher; 461 462 LIST_FOREACH(matcher, &tbl->head, next) 463 last_ft = matcher->end_ft; 464 465 return last_ft; 466 } 467 468 int mlx5dr_table_ft_set_default_next_ft(struct mlx5dr_table *tbl, 469 struct mlx5dr_devx_obj *ft_obj) 470 { 471 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 472 int ret; 473 474 /* Due to FW limitation, resetting the flow table to default action will 475 * disconnect RTC when ignore_flow_level_rtc_valid is not supported. 476 */ 477 if (!tbl->ctx->caps->nic_ft.ignore_flow_level_rtc_valid) 478 return 0; 479 480 if (tbl->type == MLX5DR_TABLE_TYPE_FDB) 481 return mlx5dr_table_connect_to_default_miss_tbl(tbl, ft_obj); 482 483 ft_attr.type = tbl->fw_ft_type; 484 ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION; 485 ft_attr.table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_DEFAULT; 486 487 ret = mlx5dr_cmd_flow_table_modify(ft_obj, &ft_attr); 488 if (ret) { 489 DR_LOG(ERR, "Failed to set FT default miss action"); 490 return ret; 491 } 492 493 return 0; 494 } 495 496 int mlx5dr_table_ft_set_next_rtc(struct mlx5dr_devx_obj *ft, 497 uint32_t fw_ft_type, 498 struct mlx5dr_devx_obj *rtc_0, 499 struct mlx5dr_devx_obj *rtc_1) 500 { 501 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 502 503 ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID; 504 ft_attr.type = fw_ft_type; 505 ft_attr.rtc_id_0 = rtc_0 ? rtc_0->id : 0; 506 ft_attr.rtc_id_1 = rtc_1 ? rtc_1->id : 0; 507 508 return mlx5dr_cmd_flow_table_modify(ft, &ft_attr); 509 } 510 511 static int mlx5dr_table_ft_set_next_ft(struct mlx5dr_devx_obj *ft, 512 uint32_t fw_ft_type, 513 uint32_t next_ft_id) 514 { 515 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 516 517 ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION; 518 ft_attr.table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_GOTO_TBL; 519 ft_attr.type = fw_ft_type; 520 ft_attr.table_miss_id = next_ft_id; 521 522 return mlx5dr_cmd_flow_table_modify(ft, &ft_attr); 523 } 524 525 int mlx5dr_table_update_connected_miss_tables(struct mlx5dr_table *dst_tbl) 526 { 527 struct mlx5dr_table *src_tbl; 528 int ret; 529 530 if (LIST_EMPTY(&dst_tbl->default_miss.head)) 531 return 0; 532 533 LIST_FOREACH(src_tbl, &dst_tbl->default_miss.head, default_miss.next) { 534 ret = mlx5dr_table_connect_to_miss_table(src_tbl, dst_tbl, false); 535 if (ret) { 536 DR_LOG(ERR, "Failed to update source miss table, unexpected behavior"); 537 return ret; 538 } 539 } 540 541 return 0; 542 } 543 544 int mlx5dr_table_connect_src_ft_to_miss_table(struct mlx5dr_table *src_tbl, 545 struct mlx5dr_devx_obj *ft, 546 struct mlx5dr_table *dst_tbl) 547 { 548 struct mlx5dr_matcher *matcher; 549 int ret; 550 551 if (dst_tbl) { 552 if (LIST_EMPTY(&dst_tbl->head)) { 553 /* Connect src_tbl ft to dst_tbl start anchor */ 554 ret = mlx5dr_table_ft_set_next_ft(ft, 555 src_tbl->fw_ft_type, 556 dst_tbl->ft->id); 557 if (ret) 558 return ret; 559 560 /* Reset ft RTC to default RTC */ 561 ret = mlx5dr_table_ft_set_next_rtc(ft, 562 src_tbl->fw_ft_type, 563 NULL, NULL); 564 if (ret) 565 return ret; 566 } else { 567 /* Connect src_tbl ft to first matcher RTC */ 568 matcher = LIST_FIRST(&dst_tbl->head); 569 ret = mlx5dr_table_ft_set_next_rtc(ft, 570 src_tbl->fw_ft_type, 571 matcher->match_ste.rtc_0, 572 matcher->match_ste.rtc_1); 573 if (ret) 574 return ret; 575 576 /* Reset next miss FT to default */ 577 ret = mlx5dr_table_ft_set_default_next_ft(src_tbl, ft); 578 if (ret) 579 return ret; 580 } 581 } else { 582 /* Reset next miss FT to default */ 583 ret = mlx5dr_table_ft_set_default_next_ft(src_tbl, ft); 584 if (ret) 585 return ret; 586 587 /* Reset ft RTC to default RTC */ 588 ret = mlx5dr_table_ft_set_next_rtc(ft, 589 src_tbl->fw_ft_type, 590 NULL, NULL); 591 if (ret) 592 return ret; 593 } 594 595 return 0; 596 } 597 598 int mlx5dr_table_connect_to_miss_table(struct mlx5dr_table *src_tbl, 599 struct mlx5dr_table *dst_tbl, 600 bool only_update_last_ft) 601 { 602 struct mlx5dr_matcher *matcher; 603 struct mlx5dr_devx_obj *ft; 604 int ret; 605 606 /* Connect last FT in the src_tbl matchers chain */ 607 ft = mlx5dr_table_get_last_ft(src_tbl); 608 ret = mlx5dr_table_connect_src_ft_to_miss_table(src_tbl, ft, dst_tbl); 609 if (ret) 610 return ret; 611 612 if (!only_update_last_ft) { 613 /* Connect isolated matchers FT */ 614 LIST_FOREACH(matcher, &src_tbl->isolated_matchers, next) { 615 ft = matcher->end_ft; 616 ret = mlx5dr_table_connect_src_ft_to_miss_table(src_tbl, ft, dst_tbl); 617 if (ret) 618 return ret; 619 } 620 } 621 622 src_tbl->default_miss.miss_tbl = dst_tbl; 623 624 return 0; 625 } 626 627 static int mlx5dr_table_set_default_miss_not_valid(struct mlx5dr_table *tbl, 628 struct mlx5dr_table *miss_tbl) 629 { 630 if (!tbl->ctx->caps->nic_ft.ignore_flow_level_rtc_valid || 631 mlx5dr_context_shared_gvmi_used(tbl->ctx)) { 632 DR_LOG(ERR, "Default miss table is not supported"); 633 rte_errno = EOPNOTSUPP; 634 return -rte_errno; 635 } 636 637 if (mlx5dr_table_is_root(tbl) || 638 (miss_tbl && mlx5dr_table_is_root(miss_tbl)) || 639 (miss_tbl && miss_tbl->type != tbl->type)) { 640 DR_LOG(ERR, "Invalid arguments"); 641 rte_errno = EINVAL; 642 return -rte_errno; 643 } 644 645 return 0; 646 } 647 648 int mlx5dr_table_set_default_miss(struct mlx5dr_table *tbl, 649 struct mlx5dr_table *miss_tbl) 650 { 651 struct mlx5dr_context *ctx = tbl->ctx; 652 struct mlx5dr_table *old_miss_tbl; 653 int ret; 654 655 ret = mlx5dr_table_set_default_miss_not_valid(tbl, miss_tbl); 656 if (ret) 657 return ret; 658 659 pthread_spin_lock(&ctx->ctrl_lock); 660 old_miss_tbl = tbl->default_miss.miss_tbl; 661 ret = mlx5dr_table_connect_to_miss_table(tbl, miss_tbl, false); 662 if (ret) 663 goto out; 664 665 if (old_miss_tbl) 666 LIST_REMOVE(tbl, default_miss.next); 667 668 if (miss_tbl) 669 LIST_INSERT_HEAD(&miss_tbl->default_miss.head, tbl, default_miss.next); 670 671 pthread_spin_unlock(&ctx->ctrl_lock); 672 return 0; 673 out: 674 pthread_spin_unlock(&ctx->ctrl_lock); 675 return -ret; 676 } 677