From 2e4c987aad91b836bfaf8f23d281c04652d7ddad Mon Sep 17 00:00:00 2001 From: Ori Kam Date: Thu, 18 Apr 2019 13:16:02 +0000 Subject: [PATCH] net/mlx5: validate Direct Rule E-Switch Add validation logic for E-Switch using Direct Rules. Signed-off-by: Ori Kam Acked-by: Yongseok Koh --- drivers/net/mlx5/mlx5.h | 2 + drivers/net/mlx5/mlx5_ethdev.c | 41 ++++++ drivers/net/mlx5/mlx5_flow.h | 5 + drivers/net/mlx5/mlx5_flow_dv.c | 243 ++++++++++++++++++++++++++++++-- 4 files changed, 280 insertions(+), 11 deletions(-) diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 2dd0e68b0e..d771eddfd1 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -423,6 +423,8 @@ eth_rx_burst_t mlx5_select_rx_function(struct rte_eth_dev *dev); unsigned int mlx5_dev_to_port_id(const struct rte_device *dev, uint16_t *port_list, unsigned int port_list_n); +int mlx5_port_to_eswitch_info(uint16_t port, uint16_t *es_domain_id, + uint16_t *es_port_id); int mlx5_sysfs_switch_info(unsigned int ifindex, struct mlx5_switch_info *info); void mlx5_sysfs_check_switch_info(bool device_dir, diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c index 9c24462553..57a64495d9 100644 --- a/drivers/net/mlx5/mlx5_ethdev.c +++ b/drivers/net/mlx5/mlx5_ethdev.c @@ -1375,6 +1375,47 @@ mlx5_dev_to_port_id(const struct rte_device *dev, uint16_t *port_list, return n; } +/** + * Get the E-Switch domain id this port belongs to. + * + * @param[in] port + * Device port id. + * @param[out] es_domain_id + * E-Switch domain id. + * @param[out] es_port_id + * The port id of the port in the E-Switch. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_port_to_eswitch_info(uint16_t port, + uint16_t *es_domain_id, uint16_t *es_port_id) +{ + struct rte_eth_dev *dev; + struct mlx5_priv *priv; + + if (port >= RTE_MAX_ETHPORTS) { + rte_errno = EINVAL; + return -rte_errno; + } + if (!rte_eth_dev_is_valid_port(port)) { + rte_errno = ENODEV; + return -rte_errno; + } + dev = &rte_eth_devices[port]; + priv = dev->data->dev_private; + if (!(priv->representor || priv->master)) { + rte_errno = EINVAL; + return -rte_errno; + } + if (es_domain_id) + *es_domain_id = priv->domain_id; + if (es_port_id) + *es_port_id = priv->vport_id; + return 0; +} + /** * Get switch information associated with network interface. * diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 9f47fd4ee1..85954c2b81 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -48,6 +48,7 @@ /* General pattern items bits. */ #define MLX5_FLOW_ITEM_METADATA (1u << 16) +#define MLX5_FLOW_ITEM_PORT_ID (1u << 17) /* Outer Masks. */ #define MLX5_FLOW_LAYER_OUTER_L3 \ @@ -118,6 +119,10 @@ (MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | \ MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_JUMP) +#define MLX5_FLOW_FATE_ESWITCH_ACTIONS \ + (MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_PORT_ID | \ + MLX5_FLOW_ACTION_JUMP) + #define MLX5_FLOW_ENCAP_ACTIONS (MLX5_FLOW_ACTION_VXLAN_ENCAP | \ MLX5_FLOW_ACTION_NVGRE_ENCAP | \ MLX5_FLOW_ACTION_RAW_ENCAP) diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 0e7d67bc6a..f048920c1d 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -611,6 +611,89 @@ flow_dv_validate_item_meta(struct rte_eth_dev *dev, return 0; } +/** + * Validate vport item. + * + * @param[in] dev + * Pointer to the rte_eth_dev structure. + * @param[in] item + * Item specification. + * @param[in] attr + * Attributes of flow that includes this item. + * @param[in] item_flags + * Bit-fields that holds the items detected until now. + * @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_item_port_id(struct rte_eth_dev *dev, + const struct rte_flow_item *item, + const struct rte_flow_attr *attr, + uint64_t item_flags, + struct rte_flow_error *error) +{ + const struct rte_flow_item_port_id *spec = item->spec; + const struct rte_flow_item_port_id *mask = item->mask; + const struct rte_flow_item_port_id switch_mask = { + .id = 0xffffffff, + }; + uint16_t esw_domain_id; + uint16_t item_port_esw_domain_id; + int ret; + + if (!attr->transfer) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + NULL, + "match on port id is valid only" + " when transfer flag is enabled"); + if (item_flags & MLX5_FLOW_ITEM_PORT_ID) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, item, + "multiple source ports are not" + " supported"); + if (!mask) + mask = &switch_mask; + if (mask->id != 0xffffffff) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM_MASK, + mask, + "no support for partial mask on" + " \"id\" field"); + ret = mlx5_flow_item_acceptable + (item, (const uint8_t *)mask, + (const uint8_t *)&rte_flow_item_port_id_mask, + sizeof(struct rte_flow_item_port_id), + error); + if (ret) + return ret; + if (!spec) + return 0; + ret = mlx5_port_to_eswitch_info(spec->id, &item_port_esw_domain_id, + NULL); + if (ret) + return rte_flow_error_set(error, -ret, + RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, + "failed to obtain E-Switch info for" + " port"); + ret = mlx5_port_to_eswitch_info(dev->data->port_id, + &esw_domain_id, NULL); + if (ret < 0) + return rte_flow_error_set(error, -ret, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "failed to obtain E-Switch info"); + if (item_port_esw_domain_id != esw_domain_id) + return rte_flow_error_set(error, -ret, + RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, + "cannot match on a port from a" + " different E-Switch"); + return 0; +} + /** * Validate count action. * @@ -675,7 +758,7 @@ flow_dv_validate_action_l2_encap(uint64_t action_flags, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "can only have a single encap or" " decap action in a flow"); - if (attr->ingress) + if (!attr->transfer && attr->ingress) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, NULL, @@ -760,7 +843,8 @@ flow_dv_validate_action_raw_encap(uint64_t action_flags, "can only have a single encap" " action in a flow"); /* encap without preceding decap is not supported for ingress */ - if (attr->ingress && !(action_flags & MLX5_FLOW_ACTION_RAW_DECAP)) + if (!attr->transfer && attr->ingress && + !(action_flags & MLX5_FLOW_ACTION_RAW_DECAP)) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, NULL, @@ -1560,6 +1644,77 @@ flow_dv_validate_action_jump(const struct rte_flow_action *action, return 0; } +/* + * Validate the port_id action. + * + * @param[in] dev + * Pointer to rte_eth_dev structure. + * @param[in] action_flags + * Bit-fields that holds the actions detected until now. + * @param[in] action + * Port_id RTE action structure. + * @param[in] attr + * Attributes of flow that includes this action. + * @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_port_id(struct rte_eth_dev *dev, + 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_port_id *port_id; + uint16_t port; + uint16_t esw_domain_id; + uint16_t act_port_domain_id; + int ret; + + if (!attr->transfer) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "port id action is valid in transfer" + " mode only"); + if (!action || !action->conf) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, + NULL, + "port id action parameters must be" + " specified"); + if (action_flags & (MLX5_FLOW_FATE_ACTIONS | + MLX5_FLOW_FATE_ESWITCH_ACTIONS)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "can have only one fate actions in" + " a flow"); + ret = mlx5_port_to_eswitch_info(dev->data->port_id, + &esw_domain_id, NULL); + if (ret < 0) + return rte_flow_error_set(error, -ret, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "failed to obtain E-Switch info"); + port_id = action->conf; + port = port_id->original ? dev->data->port_id : port_id->id; + ret = mlx5_port_to_eswitch_info(port, &act_port_domain_id, NULL); + if (ret) + return rte_flow_error_set + (error, -ret, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, port_id, + "failed to obtain E-Switch port id for port"); + if (act_port_domain_id != esw_domain_id) + return rte_flow_error_set + (error, -ret, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "port does not belong to" + " E-Switch being configured"); + return 0; +} /** * Find existing modify-header resource or create and register a new one. @@ -1758,11 +1913,29 @@ flow_dv_validate_attributes(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, NULL, "priority out of range"); - if (attributes->transfer) - return rte_flow_error_set(error, ENOTSUP, - RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, - NULL, - "transfer is not supported"); + if (attributes->transfer) { + if (!priv->config.dv_esw_en) + return rte_flow_error_set + (error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "E-Switch dr is not supported"); + if (!(priv->representor || priv->master)) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "E-Switch configurationd can only be" + " done by a master or a representor device"); + if (attributes->egress) + return rte_flow_error_set + (error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes, + "egress is not supported"); + if (attributes->group >= MLX5_MAX_TABLES_FDB) + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, + NULL, "group must be smaller than " + RTE_STR(MLX5_MAX_FDB_TABLES)); + } if (!(attributes->egress ^ attributes->ingress)) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR, NULL, @@ -1811,6 +1984,13 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, switch (items->type) { case RTE_FLOW_ITEM_TYPE_VOID: break; + case RTE_FLOW_ITEM_TYPE_PORT_ID: + ret = flow_dv_validate_item_port_id + (dev, items, attr, item_flags, error); + if (ret < 0) + return ret; + last_item |= MLX5_FLOW_ITEM_PORT_ID; + break; case RTE_FLOW_ITEM_TYPE_ETH: ret = mlx5_flow_validate_item_eth(items, item_flags, error); @@ -1942,6 +2122,17 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, switch (actions->type) { case RTE_FLOW_ACTION_TYPE_VOID: break; + case RTE_FLOW_ACTION_TYPE_PORT_ID: + ret = flow_dv_validate_action_port_id(dev, + action_flags, + actions, + attr, + error); + if (ret) + return ret; + action_flags |= MLX5_FLOW_ACTION_PORT_ID; + ++actions_n; + break; case RTE_FLOW_ACTION_TYPE_FLAG: ret = mlx5_flow_validate_action_flag(action_flags, attr, error); @@ -2132,10 +2323,40 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, "action not supported"); } } - if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress) - return rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ACTION, actions, - "no fate action is found"); + /* Eswitch has few restrictions on using items and actions */ + if (attr->transfer) { + if (action_flags & MLX5_FLOW_ACTION_FLAG) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "unsupported action FLAG"); + if (action_flags & MLX5_FLOW_ACTION_MARK) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "unsupported action MARK"); + if (action_flags & MLX5_FLOW_ACTION_QUEUE) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "unsupported action QUEUE"); + if (action_flags & MLX5_FLOW_ACTION_RSS) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "unsupported action RSS"); + if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + actions, + "no fate action is found"); + } else { + if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + actions, + "no fate action is found"); + } return 0; } -- 2.20.1