* [PATCH v3] net/af_packet: add multi-segment mbuf support for jumbo frames
@ 2026-03-12 7:34 Sriram Yagnaraman
2026-03-12 16:06 ` Stephen Hemminger
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Sriram Yagnaraman @ 2026-03-12 7:34 UTC (permalink / raw)
To: dev; +Cc: xavier.guillaume, stephen, robin.l.lin, Sriram Yagnaraman
Enable jumbo frame reception with default mbuf data room size by
chaining multiple mbufs when packet exceeds single mbuf tailroom.
Scatter Rx is only enabled when RTE_ETH_RX_OFFLOAD_SCATTER is
requested. Packets are dropped if they exceed single mbuf size
and scatter is not enabled, or if mbuf allocation fails during
chaining. Error counter rx_dropped_pkts tracks all drops.
This allows receiving 9KB jumbo frames using standard 2KB mbufs,
chaining ~5 segments per jumbo packet.
---
doc/guides/rel_notes/release_26_03.rst | 5 ++
drivers/net/af_packet/rte_eth_af_packet.c | 76 +++++++++++++++++++----
2 files changed, 68 insertions(+), 13 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index fdc880687b..ec627e76c9 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -65,6 +65,11 @@ New Features
* Added support for V4000 Krackan2e.
+* **Updated AF_PACKET ethernet driver.**
+
+ * Added support for multi-segment mbuf reception to handle jumbo frames
+ with standard mbuf sizes when scatter Rx offload is enabled.
+
* **Updated CESNET nfb ethernet driver.**
* The timestamp value has been updated to make it usable.
diff --git a/drivers/net/af_packet/rte_eth_af_packet.c b/drivers/net/af_packet/rte_eth_af_packet.c
index e132dc387b..5d43306c09 100644
--- a/drivers/net/af_packet/rte_eth_af_packet.c
+++ b/drivers/net/af_packet/rte_eth_af_packet.c
@@ -56,6 +56,7 @@ struct __rte_cache_aligned pkt_rx_queue {
uint16_t in_port;
uint8_t vlan_strip;
uint8_t timestamp_offloading;
+ uint8_t scatter_enabled;
volatile unsigned long rx_pkts;
volatile unsigned long rx_bytes;
@@ -125,12 +126,13 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
{
unsigned i;
struct tpacket2_hdr *ppd;
- struct rte_mbuf *mbuf;
+ struct rte_mbuf *mbuf, *seg, *prev;
uint8_t *pbuf;
struct pkt_rx_queue *pkt_q = queue;
uint16_t num_rx = 0;
unsigned long num_rx_bytes = 0;
unsigned int framecount, framenum;
+ uint16_t pkt_len, data_len, remaining;
if (unlikely(nb_pkts == 0))
return 0;
@@ -154,8 +156,11 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
break;
}
- /* drop packets that won't fit in the mbuf */
- if (ppd->tp_snaplen > rte_pktmbuf_tailroom(mbuf)) {
+ pkt_len = ppd->tp_snaplen;
+ pbuf = (uint8_t *) ppd + ppd->tp_mac;
+
+ /* drop packets that won't fit in single mbuf if scatter not enabled */
+ if (!pkt_q->scatter_enabled && pkt_len > rte_pktmbuf_tailroom(mbuf)) {
rte_pktmbuf_free(mbuf);
ppd->tp_status = TP_STATUS_KERNEL;
if (++framenum >= framecount)
@@ -164,10 +169,57 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
continue;
}
- /* packet will fit in the mbuf, go ahead and receive it */
- rte_pktmbuf_pkt_len(mbuf) = rte_pktmbuf_data_len(mbuf) = ppd->tp_snaplen;
- pbuf = (uint8_t *) ppd + ppd->tp_mac;
- memcpy(rte_pktmbuf_mtod(mbuf, void *), pbuf, rte_pktmbuf_data_len(mbuf));
+ /* copy first segment */
+ data_len = RTE_MIN(pkt_len, rte_pktmbuf_tailroom(mbuf));
+ memcpy(rte_pktmbuf_mtod(mbuf, void *), pbuf, data_len);
+ rte_pktmbuf_data_len(mbuf) = data_len;
+ mbuf->nb_segs = 1;
+ remaining = pkt_len - data_len;
+ pbuf += data_len;
+ prev = mbuf;
+
+ /* chain additional segments if needed */
+ while (remaining > 0) {
+ seg = rte_pktmbuf_alloc(pkt_q->mb_pool);
+ if (unlikely(seg == NULL)) {
+ rte_pktmbuf_free(mbuf);
+ ppd->tp_status = TP_STATUS_KERNEL;
+ if (++framenum >= framecount)
+ framenum = 0;
+ pkt_q->rx_dropped_pkts++;
+ continue;
+ }
+
+ /* Remove headroom to maximize data space in chained segments */
+ rte_pktmbuf_prepend(seg, rte_pktmbuf_headroom(seg));
+
+ data_len = RTE_MIN(remaining, rte_pktmbuf_tailroom(seg));
+ if (unlikely(data_len == 0)) {
+ rte_pktmbuf_free(seg);
+ rte_pktmbuf_free(mbuf);
+ ppd->tp_status = TP_STATUS_KERNEL;
+ if (++framenum >= framecount)
+ framenum = 0;
+ pkt_q->rx_dropped_pkts++;
+ continue;
+ }
+
+ memcpy(rte_pktmbuf_mtod(seg, void *), pbuf, data_len);
+ rte_pktmbuf_data_len(seg) = data_len;
+ pbuf += data_len;
+ remaining -= data_len;
+
+ prev->next = seg;
+ prev = seg;
+ mbuf->nb_segs++;
+ }
+
+ /* release incoming frame and advance ring buffer */
+ ppd->tp_status = TP_STATUS_KERNEL;
+ if (++framenum >= framecount)
+ framenum = 0;
+
+ rte_pktmbuf_pkt_len(mbuf) = pkt_len;
/* check for vlan info */
if (ppd->tp_status & TP_STATUS_VLAN_VALID) {
@@ -188,14 +240,10 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
mbuf->ol_flags |= timestamp_dynflag;
}
- /* release incoming frame and advance ring buffer */
- ppd->tp_status = TP_STATUS_KERNEL;
- if (++framenum >= framecount)
- framenum = 0;
mbuf->port = pkt_q->in_port;
/* account for the receive frame */
- bufs[i] = mbuf;
+ bufs[num_rx] = mbuf;
num_rx++;
num_rx_bytes += mbuf->pkt_len;
}
@@ -412,7 +460,8 @@ eth_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
RTE_ETH_TX_OFFLOAD_VLAN_INSERT;
dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
- RTE_ETH_RX_OFFLOAD_TIMESTAMP;
+ RTE_ETH_RX_OFFLOAD_TIMESTAMP |
+ RTE_ETH_RX_OFFLOAD_SCATTER;
return 0;
}
@@ -599,6 +648,7 @@ eth_rx_queue_setup(struct rte_eth_dev *dev,
pkt_q->in_port = dev->data->port_id;
pkt_q->vlan_strip = internals->vlan_strip;
pkt_q->timestamp_offloading = internals->timestamp_offloading;
+ pkt_q->scatter_enabled = !!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SCATTER);
return 0;
}
--
2.43.7
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v3] net/af_packet: add multi-segment mbuf support for jumbo frames 2026-03-12 7:34 [PATCH v3] net/af_packet: add multi-segment mbuf support for jumbo frames Sriram Yagnaraman @ 2026-03-12 16:06 ` Stephen Hemminger 2026-03-12 16:34 ` Stephen Hemminger 2026-03-13 9:10 ` [PATCH v4] " Sriram Yagnaraman 2 siblings, 0 replies; 9+ messages in thread From: Stephen Hemminger @ 2026-03-12 16:06 UTC (permalink / raw) To: Sriram Yagnaraman; +Cc: dev, xavier.guillaume, robin.l.lin On Thu, 12 Mar 2026 08:34:03 +0100 Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> wrote: > Enable jumbo frame reception with default mbuf data room size by > chaining multiple mbufs when packet exceeds single mbuf tailroom. > > Scatter Rx is only enabled when RTE_ETH_RX_OFFLOAD_SCATTER is > requested. Packets are dropped if they exceed single mbuf size > and scatter is not enabled, or if mbuf allocation fails during > chaining. Error counter rx_dropped_pkts tracks all drops. > > This allows receiving 9KB jumbo frames using standard 2KB mbufs, > chaining ~5 segments per jumbo packet. > --- Scatter is good, but additional checks are necessary to validate mbuf pool and buffer constraints. See virtio configure for example. bool virtio_rx_check_scatter(uint16_t max_rx_pkt_len, uint16_t rx_buf_size, bool rx_scatter_enabled, const char **error) { if (!rx_scatter_enabled && max_rx_pkt_len > rx_buf_size) { *error = "Rx scatter is disabled and RxQ mbuf pool object size is too small"; return false; } return true; } ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3] net/af_packet: add multi-segment mbuf support for jumbo frames 2026-03-12 7:34 [PATCH v3] net/af_packet: add multi-segment mbuf support for jumbo frames Sriram Yagnaraman 2026-03-12 16:06 ` Stephen Hemminger @ 2026-03-12 16:34 ` Stephen Hemminger 2026-03-13 9:10 ` [PATCH v4] " Sriram Yagnaraman 2 siblings, 0 replies; 9+ messages in thread From: Stephen Hemminger @ 2026-03-12 16:34 UTC (permalink / raw) To: Sriram Yagnaraman; +Cc: dev, xavier.guillaume, robin.l.lin On Thu, 12 Mar 2026 08:34:03 +0100 Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> wrote: > Enable jumbo frame reception with default mbuf data room size by > chaining multiple mbufs when packet exceeds single mbuf tailroom. > > Scatter Rx is only enabled when RTE_ETH_RX_OFFLOAD_SCATTER is > requested. Packets are dropped if they exceed single mbuf size > and scatter is not enabled, or if mbuf allocation fails during > chaining. Error counter rx_dropped_pkts tracks all drops. > > This allows receiving 9KB jumbo frames using standard 2KB mbufs, > chaining ~5 segments per jumbo packet. > --- Project does not accept patches without DCO (ie. Signed-off-by) ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4] net/af_packet: add multi-segment mbuf support for jumbo frames 2026-03-12 7:34 [PATCH v3] net/af_packet: add multi-segment mbuf support for jumbo frames Sriram Yagnaraman 2026-03-12 16:06 ` Stephen Hemminger 2026-03-12 16:34 ` Stephen Hemminger @ 2026-03-13 9:10 ` Sriram Yagnaraman 2026-03-18 9:47 ` [PATCH v5] " Sriram Yagnaraman 2 siblings, 1 reply; 9+ messages in thread From: Sriram Yagnaraman @ 2026-03-13 9:10 UTC (permalink / raw) To: dev; +Cc: stephen, xavier.guillaume, robin.l.lin, Sriram Yagnaraman Enable jumbo frame reception with default mbuf data room size by chaining multiple mbufs when packet exceeds single mbuf tailroom. Scatter Rx is only enabled when RTE_ETH_RX_OFFLOAD_SCATTER is requested. Packets are dropped if they exceed single mbuf size and scatter is not enabled, or if mbuf allocation fails during chaining. Error counter rx_dropped_pkts tracks all drops. This allows receiving 9KB jumbo frames using standard 2KB mbufs, chaining ~5 segments per jumbo packet. Signed-off-by: Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> --- doc/guides/rel_notes/release_26_03.rst | 5 ++ drivers/net/af_packet/rte_eth_af_packet.c | 79 +++++++++++++++++------ 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst index 9649185133..1048a6b595 100644 --- a/doc/guides/rel_notes/release_26_03.rst +++ b/doc/guides/rel_notes/release_26_03.rst @@ -65,6 +65,11 @@ New Features * Added support for V4000 Krackan2e. +* **Updated AF_PACKET ethernet driver.** + + * Added support for multi-segment mbuf reception to handle jumbo frames + with standard mbuf sizes when scatter Rx offload is enabled. + * **Updated CESNET nfb ethernet driver.** * The timestamp value has been updated to make it usable. diff --git a/drivers/net/af_packet/rte_eth_af_packet.c b/drivers/net/af_packet/rte_eth_af_packet.c index e132dc387b..13daa02fe0 100644 --- a/drivers/net/af_packet/rte_eth_af_packet.c +++ b/drivers/net/af_packet/rte_eth_af_packet.c @@ -56,6 +56,7 @@ struct __rte_cache_aligned pkt_rx_queue { uint16_t in_port; uint8_t vlan_strip; uint8_t timestamp_offloading; + uint8_t scatter_enabled; volatile unsigned long rx_pkts; volatile unsigned long rx_bytes; @@ -125,12 +126,13 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) { unsigned i; struct tpacket2_hdr *ppd; - struct rte_mbuf *mbuf; + struct rte_mbuf *mbuf, *seg, *prev; uint8_t *pbuf; struct pkt_rx_queue *pkt_q = queue; uint16_t num_rx = 0; unsigned long num_rx_bytes = 0; unsigned int framecount, framenum; + uint16_t pkt_len, data_len, remaining; if (unlikely(nb_pkts == 0)) return 0; @@ -154,20 +156,49 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) break; } - /* drop packets that won't fit in the mbuf */ - if (ppd->tp_snaplen > rte_pktmbuf_tailroom(mbuf)) { + pkt_len = ppd->tp_snaplen; + pbuf = (uint8_t *)ppd + ppd->tp_mac; + + /* drop packets that won't fit in single mbuf if scatter not enabled */ + if (!pkt_q->scatter_enabled && pkt_len > rte_pktmbuf_tailroom(mbuf)) { rte_pktmbuf_free(mbuf); - ppd->tp_status = TP_STATUS_KERNEL; - if (++framenum >= framecount) - framenum = 0; pkt_q->rx_dropped_pkts++; - continue; + goto release_frame; + } + + /* copy first segment */ + data_len = RTE_MIN(pkt_len, rte_pktmbuf_tailroom(mbuf)); + memcpy(rte_pktmbuf_mtod(mbuf, void *), pbuf, data_len); + rte_pktmbuf_data_len(mbuf) = data_len; + mbuf->nb_segs = 1; + remaining = pkt_len - data_len; + pbuf += data_len; + prev = mbuf; + + /* chain additional segments if needed */ + while (remaining > 0) { + seg = rte_pktmbuf_alloc(pkt_q->mb_pool); + if (unlikely(seg == NULL)) { + rte_pktmbuf_free(mbuf); + pkt_q->rx_dropped_pkts++; + goto release_frame; + } + + /* Remove headroom to maximize data space in chained segments */ + rte_pktmbuf_prepend(seg, rte_pktmbuf_headroom(seg)); + + data_len = RTE_MIN(remaining, rte_pktmbuf_tailroom(seg)); + memcpy(rte_pktmbuf_mtod(seg, void *), pbuf, data_len); + rte_pktmbuf_data_len(seg) = data_len; + pbuf += data_len; + remaining -= data_len; + + prev->next = seg; + prev = seg; + mbuf->nb_segs++; } - /* packet will fit in the mbuf, go ahead and receive it */ - rte_pktmbuf_pkt_len(mbuf) = rte_pktmbuf_data_len(mbuf) = ppd->tp_snaplen; - pbuf = (uint8_t *) ppd + ppd->tp_mac; - memcpy(rte_pktmbuf_mtod(mbuf, void *), pbuf, rte_pktmbuf_data_len(mbuf)); + rte_pktmbuf_pkt_len(mbuf) = pkt_len; /* check for vlan info */ if (ppd->tp_status & TP_STATUS_VLAN_VALID) { @@ -188,16 +219,18 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) mbuf->ol_flags |= timestamp_dynflag; } - /* release incoming frame and advance ring buffer */ - ppd->tp_status = TP_STATUS_KERNEL; - if (++framenum >= framecount) - framenum = 0; mbuf->port = pkt_q->in_port; /* account for the receive frame */ - bufs[i] = mbuf; + bufs[num_rx] = mbuf; num_rx++; num_rx_bytes += mbuf->pkt_len; + +release_frame: + /* release incoming frame and advance ring buffer */ + ppd->tp_status = TP_STATUS_KERNEL; + if (++framenum >= framecount) + framenum = 0; } pkt_q->framenum = framenum; pkt_q->rx_pkts += num_rx; @@ -412,7 +445,8 @@ eth_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_MULTI_SEGS | RTE_ETH_TX_OFFLOAD_VLAN_INSERT; dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP | - RTE_ETH_RX_OFFLOAD_TIMESTAMP; + RTE_ETH_RX_OFFLOAD_TIMESTAMP | + RTE_ETH_RX_OFFLOAD_SCATTER; return 0; } @@ -579,26 +613,29 @@ eth_rx_queue_setup(struct rte_eth_dev *dev, struct pmd_internals *internals = dev->data->dev_private; struct pkt_rx_queue *pkt_q = &internals->rx_queue[rx_queue_id]; unsigned int buf_size, data_size; + bool scatter_enabled; pkt_q->mb_pool = mb_pool; - /* Now get the space available for data in the mbuf */ buf_size = rte_pktmbuf_data_room_size(pkt_q->mb_pool) - RTE_PKTMBUF_HEADROOM; data_size = internals->req.tp_frame_size; data_size -= TPACKET2_HDRLEN - sizeof(struct sockaddr_ll); - if (data_size > buf_size) { + scatter_enabled = !!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SCATTER); + + if (!scatter_enabled && data_size > buf_size) { PMD_LOG(ERR, - "%s: %d bytes will not fit in mbuf (%d bytes)", + "%s: %d bytes will not fit in mbuf (%d bytes), enable scatter offload", dev->device->name, data_size, buf_size); - return -ENOMEM; + return -EINVAL; } dev->data->rx_queues[rx_queue_id] = pkt_q; pkt_q->in_port = dev->data->port_id; pkt_q->vlan_strip = internals->vlan_strip; pkt_q->timestamp_offloading = internals->timestamp_offloading; + pkt_q->scatter_enabled = scatter_enabled; return 0; } -- 2.43.7 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v5] net/af_packet: add multi-segment mbuf support for jumbo frames 2026-03-13 9:10 ` [PATCH v4] " Sriram Yagnaraman @ 2026-03-18 9:47 ` Sriram Yagnaraman 2026-03-23 23:42 ` Stephen Hemminger 2026-03-24 16:29 ` [PATCH v6] net/af_packet: add Rx scatter " Sriram Yagnaraman 0 siblings, 2 replies; 9+ messages in thread From: Sriram Yagnaraman @ 2026-03-18 9:47 UTC (permalink / raw) To: dev; +Cc: stephen, xavier.guillaume, robin.l.lin, Sriram Yagnaraman Enable jumbo frame reception with default mbuf data room size by chaining multiple mbufs when packet exceeds single mbuf tailroom. Scatter Rx is only enabled when RTE_ETH_RX_OFFLOAD_SCATTER is requested. Packets are dropped if they exceed single mbuf size and scatter is not enabled, or if mbuf allocation fails during chaining. Error counter rx_dropped_pkts tracks all drops. This allows receiving 9KB jumbo frames using standard 2KB mbufs, chaining ~5 segments per jumbo packet. Signed-off-by: Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> --- v5: * Rebased on main (26.03-rc2) now that Xavier's jumbo frame series is merged * Removed Depends-on (dependency is now in main) * Extracted scatter copy into eth_af_packet_rx_scatter() helper (matches pcap pattern) v4: * Added scatter validation in rx_queue_setup to reject invalid configurations * Fixed control flow: use goto instead of continue in scatter loop * Moved frame release to common label to prevent use-after-free * Ensured VLAN/timestamp extraction happens before releasing frame to kernel v3: * Added conditional scatter based on RTE_ETH_RX_OFFLOAD_SCATTER configuration * Removed headroom from chained segments to maximize data capacity * Fixed infinite loop risk by removing zero tailroom check (trust mempool config) v2: * Fixed goto label to properly exit outer loop on allocation failure * Changed bufs indexing from [i] to [num_rx] for correct packet placement --- doc/guides/rel_notes/release_26_03.rst | 5 ++ drivers/net/af_packet/rte_eth_af_packet.c | 97 ++++++++++++++++++----- 2 files changed, 82 insertions(+), 20 deletions(-) diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst index 3d2ed19eb8..54e3bdbcc7 100644 --- a/doc/guides/rel_notes/release_26_03.rst +++ b/doc/guides/rel_notes/release_26_03.rst @@ -65,6 +65,11 @@ New Features * Added support for V4000 Krackan2e. +* **Updated AF_PACKET ethernet driver.** + + * Added support for multi-segment mbuf reception to handle jumbo frames + with standard mbuf sizes when scatter Rx offload is enabled. + * **Updated CESNET nfb ethernet driver.** * The timestamp value has been updated to make it usable. diff --git a/drivers/net/af_packet/rte_eth_af_packet.c b/drivers/net/af_packet/rte_eth_af_packet.c index e132dc387b..7db3843610 100644 --- a/drivers/net/af_packet/rte_eth_af_packet.c +++ b/drivers/net/af_packet/rte_eth_af_packet.c @@ -56,6 +56,7 @@ struct __rte_cache_aligned pkt_rx_queue { uint16_t in_port; uint8_t vlan_strip; uint8_t timestamp_offloading; + uint8_t scatter_enabled; volatile unsigned long rx_pkts; volatile unsigned long rx_bytes; @@ -120,6 +121,46 @@ RTE_LOG_REGISTER_DEFAULT(af_packet_logtype, NOTICE); RTE_LOG_LINE(level, AFPACKET, "%s(): " fmt ":%s", __func__, \ ## __VA_ARGS__, strerror(errno)) +/* + * Copy packet data into chained mbufs when it exceeds single mbuf tailroom. + * Returns 0 on success, -1 on mbuf allocation failure. + */ +static int +eth_af_packet_rx_scatter(struct rte_mempool *mb_pool, struct rte_mbuf *mbuf, + const uint8_t *data, uint16_t data_len) +{ + uint16_t len = rte_pktmbuf_tailroom(mbuf); + struct rte_mbuf *m = mbuf; + + memcpy(rte_pktmbuf_mtod(mbuf, void *), data, len); + rte_pktmbuf_data_len(mbuf) = len; + data_len -= len; + data += len; + + while (data_len > 0) { + m->next = rte_pktmbuf_alloc(mb_pool); + if (unlikely(m->next == NULL)) + return -1; + + m = m->next; + + /* Headroom is not needed in chained mbufs */ + rte_pktmbuf_prepend(m, rte_pktmbuf_headroom(m)); + m->pkt_len = 0; + m->data_len = 0; + + len = RTE_MIN(rte_pktmbuf_tailroom(m), data_len); + memcpy(rte_pktmbuf_mtod(m, void *), data, len); + rte_pktmbuf_data_len(m) = len; + + mbuf->nb_segs++; + data_len -= len; + data += len; + } + + return 0; +} + static uint16_t eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) { @@ -131,6 +172,7 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) uint16_t num_rx = 0; unsigned long num_rx_bytes = 0; unsigned int framecount, framenum; + uint16_t pkt_len; if (unlikely(nb_pkts == 0)) return 0; @@ -154,20 +196,29 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) break; } - /* drop packets that won't fit in the mbuf */ - if (ppd->tp_snaplen > rte_pktmbuf_tailroom(mbuf)) { + pkt_len = ppd->tp_snaplen; + pbuf = (uint8_t *)ppd + ppd->tp_mac; + + if (pkt_len <= rte_pktmbuf_tailroom(mbuf)) { + /* packet fits in a single mbuf */ + memcpy(rte_pktmbuf_mtod(mbuf, void *), pbuf, pkt_len); + rte_pktmbuf_data_len(mbuf) = pkt_len; + } else if (pkt_q->scatter_enabled) { + /* scatter into chained mbufs */ + if (unlikely(eth_af_packet_rx_scatter(pkt_q->mb_pool, + mbuf, pbuf, pkt_len) < 0)) { + rte_pktmbuf_free(mbuf); + pkt_q->rx_dropped_pkts++; + goto release_frame; + } + } else { + /* oversized and no scatter - drop */ rte_pktmbuf_free(mbuf); - ppd->tp_status = TP_STATUS_KERNEL; - if (++framenum >= framecount) - framenum = 0; pkt_q->rx_dropped_pkts++; - continue; + goto release_frame; } - /* packet will fit in the mbuf, go ahead and receive it */ - rte_pktmbuf_pkt_len(mbuf) = rte_pktmbuf_data_len(mbuf) = ppd->tp_snaplen; - pbuf = (uint8_t *) ppd + ppd->tp_mac; - memcpy(rte_pktmbuf_mtod(mbuf, void *), pbuf, rte_pktmbuf_data_len(mbuf)); + rte_pktmbuf_pkt_len(mbuf) = pkt_len; /* check for vlan info */ if (ppd->tp_status & TP_STATUS_VLAN_VALID) { @@ -188,16 +239,18 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) mbuf->ol_flags |= timestamp_dynflag; } - /* release incoming frame and advance ring buffer */ - ppd->tp_status = TP_STATUS_KERNEL; - if (++framenum >= framecount) - framenum = 0; mbuf->port = pkt_q->in_port; /* account for the receive frame */ - bufs[i] = mbuf; + bufs[num_rx] = mbuf; num_rx++; num_rx_bytes += mbuf->pkt_len; + +release_frame: + /* release incoming frame and advance ring buffer */ + ppd->tp_status = TP_STATUS_KERNEL; + if (++framenum >= framecount) + framenum = 0; } pkt_q->framenum = framenum; pkt_q->rx_pkts += num_rx; @@ -412,7 +465,8 @@ eth_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_MULTI_SEGS | RTE_ETH_TX_OFFLOAD_VLAN_INSERT; dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP | - RTE_ETH_RX_OFFLOAD_TIMESTAMP; + RTE_ETH_RX_OFFLOAD_TIMESTAMP | + RTE_ETH_RX_OFFLOAD_SCATTER; return 0; } @@ -579,26 +633,29 @@ eth_rx_queue_setup(struct rte_eth_dev *dev, struct pmd_internals *internals = dev->data->dev_private; struct pkt_rx_queue *pkt_q = &internals->rx_queue[rx_queue_id]; unsigned int buf_size, data_size; + bool scatter_enabled; pkt_q->mb_pool = mb_pool; - /* Now get the space available for data in the mbuf */ buf_size = rte_pktmbuf_data_room_size(pkt_q->mb_pool) - RTE_PKTMBUF_HEADROOM; data_size = internals->req.tp_frame_size; data_size -= TPACKET2_HDRLEN - sizeof(struct sockaddr_ll); - if (data_size > buf_size) { + scatter_enabled = !!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SCATTER); + + if (!scatter_enabled && data_size > buf_size) { PMD_LOG(ERR, - "%s: %d bytes will not fit in mbuf (%d bytes)", + "%s: %d bytes will not fit in mbuf (%d bytes), enable scatter offload", dev->device->name, data_size, buf_size); - return -ENOMEM; + return -EINVAL; } dev->data->rx_queues[rx_queue_id] = pkt_q; pkt_q->in_port = dev->data->port_id; pkt_q->vlan_strip = internals->vlan_strip; pkt_q->timestamp_offloading = internals->timestamp_offloading; + pkt_q->scatter_enabled = scatter_enabled; return 0; } -- 2.43.7 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v5] net/af_packet: add multi-segment mbuf support for jumbo frames 2026-03-18 9:47 ` [PATCH v5] " Sriram Yagnaraman @ 2026-03-23 23:42 ` Stephen Hemminger 2026-03-24 16:29 ` [PATCH v6] net/af_packet: add Rx scatter " Sriram Yagnaraman 1 sibling, 0 replies; 9+ messages in thread From: Stephen Hemminger @ 2026-03-23 23:42 UTC (permalink / raw) To: Sriram Yagnaraman; +Cc: dev, xavier.guillaume, robin.l.lin On Wed, 18 Mar 2026 10:47:26 +0100 Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> wrote: > Enable jumbo frame reception with default mbuf data room size by > chaining multiple mbufs when packet exceeds single mbuf tailroom. > > Scatter Rx is only enabled when RTE_ETH_RX_OFFLOAD_SCATTER is > requested. Packets are dropped if they exceed single mbuf size > and scatter is not enabled, or if mbuf allocation fails during > chaining. Error counter rx_dropped_pkts tracks all drops. > > This allows receiving 9KB jumbo frames using standard 2KB mbufs, > chaining ~5 segments per jumbo packet. > > Signed-off-by: Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> > --- In general looks good, but AI review found some things. Summary: Thanks for the v5, Sriram. A few comments below. 1) pkt_len is uint16_t but tp_snaplen is __u32 The scatter helper also takes uint16_t data_len, so anything above 64KB silently truncates. For jumbo frames this is fine in practice, but the type mismatch is a latent bug. Consider uint32_t for both, or at least a comment explaining why uint16_t is sufficient. 2) Scatter alloc failure should bump rx_nombuf, not just rx_dropped_pkts When rte_pktmbuf_alloc() fails for a chained segment inside eth_af_packet_rx_scatter(), only rx_dropped_pkts is incremented. The head mbuf alloc failure correctly bumps rx_nombuf. The scatter case is also a no-mbuf condition and should be reported as such, otherwise operators can't distinguish memory pressure from oversized-packet drops in the stats. 3) Reclaiming headroom in chained segments The prepend/zero-data_len/zero-pkt_len sequence works but is roundabout. Setting m->data_off = 0 directly would be cleaner and avoid the intermediate state where data_len is non-zero then immediately overwritten. 4) bufs[num_rx] fix looks correct The change from bufs[i] to bufs[num_rx] fixes a pre-existing gap in the output array when packets are dropped via continue. Good catch. Overall the structure looks solid — the scatter helper extraction is clean, the goto-based frame release avoids the earlier use-after-free risk, and the queue setup validation is correct. Full detail: ## Review: [PATCH v5] net/af_packet: add multi-segment mbuf support for jumbo frames ### Error: `eth_af_packet_rx_scatter()` leaks chained mbufs on allocation failure When `rte_pktmbuf_alloc()` fails inside the `while` loop, the function returns `-1`. The caller then calls `rte_pktmbuf_free(mbuf)` on the head mbuf. However, before the failure, previous iterations of the loop have already linked allocated segments via `m->next`. The question is whether `rte_pktmbuf_free()` walks the chain — it does, so segments linked before the failure *will* be freed. But there's a subtlety: `mbuf->nb_segs` is incremented for each successfully chained segment, and `rte_pktmbuf_free()` uses `nb_segs` to walk the chain. Since `nb_segs` and the `->next` linkage are kept in sync, this is actually correct. On closer inspection: **no leak here.** Disregard — the caller's `rte_pktmbuf_free(mbuf)` correctly frees the entire chain. (Keeping this analysis transparent so you can verify the reasoning.) ### Error: `pkt_len` declared as `uint16_t` but `tp_snaplen` is `uint32_t` — silent truncation `ppd->tp_snaplen` is `__u32` in the kernel's `tpacket2_hdr`. The patch declares `pkt_len` as `uint16_t`: ```c uint16_t pkt_len; ... pkt_len = ppd->tp_snaplen; ``` For jumbo frames up to 9KB this works, but `tp_snaplen` can be up to 65535 (or larger with cooked sockets). If `tp_snaplen > 65535` this silently truncates, and even values in the 32768–65535 range could cause issues if `pkt_len` is used in signed comparisons. More practically, the scatter helper also takes `uint16_t data_len`, capping the maximum receivable packet at 64KB. Since this patch specifically targets jumbo frames (9KB), the practical risk is low, but the type should match the source. Consider using `uint32_t` for `pkt_len` and the `data_len` parameter of `eth_af_packet_rx_scatter()`, or at minimum add a bounds check / comment explaining why `uint16_t` is sufficient. ### Error: `rte_pktmbuf_pkt_len(mbuf)` not set in the single-mbuf fast path before VLAN reinsertion In the patched code, the single-mbuf path sets `data_len` but defers setting `pkt_len` until after the VLAN/timestamp block: ```c if (pkt_len <= rte_pktmbuf_tailroom(mbuf)) { memcpy(rte_pktmbuf_mtod(mbuf, void *), pbuf, pkt_len); rte_pktmbuf_data_len(mbuf) = pkt_len; } else if (...) { ... } rte_pktmbuf_pkt_len(mbuf) = pkt_len; /* check for vlan info */ if (ppd->tp_status & TP_STATUS_VLAN_VALID) { ... if (!pkt_q->vlan_strip && rte_vlan_insert(&mbuf)) ``` `rte_vlan_insert()` reads `mbuf->pkt_len` to determine packet length. At that point `pkt_len` has been assigned to `rte_pktmbuf_pkt_len(mbuf)` — wait, looking again, `pkt_len` assignment is on the line *before* the VLAN block. Let me re-read the patch flow: ``` } else { ... goto release_frame; } rte_pktmbuf_pkt_len(mbuf) = pkt_len; // <-- this line /* check for vlan info */ ``` Yes, `pkt_len` is set before the VLAN check. This is correct. Disregard. ### Warning: `rx_nombuf` not incremented on scatter allocation failure In the original code, `rx_nombuf` is incremented when `rte_pktmbuf_alloc()` fails for the head mbuf. In the scatter path, when `rte_pktmbuf_alloc()` fails for a *chained* segment, only `rx_dropped_pkts` is incremented. This is arguably a no-mbuf condition and should also increment `rx_nombuf` so that `rte_eth_stats.rx_nombuf` accurately reflects memory pressure. The current code makes it impossible to distinguish "dropped because too large and no scatter" from "dropped because mbuf pool exhausted during scatter." Suggested fix: increment `pkt_q->rx_nombuf` instead of (or in addition to) `rx_dropped_pkts` when scatter allocation fails. ### Warning: `rte_pktmbuf_prepend()` return value unchecked In `eth_af_packet_rx_scatter()`: ```c rte_pktmbuf_prepend(m, rte_pktmbuf_headroom(m)); m->pkt_len = 0; m->data_len = 0; ``` `rte_pktmbuf_prepend()` can return `NULL` if the headroom requested exceeds available headroom (shouldn't happen for a freshly allocated mbuf, but it's defensive). More importantly, after `rte_pktmbuf_prepend()`, `data_len` is increased by the headroom amount, but then immediately overwritten to `0`. The `pkt_len` is similarly set to `0`. This sequence works but is fragile — a cleaner approach would be to directly manipulate `m->data_off = 0` to reclaim the headroom, which is what this is effectively doing. Consider: ```c m->data_off = 0; ``` This is simpler, less error-prone, and avoids the intermediate state where `data_len` contains a non-zero value that is immediately discarded. ### Warning: `scatter_enabled` read from `rxmode.offloads` in `rx_queue_setup` Per AGENTS.md guidance, reading from `dev->data->dev_conf.rxmode` after configure can become stale. In this case, `rx_queue_setup` is called between `dev_configure` and `dev_start`, so the value should be consistent. However, the canonical pattern in DPDK is to check `dev->data->scattered_rx` or the offloads via `dev->data->dev_conf.rxmode.offloads` (which is acceptable in queue setup since it runs in the configure-to-start window). This is borderline acceptable but worth noting — if `mtu_set` is called after queue setup, the scatter state won't be re-evaluated. The AF_PACKET PMD's `mtu_set` doesn't re-select Rx functions or re-evaluate scatter, which is a pre-existing gap not introduced by this patch. ### Info: `bufs[i]` changed to `bufs[num_rx]` — correct fix for existing bug The original code used `bufs[i]` which would leave gaps in the output array when packets are dropped (via `continue`). The change to `bufs[num_rx]` is correct and actually fixes a pre-existing bug in the drop path. Good catch in this patch. ### Info: Consider adding `rx_nombuf` tracking for the scatter failure case As noted above, distinguishing "no mbuf" from "oversized drop" in statistics would be valuable for debugging. Minor suggestion for a follow-up. ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v6] net/af_packet: add Rx scatter for jumbo frames 2026-03-18 9:47 ` [PATCH v5] " Sriram Yagnaraman 2026-03-23 23:42 ` Stephen Hemminger @ 2026-03-24 16:29 ` Sriram Yagnaraman 2026-03-25 17:31 ` Stephen Hemminger 1 sibling, 1 reply; 9+ messages in thread From: Sriram Yagnaraman @ 2026-03-24 16:29 UTC (permalink / raw) To: stephen; +Cc: dev, xavier.guillaume, robin.l.lin, Sriram Yagnaraman Enable jumbo frame reception with default mbuf data room size by chaining multiple mbufs when packet exceeds single mbuf tailroom. Scatter Rx is only enabled when RTE_ETH_RX_OFFLOAD_SCATTER is requested. Packets exceeding single mbuf size are dropped if scatter is not enabled. Allocation failures during chaining increment rx_nombuf. Oversized drops increment rx_dropped_pkts. Signed-off-by: Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> --- v6: - Use uint32_t for pkt_len and scatter data_len to match tp_snaplen type __u32. (Stephen Hemminger) - Increment rx_nombuf on scatter alloc failure instead of rx_dropped_pkts. (Stephen Hemminger) - Set m->data_off = 0 directly instead of rte_pktmbuf_prepend sequence for chained segments. (Stephen Hemminger) v5: - Rebased on main (26.03-rc2), removed Depends-on - Extracted scatter into eth_af_packet_rx_scatter() helper v4: - Added scatter validation in rx_queue_setup - Fixed control flow: goto instead of continue in scatter loop - Moved frame release to common label to prevent use-after-free v3: - Conditional scatter based on RTE_ETH_RX_OFFLOAD_SCATTER - Removed headroom from chained segments v2: - Fixed goto label to properly exit outer loop on alloc failure - Changed bufs indexing from [i] to [num_rx] doc/guides/rel_notes/release_26_03.rst | 5 ++ drivers/net/af_packet/rte_eth_af_packet.c | 95 ++++++++++++++++++----- 2 files changed, 80 insertions(+), 20 deletions(-) diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst index 3d2ed19eb8..54e3bdbcc7 100644 --- a/doc/guides/rel_notes/release_26_03.rst +++ b/doc/guides/rel_notes/release_26_03.rst @@ -65,6 +65,11 @@ New Features * Added support for V4000 Krackan2e. +* **Updated AF_PACKET ethernet driver.** + + * Added support for multi-segment mbuf reception to handle jumbo frames + with standard mbuf sizes when scatter Rx offload is enabled. + * **Updated CESNET nfb ethernet driver.** * The timestamp value has been updated to make it usable. diff --git a/drivers/net/af_packet/rte_eth_af_packet.c b/drivers/net/af_packet/rte_eth_af_packet.c index e132dc387b..0ee94e71ea 100644 --- a/drivers/net/af_packet/rte_eth_af_packet.c +++ b/drivers/net/af_packet/rte_eth_af_packet.c @@ -56,6 +56,7 @@ struct __rte_cache_aligned pkt_rx_queue { uint16_t in_port; uint8_t vlan_strip; uint8_t timestamp_offloading; + uint8_t scatter_enabled; volatile unsigned long rx_pkts; volatile unsigned long rx_bytes; @@ -120,6 +121,44 @@ RTE_LOG_REGISTER_DEFAULT(af_packet_logtype, NOTICE); RTE_LOG_LINE(level, AFPACKET, "%s(): " fmt ":%s", __func__, \ ## __VA_ARGS__, strerror(errno)) +/* + * Copy packet data into chained mbufs when it exceeds single mbuf tailroom. + * Returns 0 on success, -1 on mbuf allocation failure. + */ +static int +eth_af_packet_rx_scatter(struct rte_mempool *mb_pool, struct rte_mbuf *mbuf, + const uint8_t *data, uint32_t data_len) +{ + uint16_t len = rte_pktmbuf_tailroom(mbuf); + struct rte_mbuf *m = mbuf; + + memcpy(rte_pktmbuf_mtod(mbuf, void *), data, len); + rte_pktmbuf_data_len(mbuf) = len; + data_len -= len; + data += len; + + while (data_len > 0) { + m->next = rte_pktmbuf_alloc(mb_pool); + if (unlikely(m->next == NULL)) + return -1; + + m = m->next; + + /* Headroom is not needed in chained mbufs */ + m->data_off = 0; + + len = RTE_MIN(rte_pktmbuf_tailroom(m), data_len); + memcpy(rte_pktmbuf_mtod(m, void *), data, len); + rte_pktmbuf_data_len(m) = len; + + mbuf->nb_segs++; + data_len -= len; + data += len; + } + + return 0; +} + static uint16_t eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) { @@ -131,6 +170,7 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) uint16_t num_rx = 0; unsigned long num_rx_bytes = 0; unsigned int framecount, framenum; + uint32_t pkt_len; if (unlikely(nb_pkts == 0)) return 0; @@ -154,20 +194,29 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) break; } - /* drop packets that won't fit in the mbuf */ - if (ppd->tp_snaplen > rte_pktmbuf_tailroom(mbuf)) { + pkt_len = ppd->tp_snaplen; + pbuf = (uint8_t *)ppd + ppd->tp_mac; + + if (pkt_len <= rte_pktmbuf_tailroom(mbuf)) { + /* packet fits in a single mbuf */ + memcpy(rte_pktmbuf_mtod(mbuf, void *), pbuf, pkt_len); + rte_pktmbuf_data_len(mbuf) = pkt_len; + } else if (pkt_q->scatter_enabled) { + /* scatter into chained mbufs */ + if (unlikely(eth_af_packet_rx_scatter(pkt_q->mb_pool, + mbuf, pbuf, pkt_len) < 0)) { + rte_pktmbuf_free(mbuf); + pkt_q->rx_nombuf++; + goto release_frame; + } + } else { + /* oversized and no scatter - drop */ rte_pktmbuf_free(mbuf); - ppd->tp_status = TP_STATUS_KERNEL; - if (++framenum >= framecount) - framenum = 0; pkt_q->rx_dropped_pkts++; - continue; + goto release_frame; } - /* packet will fit in the mbuf, go ahead and receive it */ - rte_pktmbuf_pkt_len(mbuf) = rte_pktmbuf_data_len(mbuf) = ppd->tp_snaplen; - pbuf = (uint8_t *) ppd + ppd->tp_mac; - memcpy(rte_pktmbuf_mtod(mbuf, void *), pbuf, rte_pktmbuf_data_len(mbuf)); + rte_pktmbuf_pkt_len(mbuf) = pkt_len; /* check for vlan info */ if (ppd->tp_status & TP_STATUS_VLAN_VALID) { @@ -188,16 +237,18 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) mbuf->ol_flags |= timestamp_dynflag; } - /* release incoming frame and advance ring buffer */ - ppd->tp_status = TP_STATUS_KERNEL; - if (++framenum >= framecount) - framenum = 0; mbuf->port = pkt_q->in_port; /* account for the receive frame */ - bufs[i] = mbuf; + bufs[num_rx] = mbuf; num_rx++; num_rx_bytes += mbuf->pkt_len; + +release_frame: + /* release incoming frame and advance ring buffer */ + ppd->tp_status = TP_STATUS_KERNEL; + if (++framenum >= framecount) + framenum = 0; } pkt_q->framenum = framenum; pkt_q->rx_pkts += num_rx; @@ -412,7 +463,8 @@ eth_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_MULTI_SEGS | RTE_ETH_TX_OFFLOAD_VLAN_INSERT; dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP | - RTE_ETH_RX_OFFLOAD_TIMESTAMP; + RTE_ETH_RX_OFFLOAD_TIMESTAMP | + RTE_ETH_RX_OFFLOAD_SCATTER; return 0; } @@ -579,26 +631,29 @@ eth_rx_queue_setup(struct rte_eth_dev *dev, struct pmd_internals *internals = dev->data->dev_private; struct pkt_rx_queue *pkt_q = &internals->rx_queue[rx_queue_id]; unsigned int buf_size, data_size; + bool scatter_enabled; pkt_q->mb_pool = mb_pool; - /* Now get the space available for data in the mbuf */ buf_size = rte_pktmbuf_data_room_size(pkt_q->mb_pool) - RTE_PKTMBUF_HEADROOM; data_size = internals->req.tp_frame_size; data_size -= TPACKET2_HDRLEN - sizeof(struct sockaddr_ll); - if (data_size > buf_size) { + scatter_enabled = !!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SCATTER); + + if (!scatter_enabled && data_size > buf_size) { PMD_LOG(ERR, - "%s: %d bytes will not fit in mbuf (%d bytes)", + "%s: %d bytes will not fit in mbuf (%d bytes), enable scatter offload", dev->device->name, data_size, buf_size); - return -ENOMEM; + return -EINVAL; } dev->data->rx_queues[rx_queue_id] = pkt_q; pkt_q->in_port = dev->data->port_id; pkt_q->vlan_strip = internals->vlan_strip; pkt_q->timestamp_offloading = internals->timestamp_offloading; + pkt_q->scatter_enabled = scatter_enabled; return 0; } -- 2.43.7 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v6] net/af_packet: add Rx scatter for jumbo frames 2026-03-24 16:29 ` [PATCH v6] net/af_packet: add Rx scatter " Sriram Yagnaraman @ 2026-03-25 17:31 ` Stephen Hemminger 2026-03-26 13:01 ` Sriram Yagnaraman 0 siblings, 1 reply; 9+ messages in thread From: Stephen Hemminger @ 2026-03-25 17:31 UTC (permalink / raw) To: Sriram Yagnaraman; +Cc: dev, xavier.guillaume, robin.l.lin On Tue, 24 Mar 2026 17:29:52 +0100 Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> wrote: > +/* > + * Copy packet data into chained mbufs when it exceeds single mbuf tailroom. > + * Returns 0 on success, -1 on mbuf allocation failure. > + */ > +static int > +eth_af_packet_rx_scatter(struct rte_mempool *mb_pool, struct rte_mbuf *mbuf, > + const uint8_t *data, uint32_t data_len) > +{ > + uint16_t len = rte_pktmbuf_tailroom(mbuf); > + struct rte_mbuf *m = mbuf; > + > + memcpy(rte_pktmbuf_mtod(mbuf, void *), data, len); > + rte_pktmbuf_data_len(mbuf) = len; Very minor personal preference here. I prefer avoiding using rte_pktmbuf_data_len() and rte_pktmbuf_pkt_len() since they are really macros and the use of data_len and pkt_len directly is clearer in code that is manipulating other mbuf fields. Applied to next-net ^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: [PATCH v6] net/af_packet: add Rx scatter for jumbo frames 2026-03-25 17:31 ` Stephen Hemminger @ 2026-03-26 13:01 ` Sriram Yagnaraman 0 siblings, 0 replies; 9+ messages in thread From: Sriram Yagnaraman @ 2026-03-26 13:01 UTC (permalink / raw) To: Stephen Hemminger Cc: dev@dpdk.org, xavier.guillaume@ovhcloud.com, Robin Lin L > -----Original Message----- > From: Stephen Hemminger <stephen@networkplumber.org> > Sent: Wednesday, 25 March 2026 18:32 > To: Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> > Cc: dev@dpdk.org; xavier.guillaume@ovhcloud.com; Robin Lin L > <robin.l.lin@ericsson.com> > Subject: Re: [PATCH v6] net/af_packet: add Rx scatter for jumbo frames > > On Tue, 24 Mar 2026 17:29:52 +0100 > Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> wrote: > > > +/* > > + * Copy packet data into chained mbufs when it exceeds single mbuf > tailroom. > > + * Returns 0 on success, -1 on mbuf allocation failure. > > + */ > > +static int > > +eth_af_packet_rx_scatter(struct rte_mempool *mb_pool, struct rte_mbuf > *mbuf, > > + const uint8_t *data, uint32_t data_len) { > > + uint16_t len = rte_pktmbuf_tailroom(mbuf); > > + struct rte_mbuf *m = mbuf; > > + > > + memcpy(rte_pktmbuf_mtod(mbuf, void *), data, len); > > + rte_pktmbuf_data_len(mbuf) = len; > > Very minor personal preference here. I prefer avoiding using > rte_pktmbuf_data_len() and rte_pktmbuf_pkt_len() since they are really > macros and the use of data_len and pkt_len directly is clearer in code that is > manipulating other mbuf fields. > I agree, will keep in mind for future patches. Thank you for applying my patches. > Applied to next-net ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-03-26 13:01 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-12 7:34 [PATCH v3] net/af_packet: add multi-segment mbuf support for jumbo frames Sriram Yagnaraman 2026-03-12 16:06 ` Stephen Hemminger 2026-03-12 16:34 ` Stephen Hemminger 2026-03-13 9:10 ` [PATCH v4] " Sriram Yagnaraman 2026-03-18 9:47 ` [PATCH v5] " Sriram Yagnaraman 2026-03-23 23:42 ` Stephen Hemminger 2026-03-24 16:29 ` [PATCH v6] net/af_packet: add Rx scatter " Sriram Yagnaraman 2026-03-25 17:31 ` Stephen Hemminger 2026-03-26 13:01 ` Sriram Yagnaraman
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox