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 <[email protected]> > --- > 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

