* [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