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