FILE
fs_dr.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.c
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2/* Copyright (c) 2019 Mellanox Technologies */ 3 4#include <linux/mlx5/vport.h> 5#include "mlx5_core.h" 6#include "fs_core.h" 7#include "fs_cmd.h" 8#include "mlx5dr.h" 9#include "fs_dr.h" 10#include "dr_types.h" 11 12static int mlx5_cmd_dr_update_root_ft(struct mlx5_flow_root_namespace *ns, 13 struct mlx5_flow_table *ft, 14 u32 underlay_qpn, 15 bool disconnect) 16{ 17 return mlx5_fs_cmd_get_fw_cmds()->update_root_ft(ns, ft, underlay_qpn, 18 disconnect); 19} 20 21static int set_miss_action(struct mlx5_flow_root_namespace *ns, 22 struct mlx5_flow_table *ft, 23 struct mlx5_flow_table *next_ft) 24{ 25 struct mlx5dr_action *old_miss_action; 26 struct mlx5dr_action *action = NULL; 27 struct mlx5dr_table *next_tbl; 28 int err; 29 30 next_tbl = next_ft ? next_ft->fs_dr_table.dr_table : NULL; 31 if (next_tbl) { 32 action = mlx5dr_action_create_dest_table(next_tbl); 33 if (!action) 34 return -EINVAL; 35 } 36 old_miss_action = ft->fs_dr_table.miss_action; 37 err = mlx5dr_table_set_miss_action(ft->fs_dr_table.dr_table, action); 38 if (err && action) { 39 err = mlx5dr_action_destroy(action); 40 if (err) 41 mlx5_core_err(ns->dev, 42 "Failed to destroy action (%d)\n", err); 43 action = NULL; 44 } 45 ft->fs_dr_table.miss_action = action; 46 if (old_miss_action) { 47 err = mlx5dr_action_destroy(old_miss_action); 48 if (err) 49 mlx5_core_err(ns->dev, "Failed to destroy action (%d)\n", 50 err); 51 } 52 53 return err; 54} 55 56static int mlx5_cmd_dr_create_flow_table(struct mlx5_flow_root_namespace *ns, 57 struct mlx5_flow_table *ft, 58 struct mlx5_flow_table_attr *ft_attr, 59 struct mlx5_flow_table *next_ft) 60{ 61 struct mlx5dr_table *tbl; 62 u32 flags; 63 int err; 64 65 if (mlx5_fs_cmd_is_fw_term_table(ft)) 66 return mlx5_fs_cmd_get_fw_cmds()->create_flow_table(ns, ft, 67 ft_attr, 68 next_ft); 69 flags = ft->flags; 70 /* turn off encap/decap if not supported for sw-str by fw */ 71 if (!MLX5_CAP_FLOWTABLE(ns->dev, sw_owner_reformat_supported)) 72 flags = ft->flags & ~(MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | 73 MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); 74 75 tbl = mlx5dr_table_create(ns->fs_dr_domain.dr_domain, ft->level, flags, 76 ft_attr->uid); 77 if (!tbl) { 78 mlx5_core_err(ns->dev, "Failed creating dr flow_table\n"); 79 return -EINVAL; 80 } 81 82 ft->fs_dr_table.dr_table = tbl; 83 ft->id = mlx5dr_table_get_id(tbl); 84 85 if (next_ft) { 86 err = set_miss_action(ns, ft, next_ft); 87 if (err) { 88 mlx5dr_table_destroy(tbl); 89 ft->fs_dr_table.dr_table = NULL; 90 return err; 91 } 92 } 93 94 ft->max_fte = INT_MAX; 95 96 return 0; 97} 98 99static int mlx5_cmd_dr_destroy_flow_table(struct mlx5_flow_root_namespace *ns, 100 struct mlx5_flow_table *ft) 101{ 102 struct mlx5dr_action *action = ft->fs_dr_table.miss_action; 103 int err; 104 105 if (mlx5_fs_cmd_is_fw_term_table(ft)) 106 return mlx5_fs_cmd_get_fw_cmds()->destroy_flow_table(ns, ft); 107 108 err = mlx5dr_table_destroy(ft->fs_dr_table.dr_table); 109 if (err) { 110 mlx5_core_err(ns->dev, "Failed to destroy flow_table (%d)\n", 111 err); 112 return err; 113 } 114 if (action) { 115 err = mlx5dr_action_destroy(action); 116 if (err) { 117 mlx5_core_err(ns->dev, "Failed to destroy action(%d)\n", 118 err); 119 return err; 120 } 121 } 122 123 return err; 124} 125 126static int mlx5_cmd_dr_modify_flow_table(struct mlx5_flow_root_namespace *ns, 127 struct mlx5_flow_table *ft, 128 struct mlx5_flow_table *next_ft) 129{ 130 if (mlx5_fs_cmd_is_fw_term_table(ft)) 131 return mlx5_fs_cmd_get_fw_cmds()->modify_flow_table(ns, ft, next_ft); 132 133 return set_miss_action(ns, ft, next_ft); 134} 135 136static int mlx5_cmd_dr_create_flow_group(struct mlx5_flow_root_namespace *ns, 137 struct mlx5_flow_table *ft, 138 u32 *in, 139 struct mlx5_flow_group *fg) 140{ 141 struct mlx5dr_matcher *matcher; 142 u32 priority = MLX5_GET(create_flow_group_in, in, 143 start_flow_index); 144 u8 match_criteria_enable = MLX5_GET(create_flow_group_in, 145 in, 146 match_criteria_enable); 147 struct mlx5dr_match_parameters mask; 148 149 if (mlx5_fs_cmd_is_fw_term_table(ft)) 150 return mlx5_fs_cmd_get_fw_cmds()->create_flow_group(ns, ft, in, 151 fg); 152 153 mask.match_buf = MLX5_ADDR_OF(create_flow_group_in, 154 in, match_criteria); 155 mask.match_sz = sizeof(fg->mask.match_criteria); 156 157 matcher = mlx5dr_matcher_create(ft->fs_dr_table.dr_table, 158 priority, 159 match_criteria_enable, 160 &mask); 161 if (!matcher) { 162 mlx5_core_err(ns->dev, "Failed creating matcher\n"); 163 return -EINVAL; 164 } 165 166 fg->fs_dr_matcher.dr_matcher = matcher; 167 return 0; 168} 169 170static int mlx5_cmd_dr_destroy_flow_group(struct mlx5_flow_root_namespace *ns, 171 struct mlx5_flow_table *ft, 172 struct mlx5_flow_group *fg) 173{ 174 if (mlx5_fs_cmd_is_fw_term_table(ft)) 175 return mlx5_fs_cmd_get_fw_cmds()->destroy_flow_group(ns, ft, fg); 176 177 return mlx5dr_matcher_destroy(fg->fs_dr_matcher.dr_matcher); 178} 179 180static struct mlx5dr_action *create_vport_action(struct mlx5dr_domain *domain, 181 struct mlx5_flow_rule *dst) 182{ 183 struct mlx5_flow_destination *dest_attr = &dst->dest_attr; 184 185 return mlx5dr_action_create_dest_vport(domain, dest_attr->vport.num, 186 dest_attr->vport.flags & 187 MLX5_FLOW_DEST_VPORT_VHCA_ID, 188 dest_attr->vport.vhca_id); 189} 190 191static struct mlx5dr_action *create_uplink_action(struct mlx5dr_domain *domain, 192 struct mlx5_flow_rule *dst) 193{ 194 struct mlx5_flow_destination *dest_attr = &dst->dest_attr; 195 196 return mlx5dr_action_create_dest_vport(domain, MLX5_VPORT_UPLINK, 1, 197 dest_attr->vport.vhca_id); 198} 199 200static struct mlx5dr_action *create_ft_action(struct mlx5dr_domain *domain, 201 struct mlx5_flow_rule *dst) 202{ 203 struct mlx5_flow_table *dest_ft = dst->dest_attr.ft; 204 struct mlx5dr_action *tbl_action; 205 206 if (mlx5dr_is_fw_table(dest_ft)) 207 return mlx5dr_action_create_dest_flow_fw_table(domain, dest_ft); 208 209 tbl_action = mlx5dr_action_create_dest_table(dest_ft->fs_dr_table.dr_table); 210 if (tbl_action) 211 tbl_action->dest_tbl->is_wire_ft = 212 dest_ft->flags & MLX5_FLOW_TABLE_UPLINK_VPORT ? 1 : 0; 213 214 return tbl_action; 215} 216 217static struct mlx5dr_action *create_range_action(struct mlx5dr_domain *domain, 218 struct mlx5_flow_rule *dst) 219{ 220 return mlx5dr_action_create_dest_match_range(domain, 221 dst->dest_attr.range.field, 222 dst->dest_attr.range.hit_ft, 223 dst->dest_attr.range.miss_ft, 224 dst->dest_attr.range.min, 225 dst->dest_attr.range.max); 226} 227 228static struct mlx5dr_action *create_action_push_vlan(struct mlx5dr_domain *domain, 229 struct mlx5_fs_vlan *vlan) 230{ 231 u16 n_ethtype = vlan->ethtype; 232 u8 prio = vlan->prio; 233 u16 vid = vlan->vid; 234 u32 vlan_hdr; 235 236 vlan_hdr = (u32)n_ethtype << 16 | (u32)(prio) << 12 | (u32)vid; 237 return mlx5dr_action_create_push_vlan(domain, htonl(vlan_hdr)); 238} 239 240static bool contain_vport_reformat_action(struct mlx5_flow_rule *dst) 241{ 242 return (dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_VPORT || 243 dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_UPLINK) && 244 dst->dest_attr.vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID; 245} 246 247/* We want to support a rule with 32 destinations, which means we need to 248 * account for 32 destinations plus usually a counter plus one more action 249 * for a multi-destination flow table. 250 */ 251#define MLX5_FLOW_CONTEXT_ACTION_MAX 34 252static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns, 253 struct mlx5_flow_table *ft, 254 struct mlx5_flow_group *group, 255 struct fs_fte *fte) 256{ 257 struct mlx5dr_domain *domain = ns->fs_dr_domain.dr_domain; 258 struct mlx5dr_action_dest *term_actions; 259 struct mlx5_pkt_reformat *pkt_reformat; 260 struct mlx5dr_match_parameters params; 261 struct mlx5_core_dev *dev = ns->dev; 262 struct mlx5dr_action **fs_dr_actions; 263 struct mlx5dr_action *tmp_action; 264 struct mlx5dr_action **actions; 265 bool delay_encap_set = false; 266 struct mlx5dr_rule *rule; 267 struct mlx5_flow_rule *dst; 268 int fs_dr_num_actions = 0; 269 int num_term_actions = 0; 270 int num_actions = 0; 271 size_t match_sz; 272 int err = 0; 273 int i; 274 275 if (mlx5_fs_cmd_is_fw_term_table(ft)) 276 return mlx5_fs_cmd_get_fw_cmds()->create_fte(ns, ft, group, fte); 277 278 actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, sizeof(*actions), 279 GFP_KERNEL); 280 if (!actions) { 281 err = -ENOMEM; 282 goto out_err; 283 } 284 285 fs_dr_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, 286 sizeof(*fs_dr_actions), GFP_KERNEL); 287 if (!fs_dr_actions) { 288 err = -ENOMEM; 289 goto free_actions_alloc; 290 } 291 292 term_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, 293 sizeof(*term_actions), GFP_KERNEL); 294 if (!term_actions) { 295 err = -ENOMEM; 296 goto free_fs_dr_actions_alloc; 297 } 298 299 match_sz = sizeof(fte->val); 300 301 /* Drop reformat action bit if destination vport set with reformat */ 302 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { 303 list_for_each_entry(dst, &fte->node.children, node.list) { 304 if (!contain_vport_reformat_action(dst)) 305 continue; 306 307 fte->act_dests.action.action &= ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; 308 break; 309 } 310 } 311 312 /* The order of the actions are must to be keep, only the following 313 * order is supported by SW steering: 314 * TX: modify header -> push vlan -> encap 315 * RX: decap -> pop vlan -> modify header 316 */ 317 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) { 318 enum mlx5dr_action_reformat_type decap_type = 319 DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2; 320 321 tmp_action = mlx5dr_action_create_packet_reformat(domain, 322 decap_type, 323 0, 0, 0, 324 NULL); 325 if (!tmp_action) { 326 err = -ENOMEM; 327 goto free_actions; 328 } 329 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 330 actions[num_actions++] = tmp_action; 331 } 332 333 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { 334 bool is_decap; 335 336 pkt_reformat = fte->act_dests.action.pkt_reformat; 337 if (pkt_reformat->owner == MLX5_FLOW_RESOURCE_OWNER_FW) { 338 err = -EINVAL; 339 mlx5dr_err(domain, "FW-owned reformat can't be used in SW rule\n"); 340 goto free_actions; 341 } 342 343 is_decap = pkt_reformat->reformat_type == 344 MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2; 345 346 if (is_decap) 347 actions[num_actions++] = 348 pkt_reformat->fs_dr_action.dr_action; 349 else 350 delay_encap_set = true; 351 } 352 353 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP) { 354 tmp_action = 355 mlx5dr_action_create_pop_vlan(); 356 if (!tmp_action) { 357 err = -ENOMEM; 358 goto free_actions; 359 } 360 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 361 actions[num_actions++] = tmp_action; 362 } 363 364 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP_2) { 365 tmp_action = 366 mlx5dr_action_create_pop_vlan(); 367 if (!tmp_action) { 368 err = -ENOMEM; 369 goto free_actions; 370 } 371 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 372 actions[num_actions++] = tmp_action; 373 } 374 375 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { 376 struct mlx5_modify_hdr *modify_hdr = fte->act_dests.action.modify_hdr; 377 378 actions[num_actions++] = modify_hdr->fs_dr_action.dr_action; 379 } 380 381 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) { 382 tmp_action = create_action_push_vlan(domain, &fte->act_dests.action.vlan[0]); 383 if (!tmp_action) { 384 err = -ENOMEM; 385 goto free_actions; 386 } 387 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 388 actions[num_actions++] = tmp_action; 389 } 390 391 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) { 392 tmp_action = create_action_push_vlan(domain, &fte->act_dests.action.vlan[1]); 393 if (!tmp_action) { 394 err = -ENOMEM; 395 goto free_actions; 396 } 397 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 398 actions[num_actions++] = tmp_action; 399 } 400 401 if (delay_encap_set) 402 actions[num_actions++] = pkt_reformat->fs_dr_action.dr_action; 403 404 /* The order of the actions below is not important */ 405 406 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_DROP) { 407 tmp_action = mlx5dr_action_create_drop(); 408 if (!tmp_action) { 409 err = -ENOMEM; 410 goto free_actions; 411 } 412 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 413 term_actions[num_term_actions++].dest = tmp_action; 414 } 415 416 if (fte->act_dests.flow_context.flow_tag) { 417 tmp_action = 418 mlx5dr_action_create_tag(fte->act_dests.flow_context.flow_tag); 419 if (!tmp_action) { 420 err = -ENOMEM; 421 goto free_actions; 422 } 423 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 424 actions[num_actions++] = tmp_action; 425 } 426 427 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { 428 list_for_each_entry(dst, &fte->node.children, node.list) { 429 enum mlx5_flow_destination_type type = dst->dest_attr.type; 430 u32 id; 431 432 if (fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX || 433 num_term_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { 434 err = -EOPNOTSUPP; 435 goto free_actions; 436 } 437 438 if (type == MLX5_FLOW_DESTINATION_TYPE_COUNTER) 439 continue; 440 441 switch (type) { 442 case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: 443 tmp_action = create_ft_action(domain, dst); 444 if (!tmp_action) { 445 err = -ENOMEM; 446 goto free_actions; 447 } 448 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 449 term_actions[num_term_actions++].dest = tmp_action; 450 break; 451 case MLX5_FLOW_DESTINATION_TYPE_UPLINK: 452 case MLX5_FLOW_DESTINATION_TYPE_VPORT: 453 tmp_action = type == MLX5_FLOW_DESTINATION_TYPE_VPORT ? 454 create_vport_action(domain, dst) : 455 create_uplink_action(domain, dst); 456 if (!tmp_action) { 457 err = -ENOMEM; 458 goto free_actions; 459 } 460 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 461 term_actions[num_term_actions].dest = tmp_action; 462 463 if (dst->dest_attr.vport.flags & 464 MLX5_FLOW_DEST_VPORT_REFORMAT_ID) { 465 pkt_reformat = dst->dest_attr.vport.pkt_reformat; 466 term_actions[num_term_actions].reformat = 467 pkt_reformat->fs_dr_action.dr_action; 468 } 469 470 num_term_actions++; 471 break; 472 case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM: 473 id = dst->dest_attr.ft_num; 474 tmp_action = mlx5dr_action_create_dest_table_num(domain, 475 id); 476 if (!tmp_action) { 477 err = -ENOMEM; 478 goto free_actions; 479 } 480 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 481 term_actions[num_term_actions++].dest = tmp_action; 482 break; 483 case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER: 484 id = dst->dest_attr.sampler_id; 485 tmp_action = mlx5dr_action_create_flow_sampler(domain, 486 id); 487 if (!tmp_action) { 488 err = -ENOMEM; 489 goto free_actions; 490 } 491 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 492 term_actions[num_term_actions++].dest = tmp_action; 493 break; 494 case MLX5_FLOW_DESTINATION_TYPE_RANGE: 495 tmp_action = create_range_action(domain, dst); 496 if (!tmp_action) { 497 err = -ENOMEM; 498 goto free_actions; 499 } 500 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 501 term_actions[num_term_actions++].dest = tmp_action; 502 break; 503 default: 504 err = -EOPNOTSUPP; 505 goto free_actions; 506 } 507 } 508 } 509 510 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { 511 list_for_each_entry(dst, &fte->node.children, node.list) { 512 u32 id; 513 514 if (dst->dest_attr.type != 515 MLX5_FLOW_DESTINATION_TYPE_COUNTER) 516 continue; 517 518 if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX || 519 fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { 520 err = -EOPNOTSUPP; 521 goto free_actions; 522 } 523 524 id = mlx5_fc_id(dst->dest_attr.counter); 525 tmp_action = 526 mlx5dr_action_create_flow_counter(id); 527 if (!tmp_action) { 528 err = -ENOMEM; 529 goto free_actions; 530 } 531 532 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 533 actions[num_actions++] = tmp_action; 534 } 535 } 536 537 if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO) { 538 struct mlx5_flow_act *action = &fte->act_dests.action; 539 540 if (fte->act_dests.action.exe_aso.type != MLX5_EXE_ASO_FLOW_METER) { 541 err = -EOPNOTSUPP; 542 goto free_actions; 543 } 544 545 tmp_action = 546 mlx5dr_action_create_aso(domain, 547 action->exe_aso.object_id, 548 action->exe_aso.return_reg_id, 549 action->exe_aso.type, 550 action->exe_aso.flow_meter.init_color, 551 action->exe_aso.flow_meter.meter_idx); 552 if (!tmp_action) { 553 err = -ENOMEM; 554 goto free_actions; 555 } 556 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 557 actions[num_actions++] = tmp_action; 558 } 559 560 params.match_sz = match_sz; 561 params.match_buf = (u64 *)fte->val; 562 if (num_term_actions == 1) { 563 if (term_actions->reformat) { 564 if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { 565 err = -EOPNOTSUPP; 566 goto free_actions; 567 } 568 actions[num_actions++] = term_actions->reformat; 569 } 570 571 if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { 572 err = -EOPNOTSUPP; 573 goto free_actions; 574 } 575 actions[num_actions++] = term_actions->dest; 576 } else if (num_term_actions > 1) { 577 bool ignore_flow_level = 578 !!(fte->act_dests.action.flags & FLOW_ACT_IGNORE_FLOW_LEVEL); 579 u32 flow_source = fte->act_dests.flow_context.flow_source; 580 581 if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX || 582 fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { 583 err = -EOPNOTSUPP; 584 goto free_actions; 585 } 586 tmp_action = mlx5dr_action_create_mult_dest_tbl(domain, 587 term_actions, 588 num_term_actions, 589 ignore_flow_level, 590 flow_source); 591 if (!tmp_action) { 592 err = -EOPNOTSUPP; 593 goto free_actions; 594 } 595 fs_dr_actions[fs_dr_num_actions++] = tmp_action; 596 actions[num_actions++] = tmp_action; 597 } 598 599 rule = mlx5dr_rule_create(group->fs_dr_matcher.dr_matcher, 600 ¶ms, 601 num_actions, 602 actions, 603 fte->act_dests.flow_context.flow_source); 604 if (!rule) { 605 err = -EINVAL; 606 goto free_actions; 607 } 608 609 kfree(term_actions); 610 kfree(actions); 611 612 fte->fs_dr_rule.dr_rule = rule; 613 fte->fs_dr_rule.num_actions = fs_dr_num_actions; 614 fte->fs_dr_rule.dr_actions = fs_dr_actions; 615 616 return 0; 617 618free_actions: 619 /* Free in reverse order to handle action dependencies */ 620 for (i = fs_dr_num_actions - 1; i >= 0; i--) 621 if (!IS_ERR_OR_NULL(fs_dr_actions[i])) 622 mlx5dr_action_destroy(fs_dr_actions[i]); 623 624 kfree(term_actions); 625free_fs_dr_actions_alloc: 626 kfree(fs_dr_actions); 627free_actions_alloc: 628 kfree(actions); 629out_err: 630 mlx5_core_err(dev, "Failed to create dr rule err(%d)\n", err); 631 return err; 632} 633 634static int mlx5_cmd_dr_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns, 635 struct mlx5_pkt_reformat_params *params, 636 enum mlx5_flow_namespace_type namespace, 637 struct mlx5_pkt_reformat *pkt_reformat) 638{ 639 struct mlx5dr_domain *dr_domain = ns->fs_dr_domain.dr_domain; 640 struct mlx5dr_action *action; 641 int dr_reformat; 642 643 switch (params->type) { 644 case MLX5_REFORMAT_TYPE_L2_TO_VXLAN: 645 case MLX5_REFORMAT_TYPE_L2_TO_NVGRE: 646 case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL: 647 dr_reformat = DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2; 648 break; 649 case MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2: 650 dr_reformat = DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2; 651 break; 652 case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL: 653 dr_reformat = DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3; 654 break; 655 case MLX5_REFORMAT_TYPE_INSERT_HDR: 656 dr_reformat = DR_ACTION_REFORMAT_TYP_INSERT_HDR; 657 break; 658 case MLX5_REFORMAT_TYPE_REMOVE_HDR: 659 dr_reformat = DR_ACTION_REFORMAT_TYP_REMOVE_HDR; 660 break; 661 default: 662 mlx5_core_err(ns->dev, "Packet-reformat not supported(%d)\n", 663 params->type); 664 return -EOPNOTSUPP; 665 } 666 667 action = mlx5dr_action_create_packet_reformat(dr_domain, 668 dr_reformat, 669 params->param_0, 670 params->param_1, 671 params->size, 672 params->data); 673 if (!action) { 674 mlx5_core_err(ns->dev, "Failed allocating packet-reformat action\n"); 675 return -EINVAL; 676 } 677 678 pkt_reformat->owner = MLX5_FLOW_RESOURCE_OWNER_SW; 679 pkt_reformat->fs_dr_action.dr_action = action; 680 681 return 0; 682} 683 684static void mlx5_cmd_dr_packet_reformat_dealloc(struct mlx5_flow_root_namespace *ns, 685 struct mlx5_pkt_reformat *pkt_reformat) 686{ 687 mlx5dr_action_destroy(pkt_reformat->fs_dr_action.dr_action); 688} 689 690static int mlx5_cmd_dr_modify_header_alloc(struct mlx5_flow_root_namespace *ns, 691 u8 namespace, u8 num_actions, 692 void *modify_actions, 693 struct mlx5_modify_hdr *modify_hdr) 694{ 695 struct mlx5dr_domain *dr_domain = ns->fs_dr_domain.dr_domain; 696 struct mlx5dr_action *action; 697 size_t actions_sz; 698 699 actions_sz = MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto) * 700 num_actions; 701 action = mlx5dr_action_create_modify_header(dr_domain, 0, 702 actions_sz, 703 modify_actions); 704 if (!action) { 705 mlx5_core_err(ns->dev, "Failed allocating modify-header action\n"); 706 return -EINVAL; 707 } 708 709 modify_hdr->owner = MLX5_FLOW_RESOURCE_OWNER_SW; 710 modify_hdr->fs_dr_action.dr_action = action; 711 712 return 0; 713} 714 715static void mlx5_cmd_dr_modify_header_dealloc(struct mlx5_flow_root_namespace *ns, 716 struct mlx5_modify_hdr *modify_hdr) 717{ 718 mlx5dr_action_destroy(modify_hdr->fs_dr_action.dr_action); 719} 720 721static int 722mlx5_cmd_dr_destroy_match_definer(struct mlx5_flow_root_namespace *ns, 723 int definer_id) 724{ 725 return -EOPNOTSUPP; 726} 727 728static int mlx5_cmd_dr_create_match_definer(struct mlx5_flow_root_namespace *ns, 729 u16 format_id, u32 *match_mask) 730{ 731 return -EOPNOTSUPP; 732} 733 734static int mlx5_cmd_dr_delete_fte(struct mlx5_flow_root_namespace *ns, 735 struct mlx5_flow_table *ft, 736 struct fs_fte *fte) 737{ 738 struct mlx5_fs_dr_rule *rule = &fte->fs_dr_rule; 739 int err; 740 int i; 741 742 if (mlx5_fs_cmd_is_fw_term_table(ft)) 743 return mlx5_fs_cmd_get_fw_cmds()->delete_fte(ns, ft, fte); 744 745 err = mlx5dr_rule_destroy(rule->dr_rule); 746 if (err) 747 return err; 748 749 /* Free in reverse order to handle action dependencies */ 750 for (i = rule->num_actions - 1; i >= 0; i--) 751 if (!IS_ERR_OR_NULL(rule->dr_actions[i])) 752 mlx5dr_action_destroy(rule->dr_actions[i]); 753 754 kfree(rule->dr_actions); 755 return 0; 756} 757 758static int mlx5_cmd_dr_update_fte(struct mlx5_flow_root_namespace *ns, 759 struct mlx5_flow_table *ft, 760 struct mlx5_flow_group *group, 761 int modify_mask, 762 struct fs_fte *fte) 763{ 764 struct fs_fte fte_tmp = {}; 765 int ret; 766 767 if (mlx5_fs_cmd_is_fw_term_table(ft)) 768 return mlx5_fs_cmd_get_fw_cmds()->update_fte(ns, ft, group, modify_mask, fte); 769 770 /* Backup current dr rule details */ 771 fte_tmp.fs_dr_rule = fte->fs_dr_rule; 772 memset(&fte->fs_dr_rule, 0, sizeof(struct mlx5_fs_dr_rule)); 773 774 /* First add the new updated rule, then delete the old rule */ 775 ret = mlx5_cmd_dr_create_fte(ns, ft, group, fte); 776 if (ret) 777 goto restore_fte; 778 779 ret = mlx5_cmd_dr_delete_fte(ns, ft, &fte_tmp); 780 WARN_ONCE(ret, "dr update fte duplicate rule deletion failed\n"); 781 return ret; 782 783restore_fte: 784 fte->fs_dr_rule = fte_tmp.fs_dr_rule; 785 return ret; 786} 787 788static int mlx5_cmd_dr_set_peer(struct mlx5_flow_root_namespace *ns, 789 struct mlx5_flow_root_namespace *peer_ns, 790 u16 peer_vhca_id) 791{ 792 struct mlx5dr_domain *peer_domain = NULL; 793 794 if (peer_ns) 795 peer_domain = peer_ns->fs_dr_domain.dr_domain; 796 mlx5dr_domain_set_peer(ns->fs_dr_domain.dr_domain, 797 peer_domain, peer_vhca_id); 798 return 0; 799} 800 801static int mlx5_cmd_dr_create_ns(struct mlx5_flow_root_namespace *ns) 802{ 803 ns->fs_dr_domain.dr_domain = 804 mlx5dr_domain_create(ns->dev, 805 MLX5DR_DOMAIN_TYPE_FDB); 806 if (!ns->fs_dr_domain.dr_domain) { 807 mlx5_core_err(ns->dev, "Failed to create dr flow namespace\n"); 808 return -EOPNOTSUPP; 809 } 810 return 0; 811} 812 813static int mlx5_cmd_dr_destroy_ns(struct mlx5_flow_root_namespace *ns) 814{ 815 return mlx5dr_domain_destroy(ns->fs_dr_domain.dr_domain); 816} 817 818static u32 mlx5_cmd_dr_get_capabilities(struct mlx5_flow_root_namespace *ns, 819 enum fs_flow_table_type ft_type) 820{ 821 u32 steering_caps = MLX5_FLOW_STEERING_CAP_DUPLICATE_MATCH; 822 823 if (ft_type != FS_FT_FDB || 824 MLX5_CAP_GEN(ns->dev, steering_format_version) == MLX5_STEERING_FORMAT_CONNECTX_5) 825 return steering_caps; 826 827 steering_caps |= MLX5_FLOW_STEERING_CAP_VLAN_PUSH_ON_RX; 828 steering_caps |= MLX5_FLOW_STEERING_CAP_VLAN_POP_ON_TX; 829 830 if (mlx5dr_supp_match_ranges(ns->dev)) 831 steering_caps |= MLX5_FLOW_STEERING_CAP_MATCH_RANGES; 832 833 return steering_caps; 834} 835 836int 837mlx5_fs_dr_action_get_pkt_reformat_id(struct mlx5_pkt_reformat *pkt_reformat, 838 u32 *reformat_id) 839{ 840 struct mlx5dr_action *dr_action; 841 842 switch (pkt_reformat->reformat_type) { 843 case MLX5_REFORMAT_TYPE_L2_TO_VXLAN: 844 case MLX5_REFORMAT_TYPE_L2_TO_NVGRE: 845 case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL: 846 case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL: 847 case MLX5_REFORMAT_TYPE_INSERT_HDR: 848 dr_action = pkt_reformat->fs_dr_action.dr_action; 849 *reformat_id = mlx5dr_action_get_pkt_reformat_id(dr_action); 850 return 0; 851 } 852 return -EOPNOTSUPP; 853} 854 855bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev) 856{ 857 return mlx5dr_is_supported(dev); 858} 859 860static const struct mlx5_flow_cmds mlx5_flow_cmds_dr = { 861 .create_flow_table = mlx5_cmd_dr_create_flow_table, 862 .destroy_flow_table = mlx5_cmd_dr_destroy_flow_table, 863 .modify_flow_table = mlx5_cmd_dr_modify_flow_table, 864 .create_flow_group = mlx5_cmd_dr_create_flow_group, 865 .destroy_flow_group = mlx5_cmd_dr_destroy_flow_group, 866 .create_fte = mlx5_cmd_dr_create_fte, 867 .update_fte = mlx5_cmd_dr_update_fte, 868 .delete_fte = mlx5_cmd_dr_delete_fte, 869 .update_root_ft = mlx5_cmd_dr_update_root_ft, 870 .packet_reformat_alloc = mlx5_cmd_dr_packet_reformat_alloc, 871 .packet_reformat_dealloc = mlx5_cmd_dr_packet_reformat_dealloc, 872 .modify_header_alloc = mlx5_cmd_dr_modify_header_alloc, 873 .modify_header_dealloc = mlx5_cmd_dr_modify_header_dealloc, 874 .create_match_definer = mlx5_cmd_dr_create_match_definer, 875 .destroy_match_definer = mlx5_cmd_dr_destroy_match_definer, 876 .set_peer = mlx5_cmd_dr_set_peer, 877 .create_ns = mlx5_cmd_dr_create_ns, 878 .destroy_ns = mlx5_cmd_dr_destroy_ns, 879 .get_capabilities = mlx5_cmd_dr_get_capabilities, 880}; 881 882const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void) 883{ 884 return &mlx5_flow_cmds_dr; 885}
~/
Read-only file preview.