<div dir="auto">the coding style against bool is more of a keenel thing. </div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Mon, Jul 20, 2026, 10:33 Maxime Leroy <<a href="mailto:maxime@leroys.fr">maxime@leroys.fr</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Fri, Jul 17, 2026 at 2:34 PM Stephen Hemminger<br>
<<a href="mailto:stephen@networkplumber.org" target="_blank" rel="noreferrer">stephen@networkplumber.org</a>> wrote:<br>
><br>
> Don't use int as a boolean. Use bool. Ideally find unused pad hole for it<br>
<br>
Agreed int-as-a-boolean is not great. But bool in a structure is<br>
discouraged by coding_style.rst:<br>
<br>
   "Uses of bool in structures are not preferred as is wastes space and<br>
    it's also not clear as to what type size the bool is."  (Ref: LKML)<br>
<br>
and that very LKML reference is Linus recommending the opposite of<br>
bool for struct members:<br>
<br>
   "please don't use bool in structures at all. [...] Use bool mainly as a<br>
    return type from functions [...]. [...] just make sure the base type is<br>
    unsigned [...] you can specify the base type as you wish [...] for<br>
    packing."<br>
<br>
The current tap PMD follows that too: the existing flags (persist,<br>
flow_init, flow_isolate) are all int, and stdbool.h is not even<br>
included in the headers.<br>
<br>
So for v2 I'll use uint8_t for intr_mode and intr_mode_set: fixed<br>
1-byte size, unambiguous representation, and it fits the existing<br>
padding so neither struct grows (pmd_internals stays 144 bytes,<br>
rx_queue stays 80). That matches both the guide and the referenced<br>
LKML guidance.<br>
<br>
I can also add a third patch at the end of the series converting the<br>
existing int flags (persist, flow_init, flow_isolate) to uint8_t, to<br>
make the driver consistent<br>
<br>
><br>
> On Fri, Jul 17, 2026, 11:59 AM Maxime Leroy <<a href="mailto:maxime@leroys.fr" target="_blank" rel="noreferrer">maxime@leroys.fr</a>> wrote:<br>
>><br>
>> The tap Rx path is driven by a SIGIO trigger: pmd_rx_burst() returns<br>
>> without reading the queue fd unless tap_trigger, bumped by the O_ASYNC<br>
>> signal handler, has advanced. That avoids a readv() on every empty poll.<br>
>><br>
>> In Rx interrupt mode the application blocks on the queue fd through epoll<br>
>> and polls only after a wakeup. The epoll wakeup and the trigger are<br>
>> distinct signals, so the burst can return 0 right after a wakeup because<br>
>> the trigger has not advanced, leaving the fd readable with no further<br>
>> edge: traffic stalls.<br>
>><br>
>> When the port is configured for Rx interrupts, drain the fd<br>
>> unconditionally in the burst and do not arm the SIGIO trigger on the data<br>
>> queue fd. A data queue fd can be closed and recreated on a later setup,<br>
>> so the mode must stay constant to keep every fd on the same SIGIO policy:<br>
>> it is fixed at configure time and a later change is rejected. Close and<br>
>> reopen the port to switch modes.<br>
>><br>
>> Fixes: 4870a8cdd968 ("net/tap: support Rx interrupt")<br>
>> Cc: <a href="mailto:stable@dpdk.org" target="_blank" rel="noreferrer">stable@dpdk.org</a><br>
>><br>
>> Signed-off-by: Maxime Leroy <<a href="mailto:maxime@leroys.fr" target="_blank" rel="noreferrer">maxime@leroys.fr</a>><br>
>> ---<br>
>>  drivers/net/tap/rte_eth_tap.c | 18 +++++++++++++++++-<br>
>>  drivers/net/tap/rte_eth_tap.h |  2 ++<br>
>>  2 files changed, 19 insertions(+), 1 deletion(-)<br>
>><br>
>> diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c<br>
>> index 99ede19e49..ea9ef76335 100644<br>
>> --- a/drivers/net/tap/rte_eth_tap.c<br>
>> +++ b/drivers/net/tap/rte_eth_tap.c<br>
>> @@ -254,6 +254,10 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive, int persistent)<br>
>>                 goto error;<br>
>>         }<br>
>><br>
>> +       /* interrupt mode wakes through epoll on the data queue fd, not the SIGIO trigger */<br>
>> +       if (pmd->intr_mode)<br>
>> +               return fd;<br>
>> +<br>
>>         /* Find a free realtime signal */<br>
>>         for (signo = SIGRTMIN + 1; signo < SIGRTMAX; signo++) {<br>
>>                 struct sigaction sa;<br>
>> @@ -477,7 +481,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)<br>
>>         unsigned long num_rx_bytes = 0;<br>
>>         uint32_t trigger = tap_trigger;<br>
>><br>
>> -       if (trigger == rxq->trigger_seen)<br>
>> +       if (!rxq->intr_mode && trigger == rxq->trigger_seen)<br>
>>                 return 0;<br>
>><br>
>>         process_private = rte_eth_devices[rxq->in_port].process_private;<br>
>> @@ -937,6 +941,16 @@ tap_dev_configure(struct rte_eth_dev *dev)<br>
>>         struct pmd_internals *pmd = dev->data->dev_private;<br>
>>         int intr_mode = !!dev->data->dev_conf.intr_conf.rxq;<br>
>><br>
>> +       /* The queue fd is created once and its SIGIO trigger is armed for poll<br>
>> +        * mode only; the interrupt mode cannot be toggled on an existing port.<br>
>> +        */<br>
>> +       if (pmd->intr_mode_set && pmd->intr_mode != intr_mode) {<br>
>> +               TAP_LOG(ERR,<br>
>> +                       "%s: Rx interrupt mode is fixed after configure, close and reopen the port to change it",<br>
>> +                       dev->device->name);<br>
>> +               return -ENOTSUP;<br>
>> +       }<br>
>> +<br>
>>         if (dev->data->nb_rx_queues != dev->data->nb_tx_queues) {<br>
>>                 TAP_LOG(ERR,<br>
>>                         "%s: number of rx queues %d must be equal to number of tx queues %d",<br>
>> @@ -947,6 +961,7 @@ tap_dev_configure(struct rte_eth_dev *dev)<br>
>>         }<br>
>><br>
>>         pmd->intr_mode = intr_mode;<br>
>> +       pmd->intr_mode_set = 1;<br>
>><br>
>>         TAP_LOG(INFO, "%s: %s: TX configured queues number: %u",<br>
>>                 dev->device->name, pmd->name, dev->data->nb_tx_queues);<br>
>> @@ -1620,6 +1635,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev,<br>
>>         rxq->queue_id = rx_queue_id;<br>
>>         rxq->max_rx_segs = max_rx_segs;<br>
>>         rxq->rxmode = &dev->data->dev_conf.rxmode;<br>
>> +       rxq->intr_mode = internals->intr_mode;<br>
>><br>
>>         dev->data->rx_queues[rx_queue_id] = rxq;<br>
>>         int fd = tap_setup_queue(dev, rx_queue_id, 1);<br>
>> diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h<br>
>> index 3180719c34..abe22aac9f 100644<br>
>> --- a/drivers/net/tap/rte_eth_tap.h<br>
>> +++ b/drivers/net/tap/rte_eth_tap.h<br>
>> @@ -50,6 +50,7 @@ struct rx_queue {<br>
>>         uint16_t queue_id;              /* queue ID*/<br>
>>         struct queue_stats stats;        /* Stats for this RX queue */<br>
>>         uint16_t max_rx_segs;           /* max scatter segments per packet */<br>
>> +       uint16_t intr_mode;             /* 1 when Rx queue interrupts are used */<br>
>>         struct rte_eth_rxmode *rxmode;  /* RX features */<br>
>>         struct rte_mbuf *pool;          /* mbufs pool for this queue */<br>
>>         struct tun_pi pi;               /* packet info for iovecs */<br>
>> @@ -94,6 +95,7 @@ struct pmd_internals {<br>
>><br>
>>         struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */<br>
>>         int intr_mode;                    /* Rx queue interrupt mode */<br>
>> +       int intr_mode_set;                /* intr_mode locked after configure */<br>
>>         int ka_fd;                        /* keep-alive file descriptor */<br>
>>         struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */<br>
>>  };<br>
>> --<br>
>> 2.43.0<br>
>><br>
<br>
<br>
-- <br>
-------------------------------<br>
Maxime Leroy<br>
<a href="mailto:maxime@leroys.fr" target="_blank" rel="noreferrer">maxime@leroys.fr</a><br>
</blockquote></div>