@@ -185,6 +185,21 @@ Supports receiving segmented mbufs.
* **[related] eth_dev_ops**: ``rx_pkt_burst``.
+.. _nic_features_buffer_split:
+
+Buffer Split on Rx
+------------
+
+Scatters the packets being received on specified boundaries to segmented mbufs.
+
+* **[uses] rte_eth_rxconf,rte_eth_rxmode**: ``offloads:RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT``.
+* **[implements] datapath**: ``Buffer Split functionality``.
+* **[implements] rte_eth_dev_data**: ``buffer_split``.
+* **[provides] rte_eth_dev_info**: ``rx_offload_capa:RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT``.
+* **[provides] eth_dev_ops**: ``rxq_info_get:buffer_split``.
+* **[related] API**: ``rte_eth_rxseg_queue_setup()``.
+
+
.. _nic_features_lro:
LRO
@@ -60,6 +60,12 @@ 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.
+* **Introduced extended buffer description for receiving.**
+
+ Added the extended Rx queue setup routine providing the individual
+ descriptions for each Rx segment with maximal size, buffer offset and memory
+ pool to allocate data buffers from.
+
* **Updated Broadcom bnxt driver.**
Updated the Broadcom bnxt driver with new features and improvements, including:
@@ -12,6 +12,9 @@
RTE_TRACE_POINT_REGISTER(rte_ethdev_trace_rxq_setup,
lib.ethdev.rxq.setup)
+RTE_TRACE_POINT_REGISTER(rte_ethdev_trace_rxq_seg_setup,
+ lib.ethdev.rxq.setup)
+
RTE_TRACE_POINT_REGISTER(rte_ethdev_trace_txq_setup,
lib.ethdev.txq.setup)
@@ -105,6 +105,9 @@ struct rte_eth_xstats_name_off {
#define RTE_RX_OFFLOAD_BIT2STR(_name) \
{ DEV_RX_OFFLOAD_##_name, #_name }
+#define RTE_ETH_RX_OFFLOAD_BIT2STR(_name) \
+ { RTE_ETH_RX_OFFLOAD_##_name, #_name }
+
static const struct {
uint64_t offload;
const char *name;
@@ -128,9 +131,11 @@ struct rte_eth_xstats_name_off {
RTE_RX_OFFLOAD_BIT2STR(SCTP_CKSUM),
RTE_RX_OFFLOAD_BIT2STR(OUTER_UDP_CKSUM),
RTE_RX_OFFLOAD_BIT2STR(RSS_HASH),
+ RTE_ETH_RX_OFFLOAD_BIT2STR(BUFFER_SPLIT),
};
#undef RTE_RX_OFFLOAD_BIT2STR
+#undef RTE_ETH_RX_OFFLOAD_BIT2STR
#define RTE_TX_OFFLOAD_BIT2STR(_name) \
{ DEV_TX_OFFLOAD_##_name, #_name }
@@ -1763,13 +1768,14 @@ struct rte_eth_dev *
return ret;
}
-int
-rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
- uint16_t nb_rx_desc, unsigned int socket_id,
- const struct rte_eth_rxconf *rx_conf,
- struct rte_mempool *mp)
+static int
+__rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
+ uint16_t nb_rx_desc, unsigned int socket_id,
+ const struct rte_eth_rxconf *rx_conf,
+ const struct rte_eth_rxseg *rx_seg, uint16_t n_seg)
{
- int ret;
+ int ret, ext;
+ uint16_t seg_idx;
uint32_t mbp_buf_size;
struct rte_eth_dev *dev;
struct rte_eth_dev_info dev_info;
@@ -1784,12 +1790,23 @@ struct rte_eth_dev *
return -EINVAL;
}
- if (mp == NULL) {
- RTE_ETHDEV_LOG(ERR, "Invalid null mempool pointer\n");
+ if (rx_seg == NULL) {
+ RTE_ETHDEV_LOG(ERR, "Invalid null description pointer\n");
+ return -EINVAL;
+ }
+
+ if (n_seg == 0) {
+ RTE_ETHDEV_LOG(ERR, "Invalid zero description number\n");
return -EINVAL;
}
- RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rx_queue_setup, -ENOTSUP);
+ ext = rx_seg[0].length || rx_seg[0].offset || n_seg > 1;
+ if (ext)
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rxseg_queue_setup,
+ -ENOTSUP);
+ else
+ RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rx_queue_setup,
+ -ENOTSUP);
/*
* Check the size of the mbuf data buffer.
@@ -1800,22 +1817,48 @@ struct rte_eth_dev *
if (ret != 0)
return ret;
- if (mp->private_data_size < sizeof(struct rte_pktmbuf_pool_private)) {
- RTE_ETHDEV_LOG(ERR, "%s private_data_size %d < %d\n",
- mp->name, (int)mp->private_data_size,
- (int)sizeof(struct rte_pktmbuf_pool_private));
- return -ENOSPC;
- }
- mbp_buf_size = rte_pktmbuf_data_room_size(mp);
+ for (seg_idx = 0; seg_idx < n_seg; seg_idx++) {
+ struct rte_mempool *mp = rx_seg[seg_idx].mp;
+ uint32_t length = rx_seg[seg_idx].length;
+ uint32_t offset = rx_seg[seg_idx].offset;
+ uint32_t head_room = seg_idx ? 0 : RTE_PKTMBUF_HEADROOM;
- if (mbp_buf_size < dev_info.min_rx_bufsize + RTE_PKTMBUF_HEADROOM) {
- RTE_ETHDEV_LOG(ERR,
- "%s mbuf_data_room_size %d < %d (RTE_PKTMBUF_HEADROOM=%d + min_rx_bufsize(dev)=%d)\n",
- mp->name, (int)mbp_buf_size,
- (int)(RTE_PKTMBUF_HEADROOM + dev_info.min_rx_bufsize),
- (int)RTE_PKTMBUF_HEADROOM,
- (int)dev_info.min_rx_bufsize);
- return -EINVAL;
+ if (mp == NULL) {
+ RTE_ETHDEV_LOG(ERR, "Invalid null mempool pointer\n");
+ return -EINVAL;
+ }
+
+ if (mp->private_data_size <
+ sizeof(struct rte_pktmbuf_pool_private)) {
+ RTE_ETHDEV_LOG(ERR, "%s private_data_size %d < %d\n",
+ mp->name, (int)mp->private_data_size,
+ (int)sizeof(struct rte_pktmbuf_pool_private));
+ return -ENOSPC;
+ }
+
+ mbp_buf_size = rte_pktmbuf_data_room_size(mp);
+ length = length ? length : (mbp_buf_size - head_room);
+ if (mbp_buf_size < length + offset + head_room) {
+ RTE_ETHDEV_LOG(ERR,
+ "%s mbuf_data_room_size %u < %u"
+ " (segment length=%u + segment offset=%u)\n",
+ mp->name, mbp_buf_size,
+ length + offset, length, offset);
+ return -EINVAL;
+ }
+ if (!ext && (mbp_buf_size < dev_info.min_rx_bufsize +
+ RTE_PKTMBUF_HEADROOM)) {
+ RTE_ETHDEV_LOG(ERR,
+ "%s mbuf_data_room_size %u < %u "
+ "(RTE_PKTMBUF_HEADROOM=%u + "
+ "min_rx_bufsize(dev)=%u)\n",
+ mp->name, mbp_buf_size,
+ (RTE_PKTMBUF_HEADROOM +
+ dev_info.min_rx_bufsize),
+ RTE_PKTMBUF_HEADROOM,
+ dev_info.min_rx_bufsize);
+ return -EINVAL;
+ }
}
/* Use default specified by driver, if nb_rx_desc is zero */
@@ -1906,20 +1949,54 @@ struct rte_eth_dev *
return ret;
}
- ret = (*dev->dev_ops->rx_queue_setup)(dev, rx_queue_id, nb_rx_desc,
- socket_id, &local_conf, mp);
+ ret = ext ?
+ (*dev->dev_ops->rxseg_queue_setup)(dev, rx_queue_id, nb_rx_desc,
+ socket_id, &local_conf,
+ rx_seg, n_seg) :
+ (*dev->dev_ops->rx_queue_setup)(dev, rx_queue_id, nb_rx_desc,
+ socket_id, &local_conf,
+ rx_seg[0].mp);
if (!ret) {
if (!dev->data->min_rx_buf_size ||
dev->data->min_rx_buf_size > mbp_buf_size)
dev->data->min_rx_buf_size = mbp_buf_size;
}
- rte_ethdev_trace_rxq_setup(port_id, rx_queue_id, nb_rx_desc, mp,
- rx_conf, ret);
return eth_err(port_id, ret);
}
int
+rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
+ uint16_t nb_rx_desc, unsigned int socket_id,
+ const struct rte_eth_rxconf *rx_conf,
+ struct rte_mempool *mp)
+{
+ struct rte_eth_rxseg rx_seg = {.mp = mp};
+ int ret;
+
+ ret = __rte_eth_rx_queue_setup(port_id, rx_queue_id, nb_rx_desc,
+ socket_id, rx_conf, &rx_seg, 1);
+ rte_ethdev_trace_rxq_setup(port_id, rx_queue_id, nb_rx_desc,
+ mp, rx_conf, ret);
+ return ret;
+}
+
+int
+rte_eth_rxseg_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
+ uint16_t nb_rx_desc, unsigned int socket_id,
+ const struct rte_eth_rxconf *rx_conf,
+ const struct rte_eth_rxseg *rx_seg, uint16_t n_seg)
+{
+ int ret;
+
+ ret = __rte_eth_rx_queue_setup(port_id, rx_queue_id, nb_rx_desc,
+ socket_id, rx_conf, rx_seg, n_seg);
+ rte_ethdev_trace_rxq_seg_setup(port_id, rx_queue_id, nb_rx_desc,
+ rx_conf, rx_seg, n_seg, ret);
+ return 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)
@@ -970,6 +970,16 @@ struct rte_eth_txmode {
};
/**
+ * A structure used to configure an RX packet segment to split.
+ */
+struct rte_eth_rxseg {
+ struct rte_mempool *mp; /**< Memory pools to allocate segment from */
+ uint16_t length; /**< Segment data length, configures split point. */
+ uint16_t offset; /**< Data offset from beginning of mbuf data buffer */
+ uint32_t reserved; /**< Reserved field */
+};
+
+/**
* A structure used to configure an RX ring of an Ethernet port.
*/
struct rte_eth_rxconf {
@@ -1260,6 +1270,7 @@ struct rte_eth_conf {
#define DEV_RX_OFFLOAD_SCTP_CKSUM 0x00020000
#define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
+#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000
#define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
DEV_RX_OFFLOAD_UDP_CKSUM | \
@@ -2044,6 +2055,102 @@ int rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
uint16_t nb_rx_desc, unsigned int socket_id,
const struct rte_eth_rxconf *rx_conf,
struct rte_mempool *mb_pool);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Allocate and set up a receive queue for an Ethernet device
+ * with specifying receiving segments parameters.
+ *
+ * The function allocates a contiguous block of memory for *nb_rx_desc*
+ * receive descriptors from a memory zone associated with *socket_id*.
+ * The descriptors might be divided into groups by PMD to receive the data
+ * into multi-segment packet presented by the chain of mbufs.
+ *
+ * Each descriptor within the group is initialized accordingly with
+ * the network buffers allocated from the specified memory pool and with
+ * specified buffer offset and maximal segment length.
+ *
+ * @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.
+ * @param socket_id
+ * The *socket_id* argument is the socket identifier in case of NUMA.
+ * The value can be *SOCKET_ID_ANY* if there is no NUMA constraint for
+ * the DMA memory allocated for the receive descriptors of the ring.
+ * @param rx_conf
+ * The pointer to the configuration data to be used for the receive queue.
+ * NULL value is allowed, in which case default RX configuration
+ * will be used.
+ * The *rx_conf* structure contains an *rx_thresh* structure with the values
+ * of the Prefetch, Host, and Write-Back threshold registers of the receive
+ * ring.
+ * In addition it contains the hardware offloads features to activate using
+ * the DEV_RX_OFFLOAD_* flags.
+ * If an offloading set in rx_conf->offloads
+ * hasn't been set in the input argument eth_conf->rxmode.offloads
+ * to rte_eth_dev_configure(), it is a new added offloading, it must be
+ * per-queue type and it is enabled for the queue.
+ * No need to repeat any bit in rx_conf->offloads which has already been
+ * enabled in rte_eth_dev_configure() at port level. An offloading enabled
+ * at port level can't be disabled at queue level.
+ * @param rx_seg
+ * The pointer to the array of segment descriptions, each element describes
+ * the memory pool, maximal segment data length, initial data offset from
+ * the beginning of data buffer in mbuf. This allow to specify the dedicated
+ * properties for each segment in the receiving buffer - pool, buffer
+ * offset, maximal segment size. If RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT offload
+ * flag is configured the PMD will split the received packets into multiple
+ * segments according to the specification in the description array:
+ * - the first network buffer will be allocated from the memory pool,
+ * specified in the first segment description element, the second
+ * network buffer - from the pool in the second segment description
+ * element and so on. If there is no enough elements to describe
+ * the buffer for entire packet of maximal length the pool from the last
+ * valid element will be used to allocate the buffers from for the rest
+ * of segments.
+ * - the offsets from the segment description elements will provide the
+ * data offset from the buffer beginning except the first mbuf - for this
+ * one the offset is added to the RTE_PKTMBUF_HEADROOM to get actual
+ * offset from the buffer beginning. If there is no enough elements
+ * to describe the buffer for entire packet of maximal length the offsets
+ * for the rest of segment will be supposed to be zero.
+ * - the data length being received to each segment is limited by the
+ * length specified in the segment description element. The data receiving
+ * starts with filling up the first mbuf data buffer, if the specified
+ * maximal segment length is reached and there are data remaining
+ * (packet is longer than buffer in the first mbuf) the following data
+ * will be pushed to the next segment up to its own length. If the first
+ * two segments is not enough to store all the packet data the next
+ * (third) segment will be engaged and so on. If the length in the segment
+ * description element is zero the actual buffer size will be deduced
+ * from the appropriate memory pool properties. If there is no enough
+ * elements to describe the buffer for entire packet of maximal length
+ * the buffer size will be deduced from the pool of the last valid
+ * element for the all remaining segments.
+ * @param n_seg
+ * The number of elements in the segment description array.
+ * @return
+ * - 0: Success, receive queue correctly set up.
+ * - -EIO: if device is removed.
+ * - -EINVAL: The segment descriptors array is empty (pointer to is null or
+ * zero number of elements) or the size of network buffers which can be
+ * allocated from this memory pool does not fit the various buffer sizes
+ * allowed by the device controller.
+ * - -ENOMEM: Unable to allocate the receive ring descriptors or to
+ * allocate network memory buffers from the memory pool when
+ * initializing receive descriptors.
+ */
+__rte_experimental
+int rte_eth_rxseg_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
+ uint16_t nb_rx_desc, unsigned int socket_id,
+ const struct rte_eth_rxconf *rx_conf,
+ const struct rte_eth_rxseg *rx_seg, uint16_t n_seg);
/**
* @warning
@@ -264,6 +264,15 @@ typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev,
struct rte_mempool *mb_pool);
/**< @internal Set up a receive queue of an Ethernet device. */
+typedef int (*eth_rxseg_queue_setup_t)(struct rte_eth_dev *dev,
+ uint16_t rx_queue_id,
+ uint16_t nb_rx_desc,
+ unsigned int socket_id,
+ const struct rte_eth_rxconf *rx_conf,
+ const struct rte_eth_rxseg *rx_seg,
+ uint16_t n_seg);
+/**< @internal extended Set up a receive queue of an Ethernet device. */
+
typedef int (*eth_tx_queue_setup_t)(struct rte_eth_dev *dev,
uint16_t tx_queue_id,
uint16_t nb_tx_desc,
@@ -711,6 +720,7 @@ struct eth_dev_ops {
eth_queue_start_t tx_queue_start;/**< Start TX for a queue. */
eth_queue_stop_t tx_queue_stop; /**< Stop TX for a queue. */
eth_rx_queue_setup_t rx_queue_setup;/**< Set up device RX queue. */
+ eth_rxseg_queue_setup_t rxseg_queue_setup;/**< Extended RX setup. */
eth_queue_release_t rx_queue_release; /**< Release RX queue. */
eth_rx_enable_intr_t rx_queue_intr_enable; /**< Enable Rx queue interrupt. */
@@ -55,6 +55,25 @@
)
RTE_TRACE_POINT(
+ rte_ethdev_trace_rxq_seg_setup,
+ RTE_TRACE_POINT_ARGS(uint16_t port_id, uint16_t rx_queue_id,
+ uint16_t nb_rx_desc, const struct rte_eth_rxconf *rx_conf,
+ const struct rte_eth_rxseg *rx_seg, uint16_t n_seg, int rc),
+ rte_trace_point_emit_u16(port_id);
+ rte_trace_point_emit_u16(rx_queue_id);
+ rte_trace_point_emit_u16(nb_rx_desc);
+ rte_trace_point_emit_u8(rx_conf->rx_thresh.pthresh);
+ rte_trace_point_emit_u8(rx_conf->rx_thresh.hthresh);
+ rte_trace_point_emit_u8(rx_conf->rx_thresh.wthresh);
+ rte_trace_point_emit_u8(rx_conf->rx_drop_en);
+ rte_trace_point_emit_u8(rx_conf->rx_deferred_start);
+ rte_trace_point_emit_u64(rx_conf->offloads);
+ rte_trace_point_emit_ptr(rx_seg);
+ rte_trace_point_emit_u16(n_seg);
+ rte_trace_point_emit_int(rc);
+)
+
+RTE_TRACE_POINT(
rte_ethdev_trace_txq_setup,
RTE_TRACE_POINT_ARGS(uint16_t port_id, uint16_t tx_queue_id,
uint16_t nb_tx_desc, const struct rte_eth_txconf *tx_conf),
@@ -195,6 +195,7 @@ EXPERIMENTAL {
rte_flow_get_aged_flows;
# Marked as experimental in 20.11
+ rte_eth_rxseg_queue_setup;
rte_tm_capabilities_get;
rte_tm_get_number_of_leaf_nodes;
rte_tm_hierarchy_commit;
@@ -232,6 +233,8 @@ EXPERIMENTAL {
rte_eth_fec_get_capability;
rte_eth_fec_get;
rte_eth_fec_set;
+ __rte_ethdev_trace_rxq_seg_setup;
+
};
INTERNAL {