From patchwork Thu Oct 15 05:35:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 80827 X-Patchwork-Delegate: ferruh.yigit@amd.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 53DE4A04DB; Thu, 15 Oct 2020 07:35:51 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id EE3E31DC2E; Thu, 15 Oct 2020 07:35:38 +0200 (CEST) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id ABA781DC29 for ; Thu, 15 Oct 2020 07:35:34 +0200 (CEST) From: Bing Zhao To: thomas@monjalon.net, orika@nvidia.com, ferruh.yigit@intel.com, arybchenko@solarflare.com, mdr@ashroe.eu, nhorman@tuxdriver.com, bernard.iremonger@intel.com, beilei.xing@intel.com, wenzhuo.lu@intel.com Cc: dev@dpdk.org Date: Thu, 15 Oct 2020 13:35:20 +0800 Message-Id: <1602740124-397688-2-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1602740124-397688-1-git-send-email-bingz@nvidia.com> References: <1601511962-21532-1-git-send-email-bingz@nvidia.com> <1602740124-397688-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v5 1/5] ethdev: add hairpin bind and unbind APIs 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, all the hairpin TX and RX queues belong to the same device. After the queues are set up properly, there is no other dependency between the TX queue and its RX peer queue. The binding process that connected the TX and RX queues together from hardware level will be done automatically during the device start procedure. Everything required is configured and initialized already for the binding process. But in two ports hairpin mode, there will be some cross-dependences between two different ports. Usually, the ports will be initialized serially by the main thread but not in parallel. The earlier port will not be able to enable the bind if the following peer port is not yet configured with HW resources. What's more, if one port is detached / attached dynamically, it would introduce more trouble for the hairpin binding. To overcome these, new APIs for binding and unbinding are added. During startup, only the hairpin TX and RX peer queues will be set up. Nothing will be done when starting the device if the queues are without auto-bind attribute. Only after the required ports pair started, the `rte_eth_hairpin_bind()` API can be called to bind the all TX queues of the egress port to the RX queues of the peer port. Then the connection between the egress and ingress ports pair will be established. The `rte_eth_hairpin_unbind()` API could be used to disconnect the egress and the peer ingress ports. This should only be called before the device is closed if needed. When doing the clean up, all the egress and ingress pairs related to a single port should be taken into consideration, especially in the hot unplug case. mode is described. Signed-off-by: Bing Zhao Acked-by: Ori Kam Acked-by: Thomas Monjalon --- v5: * Change EINVAL to ENODEV * add newline character in the end of log line * descriptions update v4: squash release notes update v2: remove the all peer ports logic from rte API --- doc/guides/rel_notes/release_20_11.rst | 4 +++ lib/librte_ethdev/rte_ethdev.c | 46 ++++++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev.h | 52 ++++++++++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_driver.h | 52 ++++++++++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_version.map | 2 ++ 5 files changed, 156 insertions(+) diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst index 30db8f2..0a9ae54 100644 --- a/doc/guides/rel_notes/release_20_11.rst +++ b/doc/guides/rel_notes/release_20_11.rst @@ -67,6 +67,10 @@ New Features Added the FEC API which provides functions for query FEC capabilities and current FEC mode from device. Also, API for configuring FEC mode is also provided. +* **Updated the ethdev library to support hairpin between two ports.** + + New APIs are introduced to support binding / unbinding 2 ports hairpin. + * **Updated Broadcom bnxt driver.** Updated the Broadcom bnxt driver with new features and improvements, including: diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c index 5b7979a..150c555 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -2212,6 +2212,52 @@ struct rte_eth_dev * return eth_err(port_id, ret); } +int +rte_eth_hairpin_bind(uint16_t tx_port, uint16_t rx_port) +{ + struct rte_eth_dev *dev; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(tx_port, -ENODEV); + dev = &rte_eth_devices[tx_port]; + if (!dev->data->dev_started) { + RTE_ETHDEV_LOG(ERR, "TX port %d is not started\n", tx_port); + return -EBUSY; + } + + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->hairpin_bind, -ENOTSUP); + ret = (*dev->dev_ops->hairpin_bind)(dev, rx_port); + if (ret) + RTE_ETHDEV_LOG(ERR, "Failed to bind hairpin TX %d " + "to RX %d (%d - all ports)\n", tx_port, + rx_port, RTE_MAX_ETHPORTS); + + return ret; +} + +int +rte_eth_hairpin_unbind(uint16_t tx_port, uint16_t rx_port) +{ + struct rte_eth_dev *dev; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(tx_port, -ENODEV); + dev = &rte_eth_devices[tx_port]; + if (!dev->data->dev_started) { + RTE_ETHDEV_LOG(ERR, "TX port %d is already stopped\n", tx_port); + return -EBUSY; + } + + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->hairpin_unbind, -ENOTSUP); + ret = (*dev->dev_ops->hairpin_unbind)(dev, rx_port); + if (ret) + RTE_ETHDEV_LOG(ERR, "Failed to unbind hairpin " + "TX %d from RX %d (%d - all ports)\n", tx_port, + rx_port, RTE_MAX_ETHPORTS); + + return ret; +} + void rte_eth_tx_buffer_drop_callback(struct rte_mbuf **pkts, uint16_t unsent, void *userdata __rte_unused) diff --git a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index f4cc591..3bdb189 100644 --- a/lib/librte_ethdev/rte_ethdev.h +++ b/lib/librte_ethdev/rte_ethdev.h @@ -2158,6 +2158,58 @@ int rte_eth_tx_queue_setup(uint16_t port_id, uint16_t tx_queue_id, const struct rte_eth_hairpin_conf *conf); /** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Bind all hairpin TX queues of one port to the RX queues of the peer port. + * It is only allowed to call this function after all hairpin queues are + * configured properly and the devices are in started state. + * + * @param tx_port + * The identifier of the TX port. + * @param rx_port + * The identifier of peer RX port. + * RTE_MAX_ETHPORTS is allowed for the traversal of all devices. + * RX port ID could have the same value as TX port ID. + * + * @return + * - (0) if successful. + * - (-ENODEV) if TX port ID is invalid. + * - (-EBUSY) if device is not in started state. + * - (-ENOTSUP) if hardware doesn't support. + * - Others detailed errors from PMD drivers. + */ +__rte_experimental +int rte_eth_hairpin_bind(uint16_t tx_port, uint16_t rx_port); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Unbind all hairpin TX queues of one port from the RX queues of the peer port. + * This should be called before closing the TX or RX devices, if the bind + * function is called before. + * After unbinding the hairpin ports pair, it is allowed to bind them again. + * Changing queues configuration should be after stopping the device(s). + * + * @param tx_port + * The identifier of the TX port. + * @param rx_port + * The identifier of peer RX port. + * RTE_MAX_ETHPORTS is allowed for traversal of all devices. + * RX port ID could have the same value as TX port ID. + * + * @return + * - (0) if successful. + * - (-ENODEV) if TX port ID is invalid. + * - (-EBUSY) if device is in stopped state. + * - (-ENOTSUP) if hardware doesn't support. + * - Others detailed errors from PMD drivers. + */ +__rte_experimental +int rte_eth_hairpin_unbind(uint16_t tx_port, uint16_t rx_port); + +/** * Return the NUMA socket to which an Ethernet device is connected * * @param port_id diff --git a/lib/librte_ethdev/rte_ethdev_driver.h b/lib/librte_ethdev/rte_ethdev_driver.h index 35cc4fb..26ded15 100644 --- a/lib/librte_ethdev/rte_ethdev_driver.h +++ b/lib/librte_ethdev/rte_ethdev_driver.h @@ -656,6 +656,54 @@ typedef int (*eth_fec_get_t)(struct rte_eth_dev *dev, typedef int (*eth_fec_set_t)(struct rte_eth_dev *dev, uint32_t fec_capa); /** + * @internal + * Bind all hairpin TX queues of one port to the RX queues of the peer port. + * + * @param dev + * ethdev handle of port. + * @param rx_port + * the peer RX port. + * + * @return + * Negative errno value on error, 0 on success. + * + * @retval 0 + * Success, bind successfully. + * @retval -ENOTSUP + * Bind API is not supported. + * @retval -EINVAL + * One of the parameters is invalid. + * @retval -EBUSY + * Device is not started. + */ +typedef int (*eth_hairpin_bind_t)(struct rte_eth_dev *dev, + uint16_t rx_port); + +/** + * @internal + * Unbind all hairpin TX queues of one port from the RX queues of the peer port. + * + * @param dev + * ethdev handle of port. + * @param rx_port + * the peer RX port. + * + * @return + * Negative errno value on error, 0 on success. + * + * @retval 0 + * Success, unbind successfully. + * @retval -ENOTSUP + * Bind API is not supported. + * @retval -EINVAL + * One of the parameters is invalid. + * @retval -EBUSY + * Device is already stopped. + */ +typedef int (*eth_hairpin_unbind_t)(struct rte_eth_dev *dev, + uint16_t rx_port); + +/** * @internal A structure containing the functions exported by an Ethernet driver. */ struct eth_dev_ops { @@ -801,6 +849,10 @@ struct eth_dev_ops { /**< Get Forward Error Correction(FEC) mode. */ eth_fec_set_t fec_set; /**< Set Forward Error Correction(FEC) mode. */ + eth_hairpin_bind_t hairpin_bind; + /**< Bind all hairpin TX queues of device to the peer port RX queues. */ + eth_hairpin_unbind_t hairpin_unbind; + /**< Unbind all hairpin TX queues from the peer port RX queues. */ }; /** diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map index f8a0945..1aee03a 100644 --- a/lib/librte_ethdev/rte_ethdev_version.map +++ b/lib/librte_ethdev/rte_ethdev_version.map @@ -227,6 +227,8 @@ EXPERIMENTAL { rte_tm_wred_profile_delete; # added in 20.11 + rte_eth_hairpin_bind; + rte_eth_hairpin_unbind; rte_eth_link_speed_to_str; rte_eth_link_to_str; rte_eth_fec_get_capability; From patchwork Thu Oct 15 05:35:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 80828 X-Patchwork-Delegate: ferruh.yigit@amd.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 F2508A04DB; Thu, 15 Oct 2020 07:36:11 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 253DB1DC3B; Thu, 15 Oct 2020 07:35:47 +0200 (CEST) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 956E01DC29 for ; Thu, 15 Oct 2020 07:35:38 +0200 (CEST) From: Bing Zhao To: thomas@monjalon.net, orika@nvidia.com, ferruh.yigit@intel.com, arybchenko@solarflare.com, mdr@ashroe.eu, nhorman@tuxdriver.com, bernard.iremonger@intel.com, beilei.xing@intel.com, wenzhuo.lu@intel.com Cc: dev@dpdk.org Date: Thu, 15 Oct 2020 13:35:21 +0800 Message-Id: <1602740124-397688-3-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1602740124-397688-1-git-send-email-bingz@nvidia.com> References: <1601511962-21532-1-git-send-email-bingz@nvidia.com> <1602740124-397688-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v5 2/5] ethdev: add new attributes to hairpin config 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" To support two ports hairpin mode and keep the backward compatibility for the application, two new attribute members of the hairpin queue configuration structure will be added. `tx_explicit` means if the application itself will insert the TX part flow rules. If not set, PMD will insert the rules implicitly. `manual_bind` means if the hairpin TX queue and peer RX queue will be bound automatically during the device start stage. Different TX and RX queue pairs could have different values, but it is highly recommended that all paired queues between one egress and its peer ingress ports have the same values, in order not to bring any chaos to the system. The actual support of these attribute parameters will be checked and decided by the PMD drivers. In the single port hairpin, if both are zero without any setting, the behavior will remain the same as before. It means that no bind API needs to be called and no TX flow rules need to be inserted manually by the application. Signed-off-by: Bing Zhao Acked-by: Ori Kam Acked-by: Thomas Monjalon --- v4: squash document update and more info for the two new attributes v2: optimize the structure and remove unused macros --- doc/guides/prog_guide/rte_flow.rst | 3 +++ doc/guides/rel_notes/release_20_11.rst | 6 ++++++ lib/librte_ethdev/rte_ethdev.c | 8 ++++---- lib/librte_ethdev/rte_ethdev.h | 27 ++++++++++++++++++++++++++- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst index f26a6c2..c6f828a 100644 --- a/doc/guides/prog_guide/rte_flow.rst +++ b/doc/guides/prog_guide/rte_flow.rst @@ -2592,6 +2592,9 @@ set, unpredictable value will be seen depending on driver implementation. For loopback/hairpin packet, metadata set on Rx/Tx may or may not be propagated to the other path depending on HW capability. +In hairpin case with TX explicit flow mode, metadata could (not mandatory) be +used to connect the RX and TX flows if it can be propagated from RX to TX path. + .. _table_rte_flow_action_set_meta: .. table:: SET_META diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst index 0a9ae54..2e7dc2d 100644 --- a/doc/guides/rel_notes/release_20_11.rst +++ b/doc/guides/rel_notes/release_20_11.rst @@ -70,6 +70,7 @@ New Features * **Updated the ethdev library to support hairpin between two ports.** New APIs are introduced to support binding / unbinding 2 ports hairpin. + Hairpin TX part flow rules can be inserted explicitly. * **Updated Broadcom bnxt driver.** @@ -355,6 +356,11 @@ ABI Changes * ``ethdev`` internal functions are marked with ``__rte_internal`` tag. + * ``struct rte_eth_hairpin_conf`` has two new members: + + * ``uint32_t tx_explicit:1;`` + * ``uint32_t manual_bind:1;`` + Known Issues ------------ diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c index 150c555..3cde7a7 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -2004,13 +2004,13 @@ struct rte_eth_dev * } if (conf->peer_count > cap.max_rx_2_tx) { RTE_ETHDEV_LOG(ERR, - "Invalid value for number of peers for Rx queue(=%hu), should be: <= %hu", + "Invalid value for number of peers for Rx queue(=%u), should be: <= %hu", conf->peer_count, cap.max_rx_2_tx); return -EINVAL; } if (conf->peer_count == 0) { RTE_ETHDEV_LOG(ERR, - "Invalid value for number of peers for Rx queue(=%hu), should be: > 0", + "Invalid value for number of peers for Rx queue(=%u), should be: > 0", conf->peer_count); return -EINVAL; } @@ -2175,13 +2175,13 @@ struct rte_eth_dev * } if (conf->peer_count > cap.max_tx_2_rx) { RTE_ETHDEV_LOG(ERR, - "Invalid value for number of peers for Tx queue(=%hu), should be: <= %hu", + "Invalid value for number of peers for Tx queue(=%u), should be: <= %hu", conf->peer_count, cap.max_tx_2_rx); return -EINVAL; } if (conf->peer_count == 0) { RTE_ETHDEV_LOG(ERR, - "Invalid value for number of peers for Tx queue(=%hu), should be: > 0", + "Invalid value for number of peers for Tx queue(=%u), should be: > 0", conf->peer_count); return -EINVAL; } diff --git a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index 3bdb189..dabbbd4 100644 --- a/lib/librte_ethdev/rte_ethdev.h +++ b/lib/librte_ethdev/rte_ethdev.h @@ -1045,7 +1045,32 @@ struct rte_eth_hairpin_peer { * A structure used to configure hairpin binding. */ struct rte_eth_hairpin_conf { - uint16_t peer_count; /**< The number of peers. */ + uint32_t peer_count:16; /**< The number of peers. */ + + /** + * Explicit TX flow rule mode. One hairpin pair of queues should have + * the same attribute. The actual support depends on the PMD. + * + * - When set, the user should be responsible for inserting the hairpin + * TX part flows and removing them. + * - When clear, the PMD will try to handle the TX part of the flows, + * e.g., by splitting one flow into two parts. + */ + uint32_t tx_explicit:1; + + /** + * Manually bind hairpin queues. One hairpin pair of queues should have + * the same attribute. The actual support depends on the PMD. + * + * - When set, to enable hairpin, the user should call the hairpin bind + * API after all the queues are set up properly and the ports are + * started. Also, the hairpin unbind API should be called accordingly + * before stopping a port that with hairpin configured. + * - When clear, the PMD will try to enable the hairpin with the queues + * configured automatically during port start. + */ + uint32_t manual_bind:1; + uint32_t reserved:14; /**< Reserved bits. */ struct rte_eth_hairpin_peer peers[RTE_ETH_MAX_HAIRPIN_PEERS]; }; From patchwork Thu Oct 15 05:35:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 80829 X-Patchwork-Delegate: ferruh.yigit@amd.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 7C514A04DB; Thu, 15 Oct 2020 07:36:30 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 452131DC4B; Thu, 15 Oct 2020 07:35:49 +0200 (CEST) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id B91AE1DC37 for ; Thu, 15 Oct 2020 07:35:42 +0200 (CEST) From: Bing Zhao To: thomas@monjalon.net, orika@nvidia.com, ferruh.yigit@intel.com, arybchenko@solarflare.com, mdr@ashroe.eu, nhorman@tuxdriver.com, bernard.iremonger@intel.com, beilei.xing@intel.com, wenzhuo.lu@intel.com Cc: dev@dpdk.org Date: Thu, 15 Oct 2020 13:35:22 +0800 Message-Id: <1602740124-397688-4-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1602740124-397688-1-git-send-email-bingz@nvidia.com> References: <1601511962-21532-1-git-send-email-bingz@nvidia.com> <1602740124-397688-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v5 3/5] ethdev: add API to get hairpin peer ports list 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" After hairpin queues are configured, in general, the application will maintain the ports topology and even the queues configuration for the hairpin. But sometimes it will not. If there is no hot-plug, it is easy to bind and unbind hairpin among all the ports. The application can just connect or disconnect the hairpin egress ports to/from all the probed ingress ports. Then all the connections could be handled properly. But with hot-plug / hot-unplug, one port could be probed and removed dynamically. With two ports hairpin, all the connections from and to this port should be handled after start(bind) or before stop(unbind). It is necessary to know the hairpin topology with this port. This function will return the ports list with the actual peer ports number after configuration. Either peer RX or TX ports will be gotten with this function call. Signed-off-by: Bing Zhao Acked-by: Ori Kam --- v5: * change EINVAL to ENODEV * add newline character v4: add release notes update v3: * change the direction from bool to unsigned int type * add length to protect the array from getting corrupted --- doc/guides/rel_notes/release_20_11.rst | 1 + lib/librte_ethdev/rte_ethdev.c | 24 +++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev.h | 30 +++++++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_driver.h | 33 ++++++++++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_version.map | 1 + 5 files changed, 89 insertions(+) diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst index 2e7dc2d..0596c66 100644 --- a/doc/guides/rel_notes/release_20_11.rst +++ b/doc/guides/rel_notes/release_20_11.rst @@ -71,6 +71,7 @@ New Features New APIs are introduced to support binding / unbinding 2 ports hairpin. Hairpin TX part flow rules can be inserted explicitly. + New API is added to get the hairpin peer ports list. * **Updated Broadcom bnxt driver.** diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c index 3cde7a7..a95d294 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -2258,6 +2258,30 @@ struct rte_eth_dev * return ret; } +int +rte_eth_hairpin_get_peer_ports(uint16_t port_id, uint16_t *peer_ports, + size_t len, uint32_t direction) +{ + struct rte_eth_dev *dev; + int ret; + + if (!peer_ports || !len) + return -EINVAL; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV); + dev = &rte_eth_devices[port_id]; + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->hairpin_get_peer_ports, + -ENOTSUP); + + ret = (*dev->dev_ops->hairpin_get_peer_ports)(dev, peer_ports, + len, direction); + if (ret < 0) + RTE_ETHDEV_LOG(ERR, "Failed to get %d hairpin peer %s ports\n", + port_id, direction ? "RX" : "TX"); + + return ret; +} + void rte_eth_tx_buffer_drop_callback(struct rte_mbuf **pkts, uint16_t unsent, void *userdata __rte_unused) diff --git a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index dabbbd4..bf81dfe 100644 --- a/lib/librte_ethdev/rte_ethdev.h +++ b/lib/librte_ethdev/rte_ethdev.h @@ -2186,6 +2186,36 @@ int rte_eth_tx_queue_setup(uint16_t port_id, uint16_t tx_queue_id, * @warning * @b EXPERIMENTAL: this API may change, or be removed, without prior notice * + * Get all the hairpin peer RX / TX ports of the current port. + * The caller should ensure that the array is large enough to save the ports + * list. + * + * @param port_id + * The port identifier of the Ethernet device. + * @param peer_ports + * Pointer to the array to store the peer ports list. + * @param len + * Length of the array to store the port identifiers. + * @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) actual peer ports number. + * - (-EINVAL) if bad parameter. + * - (-ENODEV) if *port_id* invalid + * - (-ENOTSUP) if hardware doesn't support. + * - Others detailed errors from PMD drivers. + */ +__rte_experimental +int rte_eth_hairpin_get_peer_ports(uint16_t port_id, uint16_t *peer_ports, + size_t len, uint32_t direction); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * * Bind all hairpin TX queues of one port to the RX queues of the peer port. * It is only allowed to call this function after all hairpin queues are * configured properly and the devices are in started state. diff --git a/lib/librte_ethdev/rte_ethdev_driver.h b/lib/librte_ethdev/rte_ethdev_driver.h index 26ded15..3c3c859 100644 --- a/lib/librte_ethdev/rte_ethdev_driver.h +++ b/lib/librte_ethdev/rte_ethdev_driver.h @@ -657,6 +657,37 @@ typedef int (*eth_fec_get_t)(struct rte_eth_dev *dev, /** * @internal + * Get all hairpin TX/RX peer ports of the current device, if any. + * + * @param dev + * ethdev handle of port. + * @param peer_ports + * array to save the ports list. + * @param len + * array length. + * @param direction + * value to decide the current to peer direction + * positive - used as TX to get all peer RX ports. + * zero - used as RX to get all peer TX ports. + * + * @return + * Negative errno value on error, 0 or positive on success. + * + * @retval 0 + * Success, no peer ports. + * @retval >0 + * Actual number of the peer ports. + * @retval -ENOTSUP + * Get peer ports API is not supported. + * @retval -EINVAL + * One of the parameters is invalid. + */ +typedef int (*hairpin_get_peer_ports_t)(struct rte_eth_dev *dev, + uint16_t *peer_ports, size_t len, + uint32_t direction); + +/** + * @internal * Bind all hairpin TX queues of one port to the RX queues of the peer port. * * @param dev @@ -849,6 +880,8 @@ struct eth_dev_ops { /**< Get Forward Error Correction(FEC) mode. */ eth_fec_set_t fec_set; /**< Set Forward Error Correction(FEC) mode. */ + hairpin_get_peer_ports_t hairpin_get_peer_ports; + /**< Get hairpin peer ports list. */ eth_hairpin_bind_t hairpin_bind; /**< Bind all hairpin TX queues of device to the peer port RX queues. */ eth_hairpin_unbind_t hairpin_unbind; diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map index 1aee03a..e644391 100644 --- a/lib/librte_ethdev/rte_ethdev_version.map +++ b/lib/librte_ethdev/rte_ethdev_version.map @@ -228,6 +228,7 @@ EXPERIMENTAL { # added in 20.11 rte_eth_hairpin_bind; + rte_eth_hairpin_get_peer_ports; rte_eth_hairpin_unbind; rte_eth_link_speed_to_str; rte_eth_link_to_str; From patchwork Thu Oct 15 05:35:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 80830 X-Patchwork-Delegate: ferruh.yigit@amd.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 43084A04DB; Thu, 15 Oct 2020 07:36:51 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id E14231DC63; Thu, 15 Oct 2020 07:35:59 +0200 (CEST) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 8BA3D1DC37 for ; Thu, 15 Oct 2020 07:35:46 +0200 (CEST) From: Bing Zhao To: thomas@monjalon.net, orika@nvidia.com, ferruh.yigit@intel.com, arybchenko@solarflare.com, mdr@ashroe.eu, nhorman@tuxdriver.com, bernard.iremonger@intel.com, beilei.xing@intel.com, wenzhuo.lu@intel.com Cc: dev@dpdk.org Date: Thu, 15 Oct 2020 13:35:23 +0800 Message-Id: <1602740124-397688-5-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1602740124-397688-1-git-send-email-bingz@nvidia.com> References: <1601511962-21532-1-git-send-email-bingz@nvidia.com> <1602740124-397688-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v5 4/5] ethdev: add APIs for hairpin queue operation 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" Every hairpin queue pair should be configured properly and the connection between TX and RX queues should be established, before hairpin function works. In single port hairpin mode, the queues of each pair belong to the same device. It is easy to get the hardware and software information of each queue and configure the hairpin connection with such information. In two ports hairpin mode, it is not easy or inappropriate to access one queue's information from another device. Since hairpin is configured per queue pair, three new APIs are introduced and they are internal for the PMD using. The peer update API helps to pass one queue's information to the peer queue and get the peer's information back for the next step. The peer bind API configures the current queue with the peer's information. For each hairpin queue pair, this API may need to be called twice to configure the TX, RX queues separately. The peer unbind API resets the current queue configuration and state to disconnect it from the peer queue. Also, it may need to be called twice to disconnect TX, RX queues from each other. Some parameter of the above APIs might not be mandatory, and it depends on the PMD implementation. The structure of `rte_hairpin_peer_info` is only a declaration and the actual members will be defined in each PMD when being used. Signed-off-by: Bing Zhao Acked-by: Ori Kam --- v5: commnets update v3: change the direction from bool to unsigned int type --- lib/librte_ethdev/rte_ethdev.c | 55 +++++++++++++++++ lib/librte_ethdev/rte_ethdev_driver.h | 101 +++++++++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_version.map | 3 + 3 files changed, 159 insertions(+) diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c index a95d294..8358337 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -5624,6 +5624,61 @@ enum rte_eth_switch_domain_state { return 0; } +int +rte_eth_hairpin_queue_peer_update(uint16_t peer_port, uint16_t peer_queue, + struct rte_hairpin_peer_info *cur_info, + struct rte_hairpin_peer_info *peer_info, + uint32_t direction) +{ + struct rte_eth_dev *dev; + + /* Current queue information is not mandatory. */ + if (peer_info == NULL) + return -EINVAL; + + /* No need to check the validity again. */ + dev = &rte_eth_devices[peer_port]; + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->hairpin_queue_peer_update, + -ENOTSUP); + + return (*dev->dev_ops->hairpin_queue_peer_update)(dev, peer_queue, + cur_info, peer_info, direction); +} + +int +rte_eth_hairpin_queue_peer_bind(uint16_t cur_port, uint16_t cur_queue, + struct rte_hairpin_peer_info *peer_info, + uint32_t direction) +{ + struct rte_eth_dev *dev; + + if (peer_info == NULL) + return -EINVAL; + + /* No need to check the validity again. */ + dev = &rte_eth_devices[cur_port]; + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->hairpin_queue_peer_bind, + -ENOTSUP); + + return (*dev->dev_ops->hairpin_queue_peer_bind)(dev, cur_queue, + peer_info, direction); +} + +int +rte_eth_hairpin_queue_peer_unbind(uint16_t cur_port, uint16_t cur_queue, + uint32_t direction) +{ + struct rte_eth_dev *dev; + + /* No need to check the validity again. */ + dev = &rte_eth_devices[cur_port]; + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->hairpin_queue_peer_unbind, + -ENOTSUP); + + return (*dev->dev_ops->hairpin_queue_peer_unbind)(dev, cur_queue, + direction); +} + RTE_LOG_REGISTER(rte_eth_dev_logtype, lib.ethdev, INFO); RTE_INIT(ethdev_init_telemetry) diff --git a/lib/librte_ethdev/rte_ethdev_driver.h b/lib/librte_ethdev/rte_ethdev_driver.h index 3c3c859..1744d27 100644 --- a/lib/librte_ethdev/rte_ethdev_driver.h +++ b/lib/librte_ethdev/rte_ethdev_driver.h @@ -21,6 +21,9 @@ extern "C" { #endif +/**< @internal Declaration of the hairpin peer queue information structure. */ +struct rte_hairpin_peer_info; + /* * Definitions of all functions exported by an Ethernet driver through the * generic structure of type *eth_dev_ops* supplied in the *rte_eth_dev* @@ -734,6 +737,21 @@ typedef int (*eth_hairpin_bind_t)(struct rte_eth_dev *dev, typedef int (*eth_hairpin_unbind_t)(struct rte_eth_dev *dev, uint16_t rx_port); +typedef int (*eth_hairpin_queue_peer_update_t) + (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); +/**< @internal Update and fetch peer queue information. */ + +typedef int (*eth_hairpin_queue_peer_bind_t) + (struct rte_eth_dev *dev, uint16_t cur_queue, + struct rte_hairpin_peer_info *peer_info, uint32_t direction); +/**< @internal Bind peer queue to the current queue with fetched information. */ + +typedef int (*eth_hairpin_queue_peer_unbind_t) + (struct rte_eth_dev *dev, uint16_t cur_queue, uint32_t direction); +/**< @internal Unbind peer queue from the current queue. */ + /** * @internal A structure containing the functions exported by an Ethernet driver. */ @@ -886,6 +904,12 @@ struct eth_dev_ops { /**< Bind all hairpin TX queues of device to the peer port RX queues. */ eth_hairpin_unbind_t hairpin_unbind; /**< Unbind all hairpin TX queues from the peer port RX queues. */ + eth_hairpin_queue_peer_update_t hairpin_queue_peer_update; + /**< Pass the current queue info and get the peer queue info. */ + eth_hairpin_queue_peer_bind_t hairpin_queue_peer_bind; + /**< Set up the connection between the pair of hairpin queues. */ + eth_hairpin_queue_peer_unbind_t hairpin_queue_peer_unbind; + /**< Disconnect the hairpin queues of a pair from each other. */ }; /** @@ -1241,6 +1265,83 @@ typedef int (*ethdev_bus_specific_init)(struct rte_eth_dev *ethdev, int rte_eth_dev_destroy(struct rte_eth_dev *ethdev, ethdev_uninit_t ethdev_uninit); +/** + * @internal + * Pass the current hairpin queue HW and/or SW information to the peer queue + * and fetch back the information of the peer queue. + * + * @param peer_port + * Peer port identifier of the Ethernet device. + * @param peer_queue + * Peer queue index of the port. + * @param cur_info + * Pointer to the current information structure. + * @param peer_info + * Pointer to the peer information, output. + * @param direction + * Direction to pass the information. + * positive - pass TX queue information and get peer RX queue information + * zero - pass RX queue information and get peer TX queue information + * + * @return + * Negative errno value on error, 0 on success. + */ +__rte_internal +int +rte_eth_hairpin_queue_peer_update(uint16_t peer_port, uint16_t peer_queue, + struct rte_hairpin_peer_info *cur_info, + struct rte_hairpin_peer_info *peer_info, + uint32_t direction); + +/** + * @internal + * Configure current hairpin queue with the peer information fetched to create + * the connection (bind) with peer queue in the specified direction. + * This function might need to be called twice to fully create the connections. + * + * @param cur_port + * Current port identifier of the Ethernet device. + * @param cur_queue + * Current queue index of the port. + * @param peer_info + * Pointer to the peer information, input. + * @param direction + * Direction to create the connection. + * positive - bind current TX queue to peer RX queue + * zero - bind current RX queue to peer TX queue + * + * @return + * Negative errno value on error, 0 on success. + */ +__rte_internal +int +rte_eth_hairpin_queue_peer_bind(uint16_t cur_port, uint16_t cur_queue, + struct rte_hairpin_peer_info *peer_info, + uint32_t direction); + +/** + * @internal + * Reset the current queue state and configuration to disconnect (unbind) it + * from the peer queue. + * This function might need to be called twice to disconnect each other. + * + * @param cur_port + * Current port identifier of the Ethernet device. + * @param cur_queue + * Current queue index of the port. + * @param direction + * Direction to destroy the connection. + * positive - unbind current TX queue from peer RX queue + * zero - unbind current RX queue from peer TX queue + * + * @return + * Negative errno value on error, 0 on success. + */ +__rte_internal +int +rte_eth_hairpin_queue_peer_unbind(uint16_t cur_port, uint16_t cur_queue, + uint32_t direction); + #ifdef __cplusplus } #endif diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map index e644391..7402e9a 100644 --- a/lib/librte_ethdev/rte_ethdev_version.map +++ b/lib/librte_ethdev/rte_ethdev_version.map @@ -254,6 +254,9 @@ INTERNAL { rte_eth_devargs_parse; rte_eth_dma_zone_free; rte_eth_dma_zone_reserve; + rte_eth_hairpin_queue_peer_bind; + rte_eth_hairpin_queue_peer_unbind; + rte_eth_hairpin_queue_peer_update; rte_eth_switch_domain_alloc; rte_eth_switch_domain_free; }; From patchwork Thu Oct 15 05:35:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 80831 X-Patchwork-Delegate: ferruh.yigit@amd.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 27717A04DB; Thu, 15 Oct 2020 07:37:08 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 731661DC6D; Thu, 15 Oct 2020 07:36:01 +0200 (CEST) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 4D6BC1DC47 for ; Thu, 15 Oct 2020 07:35:50 +0200 (CEST) From: Bing Zhao To: thomas@monjalon.net, orika@nvidia.com, ferruh.yigit@intel.com, arybchenko@solarflare.com, mdr@ashroe.eu, nhorman@tuxdriver.com, bernard.iremonger@intel.com, beilei.xing@intel.com, wenzhuo.lu@intel.com Cc: dev@dpdk.org Date: Thu, 15 Oct 2020 13:35:24 +0800 Message-Id: <1602740124-397688-6-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1602740124-397688-1-git-send-email-bingz@nvidia.com> References: <1601511962-21532-1-git-send-email-bingz@nvidia.com> <1602740124-397688-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH v5 5/5] app/testpmd: change hairpin queues setup 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" A new parameter `hairpin-mode` is introduced to the testpmd command line. Bitmask value is used to provide a more flexible configuration. This parameter should be used when `hairpinq` is specified in the command line. Bit 0 in the LSB indicates the hairpin will use the loop mode. The previous port RX queue will be connected to the current port TX queue. Bit 1 in the LSB indicates the hairpin will use pair port mode. The even index port will be paired with the next odd index port. If the total number of the probed ports is odd, then the last one will be paired to itself. If this byte is zero, then each port will be paired to itself. Bit 0 takes a higher priority in the checking. Bit 4 in the second bytes indicate if the hairpin will use explicit TX flow mode. e.g. in the command line, "--hairpinq=2 --hairpin-mode=0x11" If not set, default value zero will be used and the behavior will try to get aligned with the previous single port mode. If the ports belong to different vendors' NICs, it is suggested to use the `self` hairpin mode only. Since hairpin configures the hardware resources, the port mask of packets forwarding engine will not be used here. Signed-off-by: Bing Zhao Acked-by: Ori Kam --- v5: add newline character v4: squash testpmd guide update v2: move the hairpin bind/unbind into start/stop to support hot-plug and hot-unplug --- app/test-pmd/parameters.c | 15 ++++ app/test-pmd/testpmd.c | 125 ++++++++++++++++++++++++++++++++-- app/test-pmd/testpmd.h | 2 + doc/guides/testpmd_app_ug/run_app.rst | 8 +++ 4 files changed, 146 insertions(+), 4 deletions(-) diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index 15ce8c1..e231b46 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -222,6 +222,9 @@ "enabled\n"); printf(" --record-core-cycles: enable measurement of CPU cycles.\n"); printf(" --record-burst-stats: enable display of RX and TX bursts.\n"); + printf(" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n " + " 0x10 - explicit tx rule, 0x02 - hairpin ports paired\n" + " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n"); } #ifdef RTE_LIBRTE_CMDLINE @@ -645,6 +648,7 @@ { "rxd", 1, 0, 0 }, { "txd", 1, 0, 0 }, { "hairpinq", 1, 0, 0 }, + { "hairpin-mode", 1, 0, 0 }, { "burst", 1, 0, 0 }, { "mbcache", 1, 0, 0 }, { "txpt", 1, 0, 0 }, @@ -1113,6 +1117,17 @@ rte_exit(EXIT_FAILURE, "Either rx or tx queues should " "be non-zero\n"); } + if (!strcmp(lgopts[opt_idx].name, "hairpin-mode")) { + char *end = NULL; + unsigned int n; + + errno = 0; + n = strtoul(optarg, &end, 0); + if (errno != 0 || end == optarg) + rte_exit(EXIT_FAILURE, "hairpin mode invalid\n"); + else + hairpin_mode = (uint16_t)n; + } if (!strcmp(lgopts[opt_idx].name, "burst")) { n = atoi(optarg); if (n == 0) { diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index ccba71c..6e07162 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -367,6 +367,9 @@ struct fwd_engine * fwd_engines[] = { /* Clear ptypes on port initialization. */ uint8_t clear_ptypes = true; +/* Hairpin ports configuration mode. */ +uint16_t hairpin_mode; + /* Pretty printing of ethdev events */ static const char * const eth_event_desc[] = { [RTE_ETH_EVENT_UNKNOWN] = "unknown", @@ -2345,7 +2348,7 @@ struct extmem_param { /* Configure the Rx and Tx hairpin queues for the selected port. */ static int -setup_hairpin_queues(portid_t pi) +setup_hairpin_queues(portid_t pi, portid_t p_pi, uint16_t cnt_pi) { queueid_t qi; struct rte_eth_hairpin_conf hairpin_conf = { @@ -2354,10 +2357,49 @@ struct extmem_param { int i; int diag; struct rte_port *port = &ports[pi]; + uint16_t peer_rx_port = pi; + uint16_t peer_tx_port = pi; + uint32_t manual = 1; + uint32_t tx_exp = hairpin_mode & 0x10; + + if (!(hairpin_mode & 0xf)) { + peer_rx_port = pi; + peer_tx_port = pi; + manual = 0; + } else if (hairpin_mode & 0x1) { + peer_tx_port = rte_eth_find_next_owned_by(pi + 1, + RTE_ETH_DEV_NO_OWNER); + if (peer_tx_port >= RTE_MAX_ETHPORTS) + peer_tx_port = rte_eth_find_next_owned_by(0, + RTE_ETH_DEV_NO_OWNER); + if (p_pi != RTE_MAX_ETHPORTS) { + peer_rx_port = p_pi; + } else { + uint16_t next_pi; + + /* Last port will be the peer RX port of the first. */ + RTE_ETH_FOREACH_DEV(next_pi) + peer_rx_port = next_pi; + } + manual = 1; + } else if (hairpin_mode & 0x2) { + if (cnt_pi & 0x1) { + peer_rx_port = p_pi; + } else { + peer_rx_port = rte_eth_find_next_owned_by(pi + 1, + RTE_ETH_DEV_NO_OWNER); + if (peer_rx_port >= RTE_MAX_ETHPORTS) + peer_rx_port = pi; + } + peer_tx_port = peer_rx_port; + manual = 1; + } for (qi = nb_txq, i = 0; qi < nb_hairpinq + nb_txq; qi++) { - hairpin_conf.peers[0].port = pi; + hairpin_conf.peers[0].port = peer_rx_port; hairpin_conf.peers[0].queue = i + nb_rxq; + hairpin_conf.manual_bind = !!manual; + hairpin_conf.tx_explicit = !!tx_exp; diag = rte_eth_tx_hairpin_queue_setup (pi, qi, nb_txd, &hairpin_conf); i++; @@ -2377,8 +2419,10 @@ struct extmem_param { return -1; } for (qi = nb_rxq, i = 0; qi < nb_hairpinq + nb_rxq; qi++) { - hairpin_conf.peers[0].port = pi; + hairpin_conf.peers[0].port = peer_tx_port; hairpin_conf.peers[0].queue = i + nb_txq; + hairpin_conf.manual_bind = !!manual; + hairpin_conf.tx_explicit = !!tx_exp; diag = rte_eth_rx_hairpin_queue_setup (pi, qi, nb_rxd, &hairpin_conf); i++; @@ -2405,6 +2449,12 @@ struct extmem_param { { int diag, need_check_link_status = -1; portid_t pi; + portid_t p_pi = RTE_MAX_ETHPORTS; + portid_t pl[RTE_MAX_ETHPORTS]; + portid_t peer_pl[RTE_MAX_ETHPORTS]; + uint16_t cnt_pi = 0; + uint16_t cfg_pi = 0; + int peer_pi; queueid_t qi; struct rte_port *port; struct rte_ether_addr mac_addr; @@ -2544,7 +2594,7 @@ struct extmem_param { return -1; } /* setup hairpin queues */ - if (setup_hairpin_queues(pi) != 0) + if (setup_hairpin_queues(pi, p_pi, cnt_pi) != 0) return -1; } configure_rxtx_dump_callbacks(verbose_level); @@ -2557,6 +2607,9 @@ struct extmem_param { pi); } + p_pi = pi; + cnt_pi++; + /* start port */ if (rte_eth_dev_start(pi) < 0) { printf("Fail to start port %d\n", pi); @@ -2581,6 +2634,8 @@ struct extmem_param { /* at least one port started, need checking link status */ need_check_link_status = 1; + + pl[cfg_pi++] = pi; } if (need_check_link_status == 1 && !no_link_check) @@ -2588,6 +2643,50 @@ struct extmem_param { else if (need_check_link_status == 0) printf("Please stop the ports first\n"); + if (hairpin_mode & 0xf) { + uint16_t i; + int j; + + /* bind all started hairpin ports */ + for (i = 0; i < cfg_pi; i++) { + pi = pl[i]; + /* bind current TX to all peer RX */ + peer_pi = rte_eth_hairpin_get_peer_ports(pi, peer_pl, + RTE_MAX_ETHPORTS, 1); + if (peer_pi < 0) + return peer_pi; + for (j = 0; j < peer_pi; j++) { + if (!port_is_started(peer_pl[j])) + continue; + diag = rte_eth_hairpin_bind(pi, peer_pl[j]); + if (diag < 0) { + printf("Error during binding " + "hairpin tx port %u to %u: %s\n", + pi, peer_pl[j], + rte_strerror(-diag)); + return -1; + } + } + /* bind all peer TX to current RX */ + peer_pi = rte_eth_hairpin_get_peer_ports(pi, peer_pl, + RTE_MAX_ETHPORTS, 0); + if (peer_pi < 0) + return peer_pi; + for (j = 0; j < peer_pi; j++) { + if (!port_is_started(peer_pl[j])) + continue; + diag = rte_eth_hairpin_bind(peer_pl[j], pi); + if (diag < 0) { + printf("Error during binding " + "hairpin tx port %u to %u: %s\n", + peer_pl[j], pi, + rte_strerror(-diag)); + return -1; + } + } + } + } + printf("Done\n"); return 0; } @@ -2598,6 +2697,8 @@ struct extmem_param { portid_t pi; struct rte_port *port; int need_check_link_status = 0; + portid_t peer_pl[RTE_MAX_ETHPORTS]; + int peer_pi; if (dcb_test) { dcb_test = 0; @@ -2628,6 +2729,22 @@ struct extmem_param { RTE_PORT_HANDLING) == 0) continue; + if (hairpin_mode & 0xf) { + int j; + + rte_eth_hairpin_unbind(pi, RTE_MAX_ETHPORTS); + /* unbind all peer TX from current RX */ + peer_pi = rte_eth_hairpin_get_peer_ports(pi, peer_pl, + RTE_MAX_ETHPORTS, 0); + if (peer_pi < 0) + continue; + for (j = 0; j < peer_pi; j++) { + if (!port_is_started(peer_pl[j])) + continue; + rte_eth_hairpin_unbind(peer_pl[j], pi); + } + } + rte_eth_dev_stop(pi); if (rte_atomic16_cmpset(&(port->port_status), diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 9a29d7a..f2b604c 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -398,6 +398,8 @@ struct queue_stats_mappings { extern uint16_t stats_period; +extern uint16_t hairpin_mode; + #ifdef RTE_LIBRTE_LATENCY_STATS extern uint8_t latencystats_enabled; extern lcoreid_t latencystats_lcore_id; diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst index ec085c2..b5f5b98 100644 --- a/doc/guides/testpmd_app_ug/run_app.rst +++ b/doc/guides/testpmd_app_ug/run_app.rst @@ -503,3 +503,11 @@ The command line options are: * ``--record-burst-stats`` Enable display of RX and TX burst stats. + +* ``--hairpin-mode=0xXX`` + + Set the hairpin port mode with bitmask, only valid when hairpin queues number is set. + bit 4 - explicit TX flow rule + bit 1 - two hairpin ports paired + bit 0 - two hairpin ports loop + The default value is 0. Hairpin will use single port mode and implicit TX flow mode.