Re: [PATCH 2/2] net/tap: drain queue FD in Rx interrupt mode

Maxime Leroy <[email protected]>
Newsgroups org.dpdk.dev
Message-ID <CAHHRULUiZp2bLHONoDPhqexWd_ptXRLAQYVC=V3ojXonhecq1g@mail.gmail.com>
On Fri, Jul 17, 2026 at 2:34 PM Stephen Hemminger
<[email protected]> wrote:
>
> Don't use int as a boolean. Use bool. Ideally find unused pad hole for it

Agreed int-as-a-boolean is not great. But bool in a structure is
discouraged by coding_style.rst:

   "Uses of bool in structures are not preferred as is wastes space and
    it's also not clear as to what type size the bool is."  (Ref: LKML)

and that very LKML reference is Linus recommending the opposite of
bool for struct members:

   "please don't use bool in structures at all. [...] Use bool mainly as a
    return type from functions [...]. [...] just make sure the base type is
    unsigned [...] you can specify the base type as you wish [...] for
    packing."

The current tap PMD follows that too: the existing flags (persist,
flow_init, flow_isolate) are all int, and stdbool.h is not even
included in the headers.

So for v2 I'll use uint8_t for intr_mode and intr_mode_set: fixed
1-byte size, unambiguous representation, and it fits the existing
padding so neither struct grows (pmd_internals stays 144 bytes,
rx_queue stays 80). That matches both the guide and the referenced
LKML guidance.

I can also add a third patch at the end of the series converting the
existing int flags (persist, flow_init, flow_isolate) to uint8_t, to
make the driver consistent

>
> On Fri, Jul 17, 2026, 11:59 AM Maxime Leroy <[email protected]> wrote:
>>
>> The tap Rx path is driven by a SIGIO trigger: pmd_rx_burst() returns
>> without reading the queue fd unless tap_trigger, bumped by the O_ASYNC
>> signal handler, has advanced. That avoids a readv() on every empty poll.
>>
>> In Rx interrupt mode the application blocks on the queue fd through epoll
>> and polls only after a wakeup. The epoll wakeup and the trigger are
>> distinct signals, so the burst can return 0 right after a wakeup because
>> the trigger has not advanced, leaving the fd readable with no further
>> edge: traffic stalls.
>>
>> When the port is configured for Rx interrupts, drain the fd
>> unconditionally in the burst and do not arm the SIGIO trigger on the data
>> queue fd. A data queue fd can be closed and recreated on a later setup,
>> so the mode must stay constant to keep every fd on the same SIGIO policy:
>> it is fixed at configure time and a later change is rejected. Close and
>> reopen the port to switch modes.
>>
>> Fixes: 4870a8cdd968 ("net/tap: support Rx interrupt")
>> Cc: [email protected]
>>
>> Signed-off-by: Maxime Leroy <[email protected]>
>> ---
>>  drivers/net/tap/rte_eth_tap.c | 18 +++++++++++++++++-
>>  drivers/net/tap/rte_eth_tap.h |  2 ++
>>  2 files changed, 19 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
>> index 99ede19e49..ea9ef76335 100644
>> --- a/drivers/net/tap/rte_eth_tap.c
>> +++ b/drivers/net/tap/rte_eth_tap.c
>> @@ -254,6 +254,10 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive, int persistent)
>>                 goto error;
>>         }
>>
>> +       /* interrupt mode wakes through epoll on the data queue fd, not the SIGIO trigger */
>> +       if (pmd->intr_mode)
>> +               return fd;
>> +
>>         /* Find a free realtime signal */
>>         for (signo = SIGRTMIN + 1; signo < SIGRTMAX; signo++) {
>>                 struct sigaction sa;
>> @@ -477,7 +481,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
>>         unsigned long num_rx_bytes = 0;
>>         uint32_t trigger = tap_trigger;
>>
>> -       if (trigger == rxq->trigger_seen)
>> +       if (!rxq->intr_mode && trigger == rxq->trigger_seen)
>>                 return 0;
>>
>>         process_private = rte_eth_devices[rxq->in_port].process_private;
>> @@ -937,6 +941,16 @@ tap_dev_configure(struct rte_eth_dev *dev)
>>         struct pmd_internals *pmd = dev->data->dev_private;
>>         int intr_mode = !!dev->data->dev_conf.intr_conf.rxq;
>>
>> +       /* The queue fd is created once and its SIGIO trigger is armed for poll
>> +        * mode only; the interrupt mode cannot be toggled on an existing port.
>> +        */
>> +       if (pmd->intr_mode_set && pmd->intr_mode != intr_mode) {
>> +               TAP_LOG(ERR,
>> +                       "%s: Rx interrupt mode is fixed after configure, close and reopen the port to change it",
>> +                       dev->device->name);
>> +               return -ENOTSUP;
>> +       }
>> +
>>         if (dev->data->nb_rx_queues != dev->data->nb_tx_queues) {
>>                 TAP_LOG(ERR,
>>                         "%s: number of rx queues %d must be equal to number of tx queues %d",
>> @@ -947,6 +961,7 @@ tap_dev_configure(struct rte_eth_dev *dev)
>>         }
>>
>>         pmd->intr_mode = intr_mode;
>> +       pmd->intr_mode_set = 1;
>>
>>         TAP_LOG(INFO, "%s: %s: TX configured queues number: %u",
>>                 dev->device->name, pmd->name, dev->data->nb_tx_queues);
>> @@ -1620,6 +1635,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev,
>>         rxq->queue_id = rx_queue_id;
>>         rxq->max_rx_segs = max_rx_segs;
>>         rxq->rxmode = &dev->data->dev_conf.rxmode;
>> +       rxq->intr_mode = internals->intr_mode;
>>
>>         dev->data->rx_queues[rx_queue_id] = rxq;
>>         int fd = tap_setup_queue(dev, rx_queue_id, 1);
>> diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
>> index 3180719c34..abe22aac9f 100644
>> --- a/drivers/net/tap/rte_eth_tap.h
>> +++ b/drivers/net/tap/rte_eth_tap.h
>> @@ -50,6 +50,7 @@ struct rx_queue {
>>         uint16_t queue_id;              /* queue ID*/
>>         struct queue_stats stats;        /* Stats for this RX queue */
>>         uint16_t max_rx_segs;           /* max scatter segments per packet */
>> +       uint16_t intr_mode;             /* 1 when Rx queue interrupts are used */
>>         struct rte_eth_rxmode *rxmode;  /* RX features */
>>         struct rte_mbuf *pool;          /* mbufs pool for this queue */
>>         struct tun_pi pi;               /* packet info for iovecs */
>> @@ -94,6 +95,7 @@ struct pmd_internals {
>>
>>         struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
>>         int intr_mode;                    /* Rx queue interrupt mode */
>> +       int intr_mode_set;                /* intr_mode locked after configure */
>>         int ka_fd;                        /* keep-alive file descriptor */
>>         struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */
>>  };
>> --
>> 2.43.0
>>


-- 
-------------------------------
Maxime Leroy
[email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.