From: Gregory Etelson <getel...@nvidia.com>

Add PMD implementation for HW steering VLAN push, pop and modify flow
actions.

HWS VLAN push flow action is triggered by a sequence of mandatory
OF_PUSH_VLAN, OF_SET_VLAN_VID and optional OF_SET_VLAN_PCP
flow actions commands.
The commands must be arranged in the exact order:
OF_PUSH_VLAN / OF_SET_VLAN_VID [ / OF_SET_VLAN_PCP ].
In masked HWS VLAN push flow action template *ALL* the above flow
actions must be masked.
In non-masked HWS VLAN push flow action template *ALL* the above flow
actions must not be masked.

Example:

flow actions_template <port id> create \
actions_template_id <action id> \
template \
  of_push_vlan / \
  of_set_vlan_vid \
  [ / of_set_vlan_pcp  ] / end \
mask \
  of_push_vlan ethertype 0 / \
  of_set_vlan_vid vlan_vid 0 \
  [ / of_set_vlan_pcp vlan_pcp 0 ] / end\

flow actions_template <port id> create \
actions_template_id <action id> \
template \
  of_push_vlan ethertype <E>/ \
  of_set_vlan_vid vlan_vid <VID>\
  [ / of_set_vlan_pcp  <PCP>] / end \
mask \
  of_push_vlan ethertype <type != 0> / \
  of_set_vlan_vid vlan_vid <vid_mask != 0>\
  [ / of_set_vlan_pcp vlan_pcp <pcp_mask != 0> ] / end\

HWS VLAN pop flow action is triggered by OF_POP_VLAN
flow action command.
HWS VLAN pop action template is always non-masked.

Example:

flow actions_template <port id> create \
actions_template_id <action id> \
template of_pop_vlan / end mask of_pop_vlan / end

HWS VLAN VID modify flow action is triggered by a standalone
OF_SET_VLAN_VID flow action command.
HWS VLAN VID modify action template can be ether masked or non-masked.

Example:

flow actions_template <port id> create \
actions_template_id <action id> \
template of_set_vlan_vid / end mask of_set_vlan_vid vlan_vid 0 / end

flow actions_template <port id> create \
actions_template_id <action id> \
template of_set_vlan_vid vlan_vid 0x101 / end \
mask of_set_vlan_vid vlan_vid 0xffff / end

Signed-off-by: Gregory Etelson <getel...@nvidia.com>
---
 drivers/net/mlx5/mlx5.h         |   2 +
 drivers/net/mlx5/mlx5_flow.h    |   4 +
 drivers/net/mlx5/mlx5_flow_dv.c |   2 +-
 drivers/net/mlx5/mlx5_flow_hw.c | 360 ++++++++++++++++++++++++++++++--
 4 files changed, 348 insertions(+), 20 deletions(-)

diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index ee4823f649..ec08014832 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -1590,6 +1590,8 @@ struct mlx5_priv {
        void *root_drop_action; /* Pointer to root drop action. */
        rte_spinlock_t hw_ctrl_lock;
        LIST_HEAD(hw_ctrl_flow, mlx5_hw_ctrl_flow) hw_ctrl_flows;
+       struct mlx5dr_action *hw_push_vlan[MLX5DR_TABLE_TYPE_MAX];
+       struct mlx5dr_action *hw_pop_vlan[MLX5DR_TABLE_TYPE_MAX];
        struct mlx5dr_action **hw_vport;
        struct rte_flow_template_table *hw_esw_sq_miss_root_tbl;
        struct rte_flow_template_table *hw_esw_sq_miss_tbl;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index f7bedd9605..2d1a9dba27 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -2434,4 +2434,8 @@ int mlx5_flow_pattern_validate(struct rte_eth_dev *dev,
                struct rte_flow_error *error);
 int flow_hw_table_update(struct rte_eth_dev *dev,
                         struct rte_flow_error *error);
+int mlx5_flow_item_field_width(struct rte_eth_dev *dev,
+                          enum rte_flow_field_id field, int inherit,
+                          const struct rte_flow_attr *attr,
+                          struct rte_flow_error *error);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index e2794c1d26..36059beb71 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -1326,7 +1326,7 @@ flow_dv_convert_action_modify_ipv6_dscp
                                             MLX5_MODIFICATION_TYPE_SET, error);
 }
 
