patch 'net/pcap: fix error accounting and backpressure on Tx' has been queued to stable release 24.11.7

luca.boccassi at gmail.com luca.boccassi at gmail.com
Thu Jun 11 15:19:26 CEST 2026


Hi,

FYI, your patch has been queued to stable release 24.11.7

Note it hasn't been pushed to http://dpdk.org/browse/dpdk-stable yet.
It will be pushed if I get no objections before 06/13/26. So please
shout if anyone has objections.

Also note that after the patch there's a diff of the upstream commit vs the
patch applied to the branch. This will indicate if there was any rebasing
needed to apply to the stable branch. If there were code changes for rebasing
(ie: not only metadata diffs), please double check that the rebase was
correctly done.

Queued patches are on a temporary branch at:
https://github.com/bluca/dpdk-stable

This queued commit can be viewed at:
https://github.com/bluca/dpdk-stable/commit/fec5ff44c0a3ebf3eaef2b27c99d340097d828bd

Thanks.

Luca Boccassi

---
>From fec5ff44c0a3ebf3eaef2b27c99d340097d828bd Mon Sep 17 00:00:00 2001
From: Stephen Hemminger <stephen at networkplumber.org>
Date: Sun, 19 Apr 2026 09:09:42 -0700
Subject: [PATCH] net/pcap: fix error accounting and backpressure on Tx

[ upstream commit cf91cce204ea0fd9289d91e58d1b7c6ece385d56 ]

Correct two problems in eth_pcap_tx():

Oversized multi-segment packets that exceed the bounce buffer are
dropped but were not counted as errors. Add err_pkts accounting
for these drops.

When pcap_sendpacket() fails due to kernel socket backpressure,
the remaining unsent packets were counted as TX errors. Since
backpressure is transient (EAGAIN/EBUSY/EINTR), break the loop
and return the number of packets attempted so the caller retains
ownership of the unsent mbufs per tx_burst semantics.

Fixes: fbbbf553f268 ("net/pcap: fix concurrent multiseg Tx")

Signed-off-by: Stephen Hemminger <stephen at networkplumber.org>
---
 drivers/net/pcap/pcap_ethdev.c | 35 +++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 13 deletions(-)

diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index bcee58205d..589b61e84f 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -456,13 +456,22 @@ eth_tx_drop(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 }
 
 /*
- * Callback to handle sending packets through a real NIC.
+ * Send a burst of packets to a pcap device.
+ *
+ * On Linux, pcap_sendpacket() calls send() on a blocking PF_PACKET
+ * socket with default kernel buffer sizes and no TX ring (PACKET_TX_RING).
+ * The send() call only blocks when the kernel socket send buffer is full,
+ * providing limited backpressure.
+ *
+ * On error, pcap_sendpacket() returns non-zero and the loop breaks,
+ * leaving remaining packets unsent.
+ *
+ * Bottom line: backpressure is not an error.
  */
 static uint16_t
 eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 {
 	unsigned int i;
-	int ret;
 	struct rte_mbuf *mbuf;
 	struct pmd_process_private *pp;
 	struct pcap_tx_queue *tx_queue = queue;
@@ -470,7 +479,6 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	uint32_t tx_bytes = 0;
 	pcap_t *pcap;
 	unsigned char temp_data[RTE_ETH_PCAP_SNAPLEN];
-	size_t len;
 
 	pp = rte_eth_devices[tx_queue->port_id].process_private;
 	pcap = pp->tx_pcap[tx_queue->queue_id];
@@ -480,24 +488,26 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 
 	for (i = 0; i < nb_pkts; i++) {
 		mbuf = bufs[i];
-		len = rte_pktmbuf_pkt_len(mbuf);
+		uint32_t len = rte_pktmbuf_pkt_len(mbuf);
+		const uint8_t *data;
 		if (unlikely(!rte_pktmbuf_is_contiguous(mbuf) &&
 				len > sizeof(temp_data))) {
 			PMD_LOG(ERR,
-				"Dropping multi segment PCAP packet. Size (%zd) > max size (%zd).",
+				"Dropping multi segment PCAP packet. Size (%u) > max size (%zd).",
 				len, sizeof(temp_data));
+			tx_queue->tx_stat.err_pkts++;
 			rte_pktmbuf_free(mbuf);
 			continue;
 		}
 
-		/* rte_pktmbuf_read() returns a pointer to the data directly
-		 * in the mbuf (when the mbuf is contiguous) or, otherwise,
-		 * a pointer to temp_data after copying into it.
-		 */
-		ret = pcap_sendpacket(pcap,
-			rte_pktmbuf_read(mbuf, 0, len, temp_data), len);
-		if (unlikely(ret != 0))
+		data = rte_pktmbuf_read(mbuf, 0, len, temp_data);
+		RTE_ASSERT(data != NULL);
+
+		if (unlikely(pcap_sendpacket(pcap, data, len) != 0)) {
+			/* Assume failure is backpressure */
+			PMD_LOG(ERR, "pcap_sendpacket() failed: %s", pcap_geterr(pcap));
 			break;
+		}
 		num_tx++;
 		tx_bytes += len;
 		rte_pktmbuf_free(mbuf);
@@ -505,7 +515,6 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 
 	tx_queue->tx_stat.pkts += num_tx;
 	tx_queue->tx_stat.bytes += tx_bytes;
-	tx_queue->tx_stat.err_pkts += i - num_tx;
 
 	return i;
 }
-- 
2.47.3

---
  Diff of the applied patch vs upstream commit (please double-check if non-empty:
---
--- -	2026-06-11 14:20:02.041058524 +0100
+++ 0017-net-pcap-fix-error-accounting-and-backpressure-on-Tx.patch	2026-06-11 14:20:01.182745205 +0100
@@ -1 +1 @@
-From cf91cce204ea0fd9289d91e58d1b7c6ece385d56 Mon Sep 17 00:00:00 2001
+From fec5ff44c0a3ebf3eaef2b27c99d340097d828bd Mon Sep 17 00:00:00 2001
@@ -5,0 +6,2 @@
+[ upstream commit cf91cce204ea0fd9289d91e58d1b7c6ece385d56 ]
+
@@ -19 +20,0 @@
-Cc: stable at dpdk.org
@@ -23,2 +24,2 @@
- drivers/net/pcap/pcap_ethdev.c | 34 ++++++++++++++++++++++------------
- 1 file changed, 22 insertions(+), 12 deletions(-)
+ drivers/net/pcap/pcap_ethdev.c | 35 +++++++++++++++++++++-------------
+ 1 file changed, 22 insertions(+), 13 deletions(-)
@@ -27 +28 @@
-index 02d5cb591f..ca08b8e342 100644
+index bcee58205d..589b61e84f 100644
@@ -30 +31 @@
-@@ -462,7 +462,17 @@ eth_tx_drop(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+@@ -456,13 +456,22 @@ eth_tx_drop(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
@@ -49 +50,15 @@
-@@ -484,26 +494,27 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+ {
+ 	unsigned int i;
+-	int ret;
+ 	struct rte_mbuf *mbuf;
+ 	struct pmd_process_private *pp;
+ 	struct pcap_tx_queue *tx_queue = queue;
+@@ -470,7 +479,6 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+ 	uint32_t tx_bytes = 0;
+ 	pcap_t *pcap;
+ 	unsigned char temp_data[RTE_ETH_PCAP_SNAPLEN];
+-	size_t len;
+ 
+ 	pp = rte_eth_devices[tx_queue->port_id].process_private;
+ 	pcap = pp->tx_pcap[tx_queue->queue_id];
+@@ -480,24 +488,26 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
@@ -52,3 +67,2 @@
- 		struct rte_mbuf *mbuf = bufs[i];
--		size_t len = rte_pktmbuf_pkt_len(mbuf);
--		int ret;
+ 		mbuf = bufs[i];
+-		len = rte_pktmbuf_pkt_len(mbuf);
@@ -57 +70,0 @@
- 
@@ -59 +72 @@
- 				len > RTE_ETH_PCAP_SNAPSHOT_LEN)) {
+ 				len > sizeof(temp_data))) {
@@ -61,3 +74,3 @@
--				"Dropping multi segment PCAP packet. Size (%zd) > max size (%u).",
-+				"Dropping multi segment PCAP packet. Size (%u) > max size (%u).",
- 				len, RTE_ETH_PCAP_SNAPSHOT_LEN);
+-				"Dropping multi segment PCAP packet. Size (%zd) > max size (%zd).",
++				"Dropping multi segment PCAP packet. Size (%u) > max size (%zd).",
+ 				len, sizeof(temp_data));
@@ -87 +100 @@
-@@ -511,7 +522,6 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+@@ -505,7 +515,6 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)


More information about the stable mailing list