> -----Original Message----- > From: Moti Haimovsky <mo...@mellanox.com> > Sent: Monday, September 9, 2019 18:57 > To: Slava Ovsiienko <viachesl...@mellanox.com>; Raslan Darawsheh > <rasl...@mellanox.com> > Cc: dev@dpdk.org > Subject: [PATCH v5 4/7] net/mlx5: support push flow action on VLAN header > > This commit adds support for RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN > using direct verbs flow rules. > If present in the flow, The VLAN default values are taken from the VLAN item > configuration. > In this commit only the VLAN TPID value can be set since VLAN modification > actions are not supported yet. > > Signed-off-by: Moti Haimovsky <mo...@mellanox.com> Acked-by: Viacheslav Ovsiienko <viachesl...@mellanox.com>
> --- > v5: > - Fixed bug in retrieving VLAN VID and PCP from the existing VLAN flow item. > --- > > doc/guides/nics/mlx5.rst | 6 +- > doc/guides/rel_notes/release_19_11.rst | 1 + > drivers/net/mlx5/mlx5.h | 2 + > drivers/net/mlx5/mlx5_flow.h | 18 ++- > drivers/net/mlx5/mlx5_flow_dv.c | 272 > +++++++++++++++++++++++++++++++++ > 5 files changed, 295 insertions(+), 4 deletions(-) > > diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst index > 2ae2e8f..875a87f 100644 > --- a/doc/guides/nics/mlx5.rst > +++ b/doc/guides/nics/mlx5.rst > @@ -130,6 +130,8 @@ Limitations > are lacking a match on VLAN as one of their items are not supported. > - The command is not supported on egress traffic. > > +- VLAN push offload is not supported on ingress traffic. > + > - A multi segment packet must have not more segments than reported by > dev_infos_get() > in tx_desc_lim.nb_seg_max field. This value depends on maximal supported > Tx descriptor > size and ``txq_inline_min`` settings and may be from 2 (worst case forced > by maximal @@ -1039,8 +1041,8 @@ Supported hardware offloads > | | | ConnectX-5 | | N/A | > +-----------------------+-----------------+-----------------+ > | | VLAN | | DPDK 19.11 | | DPDK 19.11 | > - | | (of_pop_vlan) | | OFED 4.6-4 | | OFED 4.6-4 | > - | | | ConnectX-5 | | ConnectX-5 | > + | | (of_pop_vlan / | | OFED 4.6-4 | | OFED 4.6-4 | > + | | of_push_vlan) | | ConnectX-5 | | ConnectX-5 | > +-----------------------+-----------------+-----------------+ > > Notes for testpmd > diff --git a/doc/guides/rel_notes/release_19_11.rst > b/doc/guides/rel_notes/release_19_11.rst > index 5c2ac15..afe92ab 100644 > --- a/doc/guides/rel_notes/release_19_11.rst > +++ b/doc/guides/rel_notes/release_19_11.rst > @@ -228,4 +228,5 @@ Tested Platforms > Updated Mellanox mlx5 driver with new features and improvements, > including: > > * Added support for VLAN pop flow offload command. > + * Added support for VLAN push flow offload command. > > diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index > a18f588..dbdc3ce 100644 > --- a/drivers/net/mlx5/mlx5.h > +++ b/drivers/net/mlx5/mlx5.h > @@ -579,6 +579,8 @@ struct mlx5_ibv_shared { > LIST_HEAD(jump, mlx5_flow_dv_jump_tbl_resource) jump_tbl; > LIST_HEAD(port_id_action_list, > mlx5_flow_dv_port_id_action_resource) > port_id_action_list; /* List of port ID actions. */ > + LIST_HEAD(push_vlan_action_list, > mlx5_flow_dv_push_vlan_action_resource) > + push_vlan_action_list; /* List of push VLAN actions. */ > struct mlx5_flow_counter_mng cmng; /* Counters management > structure. */ > /* Shared interrupt handler section. */ > pthread_mutex_t intr_mutex; /* Interrupt config mutex. */ diff --git > a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index > 06b0470..15c9c04 100644 > --- a/drivers/net/mlx5/mlx5_flow.h > +++ b/drivers/net/mlx5/mlx5_flow.h > @@ -150,7 +150,8 @@ > > #define MLX5_FLOW_ENCAP_ACTIONS > (MLX5_FLOW_ACTION_VXLAN_ENCAP | \ > MLX5_FLOW_ACTION_NVGRE_ENCAP | \ > - MLX5_FLOW_ACTION_RAW_ENCAP) > + MLX5_FLOW_ACTION_RAW_ENCAP | \ > + MLX5_FLOW_ACTION_OF_PUSH_VLAN) > > #define MLX5_FLOW_DECAP_ACTIONS > (MLX5_FLOW_ACTION_VXLAN_DECAP | \ > MLX5_FLOW_ACTION_NVGRE_DECAP | \ > @@ -172,7 +173,8 @@ > MLX5_FLOW_ACTION_INC_TCP_ACK | \ > MLX5_FLOW_ACTION_DEC_TCP_ACK) > > -#define MLX5_FLOW_VLAN_ACTIONS > (MLX5_FLOW_ACTION_OF_POP_VLAN) > +#define MLX5_FLOW_VLAN_ACTIONS > (MLX5_FLOW_ACTION_OF_POP_VLAN | \ > + MLX5_FLOW_ACTION_OF_PUSH_VLAN) > > #ifndef IPPROTO_MPLS > #define IPPROTO_MPLS 137 > @@ -309,6 +311,16 @@ struct mlx5_flow_dv_port_id_action_resource { > uint32_t port_id; /**< Port ID value. */ }; > > +/* Push VLAN action resource structure */ struct > +mlx5_flow_dv_push_vlan_action_resource { > + LIST_ENTRY(mlx5_flow_dv_push_vlan_action_resource) next; > + /* Pointer to next element. */ > + rte_atomic32_t refcnt; /**< Reference counter. */ > + void *action; /**< Direct verbs action object. */ > + uint8_t ft_type; /**< Flow table type, Rx, Tx or FDB. */ > + rte_be32_t vlan_tag; /**< VLAN tag value. */ }; > + > /* > * Max number of actions per DV flow. > * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED > @@ -335,6 +347,8 @@ struct mlx5_flow_dv { > /**< Pointer to port ID action resource. */ > struct mlx5_vf_vlan vf_vlan; > /**< Structure for VF VLAN workaround. */ > + struct mlx5_flow_dv_push_vlan_action_resource *push_vlan_res; > + /**< Pointer to push VLAN action resource in cache. */ > #ifdef HAVE_IBV_FLOW_DV_SUPPORT > void *actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS]; > /**< Action list. */ > diff --git a/drivers/net/mlx5/mlx5_flow_dv.c > b/drivers/net/mlx5/mlx5_flow_dv.c index fd2e810..2780735 100644 > --- a/drivers/net/mlx5/mlx5_flow_dv.c > +++ b/drivers/net/mlx5/mlx5_flow_dv.c > @@ -50,6 +50,13 @@ > #define MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL 1 #endif > > +/* VLAN header definitions */ > +#define MLX5DV_FLOW_VLAN_PCP_SHIFT 13 > +#define MLX5DV_FLOW_VLAN_PCP_MASK (0x7 << > MLX5DV_FLOW_VLAN_PCP_SHIFT) > +#define MLX5DV_FLOW_VLAN_VID_MASK 0x0fff #define > +MLX5DV_FLOW_VLAN_PCP_MASK_BE > RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK) > +#define MLX5DV_FLOW_VLAN_VID_MASK_BE > +RTE_BE16(MLX5DV_FLOW_VLAN_VID_MASK) > + > union flow_dv_attr { > struct { > uint32_t valid:1; > @@ -817,6 +824,8 @@ struct field_modify_info modify_tcp[] = { > /** > * Validate the pop VLAN action. > * > + * @param[in] dev > + * Pointer to the rte_eth_dev structure. > * @param[in] action_flags > * Holds the actions detected until now. > * @param[in] action > @@ -870,6 +879,101 @@ struct field_modify_info modify_tcp[] = { } > > /** > + * Get VLAN default info from vlan match info. > + * > + * @param[in] dev > + * Pointer to the rte_eth_dev structure. > + * @param[in] item > + * the list of item specifications. > + * @param[out] vlan > + * pointer VLAN info to fill to. > + * @param[out] error > + * Pointer to error structure. > + * > + * @return > + * 0 on success, a negative errno value otherwise and rte_errno is set. > + */ > +static void > +flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items, > + struct rte_vlan_hdr *vlan) > +{ > + const struct rte_flow_item_vlan nic_mask = { > + .tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK | > + MLX5DV_FLOW_VLAN_VID_MASK), > + .inner_type = RTE_BE16(0xffff), > + }; > + > + if (items == NULL) > + return; > + for (; items->type != RTE_FLOW_ITEM_TYPE_END && > + items->type != RTE_FLOW_ITEM_TYPE_VLAN; items++) > + ; > + if (items->type == RTE_FLOW_ITEM_TYPE_VLAN) { > + const struct rte_flow_item_vlan *vlan_m = items->mask; > + const struct rte_flow_item_vlan *vlan_v = items->spec; > + > + if (!vlan_m) > + vlan_m = &nic_mask; > + /* Only full match values are accepted */ > + if ((vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) == > + MLX5DV_FLOW_VLAN_PCP_MASK_BE) { > + vlan->vlan_tci &= MLX5DV_FLOW_VLAN_PCP_MASK; > + vlan->vlan_tci |= > + rte_be_to_cpu_16(vlan_v->tci & > + > MLX5DV_FLOW_VLAN_PCP_MASK_BE); > + } > + if ((vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) == > + MLX5DV_FLOW_VLAN_VID_MASK_BE) { > + vlan->vlan_tci &= > ~MLX5DV_FLOW_VLAN_VID_MASK; > + vlan->vlan_tci |= > + rte_be_to_cpu_16(vlan_v->tci & > + > MLX5DV_FLOW_VLAN_VID_MASK_BE); > + } > + if (vlan_m->inner_type == nic_mask.inner_type) > + vlan->eth_proto = rte_be_to_cpu_16(vlan_v- > >inner_type & > + vlan_m- > >inner_type); > + } > +} > + > +/** > + * Validate the push VLAN action. > + * > + * @param[in] action_flags > + * Holds the actions detected until now. > + * @param[in] action > + * Pointer to the encap action. > + * @param[in] attr > + * Pointer to flow attributes > + * @param[out] error > + * Pointer to error structure. > + * > + * @return > + * 0 on success, a negative errno value otherwise and rte_errno is set. > + */ > +static int > +flow_dv_validate_action_push_vlan(uint64_t action_flags, > + const struct rte_flow_action *action, > + const struct rte_flow_attr *attr, > + struct rte_flow_error *error) > +{ > + const struct rte_flow_action_of_push_vlan *push_vlan = action- > >conf; > + > + if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) && > + push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ)) > + return rte_flow_error_set(error, EINVAL, > + RTE_FLOW_ERROR_TYPE_ACTION, > action, > + "invalid vlan ethertype"); > + if (action_flags & > + (MLX5_FLOW_ACTION_OF_POP_VLAN | > MLX5_FLOW_ACTION_OF_PUSH_VLAN)) > + return rte_flow_error_set(error, ENOTSUP, > + RTE_FLOW_ERROR_TYPE_ACTION, > action, > + "no support for multiple VLAN " > + "actions"); > + (void)attr; > + return 0; > +} > + > +/** > * Validate count action. > * > * @param[in] dev > @@ -1300,6 +1404,77 @@ struct field_modify_info modify_tcp[] = { } > > /** > + * Find existing push vlan resource or create and register a new one. > + * > + * @param dev[in, out] > + * Pointer to rte_eth_dev structure. > + * @param[in, out] resource > + * Pointer to port ID action resource. > + * @parm[in, out] dev_flow > + * Pointer to the dev_flow. > + * @param[out] error > + * pointer to error structure. > + * > + * @return > + * 0 on success otherwise -errno and errno is set. > + */ > +static int > +flow_dv_push_vlan_action_resource_register > + (struct rte_eth_dev *dev, > + struct mlx5_flow_dv_push_vlan_action_resource > *resource, > + struct mlx5_flow *dev_flow, > + struct rte_flow_error *error) > +{ > + struct mlx5_priv *priv = dev->data->dev_private; > + struct mlx5_ibv_shared *sh = priv->sh; > + struct mlx5_flow_dv_push_vlan_action_resource *cache_resource; > + struct mlx5dv_dr_domain *domain; > + > + /* Lookup a matching resource from cache. */ > + LIST_FOREACH(cache_resource, &sh->push_vlan_action_list, next) { > + if (resource->vlan_tag == cache_resource->vlan_tag && > + resource->ft_type == cache_resource->ft_type) { > + DRV_LOG(DEBUG, "push-VLAN action resource > resource %p: " > + "refcnt %d++", > + (void *)cache_resource, > + rte_atomic32_read(&cache_resource- > >refcnt)); > + rte_atomic32_inc(&cache_resource->refcnt); > + dev_flow->dv.push_vlan_res = cache_resource; > + return 0; > + } > + } > + /* Register new push_vlan action resource. */ > + cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), > 0); > + if (!cache_resource) > + return rte_flow_error_set(error, ENOMEM, > + > RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, > + "cannot allocate resource > memory"); > + *cache_resource = *resource; > + if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) > + domain = sh->fdb_domain; > + else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) > + domain = sh->rx_domain; > + else > + domain = sh->tx_domain; > + cache_resource->action = > + mlx5_glue->dr_create_flow_action_push_vlan(domain, > + resource- > >vlan_tag); > + if (!cache_resource->action) { > + rte_free(cache_resource); > + return rte_flow_error_set(error, ENOMEM, > + > RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > + NULL, "cannot create action"); > + } > + rte_atomic32_init(&cache_resource->refcnt); > + rte_atomic32_inc(&cache_resource->refcnt); > + LIST_INSERT_HEAD(&sh->push_vlan_action_list, cache_resource, > next); > + dev_flow->dv.push_vlan_res = cache_resource; > + DRV_LOG(DEBUG, "new push vlan action resource %p: refcnt %d++", > + (void *)cache_resource, > + rte_atomic32_read(&cache_resource->refcnt)); > + return 0; > +} > +/** > * Get the size of specific rte_flow_item_type > * > * @param[in] item_type > @@ -1719,6 +1894,44 @@ struct field_modify_info modify_tcp[] = { } > > /** > + * Create action push VLAN. > + * > + * @param[in] dev > + * Pointer to rte_eth_dev structure. > + * @param[in] vlan_tag > + * the vlan tag to push to the Ethernet header. > + * @param[in, out] dev_flow > + * Pointer to the mlx5_flow. > + * @param[in] attr > + * Pointer to the flow attributes. > + * @param[out] error > + * Pointer to the error structure. > + * > + * @return > + * 0 on success, a negative errno value otherwise and rte_errno is set. > + */ > +static int > +flow_dv_create_action_push_vlan(struct rte_eth_dev *dev, > + const struct rte_flow_attr *attr, > + const struct rte_vlan_hdr *vlan, > + struct mlx5_flow *dev_flow, > + struct rte_flow_error *error) > +{ > + struct mlx5_flow_dv_push_vlan_action_resource res; > + > + res.vlan_tag = > + rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 | > + vlan->vlan_tci); > + if (attr->transfer) > + res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; > + else > + res.ft_type = attr->egress ? > MLX5DV_FLOW_TABLE_TYPE_NIC_TX : > + > MLX5DV_FLOW_TABLE_TYPE_NIC_RX; > + return flow_dv_push_vlan_action_resource_register > + (dev, &res, dev_flow, error); > +} > + > +/** > * Validate the modify-header actions. > * > * @param[in] action_flags > @@ -3174,6 +3387,15 @@ struct field_modify_info modify_tcp[] = { > action_flags |= > MLX5_FLOW_ACTION_OF_POP_VLAN; > ++actions_n; > break; > + case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: > + ret = > flow_dv_validate_action_push_vlan(action_flags, > + actions, attr, > + error); > + if (ret < 0) > + return ret; > + action_flags |= > MLX5_FLOW_ACTION_OF_PUSH_VLAN; > + ++actions_n; > + break; > case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: > case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: > ret = > flow_dv_validate_action_l2_encap(action_flags, > @@ -4765,6 +4987,8 @@ struct field_modify_info modify_tcp[] = { > void *match_mask = matcher.mask.buf; > void *match_value = dev_flow->dv.value.buf; > uint8_t next_protocol = 0xff; > + struct rte_vlan_hdr vlan = { 0 }; > + bool vlan_inherited = false; > > flow->group = attr->group; > if (attr->transfer) > @@ -4879,6 +5103,21 @@ struct field_modify_info modify_tcp[] = { > priv->sh->pop_vlan_action; > action_flags |= > MLX5_FLOW_ACTION_OF_POP_VLAN; > break; > + case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: > + if (!vlan_inherited) { > + flow_dev_get_vlan_info_from_items(items, > &vlan); > + vlan_inherited = true; > + } > + vlan.eth_proto = rte_be_to_cpu_16 > + ((((const struct rte_flow_action_of_push_vlan *) > + actions->conf)- > >ethertype)); > + if (flow_dv_create_action_push_vlan > + (dev, attr, &vlan, dev_flow, error)) > + return -rte_errno; > + dev_flow->dv.actions[actions_n++] = > + dev_flow->dv.push_vlan_res- > >action; > + action_flags |= > MLX5_FLOW_ACTION_OF_PUSH_VLAN; > + break; > case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: > case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: > if (flow_dv_create_action_l2_encap(dev, actions, > @@ -5526,6 +5765,37 @@ struct field_modify_info modify_tcp[] = { } > > /** > + * Release push vlan action resource. > + * > + * @param flow > + * Pointer to mlx5_flow. > + * > + * @return > + * 1 while a reference on it exists, 0 when freed. > + */ > +static int > +flow_dv_push_vlan_action_resource_release(struct mlx5_flow *flow) { > + struct mlx5_flow_dv_push_vlan_action_resource *cache_resource = > + flow->dv.push_vlan_res; > + > + assert(cache_resource->action); > + DRV_LOG(DEBUG, "push VLAN action resource %p: refcnt %d--", > + (void *)cache_resource, > + rte_atomic32_read(&cache_resource->refcnt)); > + if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) { > + claim_zero(mlx5_glue->destroy_flow_action > + (cache_resource->action)); > + LIST_REMOVE(cache_resource, next); > + rte_free(cache_resource); > + DRV_LOG(DEBUG, "push vlan action resource %p: removed", > + (void *)cache_resource); > + return 0; > + } > + return 1; > +} > + > +/** > * Remove the flow from the NIC but keeps it in memory. > * > * @param[in] dev > @@ -5597,6 +5867,8 @@ struct field_modify_info modify_tcp[] = { > flow_dv_jump_tbl_resource_release(dev_flow); > if (dev_flow->dv.port_id_action) > > flow_dv_port_id_action_resource_release(dev_flow); > + if (dev_flow->dv.push_vlan_res) > + > flow_dv_push_vlan_action_resource_release(dev_flow); > rte_free(dev_flow); > } > } > -- > 1.8.3.1