diff --git a/doc/guides/rel_notes/release_19_11.rst b/doc/guides/rel_notes/release_19_11.rst index 795c7601c0..ccbdca1c5e 100644 --- a/doc/guides/rel_notes/release_19_11.rst +++ b/doc/guides/rel_notes/release_19_11.rst @@ -77,6 +77,11 @@ New Features for specific offload features, where adding a static field or flag in the mbuf is not justified. +* **Added hairpin queue.** + + On supported NICs, we can now setup haipin queue which will offload packets + from the wire, backto the wire. + * **Updated the enic driver.** * Added support for Geneve with options offload. diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c index 7743205d38..4c6725f69f 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -923,6 +923,13 @@ rte_eth_dev_rx_queue_start(uint16_t port_id, uint16_t rx_queue_id) RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rx_queue_start, -ENOTSUP); + if (rte_eth_dev_is_rx_hairpin_queue(dev, rx_queue_id)) { + RTE_ETHDEV_LOG(INFO, + "Can't start Rx hairpin queue %"PRIu16" of device with port_id=%"PRIu16"\n", + rx_queue_id, port_id); + return -EINVAL; + } + if (dev->data->rx_queue_state[rx_queue_id] != RTE_ETH_QUEUE_STATE_STOPPED) { RTE_ETHDEV_LOG(INFO, "Queue %"PRIu16" of device with port_id=%"PRIu16" already started\n", @@ -950,6 +957,13 @@ rte_eth_dev_rx_queue_stop(uint16_t port_id, uint16_t rx_queue_id) RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rx_queue_stop, -ENOTSUP); + if (rte_eth_dev_is_rx_hairpin_queue(dev, rx_queue_id)) { + RTE_ETHDEV_LOG(INFO, + "Can't stop Rx hairpin queue %"PRIu16" of device with port_id=%"PRIu16"\n", + rx_queue_id, port_id); + return -EINVAL; + } + if (dev->data->rx_queue_state[rx_queue_id] == RTE_ETH_QUEUE_STATE_STOPPED) { RTE_ETHDEV_LOG(INFO, "Queue %"PRIu16" of device with port_id=%"PRIu16" already stopped\n", @@ -983,6 +997,13 @@ rte_eth_dev_tx_queue_start(uint16_t port_id, uint16_t tx_queue_id) RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->tx_queue_start, -ENOTSUP); + if (rte_eth_dev_is_tx_hairpin_queue(dev, tx_queue_id)) { + RTE_ETHDEV_LOG(INFO, + "Can't start Tx hairpin queue %"PRIu16" of device with port_id=%"PRIu16"\n", + tx_queue_id, port_id); + return -EINVAL; + } + if (dev->data->tx_queue_state[tx_queue_id] != RTE_ETH_QUEUE_STATE_STOPPED) { RTE_ETHDEV_LOG(INFO, "Queue %"PRIu16" of device with port_id=%"PRIu16" already started\n", @@ -1008,6 +1029,13 @@ rte_eth_dev_tx_queue_stop(uint16_t port_id, uint16_t tx_queue_id) RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->tx_queue_stop, -ENOTSUP); + if (rte_eth_dev_is_tx_hairpin_queue(dev, tx_queue_id)) { + RTE_ETHDEV_LOG(INFO, + "Can't stop Tx hairpin queue %"PRIu16" of device with port_id=%"PRIu16"\n", + tx_queue_id, port_id); + return -EINVAL; + } + if (dev->data->tx_queue_state[tx_queue_id] == RTE_ETH_QUEUE_STATE_STOPPED) { RTE_ETHDEV_LOG(INFO, "Queue %"PRIu16" of device with port_id=%"PRIu16" already stopped\n", @@ -1779,6 +1807,78 @@ rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id, return eth_err(port_id, ret); } +int +rte_eth_rx_hairpin_queue_setup(uint16_t port_id, uint16_t rx_queue_id, + uint16_t nb_rx_desc, + const struct rte_eth_hairpin_conf *conf) +{ + int ret; + struct rte_eth_dev *dev; + struct rte_eth_hairpin_cap cap; + void **rxq; + int i; + int count; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL); + + dev = &rte_eth_devices[port_id]; + if (rx_queue_id >= dev->data->nb_rx_queues) { + RTE_ETHDEV_LOG(ERR, "Invalid RX queue_id=%u\n", rx_queue_id); + return -EINVAL; + } + ret = rte_eth_dev_hairpin_capability_get(port_id, &cap); + if (ret != 0) + return ret; + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rx_hairpin_queue_setup, + -ENOTSUP); + /* if nb_rx_desc is zero use max number of desc from the driver. */ + if (nb_rx_desc == 0) + nb_rx_desc = cap.max_nb_desc; + if (nb_rx_desc > cap.max_nb_desc) { + RTE_ETHDEV_LOG(ERR, + "Invalid value for nb_rx_desc(=%hu), should be: <= %hu", + nb_rx_desc, cap.max_nb_desc); + return -EINVAL; + } + 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", + 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", + conf->peer_count); + return -EINVAL; + } + for (i = 0, count = 0; i < dev->data->nb_rx_queues && + cap.max_nb_queues != UINT16_MAX; i++) { + if (i == rx_queue_id || rte_eth_dev_is_rx_hairpin_queue(dev, i)) + count++; + } + if (count > cap.max_nb_queues) { + RTE_ETHDEV_LOG(ERR, "To many Rx hairpin queues max is %d", + cap.max_nb_queues); + return -EINVAL; + } + if (dev->data->dev_started) + return -EBUSY; + rxq = dev->data->rx_queues; + if (rxq[rx_queue_id] != NULL) { + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rx_queue_release, + -ENOTSUP); + (*dev->dev_ops->rx_queue_release)(rxq[rx_queue_id]); + rxq[rx_queue_id] = NULL; + } + ret = (*dev->dev_ops->rx_hairpin_queue_setup)(dev, rx_queue_id, + nb_rx_desc, conf); + if (ret == 0) + dev->data->rx_queue_state[rx_queue_id] = + RTE_ETH_QUEUE_STATE_HAIRPIN; + return eth_err(port_id, ret); +} + int rte_eth_tx_queue_setup(uint16_t port_id, uint16_t tx_queue_id, uint16_t nb_tx_desc, unsigned int socket_id, @@ -1878,6 +1978,77 @@ rte_eth_tx_queue_setup(uint16_t port_id, uint16_t tx_queue_id, tx_queue_id, nb_tx_desc, socket_id, &local_conf)); } +int +rte_eth_tx_hairpin_queue_setup(uint16_t port_id, uint16_t tx_queue_id, + uint16_t nb_tx_desc, + const struct rte_eth_hairpin_conf *conf) +{ + struct rte_eth_dev *dev; + struct rte_eth_hairpin_cap cap; + void **txq; + int i; + int count; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL); + dev = &rte_eth_devices[port_id]; + if (tx_queue_id >= dev->data->nb_tx_queues) { + RTE_ETHDEV_LOG(ERR, "Invalid TX queue_id=%u\n", tx_queue_id); + return -EINVAL; + } + ret = rte_eth_dev_hairpin_capability_get(port_id, &cap); + if (ret != 0) + return ret; + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->tx_hairpin_queue_setup, + -ENOTSUP); + /* if nb_rx_desc is zero use max number of desc from the driver. */ + if (nb_tx_desc == 0) + nb_tx_desc = cap.max_nb_desc; + if (nb_tx_desc > cap.max_nb_desc) { + RTE_ETHDEV_LOG(ERR, + "Invalid value for nb_tx_desc(=%hu), should be: <= %hu", + nb_tx_desc, cap.max_nb_desc); + return -EINVAL; + } + 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", + 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", + conf->peer_count); + return -EINVAL; + } + for (i = 0, count = 0; i < dev->data->nb_tx_queues && + cap.max_nb_queues != UINT16_MAX; i++) { + if (i == tx_queue_id || rte_eth_dev_is_tx_hairpin_queue(dev, i)) + count++; + } + if (count > cap.max_nb_queues) { + RTE_ETHDEV_LOG(ERR, "To many Tx hairpin queues max is %d", + cap.max_nb_queues); + return -EINVAL; + } + if (dev->data->dev_started) + return -EBUSY; + txq = dev->data->tx_queues; + if (txq[tx_queue_id] != NULL) { + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->tx_queue_release, + -ENOTSUP); + (*dev->dev_ops->tx_queue_release)(txq[tx_queue_id]); + txq[tx_queue_id] = NULL; + } + ret = (*dev->dev_ops->tx_hairpin_queue_setup) + (dev, tx_queue_id, nb_tx_desc, conf); + if (ret == 0) + dev->data->tx_queue_state[tx_queue_id] = + RTE_ETH_QUEUE_STATE_HAIRPIN; + return eth_err(port_id, ret); +} + void rte_eth_tx_buffer_drop_callback(struct rte_mbuf **pkts, uint16_t unsent, void *userdata __rte_unused) @@ -4007,12 +4178,19 @@ rte_eth_add_rx_callback(uint16_t port_id, uint16_t queue_id, rte_errno = ENOTSUP; return NULL; #endif + struct rte_eth_dev *dev; + /* check input parameters */ if (!rte_eth_dev_is_valid_port(port_id) || fn == NULL || queue_id >= rte_eth_devices[port_id].data->nb_rx_queues) { rte_errno = EINVAL; return NULL; } + dev = &rte_eth_devices[port_id]; + if (rte_eth_dev_is_rx_hairpin_queue(dev, queue_id)) { + rte_errno = EINVAL; + return NULL; + } struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0); if (cb == NULL) { @@ -4084,6 +4262,8 @@ rte_eth_add_tx_callback(uint16_t port_id, uint16_t queue_id, rte_errno = ENOTSUP; return NULL; #endif + struct rte_eth_dev *dev; + /* check input parameters */ if (!rte_eth_dev_is_valid_port(port_id) || fn == NULL || queue_id >= rte_eth_devices[port_id].data->nb_tx_queues) { @@ -4091,6 +4271,12 @@ rte_eth_add_tx_callback(uint16_t port_id, uint16_t queue_id, return NULL; } + dev = &rte_eth_devices[port_id]; + if (rte_eth_dev_is_tx_hairpin_queue(dev, queue_id)) { + rte_errno = EINVAL; + return NULL; + } + struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0); if (cb == NULL) { @@ -4204,6 +4390,13 @@ rte_eth_rx_queue_info_get(uint16_t port_id, uint16_t queue_id, return -EINVAL; } + if (rte_eth_dev_is_rx_hairpin_queue(dev, queue_id)) { + RTE_ETHDEV_LOG(INFO, + "Can't get hairpin Rx queue %"PRIu16" info of device with port_id=%"PRIu16"\n", + queue_id, port_id); + return -EINVAL; + } + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rxq_info_get, -ENOTSUP); memset(qinfo, 0, sizeof(*qinfo)); @@ -4228,6 +4421,13 @@ rte_eth_tx_queue_info_get(uint16_t port_id, uint16_t queue_id, return -EINVAL; } + if (rte_eth_dev_is_tx_hairpin_queue(dev, queue_id)) { + RTE_ETHDEV_LOG(INFO, + "Can't get hairpin Tx queue %"PRIu16" info of device with port_id=%"PRIu16"\n", + queue_id, port_id); + return -EINVAL; + } + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->txq_info_get, -ENOTSUP); memset(qinfo, 0, sizeof(*qinfo)); @@ -4599,6 +4799,38 @@ rte_eth_dev_adjust_nb_rx_tx_desc(uint16_t port_id, return 0; } +int +rte_eth_dev_hairpin_capability_get(uint16_t port_id, + struct rte_eth_hairpin_cap *cap) +{ + struct rte_eth_dev *dev; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL); + + dev = &rte_eth_devices[port_id]; + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->hairpin_cap_get, -ENOTSUP); + memset(cap, 0, sizeof(*cap)); + return eth_err(port_id, (*dev->dev_ops->hairpin_cap_get)(dev, cap)); +} + +int +rte_eth_dev_is_rx_hairpin_queue(struct rte_eth_dev *dev, uint16_t queue_id) +{ + if (dev->data->rx_queue_state[queue_id] == + RTE_ETH_QUEUE_STATE_HAIRPIN) + return 1; + return 0; +} + +int +rte_eth_dev_is_tx_hairpin_queue(struct rte_eth_dev *dev, uint16_t queue_id) +{ + if (dev->data->tx_queue_state[queue_id] == + RTE_ETH_QUEUE_STATE_HAIRPIN) + return 1; + return 0; +} + int rte_eth_dev_pool_ops_supported(uint16_t port_id, const char *pool) { diff --git a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index 9e1f9ae76d..bca029c224 100644 --- a/lib/librte_ethdev/rte_ethdev.h +++ b/lib/librte_ethdev/rte_ethdev.h @@ -838,6 +838,46 @@ struct rte_eth_txconf { uint64_t offloads; }; +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * A structure used to return the hairpin capabilities that are supported. + */ +struct rte_eth_hairpin_cap { + /** The max number of hairpin queues (different bindings). */ + uint16_t max_nb_queues; + /** Max number of Rx queues to be connected to one Tx queue. */ + uint16_t max_rx_2_tx; + /** Max number of Tx queues to be connected to one Rx queue. */ + uint16_t max_tx_2_rx; + uint16_t max_nb_desc; /**< The max num of descriptors. */ +}; + +#define RTE_ETH_MAX_HAIRPIN_PEERS 32 + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * A structure used to hold hairpin peer data. + */ +struct rte_eth_hairpin_peer { + uint16_t port; /**< Peer port. */ + uint16_t queue; /**< Peer queue. */ +}; + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * A structure used to configure hairpin binding. + */ +struct rte_eth_hairpin_conf { + uint16_t peer_count; /**< The number of peers. */ + struct rte_eth_hairpin_peer peers[RTE_ETH_MAX_HAIRPIN_PEERS]; +}; + /** * A structure contains information about HW descriptor ring limitations. */ @@ -1828,6 +1868,37 @@ int rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id, const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool); +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Allocate and set up a hairpin receive queue for an Ethernet device. + * + * The function set up the selected queue to be used in hairpin. + * + * @param port_id + * The port identifier of the Ethernet device. + * @param rx_queue_id + * The index of the receive queue to set up. + * The value must be in the range [0, nb_rx_queue - 1] previously supplied + * to rte_eth_dev_configure(). + * @param nb_rx_desc + * The number of receive descriptors to allocate for the receive ring. + * 0 means the PMD will use default value. + * @param conf + * The pointer to the hairpin configuration. + * + * @return + * - (0) if successful. + * - (-ENOTSUP) if hardware doesn't support. + * - (-EINVAL) if bad parameter. + * - (-ENOMEM) if unable to allocate the resources. + */ +__rte_experimental +int rte_eth_rx_hairpin_queue_setup + (uint16_t port_id, uint16_t rx_queue_id, uint16_t nb_rx_desc, + const struct rte_eth_hairpin_conf *conf); + /** * Allocate and set up a transmit queue for an Ethernet device. * @@ -1880,6 +1951,35 @@ int rte_eth_tx_queue_setup(uint16_t port_id, uint16_t tx_queue_id, uint16_t nb_tx_desc, unsigned int socket_id, const struct rte_eth_txconf *tx_conf); +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Allocate and set up a transmit hairpin queue for an Ethernet device. + * + * @param port_id + * The port identifier of the Ethernet device. + * @param tx_queue_id + * The index of the transmit queue to set up. + * The value must be in the range [0, nb_tx_queue - 1] previously supplied + * to rte_eth_dev_configure(). + * @param nb_tx_desc + * The number of transmit descriptors to allocate for the transmit ring. + * 0 to set default PMD value. + * @param conf + * The hairpin configuration. + * + * @return + * - (0) if successful. + * - (-ENOTSUP) if hardware doesn't support. + * - (-EINVAL) if bad parameter. + * - (-ENOMEM) if unable to allocate the resources. + */ +__rte_experimental +int rte_eth_tx_hairpin_queue_setup + (uint16_t port_id, uint16_t tx_queue_id, uint16_t nb_tx_desc, + const struct rte_eth_hairpin_conf *conf); + /** * Return the NUMA socket to which an Ethernet device is connected * @@ -1915,7 +2015,7 @@ int rte_eth_dev_is_valid_port(uint16_t port_id); * to rte_eth_dev_configure(). * @return * - 0: Success, the receive queue is started. - * - -EINVAL: The port_id or the queue_id out of range. + * - -EINVAL: The port_id or the queue_id out of range or belong to hairpin. * - -EIO: if device is removed. * - -ENOTSUP: The function not supported in PMD driver. */ @@ -1932,7 +2032,7 @@ int rte_eth_dev_rx_queue_start(uint16_t port_id, uint16_t rx_queue_id); * to rte_eth_dev_configure(). * @return * - 0: Success, the receive queue is stopped. - * - -EINVAL: The port_id or the queue_id out of range. + * - -EINVAL: The port_id or the queue_id out of range or belong to hairpin. * - -EIO: if device is removed. * - -ENOTSUP: The function not supported in PMD driver. */ @@ -1950,7 +2050,7 @@ int rte_eth_dev_rx_queue_stop(uint16_t port_id, uint16_t rx_queue_id); * to rte_eth_dev_configure(). * @return * - 0: Success, the transmit queue is started. - * - -EINVAL: The port_id or the queue_id out of range. + * - -EINVAL: The port_id or the queue_id out of range or belong to hairpin. * - -EIO: if device is removed. * - -ENOTSUP: The function not supported in PMD driver. */ @@ -1967,7 +2067,7 @@ int rte_eth_dev_tx_queue_start(uint16_t port_id, uint16_t tx_queue_id); * to rte_eth_dev_configure(). * @return * - 0: Success, the transmit queue is stopped. - * - -EINVAL: The port_id or the queue_id out of range. + * - -EINVAL: The port_id or the queue_id out of range or belong to hairpin. * - -EIO: if device is removed. * - -ENOTSUP: The function not supported in PMD driver. */ @@ -3633,7 +3733,8 @@ int rte_eth_remove_tx_callback(uint16_t port_id, uint16_t queue_id, * @return * - 0: Success * - -ENOTSUP: routine is not supported by the device PMD. - * - -EINVAL: The port_id or the queue_id is out of range. + * - -EINVAL: The port_id or the queue_id is out of range, or the queue + * is hairpin queue. */ int rte_eth_rx_queue_info_get(uint16_t port_id, uint16_t queue_id, struct rte_eth_rxq_info *qinfo); @@ -3653,7 +3754,8 @@ int rte_eth_rx_queue_info_get(uint16_t port_id, uint16_t queue_id, * @return * - 0: Success * - -ENOTSUP: routine is not supported by the device PMD. - * - -EINVAL: The port_id or the queue_id is out of range. + * - -EINVAL: The port_id or the queue_id is out of range, or the queue + * is hairpin queue. */ int rte_eth_tx_queue_info_get(uint16_t port_id, uint16_t queue_id, struct rte_eth_txq_info *qinfo); @@ -4151,6 +4253,23 @@ rte_eth_dev_pool_ops_supported(uint16_t port_id, const char *pool); void * rte_eth_dev_get_sec_ctx(uint16_t port_id); +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Query the device hairpin capabilities. + * + * @param port_id + * The port identifier of the Ethernet device. + * @param cap + * Pointer to a structure that will hold the hairpin capabilities. + * @return + * - (0) if successful. + * - (-ENOTSUP) if hardware doesn't support. + */ +__rte_experimental +int rte_eth_dev_hairpin_capability_get(uint16_t port_id, + struct rte_eth_hairpin_cap *cap); #include diff --git a/lib/librte_ethdev/rte_ethdev_core.h b/lib/librte_ethdev/rte_ethdev_core.h index 392aea8e6b..f215af7c94 100644 --- a/lib/librte_ethdev/rte_ethdev_core.h +++ b/lib/librte_ethdev/rte_ethdev_core.h @@ -508,6 +508,86 @@ typedef int (*eth_pool_ops_supported_t)(struct rte_eth_dev *dev, const char *pool); /**< @internal Test if a port supports specific mempool ops */ +/** + * @internal + * Get the hairpin capabilities. + * + * @param dev + * ethdev handle of port. + * @param cap + * returns the hairpin capabilities from the device. + * + * @return + * Negative errno value on error, 0 on success. + * + * @retval 0 + * Success, hairpin is supported. + * @retval -ENOTSUP + * Hairpin is not supported. + */ +typedef int (*eth_hairpin_cap_get_t)(struct rte_eth_dev *dev, + struct rte_eth_hairpin_cap *cap); + +/** + * @internal + * Setup RX hairpin queue. + * + * @param dev + * ethdev handle of port. + * @param rx_queue_id + * the selected RX queue index. + * @param nb_rx_desc + * the requested number of descriptors for this queue. 0 - use PMD default. + * @param conf + * the RX hairpin configuration structure. + * + * @return + * Negative errno value on error, 0 on success. + * + * @retval 0 + * Success, hairpin is supported. + * @retval -ENOTSUP + * Hairpin is not supported. + * @retval -EINVAL + * One of the parameters is invalid. + * @retval -ENOMEM + * Unable to allocate resources. + */ +typedef int (*eth_rx_hairpin_queue_setup_t) + (struct rte_eth_dev *dev, uint16_t rx_queue_id, + uint16_t nb_rx_desc, + const struct rte_eth_hairpin_conf *conf); + +/** + * @internal + * Setup TX hairpin queue. + * + * @param dev + * ethdev handle of port. + * @param tx_queue_id + * the selected TX queue index. + * @param nb_tx_desc + * the requested number of descriptors for this queue. 0 - use PMD default. + * @param conf + * the TX hairpin configuration structure. + * + * @return + * Negative errno value on error, 0 on success. + * + * @retval 0 + * Success, hairpin is supported. + * @retval -ENOTSUP + * Hairpin is not supported. + * @retval -EINVAL + * One of the parameters is invalid. + * @retval -ENOMEM + * Unable to allocate resources. + */ +typedef int (*eth_tx_hairpin_queue_setup_t) + (struct rte_eth_dev *dev, uint16_t tx_queue_id, + uint16_t nb_tx_desc, + const struct rte_eth_hairpin_conf *hairpin_conf); + /** * @internal A structure containing the functions exported by an Ethernet driver. */ @@ -644,6 +724,13 @@ struct eth_dev_ops { eth_pool_ops_supported_t pool_ops_supported; /**< Test if a port supports specific mempool ops */ + + eth_hairpin_cap_get_t hairpin_cap_get; + /**< Returns the hairpin capabilities. */ + eth_rx_hairpin_queue_setup_t rx_hairpin_queue_setup; + /**< Set up device RX hairpin queue. */ + eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup; + /**< Set up device TX hairpin queue. */ }; /** @@ -751,9 +838,9 @@ struct rte_eth_dev_data { dev_started : 1, /**< Device state: STARTED(1) / STOPPED(0). */ lro : 1; /**< RX LRO is ON(1) / OFF(0) */ uint8_t rx_queue_state[RTE_MAX_QUEUES_PER_PORT]; - /**< Queues state: STARTED(1) / STOPPED(0). */ + /**< Queues state: HAIRPIN(2) / STARTED(1) / STOPPED(0). */ uint8_t tx_queue_state[RTE_MAX_QUEUES_PER_PORT]; - /**< Queues state: STARTED(1) / STOPPED(0). */ + /**< Queues state: HAIRPIN(2) / STARTED(1) / STOPPED(0). */ uint32_t dev_flags; /**< Capabilities. */ enum rte_kernel_driver kdrv; /**< Kernel driver passthrough. */ int numa_node; /**< NUMA node connection. */ diff --git a/lib/librte_ethdev/rte_ethdev_driver.h b/lib/librte_ethdev/rte_ethdev_driver.h index c404f17dd1..99d4cd6cd0 100644 --- a/lib/librte_ethdev/rte_ethdev_driver.h +++ b/lib/librte_ethdev/rte_ethdev_driver.h @@ -26,6 +26,35 @@ extern "C" { */ #define RTE_ETH_QUEUE_STATE_STOPPED 0 #define RTE_ETH_QUEUE_STATE_STARTED 1 +#define RTE_ETH_QUEUE_STATE_HAIRPIN 2 + +/** + * @internal + * Check if the selected Rx queue is hairpin queue. + * + * @param dev + * Pointer to the selected device. + * @param queue_id + * The selected queue. + * + * @return + * - (1) if the queue is hairpin queue, 0 otherwise. + */ +int rte_eth_dev_is_rx_hairpin_queue(struct rte_eth_dev *dev, uint16_t queue_id); + +/** + * @internal + * Check if the selected Tx queue is hairpin queue. + * + * @param dev + * Pointer to the selected device. + * @param queue_id + * The selected queue. + * + * @return + * - (1) if the queue is hairpin queue, 0 otherwise. + */ +int rte_eth_dev_is_tx_hairpin_queue(struct rte_eth_dev *dev, uint16_t queue_id); /** * @internal diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map index e59d51648f..57a3ab4c69 100644 --- a/lib/librte_ethdev/rte_ethdev_version.map +++ b/lib/librte_ethdev/rte_ethdev_version.map @@ -285,7 +285,10 @@ EXPERIMENTAL { rte_eth_read_clock; # added in 19.11 - rte_eth_rx_burst_mode_get; - rte_eth_tx_burst_mode_get; rte_eth_burst_mode_option_name; + rte_eth_dev_hairpin_capability_get; + rte_eth_rx_burst_mode_get; + rte_eth_rx_hairpin_queue_setup; + rte_eth_tx_burst_mode_get; + rte_eth_tx_hairpin_queue_setup; };