-static int
+int
 mlx5_flow_item_field_width(struct rte_eth_dev *dev,
                           enum rte_flow_field_id field, int inherit,
                           const struct rte_flow_attr *attr,
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index a4a0882d15..7e7b48f884 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -48,12 +48,22 @@
 /* Lowest priority for HW non-root table. */
 #define MLX5_HW_LOWEST_PRIO_NON_ROOT (UINT32_MAX)
 
+#define MLX5_HW_VLAN_PUSH_TYPE_IDX 0
+#define MLX5_HW_VLAN_PUSH_VID_IDX 1
+#define MLX5_HW_VLAN_PUSH_PCP_IDX 2
+
 static int flow_hw_flush_all_ctrl_flows(struct rte_eth_dev *dev);
 static int flow_hw_translate_group(struct rte_eth_dev *dev,
                                   const struct mlx5_flow_template_table_cfg 
*cfg,
                                   uint32_t group,
                                   uint32_t *table_group,
                                   struct rte_flow_error *error);
+static __rte_always_inline int
+flow_hw_set_vlan_vid_construct(struct rte_eth_dev *dev,
+                              struct mlx5_hw_q_job *job,
+                              struct mlx5_action_construct_data *act_data,
+                              const struct mlx5_hw_actions *hw_acts,
+                              const struct rte_flow_action *action);
 
 const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops;
 
@@ -1039,6 +1049,52 @@ flow_hw_cnt_compile(struct rte_eth_dev *dev, uint32_t  
start_pos,
        return 0;
 }
 
+static __rte_always_inline bool
+is_of_vlan_pcp_present(const struct rte_flow_action *actions)
+{
+       /*
+        * Order of RTE VLAN push actions is
+        * OF_PUSH_VLAN / OF_SET_VLAN_VID [ / OF_SET_VLAN_PCP ]
+        */
+       return actions[MLX5_HW_VLAN_PUSH_PCP_IDX].type ==
+               RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP;
+}
+
+static __rte_always_inline bool
+is_template_masked_push_vlan(const struct rte_flow_action_of_push_vlan *mask)
+{
+       /*
+        * In masked push VLAN template all RTE push actions are masked.
+        */
+       return mask && mask->ethertype != 0;
+}
+
+static rte_be32_t vlan_hdr_to_be32(const struct rte_flow_action *actions)
+{
+/*
+ * OpenFlow Switch Specification defines 801.1q VID as 12+1 bits.
+ */
+       rte_be32_t type, vid, pcp;
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+       rte_be32_t vid_lo, vid_hi;
+#endif
+
+       type = ((const struct rte_flow_action_of_push_vlan *)
+               actions[MLX5_HW_VLAN_PUSH_TYPE_IDX].conf)->ethertype;
+       vid = ((const struct rte_flow_action_of_set_vlan_vid *)
+               actions[MLX5_HW_VLAN_PUSH_VID_IDX].conf)->vlan_vid;
+       pcp = is_of_vlan_pcp_present(actions) ?
+             ((const struct rte_flow_action_of_set_vlan_pcp *)
+                     actions[MLX5_HW_VLAN_PUSH_PCP_IDX].conf)->vlan_pcp : 0;
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+       vid_hi = vid & 0xff;
+       vid_lo = vid >> 8;
+       return (((vid_lo << 8) | (pcp << 5) | vid_hi) << 16) | type;
+#else
+       return (type << 16) | (pcp << 13) | vid;
+#endif
+}
+
 /**
  * Translate rte_flow actions to DR action.
  *
@@ -1141,6 +1197,26 @@ __flow_hw_actions_translate(struct rte_eth_dev *dev,
                                priv->hw_tag[!!attr->group];
                        flow_hw_rxq_flag_set(dev, true);
                        break;
+               case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+                       action_pos = at->actions_off[actions - at->actions];
+                       acts->rule_acts[action_pos].action =
+                               priv->hw_push_vlan[type];
+                       if (is_template_masked_push_vlan(masks->conf))
+                               acts->rule_acts[action_pos].push_vlan.vlan_hdr =
+                                       vlan_hdr_to_be32(actions);
+                       else if (__flow_hw_act_data_general_append
+                                       (priv, acts, actions->type,
+                                        actions - action_start, action_pos))
+                               goto err;
+                       actions += is_of_vlan_pcp_present(actions) ?
+                                       MLX5_HW_VLAN_PUSH_PCP_IDX :
+                                       MLX5_HW_VLAN_PUSH_VID_IDX;
+                       break;
+               case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
+                       action_pos = at->actions_off[actions - at->actions];
+                       acts->rule_acts[action_pos].action =
+                               priv->hw_pop_vlan[type];
+                       break;
                case RTE_FLOW_ACTION_TYPE_JUMP:
                        action_pos = at->actions_off[actions - action_start];
                        if (masks->conf &&
@@ -1746,8 +1822,17 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,
                cnt_id_t cnt_id;
 
                action = &actions[act_data->action_src];
-               MLX5_ASSERT(action->type == RTE_FLOW_ACTION_TYPE_INDIRECT ||
-                           (int)action->type == act_data->type);
+               /*
+                * action template construction replaces
+                * OF_SET_VLAN_VID with MODIFY_FIELD
+                */
+               if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID)
+                       MLX5_ASSERT(act_data->type ==
+                                   RTE_FLOW_ACTION_TYPE_MODIFY_FIELD);
+               else
+                       MLX5_ASSERT(action->type ==
+                                   RTE_FLOW_ACTION_TYPE_INDIRECT ||
+                                   (int)action->type == act_data->type);
                switch (act_data->type) {
                case RTE_FLOW_ACTION_TYPE_INDIRECT:
                        if (flow_hw_shared_action_construct
@@ -1763,6 +1848,10 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,
                              (action->conf))->id);
                        rule_acts[act_data->action_dst].tag.value = tag;
                        break;
