From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by dpdk.space (Postfix) with ESMTP id 3581BA00E6 for ; Sun, 14 Apr 2019 23:13:34 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B77795F0D; Sun, 14 Apr 2019 23:13:19 +0200 (CEST) Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by dpdk.org (Postfix) with ESMTP id C87C45B34 for ; Sun, 14 Apr 2019 23:13:08 +0200 (CEST) Received: from Internal Mail-Server by MTLPINE1 (envelope-from orika@mellanox.com) with ESMTPS (AES256-SHA encrypted); 15 Apr 2019 00:13:02 +0300 Received: from pegasus03.mtr.labs.mlnx (pegasus03.mtr.labs.mlnx [10.210.16.124]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id x3ELD10o027116; Mon, 15 Apr 2019 00:13:02 +0300 From: Ori Kam To: yskoh@mellanox.com, shahafs@mellanox.com, matan@mellanox.com, viacheslavo@mellanox.com, motih@mellanox.com Cc: dev@dpdk.org, orika@mellanox.com Date: Sun, 14 Apr 2019 21:12:32 +0000 Message-Id: <1555276357-4892-5-git-send-email-orika@mellanox.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1555276357-4892-1-git-send-email-orika@mellanox.com> References: <1555276357-4892-1-git-send-email-orika@mellanox.com> Subject: [dpdk-dev] [PATCH 4/9] net/mlx5: add validation for Direct Rule E-Switch X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Content-Type: text/plain; charset="UTF-8" Message-ID: <20190414211232.TSUnzTQTrvJS3A_cLQ3U5SlQbIbLyIhdTzl4ieQhc_A@z> Add validation logic for E-Switch using Direct Rules. Signed-off-by: Ori Kam --- drivers/net/mlx5/mlx5.h | 2 + drivers/net/mlx5/mlx5_ethdev.c | 39 +++++++ drivers/net/mlx5/mlx5_flow.h | 5 + drivers/net/mlx5/mlx5_flow_dv.c | 252 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 287 insertions(+), 11 deletions(-) diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 33a4127..8d63575 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -412,6 +412,8 @@ int mlx5_ibv_device_to_pci_addr(const struct ibv_device *device, 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); bool mlx5_translate_port_name(const char *port_name_in, diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c index 3992918..c821772 100644 --- a/drivers/net/mlx5/mlx5_ethdev.c +++ b/drivers/net/mlx5/mlx5_ethdev.c @@ -1376,6 +1376,45 @@ int mlx5_fw_version_get(struct rte_eth_dev *dev, char *fw_ver, size_t fw_size) } /** + * 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 switch. + * + * @return + * 0 on success, Negative error otherwise. + */ +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) + return -EINVAL; + dev = &rte_eth_devices[port]; + if (dev == NULL) + return -ENODEV; + if (!dev->device || + !dev->device->driver || + strcmp(dev->device->driver->name, MLX5_DRIVER_NAME)) + return -EINVAL; + priv = dev->data->dev_private; + if (!(priv->representor || priv->master)) + return -EINVAL; + 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. * * @param ifindex diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 9f47fd4..85954c2 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 7b582f0..fedc6cb 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -613,6 +613,92 @@ struct field_modify_info modify_tcp[] = { } /** + * 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; + uint16_t item_port_esw_port_id; + uint16_t port; + int ret; + + if (!attr->transfer) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + NULL, + "match on port id is valid for" + " eswitch only"); + if (item_flags & MLX5_FLOW_ITEM_PORT_ID) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, item, + "multiple source vport are not" + " supported"); + if (!mask) + mask = &switch_mask; + if (mask->id && 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; + port = mask->id ? spec->id : 0; + ret = mlx5_port_to_eswitch_info(port, &item_port_esw_domain_id, + &item_port_esw_port_id); + if (ret) + return rte_flow_error_set(error, -ret, + RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, + "failed to obtain eswitch 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 eswitch 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 eswitch"); + return 0; +} + +/** * Validate count action. * * @param[in] dev @@ -622,6 +708,7 @@ struct field_modify_info modify_tcp[] = { * * @return * 0 on success, a negative errno value otherwise and rte_errno is set. + * w */ static int flow_dv_validate_action_count(struct rte_eth_dev *dev, @@ -676,7 +763,7 @@ struct field_modify_info modify_tcp[] = { 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, @@ -761,7 +848,8 @@ struct field_modify_info modify_tcp[] = { "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, @@ -1561,6 +1649,77 @@ struct field_modify_info modify_tcp[] = { 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 eswitch 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 eswitch 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" + " eswitch being configured"); + return 0; +} /** * Find existing modify-header resource or create and register a new one. @@ -1759,11 +1918,34 @@ struct field_modify_info modify_tcp[] = { 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_eswitch_en) + return rte_flow_error_set + (error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "eswitch dr is not supported"); + if (!(priv->representor || priv->master)) + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "eswitch 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, @@ -1812,6 +1994,13 @@ struct field_modify_info modify_tcp[] = { 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; + item_flags |= MLX5_FLOW_ITEM_PORT_ID; + break; case RTE_FLOW_ITEM_TYPE_ETH: ret = mlx5_flow_validate_item_eth(items, item_flags, error); @@ -1943,6 +2132,17 @@ struct field_modify_info modify_tcp[] = { 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); @@ -2133,10 +2333,40 @@ struct field_modify_info modify_tcp[] = { "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; } -- 1.8.3.1