From 0c76d1c9a18d855c7d7a38db66ed7b21923c814f Mon Sep 17 00:00:00 2001 From: Yongseok Koh Date: Mon, 24 Sep 2018 19:55:14 +0000 Subject: [PATCH] net/mlx5: add abstraction for multiple flow drivers Flow engine has to support multiple driver paths. Verbs/DV for NIC flow steering and Linux TC flower for E-Switch flow steering. In the future, another flow driver could be added (devX). Signed-off-by: Yongseok Koh --- drivers/net/mlx5/mlx5.c | 1 - drivers/net/mlx5/mlx5_flow.c | 348 ++++++++++++++++++++++++++--- drivers/net/mlx5/mlx5_flow.h | 17 +- drivers/net/mlx5/mlx5_flow_dv.c | 26 +-- drivers/net/mlx5/mlx5_flow_verbs.c | 20 +- 5 files changed, 335 insertions(+), 77 deletions(-) diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index e0b3717fe4..c9026534ba 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -1194,7 +1194,6 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, if (err < 0) goto error; priv->config.flow_prio = err; - mlx5_flow_init_driver_ops(eth_dev); /* * Once the device is added to the list of memory event * callback, its global MR cache table cannot be expanded diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 3814eecc92..a8fca11bfc 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -38,6 +38,23 @@ extern const struct eth_dev_ops mlx5_dev_ops; extern const struct eth_dev_ops mlx5_dev_ops_isolate; +/** Device flow drivers. */ +#ifdef HAVE_IBV_FLOW_DV_SUPPORT +extern const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops; +#endif +extern const struct mlx5_flow_driver_ops mlx5_flow_verbs_drv_ops; + +const struct mlx5_flow_driver_ops mlx5_flow_null_drv_ops; + +const struct mlx5_flow_driver_ops *flow_drv_ops[] = { + [MLX5_FLOW_TYPE_MIN] = &mlx5_flow_null_drv_ops, +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + [MLX5_FLOW_TYPE_DV] = &mlx5_flow_dv_drv_ops, +#endif + [MLX5_FLOW_TYPE_VERBS] = &mlx5_flow_verbs_drv_ops, + [MLX5_FLOW_TYPE_MAX] = &mlx5_flow_null_drv_ops +}; + enum mlx5_expansion { MLX5_EXPANSION_ROOT, MLX5_EXPANSION_ROOT_OUTER, @@ -283,9 +300,6 @@ static struct mlx5_flow_tunnel_info tunnels_info[] = { }, }; -/* Holds the nic operations that should be used. */ -struct mlx5_flow_driver_ops nic_ops; - /** * Discover the maximum number of priority available. * @@ -1529,6 +1543,284 @@ mlx5_flow_validate_item_mpls(const struct rte_flow_item *item __rte_unused, " update."); } +static int +flow_null_validate(struct rte_eth_dev *dev __rte_unused, + const struct rte_flow_attr *attr __rte_unused, + const struct rte_flow_item items[] __rte_unused, + const struct rte_flow_action actions[] __rte_unused, + struct rte_flow_error *error __rte_unused) +{ + rte_errno = ENOTSUP; + return -rte_errno; +} + +static struct mlx5_flow * +flow_null_prepare(const struct rte_flow_attr *attr __rte_unused, + const struct rte_flow_item items[] __rte_unused, + const struct rte_flow_action actions[] __rte_unused, + uint64_t *item_flags __rte_unused, + uint64_t *action_flags __rte_unused, + struct rte_flow_error *error __rte_unused) +{ + rte_errno = ENOTSUP; + return NULL; +} + +static int +flow_null_translate(struct rte_eth_dev *dev __rte_unused, + struct mlx5_flow *dev_flow __rte_unused, + const struct rte_flow_attr *attr __rte_unused, + const struct rte_flow_item items[] __rte_unused, + const struct rte_flow_action actions[] __rte_unused, + struct rte_flow_error *error __rte_unused) +{ + rte_errno = ENOTSUP; + return -rte_errno; +} + +static int +flow_null_apply(struct rte_eth_dev *dev __rte_unused, + struct rte_flow *flow __rte_unused, + struct rte_flow_error *error __rte_unused) +{ + rte_errno = ENOTSUP; + return -rte_errno; +} + +static void +flow_null_remove(struct rte_eth_dev *dev __rte_unused, + struct rte_flow *flow __rte_unused) +{ +} + +static void +flow_null_destroy(struct rte_eth_dev *dev __rte_unused, + struct rte_flow *flow __rte_unused) +{ +} + +/* Void driver to protect from null pointer reference. */ +const struct mlx5_flow_driver_ops mlx5_flow_null_drv_ops = { + .validate = flow_null_validate, + .prepare = flow_null_prepare, + .translate = flow_null_translate, + .apply = flow_null_apply, + .remove = flow_null_remove, + .destroy = flow_null_destroy, +}; + +/** + * Select flow driver type according to flow attributes and device + * configuration. + * + * @param[in] dev + * Pointer to the dev structure. + * @param[in] attr + * Pointer to the flow attributes. + * + * @return + * flow driver type if supported, MLX5_FLOW_TYPE_MAX otherwise. + */ +static enum mlx5_flow_drv_type +flow_get_drv_type(struct rte_eth_dev *dev __rte_unused, + const struct rte_flow_attr *attr) +{ + struct priv *priv __rte_unused = dev->data->dev_private; + enum mlx5_flow_drv_type type = MLX5_FLOW_TYPE_MAX; + + if (!attr->transfer) { +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + type = priv->config.dv_flow_en ? MLX5_FLOW_TYPE_DV : + MLX5_FLOW_TYPE_VERBS; +#else + type = MLX5_FLOW_TYPE_VERBS; +#endif + } + return type; +} + +#define flow_get_drv_ops(type) flow_drv_ops[type] + +/** + * Flow driver validation API. This abstracts calling driver specific functions. + * The type of flow driver is determined according to flow attributes. + * + * @param[in] dev + * Pointer to the dev structure. + * @param[in] attr + * Pointer to the flow attributes. + * @param[in] items + * Pointer to the list of items. + * @param[in] actions + * Pointer to the list of actions. + * @param[out] error + * Pointer to the error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_ernno is set. + */ +static inline int +flow_drv_validate(struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, + const struct rte_flow_item items[], + const struct rte_flow_action actions[], + struct rte_flow_error *error) +{ + const struct mlx5_flow_driver_ops *fops; + enum mlx5_flow_drv_type type = flow_get_drv_type(dev, attr); + + fops = flow_get_drv_ops(type); + return fops->validate(dev, attr, items, actions, error); +} + +/** + * Flow driver preparation API. This abstracts calling driver specific + * functions. Parent flow (rte_flow) should have driver type (drv_type). It + * calculates the size of memory required for device flow, allocates the memory, + * initializes the device flow and returns the pointer. + * + * @param[in] attr + * Pointer to the flow attributes. + * @param[in] items + * Pointer to the list of items. + * @param[in] actions + * Pointer to the list of actions. + * @param[out] item_flags + * Pointer to bit mask of all items detected. + * @param[out] action_flags + * Pointer to bit mask of all actions detected. + * @param[out] error + * Pointer to the error structure. + * + * @return + * Pointer to device flow on success, otherwise NULL and rte_ernno is set. + */ +static inline struct mlx5_flow * +flow_drv_prepare(struct rte_flow *flow, + const struct rte_flow_attr *attr, + const struct rte_flow_item items[], + const struct rte_flow_action actions[], + uint64_t *item_flags, + uint64_t *action_flags, + struct rte_flow_error *error) +{ + const struct mlx5_flow_driver_ops *fops; + enum mlx5_flow_drv_type type = flow->drv_type; + + assert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX); + fops = flow_get_drv_ops(type); + return fops->prepare(attr, items, actions, item_flags, action_flags, + error); +} + +/** + * Flow driver translation API. This abstracts calling driver specific + * functions. Parent flow (rte_flow) should have driver type (drv_type). It + * translates a generic flow into a driver flow. flow_drv_prepare() must + * precede. + * + * + * @param[in] dev + * Pointer to the rte dev structure. + * @param[in, out] dev_flow + * Pointer to the mlx5 flow. + * @param[in] attr + * Pointer to the flow attributes. + * @param[in] items + * Pointer to the list of items. + * @param[in] actions + * Pointer to the list of actions. + * @param[out] error + * Pointer to the error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_ernno is set. + */ +static inline int +flow_drv_translate(struct rte_eth_dev *dev, struct mlx5_flow *dev_flow, + const struct rte_flow_attr *attr, + const struct rte_flow_item items[], + const struct rte_flow_action actions[], + struct rte_flow_error *error) +{ + const struct mlx5_flow_driver_ops *fops; + enum mlx5_flow_drv_type type = dev_flow->flow->drv_type; + + assert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX); + fops = flow_get_drv_ops(type); + return fops->translate(dev, dev_flow, attr, items, actions, error); +} + +/** + * Flow driver apply API. This abstracts calling driver specific functions. + * Parent flow (rte_flow) should have driver type (drv_type). It applies + * translated driver flows on to device. flow_drv_translate() must precede. + * + * @param[in] dev + * Pointer to Ethernet device structure. + * @param[in, out] flow + * Pointer to flow structure. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static inline int +flow_drv_apply(struct rte_eth_dev *dev, struct rte_flow *flow, + struct rte_flow_error *error) +{ + const struct mlx5_flow_driver_ops *fops; + enum mlx5_flow_drv_type type = flow->drv_type; + + assert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX); + fops = flow_get_drv_ops(type); + return fops->apply(dev, flow, error); +} + +/** + * Flow driver remove API. This abstracts calling driver specific functions. + * Parent flow (rte_flow) should have driver type (drv_type). It removes a flow + * on device. All the resources of the flow should be freed by calling + * flow_dv_destroy(). + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in, out] flow + * Pointer to flow structure. + */ +static inline void +flow_drv_remove(struct rte_eth_dev *dev, struct rte_flow *flow) +{ + const struct mlx5_flow_driver_ops *fops; + enum mlx5_flow_drv_type type = flow->drv_type; + + assert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX); + fops = flow_get_drv_ops(type); + fops->remove(dev, flow); +} + +/** + * Flow driver destroy API. This abstracts calling driver specific functions. + * Parent flow (rte_flow) should have driver type (drv_type). It removes a flow + * on device and releases resources of the flow. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in, out] flow + * Pointer to flow structure. + */ +static inline void +flow_drv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow) +{ + const struct mlx5_flow_driver_ops *fops; + enum mlx5_flow_drv_type type = flow->drv_type; + + assert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX); + fops = flow_get_drv_ops(type); + fops->destroy(dev, flow); +} + /** * Validate a flow supported by the NIC. * @@ -1544,7 +1836,7 @@ mlx5_flow_validate(struct rte_eth_dev *dev, { int ret; - ret = nic_ops.validate(dev, attr, items, actions, error); + ret = flow_drv_validate(dev, attr, items, actions, error); if (ret < 0) return ret; return 0; @@ -1634,7 +1926,7 @@ mlx5_flow_list_create(struct rte_eth_dev *dev, uint32_t i; uint32_t flow_size; - ret = mlx5_flow_validate(dev, attr, items, actions, error); + ret = flow_drv_validate(dev, attr, items, actions, error); if (ret < 0) return NULL; flow_size = sizeof(struct rte_flow); @@ -1645,6 +1937,9 @@ mlx5_flow_list_create(struct rte_eth_dev *dev, else flow_size += RTE_ALIGN_CEIL(sizeof(uint16_t), sizeof(void *)); flow = rte_calloc(__func__, 1, flow_size, 0); + flow->drv_type = flow_get_drv_type(dev, attr); + assert(flow->drv_type > MLX5_FLOW_TYPE_MIN && + flow->drv_type < MLX5_FLOW_TYPE_MAX); flow->queue = (void *)(flow + 1); LIST_INIT(&flow->dev_flows); if (rss && rss->types) { @@ -1662,21 +1957,21 @@ mlx5_flow_list_create(struct rte_eth_dev *dev, buf->entry[0].pattern = (void *)(uintptr_t)items; } for (i = 0; i < buf->entries; ++i) { - dev_flow = nic_ops.prepare(attr, buf->entry[i].pattern, - actions, &item_flags, - &action_flags, error); + dev_flow = flow_drv_prepare(flow, attr, buf->entry[i].pattern, + actions, &item_flags, &action_flags, + error); if (!dev_flow) goto error; dev_flow->flow = flow; LIST_INSERT_HEAD(&flow->dev_flows, dev_flow, next); - ret = nic_ops.translate(dev, dev_flow, attr, - buf->entry[i].pattern, - actions, error); + ret = flow_drv_translate(dev, dev_flow, attr, + buf->entry[i].pattern, + actions, error); if (ret < 0) goto error; } if (dev->data->dev_started) { - ret = nic_ops.apply(dev, flow, error); + ret = flow_drv_apply(dev, flow, error); if (ret < 0) goto error; } @@ -1686,7 +1981,7 @@ mlx5_flow_list_create(struct rte_eth_dev *dev, error: ret = rte_errno; /* Save rte_errno before cleanup. */ assert(flow); - nic_ops.destroy(dev, flow); + flow_drv_destroy(dev, flow); rte_free(flow); rte_errno = ret; /* Restore rte_errno. */ return NULL; @@ -1724,7 +2019,7 @@ static void mlx5_flow_list_destroy(struct rte_eth_dev *dev, struct mlx5_flows *list, struct rte_flow *flow) { - nic_ops.destroy(dev, flow); + flow_drv_destroy(dev, flow); TAILQ_REMOVE(list, flow, next); /* * Update RX queue flags only if port is started, otherwise it is @@ -1768,7 +2063,7 @@ mlx5_flow_stop(struct rte_eth_dev *dev, struct mlx5_flows *list) struct rte_flow *flow; TAILQ_FOREACH_REVERSE(flow, list, mlx5_flows, next) - nic_ops.remove(dev, flow); + flow_drv_remove(dev, flow); mlx5_flow_rxq_flags_clear(dev); } @@ -1791,7 +2086,7 @@ mlx5_flow_start(struct rte_eth_dev *dev, struct mlx5_flows *list) int ret = 0; TAILQ_FOREACH(flow, list, next) { - ret = nic_ops.apply(dev, flow, &error); + ret = flow_drv_apply(dev, flow, &error); if (ret < 0) goto error; mlx5_flow_rxq_flags_set(dev, flow); @@ -2482,24 +2777,3 @@ mlx5_dev_filter_ctrl(struct rte_eth_dev *dev, } return 0; } - -/** - * Init the driver ops structure. - * - * @param dev - * Pointer to Ethernet device structure. - */ -void -mlx5_flow_init_driver_ops(struct rte_eth_dev *dev) -{ - struct priv *priv __rte_unused = dev->data->dev_private; - -#ifdef HAVE_IBV_FLOW_DV_SUPPORT - if (priv->config.dv_flow_en) - mlx5_flow_dv_get_driver_ops(&nic_ops); - else - mlx5_flow_verbs_get_driver_ops(&nic_ops); -#else - mlx5_flow_verbs_get_driver_ops(&nic_ops); -#endif -} diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index cc1d272562..d2ec6d38a0 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -120,6 +120,13 @@ /* Max number of actions per DV flow. */ #define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8 +enum mlx5_flow_drv_type { + MLX5_FLOW_TYPE_MIN, + MLX5_FLOW_TYPE_DV, + MLX5_FLOW_TYPE_VERBS, + MLX5_FLOW_TYPE_MAX, +}; + /* Matcher PRM representation */ struct mlx5_flow_dv_match_params { size_t size; @@ -205,7 +212,7 @@ struct mlx5_flow_counter { /* Flow structure. */ struct rte_flow { TAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */ - struct rte_flow_attr attributes; /**< User flow attribute. */ + enum mlx5_flow_drv_type drv_type; /**< Drvier type. */ uint32_t layers; /**< Bit-fields of present layers see MLX5_FLOW_LAYER_*. */ struct mlx5_flow_counter *counter; /**< Holds flow counter. */ @@ -309,13 +316,5 @@ int mlx5_flow_validate_item_vxlan_gpe(const struct rte_flow_item *item, uint64_t item_flags, struct rte_eth_dev *dev, struct rte_flow_error *error); -void mlx5_flow_init_driver_ops(struct rte_eth_dev *dev); - -/* mlx5_flow_dv.c */ -void mlx5_flow_dv_get_driver_ops(struct mlx5_flow_driver_ops *flow_ops); - -/* mlx5_flow_verbs.c */ - -void mlx5_flow_verbs_get_driver_ops(struct mlx5_flow_driver_ops *flow_ops); #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 447f376c96..3bb462ceb4 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -1358,23 +1358,13 @@ flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow) } } -/** - * Fills the flow_ops with the function pointers. - * - * @param[out] flow_ops - * Pointer to driver_ops structure. - */ -void -mlx5_flow_dv_get_driver_ops(struct mlx5_flow_driver_ops *flow_ops) -{ - *flow_ops = (struct mlx5_flow_driver_ops) { - .validate = flow_dv_validate, - .prepare = flow_dv_prepare, - .translate = flow_dv_translate, - .apply = flow_dv_apply, - .remove = flow_dv_remove, - .destroy = flow_dv_destroy, - }; -} +const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = { + .validate = flow_dv_validate, + .prepare = flow_dv_prepare, + .translate = flow_dv_translate, + .apply = flow_dv_apply, + .remove = flow_dv_remove, + .destroy = flow_dv_destroy, +}; #endif /* HAVE_IBV_FLOW_DV_SUPPORT */ diff --git a/drivers/net/mlx5/mlx5_flow_verbs.c b/drivers/net/mlx5/mlx5_flow_verbs.c index bf27b45679..6964476741 100644 --- a/drivers/net/mlx5/mlx5_flow_verbs.c +++ b/drivers/net/mlx5/mlx5_flow_verbs.c @@ -1643,15 +1643,11 @@ flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow, return -rte_errno; } -void -mlx5_flow_verbs_get_driver_ops(struct mlx5_flow_driver_ops *flow_ops) -{ - *flow_ops = (struct mlx5_flow_driver_ops) { - .validate = flow_verbs_validate, - .prepare = flow_verbs_prepare, - .translate = flow_verbs_translate, - .apply = flow_verbs_apply, - .remove = flow_verbs_remove, - .destroy = flow_verbs_destroy, - }; -} +const struct mlx5_flow_driver_ops mlx5_flow_verbs_drv_ops = { + .validate = flow_verbs_validate, + .prepare = flow_verbs_prepare, + .translate = flow_verbs_translate, + .apply = flow_verbs_apply, + .remove = flow_verbs_remove, + .destroy = flow_verbs_destroy, +};