1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2019 Mellanox Technologies */ 3 4 #include "mlx5_core.h" 5 #include "fs_core.h" 6 #include "fs_cmd.h" 7 #include "mlx5dr.h" 8 #include "fs_dr.h" 9 10 static bool mlx5_dr_is_fw_table(u32 flags) 11 { 12 if (flags & MLX5_FLOW_TABLE_TERMINATION) 13 return true; 14 15 return false; 16 } 17 18 static int mlx5_cmd_dr_update_root_ft(struct mlx5_flow_root_namespace *ns, 19 struct mlx5_flow_table *ft, 20 u32 underlay_qpn, 21 bool disconnect) 22 { 23 return mlx5_fs_cmd_get_fw_cmds()->update_root_ft(ns, ft, underlay_qpn, 24 disconnect); 25 } 26 27 static int set_miss_action(struct mlx5_flow_root_namespace *ns, 28 struct mlx5_flow_table *ft, 29 struct mlx5_flow_table *next_ft) 30 { 31 struct mlx5dr_action *old_miss_action; 32 struct mlx5dr_action *action = NULL; 33 struct mlx5dr_table *next_tbl; 34 int err; 35 36 next_tbl = next_ft ? next_ft->fs_dr_table.dr_table : NULL; 37 if (next_tbl) { 38 action = mlx5dr_action_create_dest_table(next_tbl); 39 if (!action) 40 return -EINVAL; 41 } 42 old_miss_action = ft->fs_dr_table.miss_action; 43 err = mlx5dr_table_set_miss_action(ft->fs_dr_table.dr_table, action); 44 if (err && action) { 45 err = mlx5dr_action_destroy(action); 46 if (err) { 47 action = NULL; 48 mlx5_core_err(ns->dev, "Failed to destroy action (%d)\n", 49 err); 50 } 51 } 52 ft->fs_dr_table.miss_action = action; 53 if (old_miss_action) { 54 err = mlx5dr_action_destroy(old_miss_action); 55 if (err) 56 mlx5_core_err(ns->dev, "Failed to destroy action (%d)\n", 57 err); 58 } 59 60 return err; 61 } 62 63 static int mlx5_cmd_dr_create_flow_table(struct mlx5_flow_root_namespace *ns, 64 struct mlx5_flow_table *ft, 65 unsigned int size, 66 struct mlx5_flow_table *next_ft) 67 { 68 struct mlx5dr_table *tbl; 69 u32 flags; 70 int err; 71 72 if (mlx5_dr_is_fw_table(ft->flags)) 73 return mlx5_fs_cmd_get_fw_cmds()->create_flow_table(ns, ft, 74 size, 75 next_ft); 76 flags = ft->flags; 77 /* turn off encap/decap if not supported for sw-str by fw */ 78 if (!MLX5_CAP_FLOWTABLE(ns->dev, sw_owner_reformat_supported)) 79 flags = ft->flags & ~(MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | 80 MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); 81 82 tbl = mlx5dr_table_create(ns->fs_dr_domain.dr_domain, ft->level, flags); 83 if (!tbl) { 84 mlx5_core_err(ns->dev, "Failed creating dr flow_table\n"); 85 return -EINVAL; 86 } 87 88 ft->fs_dr_table.dr_table = tbl; 89 ft->id = mlx5dr_table_get_id(tbl); 90 91 if (next_ft) { 92 err = set_miss_action(ns, ft, next_ft); 93 if (err) { 94 mlx5dr_table_destroy(tbl); 95 ft->fs_dr_table.dr_table = NULL; 96 return err; 97 } 98 } 99 100 ft->max_fte = INT_MAX; 101 102 return 0; 103 } 104 105 static int mlx5_cmd_dr_destroy_flow_table(struct mlx5_flow_root_namespace *ns, 106 struct mlx5_flow_table *ft) 107 { 108 struct mlx5dr_action *action = ft->fs_dr_table.miss_action; 109 int err; 110 111 if (mlx5_dr_is_fw_table(ft->flags)) 112 return mlx5_fs_cmd_get_fw_cmds()->destroy_flow_table(ns, ft); 113 114 err = mlx5dr_table_destroy(ft->fs_dr_table.dr_table); 115 if (err) { 116 mlx5_core_err(ns->dev, "Failed to destroy flow_table (%d)\n", 117 err); 118 return err; 119 } 120 if (action) { 121 err = mlx5dr_action_destroy(action); 122 if (err) { 123 mlx5_core_err(ns->dev, "Failed to destroy action(%d)\n", 124 err); 125 return err; 126 } 127 } 128 129 return err; 130 } 131 132 static int mlx5_cmd_dr_modify_flow_table(struct mlx5_flow_root_namespace *ns, 133 struct mlx5_flow_table *ft, 134 struct mlx5_flow_table *next_ft) 135 { 136 return set_miss_action(ns, ft, next_ft); 137 } 138 139 static int mlx5_cmd_dr_create_flow_group(struct mlx5_flow_root_namespace *ns, 140 struct mlx5_flow_table *ft, 141 u32 *in, 142 struct mlx5_flow_group *fg) 143 { 144 struct mlx5dr_matcher *matcher; 145 u32 priority = MLX5_GET(create_flow_group_in, in, 146 start_flow_index); 147 u8 match_criteria_enable = MLX5_GET(create_flow_group_in, 148 in, 149 match_criteria_enable); 150 struct mlx5dr_match_parameters mask; 151 152 if (mlx5_dr_is_fw_table(ft->flags)) 153 return mlx5_fs_cmd_get_fw_cmds()->create_flow_group(ns, ft, in, 154 fg); 155 156 mask.match_buf = MLX5_ADDR_OF(create_flow_group_in, 157 in, match_criteria); 158 mask.match_sz = sizeof(fg->mask.match_criteria); 159 160 matcher = mlx5dr_matcher_create(ft->fs_dr_table.dr_table, 161 priority, 162 match_criteria_enable, 163 &mask); 164 if (!matcher) { 165 mlx5_core_err(ns->dev, "Failed creating matcher\n"); 166 return -EINVAL; 167 } 168 169 fg->fs_dr_matcher.dr_matcher = matcher; 170 return 0; 171 } 172 173 static int mlx5_cmd_dr_destroy_flow_group(struct mlx5_flow_root_namespace *ns, 174 struct mlx5_flow_table *ft, 175 struct mlx5_flow_group *fg) 176 { 177 if (mlx5_dr_is_fw_table(ft->flags)) 178 return mlx5_fs_cmd_get_fw_cmds()->destroy_flow_group(ns, ft, fg); 179 180 return mlx5dr_matcher_destroy(fg->fs_dr_matcher.dr_matcher); 181 } 182 183 static struct mlx5dr_action *create_vport_action(struct mlx5dr_domain *domain, 184 struct mlx5_flow_rule *dst) 185 { 186 struct mlx5_flow_destination *dest_attr = &dst->dest_attr; 187 188 return mlx5dr_action_create_dest_vport(domain, dest_attr->vport.num, 189 dest_attr->vport.flags & 190 MLX5_FLOW_DEST_VPORT_VHCA_ID, 191 dest_attr->vport.vhca_id); 192 } 193 194 static struct mlx5dr_action *create_ft_action(struct mlx5dr_domain *domain, 195 struct mlx5_flow_rule *dst) 196 { 197 struct mlx5_flow_table *dest_ft = dst->dest_attr.ft; 198 199 if (mlx5_dr_is_fw_table(dest_ft->flags)) 200 return mlx5dr_action_create_dest_flow_fw_table(domain, dest_ft); 201 return mlx5dr_action_create_dest_table(dest_ft->fs_dr_table.dr_table); 202 } 203 204 static struct mlx5dr_action *create_action_push_vlan(struct mlx5dr_domain *domain, 205 struct mlx5_fs_vlan *vlan) 206 { 207 u16 n_ethtype = vlan->ethtype; 208 u8 prio = vlan->prio; 209 u16 vid = vlan->vid; 210 u32 vlan_hdr; 211 212 vlan_hdr = (u32)n_ethtype << 16 | (u32)(prio) << 12 | (u32)vid; 213 return mlx5dr_action_create_push_vlan(domain, htonl(vlan_hdr)); 214 } 215 216 static bool contain_vport_reformat_action(struct mlx5_flow_rule *dst) 217 { 218 return dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_VPORT && 219 dst->dest_attr.vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID; 220 } 221 222 #define MLX5_FLOW_CONTEXT_ACTION_MAX 20 223 static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns, 224 struct mlx5_flow_table *ft, 225 struct mlx5_flow_group *group, 226 struct fs_fte *fte) 227 { 228 struct mlx5dr_domain *domain = ns->fs_dr_domain.dr_domain; 229 struct mlx5dr_action_dest *term_actions; 230 struct mlx5dr_match_parameters params; 231 struct mlx5_core_dev *dev = ns->dev; 232 struct mlx5dr_action **fs_dr_actions; 233 struct mlx5dr_action *tmp_action; 234 struct mlx5dr_action **actions; 235 bool delay_encap_set = false; 236 struct mlx5dr_rule *rule; 237 struct mlx5_flow_rule *dst; 238 int fs_dr_num_actions = 0; 239 int num_term_actions = 0; 240 int num_actions = 0; 241 size_t match_sz; 242 int err = 0; 243 int i; 244 245 if (mlx5_dr_is_fw_table(ft->flags)) 246 return mlx5_fs_cmd_get_fw_cmds()->create_fte(ns, ft, group, fte); 247 248 actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, sizeof(*actions), 249 GFP_KERNEL); 250 if (!actions) { 251 err = -ENOMEM; 252 goto out_err; 253 } 254 255 fs_dr_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, 256 sizeof(*fs_dr_actions), GFP_KERNEL); 257 if (!fs_dr_actions) { 258 err = -ENOMEM; 259 goto free_actions_alloc; 260 } 261 262 term_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, 263 sizeof(*term_actions), GFP_KERNEL); 264 if (!term_actions) { 265 err = -ENOMEM; 266 goto free_fs_dr_actions_alloc; 267 } 268 269 match_sz = sizeof(fte->val); 270 271 /* Drop reformat action bit if destination vport set with reformat */ 272 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { 273 list_for_each_entry(dst, &fte->node.children, node.list) { 274 if (!contain_vport_reformat_action(dst)) 275 continue; 276 277 fte->action.action &= ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; 278 break; 279 } 280 } 281 282 /* The order of the actions are must to be keep, only the following 283 * order is supported by SW steering: 284 * TX: modify header -> push vlan -> encap 285 * RX: decap -> pop vlan -> modify header 286 */ 287 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) { 288 enum mlx5dr_action_reformat_type decap_type = 289 DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2; 290 291 tmp_action = mlx5dr_action_create_packet_reformat(domain, 292 decap_type, 293 0, 0, 0, 294 NULL); 295 if (!tmp_action) { 296 err = -ENOMEM; 297 goto free_actions; 298 } 299 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 300 actions[num_actions++] = tmp_action; 301 } 302 303 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { 304 bool is_decap = fte->action.pkt_reformat->reformat_type == 305 MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2; 306 307 if (is_decap) 308 actions[num_actions++] = 309 fte->action.pkt_reformat->action.dr_action; 310 else 311 delay_encap_set = true; 312 } 313 314 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP) { 315 tmp_action = 316 mlx5dr_action_create_pop_vlan(); 317 if (!tmp_action) { 318 err = -ENOMEM; 319 goto free_actions; 320 } 321 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 322 actions[num_actions++] = tmp_action; 323 } 324 325 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP_2) { 326 tmp_action = 327 mlx5dr_action_create_pop_vlan(); 328 if (!tmp_action) { 329 err = -ENOMEM; 330 goto free_actions; 331 } 332 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 333 actions[num_actions++] = tmp_action; 334 } 335 336 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 337 actions[num_actions++] = 338 fte->action.modify_hdr->action.dr_action; 339 340 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) { 341 tmp_action = create_action_push_vlan(domain, &fte->action.vlan[0]); 342 if (!tmp_action) { 343 err = -ENOMEM; 344 goto free_actions; 345 } 346 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 347 actions[num_actions++] = tmp_action; 348 } 349 350 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) { 351 tmp_action = create_action_push_vlan(domain, &fte->action.vlan[1]); 352 if (!tmp_action) { 353 err = -ENOMEM; 354 goto free_actions; 355 } 356 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 357 actions[num_actions++] = tmp_action; 358 } 359 360 if (delay_encap_set) 361 actions[num_actions++] = 362 fte->action.pkt_reformat->action.dr_action; 363 364 /* The order of the actions below is not important */ 365 366 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_DROP) { 367 tmp_action = mlx5dr_action_create_drop(); 368 if (!tmp_action) { 369 err = -ENOMEM; 370 goto free_actions; 371 } 372 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 373 term_actions[num_term_actions++].dest = tmp_action; 374 } 375 376 if (fte->flow_context.flow_tag) { 377 tmp_action = 378 mlx5dr_action_create_tag(fte->flow_context.flow_tag); 379 if (!tmp_action) { 380 err = -ENOMEM; 381 goto free_actions; 382 } 383 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 384 actions[num_actions++] = tmp_action; 385 } 386 387 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { 388 list_for_each_entry(dst, &fte->node.children, node.list) { 389 enum mlx5_flow_destination_type type = dst->dest_attr.type; 390 u32 id; 391 392 if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX || 393 num_term_actions >= MLX5_FLOW_CONTEXT_ACTION_MAX) { 394 err = -ENOSPC; 395 goto free_actions; 396 } 397 398 if (type == MLX5_FLOW_DESTINATION_TYPE_COUNTER) 399 continue; 400 401 switch (type) { 402 case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: 403 tmp_action = create_ft_action(domain, dst); 404 if (!tmp_action) { 405 err = -ENOMEM; 406 goto free_actions; 407 } 408 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 409 term_actions[num_term_actions++].dest = tmp_action; 410 break; 411 case MLX5_FLOW_DESTINATION_TYPE_VPORT: 412 tmp_action = create_vport_action(domain, dst); 413 if (!tmp_action) { 414 err = -ENOMEM; 415 goto free_actions; 416 } 417 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 418 term_actions[num_term_actions].dest = tmp_action; 419 420 if (dst->dest_attr.vport.flags & 421 MLX5_FLOW_DEST_VPORT_REFORMAT_ID) 422 term_actions[num_term_actions].reformat = 423 dst->dest_attr.vport.pkt_reformat->action.dr_action; 424 425 num_term_actions++; 426 break; 427 case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM: 428 id = dst->dest_attr.ft_num; 429 tmp_action = mlx5dr_action_create_dest_table_num(domain, 430 id); 431 if (!tmp_action) { 432 err = -ENOMEM; 433 goto free_actions; 434 } 435 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 436 term_actions[num_term_actions++].dest = tmp_action; 437 break; 438 case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER: 439 id = dst->dest_attr.sampler_id; 440 tmp_action = mlx5dr_action_create_flow_sampler(domain, 441 id); 442 if (!tmp_action) { 443 err = -ENOMEM; 444 goto free_actions; 445 } 446 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 447 term_actions[num_term_actions++].dest = tmp_action; 448 break; 449 default: 450 err = -EOPNOTSUPP; 451 goto free_actions; 452 } 453 } 454 } 455 456 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { 457 list_for_each_entry(dst, &fte->node.children, node.list) { 458 u32 id; 459 460 if (dst->dest_attr.type != 461 MLX5_FLOW_DESTINATION_TYPE_COUNTER) 462 continue; 463 464 if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { 465 err = -ENOSPC; 466 goto free_actions; 467 } 468 469 id = dst->dest_attr.counter_id; 470 tmp_action = 471 mlx5dr_action_create_flow_counter(id); 472 if (!tmp_action) { 473 err = -ENOMEM; 474 goto free_actions; 475 } 476 477 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 478 actions[num_actions++] = tmp_action; 479 } 480 } 481 482 params.match_sz = match_sz; 483 params.match_buf = (u64 *)fte->val; 484 if (num_term_actions == 1) { 485 if (term_actions->reformat) 486 actions[num_actions++] = term_actions->reformat; 487 488 actions[num_actions++] = term_actions->dest; 489 } else if (num_term_actions > 1) { 490 tmp_action = mlx5dr_action_create_mult_dest_tbl(domain, 491 term_actions, 492 num_term_actions); 493 if (!tmp_action) { 494 err = -EOPNOTSUPP; 495 goto free_actions; 496 } 497 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 498 actions[num_actions++] = tmp_action; 499 } 500 501 rule = mlx5dr_rule_create(group->fs_dr_matcher.dr_matcher, 502 ¶ms, 503 num_actions, 504 actions, 505 fte->flow_context.flow_source); 506 if (!rule) { 507 err = -EINVAL; 508 goto free_actions; 509 } 510 511 kfree(term_actions); 512 kfree(actions); 513 514 fte->fs_dr_rule.dr_rule = rule; 515 fte->fs_dr_rule.num_actions = fs_dr_num_actions; 516 fte->fs_dr_rule.dr_actions = fs_dr_actions; 517 518 return 0; 519 520 free_actions: 521 /* Free in reverse order to handle action dependencies */ 522 for (i = fs_dr_num_actions - 1; i >= 0; i--) 523 if (!IS_ERR_OR_NULL(fs_dr_actions[i])) 524 mlx5dr_action_destroy(fs_dr_actions[i]); 525 526 kfree(term_actions); 527 free_fs_dr_actions_alloc: 528 kfree(fs_dr_actions); 529 free_actions_alloc: 530 kfree(actions); 531 out_err: 532 mlx5_core_err(dev, "Failed to create dr rule err(%d)\n", err); 533 return err; 534 } 535 536 static int mlx5_cmd_dr_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns, 537 struct mlx5_pkt_reformat_params *params, 538 enum mlx5_flow_namespace_type namespace, 539 struct mlx5_pkt_reformat *pkt_reformat) 540 { 541 struct mlx5dr_domain *dr_domain = ns->fs_dr_domain.dr_domain; 542 struct mlx5dr_action *action; 543 int dr_reformat; 544 545 switch (params->type) { 546 case MLX5_REFORMAT_TYPE_L2_TO_VXLAN: 547 case MLX5_REFORMAT_TYPE_L2_TO_NVGRE: 548 case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL: 549 dr_reformat = DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2; 550 break; 551 case MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2: 552 dr_reformat = DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2; 553 break; 554 case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL: 555 dr_reformat = DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3; 556 break; 557 case MLX5_REFORMAT_TYPE_INSERT_HDR: 558 dr_reformat = DR_ACTION_REFORMAT_TYP_INSERT_HDR; 559 break; 560 default: 561 mlx5_core_err(ns->dev, "Packet-reformat not supported(%d)\n", 562 params->type); 563 return -EOPNOTSUPP; 564 } 565 566 action = mlx5dr_action_create_packet_reformat(dr_domain, 567 dr_reformat, 568 params->param_0, 569 params->param_1, 570 params->size, 571 params->data); 572 if (!action) { 573 mlx5_core_err(ns->dev, "Failed allocating packet-reformat action\n"); 574 return -EINVAL; 575 } 576 577 pkt_reformat->action.dr_action = action; 578 579 return 0; 580 } 581 582 static void mlx5_cmd_dr_packet_reformat_dealloc(struct mlx5_flow_root_namespace *ns, 583 struct mlx5_pkt_reformat *pkt_reformat) 584 { 585 mlx5dr_action_destroy(pkt_reformat->action.dr_action); 586 } 587 588 static int mlx5_cmd_dr_modify_header_alloc(struct mlx5_flow_root_namespace *ns, 589 u8 namespace, u8 num_actions, 590 void *modify_actions, 591 struct mlx5_modify_hdr *modify_hdr) 592 { 593 struct mlx5dr_domain *dr_domain = ns->fs_dr_domain.dr_domain; 594 struct mlx5dr_action *action; 595 size_t actions_sz; 596 597 actions_sz = MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto) * 598 num_actions; 599 action = mlx5dr_action_create_modify_header(dr_domain, 0, 600 actions_sz, 601 modify_actions); 602 if (!action) { 603 mlx5_core_err(ns->dev, "Failed allocating modify-header action\n"); 604 return -EINVAL; 605 } 606 607 modify_hdr->action.dr_action = action; 608 609 return 0; 610 } 611 612 static void mlx5_cmd_dr_modify_header_dealloc(struct mlx5_flow_root_namespace *ns, 613 struct mlx5_modify_hdr *modify_hdr) 614 { 615 mlx5dr_action_destroy(modify_hdr->action.dr_action); 616 } 617 618 static int mlx5_cmd_dr_update_fte(struct mlx5_flow_root_namespace *ns, 619 struct mlx5_flow_table *ft, 620 struct mlx5_flow_group *group, 621 int modify_mask, 622 struct fs_fte *fte) 623 { 624 return -EOPNOTSUPP; 625 } 626 627 static int mlx5_cmd_dr_delete_fte(struct mlx5_flow_root_namespace *ns, 628 struct mlx5_flow_table *ft, 629 struct fs_fte *fte) 630 { 631 struct mlx5_fs_dr_rule *rule = &fte->fs_dr_rule; 632 int err; 633 int i; 634 635 if (mlx5_dr_is_fw_table(ft->flags)) 636 return mlx5_fs_cmd_get_fw_cmds()->delete_fte(ns, ft, fte); 637 638 err = mlx5dr_rule_destroy(rule->dr_rule); 639 if (err) 640 return err; 641 642 /* Free in reverse order to handle action dependencies */ 643 for (i = rule->num_actions - 1; i >= 0; i--) 644 if (!IS_ERR_OR_NULL(rule->dr_actions[i])) 645 mlx5dr_action_destroy(rule->dr_actions[i]); 646 647 kfree(rule->dr_actions); 648 return 0; 649 } 650 651 static int mlx5_cmd_dr_set_peer(struct mlx5_flow_root_namespace *ns, 652 struct mlx5_flow_root_namespace *peer_ns) 653 { 654 struct mlx5dr_domain *peer_domain = NULL; 655 656 if (peer_ns) 657 peer_domain = peer_ns->fs_dr_domain.dr_domain; 658 mlx5dr_domain_set_peer(ns->fs_dr_domain.dr_domain, 659 peer_domain); 660 return 0; 661 } 662 663 static int mlx5_cmd_dr_create_ns(struct mlx5_flow_root_namespace *ns) 664 { 665 ns->fs_dr_domain.dr_domain = 666 mlx5dr_domain_create(ns->dev, 667 MLX5DR_DOMAIN_TYPE_FDB); 668 if (!ns->fs_dr_domain.dr_domain) { 669 mlx5_core_err(ns->dev, "Failed to create dr flow namespace\n"); 670 return -EOPNOTSUPP; 671 } 672 return 0; 673 } 674 675 static int mlx5_cmd_dr_destroy_ns(struct mlx5_flow_root_namespace *ns) 676 { 677 return mlx5dr_domain_destroy(ns->fs_dr_domain.dr_domain); 678 } 679 680 bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev) 681 { 682 return mlx5dr_is_supported(dev); 683 } 684 685 static const struct mlx5_flow_cmds mlx5_flow_cmds_dr = { 686 .create_flow_table = mlx5_cmd_dr_create_flow_table, 687 .destroy_flow_table = mlx5_cmd_dr_destroy_flow_table, 688 .modify_flow_table = mlx5_cmd_dr_modify_flow_table, 689 .create_flow_group = mlx5_cmd_dr_create_flow_group, 690 .destroy_flow_group = mlx5_cmd_dr_destroy_flow_group, 691 .create_fte = mlx5_cmd_dr_create_fte, 692 .update_fte = mlx5_cmd_dr_update_fte, 693 .delete_fte = mlx5_cmd_dr_delete_fte, 694 .update_root_ft = mlx5_cmd_dr_update_root_ft, 695 .packet_reformat_alloc = mlx5_cmd_dr_packet_reformat_alloc, 696 .packet_reformat_dealloc = mlx5_cmd_dr_packet_reformat_dealloc, 697 .modify_header_alloc = mlx5_cmd_dr_modify_header_alloc, 698 .modify_header_dealloc = mlx5_cmd_dr_modify_header_dealloc, 699 .set_peer = mlx5_cmd_dr_set_peer, 700 .create_ns = mlx5_cmd_dr_create_ns, 701 .destroy_ns = mlx5_cmd_dr_destroy_ns, 702 }; 703 704 const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void) 705 { 706 return &mlx5_flow_cmds_dr; 707 } 708