> -----Original Message----- > From: Ori Kam > Sent: Thursday, March 28, 2019 18:33 > To: Matan Azrad <ma...@mellanox.com>; Yongseok Koh > <ys...@mellanox.com>; Shahaf Shuler <shah...@mellanox.com> > Cc: dev@dpdk.org; Ori Kam <or...@mellanox.com>; Slava Ovsiienko > <viachesl...@mellanox.com> > Subject: [PATCH v2 3/3] net/mlx5: add jump action support for NIC > > When using Direct Rules we can add actions to jump between tables. > This is extra useful since rule insertion rate is much higher on other tables > compared to table zero. > > if no group is selected the rule is added to group 0. > > Signed-off-by: Ori Kam <or...@mellanox.com> Acked-by: Viacheslav Ovsiienko <viachesl...@mellanox.com>
> --- > drivers/net/mlx5/mlx5.h | 6 + > drivers/net/mlx5/mlx5_flow.h | 15 ++- > drivers/net/mlx5/mlx5_flow_dv.c | 278 > +++++++++++++++++++++++++++++++++++----- > drivers/net/mlx5/mlx5_glue.c | 13 ++ > drivers/net/mlx5/mlx5_glue.h | 1 + > 5 files changed, 282 insertions(+), 31 deletions(-) > > diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index > 73f6f0d..a3d5f8e 100644 > --- a/drivers/net/mlx5/mlx5.h > +++ b/drivers/net/mlx5/mlx5.h > @@ -279,6 +279,12 @@ struct mlx5_priv { > LIST_HEAD(encap_decap, mlx5_flow_dv_encap_decap_resource) > encaps_decaps; > LIST_HEAD(modify_cmd, mlx5_flow_dv_modify_hdr_resource) > modify_cmds; > LIST_HEAD(tag, mlx5_flow_dv_tag_resource) tags; > + LIST_HEAD(jump, mlx5_flow_dv_jump_tbl_resource) jump_tbl; > + /* Pointer to next element. */ > + rte_atomic32_t refcnt; /**< Reference counter. */ > + struct ibv_flow_action *verbs_action; > + /**< Verbs modify header action object. */ > + uint8_t ft_type; /**< Flow table type, Rx or Tx. */ > /* Tags resources cache. */ > uint32_t link_speed_capa; /* Link speed capabilities. */ > struct mlx5_xstats_ctrl xstats_ctrl; /* Extended stats control. */ diff > -- > git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index > 8ba37a0..622e305 100644 > --- a/drivers/net/mlx5/mlx5_flow.h > +++ b/drivers/net/mlx5/mlx5_flow.h > @@ -115,7 +115,8 @@ > #define MLX5_FLOW_ACTION_RAW_DECAP (1u << 27) > > #define MLX5_FLOW_FATE_ACTIONS \ > - (MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | > MLX5_FLOW_ACTION_RSS) > + (MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | \ > + MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_JUMP) > > #define MLX5_FLOW_ENCAP_ACTIONS > (MLX5_FLOW_ACTION_VXLAN_ENCAP | \ > MLX5_FLOW_ACTION_NVGRE_ENCAP | \ > @@ -250,6 +251,16 @@ struct mlx5_flow_dv_modify_hdr_resource { > /**< Modification actions. */ > }; > > +/* Jump action resource structure. */ > +struct mlx5_flow_dv_jump_tbl_resource { > + LIST_ENTRY(mlx5_flow_dv_jump_tbl_resource) next; > + /* Pointer to next element. */ > + rte_atomic32_t refcnt; /**< Reference counter. */ > + void *action; /**< Pointer to the rdma core action. */ > + uint8_t ft_type; /**< Flow table type, Rx or Tx. */ > + struct mlx5_flow_tbl_resource *tbl; /**< The target table. */ }; > + > /* > * Max number of actions per DV flow. > * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED > @@ -270,6 +281,8 @@ struct mlx5_flow_dv { > struct mlx5_flow_dv_modify_hdr_resource *modify_hdr; > /**< Pointer to modify header resource in cache. */ > struct ibv_flow *flow; /**< Installed flow. */ > + struct mlx5_flow_dv_jump_tbl_resource *jump; > + /**< Pointer to the jump action resource. */ > #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 6e4f6c4..6997dc6 100644 > --- a/drivers/net/mlx5/mlx5_flow_dv.c > +++ b/drivers/net/mlx5/mlx5_flow_dv.c > @@ -861,6 +861,68 @@ struct field_modify_info modify_tcp[] = { } > > /** > + * Find existing table jump resource or create and register a new one. > + * > + * @param dev[in, out] > + * Pointer to rte_eth_dev structure. > + * @param[in, out] resource > + * Pointer to jump table 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_jump_tbl_resource_register > + (struct rte_eth_dev *dev, > + struct mlx5_flow_dv_jump_tbl_resource *resource, > + struct mlx5_flow *dev_flow, > + struct rte_flow_error *error) > +{ > + struct mlx5_priv *priv = dev->data->dev_private; > + struct mlx5_flow_dv_jump_tbl_resource *cache_resource; > + > + /* Lookup a matching resource from cache. */ > + LIST_FOREACH(cache_resource, &priv->jump_tbl, next) { > + if (resource->tbl == cache_resource->tbl) { > + DRV_LOG(DEBUG, "jump table resource resource %p: > refcnt %d++", > + (void *)cache_resource, > + rte_atomic32_read(&cache_resource- > >refcnt)); > + rte_atomic32_inc(&cache_resource->refcnt); > + dev_flow->dv.jump = cache_resource; > + return 0; > + } > + } > + /* Register new jump table 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; > + cache_resource->action = > + mlx5_glue->dr_create_flow_action_dest_flow_tbl > + (resource->tbl->obj); > + 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(&priv->jump_tbl, cache_resource, next); > + dev_flow->dv.jump = cache_resource; > + DRV_LOG(DEBUG, "new jump table 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 > @@ -1423,6 +1485,37 @@ struct field_modify_info modify_tcp[] = { } > > /** > + * Validate jump action. > + * > + * @param[in] action > + * Pointer to the modify action. > + * @param[in] group > + * The group of the current flow. > + * @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_jump(const struct rte_flow_action *action, > + uint32_t group, > + struct rte_flow_error *error) > +{ > + if (action->type != RTE_FLOW_ACTION_TYPE_JUMP && !action->conf) > + return rte_flow_error_set(error, EINVAL, > + > RTE_FLOW_ERROR_TYPE_ACTION_CONF, > + NULL, "action configuration not > set"); > + if (group >= ((const struct rte_flow_action_jump *)action->conf)- > >group) > + return rte_flow_error_set(error, EINVAL, > + RTE_FLOW_ERROR_TYPE_ACTION, > NULL, > + "target group must be higher then" > + " the current flow group"); > + return 0; > +} > + > + > +/** > * Find existing modify-header resource or create and register a new one. > * > * @param dev[in, out] > @@ -1605,7 +1698,7 @@ struct field_modify_info modify_tcp[] = { > struct mlx5_priv *priv = dev->data->dev_private; > uint32_t priority_max = priv->config.flow_prio - 1; > > -#ifdef HAVE_MLX5DV_DR > +#ifndef HAVE_MLX5DV_DR > if (attributes->group) > return rte_flow_error_set(error, ENOTSUP, > > RTE_FLOW_ERROR_TYPE_ATTR_GROUP, > @@ -1977,6 +2070,14 @@ struct field_modify_info modify_tcp[] = { > > MLX5_FLOW_ACTION_SET_TTL : > > MLX5_FLOW_ACTION_DEC_TTL; > break; > + case RTE_FLOW_ACTION_TYPE_JUMP: > + ret = flow_dv_validate_action_jump(actions, > + attr->group, error); > + if (ret) > + return ret; > + ++actions_n; > + action_flags |= MLX5_FLOW_ACTION_JUMP; > + break; > default: > return rte_flow_error_set(error, ENOTSUP, > > RTE_FLOW_ERROR_TYPE_ACTION, > @@ -2756,6 +2857,73 @@ struct field_modify_info modify_tcp[] = { > return match_criteria_enable; > } > > + > +/** > + * Get a flow table. > + * > + * @param dev[in, out] > + * Pointer to rte_eth_dev structure. > + * @param[in] table_id > + * Table id to use. > + * @param[in] egress > + * Direction of the table. > + * @param[out] error > + * pointer to error structure. > + * > + * @return > + * Returns tables resource based on the index, NULL in case of failed. > + */ > +static struct mlx5_flow_tbl_resource * > +flow_dv_tbl_resource_get(struct rte_eth_dev *dev, > + uint32_t table_id, uint8_t egress, > + struct rte_flow_error *error) > +{ > + struct mlx5_priv *priv = dev->data->dev_private; > + struct mlx5_flow_tbl_resource *tbl; > + > + if (egress) { > + tbl = &priv->tx_tbl[table_id]; > + if (!tbl->obj) > + tbl->obj = mlx5_glue->dr_create_flow_tbl > + (priv->tx_ns, table_id); > + } else { > + tbl = &priv->rx_tbl[table_id]; > + if (!tbl->obj) > + tbl->obj = mlx5_glue->dr_create_flow_tbl > + (priv->rx_ns, table_id); > + } > + if (!tbl->obj) { > + rte_flow_error_set(error, ENOMEM, > + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > + NULL, "cannot create table"); > + return NULL; > + } > + rte_atomic32_inc(&tbl->refcnt); > + return tbl; > +} > + > +/** > + * Release a flow table. > + * > + * @param[in] tbl > + * Table resource to be released. > + * > + * @return > + * Returns 0 if table was released, else return 1; > + */ > +static int > +flow_dv_tbl_resource_release(struct mlx5_flow_tbl_resource *tbl) { > + if (!tbl) > + return 0; > + if (rte_atomic32_dec_and_test(&tbl->refcnt)) { > + mlx5_glue->dr_destroy_flow_tbl(tbl->obj); > + tbl->obj = NULL; > + return 0; > + } > + return 1; > +} > + > /** > * Register the flow matcher. > * > @@ -2784,6 +2952,9 @@ struct field_modify_info modify_tcp[] = { > .match_mask = (void *)&matcher->mask, > }; > struct mlx5_flow_tbl_resource *tbl = NULL; > +#ifndef HAVE_MLX5DV_DR > + struct mlx5_flow_tbl_resource tbl_tmp; #endif > > /* Lookup from cache. */ > LIST_FOREACH(cache_matcher, &priv->matchers, next) { @@ - > 2805,33 +2976,24 @@ struct field_modify_info modify_tcp[] = { > return 0; > } > } > -#ifdef HAVE_MLX5DV_DR > - if (matcher->egress) { > - tbl = &priv->tx_tbl[matcher->group]; > - if (!tbl->obj) > - tbl->obj = mlx5_glue->dr_create_flow_tbl > - (priv->tx_ns, > - matcher->group * MLX5_GROUP_FACTOR); > - } else { > - tbl = &priv->rx_tbl[matcher->group]; > - if (!tbl->obj) > - tbl->obj = mlx5_glue->dr_create_flow_tbl > - (priv->rx_ns, > - matcher->group * MLX5_GROUP_FACTOR); > - } > - if (!tbl->obj) > - return rte_flow_error_set(error, ENOMEM, > - > RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > - NULL, "cannot create table"); > - > - rte_atomic32_inc(&tbl->refcnt); > -#endif > /* Register new matcher. */ > cache_matcher = rte_calloc(__func__, 1, sizeof(*cache_matcher), 0); > if (!cache_matcher) > return rte_flow_error_set(error, ENOMEM, > > RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, > "cannot allocate matcher memory"); > +#ifdef HAVE_MLX5DV_DR > + tbl = flow_dv_tbl_resource_get(dev, matcher->group * > MLX5_GROUP_FACTOR, > + matcher->egress, error); > + if (!tbl) { > + rte_free(cache_matcher); > + return rte_flow_error_set(error, ENOMEM, > + > RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > + NULL, "cannot create table"); > + } > +#else > + tbl = &tbl_tmp; > +#endif > *cache_matcher = *matcher; > dv_attr.match_criteria_enable = > flow_dv_matcher_enable(cache_matcher->mask.buf); > @@ -2844,10 +3006,7 @@ struct field_modify_info modify_tcp[] = { > if (!cache_matcher->matcher_object) { > rte_free(cache_matcher); > #ifdef HAVE_MLX5DV_DR > - if (rte_atomic32_dec_and_test(&tbl->refcnt)) { > - mlx5_glue->dr_destroy_flow_tbl(tbl->obj); > - tbl->obj = NULL; > - } > + flow_dv_tbl_resource_release(tbl); > #endif > return rte_flow_error_set(error, ENOMEM, > > RTE_FLOW_ERROR_TYPE_UNSPECIFIED, @@ -3033,6 +3192,9 @@ struct > field_modify_info modify_tcp[] = { > const struct rte_flow_action *action = actions; > const struct rte_flow_action_count *count = action->conf; > const uint8_t *rss_key; > + const struct rte_flow_action_jump *jump_data; > + struct mlx5_flow_dv_jump_tbl_resource jump_tbl_resource; > + struct mlx5_flow_tbl_resource *tbl; > > switch (actions->type) { > case RTE_FLOW_ACTION_TYPE_VOID: > @@ -3171,6 +3333,31 @@ struct field_modify_info modify_tcp[] = { > /* If decap is followed by encap, handle it at encap. > */ > action_flags |= MLX5_FLOW_ACTION_RAW_DECAP; > break; > + case RTE_FLOW_ACTION_TYPE_JUMP: > + jump_data = action->conf; > + tbl = flow_dv_tbl_resource_get(dev, jump_data- > >group * > + MLX5_GROUP_FACTOR, > + attr->egress, error); > + if (!tbl) > + return rte_flow_error_set > + (error, errno, > + > RTE_FLOW_ERROR_TYPE_ACTION, > + NULL, > + "cannot create jump > action."); > + jump_tbl_resource.tbl = tbl; > + if (flow_dv_jump_tbl_resource_register > + (dev, &jump_tbl_resource, dev_flow, error)) { > + flow_dv_tbl_resource_release(tbl); > + return rte_flow_error_set > + (error, errno, > + > RTE_FLOW_ERROR_TYPE_ACTION, > + NULL, > + "cannot create jump > action."); > + } > + dev_flow->dv.actions[actions_n++] = > + dev_flow->dv.jump->action; > + action_flags |= MLX5_FLOW_ACTION_JUMP; > + break; > case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: > case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: > if (flow_dv_convert_action_modify_mac(&res, > actions, @@ -3503,10 +3690,7 @@ struct field_modify_info modify_tcp[] = { > tbl = &priv->tx_tbl[matcher->group]; > else > tbl = &priv->rx_tbl[matcher->group]; > - if (rte_atomic32_dec_and_test(&tbl->refcnt)) { > - mlx5_glue->dr_destroy_flow_tbl(tbl->obj); > - tbl->obj = NULL; > - } > + flow_dv_tbl_resource_release(tbl); > rte_free(matcher); > DRV_LOG(DEBUG, "port %u matcher %p: removed", > dev->data->port_id, (void *)matcher); @@ -3547,6 > +3731,38 @@ struct field_modify_info modify_tcp[] = { } > > /** > + * Release an jump to table action resource. > + * > + * @param flow > + * Pointer to mlx5_flow. > + * > + * @return > + * 1 while a reference on it exists, 0 when freed. > + */ > +static int > +flow_dv_jump_tbl_resource_release(struct mlx5_flow *flow) { > + struct mlx5_flow_dv_jump_tbl_resource *cache_resource = > + flow->dv.jump; > + > + assert(cache_resource->action); > + DRV_LOG(DEBUG, "jump table 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); > + flow_dv_tbl_resource_release(cache_resource->tbl); > + rte_free(cache_resource); > + DRV_LOG(DEBUG, "jump table resource %p: removed", > + (void *)cache_resource); > + return 0; > + } > + return 1; > +} > + > +/** > * Release a modify-header resource. > * > * @param flow > @@ -3642,6 +3858,8 @@ struct field_modify_info modify_tcp[] = { > flow_dv_encap_decap_resource_release(dev_flow); > if (dev_flow->dv.modify_hdr) > flow_dv_modify_hdr_resource_release(dev_flow); > + if (dev_flow->dv.jump) > + flow_dv_jump_tbl_resource_release(dev_flow); > rte_free(dev_flow); > } > } > diff --git a/drivers/net/mlx5/mlx5_glue.c b/drivers/net/mlx5/mlx5_glue.c > index f509f85..fca34ca 100644 > --- a/drivers/net/mlx5/mlx5_glue.c > +++ b/drivers/net/mlx5/mlx5_glue.c > @@ -370,6 +370,17 @@ > } > > static void * > +mlx5_glue_dr_create_flow_action_dest_flow_tbl(void *tbl) { #ifdef > +HAVE_MLX5DV_DR > + return mlx5dv_dr_create_action_dest_flow_table(tbl); > +#else > + (void)tbl; > + return NULL; > +#endif > +} > + > +static void * > mlx5_glue_dr_create_flow_tbl(void *ns, uint32_t level) { #ifdef > HAVE_MLX5DV_DR @@ -833,6 +844,8 @@ > .get_async_event = mlx5_glue_get_async_event, > .port_state_str = mlx5_glue_port_state_str, > .cq_ex_to_cq = mlx5_glue_cq_ex_to_cq, > + .dr_create_flow_action_dest_flow_tbl = > + mlx5_glue_dr_create_flow_action_dest_flow_tbl, > .dr_create_flow_tbl = mlx5_glue_dr_create_flow_tbl, > .dr_destroy_flow_tbl = mlx5_glue_dr_destroy_flow_tbl, > .dr_create_ns = mlx5_glue_dr_create_ns, diff --git > a/drivers/net/mlx5/mlx5_glue.h b/drivers/net/mlx5/mlx5_glue.h index > 7115575..16d5dd6 100644 > --- a/drivers/net/mlx5/mlx5_glue.h > +++ b/drivers/net/mlx5/mlx5_glue.h > @@ -145,6 +145,7 @@ struct mlx5_glue { > struct ibv_async_event *event); > const char *(*port_state_str)(enum ibv_port_state port_state); > struct ibv_cq *(*cq_ex_to_cq)(struct ibv_cq_ex *cq); > + void *(*dr_create_flow_action_dest_flow_tbl)(void *tbl); > void *(*dr_create_flow_tbl)(void *ns, uint32_t level); > int (*dr_destroy_flow_tbl)(void *tbl); > void *(*dr_create_ns)(struct ibv_context *ctx, > -- > 1.8.3.1