From patchwork Thu Oct 1 00:25:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 79389 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 3D607A04B5; Thu, 1 Oct 2020 02:26:38 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id AD1881D5E3; Thu, 1 Oct 2020 02:26:27 +0200 (CEST) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id AD0221D5D9 for ; Thu, 1 Oct 2020 02:26:24 +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, 1 Oct 2020 08:25:59 +0800 Message-Id: <1601511962-21532-2-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1601511962-21532-1-git-send-email-bingz@nvidia.com> References: <1600012140-70151-1-git-send-email-bingz@nvidia.com> <1601511962-21532-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH 1/4] 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. Signed-off-by: Bing Zhao --- lib/librte_ethdev/rte_ethdev.c | 107 +++++++++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev.h | 51 +++++++++++++++ lib/librte_ethdev/rte_ethdev_driver.h | 52 +++++++++++++++ lib/librte_ethdev/rte_ethdev_version.map | 2 + 4 files changed, 212 insertions(+) diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c index dfe5c1b..72f567b 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -2175,6 +2175,113 @@ rte_eth_tx_hairpin_queue_setup(uint16_t port_id, uint16_t tx_queue_id, return eth_err(port_id, ret); } +int +rte_eth_hairpin_bind(uint16_t tx_port, uint16_t rx_port) +{ + struct rte_eth_dev *dev; + struct rte_eth_dev *rdev; + uint16_t p; + uint16_t rp; + int ret = 0; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(tx_port, -EINVAL); + dev = &rte_eth_devices[tx_port]; + if (!dev->data->dev_started) { + RTE_ETHDEV_LOG(ERR, "TX port %d is not started", tx_port); + return -EBUSY; + } + + /* + * If the all the ports probed belong to two or more separate NICs, it + * is recommended that each pair is bound independently but not in the + * loop to bind all ports. + */ + if (rx_port == RTE_MAX_ETHPORTS) { + RTE_ETH_FOREACH_DEV(p) { + rdev = &rte_eth_devices[p]; + if (!rdev->data->dev_started) { + RTE_ETHDEV_LOG(ERR, + "RX port %d is not started", p); + ret = -EBUSY; + goto unbind; + } + ret = (*dev->dev_ops->hairpin_bind)(dev, p); + if (ret) { + RTE_ETHDEV_LOG(ERR, "Failed to bind hairpin TX " + "%d to RX %d", tx_port, p); + goto unbind; + } + } + } else { + RTE_ETH_VALID_PORTID_OR_ERR_RET(rx_port, -EINVAL); + rdev = &rte_eth_devices[rx_port]; + if (!rdev->data->dev_started) { + RTE_ETHDEV_LOG(ERR, + "RX port %d is not started", rx_port); + return -EBUSY; + } + ret = (*dev->dev_ops->hairpin_bind)(dev, rx_port); + if (ret) + RTE_ETHDEV_LOG(ERR, "Failed to bind hairpin TX %d " + "to RX %d", tx_port, rx_port); + } + + return ret; + +unbind: + /* Roll back the previous binding process. */ + RTE_ETH_FOREACH_DEV(rp) { + if (rp < p) + (*dev->dev_ops->hairpin_unbind)(dev, rp); + else + break; + } + return ret; +} + +int +rte_eth_hairpin_unbind(uint16_t tx_port, uint16_t rx_port) +{ + struct rte_eth_dev *dev; + struct rte_eth_dev *rdev; + uint16_t p; + int ret = 0; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(tx_port, -EINVAL); + dev = &rte_eth_devices[tx_port]; + if (!dev->data->dev_started) { + RTE_ETHDEV_LOG(ERR, "TX port %d is stopped", tx_port); + return -EBUSY; + } + + if (rx_port == RTE_MAX_ETHPORTS) { + RTE_ETH_FOREACH_DEV(p) { + rdev = &rte_eth_devices[p]; + if (!rdev->data->dev_started) { + RTE_ETHDEV_LOG(ERR, "RX port %d is stopped", p); + ret = -EBUSY; + break; + } + ret = (*dev->dev_ops->hairpin_unbind)(dev, p); + if (ret) { + RTE_ETHDEV_LOG(ERR, "Failed to unbind hairpin " + "TX %d from RX %d", tx_port, p); + break; + } + } + } else { + RTE_ETH_VALID_PORTID_OR_ERR_RET(rx_port, -EINVAL); + rdev = &rte_eth_devices[rx_port]; + if (!rdev->data->dev_started) { + RTE_ETHDEV_LOG(ERR, "RX port %d is stopped", rx_port); + return -EBUSY; + } + ret = (*dev->dev_ops->hairpin_unbind)(dev, rx_port); + } + + 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 645a186..c3fb684 100644 --- a/lib/librte_ethdev/rte_ethdev.h +++ b/lib/librte_ethdev/rte_ethdev.h @@ -2133,6 +2133,57 @@ int rte_eth_tx_hairpin_queue_setup 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 API after all hairpin queues are configured + * properly and the devices of TX and peer RX are in started state. + * + * @param tx_port + * The TX port identifier of the Ethernet device. + * @param rx_port + * The peer RX port identifier of the Ethernet device. + * RTE_MAX_ETHPORTS is allowed for the traversal of all devices. + * RX port ID could have the same value with TX port ID. + * + * @return + * - (0) if successful. + * - (-EINVAL) if bad parameter. + * - (-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 (optional). After + * unbind the hairpin ports pair, it is allowed to bind them again. + * Changing queues configuration should be after stopping the device. + * + * @param tx_port + * The TX port identifier of the Ethernet device. + * @param rx_port + * The peer RX port identifier of the Ethernet device. + * RTE_MAX_ETHPORTS is allowed for traversal of all devices. + * RX port ID could have the same value with TX port ID. + * + * @return + * - (0) if successful. + * - (-EINVAL) if bad parameter. + * - (-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 04ac8e9..910433f 100644 --- a/lib/librte_ethdev/rte_ethdev_driver.h +++ b/lib/librte_ethdev/rte_ethdev_driver.h @@ -575,6 +575,54 @@ typedef int (*eth_tx_hairpin_queue_setup_t) const struct rte_eth_hairpin_conf *hairpin_conf); /** + * @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, bind 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 { @@ -713,6 +761,10 @@ struct eth_dev_ops { /**< Set up device RX hairpin queue. */ eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup; /**< Set up device TX hairpin queue. */ + 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 c95ef51..18efe4e 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; }; From patchwork Thu Oct 1 00:26:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 79390 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 47783A04B5; Thu, 1 Oct 2020 02:27:03 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 9A5061D615; Thu, 1 Oct 2020 02:26:30 +0200 (CEST) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id A6C131D5F5 for ; Thu, 1 Oct 2020 02:26:28 +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, 1 Oct 2020 08:26:00 +0800 Message-Id: <1601511962-21532-3-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1601511962-21532-1-git-send-email-bingz@nvidia.com> References: <1600012140-70151-1-git-send-email-bingz@nvidia.com> <1601511962-21532-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH 2/4] 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 hairpin queue config structure are 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 device start stage. Different TX and RX queue pairs could have different values, but it is highly recommend 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 driver. In a single port hairpin, if both are zero without any setting, the behavior will remain the same as before. It means 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 --- lib/librte_ethdev/rte_ethdev.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index c3fb684..0cabff0 100644 --- a/lib/librte_ethdev/rte_ethdev.h +++ b/lib/librte_ethdev/rte_ethdev.h @@ -1027,6 +1027,21 @@ struct rte_eth_hairpin_cap { #define RTE_ETH_MAX_HAIRPIN_PEERS 32 +/* + * Hairpin queue attribute parameters. + * Each TX queue and peer RX queue should have the same value. + * Default value 0 is for backward-compatibility, the same behaviors should + * remain if the value is not set (0). + */ +/**< Hairpin queues will be bound automatically */ +#define RTE_ETH_HAIRPIN_BIND_AUTO (0) +/**< Hairpin queues will be bound manually with bind API */ +#define RTE_ETH_HAIRPIN_BIND_MANUAL (1) +/**< Hairpin TX part flow rule will be inserted implicitly by PMD */ +#define RTE_ETH_HAIRPIN_TXRULE_IMPLICIT (0) +/**< Hairpin TX part flow rule will be inserted explicitly by APP */ +#define RTE_ETH_HAIRPIN_TXRULE_EXPLICIT (1) + /** * @warning * @b EXPERIMENTAL: this API may change, or be removed, without prior notice @@ -1046,6 +1061,9 @@ struct rte_eth_hairpin_peer { */ struct rte_eth_hairpin_conf { uint16_t peer_count; /**< The number of peers. */ + uint32_t reserved : 30; /**< Reserved bits. */ + uint32_t tx_explicit : 1; /**< Explicit TX flow rule mode. */ + uint32_t manual_bind : 1; /**< Manually bind hairpin queues. */ struct rte_eth_hairpin_peer peers[RTE_ETH_MAX_HAIRPIN_PEERS]; }; From patchwork Thu Oct 1 00:26:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 79391 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 43363A04B5; Thu, 1 Oct 2020 02:27:21 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id AB5FC1D629; Thu, 1 Oct 2020 02:26:34 +0200 (CEST) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 49C8B1D625 for ; Thu, 1 Oct 2020 02:26:32 +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, 1 Oct 2020 08:26:01 +0800 Message-Id: <1601511962-21532-4-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1601511962-21532-1-git-send-email-bingz@nvidia.com> References: <1600012140-70151-1-git-send-email-bingz@nvidia.com> <1601511962-21532-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH 3/4] 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 configuraion 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 --- lib/librte_ethdev/rte_ethdev.c | 55 ++++++++++++++++ lib/librte_ethdev/rte_ethdev_driver.h | 108 +++++++++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_version.map | 3 + 3 files changed, 166 insertions(+) diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c index 72f567b..4bfc26e 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -5515,6 +5515,61 @@ handle_port_link_status(const char *cmd __rte_unused, 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, + bool 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, + bool 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, + bool 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_bind, + -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 910433f..d759c58 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* @@ -622,6 +625,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, bool 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, bool 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, bool direction); +/**< @internal Unbind peer queue from the current queue. */ + /** * @internal A structure containing the functions exported by an Ethernet driver. */ @@ -765,6 +783,9 @@ 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; + eth_hairpin_queue_peer_bind_t hairpin_queue_peer_bind; + eth_hairpin_queue_peer_unbind_t hairpin_queue_peer_unbind; }; /** @@ -1120,6 +1141,93 @@ __rte_internal int rte_eth_dev_destroy(struct rte_eth_dev *ethdev, ethdev_uninit_t ethdev_uninit); +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * @internal + * Pass the current hairpin queue HW and/or HW 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. + * true - pass TX queue information and get peer RX queue information + * false - 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, + bool direction); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * @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 connection. + * + * @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. + * true - bind current TX queue to peer RX queue + * false - 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, + bool direction); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * @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 create the connection. + * true - unbind current TX queue from peer RX queue + * false - 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, + bool direction); + + #ifdef __cplusplus } #endif diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map index 18efe4e..d05cd97 100644 --- a/lib/librte_ethdev/rte_ethdev_version.map +++ b/lib/librte_ethdev/rte_ethdev_version.map @@ -250,6 +250,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; rte_flow_expand_rss; From patchwork Thu Oct 1 00:26:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bing Zhao X-Patchwork-Id: 79392 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 5B7E5A04B5; Thu, 1 Oct 2020 02:27:39 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 30C391D64A; Thu, 1 Oct 2020 02:26:38 +0200 (CEST) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 228A41D5F8 for ; Thu, 1 Oct 2020 02:26:36 +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, 1 Oct 2020 08:26:02 +0800 Message-Id: <1601511962-21532-5-git-send-email-bingz@nvidia.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1601511962-21532-1-git-send-email-bingz@nvidia.com> References: <1600012140-70151-1-git-send-email-bingz@nvidia.com> <1601511962-21532-1-git-send-email-bingz@nvidia.com> Subject: [dpdk-dev] [PATCH 4/4] 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 more flexible configuration. 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 probed port 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. If not set, default value zero will be used and the behavior will try to get align 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 --- app/test-pmd/parameters.c | 15 +++++++++++ app/test-pmd/testpmd.c | 68 ++++++++++++++++++++++++++++++++++++++++++++--- app/test-pmd/testpmd.h | 2 ++ 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index 1ead595..991029d 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -221,6 +221,9 @@ usage(char* progname) "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 @@ -644,6 +647,7 @@ launch_args_parse(int argc, char** argv) { "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 }, @@ -1111,6 +1115,17 @@ launch_args_parse(int argc, char** argv) 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 fe6450c..c604045 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -367,6 +367,9 @@ bool setup_on_probe_event = true; /* 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 @@ port_is_started(portid_t port_id) /* 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,48 @@ setup_hairpin_queues(portid_t pi) 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; + + 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 +2418,10 @@ setup_hairpin_queues(portid_t pi) 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 +2448,8 @@ start_port(portid_t pid) { int diag, need_check_link_status = -1; portid_t pi; + portid_t p_pi = RTE_MAX_ETHPORTS; + uint16_t cnt_pi = 0; queueid_t qi; struct rte_port *port; struct rte_ether_addr mac_addr; @@ -2544,8 +2589,10 @@ start_port(portid_t pid) return -1; } /* setup hairpin queues */ - if (setup_hairpin_queues(pi) != 0) + if (setup_hairpin_queues(pi, p_pi, cnt_pi) != 0) return -1; + p_pi = pi; + cnt_pi++; } configure_rxtx_dump_callbacks(verbose_level); if (clear_ptypes) { @@ -3775,6 +3822,19 @@ main(int argc, char** argv) rte_exit(EXIT_FAILURE, "Start ports failed\n"); /* set all ports to promiscuous mode by default */ + if (hairpin_mode & 0x3) { + RTE_ETH_FOREACH_DEV(port_id) { + ret = rte_eth_hairpin_bind(port_id, RTE_MAX_ETHPORTS); + if (ret != 0) { + RTE_LOG(ERR, EAL, "Error during binding " + "hairpin tx port %u: %s", + port_id, rte_strerror(-ret)); + return -1; + } + } + } + + /* set all ports to promiscuous mode by default */ RTE_ETH_FOREACH_DEV(port_id) { ret = rte_eth_promiscuous_enable(port_id); if (ret != 0) diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index c7e7e41..29ede20 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -398,6 +398,8 @@ extern uint32_t param_total_num_mbufs; 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;