[PATCH v21 22/25] net/pcap: add Rx scatter offload

Stephen Hemminger
2026-03-25T02:42:28Z

Add RTE_ETH_RX_OFFLOAD_SCATTER to the advertised receive offload
capabilities if not using infinite_rx mode.

Validate in rx_queue_setup that the mbuf pool data room is
large enough when scatter is not enabled, following the
same pattern as the virtio driver.

Gate the multi-segment receive path on the scatter offload flag
and drop oversized packets when scatter is disabled.
Reject scatter with infinite_rx mode since the ring-based replay
path does not support multi-segment mbufs.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
drivers/net/pcap/pcap_ethdev.c | 47 ++++++++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index 2de9c85124..9b1fbdba3d 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -79,6 +79,7 @@ struct pcap_rx_queue {
uint16_t port_id;
uint16_t queue_id;
bool vlan_strip;
+ bool rx_scatter;
bool timestamp_offloading;
struct rte_mempool *mb_pool;
struct queue_stat rx_stat;
@@ -112,6 +113,7 @@ struct pmd_internals {
bool phy_mac;
bool infinite_rx;
bool vlan_strip;
+ bool rx_scatter;
bool timestamp_offloading;
};

@@ -342,14 +344,19 @@ eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
/* pcap packet will fit in the mbuf, can copy it */
rte_memcpy(rte_pktmbuf_mtod(mbuf, void *), packet, len);
mbuf->data_len = len;
- } else {
- /* Try read jumbo frame into multi mbufs. */
+ } else if (pcap_q->rx_scatter) {
+ /* Scatter into multi-segment mbufs. */
if (unlikely(eth_pcap_rx_jumbo(pcap_q->mb_pool,
mbuf, packet, len) == -1)) {
pcap_q->rx_stat.err_pkts++;
rte_pktmbuf_free(mbuf);
break;
}
+ } else {
+ /* Packet too large and scatter not enabled, drop it. */
+ pcap_q->rx_stat.err_pkts++;
+ rte_pktmbuf_free(mbuf);
+ continue;
}

mbuf->pkt_len = len;
@@ -904,6 +911,7 @@ eth_dev_configure(struct rte_eth_dev *dev)
const struct rte_eth_rxmode *rxmode = &dev_conf->rxmode;

internals->vlan_strip = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_STRIP);
+ internals->rx_scatter = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_SCATTER);
internals->timestamp_offloading = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP);

if (internals->timestamp_offloading && timestamp_rx_dynflag == 0) {
@@ -936,6 +944,9 @@ eth_dev_info(struct rte_eth_dev *dev,
dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
RTE_ETH_RX_OFFLOAD_TIMESTAMP;

+ if (!internals->infinite_rx)
+ dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_SCATTER;
+
return 0;
}

@@ -1095,11 +1106,37 @@ eth_rx_queue_setup(struct rte_eth_dev *dev,
{
struct pmd_internals *internals = dev->data->dev_private;
struct pcap_rx_queue *pcap_q = &internals->rx_queue[rx_queue_id];
+ uint16_t buf_size;
+ bool rx_scatter;
+
+ buf_size = rte_pktmbuf_data_room_size(mb_pool) - RTE_PKTMBUF_HEADROOM;
+ rx_scatter = !!(dev->data->dev_conf.rxmode.offloads &
+ RTE_ETH_RX_OFFLOAD_SCATTER);
+
+ /*
+ * If Rx scatter is not enabled, verify that the mbuf data room
+ * can hold the largest received packet in a single segment.
+ * Use the MTU-derived frame size as the expected maximum, not
+ * snapshot_len which is a capture truncation limit rather than
+ * an expected packet size.
+ */
+ if (!rx_scatter) {
+ uint32_t max_rx_pktlen = dev->data->mtu + RTE_ETHER_HDR_LEN;
+
+ if (max_rx_pktlen > buf_size) {
+ PMD_LOG(ERR,
+ "Rx scatter is disabled and RxQ mbuf pool object size is too small "
+ "(buf_size=%u, max_rx_pkt_len=%u)",
+ buf_size, max_rx_pktlen);
+ return -EINVAL;
+ }
+ }

pcap_q->mb_pool = mb_pool;
pcap_q->port_id = dev->data->port_id;
pcap_q->queue_id = rx_queue_id;
pcap_q->vlan_strip = internals->vlan_strip;
+ pcap_q->rx_scatter = rx_scatter;
dev->data->rx_queues[rx_queue_id] = pcap_q;
pcap_q->timestamp_offloading = internals->timestamp_offloading;

@@ -1112,6 +1149,12 @@ eth_rx_queue_setup(struct rte_eth_dev *dev,
pcap_t **pcap;
bool save_vlan_strip;

+ if (rx_scatter) {
+ PMD_LOG(ERR,
+ "Rx scatter is not supported with infinite_rx mode");
+ return -EINVAL;
+ }
+
pp = rte_eth_devices[pcap_q->port_id].process_private;
pcap = &pp->rx_pcap[pcap_q->queue_id];

--
2.53.0