+               case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+                       rule_acts[act_data->action_dst].push_vlan.vlan_hdr =
+                               vlan_hdr_to_be32(action);
+                       break;
                case RTE_FLOW_ACTION_TYPE_JUMP:
                        jump_group = ((const struct rte_flow_action_jump *)
                                                action->conf)->group;
@@ -1814,10 +1903,16 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,
                                    act_data->encap.len);
                        break;
                case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
-                       ret = flow_hw_modify_field_construct(job,
-                                                            act_data,
-                                                            hw_acts,
-                                                            action);
+                       if (action->type == 
RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID)
+                               ret = flow_hw_set_vlan_vid_construct(dev, job,
+                                                                    act_data,
+                                                                    hw_acts,
+                                                                    action);
+                       else
+                               ret = flow_hw_modify_field_construct(job,
+                                                                    act_data,
+                                                                    hw_acts,
+                                                                    action);
                        if (ret)
                                return -1;
                        break;
@@ -2841,6 +2936,56 @@ flow_hw_action_meta_copy_insert(const struct 
rte_flow_action actions[],
        return 0;
 }
 
+static int
+flow_hw_validate_action_push_vlan(struct rte_eth_dev *dev,
+                                 const
+                                 struct rte_flow_actions_template_attr *attr,
+                                 const struct rte_flow_action *action,
+                                 const struct rte_flow_action *mask,
+                                 struct rte_flow_error *error)
+{
+#define X_FIELD(ptr, t, f) ((t *)((ptr)->conf))->f
+       /*
+        * 1. Mandatory actions order:
+        * OF_PUSH_VLAN / OF_SET_VLAN_VID [ / OF_SET_VLAN_PCP ]
+        * 2. All actions ether masked or not.
+        */
+       const bool masked_action = action[MLX5_HW_VLAN_PUSH_TYPE_IDX].conf &&
+               X_FIELD(action + MLX5_HW_VLAN_PUSH_TYPE_IDX,
+                       const struct rte_flow_action_of_push_vlan,
+                       ethertype) != 0;
+       bool masked_param;
+
+       RTE_SET_USED(dev);
+       RTE_SET_USED(attr);
+       RTE_SET_USED(mask);
+       if (action[MLX5_HW_VLAN_PUSH_VID_IDX].type !=
+               RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION,
+                                         action, "OF_PUSH_VLAN: invalid 
actions order");
+       masked_param = action[MLX5_HW_VLAN_PUSH_VID_IDX].conf &&
+               X_FIELD(action + MLX5_HW_VLAN_PUSH_VID_IDX,
+                       const struct rte_flow_action_of_set_vlan_vid, vlan_vid);
+       if (!(masked_action & masked_param))
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION,
+                                         action, "OF_SET_VLAN_VID: template 
mask does not match OF_PUSH_VLAN");
+       if (is_of_vlan_pcp_present(action)) {
+               masked_param = action[MLX5_HW_VLAN_PUSH_PCP_IDX].conf &&
+                       X_FIELD(action + MLX5_HW_VLAN_PUSH_PCP_IDX,
+                               const struct rte_flow_action_of_set_vlan_pcp,
+                                       vlan_pcp);
+               if (!(masked_action & masked_param))
+                       return rte_flow_error_set(error, EINVAL,
+                                                 RTE_FLOW_ERROR_TYPE_ACTION,
+                                                 action, "OF_SET_VLAN_PCP: 
template mask does not match OF_PUSH_VLAN");
+       }
+
+       return 0;
+#undef X_FIELD
+}
+
 static int
 flow_hw_actions_validate(struct rte_eth_dev *dev,
                        const struct rte_flow_actions_template_attr *attr,
@@ -2931,6 +3076,18 @@ flow_hw_actions_validate(struct rte_eth_dev *dev,
                case RTE_FLOW_ACTION_TYPE_CONNTRACK:
                        /* TODO: Validation logic */
                        break;
+               case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
+               case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
+                       break;
+               case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+                       ret = flow_hw_validate_action_push_vlan
+                                       (dev, attr, action, mask, error);
+                       if (ret != 0)
+                               return ret;
+                       i += is_of_vlan_pcp_present(action) ?
+                               MLX5_HW_VLAN_PUSH_PCP_IDX :
+                               MLX5_HW_VLAN_PUSH_VID_IDX;
+                       break;
                case RTE_FLOW_ACTION_TYPE_END:
                        actions_end = true;
                        break;
@@ -2958,6 +3115,8 @@ static enum mlx5dr_action_type mlx5_hw_dr_action_types[] 
= {
        [RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT] = MLX5DR_ACTION_TYP_VPORT,
        [RTE_FLOW_ACTION_TYPE_COUNT] = MLX5DR_ACTION_TYP_CTR,
        [RTE_FLOW_ACTION_TYPE_CONNTRACK] = MLX5DR_ACTION_TYP_ASO_CT,
+       [RTE_FLOW_ACTION_TYPE_OF_POP_VLAN] = MLX5DR_ACTION_TYP_POP_VLAN,
+       [RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN] = MLX5DR_ACTION_TYP_PUSH_VLAN,
 };
 
 static int
@@ -3074,6 +3233,14 @@ flow_hw_dr_actions_template_create(struct 
rte_flow_actions_template *at)
                                goto err_actions_num;
                        action_types[curr_off++] = MLX5DR_ACTION_TYP_FT;
                        break;
+               case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+                       type = mlx5_hw_dr_action_types[at->actions[i].type];
+                       at->actions_off[i] = curr_off;
+                       action_types[curr_off++] = type;
+                       i += is_of_vlan_pcp_present(at->actions + i) ?
+                               MLX5_HW_VLAN_PUSH_PCP_IDX :
+                               MLX5_HW_VLAN_PUSH_VID_IDX;
+                       break;
                default:
                        type = mlx5_hw_dr_action_types[at->actions[i].type];
                        at->actions_off[i] = curr_off;
@@ -3101,6 +3268,95 @@ flow_hw_dr_actions_template_create(struct 
rte_flow_actions_template *at)
        return NULL;
 }
 
+static void
+flow_hw_set_vlan_vid(struct rte_eth_dev *dev,
+                    const struct rte_flow_action *actions,
+                    const struct rte_flow_action *masks,
+                    struct rte_flow_action *ra, struct rte_flow_action *rm,
+                    struct rte_flow_action_modify_field *spec,
+                    struct rte_flow_action_modify_field *mask,
+                    uint32_t act_num, int set_vlan_vid_ix)
+{
+       struct rte_flow_error error;
+       const bool masked = masks[set_vlan_vid_ix].conf &&
+               (((const struct rte_flow_action_of_set_vlan_vid *)
+                       masks[set_vlan_vid_ix].conf)->vlan_vid != 0);
+       const struct rte_flow_action_of_set_vlan_vid *conf =
+               actions[set_vlan_vid_ix].conf;
+       rte_be16_t vid = masked ? conf->vlan_vid : 0;
+       int width = mlx5_flow_item_field_width(dev, RTE_FLOW_FIELD_VLAN_ID, 0,
+                                              NULL, &error);
+       if (actions == ra) {
+               size_t copy_sz = sizeof(ra[0]) * act_num;
+               rte_memcpy(ra, actions, copy_sz);
+               rte_memcpy(rm, masks, copy_sz);
+       }
+       *spec = (typeof(*spec)) {
+               .operation = RTE_FLOW_MODIFY_SET,
+               .dst = {
+                       .field = RTE_FLOW_FIELD_VLAN_ID,
+                       .level = 0, .offset = 0,
+               },
+               .src = {
+                       .field = RTE_FLOW_FIELD_VALUE,
+                       .level = vid,
+                       .offset = 0,
+               },
+               .width = width,
+       };
+       *mask = (typeof(*mask)) {
+               .operation = RTE_FLOW_MODIFY_SET,
+               .dst = {
+                       .field = RTE_FLOW_FIELD_VLAN_ID,
+                       .level = 0xffffffff, .offset = 0xffffffff,
+               },
+               .src = {
+                       .field = RTE_FLOW_FIELD_VALUE,
+                       .level = masked ? (1U << width) - 1 : 0,
+                       .offset = 0,
+               },
+               .width = 0xffffffff,
+       };
+       ra[set_vlan_vid_ix].type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD;
+       ra[set_vlan_vid_ix].conf = spec;
+       rm[set_vlan_vid_ix].type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD;
+       rm[set_vlan_vid_ix].conf = mask;
+}
+
+static __rte_always_inline int
+flow_hw_set_vlan_vid_construct(struct rte_eth_dev *dev,
+                              struct mlx5_hw_q_job *job,
+                              struct mlx5_action_construct_data *act_data,
+                              const struct mlx5_hw_actions *hw_acts,
+                              const struct rte_flow_action *action)
+{
+       struct rte_flow_error error;
+       rte_be16_t vid = ((const struct rte_flow_action_of_set_vlan_vid *)
+                          action->conf)->vlan_vid;
+       int width = mlx5_flow_item_field_width(dev, RTE_FLOW_FIELD_VLAN_ID, 0,
+                                              NULL, &error);
+       struct rte_flow_action_modify_field conf = {
+               .operation = RTE_FLOW_MODIFY_SET,
+               .dst = {
+                       .field = RTE_FLOW_FIELD_VLAN_ID,
+                       .level = 0, .offset = 0,
+               },
+               .src = {
+                       .field = RTE_FLOW_FIELD_VALUE,
+                       .level = vid,
+                       .offset = 0,
+               },
+               .width = width,
+       };
+       struct rte_flow_action modify_action = {
+               .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD,
+               .conf = &conf
+       };
+
+       return flow_hw_modify_field_construct(job, act_data, hw_acts,
+                                             &modify_action);
+}
+
 /**
  * Create flow action template.
  *
@@ -3132,8 +3388,11 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev,
        uint16_t pos = MLX5_HW_MAX_ACTS;
        struct rte_flow_action tmp_action[MLX5_HW_MAX_ACTS];
        struct rte_flow_action tmp_mask[MLX5_HW_MAX_ACTS];
-       const struct rte_flow_action *ra;
-       const struct rte_flow_action *rm;
+       struct rte_flow_action *ra = (void *)(uintptr_t)actions;
+       struct rte_flow_action *rm = (void *)(uintptr_t)masks;
+       int set_vlan_vid_ix = -1;
+       struct rte_flow_action_modify_field set_vlan_vid_spec = {0, };
+       struct rte_flow_action_modify_field set_vlan_vid_mask = {0, };
        const struct rte_flow_action_modify_field rx_mreg = {
                .operation = RTE_FLOW_MODIFY_SET,
                .dst = {
@@ -3173,22 +3432,42 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev,
                return NULL;
        if (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS &&
            priv->sh->config.dv_esw_en) {
+               /* Application should make sure only one Q/RSS exist in one 
rule. */
                if (flow_hw_action_meta_copy_insert(actions, masks, &rx_cpy, 
&rx_cpy_mask,
                                                    tmp_action, tmp_mask, 
&pos)) {
                        rte_flow_error_set(error, EINVAL,
                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                           "Failed to concatenate new 
action/mask");
                        return NULL;
+               } else if (pos != MLX5_HW_MAX_ACTS) {
+                       ra = tmp_action;
+                       rm = tmp_mask;
                }
        }
-       /* Application should make sure only one Q/RSS exist in one rule. */
-       if (pos == MLX5_HW_MAX_ACTS) {
-               ra = actions;
-               rm = masks;
-       } else {
-               ra = tmp_action;
-               rm = tmp_mask;
+       for (i = 0; ra[i].type != RTE_FLOW_ACTION_TYPE_END; ++i) {
+                       switch (ra[i].type) {
+                       /* OF_PUSH_VLAN *MUST* come before OF_SET_VLAN_VID */
+                       case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+                               i += is_of_vlan_pcp_present(ra + i) ?
+                                       MLX5_HW_VLAN_PUSH_PCP_IDX :
+                                       MLX5_HW_VLAN_PUSH_VID_IDX;
+                               break;
+                       case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
+                               set_vlan_vid_ix = i;
+                               break;
+                       default:
+                               break;
+                       }
        }
+       /* Count flow actions to allocate required space for storing DR 
offsets. */
+       act_num = i;
+       if (act_num >= MLX5_HW_MAX_ACTS)
+               rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_ACTION, NULL, "Too many 
actions");
+       if (set_vlan_vid_ix != -1)
+               flow_hw_set_vlan_vid(dev, actions, masks, ra, rm,
+                                    &set_vlan_vid_spec, &set_vlan_vid_mask,
+                                    act_num, set_vlan_vid_ix);
        act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, NULL, 0, ra, error);
        if (act_len <= 0)
                return NULL;
@@ -3197,10 +3476,6 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev,
        if (mask_len <= 0)
                return NULL;
        len += RTE_ALIGN(mask_len, 16);
-       /* Count flow actions to allocate required space for storing DR 
offsets. */
-       act_num = 0;
-       for (i = 0; ra[i].type != RTE_FLOW_ACTION_TYPE_END; ++i)
-               act_num++;
        len += RTE_ALIGN(act_num * sizeof(*at->actions_off), 16);
        at = mlx5_malloc(MLX5_MEM_ZERO, len + sizeof(*at),
                         RTE_CACHE_LINE_SIZE, rte_socket_id());
@@ -4719,6 +4994,48 @@ flow_hw_ct_pool_create(struct rte_eth_dev *dev,
        return NULL;
 }
 
+static void
+flow_hw_destroy_vlan(struct rte_eth_dev *dev)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       enum mlx5dr_table_type i;
+
+       for (i = MLX5DR_TABLE_TYPE_NIC_RX; i < MLX5DR_TABLE_TYPE_MAX; i++) {
+               if (priv->hw_pop_vlan[i]) {
+                       mlx5dr_action_destroy(priv->hw_pop_vlan[i]);
+                       priv->hw_pop_vlan[i] = NULL;
+               }
+               if (priv->hw_push_vlan[i]) {
+                       mlx5dr_action_destroy(priv->hw_push_vlan[i]);
+                       priv->hw_push_vlan[i] = NULL;
+               }
+       }
+}
+
+static int
+flow_hw_create_vlan(struct rte_eth_dev *dev)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       enum mlx5dr_table_type i;
+       const enum mlx5dr_action_flags flags[MLX5DR_TABLE_TYPE_MAX] = {
+               MLX5DR_ACTION_FLAG_HWS_RX,
+               MLX5DR_ACTION_FLAG_HWS_TX,
+               MLX5DR_ACTION_FLAG_HWS_FDB
+       };
+
+       for (i = MLX5DR_TABLE_TYPE_NIC_RX; i < MLX5DR_TABLE_TYPE_MAX; i++) {
+               priv->hw_pop_vlan[i] =
+                       mlx5dr_action_create_pop_vlan(priv->dr_ctx, flags[i]);
+               if (!priv->hw_pop_vlan[i])
+                       return -ENOENT;
+               priv->hw_push_vlan[i] =
+                       mlx5dr_action_create_push_vlan(priv->dr_ctx, flags[i]);
+               if (!priv->hw_pop_vlan[i])
+                       return -ENOENT;
+       }
+       return 0;
+}
+
 /**
  * Configure port HWS resources.
  *
@@ -4915,6 +5232,9 @@ flow_hw_configure(struct rte_eth_dev *dev,
                if (priv->hws_cpool == NULL)
                        goto err;
        }
+       ret = flow_hw_create_vlan(dev);
+       if (ret)
+               goto err;
        return 0;
 err:
        if (priv->hws_ctpool) {
@@ -4928,6 +5248,7 @@ flow_hw_configure(struct rte_eth_dev *dev,
                if (priv->hw_tag[i])
                        mlx5dr_action_destroy(priv->hw_tag[i]);
        }
+       flow_hw_destroy_vlan(dev);
        if (dr_ctx)
                claim_zero(mlx5dr_context_close(dr_ctx));
        mlx5_free(priv->hw_q);
@@ -4986,6 +5307,7 @@ flow_hw_resource_release(struct rte_eth_dev *dev)
                if (priv->hw_tag[i])
                        mlx5dr_action_destroy(priv->hw_tag[i]);
        }
+       flow_hw_destroy_vlan(dev);
        flow_hw_free_vport_actions(priv);
        if (priv->acts_ipool) {
                mlx5_ipool_destroy(priv->acts_ipool);
-- 
2.25.1

Reply via email to