Enable jumbo frame reception with default mbuf data room size by
chaining multiple mbufs when packet exceeds single mbuf tailroom.
The RX path now:
- Copies first segment up to mbuf tailroom
- Allocates and chains additional segments for remaining data
- Properly maintains nb_segs, next pointers, and pkt_len
- Drops packets only on mbuf allocation failure
This allows receiving 9KB jumbo frames using standard 2KB mbufs,
chaining ~5 segments per jumbo packet. No need for custom mbuf
pools with large data room.
Advertises RTE_ETH_RX_OFFLOAD_SCATTER capability.
Depends-on: series-34567 ("net/af_packet: fix MTU handling and add
jumbo frame support")
Note: Implementation generated with AI assistance.
Signed-off-by: Sriram Yagnaraman <[email protected]>
---
drivers/net/af_packet/rte_eth_af_packet.c | 53 ++++++++++++++++++-----
1 file changed, 43 insertions(+), 10 deletions(-)
diff --git a/drivers/net/af_packet/rte_eth_af_packet.c
b/drivers/net/af_packet/rte_eth_af_packet.c
index d9fafd4..a18bc41 100644
--- a/drivers/net/af_packet/rte_eth_af_packet.c
+++ b/drivers/net/af_packet/rte_eth_af_packet.c
@@ -121,12 +121,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;
+ uint32_t pkt_len, data_len, remaining;
if (unlikely(nb_pkts == 0))
return 0;
@@ -148,10 +149,36 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs,
uint16_t nb_pkts)
if (unlikely(mbuf == NULL))
break;
- /* packet will fit in the mbuf, go ahead and receive it */
- rte_pktmbuf_pkt_len(mbuf) = rte_pktmbuf_data_len(mbuf) =
ppd->tp_snaplen;
+ pkt_len = ppd->tp_snaplen;
pbuf = (uint8_t *) ppd + ppd->tp_mac;
- memcpy(rte_pktmbuf_mtod(mbuf, void *), pbuf,
rte_pktmbuf_data_len(mbuf));
+
+ /* copy data to mbuf chain */
+ 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;
+ remaining = pkt_len - data_len;
+ pbuf += data_len;
+ prev = mbuf;
+
+ while (remaining > 0) {
+ seg = rte_pktmbuf_alloc(pkt_q->mb_pool);
+ if (unlikely(seg == NULL)) {
+ rte_pktmbuf_free(mbuf);
+ goto drop;
+ }
+
+ 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++;
+ }
+
+ rte_pktmbuf_pkt_len(mbuf) = pkt_len;
/* check for vlan info */
if (ppd->tp_status & TP_STATUS_VLAN_VALID) {
@@ -172,16 +199,21 @@ eth_af_packet_rx(void *queue, struct rte_mbuf **bufs,
uint16_t nb_pkts)
mbuf->ol_flags |= timestamp_dynflag;
}
+drop:
/* 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;
- num_rx++;
- num_rx_bytes += mbuf->pkt_len;
+ if (mbuf != NULL) {
+ mbuf->port = pkt_q->in_port;
+ /* account for the receive frame */
+ bufs[num_rx] = mbuf;
+ num_rx++;
+ num_rx_bytes += mbuf->pkt_len;
+ } else {
+ pkt_q->rx_dropped_pkts++;
+ }
}
pkt_q->framenum = framenum;
pkt_q->rx_pkts += num_rx;
@@ -411,7 +443,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;
}
--
2.43.7