net/mlx5: add header reformat HW steering action
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_hw.c
index 29c2e02..2c2bd0f 100644 (file)
@@ -332,6 +332,50 @@ __flow_hw_act_data_general_append(struct mlx5_priv *priv,
        return 0;
 }
 
+/**
+ * Append dynamic encap action to the dynamic action list.
+ *
+ * @param[in] priv
+ *   Pointer to the port private data structure.
+ * @param[in] acts
+ *   Pointer to the template HW steering DR actions.
+ * @param[in] type
+ *   Action type.
+ * @param[in] action_src
+ *   Offset of source rte flow action.
+ * @param[in] action_dst
+ *   Offset of destination DR action.
+ * @param[in] encap_src
+ *   Offset of source encap raw data.
+ * @param[in] encap_dst
+ *   Offset of destination encap raw data.
+ * @param[in] len
+ *   Length of the data to be updated.
+ *
+ * @return
+ *    0 on success, negative value otherwise and rte_errno is set.
+ */
+static __rte_always_inline int
+__flow_hw_act_data_encap_append(struct mlx5_priv *priv,
+                               struct mlx5_hw_actions *acts,
+                               enum rte_flow_action_type type,
+                               uint16_t action_src,
+                               uint16_t action_dst,
+                               uint16_t encap_src,
+                               uint16_t encap_dst,
+                               uint16_t len)
+{      struct mlx5_action_construct_data *act_data;
+
+       act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst);
+       if (!act_data)
+               return -1;
+       act_data->encap.src = encap_src;
+       act_data->encap.dst = encap_dst;
+       act_data->encap.len = len;
+       LIST_INSERT_HEAD(&acts->act_list, act_data, next);
+       return 0;
+}
+
 /**
  * Append shared RSS action to the dynamic action list.
  *
@@ -422,6 +466,53 @@ flow_hw_shared_action_translate(struct rte_eth_dev *dev,
        return 0;
 }
 
+/**
+ * Translate encap items to encapsulation list.
+ *
+ * @param[in] dev
+ *   Pointer to the rte_eth_dev data structure.
+ * @param[in] acts
+ *   Pointer to the template HW steering DR actions.
+ * @param[in] type
+ *   Action type.
+ * @param[in] action_src
+ *   Offset of source rte flow action.
+ * @param[in] action_dst
+ *   Offset of destination DR action.
+ * @param[in] items
+ *   Encap item pattern.
+ * @param[in] items_m
+ *   Encap item mask indicates which part are constant and dynamic.
+ *
+ * @return
+ *    0 on success, negative value otherwise and rte_errno is set.
+ */
+static __rte_always_inline int
+flow_hw_encap_item_translate(struct rte_eth_dev *dev,
+                            struct mlx5_hw_actions *acts,
+                            enum rte_flow_action_type type,
+                            uint16_t action_src,
+                            uint16_t action_dst,
+                            const struct rte_flow_item *items,
+                            const struct rte_flow_item *items_m)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       size_t len, total_len = 0;
+       uint32_t i = 0;
+
+       for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++, items_m++, i++) {
+               len = flow_dv_get_item_hdr_len(items->type);
+               if ((!items_m->spec ||
+                   memcmp(items_m->spec, items->spec, len)) &&
+                   __flow_hw_act_data_encap_append(priv, acts, type,
+                                                   action_src, action_dst, i,
+                                                   total_len, len))
+                       return -1;
+               total_len += len;
+       }
+       return 0;
+}
+
 /**
  * Translate rte_flow actions to DR action.
  *
@@ -459,6 +550,12 @@ flow_hw_actions_translate(struct rte_eth_dev *dev,
        struct rte_flow_action *actions = at->actions;
        struct rte_flow_action *action_start = actions;
        struct rte_flow_action *masks = at->masks;
+       enum mlx5dr_action_reformat_type refmt_type = 0;
+       const struct rte_flow_action_raw_encap *raw_encap_data;
+       const struct rte_flow_item *enc_item = NULL, *enc_item_m = NULL;
+       uint16_t reformat_pos = MLX5_HW_MAX_ACTS, reformat_src = 0;
+       uint8_t *encap_data = NULL;
+       size_t data_size = 0;
        bool actions_end = false;
        uint32_t type, i;
        int err;
@@ -560,6 +657,56 @@ flow_hw_actions_translate(struct rte_eth_dev *dev,
                        }
                        i++;
                        break;
+               case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
+                       MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS);
+                       enc_item = ((const struct rte_flow_action_vxlan_encap *)
+                                  actions->conf)->definition;
+                       enc_item_m =
+                               ((const struct rte_flow_action_vxlan_encap *)
+                                masks->conf)->definition;
+                       reformat_pos = i++;
+                       reformat_src = actions - action_start;
+                       refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2;
+                       break;
+               case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
+                       MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS);
+                       enc_item = ((const struct rte_flow_action_nvgre_encap *)
+                                  actions->conf)->definition;
+                       enc_item_m =
+                               ((const struct rte_flow_action_nvgre_encap *)
+                               actions->conf)->definition;
+                       reformat_pos = i++;
+                       reformat_src = actions - action_start;
+                       refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2;
+                       break;
+               case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+               case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
+                       MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS);
+                       reformat_pos = i++;
+                       refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2;
+                       break;
+               case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+                       raw_encap_data =
+                               (const struct rte_flow_action_raw_encap *)
+                                actions->conf;
+                       encap_data = raw_encap_data->data;
+                       data_size = raw_encap_data->size;
+                       if (reformat_pos != MLX5_HW_MAX_ACTS) {
+                               refmt_type = data_size <
+                               MLX5_ENCAPSULATION_DECISION_SIZE ?
+                               MLX5DR_ACTION_REFORMAT_TYPE_TNL_L3_TO_L2 :
+                               MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L3;
+                       } else {
+                               reformat_pos = i++;
+                               refmt_type =
+                               MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2;
+                       }
+                       reformat_src = actions - action_start;
+                       break;
+               case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+                       reformat_pos = i++;
+                       refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2;
+                       break;
                case RTE_FLOW_ACTION_TYPE_END:
                        actions_end = true;
                        break;
@@ -567,6 +714,45 @@ flow_hw_actions_translate(struct rte_eth_dev *dev,
                        break;
                }
        }
+       if (reformat_pos != MLX5_HW_MAX_ACTS) {
+               uint8_t buf[MLX5_ENCAP_MAX_LEN];
+
+               if (enc_item) {
+                       MLX5_ASSERT(!encap_data);
+                       if (flow_dv_convert_encap_data
+                               (enc_item, buf, &data_size, error) ||
+                           flow_hw_encap_item_translate
+                               (dev, acts, (action_start + reformat_src)->type,
+                                reformat_src, reformat_pos,
+                                enc_item, enc_item_m))
+                               goto err;
+                       encap_data = buf;
+               } else if (encap_data && __flow_hw_act_data_encap_append
+                               (priv, acts,
+                                (action_start + reformat_src)->type,
+                                reformat_src, reformat_pos, 0, 0, data_size)) {
+                       goto err;
+               }
+               acts->encap_decap = mlx5_malloc(MLX5_MEM_ZERO,
+                                   sizeof(*acts->encap_decap) + data_size,
+                                   0, SOCKET_ID_ANY);
+               if (!acts->encap_decap)
+                       goto err;
+               if (data_size) {
+                       acts->encap_decap->data_size = data_size;
+                       memcpy(acts->encap_decap->data, encap_data, data_size);
+               }
+               acts->encap_decap->action = mlx5dr_action_create_reformat
+                               (priv->dr_ctx, refmt_type,
+                                data_size, encap_data,
+                                rte_log2_u32(table_attr->nb_flows),
+                                mlx5_hw_act_flag[!!attr->group][type]);
+               if (!acts->encap_decap->action)
+                       goto err;
+               acts->rule_acts[reformat_pos].action =
+                                               acts->encap_decap->action;
+               acts->encap_decap_pos = reformat_pos;
+       }
        acts->acts_num = i;
        return 0;
 err:
@@ -722,6 +908,9 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,
        struct rte_flow_template_table *table = job->flow->table;
        struct mlx5_action_construct_data *act_data;
        const struct rte_flow_action *action;
+       const struct rte_flow_action_raw_encap *raw_encap_data;
+       const struct rte_flow_item *enc_item = NULL;
+       uint8_t *buf = job->encap_data;
        struct rte_flow_attr attr = {
                        .ingress = 1,
        };
@@ -743,6 +932,9 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,
        } else {
                attr.ingress = 1;
        }
+       if (hw_acts->encap_decap && hw_acts->encap_decap->data_size)
+               memcpy(buf, hw_acts->encap_decap->data,
+                      hw_acts->encap_decap->data_size);
        LIST_FOREACH(act_data, &hw_acts->act_list, next) {
                uint32_t jump_group;
                uint32_t tag;
@@ -798,10 +990,38 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,
                                 &rule_acts[act_data->action_dst]))
                                return -1;
                        break;
+               case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
+                       enc_item = ((const struct rte_flow_action_vxlan_encap *)
+                                  action->conf)->definition;
+                       rte_memcpy((void *)&buf[act_data->encap.dst],
+                                  enc_item[act_data->encap.src].spec,
+                                  act_data->encap.len);
+                       break;
+               case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
+                       enc_item = ((const struct rte_flow_action_nvgre_encap *)
+                                  action->conf)->definition;
+                       rte_memcpy((void *)&buf[act_data->encap.dst],
+                                  enc_item[act_data->encap.src].spec,
+                                  act_data->encap.len);
+                       break;
+               case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+                       raw_encap_data =
+                               (const struct rte_flow_action_raw_encap *)
+                                action->conf;
+                       rte_memcpy((void *)&buf[act_data->encap.dst],
+                                  raw_encap_data->data, act_data->encap.len);
+                       MLX5_ASSERT(raw_encap_data->size ==
+                                   act_data->encap.len);
+                       break;
                default:
                        break;
                }
        }
+       if (hw_acts->encap_decap) {
+               rule_acts[hw_acts->encap_decap_pos].reformat.offset =
+                               job->flow->idx - 1;
+               rule_acts[hw_acts->encap_decap_pos].reformat.data = buf;
+       }
        return 0;
 }
 
@@ -1865,6 +2085,7 @@ flow_hw_configure(struct rte_eth_dev *dev,
                        goto err;
                }
                mem_size += (sizeof(struct mlx5_hw_q_job *) +
+                           sizeof(uint8_t) * MLX5_ENCAP_MAX_LEN +
                            sizeof(struct mlx5_hw_q_job)) *
                            queue_attr[0]->size;
        }
@@ -1875,6 +2096,8 @@ flow_hw_configure(struct rte_eth_dev *dev,
                goto err;
        }
        for (i = 0; i < nb_queue; i++) {
+               uint8_t *encap = NULL;
+
                priv->hw_q[i].job_idx = queue_attr[i]->size;
                priv->hw_q[i].size = queue_attr[i]->size;
                if (i == 0)
@@ -1885,8 +2108,11 @@ flow_hw_configure(struct rte_eth_dev *dev,
                                            &job[queue_attr[i - 1]->size];
                job = (struct mlx5_hw_q_job *)
                      &priv->hw_q[i].job[queue_attr[i]->size];
-               for (j = 0; j < queue_attr[i]->size; j++)
+               encap = (uint8_t *)&job[queue_attr[i]->size];
+               for (j = 0; j < queue_attr[i]->size; j++) {
+                       job[j].encap_data = &encap[j * MLX5_ENCAP_MAX_LEN];
                        priv->hw_q[i].job[j] = &job[j];
+               }
        }
        dr_ctx_attr.pd = priv->sh->cdev->pd;
        dr_ctx_attr.queues = nb_queue;