From patchwork Mon Oct 26 16:37:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 82204 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id A78BEA04DD; Mon, 26 Oct 2020 17:38:16 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 979802BAA; Mon, 26 Oct 2020 17:38:05 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 74798100C for ; Mon, 26 Oct 2020 17:37:58 +0100 (CET) From: Bing Zhao To: viacheslavo@mellanox.com, matan@mellanox.com Cc: dev@dpdk.org, orika@nvidia.com, rasland@nvidia.com Date: Tue, 27 Oct 2020 00:37:41 +0800 Message-Id: <1603730267-267228-2-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1603730267-267228-1-git-send-email-bingz@nvidia.com> References: <1602166620-46303-1-git-send-email-bingz@nvidia.com> <1603730267-267228-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v3 1/7] net/mlx5: change hairpin queue peer checking 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" In the current implementation of single port mode hairpin, the peer queue should belong to the same port of the current queue. When the two ports hairpin mode is introduced, such checking should be removed to make the hairpin queue setup execute successfully since it is not an invalid condition, if the Tx port and Rx port are not the same. In the meanwhile, different devices could have different queue configurations. The queues number of peer port is unknown to the current device. The checking should be removed also. If the Tx and Rx port IDs of a hairpin peer are different, only the manual binding and explicit Tx flows are supported. Or else, the four combinations of modes could be supported. The mode attributes consistency checking will be done when connecting the queue with its peer queue. Signed-off-by: Bing Zhao Acked-by: Viacheslav Ovsiienko --- v3: fix attributes checking --- drivers/net/mlx5/mlx5_rxq.c | 32 ++++++++++++++++++++++++++------ drivers/net/mlx5/mlx5_txq.c | 32 ++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c index 1cc477a..034f43e 100644 --- a/drivers/net/mlx5/mlx5_rxq.c +++ b/drivers/net/mlx5/mlx5_rxq.c @@ -818,15 +818,35 @@ res = mlx5_rx_queue_pre_setup(dev, idx, &desc); if (res) return res; - if (hairpin_conf->peer_count != 1 || - hairpin_conf->peers[0].port != dev->data->port_id || - hairpin_conf->peers[0].queue >= priv->txqs_n) { - DRV_LOG(ERR, "port %u unable to setup hairpin queue index %u " - " invalid hairpind configuration", dev->data->port_id, - idx); + if (hairpin_conf->peer_count != 1) { rte_errno = EINVAL; + DRV_LOG(ERR, "port %u unable to setup Rx hairpin queue index %u" + " peer count is %u", dev->data->port_id, + idx, hairpin_conf->peer_count); return -rte_errno; } + if (hairpin_conf->peers[0].port == dev->data->port_id) { + if (hairpin_conf->peers[0].queue >= priv->txqs_n) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u unable to setup Rx hairpin queue" + " index %u, Tx %u is larger than %u", + dev->data->port_id, idx, + hairpin_conf->peers[0].queue, priv->txqs_n); + return -rte_errno; + } + } else { + if (hairpin_conf->manual_bind == 0 || + hairpin_conf->tx_explicit == 0) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u unable to setup Rx hairpin queue" + " index %u peer port %u with attributes %u %u", + dev->data->port_id, idx, + hairpin_conf->peers[0].port, + hairpin_conf->manual_bind, + hairpin_conf->tx_explicit); + return -rte_errno; + } + } rxq_ctrl = mlx5_rxq_hairpin_new(dev, idx, desc, hairpin_conf); if (!rxq_ctrl) { DRV_LOG(ERR, "port %u unable to allocate queue index %u", diff --git a/drivers/net/mlx5/mlx5_txq.c b/drivers/net/mlx5/mlx5_txq.c index 9c2dd2a..dca9c05 100644 --- a/drivers/net/mlx5/mlx5_txq.c +++ b/drivers/net/mlx5/mlx5_txq.c @@ -421,15 +421,35 @@ res = mlx5_tx_queue_pre_setup(dev, idx, &desc); if (res) return res; - if (hairpin_conf->peer_count != 1 || - hairpin_conf->peers[0].port != dev->data->port_id || - hairpin_conf->peers[0].queue >= priv->rxqs_n) { - DRV_LOG(ERR, "port %u unable to setup hairpin queue index %u " - " invalid hairpind configuration", dev->data->port_id, - idx); + if (hairpin_conf->peer_count != 1) { rte_errno = EINVAL; + DRV_LOG(ERR, "port %u unable to setup Tx hairpin queue index %u" + " peer count is %u", dev->data->port_id, + idx, hairpin_conf->peer_count); return -rte_errno; } + if (hairpin_conf->peers[0].port == dev->data->port_id) { + if (hairpin_conf->peers[0].queue >= priv->rxqs_n) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u unable to setup Tx hairpin queue" + " index %u, Rx %u is larger than %u", + dev->data->port_id, idx, + hairpin_conf->peers[0].queue, priv->txqs_n); + return -rte_errno; + } + } else { + if (hairpin_conf->manual_bind == 0 || + hairpin_conf->tx_explicit == 0) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u unable to setup Tx hairpin queue" + " index %u peer port %u with attributes %u %u", + dev->data->port_id, idx, + hairpin_conf->peers[0].port, + hairpin_conf->manual_bind, + hairpin_conf->tx_explicit); + return -rte_errno; + } + } txq_ctrl = mlx5_txq_hairpin_new(dev, idx, desc, hairpin_conf); if (!txq_ctrl) { DRV_LOG(ERR, "port %u unable to allocate queue index %u", From patchwork Mon Oct 26 16:37:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 82205 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id E4675A04DD; Mon, 26 Oct 2020 17:38:35 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id E970A2BA3; Mon, 26 Oct 2020 17:38:18 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 393AF1D9E for ; Mon, 26 Oct 2020 17:38:16 +0100 (CET) From: Bing Zhao To: viacheslavo@mellanox.com, matan@mellanox.com Cc: dev@dpdk.org, orika@nvidia.com, rasland@nvidia.com Date: Tue, 27 Oct 2020 00:37:42 +0800 Message-Id: <1603730267-267228-3-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1603730267-267228-1-git-send-email-bingz@nvidia.com> References: <1602166620-46303-1-git-send-email-bingz@nvidia.com> <1603730267-267228-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v3 2/7] net/mlx5: add support for two ports hairpin mode 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" In order to support hairpin between two ports, mlx5 PMD needs to implement the functions and provide them as the function pointers. The bind and unbind functions are executed per port pairs. All the hairpin queues between the two ports should have the same attributes during queues setup. Different configurations among queue pairs from the same ports are not supported. It is allowed that two ports only have one direction hairpin. In order to set up the connection between two queues, peer Rx queue HW information must be fetched via the internal RTE API and the queue information could be used to modify the SQ object. Then the RQ object will be modified with the Tx queue HW information. The reverse operation is not supported right now. When disconnecting the queues pair, SQ and RQ object should be reset without any peer HW information. The unbinding operation will try to disconnect all Tx queues from the port from the Rx queues of the peer port. Tx explicit mode attribute will be saved and used when creating a hairpin flow. Signed-off-by: Bing Zhao Acked-by: Viacheslav Ovsiienko --- v3: * fix code review comments and bugs for unbinding * code style update * Checking for mlx5 driver type --- drivers/net/mlx5/linux/mlx5_os.c | 10 + drivers/net/mlx5/mlx5.h | 19 ++ drivers/net/mlx5/mlx5_rxtx.h | 2 + drivers/net/mlx5/mlx5_trigger.c | 629 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 658 insertions(+), 2 deletions(-) diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index ed3f020..b791859 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -2570,6 +2570,11 @@ .get_module_eeprom = mlx5_get_module_eeprom, .hairpin_cap_get = mlx5_hairpin_cap_get, .mtr_ops_get = mlx5_flow_meter_ops_get, + .hairpin_bind = mlx5_hairpin_bind, + .hairpin_unbind = mlx5_hairpin_unbind, + .hairpin_queue_peer_update = mlx5_hairpin_queue_peer_update, + .hairpin_queue_peer_bind = mlx5_hairpin_queue_peer_bind, + .hairpin_queue_peer_unbind = mlx5_hairpin_queue_peer_unbind, }; /* Available operations from secondary process. */ @@ -2648,4 +2653,9 @@ .get_module_eeprom = mlx5_get_module_eeprom, .hairpin_cap_get = mlx5_hairpin_cap_get, .mtr_ops_get = mlx5_flow_meter_ops_get, + .hairpin_bind = mlx5_hairpin_bind, + .hairpin_unbind = mlx5_hairpin_unbind, + .hairpin_queue_peer_update = mlx5_hairpin_queue_peer_update, + .hairpin_queue_peer_bind = mlx5_hairpin_queue_peer_bind, + .hairpin_queue_peer_unbind = mlx5_hairpin_queue_peer_unbind, }; diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 258be03..010152c 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -904,6 +904,14 @@ struct mlx5_priv { #define PORT_ID(priv) ((priv)->dev_data->port_id) #define ETH_DEV(priv) (&rte_eth_devices[PORT_ID(priv)]) +struct rte_hairpin_peer_info { + uint32_t qp_id; + uint32_t vhca_id; + uint16_t peer_q; + uint16_t tx_explicit; + uint16_t manual_bind; +}; + /* mlx5.c */ int mlx5_getenv_int(const char *); @@ -1054,6 +1062,17 @@ void mlx5_vlan_vmwa_acquire(struct rte_eth_dev *dev, int mlx5_traffic_enable(struct rte_eth_dev *dev); void mlx5_traffic_disable(struct rte_eth_dev *dev); int mlx5_traffic_restart(struct rte_eth_dev *dev); +int mlx5_hairpin_queue_peer_update(struct rte_eth_dev *dev, uint16_t peer_queue, + struct rte_hairpin_peer_info *current_info, + struct rte_hairpin_peer_info *peer_info, + uint32_t direction); +int mlx5_hairpin_queue_peer_bind(struct rte_eth_dev *dev, uint16_t cur_queue, + struct rte_hairpin_peer_info *peer_info, + uint32_t direction); +int mlx5_hairpin_queue_peer_unbind(struct rte_eth_dev *dev, uint16_t cur_queue, + uint32_t direction); +int mlx5_hairpin_bind(struct rte_eth_dev *dev, uint16_t rx_port); +int mlx5_hairpin_unbind(struct rte_eth_dev *dev, uint16_t rx_port); /* mlx5_flow.c */ diff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h index f204f7e..cdc18e3 100644 --- a/drivers/net/mlx5/mlx5_rxtx.h +++ b/drivers/net/mlx5/mlx5_rxtx.h @@ -199,6 +199,7 @@ struct mlx5_rxq_ctrl { void *wq_umem; /* WQ buffer registration info. */ void *cq_umem; /* CQ buffer registration info. */ struct rte_eth_hairpin_conf hairpin_conf; /* Hairpin configuration. */ + uint32_t hairpin_status; /* Hairpin binding status. */ }; /* TX queue send local data. */ @@ -295,6 +296,7 @@ struct mlx5_txq_ctrl { void *bf_reg; /* BlueFlame register from Verbs. */ uint16_t dump_file_n; /* Number of dump files. */ struct rte_eth_hairpin_conf hairpin_conf; /* Hairpin configuration. */ + uint32_t hairpin_status; /* Hairpin binding status. */ struct mlx5_txq_data txq; /* Data path structure. */ /* Must be the last field in the structure, contains elts[]. */ }; diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c index 19f2d66..f76122b 100644 --- a/drivers/net/mlx5/mlx5_trigger.c +++ b/drivers/net/mlx5/mlx5_trigger.c @@ -207,7 +207,7 @@ * 0 on success, a negative errno value otherwise and rte_errno is set. */ static int -mlx5_hairpin_bind(struct rte_eth_dev *dev) +mlx5_hairpin_auto_bind(struct rte_eth_dev *dev) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_devx_modify_sq_attr sq_attr = { 0 }; @@ -285,6 +285,631 @@ return -rte_errno; } +/* + * Fetch the peer queue's SW & HW information. + * + * @param dev + * Pointer to Ethernet device structure. + * @param peer_queue + * Index of the queue to fetch the information. + * @param current_info + * Pointer to the input peer information, not used currently. + * @param peer_info + * Pointer to the structure to store the information, output. + * @param direction + * Positive to get the RxQ information, zero to get the TxQ information. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_hairpin_queue_peer_update(struct rte_eth_dev *dev, uint16_t peer_queue, + struct rte_hairpin_peer_info *current_info, + struct rte_hairpin_peer_info *peer_info, + uint32_t direction) +{ + struct mlx5_priv *priv = dev->data->dev_private; + RTE_SET_USED(current_info); + + if (dev->data->dev_started == 0) { + rte_errno = EBUSY; + DRV_LOG(ERR, "peer port %u is not started", + dev->data->port_id); + return -rte_errno; + } + /* + * Peer port used as egress. In the current design, hairpin Tx queue + * will be bound to the peer Rx queue. Indeed, only the information of + * peer Rx queue needs to be fetched. + */ + if (direction == 0) { + struct mlx5_txq_ctrl *txq_ctrl; + + txq_ctrl = mlx5_txq_get(dev, peer_queue); + if (txq_ctrl == NULL) { + rte_errno = EINVAL; + DRV_LOG(ERR, "Failed to get port %u Tx queue %d", + dev->data->port_id, peer_queue); + return -rte_errno; + } + if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u queue %d is not a hairpin Txq", + dev->data->port_id, peer_queue); + mlx5_txq_release(dev, peer_queue); + return -rte_errno; + } + if (txq_ctrl->obj == NULL || txq_ctrl->obj->sq == NULL) { + rte_errno = ENOMEM; + DRV_LOG(ERR, "port %u no Txq object found: %d", + dev->data->port_id, peer_queue); + mlx5_txq_release(dev, peer_queue); + return -rte_errno; + } + peer_info->qp_id = txq_ctrl->obj->sq->id; + peer_info->vhca_id = priv->config.hca_attr.vhca_id; + /* 1-to-1 mapping, only the first one is used. */ + peer_info->peer_q = txq_ctrl->hairpin_conf.peers[0].queue; + peer_info->tx_explicit = txq_ctrl->hairpin_conf.tx_explicit; + peer_info->manual_bind = txq_ctrl->hairpin_conf.manual_bind; + mlx5_txq_release(dev, peer_queue); + } else { /* Peer port used as ingress. */ + struct mlx5_rxq_ctrl *rxq_ctrl; + + rxq_ctrl = mlx5_rxq_get(dev, peer_queue); + if (rxq_ctrl == NULL) { + rte_errno = EINVAL; + DRV_LOG(ERR, "Failed to get port %u Rx queue %d", + dev->data->port_id, peer_queue); + return -rte_errno; + } + if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u queue %d is not a hairpin Rxq", + dev->data->port_id, peer_queue); + mlx5_rxq_release(dev, peer_queue); + return -rte_errno; + } + if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) { + rte_errno = ENOMEM; + DRV_LOG(ERR, "port %u no Rxq object found: %d", + dev->data->port_id, peer_queue); + mlx5_rxq_release(dev, peer_queue); + return -rte_errno; + } + peer_info->qp_id = rxq_ctrl->obj->rq->id; + peer_info->vhca_id = priv->config.hca_attr.vhca_id; + peer_info->peer_q = rxq_ctrl->hairpin_conf.peers[0].queue; + peer_info->tx_explicit = rxq_ctrl->hairpin_conf.tx_explicit; + peer_info->manual_bind = rxq_ctrl->hairpin_conf.manual_bind; + mlx5_rxq_release(dev, peer_queue); + } + return 0; +} + +/* + * Bind the hairpin queue with the peer HW information. + * This needs to be called twice both for Tx and Rx queues of a pair. + * If the queue is already bound, it is considered successful. + * + * @param dev + * Pointer to Ethernet device structure. + * @param cur_queue + * Index of the queue to change the HW configuration to bind. + * @param peer_info + * Pointer to information of the peer queue. + * @param direction + * Positive to configure the TxQ, zero to configure the RxQ. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_hairpin_queue_peer_bind(struct rte_eth_dev *dev, uint16_t cur_queue, + struct rte_hairpin_peer_info *peer_info, + uint32_t direction) +{ + int ret = 0; + + /* + * Consistency checking of the peer queue: opposite direction is used + * to get the peer queue info with ethdev port ID, no need to check. + */ + if (peer_info->peer_q != cur_queue) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u queue %d and peer queue %d mismatch", + dev->data->port_id, cur_queue, peer_info->peer_q); + return -rte_errno; + } + if (direction != 0) { + struct mlx5_txq_ctrl *txq_ctrl; + struct mlx5_devx_modify_sq_attr sq_attr = { 0 }; + + txq_ctrl = mlx5_txq_get(dev, cur_queue); + if (txq_ctrl == NULL) { + rte_errno = EINVAL; + DRV_LOG(ERR, "Failed to get port %u Tx queue %d", + dev->data->port_id, cur_queue); + return -rte_errno; + } + if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u queue %d not a hairpin Txq", + dev->data->port_id, cur_queue); + mlx5_txq_release(dev, cur_queue); + return -rte_errno; + } + if (txq_ctrl->obj == NULL || txq_ctrl->obj->sq == NULL) { + rte_errno = ENOMEM; + DRV_LOG(ERR, "port %u no Txq object found: %d", + dev->data->port_id, cur_queue); + mlx5_txq_release(dev, cur_queue); + return -rte_errno; + } + if (txq_ctrl->hairpin_status != 0) { + DRV_LOG(DEBUG, "port %u Tx queue %d is already bound", + dev->data->port_id, cur_queue); + mlx5_txq_release(dev, cur_queue); + return 0; + } + /* + * All queues' of one port consistency checking is done in the + * bind() function, and that is optional. + */ + if (peer_info->tx_explicit != + txq_ctrl->hairpin_conf.tx_explicit) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u Tx queue %d and peer Tx rule mode" + " mismatch", dev->data->port_id, cur_queue); + mlx5_txq_release(dev, cur_queue); + return -rte_errno; + } + if (peer_info->manual_bind != + txq_ctrl->hairpin_conf.manual_bind) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u Tx queue %d and peer binding mode" + " mismatch", dev->data->port_id, cur_queue); + mlx5_txq_release(dev, cur_queue); + return -rte_errno; + } + sq_attr.state = MLX5_SQC_STATE_RDY; + sq_attr.sq_state = MLX5_SQC_STATE_RST; + sq_attr.hairpin_peer_rq = peer_info->qp_id; + sq_attr.hairpin_peer_vhca = peer_info->vhca_id; + ret = mlx5_devx_cmd_modify_sq(txq_ctrl->obj->sq, &sq_attr); + if (ret == 0) + txq_ctrl->hairpin_status = 1; + mlx5_txq_release(dev, cur_queue); + } else { + struct mlx5_rxq_ctrl *rxq_ctrl; + struct mlx5_devx_modify_rq_attr rq_attr = { 0 }; + + rxq_ctrl = mlx5_rxq_get(dev, cur_queue); + if (rxq_ctrl == NULL) { + rte_errno = EINVAL; + DRV_LOG(ERR, "Failed to get port %u Rx queue %d", + dev->data->port_id, cur_queue); + return -rte_errno; + } + if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u queue %d not a hairpin Rxq", + dev->data->port_id, cur_queue); + mlx5_rxq_release(dev, cur_queue); + return -rte_errno; + } + if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) { + rte_errno = ENOMEM; + DRV_LOG(ERR, "port %u no Rxq object found: %d", + dev->data->port_id, cur_queue); + mlx5_rxq_release(dev, cur_queue); + return -rte_errno; + } + if (rxq_ctrl->hairpin_status != 0) { + DRV_LOG(DEBUG, "port %u Rx queue %d is already bound", + dev->data->port_id, cur_queue); + mlx5_rxq_release(dev, cur_queue); + return 0; + } + if (peer_info->tx_explicit != + rxq_ctrl->hairpin_conf.tx_explicit) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u Rx queue %d and peer Tx rule mode" + " mismatch", dev->data->port_id, cur_queue); + mlx5_rxq_release(dev, cur_queue); + return -rte_errno; + } + if (peer_info->manual_bind != + rxq_ctrl->hairpin_conf.manual_bind) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u Rx queue %d and peer binding mode" + " mismatch", dev->data->port_id, cur_queue); + mlx5_rxq_release(dev, cur_queue); + return -rte_errno; + } + rq_attr.state = MLX5_SQC_STATE_RDY; + rq_attr.rq_state = MLX5_SQC_STATE_RST; + rq_attr.hairpin_peer_sq = peer_info->qp_id; + rq_attr.hairpin_peer_vhca = peer_info->vhca_id; + ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq, &rq_attr); + if (ret == 0) + rxq_ctrl->hairpin_status = 1; + mlx5_rxq_release(dev, cur_queue); + } + return ret; +} + +/* + * Unbind the hairpin queue and reset its HW configuration. + * This needs to be called twice both for Tx and Rx queues of a pair. + * If the queue is already unbound, it is considered successful. + * + * @param dev + * Pointer to Ethernet device structure. + * @param cur_queue + * Index of the queue to change the HW configuration to unbind. + * @param direction + * Positive to reset the TxQ, zero to reset the RxQ. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_hairpin_queue_peer_unbind(struct rte_eth_dev *dev, uint16_t cur_queue, + uint32_t direction) +{ + int ret = 0; + + if (direction != 0) { + struct mlx5_txq_ctrl *txq_ctrl; + struct mlx5_devx_modify_sq_attr sq_attr = { 0 }; + + txq_ctrl = mlx5_txq_get(dev, cur_queue); + if (txq_ctrl == NULL) { + rte_errno = EINVAL; + DRV_LOG(ERR, "Failed to get port %u Tx queue %d", + dev->data->port_id, cur_queue); + return -rte_errno; + } + if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u queue %d not a hairpin Txq", + dev->data->port_id, cur_queue); + mlx5_txq_release(dev, cur_queue); + return -rte_errno; + } + /* Already unbound, return success before obj checking. */ + if (txq_ctrl->hairpin_status == 0) { + DRV_LOG(DEBUG, "port %u Tx queue %d is already unbound", + dev->data->port_id, cur_queue); + mlx5_txq_release(dev, cur_queue); + return 0; + } + if (!txq_ctrl->obj || !txq_ctrl->obj->sq) { + rte_errno = ENOMEM; + DRV_LOG(ERR, "port %u no Txq object found: %d", + dev->data->port_id, cur_queue); + mlx5_txq_release(dev, cur_queue); + return -rte_errno; + } + sq_attr.state = MLX5_SQC_STATE_RST; + sq_attr.sq_state = MLX5_SQC_STATE_RST; + ret = mlx5_devx_cmd_modify_sq(txq_ctrl->obj->sq, &sq_attr); + if (ret == 0) + txq_ctrl->hairpin_status = 0; + mlx5_txq_release(dev, cur_queue); + } else { + struct mlx5_rxq_ctrl *rxq_ctrl; + struct mlx5_devx_modify_rq_attr rq_attr = { 0 }; + + rxq_ctrl = mlx5_rxq_get(dev, cur_queue); + if (rxq_ctrl == NULL) { + rte_errno = EINVAL; + DRV_LOG(ERR, "Failed to get port %u Rx queue %d", + dev->data->port_id, cur_queue); + return -rte_errno; + } + if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u queue %d not a hairpin Rxq", + dev->data->port_id, cur_queue); + mlx5_rxq_release(dev, cur_queue); + return -rte_errno; + } + if (rxq_ctrl->hairpin_status == 0) { + DRV_LOG(DEBUG, "port %u Rx queue %d is already unbound", + dev->data->port_id, cur_queue); + mlx5_rxq_release(dev, cur_queue); + return 0; + } + if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) { + rte_errno = ENOMEM; + DRV_LOG(ERR, "port %u no Rxq object found: %d", + dev->data->port_id, cur_queue); + mlx5_rxq_release(dev, cur_queue); + return -rte_errno; + } + rq_attr.state = MLX5_SQC_STATE_RST; + rq_attr.rq_state = MLX5_SQC_STATE_RST; + ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq, &rq_attr); + if (ret == 0) + rxq_ctrl->hairpin_status = 0; + mlx5_rxq_release(dev, cur_queue); + } + return ret; +} + +/* + * Bind the hairpin port pairs, from the Tx to the peer Rx. + * This function only supports to bind the Tx to one Rx. + * + * @param dev + * Pointer to Ethernet device structure. + * @param rx_port + * Port identifier of the Rx port. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_hairpin_bind_single_port(struct rte_eth_dev *dev, uint16_t rx_port) +{ + struct mlx5_priv *priv = dev->data->dev_private; + int ret = 0; + struct mlx5_txq_ctrl *txq_ctrl; + uint32_t i; + struct rte_hairpin_peer_info peer = {0xffffff}; + struct rte_hairpin_peer_info cur; + const struct rte_eth_hairpin_conf *conf; + uint16_t num_q = 0; + uint16_t local_port = priv->dev_data->port_id; + uint32_t manual; + uint32_t explicit; + uint16_t rx_queue; + + if (mlx5_eth_find_next(rx_port, priv->pci_dev) != rx_port) { + rte_errno = ENODEV; + DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port); + return -rte_errno; + } + /* + * Before binding TxQ to peer RxQ, first round loop will be used for + * checking the queues' configuration consistency. This would be a + * little time consuming but better than doing the rollback. + */ + for (i = 0; i != priv->txqs_n; i++) { + txq_ctrl = mlx5_txq_get(dev, i); + if (txq_ctrl == NULL) + continue; + if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { + mlx5_txq_release(dev, i); + continue; + } + /* + * All hairpin Tx queues of a single port that connected to the + * same peer Rx port should have the same "auto binding" and + * "implicit Tx flow" modes. + * Peer consistency checking will be done in per queue binding. + */ + conf = &txq_ctrl->hairpin_conf; + if (conf->peers[0].port == rx_port) { + if (num_q == 0) { + manual = conf->manual_bind; + explicit = conf->tx_explicit; + } else { + if (manual != conf->manual_bind || + explicit != conf->tx_explicit) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u queue %d mode" + " mismatch: %u %u, %u %u", + local_port, i, manual, + conf->manual_bind, explicit, + conf->tx_explicit); + mlx5_txq_release(dev, i); + return -rte_errno; + } + } + num_q++; + } + mlx5_txq_release(dev, i); + } + /* Once no queue is configured, success is returned directly. */ + if (num_q == 0) + return ret; + /* All the hairpin TX queues need to be traversed again. */ + for (i = 0; i != priv->txqs_n; i++) { + txq_ctrl = mlx5_txq_get(dev, i); + if (txq_ctrl == NULL) + continue; + if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { + mlx5_txq_release(dev, i); + continue; + } + if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) { + mlx5_txq_release(dev, i); + continue; + } + rx_queue = txq_ctrl->hairpin_conf.peers[0].queue; + /* + * Fetch peer RxQ's information. + * No need to pass the information of the current queue. + */ + ret = rte_eth_hairpin_queue_peer_update(rx_port, rx_queue, + NULL, &peer, 1); + if (ret != 0) { + mlx5_txq_release(dev, i); + goto error; + } + /* Accessing its own device, inside mlx5 PMD. */ + ret = mlx5_hairpin_queue_peer_bind(dev, i, &peer, 1); + if (ret != 0) { + mlx5_txq_release(dev, i); + goto error; + } + /* Pass TxQ's information to peer RxQ and try binding. */ + cur.peer_q = rx_queue; + cur.qp_id = txq_ctrl->obj->sq->id; + cur.vhca_id = priv->config.hca_attr.vhca_id; + cur.tx_explicit = txq_ctrl->hairpin_conf.tx_explicit; + cur.manual_bind = txq_ctrl->hairpin_conf.manual_bind; + /* + * In order to access another device in a proper way, RTE level + * private function is needed. + */ + ret = rte_eth_hairpin_queue_peer_bind(rx_port, rx_queue, + &cur, 0); + if (ret != 0) { + mlx5_txq_release(dev, i); + goto error; + } + mlx5_txq_release(dev, i); + } + return 0; +error: + /* + * Do roll-back process for the queues already bound. + * No need to check the return value of the queue unbind function. + */ + do { + /* No validation is needed here. */ + txq_ctrl = mlx5_txq_get(dev, i); + if (txq_ctrl == NULL) + continue; + rx_queue = txq_ctrl->hairpin_conf.peers[0].queue; + rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0); + mlx5_hairpin_queue_peer_unbind(dev, i, 1); + mlx5_txq_release(dev, i); + } while (i--); + return ret; +} + +/* + * Unbind the hairpin port pair, HW configuration of both devices will be clear + * and status will be reset for all the queues used between the them. + * This function only supports to unbind the Tx from one Rx. + * + * @param dev + * Pointer to Ethernet device structure. + * @param rx_port + * Port identifier of the Rx port. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_hairpin_unbind_single_port(struct rte_eth_dev *dev, uint16_t rx_port) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_txq_ctrl *txq_ctrl; + uint32_t i; + int ret; + uint16_t cur_port = priv->dev_data->port_id; + + if (mlx5_eth_find_next(rx_port, priv->pci_dev) != rx_port) { + rte_errno = ENODEV; + DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port); + return -rte_errno; + } + for (i = 0; i != priv->txqs_n; i++) { + uint16_t rx_queue; + + txq_ctrl = mlx5_txq_get(dev, i); + if (txq_ctrl == NULL) + continue; + if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { + mlx5_txq_release(dev, i); + continue; + } + if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) { + mlx5_txq_release(dev, i); + continue; + } + /* Indeed, only the first used queue needs to be checked. */ + if (txq_ctrl->hairpin_conf.manual_bind == 0) { + if (cur_port != rx_port) { + rte_errno = EINVAL; + DRV_LOG(ERR, "port %u and port %u are in" + " auto-bind mode", cur_port, rx_port); + mlx5_txq_release(dev, i); + return -rte_errno; + } else { + return 0; + } + } + rx_queue = txq_ctrl->hairpin_conf.peers[0].queue; + mlx5_txq_release(dev, i); + ret = rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0); + if (ret) { + DRV_LOG(ERR, "port %u Rx queue %d unbind - failure", + rx_port, rx_queue); + return ret; + } + ret = mlx5_hairpin_queue_peer_unbind(dev, i, 1); + if (ret) { + DRV_LOG(ERR, "port %u Tx queue %d unbind - failure", + cur_port, i); + return ret; + } + } + return 0; +} + +/* + * Bind hairpin ports, Rx could be all ports when using RTE_MAX_ETHPORTS. + * @see mlx5_hairpin_bind_single_port() + */ +int +mlx5_hairpin_bind(struct rte_eth_dev *dev, uint16_t rx_port) +{ + int ret = 0; + uint16_t p, pp; + struct mlx5_priv *priv = dev->data->dev_private; + + /* + * If the Rx port has no hairpin configuration with the current port, + * the binding will be skipped in the called function of single port. + * Device started status will be checked only before the queue + * information updating. + */ + if (rx_port == RTE_MAX_ETHPORTS) { + MLX5_ETH_FOREACH_DEV(p, priv->pci_dev) { + ret = mlx5_hairpin_bind_single_port(dev, p); + if (ret != 0) + goto unbind; + } + return ret; + } else { + return mlx5_hairpin_bind_single_port(dev, rx_port); + } +unbind: + MLX5_ETH_FOREACH_DEV(pp, priv->pci_dev) + if (pp < p) + mlx5_hairpin_unbind_single_port(dev, pp); + return ret; +} + +/* + * Unbind hairpin ports, Rx could be all ports when using RTE_MAX_ETHPORTS. + * @see mlx5_hairpin_unbind_single_port() + */ +int +mlx5_hairpin_unbind(struct rte_eth_dev *dev, uint16_t rx_port) +{ + int ret = 0; + uint16_t p; + struct mlx5_priv *priv = dev->data->dev_private; + + if (rx_port == RTE_MAX_ETHPORTS) + MLX5_ETH_FOREACH_DEV(p, priv->pci_dev) { + ret = mlx5_hairpin_unbind_single_port(dev, p); + if (ret != 0) + return ret; + } + else + ret = mlx5_hairpin_bind_single_port(dev, rx_port); + return ret; +} + /** * DPDK callback to start the device. * @@ -336,7 +961,7 @@ dev->data->port_id, strerror(rte_errno)); goto error; } - ret = mlx5_hairpin_bind(dev); + ret = mlx5_hairpin_auto_bind(dev); if (ret) { DRV_LOG(ERR, "port %u hairpin binding failed: %s", dev->data->port_id, strerror(rte_errno)); From patchwork Mon Oct 26 16:37:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 82206 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 102A4A04DD; Mon, 26 Oct 2020 17:39:21 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id DD9FA2C27; Mon, 26 Oct 2020 17:38:28 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id CAC9C2BF7 for ; Mon, 26 Oct 2020 17:38:22 +0100 (CET) From: Bing Zhao To: viacheslavo@mellanox.com, matan@mellanox.com Cc: dev@dpdk.org, orika@nvidia.com, rasland@nvidia.com Date: Tue, 27 Oct 2020 00:37:43 +0800 Message-Id: <1603730267-267228-4-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1603730267-267228-1-git-send-email-bingz@nvidia.com> References: <1602166620-46303-1-git-send-email-bingz@nvidia.com> <1603730267-267228-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v3 3/7] net/mlx5: add support to get hairpin peer ports 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" In real-life business, one device could be attached and detached dynamically. The hairpin configuration of this port to/from all the other ports should be enabled and disabled accordingly. The RTE ethdev lib and PMD should provide this ability to get the peer ports list in case that the application doesn't save it. It is recommended that the size of the array to save the port IDs is as large as the "RTE_MAX_ETHPORTS" to have the maximal capacity. The order of the peer port IDs may be different from that during hairpin queues set in the initialization stage. The peer port ID could be the same as the current device port ID when the hairpin peer ports contain itself - the single port hairpin. The application should check the ports' status and decide if the peer port should be bound / unbound when starting / stopping the current device. Signed-off-by: Bing Zhao Acked-by: Viacheslav Ovsiienko --- drivers/net/mlx5/linux/mlx5_os.c | 2 + drivers/net/mlx5/mlx5.h | 2 + drivers/net/mlx5/mlx5_trigger.c | 89 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index b791859..c890998 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -2572,6 +2572,7 @@ .mtr_ops_get = mlx5_flow_meter_ops_get, .hairpin_bind = mlx5_hairpin_bind, .hairpin_unbind = mlx5_hairpin_unbind, + .hairpin_get_peer_ports = mlx5_hairpin_get_peer_ports, .hairpin_queue_peer_update = mlx5_hairpin_queue_peer_update, .hairpin_queue_peer_bind = mlx5_hairpin_queue_peer_bind, .hairpin_queue_peer_unbind = mlx5_hairpin_queue_peer_unbind, @@ -2655,6 +2656,7 @@ .mtr_ops_get = mlx5_flow_meter_ops_get, .hairpin_bind = mlx5_hairpin_bind, .hairpin_unbind = mlx5_hairpin_unbind, + .hairpin_get_peer_ports = mlx5_hairpin_get_peer_ports, .hairpin_queue_peer_update = mlx5_hairpin_queue_peer_update, .hairpin_queue_peer_bind = mlx5_hairpin_queue_peer_bind, .hairpin_queue_peer_unbind = mlx5_hairpin_queue_peer_unbind, diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 010152c..c537af9 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -1073,6 +1073,8 @@ int mlx5_hairpin_queue_peer_unbind(struct rte_eth_dev *dev, uint16_t cur_queue, uint32_t direction); int mlx5_hairpin_bind(struct rte_eth_dev *dev, uint16_t rx_port); int mlx5_hairpin_unbind(struct rte_eth_dev *dev, uint16_t rx_port); +int mlx5_hairpin_get_peer_ports(struct rte_eth_dev *dev, uint16_t *peer_ports, + size_t len, uint32_t direction); /* mlx5_flow.c */ diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c index f76122b..3f56592 100644 --- a/drivers/net/mlx5/mlx5_trigger.c +++ b/drivers/net/mlx5/mlx5_trigger.c @@ -910,6 +910,95 @@ return ret; } +/* + * DPDK callback to get the hairpin peer ports list. + * This will return the actual number of peer ports and save the identifiers + * into the array (sorted, may be different from that when setting up the + * hairpin peer queues). + * The peer port ID could be the same as the port ID of the current device. + * + * @param dev + * Pointer to Ethernet device structure. + * @param peer_ports + * Pointer to array to save the port identifiers. + * @param len + * The length of the array. + * @param direction + * Current port to peer port direction. + * positive - current used as Tx to get all peer Rx ports. + * zero - current used as Rx to get all peer Tx ports. + * + * @return + * 0 or positive value on success, actual number of peer ports. + * a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_hairpin_get_peer_ports(struct rte_eth_dev *dev, uint16_t *peer_ports, + size_t len, uint32_t direction) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_txq_ctrl *txq_ctrl; + struct mlx5_rxq_ctrl *rxq_ctrl; + uint32_t i; + uint16_t pp; + uint32_t bits[(RTE_MAX_ETHPORTS + 31) / 32] = {0}; + int ret = 0; + + if (direction) { + for (i = 0; i < priv->txqs_n; i++) { + txq_ctrl = mlx5_txq_get(dev, i); + if (!txq_ctrl) + continue; + if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { + mlx5_txq_release(dev, i); + continue; + } + pp = txq_ctrl->hairpin_conf.peers[0].port; + if (pp >= RTE_MAX_ETHPORTS) { + rte_errno = ERANGE; + mlx5_txq_release(dev, i); + DRV_LOG(ERR, "port %hu queue %u peer port " + "out of range %hu", + priv->dev_data->port_id, i, pp); + return -rte_errno; + } + bits[pp / 32] |= 1 << (pp % 32); + mlx5_txq_release(dev, i); + } + } else { + for (i = 0; i < priv->rxqs_n; i++) { + rxq_ctrl = mlx5_rxq_get(dev, i); + if (!rxq_ctrl) + continue; + if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) { + mlx5_rxq_release(dev, i); + continue; + } + pp = rxq_ctrl->hairpin_conf.peers[0].port; + if (pp >= RTE_MAX_ETHPORTS) { + rte_errno = ERANGE; + mlx5_rxq_release(dev, i); + DRV_LOG(ERR, "port %hu queue %u peer port " + "out of range %hu", + priv->dev_data->port_id, i, pp); + return -rte_errno; + } + bits[pp / 32] |= 1 << (pp % 32); + mlx5_rxq_release(dev, i); + } + } + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (bits[i / 32] & (1 << (i % 32))) { + if ((size_t)ret >= len) { + rte_errno = E2BIG; + return -rte_errno; + } + peer_ports[ret++] = i; + } + } + return ret; +} + /** * DPDK callback to start the device. * From patchwork Mon Oct 26 16:37:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 82207 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 741BDA04DD; Mon, 26 Oct 2020 17:39:39 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 8B27A2BDB; Mon, 26 Oct 2020 17:38:40 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 389EF2BDB for ; Mon, 26 Oct 2020 17:38:33 +0100 (CET) From: Bing Zhao To: viacheslavo@mellanox.com, matan@mellanox.com Cc: dev@dpdk.org, orika@nvidia.com, rasland@nvidia.com Date: Tue, 27 Oct 2020 00:37:44 +0800 Message-Id: <1603730267-267228-5-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1603730267-267228-1-git-send-email-bingz@nvidia.com> References: <1602166620-46303-1-git-send-email-bingz@nvidia.com> <1603730267-267228-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v3 4/7] net/mlx5: conditional hairpin auto bind 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" In single port hairpin mode, after the queues are configured during start up. The binding process will be enabled automatically in the port start phase and the default control flow for egress will be created. When switching to two ports hairpin mode, the auto binding process should be skipped if there is no TX queue with the peer RX queue on the same device, and it should be skipped also if the queues are configured with manual bind attribute. If the explicit TX flow rule mode is configured or hairpin is between two ports, the default control flows for TX queues should not be created. Signed-off-by: Bing Zhao Acked-by: Viacheslav Ovsiienko --- drivers/net/mlx5/mlx5_trigger.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c index 3f56592..52691b6 100644 --- a/drivers/net/mlx5/mlx5_trigger.c +++ b/drivers/net/mlx5/mlx5_trigger.c @@ -218,6 +218,8 @@ struct mlx5_devx_obj *rq; unsigned int i; int ret = 0; + bool need_auto = false; + uint16_t self_port = dev->data->port_id; for (i = 0; i != priv->txqs_n; ++i) { txq_ctrl = mlx5_txq_get(dev, i); @@ -227,6 +229,28 @@ mlx5_txq_release(dev, i); continue; } + if (txq_ctrl->hairpin_conf.peers[0].port != self_port) + continue; + if (txq_ctrl->hairpin_conf.manual_bind) { + mlx5_txq_release(dev, i); + return 0; + } + need_auto = true; + mlx5_txq_release(dev, i); + } + if (!need_auto) + return 0; + for (i = 0; i != priv->txqs_n; ++i) { + txq_ctrl = mlx5_txq_get(dev, i); + if (!txq_ctrl) + continue; + if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { + mlx5_txq_release(dev, i); + continue; + } + /* Skip hairpin queues with other peer ports. */ + if (txq_ctrl->hairpin_conf.peers[0].port != self_port) + continue; if (!txq_ctrl->obj) { rte_errno = ENOMEM; DRV_LOG(ERR, "port %u no txq object found: %d", @@ -275,6 +299,9 @@ ret = mlx5_devx_cmd_modify_rq(rq, &rq_attr); if (ret) goto error; + /* Qs with auto-bind will be destroyed directly. */ + rxq_ctrl->hairpin_status = 1; + txq_ctrl->hairpin_status = 1; mlx5_txq_release(dev, i); mlx5_rxq_release(dev, txq_ctrl->hairpin_conf.peers[0].queue); } @@ -1050,9 +1077,13 @@ dev->data->port_id, strerror(rte_errno)); goto error; } + /* + * Such step will be skipped if there is no hairpin TX queue configured + * with RX peer queue from the same device. + */ ret = mlx5_hairpin_auto_bind(dev); if (ret) { - DRV_LOG(ERR, "port %u hairpin binding failed: %s", + DRV_LOG(ERR, "port %u hairpin auto binding failed: %s", dev->data->port_id, strerror(rte_errno)); goto error; } @@ -1203,7 +1234,11 @@ struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i); if (!txq_ctrl) continue; - if (txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN) { + /* Only Tx implicit mode requires the default Tx flow. */ + if (txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN && + txq_ctrl->hairpin_conf.tx_explicit == 0 && + txq_ctrl->hairpin_conf.peers[0].port == + priv->dev_data->port_id) { ret = mlx5_ctrl_flow_source_queue(dev, i); if (ret) { mlx5_txq_release(dev, i); From patchwork Mon Oct 26 16:37:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 82208 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id CA14AA04DD; Mon, 26 Oct 2020 17:39:59 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 3F1B22E1E; Mon, 26 Oct 2020 17:38:42 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 4E9B52BDB for ; Mon, 26 Oct 2020 17:38:37 +0100 (CET) From: Bing Zhao To: viacheslavo@mellanox.com, matan@mellanox.com Cc: dev@dpdk.org, orika@nvidia.com, rasland@nvidia.com Date: Tue, 27 Oct 2020 00:37:45 +0800 Message-Id: <1603730267-267228-6-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1603730267-267228-1-git-send-email-bingz@nvidia.com> References: <1602166620-46303-1-git-send-email-bingz@nvidia.com> <1603730267-267228-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v3 5/7] net/mlx5: change hairpin ingress flow validation 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" In the current implementation of the single port hairpin, there is an implicit splitting process for actions. When inserting a hairpin flow, all the actions will be included with the ingress attribute. The flow engine will check and decide which actions should be moved into the TX flow part, e.g., encapsulation, VLAN push. In some NICs, some actions can only be done in one direction. Since the hairpin flow will be split into two parts, such validation will be skipped. With the hairpin explicit TX flow mode, no splitting is needed any more. The hairpin flow may have no big difference from a standard flow (except the queue). The application should take full charge of the actions and the flow engine should validate the hairpin flow in the same way as other flows. In the meanwhile, a new internal API is added to get the hairpin configuration. This will bypass the useless atomic operation to save the CPU cycles. Signed-off-by: Bing Zhao Acked-by: Viacheslav Ovsiienko --- drivers/net/mlx5/mlx5_flow_dv.c | 17 ++++++++++++++--- drivers/net/mlx5/mlx5_rxq.c | 27 +++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_rxtx.h | 2 ++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 504d842..62e1d19 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -5310,6 +5310,7 @@ struct field_modify_info modify_tcp[] = { .transfer = !!attr->transfer, .fdb_def_rule = !!priv->fdb_def_rule, }; + const struct rte_eth_hairpin_conf *conf; if (items == NULL) return -1; @@ -6155,11 +6156,18 @@ struct field_modify_info modify_tcp[] = { actions, "no fate action is found"); } - /* Continue validation for Xcap and VLAN actions.*/ + /* + * Continue validation for Xcap and VLAN actions. + * If hairpin is working in explicit TX rule mode, there is no actions + * splitting and the validation of hairpin ingress flow should be the + * same as other standard flows. + */ if ((action_flags & (MLX5_FLOW_XCAP_ACTIONS | MLX5_FLOW_VLAN_ACTIONS)) && (queue_index == 0xFFFF || - mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN)) { + mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN || + ((conf = mlx5_rxq_get_hairpin_conf(dev, queue_index)) != NULL && + conf->tx_explicit != 0))) { if ((action_flags & MLX5_FLOW_XCAP_ACTIONS) == MLX5_FLOW_XCAP_ACTIONS) return rte_flow_error_set(error, ENOTSUP, @@ -6188,7 +6196,10 @@ struct field_modify_info modify_tcp[] = { "multiple VLAN actions"); } } - /* Hairpin flow will add one more TAG action. */ + /* + * Hairpin flow will add one more TAG action in TX implicit mode. + * In TX explicit mode, there will be no hairpin flow ID. + */ if (hairpin > 0) rw_act_num += MLX5_ACT_NUM_SET_TAG; /* extra metadata enabled: one more TAG action will be add. */ diff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c index 034f43e..493c5f2 100644 --- a/drivers/net/mlx5/mlx5_rxq.c +++ b/drivers/net/mlx5/mlx5_rxq.c @@ -1845,6 +1845,33 @@ enum mlx5_rxq_type return MLX5_RXQ_TYPE_UNDEFINED; } +/* + * Get a Rx hairpin queue configuration. + * + * @param dev + * Pointer to Ethernet device. + * @param idx + * Rx queue index. + * + * @return + * Pointer to the configuration if a hairpin RX queue, otherwise NULL. + */ +const struct rte_eth_hairpin_conf * +mlx5_rxq_get_hairpin_conf(struct rte_eth_dev *dev, uint16_t idx) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_rxq_ctrl *rxq_ctrl = NULL; + + if (idx < priv->rxqs_n && (*priv->rxqs)[idx]) { + rxq_ctrl = container_of((*priv->rxqs)[idx], + struct mlx5_rxq_ctrl, + rxq); + if (rxq_ctrl->type == MLX5_RXQ_TYPE_HAIRPIN) + return &rxq_ctrl->hairpin_conf; + } + return NULL; +} + /** * Match queues listed in arguments to queues contained in indirection table * object. diff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h index cdc18e3..1b5fba4 100644 --- a/drivers/net/mlx5/mlx5_rxtx.h +++ b/drivers/net/mlx5/mlx5_rxtx.h @@ -360,6 +360,8 @@ uint32_t mlx5_hrxq_get(struct rte_eth_dev *dev, int mlx5_hrxq_release(struct rte_eth_dev *dev, uint32_t hxrq_idx); int mlx5_hrxq_verify(struct rte_eth_dev *dev); enum mlx5_rxq_type mlx5_rxq_get_type(struct rte_eth_dev *dev, uint16_t idx); +const struct rte_eth_hairpin_conf *mlx5_rxq_get_hairpin_conf + (struct rte_eth_dev *dev, uint16_t idx); struct mlx5_hrxq *mlx5_drop_action_create(struct rte_eth_dev *dev); void mlx5_drop_action_destroy(struct rte_eth_dev *dev); uint64_t mlx5_get_rx_port_offloads(void); From patchwork Mon Oct 26 16:37:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 82209 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 22686A04DD; Mon, 26 Oct 2020 17:40:20 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B95763257; Mon, 26 Oct 2020 17:38:43 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 100322C2E for ; Mon, 26 Oct 2020 17:38:41 +0100 (CET) From: Bing Zhao To: viacheslavo@mellanox.com, matan@mellanox.com Cc: dev@dpdk.org, orika@nvidia.com, rasland@nvidia.com Date: Tue, 27 Oct 2020 00:37:46 +0800 Message-Id: <1603730267-267228-7-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1603730267-267228-1-git-send-email-bingz@nvidia.com> References: <1602166620-46303-1-git-send-email-bingz@nvidia.com> <1603730267-267228-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v3 6/7] net/mlx5: not split hairpin flow in explicit mode 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" In the current implementation, the hairpin flow will be split into two flows implicitly if there is some action that only belongs to the Tx part. A Tx device flow will be inserted by the mlx5 PMD itself. In hairpin between two ports, the explicit Tx flow mode will be the only one to be supported. It is not the appropriate behavior to insert a Tx flow into another device implicitly. The application could create any flow as it likes and has full control of the user flows. Hairpin flows will have no difference from standard flows and the application can decide how to chain Rx and Tx flows together. Even in the single port hairpin, this explicit Tx flow mode could also be supported. When checking if the hairpin needs to be split, it will just return if the hairpin queue is with "tx_explicit" attribute. Then in the following steps for validation and translation, the code path will be the same as that for standard flows. Signed-off-by: Bing Zhao Acked-by: Viacheslav Ovsiienko --- v3: remove unnecessary checking of hairpin queue type --- drivers/net/mlx5/mlx5_flow.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 949b9ce..4756cf9 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -3618,6 +3618,7 @@ struct rte_flow_shared_action * const struct rte_flow_action_queue *queue; const struct rte_flow_action_rss *rss; const struct rte_flow_action_raw_encap *raw_encap; + const struct rte_eth_hairpin_conf *conf; if (!attr->ingress) return 0; @@ -3627,8 +3628,8 @@ struct rte_flow_shared_action * queue = actions->conf; if (queue == NULL) return 0; - if (mlx5_rxq_get_type(dev, queue->index) != - MLX5_RXQ_TYPE_HAIRPIN) + conf = mlx5_rxq_get_hairpin_conf(dev, queue->index); + if (conf != NULL && !!conf->tx_explicit) return 0; queue_action = 1; action_n++; @@ -3637,8 +3638,8 @@ struct rte_flow_shared_action * rss = actions->conf; if (rss == NULL || rss->queue_num == 0) return 0; - if (mlx5_rxq_get_type(dev, rss->queue[0]) != - MLX5_RXQ_TYPE_HAIRPIN) + conf = mlx5_rxq_get_hairpin_conf(dev, rss->queue[0]); + if (conf != NULL && !!conf->tx_explicit) return 0; queue_action = 1; action_n++; From patchwork Mon Oct 26 16:37:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 82210 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 66D41A04DE; Mon, 26 Oct 2020 17:40:41 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 6E78E2B9E; Mon, 26 Oct 2020 17:39:03 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id D66C1354D for ; Mon, 26 Oct 2020 17:38:43 +0100 (CET) From: Bing Zhao To: viacheslavo@mellanox.com, matan@mellanox.com Cc: dev@dpdk.org, orika@nvidia.com, rasland@nvidia.com Date: Tue, 27 Oct 2020 00:37:47 +0800 Message-Id: <1603730267-267228-8-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1603730267-267228-1-git-send-email-bingz@nvidia.com> References: <1602166620-46303-1-git-send-email-bingz@nvidia.com> <1603730267-267228-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v3 7/7] doc: update mlx5 hairpin support and limitations 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" Hairpin between two ports will be supported by mlx5 PMD. The supported scenarios and limitations are listed in "mlx5.rst". Signed-off-by: Bing Zhao Acked-by: Viacheslav Ovsiienko --- doc/guides/nics/mlx5.rst | 5 +++++ doc/guides/rel_notes/release_20_11.rst | 1 + 2 files changed, 6 insertions(+) diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst index 8dc7c62..ab5cc62 100644 --- a/doc/guides/nics/mlx5.rst +++ b/doc/guides/nics/mlx5.rst @@ -326,6 +326,11 @@ Limitations The last extension header item 'next header' field can specify the following header protocol type. +- Hairpin: + + - Hairpin between two ports could only manual binding and explicit Tx flow mode. For single port hairpin, all the combinations of auto/manual binding and explicit/implicit Tx flow mode could be supported. + - Hairpin in switchdev SR-IOV mode is not supported till now. + Statistics ---------- diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst index f9ef4fe..1c5c2e0 100644 --- a/doc/guides/rel_notes/release_20_11.rst +++ b/doc/guides/rel_notes/release_20_11.rst @@ -354,6 +354,7 @@ New Features * Updated the supported timeout for Age action to the maximal value supported by rte_flow API. * Added support of Age action query. + * Added support of multi-ports hairpin. * **Updated vhost sample application.**