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

Reply via email to