[PATCH v20 12/25] net/pcap: support VLAN strip and insert offloads

Bruce Richardson bruce.richardson at intel.com
Mon Mar 16 15:04:59 CET 2026


On Tue, Mar 10, 2026 at 09:09:50AM -0700, Stephen Hemminger wrote:
> Add VLAN tag handling to the pcap PMD, consistent with how virtio
> and af_packet drivers implement it. This also gets used for
> capture of VLAN tagged packets when legacy pdump is used.
> 
> RX strip: when RTE_ETH_RX_OFFLOAD_VLAN_STRIP is enabled, the driver
> calls rte_vlan_strip() on received packets in both normal and
> infinite_rx modes. For infinite_rx, offloads are deferred to
> packet delivery rather than applied during ring fill, so the
> stored template packets remain unmodified.
> 
> TX insert: when RTE_MBUF_F_TX_VLAN is set on an mbuf, the driver
> inserts the VLAN tag via rte_vlan_insert() before writing to pcap
> or sending to the interface. Indirect or shared mbufs get a new
> header mbuf to avoid modifying the original.
> 
> Runtime reconfiguration is supported through vlan_offload_set,
> which propagates the strip setting to all active RX queues.
> 
> Signed-off-by: Stephen Hemminger <stephen at networkplumber.org>
> ---
>  doc/guides/nics/features/pcap.ini      |  1 +
>  doc/guides/nics/pcap.rst               | 11 +++
>  doc/guides/rel_notes/release_26_03.rst |  5 ++
>  drivers/net/pcap/pcap_ethdev.c         | 96 ++++++++++++++++++++++++--
>  4 files changed, 109 insertions(+), 4 deletions(-)
> 
> diff --git a/doc/guides/nics/features/pcap.ini b/doc/guides/nics/features/pcap.ini
> index c4f0360a06..ec7c91c650 100644
> --- a/doc/guides/nics/features/pcap.ini
> +++ b/doc/guides/nics/features/pcap.ini
> @@ -9,6 +9,7 @@ Queue start/stop     = Y
>  Timestamp offload    = Y
>  Basic stats          = Y
>  Stats per queue      = Y
> +VLAN offload         = Y
>  Multiprocess aware   = Y
>  FreeBSD              = Y
>  Linux                = Y
> diff --git a/doc/guides/nics/pcap.rst b/doc/guides/nics/pcap.rst
> index fbfe854bb1..bed5006a42 100644
> --- a/doc/guides/nics/pcap.rst
> +++ b/doc/guides/nics/pcap.rst
> @@ -247,3 +247,14 @@ will be discarded by the Rx flushing operation.
>     The network interface provided to the PMD should be up.
>     The PMD will return an error if the interface is down,
>     and the PMD itself won't change the status of the external network interface.
> +
> +Features and Limitations
> +~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +*  The PMD will re-insert the VLAN tag transparently to the packet if the kernel
> +   strips it, as long as the ``RTE_ETH_RX_OFFLOAD_VLAN_STRIP`` is not enabled by the
> +   application.
> +
> +*  The PMD will transparently insert a VLAN tag to transmitted packets if
> +   ``RTE_ETH_TX_OFFLOAD_VLAN_INSERT`` is enabled and the mbuf has ``RTE_MBUF_F_TX_VLAN``
> +   set.
> diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
> index d121951f5c..6aef623bf8 100644
> --- a/doc/guides/rel_notes/release_26_03.rst
> +++ b/doc/guides/rel_notes/release_26_03.rst
> @@ -118,6 +118,11 @@ New Features
>    Added handling of the key combination Control+L
>    to clear the screen before redisplaying the prompt.
>  
> +* **Updated PCAP ethernet driver.**
> +
> +  * Added support for VLAN insertion and stripping.
> +
> +
>  Removed Items
>  -------------
>  
> diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
> index c3270a676c..c49ca7fa2b 100644
> --- a/drivers/net/pcap/pcap_ethdev.c
> +++ b/drivers/net/pcap/pcap_ethdev.c
> @@ -76,6 +76,7 @@ struct queue_missed_stat {
>  struct pcap_rx_queue {
>  	uint16_t port_id;
>  	uint16_t queue_id;
> +	bool vlan_strip;
>  	struct rte_mempool *mb_pool;
>  	struct queue_stat rx_stat;
>  	struct queue_missed_stat missed_stat;
> @@ -106,6 +107,7 @@ struct pmd_internals {
>  	bool single_iface;
>  	bool phy_mac;
>  	bool infinite_rx;
> +	bool vlan_strip;
>  };
>  
>  struct pmd_process_private {
> @@ -270,7 +272,11 @@ eth_pcap_rx_infinite(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
>  		bufs[i]->data_len = pcap_buf->data_len;
>  		bufs[i]->pkt_len = pcap_buf->pkt_len;
>  		bufs[i]->port = pcap_q->port_id;
> -		rx_bytes += pcap_buf->data_len;
> +
> +		if (pcap_q->vlan_strip)
> +			rte_vlan_strip(bufs[i]);
> +
> +		rx_bytes += bufs[i]->data_len;
>  
>  		/* Enqueue packet back on ring to allow infinite rx. */
>  		rte_ring_enqueue(pcap_q->pkts, pcap_buf);
> @@ -336,6 +342,10 @@ eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
>  		}
>  
>  		mbuf->pkt_len = len;
> +
> +		if (pcap_q->vlan_strip)
> +			rte_vlan_strip(mbuf);
> +
>  		uint64_t us = (uint64_t)header->ts.tv_sec * US_PER_S + header->ts.tv_usec;
>  
>  		*RTE_MBUF_DYNFIELD(mbuf, timestamp_dynfield_offset, rte_mbuf_timestamp_t *) = us;
> @@ -382,6 +392,39 @@ calculate_timestamp(struct timeval *ts) {
>  	}
>  }
>  
> +static uint16_t
> +eth_pcap_tx_prepare(void *queue __rte_unused, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
> +{
> +	uint16_t nb_tx;
> +	int error;
> +
> +	for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
> +		struct rte_mbuf *m = tx_pkts[nb_tx];
> +
> +#ifdef RTE_LIBRTE_ETHDEV_DEBUG
> +		error = rte_validate_tx_offload(m);
> +		if (unlikely(error)) {
> +			rte_errno = -error;
> +			break;
> +		}
> +#endif
> +		/* Do VLAN tag insertion */
> +		if (unlikely(m->ol_flags & RTE_MBUF_F_TX_VLAN)) {
> +			error = rte_vlan_insert(&m);
> +
> +			/* rte_vlan_insert() could change pointer (currently does not) */
> +			tx_pkts[nb_tx] = m;
> +
> +			if (unlikely(error != 0)) {
> +				PMD_TX_LOG(ERR, "rte_vlan_insert failed: %s", strerror(-error));
> +				rte_errno = -error;
> +				break;
> +			}
> +		}
> +	}
> +	return nb_tx;
> +}
> +

Are we sure this is the correct way to do this? To behave like a normal NIC
the Tx VLAN tag should be inserted in the Tx function, rather than tx
prepare should it not? There is no guarantee apps will call tx_prepare
before Tx.

/Bruce


More information about the dev mailing list