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