Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net 2/2] net: xilinx: axienet: Fix BQL accounting for multi-BD TX packets
From: Sean Anderson @ 2026-03-26 19:56 UTC (permalink / raw)
  To: Gupta, Suraj, andrew+netdev@lunn.ch, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	Simek, Michal, Pandey, Radhey Shyam, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, Katakam, Harini
In-Reply-To: <SA1PR12MB679810BDE0FD91B702A869C2C956A@SA1PR12MB6798.namprd12.prod.outlook.com>

On 3/26/26 15:51, Gupta, Suraj wrote:
> [Public]
> 
>> -----Original Message-----
>> From: Sean Anderson <sean.anderson@linux.dev>
>> Sent: Thursday, March 26, 2026 9:08 PM
>> To: Gupta, Suraj <Suraj.Gupta2@amd.com>; andrew+netdev@lunn.ch;
>> davem@davemloft.net; edumazet@google.com; kuba@kernel.org;
>> pabeni@redhat.com; Simek, Michal <michal.simek@amd.com>; Pandey,
>> Radhey Shyam <radhey.shyam.pandey@amd.com>; horms@kernel.org
>> Cc: netdev@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-
>> kernel@vger.kernel.org; Katakam, Harini <harini.katakam@amd.com>
>> Subject: Re: [PATCH net 2/2] net: xilinx: axienet: Fix BQL accounting for multi-BD
>> TX packets
>>
>> Caution: This message originated from an External Source. Use proper caution
>> when opening attachments, clicking links, or responding.
>>
>>
>> On 3/25/26 01:30, Gupta, Suraj wrote:
>> > [Public]
>> >
>> >> -----Original Message-----
>> >> From: Sean Anderson <sean.anderson@linux.dev>
>> >> Sent: Tuesday, March 24, 2026 9:39 PM
>> >> To: Gupta, Suraj <Suraj.Gupta2@amd.com>; andrew+netdev@lunn.ch;
>> >> davem@davemloft.net; edumazet@google.com; kuba@kernel.org;
>> >> pabeni@redhat.com; Simek, Michal <michal.simek@amd.com>; Pandey,
>> >> Radhey Shyam <radhey.shyam.pandey@amd.com>; horms@kernel.org
>> >> Cc: netdev@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
>> >> linux- kernel@vger.kernel.org; Katakam, Harini
>> >> <harini.katakam@amd.com>
>> >> Subject: Re: [PATCH net 2/2] net: xilinx: axienet: Fix BQL accounting
>> >> for multi-BD TX packets
>> >>
>> >> Caution: This message originated from an External Source. Use proper
>> >> caution when opening attachments, clicking links, or responding.
>> >>
>> >>
>> >> On 3/24/26 10:53, Suraj Gupta wrote:
>> >> > When a TX packet spans multiple buffer descriptors
>> >> > (scatter-gather), the per-BD byte count is accumulated into a local
>> >> > variable that resets on each NAPI poll. If the BDs for a single
>> >> > packet complete across different polls, the earlier bytes are lost and never
>> credited to BQL.
>> >> > This causes BQL to think bytes are permanently in-flight,
>> >> > eventually stalling the TX queue.
>> >> >
>> >> > Fix this by replacing the local accumulator with a persistent
>> >> > counter
>> >> > (tx_compl_bytes) that survives across polls and is reset only after
>> >> > updating BQL and stats.
>> >>
>> >> Do we need this? Can't we just do something like
>> >>
>> >
>> > Nope, the 'size' variable passed to axienet_free_tx_chain() is local
>> > to axienet_tx_poll() and goes out of scope between different polls.
>> > This means it can't track completion bytes across multiple NAPI polls.
>>
>> Yes, but that's fine since we only update completed bytes when we retire at
>> least one packet:
>>
>>         packets = axienet_free_tx_chain(lp, &size, budget);
>>         if (packets) {
>>                 netdev_completed_queue(ndev, packets, size);
>>                 u64_stats_update_begin(&lp->tx_stat_sync);
>>                 u64_stats_add(&lp->tx_packets, packets);
>>                 u64_stats_add(&lp->tx_bytes, size);
>>                 u64_stats_update_end(&lp->tx_stat_sync);
>>
>>                 /* Matches barrier in axienet_start_xmit */
>>                 smp_mb();
>>                 if (((tail - ci) & (lp->rx_bd_num - 1)) >= MAX_SKB_FRAGS + 1)
>>                         netif_wake_queue(ndev);
>>         }
>>
>> and this matches the value we use when enqueuing a packet
>>
>>         tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * (last_p - lp->tx_bd_v);
>>         smp_store_release(&lp->tx_bd_tail, new_tail_ptr);
>>         netdev_sent_queue(ndev, skb->len);
>>
> 
> Let’s say we have a packet with 4 fragments. When xmit() is called, the last buffer descriptor (the 4th one) is marked with the retiral flag[1]. Now, during completion, suppose the first 3 buffer descriptors are processed in one NAPI poll, and the 4th descriptor is handled in a subsequent poll. In this scenario, the size won’t get updated for the first 3 BDs because there’s no packet retiral for them. Then, during the second poll, the size update will only reflect the completion length of the 4th BD.

That's why I suggested using skb->len and not the size from the descriptor.

--Sean

> This means that the bytes corresponding to the first 3 fragments are never credited to BQL, which leads to incorrect accounting and, eventually, to the TX queue stalling as described.
> Proposed changes to accumulate the completion length across polls until the entire packet is processed directly addresses this gap.
> 
> [1]: https://elixir.bootlin.com/linux/v7.0-rc5/source/drivers/net/ethernet/xilinx/xilinx_axienet_main.c#L1127
> 
> 
> Regards,
> Suraj
> 
>> > Regards,
>> > Suraj
>> >
>> >> diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> >> b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> >> index 415e9bc252527..1ea8a6592bce1 100644
>> >> --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> >> +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> >> @@ -768,6 +768,7 @@ static int axienet_free_tx_chain(struct
>> >> axienet_local *lp, u32 *sizep, int budge
>> >>                 if (cur_p->skb) {
>> >>                         struct axienet_cb *cb = (void
>> >> *)cur_p->skb->cb;
>> >>
>> >> +                       *sizep += skb->len;
>> >>                         dma_unmap_sgtable(lp->dev, &cb->sgt, DMA_TO_DEVICE, 0);
>> >>                         sg_free_table_chained(&cb->sgt, XAE_INLINE_SG_CNT);
>> >>                         napi_consume_skb(cur_p->skb, budget); @@
>> >> -783,8 +784,6 @@ static int axienet_free_tx_chain(struct axienet_local *lp,
>> u32 *sizep, int budge
>> >>                 wmb();
>> >>                 cur_p->cntrl = 0;
>> >>                 cur_p->status = 0;
>> >> -
>> >> -               *sizep += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
>> >>         }
>> >>
>> >>         smp_store_release(&lp->tx_bd_ci, (ci + i) & (lp->tx_bd_num -
>> >> 1));
>> >>
>> >> > Fixes: c900e49d58eb ("net: xilinx: axienet: Implement BQL")
>> >> > Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
>> >> > ---
>> >> >  drivers/net/ethernet/xilinx/xilinx_axienet.h  |  3 +++
>> >> > .../net/ethernet/xilinx/xilinx_axienet_main.c | 20
>> >> > +++++++++----------
>> >> >  2 files changed, 13 insertions(+), 10 deletions(-)
>> >> >
>> >> > diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h
>> >> > b/drivers/net/ethernet/xilinx/xilinx_axienet.h
>> >> > index 602389843342..a4444c939451 100644
>> >> > --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
>> >> > +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
>> >> > @@ -509,6 +509,8 @@ struct skbuf_dma_descriptor {
>> >> >   *           complete. Only updated at runtime by TX NAPI poll.
>> >> >   * @tx_bd_tail:      Stores the index of the next Tx buffer descriptor in the
>> ring
>> >> >   *              to be populated.
>> >> > + * @tx_compl_bytes: Accumulates TX completion length until a full
>> packet is
>> >> > + *              reported to the stack.
>> >> >   * @tx_packets: TX packet count for statistics
>> >> >   * @tx_bytes:        TX byte count for statistics
>> >> >   * @tx_stat_sync: Synchronization object for TX stats @@ -592,6
>> >> > +594,7 @@ struct axienet_local {
>> >> >       u32 tx_bd_num;
>> >> >       u32 tx_bd_ci;
>> >> >       u32 tx_bd_tail;
>> >> > +     u32 tx_compl_bytes;
>> >> >       u64_stats_t tx_packets;
>> >> >       u64_stats_t tx_bytes;
>> >> >       struct u64_stats_sync tx_stat_sync; diff --git
>> >> > a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> >> > b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> >> > index b06e4c37ff61..95bf61986cb7 100644
>> >> > --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> >> > +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> >> > @@ -692,6 +692,8 @@ static void axienet_dma_stop(struct
>> >> > axienet_local
>> >> *lp)
>> >> >       axienet_lock_mii(lp);
>> >> >       __axienet_device_reset(lp);
>> >> >       axienet_unlock_mii(lp);
>> >> > +
>> >> > +     lp->tx_compl_bytes = 0;
>> >> >  }
>> >> >
>> >> >  /**
>> >> > @@ -770,8 +772,6 @@ static int axienet_device_reset(struct
>> >> > net_device
>> >> *ndev)
>> >> >   * @first_bd:        Index of first descriptor to clean up
>> >> >   * @nr_bds:  Max number of descriptors to clean up
>> >> >   * @force:   Whether to clean descriptors even if not complete
>> >> > - * @sizep:   Pointer to a u32 filled with the total sum of all bytes
>> >> > - *           in all cleaned-up descriptors. Ignored if NULL.
>> >> >   * @budget:  NAPI budget (use 0 when not called from NAPI poll)
>> >> >   *
>> >> >   * Would either be called after a successful transmit operation,
>> >> > or after @@ -780,7 +780,7 @@ static int axienet_device_reset(struct
>> >> > net_device
>> >> *ndev)
>> >> >   * Return: The number of packets handled.
>> >> >   */
>> >> >  static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
>> >> > -                              int nr_bds, bool force, u32 *sizep, int budget)
>> >> > +                              int nr_bds, bool force, int budget)
>> >> >  {
>> >> >       struct axidma_bd *cur_p;
>> >> >       unsigned int status;
>> >> > @@ -819,8 +819,8 @@ static int axienet_free_tx_chain(struct
>> >> > axienet_local
>> >> *lp, u32 first_bd,
>> >> >               cur_p->cntrl = 0;
>> >> >               cur_p->status = 0;
>> >> >
>> >> > -             if (sizep)
>> >> > -                     *sizep += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
>> >> > +             if (!force)
>> >> > +                     lp->tx_compl_bytes += status &
>> >> > + XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
>> >> >       }
>> >> >
>> >> >       if (!force) {
>> >> > @@ -999,18 +999,18 @@ static int axienet_tx_poll(struct napi_struct
>> >> > *napi, int budget)  {
>> >> >       struct axienet_local *lp = container_of(napi, struct axienet_local,
>> napi_tx);
>> >> >       struct net_device *ndev = lp->ndev;
>> >> > -     u32 size = 0;
>> >> >       int packets;
>> >> >
>> >> >       packets = axienet_free_tx_chain(lp, lp->tx_bd_ci, lp->tx_bd_num, false,
>> >> > -                                     &size, budget);
>> >> > +                                     budget);
>> >> >
>> >> >       if (packets) {
>> >> > -             netdev_completed_queue(ndev, packets, size);
>> >> > +             netdev_completed_queue(ndev, packets,
>> >> > + lp->tx_compl_bytes);
>> >> >               u64_stats_update_begin(&lp->tx_stat_sync);
>> >> >               u64_stats_add(&lp->tx_packets, packets);
>> >> > -             u64_stats_add(&lp->tx_bytes, size);
>> >> > +             u64_stats_add(&lp->tx_bytes, lp->tx_compl_bytes);
>> >> >               u64_stats_update_end(&lp->tx_stat_sync);
>> >> > +             lp->tx_compl_bytes = 0;
>> >> >
>> >> >               /* Matches barrier in axienet_start_xmit */
>> >> >               smp_mb();
>> >> > @@ -1115,7 +1115,7 @@ axienet_start_xmit(struct sk_buff *skb,
>> >> > struct
>> >> net_device *ndev)
>> >> >                               netdev_err(ndev, "TX DMA mapping error\n");
>> >> >                       ndev->stats.tx_dropped++;
>> >> >                       axienet_free_tx_chain(lp, orig_tail_ptr, ii + 1,
>> >> > -                                           true, NULL, 0);
>> >> > +                                           true, 0);
>> >> >                       dev_kfree_skb_any(skb);
>> >> >                       return NETDEV_TX_OK;
>> >> >               }


^ permalink raw reply

* Re: [PATCH net-next 5/5] selftests: net: add veth BQL stress test
From: Jakub Kicinski @ 2026-03-26 19:55 UTC (permalink / raw)
  To: Jesper Dangaard Brouer
  Cc: netdev, andrew+netdev, davem, edumazet, pabeni, horms, jhs, jiri,
	j.koeppeler, kernel-team
In-Reply-To: <f1263c70-ef11-4622-93bf-a5f5acaf735c@kernel.org>

On Thu, 26 Mar 2026 13:19:18 +0100 Jesper Dangaard Brouer wrote:
> The netdev/shellcheck [0][1] had some review comments.
> I will work on addressing these.
> 
> [0] 
> https://netdev-ctrl.bots.linux.dev/logs/build/1071815/14493217/shellcheck/stdout
> [1] https://www.shellcheck.net/
> 
> pw-bot: changes-requested

And it's not included in the makefile

^ permalink raw reply

* RE: [PATCH net 2/2] net: xilinx: axienet: Fix BQL accounting for multi-BD TX packets
From: Gupta, Suraj @ 2026-03-26 19:51 UTC (permalink / raw)
  To: Sean Anderson, andrew+netdev@lunn.ch, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	Simek, Michal, Pandey, Radhey Shyam, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, Katakam, Harini
In-Reply-To: <9f6a4e9f-9f93-4ced-92de-8fdc6154c694@linux.dev>

[Public]

> -----Original Message-----
> From: Sean Anderson <sean.anderson@linux.dev>
> Sent: Thursday, March 26, 2026 9:08 PM
> To: Gupta, Suraj <Suraj.Gupta2@amd.com>; andrew+netdev@lunn.ch;
> davem@davemloft.net; edumazet@google.com; kuba@kernel.org;
> pabeni@redhat.com; Simek, Michal <michal.simek@amd.com>; Pandey,
> Radhey Shyam <radhey.shyam.pandey@amd.com>; horms@kernel.org
> Cc: netdev@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-
> kernel@vger.kernel.org; Katakam, Harini <harini.katakam@amd.com>
> Subject: Re: [PATCH net 2/2] net: xilinx: axienet: Fix BQL accounting for multi-BD
> TX packets
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> On 3/25/26 01:30, Gupta, Suraj wrote:
> > [Public]
> >
> >> -----Original Message-----
> >> From: Sean Anderson <sean.anderson@linux.dev>
> >> Sent: Tuesday, March 24, 2026 9:39 PM
> >> To: Gupta, Suraj <Suraj.Gupta2@amd.com>; andrew+netdev@lunn.ch;
> >> davem@davemloft.net; edumazet@google.com; kuba@kernel.org;
> >> pabeni@redhat.com; Simek, Michal <michal.simek@amd.com>; Pandey,
> >> Radhey Shyam <radhey.shyam.pandey@amd.com>; horms@kernel.org
> >> Cc: netdev@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> >> linux- kernel@vger.kernel.org; Katakam, Harini
> >> <harini.katakam@amd.com>
> >> Subject: Re: [PATCH net 2/2] net: xilinx: axienet: Fix BQL accounting
> >> for multi-BD TX packets
> >>
> >> Caution: This message originated from an External Source. Use proper
> >> caution when opening attachments, clicking links, or responding.
> >>
> >>
> >> On 3/24/26 10:53, Suraj Gupta wrote:
> >> > When a TX packet spans multiple buffer descriptors
> >> > (scatter-gather), the per-BD byte count is accumulated into a local
> >> > variable that resets on each NAPI poll. If the BDs for a single
> >> > packet complete across different polls, the earlier bytes are lost and never
> credited to BQL.
> >> > This causes BQL to think bytes are permanently in-flight,
> >> > eventually stalling the TX queue.
> >> >
> >> > Fix this by replacing the local accumulator with a persistent
> >> > counter
> >> > (tx_compl_bytes) that survives across polls and is reset only after
> >> > updating BQL and stats.
> >>
> >> Do we need this? Can't we just do something like
> >>
> >
> > Nope, the 'size' variable passed to axienet_free_tx_chain() is local
> > to axienet_tx_poll() and goes out of scope between different polls.
> > This means it can't track completion bytes across multiple NAPI polls.
>
> Yes, but that's fine since we only update completed bytes when we retire at
> least one packet:
>
>         packets = axienet_free_tx_chain(lp, &size, budget);
>         if (packets) {
>                 netdev_completed_queue(ndev, packets, size);
>                 u64_stats_update_begin(&lp->tx_stat_sync);
>                 u64_stats_add(&lp->tx_packets, packets);
>                 u64_stats_add(&lp->tx_bytes, size);
>                 u64_stats_update_end(&lp->tx_stat_sync);
>
>                 /* Matches barrier in axienet_start_xmit */
>                 smp_mb();
>                 if (((tail - ci) & (lp->rx_bd_num - 1)) >= MAX_SKB_FRAGS + 1)
>                         netif_wake_queue(ndev);
>         }
>
> and this matches the value we use when enqueuing a packet
>
>         tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * (last_p - lp->tx_bd_v);
>         smp_store_release(&lp->tx_bd_tail, new_tail_ptr);
>         netdev_sent_queue(ndev, skb->len);
>

Let’s say we have a packet with 4 fragments. When xmit() is called, the last buffer descriptor (the 4th one) is marked with the retiral flag[1]. Now, during completion, suppose the first 3 buffer descriptors are processed in one NAPI poll, and the 4th descriptor is handled in a subsequent poll. In this scenario, the size won’t get updated for the first 3 BDs because there’s no packet retiral for them. Then, during the second poll, the size update will only reflect the completion length of the 4th BD.

This means that the bytes corresponding to the first 3 fragments are never credited to BQL, which leads to incorrect accounting and, eventually, to the TX queue stalling as described.
Proposed changes to accumulate the completion length across polls until the entire packet is processed directly addresses this gap.

[1]: https://elixir.bootlin.com/linux/v7.0-rc5/source/drivers/net/ethernet/xilinx/xilinx_axienet_main.c#L1127


Regards,
Suraj

> > Regards,
> > Suraj
> >
> >> diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> >> b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> >> index 415e9bc252527..1ea8a6592bce1 100644
> >> --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> >> +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> >> @@ -768,6 +768,7 @@ static int axienet_free_tx_chain(struct
> >> axienet_local *lp, u32 *sizep, int budge
> >>                 if (cur_p->skb) {
> >>                         struct axienet_cb *cb = (void
> >> *)cur_p->skb->cb;
> >>
> >> +                       *sizep += skb->len;
> >>                         dma_unmap_sgtable(lp->dev, &cb->sgt, DMA_TO_DEVICE, 0);
> >>                         sg_free_table_chained(&cb->sgt, XAE_INLINE_SG_CNT);
> >>                         napi_consume_skb(cur_p->skb, budget); @@
> >> -783,8 +784,6 @@ static int axienet_free_tx_chain(struct axienet_local *lp,
> u32 *sizep, int budge
> >>                 wmb();
> >>                 cur_p->cntrl = 0;
> >>                 cur_p->status = 0;
> >> -
> >> -               *sizep += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
> >>         }
> >>
> >>         smp_store_release(&lp->tx_bd_ci, (ci + i) & (lp->tx_bd_num -
> >> 1));
> >>
> >> > Fixes: c900e49d58eb ("net: xilinx: axienet: Implement BQL")
> >> > Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
> >> > ---
> >> >  drivers/net/ethernet/xilinx/xilinx_axienet.h  |  3 +++
> >> > .../net/ethernet/xilinx/xilinx_axienet_main.c | 20
> >> > +++++++++----------
> >> >  2 files changed, 13 insertions(+), 10 deletions(-)
> >> >
> >> > diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h
> >> > b/drivers/net/ethernet/xilinx/xilinx_axienet.h
> >> > index 602389843342..a4444c939451 100644
> >> > --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
> >> > +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
> >> > @@ -509,6 +509,8 @@ struct skbuf_dma_descriptor {
> >> >   *           complete. Only updated at runtime by TX NAPI poll.
> >> >   * @tx_bd_tail:      Stores the index of the next Tx buffer descriptor in the
> ring
> >> >   *              to be populated.
> >> > + * @tx_compl_bytes: Accumulates TX completion length until a full
> packet is
> >> > + *              reported to the stack.
> >> >   * @tx_packets: TX packet count for statistics
> >> >   * @tx_bytes:        TX byte count for statistics
> >> >   * @tx_stat_sync: Synchronization object for TX stats @@ -592,6
> >> > +594,7 @@ struct axienet_local {
> >> >       u32 tx_bd_num;
> >> >       u32 tx_bd_ci;
> >> >       u32 tx_bd_tail;
> >> > +     u32 tx_compl_bytes;
> >> >       u64_stats_t tx_packets;
> >> >       u64_stats_t tx_bytes;
> >> >       struct u64_stats_sync tx_stat_sync; diff --git
> >> > a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> >> > b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> >> > index b06e4c37ff61..95bf61986cb7 100644
> >> > --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> >> > +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> >> > @@ -692,6 +692,8 @@ static void axienet_dma_stop(struct
> >> > axienet_local
> >> *lp)
> >> >       axienet_lock_mii(lp);
> >> >       __axienet_device_reset(lp);
> >> >       axienet_unlock_mii(lp);
> >> > +
> >> > +     lp->tx_compl_bytes = 0;
> >> >  }
> >> >
> >> >  /**
> >> > @@ -770,8 +772,6 @@ static int axienet_device_reset(struct
> >> > net_device
> >> *ndev)
> >> >   * @first_bd:        Index of first descriptor to clean up
> >> >   * @nr_bds:  Max number of descriptors to clean up
> >> >   * @force:   Whether to clean descriptors even if not complete
> >> > - * @sizep:   Pointer to a u32 filled with the total sum of all bytes
> >> > - *           in all cleaned-up descriptors. Ignored if NULL.
> >> >   * @budget:  NAPI budget (use 0 when not called from NAPI poll)
> >> >   *
> >> >   * Would either be called after a successful transmit operation,
> >> > or after @@ -780,7 +780,7 @@ static int axienet_device_reset(struct
> >> > net_device
> >> *ndev)
> >> >   * Return: The number of packets handled.
> >> >   */
> >> >  static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
> >> > -                              int nr_bds, bool force, u32 *sizep, int budget)
> >> > +                              int nr_bds, bool force, int budget)
> >> >  {
> >> >       struct axidma_bd *cur_p;
> >> >       unsigned int status;
> >> > @@ -819,8 +819,8 @@ static int axienet_free_tx_chain(struct
> >> > axienet_local
> >> *lp, u32 first_bd,
> >> >               cur_p->cntrl = 0;
> >> >               cur_p->status = 0;
> >> >
> >> > -             if (sizep)
> >> > -                     *sizep += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
> >> > +             if (!force)
> >> > +                     lp->tx_compl_bytes += status &
> >> > + XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
> >> >       }
> >> >
> >> >       if (!force) {
> >> > @@ -999,18 +999,18 @@ static int axienet_tx_poll(struct napi_struct
> >> > *napi, int budget)  {
> >> >       struct axienet_local *lp = container_of(napi, struct axienet_local,
> napi_tx);
> >> >       struct net_device *ndev = lp->ndev;
> >> > -     u32 size = 0;
> >> >       int packets;
> >> >
> >> >       packets = axienet_free_tx_chain(lp, lp->tx_bd_ci, lp->tx_bd_num, false,
> >> > -                                     &size, budget);
> >> > +                                     budget);
> >> >
> >> >       if (packets) {
> >> > -             netdev_completed_queue(ndev, packets, size);
> >> > +             netdev_completed_queue(ndev, packets,
> >> > + lp->tx_compl_bytes);
> >> >               u64_stats_update_begin(&lp->tx_stat_sync);
> >> >               u64_stats_add(&lp->tx_packets, packets);
> >> > -             u64_stats_add(&lp->tx_bytes, size);
> >> > +             u64_stats_add(&lp->tx_bytes, lp->tx_compl_bytes);
> >> >               u64_stats_update_end(&lp->tx_stat_sync);
> >> > +             lp->tx_compl_bytes = 0;
> >> >
> >> >               /* Matches barrier in axienet_start_xmit */
> >> >               smp_mb();
> >> > @@ -1115,7 +1115,7 @@ axienet_start_xmit(struct sk_buff *skb,
> >> > struct
> >> net_device *ndev)
> >> >                               netdev_err(ndev, "TX DMA mapping error\n");
> >> >                       ndev->stats.tx_dropped++;
> >> >                       axienet_free_tx_chain(lp, orig_tail_ptr, ii + 1,
> >> > -                                           true, NULL, 0);
> >> > +                                           true, 0);
> >> >                       dev_kfree_skb_any(skb);
> >> >                       return NETDEV_TX_OK;
> >> >               }

^ permalink raw reply

* WITHDRAWN -RE: [PATCH net V2 0/2] Correct BD length masks and BQL accounting for multi-BD TX packets
From: Gupta, Suraj @ 2026-03-26 19:46 UTC (permalink / raw)
  To: Gupta, Suraj, andrew+netdev@lunn.ch, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	Simek, Michal, sean.anderson@linux.dev, Pandey, Radhey Shyam,
	horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, Katakam, Harini
In-Reply-To: <20260326185510.3840084-1-suraj.gupta2@amd.com>

[Public]

> -----Original Message-----
> From: Suraj Gupta <suraj.gupta2@amd.com>
> Sent: Friday, March 27, 2026 12:25 AM
> To: andrew+netdev@lunn.ch; davem@davemloft.net; edumazet@google.com;
> kuba@kernel.org; pabeni@redhat.com; Simek, Michal
> <michal.simek@amd.com>; sean.anderson@linux.dev; Pandey, Radhey Shyam
> <radhey.shyam.pandey@amd.com>; horms@kernel.org
> Cc: netdev@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-
> kernel@vger.kernel.org; Katakam, Harini <harini.katakam@amd.com>
> Subject: [PATCH net V2 0/2] Correct BD length masks and BQL accounting for
> multi-BD TX packets
>

Please ignore / withdraw this V2 series.

Due to a syncing issue in my outlook, I sent v2 prematurely. There is still ongoing discussion on v1 that needs to be concluded first. I'll follow up after the v1 feedback is resolved.

Thanks,
Suraj

> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> This patch series fixes two issues in the Xilinx AXI Ethernet driver:
>  1. Corrects the BD length masks to match the AXIDMA IP spec.
>  2. Fixes BQL accounting for multi-BD TX packets.
>
> ---
> Changes in V2:
> Use GENMASK() to define the BD length masks.
> ---
> Suraj Gupta (2):
>   net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
>   net: xilinx: axienet: Fix BQL accounting for multi-BD TX packets
>
>  drivers/net/ethernet/xilinx/xilinx_axienet.h  |  7 +++++--
> .../net/ethernet/xilinx/xilinx_axienet_main.c | 20 +++++++++----------
>  2 files changed, 15 insertions(+), 12 deletions(-)
>
> --
> 2.49.1
>


^ permalink raw reply

* Re: [PATCH bpf-next 1/3] bpf: Disallow freplace on XDP with mismatched xdp_has_frags values
From: Jakub Kicinski @ 2026-03-26 19:42 UTC (permalink / raw)
  To: Leon Hwang
  Cc: bpf, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Shuah Khan, David S . Miller, Jesper Dangaard Brouer,
	Toke Hoiland-Jorgensen, Lorenzo Bianconi, linux-kernel,
	linux-kselftest, netdev, kernel-patches-bot
In-Reply-To: <20260324150444.68166-2-leon.hwang@linux.dev>

On Tue, 24 Mar 2026 23:04:42 +0800 Leon Hwang wrote:
> The commit f45d5b6ce2e8 ("bpf: generalise tail call map compatibility check")
> was to ensure backwards compatibility against tail calls. However, it
> missed that XDP progs can be extended by freplace progs, which could break
> the backwards compatibility, e.g. xdp_has_frags=true freplace progs are
> allowed to attach to xdp_has_frags=false XDP progs.
> 
> To avoid breaking the backwards compatibility via freplace, disallow
> freplace on XDP programs with different xdp_has_frags values.

It may be worth adding a selftest to
tools/testing/selftests/drivers/net/xdp.py
which sets MTU to 9k, tries to attach a non-frag-capable prog
if that fails attaches a frag-capable prog and then checks if
replacing the capable prog with non-capable fails.
Drivers may be buggy in this regard.

^ permalink raw reply

* Re: [PATCH 5/5] nbd: Use lock_sock_try() for TCP sendmsg() and shutdown().
From: Kuniyuki Iwashima @ 2026-03-26 19:38 UTC (permalink / raw)
  To: kernel test robot
  Cc: Josef Bacik, Jens Axboe, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, llvm, oe-kbuild-all, Simon Horman,
	linux-block, nbd, netdev, syzbot+7b4f368d3955d2c9950e
In-Reply-To: <202603270301.kJulQgkT-lkp@intel.com>

On Thu, Mar 26, 2026 at 12:14 PM kernel test robot <lkp@intel.com> wrote:
>
> Hi Kuniyuki,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on axboe/for-next]
> [also build test ERROR on linus/master v7.0-rc5]
> [cannot apply to next-20260325]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Kuniyuki-Iwashima/nbd-Remove-redundant-sock-ops-shutdown-check-in-nbd_get_socket/20260325-175457
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git for-next
> patch link:    https://lore.kernel.org/r/20260325063843.1790782-6-kuniyu%40google.com
> patch subject: [PATCH 5/5] nbd: Use lock_sock_try() for TCP sendmsg() and shutdown().
> config: x86_64-buildonly-randconfig-004-20260326 (https://download.01.org/0day-ci/archive/20260327/202603270301.kJulQgkT-lkp@intel.com/config)
> compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260327/202603270301.kJulQgkT-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202603270301.kJulQgkT-lkp@intel.com/
>
> All errors (new ones prefixed by >>):
>
> >> ld.lld: error: undefined symbol: inet_shutdown_locked
>    >>> referenced by nbd.c
>    >>>               drivers/block/nbd.o:(nbd_mark_nsock_dead) in archive vmlinux.a
> --
> >> ld.lld: error: undefined symbol: tcp_sendmsg_locked
>    >>> referenced by nbd.c
>    >>>               drivers/block/nbd.o:(__sock_xmit) in archive vmlinux.a

ah, CONFIG_INET=n.  Will fix it in v2.

Thanks

^ permalink raw reply

* Re: [PATCH v2 net] ip6_tunnel: clear skb2->cb[] in ip4ip6_err()
From: Eric Dumazet @ 2026-03-26 19:36 UTC (permalink / raw)
  To: Ido Schimmel
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, netdev, eric.dumazet, Oskar Kjos
In-Reply-To: <20260326192819.GA1103736@shredder>

On Thu, Mar 26, 2026 at 12:28 PM Ido Schimmel <idosch@nvidia.com> wrote:
>
> On Thu, Mar 26, 2026 at 03:51:38PM +0000, Eric Dumazet wrote:
> > Oskar Kjos reported the following problem.
> >
> > ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written
> > by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes
> > IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region
> > as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff
> > at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr
> > value. __ip_options_echo() then reads optlen from attacker-controlled
> > packet data at sptr[rr+1] and copies that many bytes into dopt->__data,
> > a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE).
> >
> > To fix this we clear skb2->cb[], as suggested by Oskar Kjos.
> >
> > Also add minimal IPv4 header validation (version == 4, ihl >= 5).
> >
> > Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
> > Reported-by: Oskar Kjos <oskar.kjos@hotmail.com>
> > Signed-off-by: Eric Dumazet <edumazet@google.com>
> > Cc: Ido Schimmel <idosch@nvidia.com>
>
> Reviewed-by: Ido Schimmel <idosch@nvidia.com>
>
> FWIW, I agree with the AI review [1] that we have a similar problem in
> ip6_err_gen_icmpv6_unreach(): icmp6_send() being called with an IPv4
> control block.
>

Indeed, thanks for noticing.

I can take care of this problem in a separate patch.

> [1] https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com

^ permalink raw reply

* Re: [PATCH net v3] bnxt_en: validate firmware backing store types
From: Jakub Kicinski @ 2026-03-26 19:29 UTC (permalink / raw)
  To: Pengpeng Hou
  Cc: michael.chan, pavan.chebbi, andrew+netdev, davem, edumazet,
	pabeni, netdev, linux-kernel
In-Reply-To: <20260326142033.82313-1-pengpeng@iscas.ac.cn>

On Thu, 26 Mar 2026 22:20:33 +0800 Pengpeng Hou wrote:
> bnxt_hwrm_func_backing_store_qcaps_v2() stores resp->type from the
> firmware response in ctxm->type and later uses that value to index
> fixed backing-store metadata arrays such as ctx_arr[] and
> bnxt_bstore_to_trace[] without a local range check.

please don't post the next version in reply to the old one.
Add a lore.kernel.org link to the previous posting in the change log
instead.

^ permalink raw reply

* Re: [PATCH v2 net] ip6_tunnel: clear skb2->cb[] in ip4ip6_err()
From: Ido Schimmel @ 2026-03-26 19:28 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, netdev, eric.dumazet, Oskar Kjos
In-Reply-To: <20260326155138.2429480-1-edumazet@google.com>

On Thu, Mar 26, 2026 at 03:51:38PM +0000, Eric Dumazet wrote:
> Oskar Kjos reported the following problem.
> 
> ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written
> by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes
> IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region
> as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff
> at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr
> value. __ip_options_echo() then reads optlen from attacker-controlled
> packet data at sptr[rr+1] and copies that many bytes into dopt->__data,
> a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE).
> 
> To fix this we clear skb2->cb[], as suggested by Oskar Kjos.
> 
> Also add minimal IPv4 header validation (version == 4, ihl >= 5).
> 
> Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
> Reported-by: Oskar Kjos <oskar.kjos@hotmail.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Cc: Ido Schimmel <idosch@nvidia.com>

Reviewed-by: Ido Schimmel <idosch@nvidia.com>

FWIW, I agree with the AI review [1] that we have a similar problem in
ip6_err_gen_icmpv6_unreach(): icmp6_send() being called with an IPv4
control block.

[1] https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com

^ permalink raw reply

* Re: [PATCH net v2] net/sched: sch_hfsc: fix divide-by-zero in rtsc_min()
From: Jakub Kicinski @ 2026-03-26 19:21 UTC (permalink / raw)
  To: Xiang Mei
  Cc: security, netdev, pabeni, jhs, jiri, davem, edumazet, horms,
	bestswngs
In-Reply-To: <g5kyhh74rriqg4ayz5txfqqtxpuklzu4kbkmcwihqpvyv4xq2s@xcpvtqh7bh5g>

On Thu, 26 Mar 2026 11:54:52 -0700 Xiang Mei wrote:
> PoC:
> ```sh
> #!/bin/sh
> ip link set lo up
> 
> tc qdisc replace dev lo root handle 1: \
>     stab overhead 3000000 mtu 0 tsize 0 \
>     hfsc default 1
> tc class replace dev lo parent 1: classid 1:1 hfsc \
>     rt m1 32gbit d 1ms m2 0bit \
>     ls m1 32gbit d 1ms m2 0bit
> 
> # Send UDP to loopback (same method as C PoC)
> python3 -c "
> import socket,time
> s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
> s.sendto(b'A'*64,('127.0.0.1',1337))  # activate class
> time.sleep(1)                           # drain → idle
> s.sendto(b'A'*64,('127.0.0.1',1337))  # reactivation → div-by-zero
> "
> ```

Please turn this into a TDC selftest.

^ permalink raw reply

* Re: [PATCH 5/5] nbd: Use lock_sock_try() for TCP sendmsg() and shutdown().
From: kernel test robot @ 2026-03-26 19:13 UTC (permalink / raw)
  To: Kuniyuki Iwashima, Josef Bacik, Jens Axboe, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: llvm, oe-kbuild-all, Simon Horman, Kuniyuki Iwashima, linux-block,
	nbd, netdev, syzbot+7b4f368d3955d2c9950e
In-Reply-To: <20260325063843.1790782-6-kuniyu@google.com>

Hi Kuniyuki,

kernel test robot noticed the following build errors:

[auto build test ERROR on axboe/for-next]
[also build test ERROR on linus/master v7.0-rc5]
[cannot apply to next-20260325]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kuniyuki-Iwashima/nbd-Remove-redundant-sock-ops-shutdown-check-in-nbd_get_socket/20260325-175457
base:   https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git for-next
patch link:    https://lore.kernel.org/r/20260325063843.1790782-6-kuniyu%40google.com
patch subject: [PATCH 5/5] nbd: Use lock_sock_try() for TCP sendmsg() and shutdown().
config: x86_64-buildonly-randconfig-004-20260326 (https://download.01.org/0day-ci/archive/20260327/202603270301.kJulQgkT-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260327/202603270301.kJulQgkT-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603270301.kJulQgkT-lkp@intel.com/

All errors (new ones prefixed by >>):

>> ld.lld: error: undefined symbol: inet_shutdown_locked
   >>> referenced by nbd.c
   >>>               drivers/block/nbd.o:(nbd_mark_nsock_dead) in archive vmlinux.a
--
>> ld.lld: error: undefined symbol: tcp_sendmsg_locked
   >>> referenced by nbd.c
   >>>               drivers/block/nbd.o:(__sock_xmit) in archive vmlinux.a

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH net-next v4 00/10] selftests: drivers: bash support for remote traffic generators
From: Jakub Kicinski @ 2026-03-26 19:03 UTC (permalink / raw)
  To: Ioana Ciornei
  Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
	Simon Horman, linux-kernel, petrm, willemb, linux-kselftest
In-Reply-To: <20260326132828.805703-1-ioana.ciornei@nxp.com>

On Thu, 26 Mar 2026 15:28:18 +0200 Ioana Ciornei wrote:
> This patch set aims to add the necessary support so that bash written
> selftests are also able to easily run with a remote traffic generator
> system, either be it in another netns or one accessible through ssh.
> 
> This patch set is a result of the discussion from v1:
> https://lore.kernel.org/all/20260303084330.340b6459@kernel.org/
> Even though the python infrastructure is already established, some
> things are easier in bash and it would be a shame to leave behind the
> bash tests that we already have.

I think this introduces a bunch of regressions, eg:

https://netdev-ctrl.bots.linux.dev/logs/vmksft/forwarding/results/575622/4-local-termination-sh/stdout

https://netdev-ctrl.bots.linux.dev/logs/vmksft/netdevsim/results/575802/18-netcons-resume-sh/stdout

^ permalink raw reply

* [PATCH net V2 2/2] net: xilinx: axienet: Fix BQL accounting for multi-BD TX packets
From: Suraj Gupta @ 2026-03-26 18:55 UTC (permalink / raw)
  To: andrew+netdev, davem, edumazet, kuba, pabeni, michal.simek,
	sean.anderson, radhey.shyam.pandey, horms
  Cc: netdev, linux-arm-kernel, linux-kernel, harini.katakam
In-Reply-To: <20260326185510.3840084-1-suraj.gupta2@amd.com>

When a TX packet spans multiple buffer descriptors (scatter-gather),
the per-BD byte count is accumulated into a local variable that resets
on each NAPI poll. If the BDs for a single packet complete across
different polls, the earlier bytes are lost and never credited to BQL.
This causes BQL to think bytes are permanently in-flight, eventually
stalling the TX queue.

Fix this by replacing the local accumulator with a persistent counter
(tx_compl_bytes) that survives across polls and is reset only after
updating BQL and stats.

Fixes: c900e49d58eb ("net: xilinx: axienet: Implement BQL")
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
 drivers/net/ethernet/xilinx/xilinx_axienet.h  |  3 +++
 .../net/ethernet/xilinx/xilinx_axienet_main.c | 20 +++++++++----------
 2 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 602389843342..a4444c939451 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -509,6 +509,8 @@ struct skbuf_dma_descriptor {
  *		complete. Only updated at runtime by TX NAPI poll.
  * @tx_bd_tail:	Stores the index of the next Tx buffer descriptor in the ring
  *              to be populated.
+ * @tx_compl_bytes: Accumulates TX completion length until a full packet is
+ *              reported to the stack.
  * @tx_packets: TX packet count for statistics
  * @tx_bytes:	TX byte count for statistics
  * @tx_stat_sync: Synchronization object for TX stats
@@ -592,6 +594,7 @@ struct axienet_local {
 	u32 tx_bd_num;
 	u32 tx_bd_ci;
 	u32 tx_bd_tail;
+	u32 tx_compl_bytes;
 	u64_stats_t tx_packets;
 	u64_stats_t tx_bytes;
 	struct u64_stats_sync tx_stat_sync;
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index b06e4c37ff61..95bf61986cb7 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -692,6 +692,8 @@ static void axienet_dma_stop(struct axienet_local *lp)
 	axienet_lock_mii(lp);
 	__axienet_device_reset(lp);
 	axienet_unlock_mii(lp);
+
+	lp->tx_compl_bytes = 0;
 }
 
 /**
@@ -770,8 +772,6 @@ static int axienet_device_reset(struct net_device *ndev)
  * @first_bd:	Index of first descriptor to clean up
  * @nr_bds:	Max number of descriptors to clean up
  * @force:	Whether to clean descriptors even if not complete
- * @sizep:	Pointer to a u32 filled with the total sum of all bytes
- *		in all cleaned-up descriptors. Ignored if NULL.
  * @budget:	NAPI budget (use 0 when not called from NAPI poll)
  *
  * Would either be called after a successful transmit operation, or after
@@ -780,7 +780,7 @@ static int axienet_device_reset(struct net_device *ndev)
  * Return: The number of packets handled.
  */
 static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
-				 int nr_bds, bool force, u32 *sizep, int budget)
+				 int nr_bds, bool force, int budget)
 {
 	struct axidma_bd *cur_p;
 	unsigned int status;
@@ -819,8 +819,8 @@ static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
 		cur_p->cntrl = 0;
 		cur_p->status = 0;
 
-		if (sizep)
-			*sizep += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
+		if (!force)
+			lp->tx_compl_bytes += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
 	}
 
 	if (!force) {
@@ -999,18 +999,18 @@ static int axienet_tx_poll(struct napi_struct *napi, int budget)
 {
 	struct axienet_local *lp = container_of(napi, struct axienet_local, napi_tx);
 	struct net_device *ndev = lp->ndev;
-	u32 size = 0;
 	int packets;
 
 	packets = axienet_free_tx_chain(lp, lp->tx_bd_ci, lp->tx_bd_num, false,
-					&size, budget);
+					budget);
 
 	if (packets) {
-		netdev_completed_queue(ndev, packets, size);
+		netdev_completed_queue(ndev, packets, lp->tx_compl_bytes);
 		u64_stats_update_begin(&lp->tx_stat_sync);
 		u64_stats_add(&lp->tx_packets, packets);
-		u64_stats_add(&lp->tx_bytes, size);
+		u64_stats_add(&lp->tx_bytes, lp->tx_compl_bytes);
 		u64_stats_update_end(&lp->tx_stat_sync);
+		lp->tx_compl_bytes = 0;
 
 		/* Matches barrier in axienet_start_xmit */
 		smp_mb();
@@ -1115,7 +1115,7 @@ axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 				netdev_err(ndev, "TX DMA mapping error\n");
 			ndev->stats.tx_dropped++;
 			axienet_free_tx_chain(lp, orig_tail_ptr, ii + 1,
-					      true, NULL, 0);
+					      true, 0);
 			dev_kfree_skb_any(skb);
 			return NETDEV_TX_OK;
 		}
-- 
2.49.1


^ permalink raw reply related

* [PATCH net V2 1/2] net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
From: Suraj Gupta @ 2026-03-26 18:55 UTC (permalink / raw)
  To: andrew+netdev, davem, edumazet, kuba, pabeni, michal.simek,
	sean.anderson, radhey.shyam.pandey, horms
  Cc: netdev, linux-arm-kernel, linux-kernel, harini.katakam
In-Reply-To: <20260326185510.3840084-1-suraj.gupta2@amd.com>

The XAXIDMA_BD_CTRL_LENGTH_MASK and XAXIDMA_BD_STS_ACTUAL_LEN_MASK
macros were defined as 0x007FFFFF (23 bits), but the AXI DMA IP
product guide (PG021) specifies the buffer length field as bits 25:0
(26 bits). Update both masks to match the IP documentation.

In practice this had no functional impact, since Ethernet frames are
far smaller than 2^23 bytes and the extra bits were always zero, but
the masks should still reflect the hardware specification.

Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
 drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 5ff742103beb..602389843342 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -105,7 +105,7 @@
 #define XAXIDMA_BD_HAS_DRE_MASK		0xF00 /* Whether has DRE mask */
 #define XAXIDMA_BD_WORDLEN_MASK		0xFF /* Whether has DRE mask */
 
-#define XAXIDMA_BD_CTRL_LENGTH_MASK	0x007FFFFF /* Requested len */
+#define XAXIDMA_BD_CTRL_LENGTH_MASK	GENMASK(25, 0) /* Requested len */
 #define XAXIDMA_BD_CTRL_TXSOF_MASK	0x08000000 /* First tx packet */
 #define XAXIDMA_BD_CTRL_TXEOF_MASK	0x04000000 /* Last tx packet */
 #define XAXIDMA_BD_CTRL_ALL_MASK	0x0C000000 /* All control bits */
@@ -130,7 +130,7 @@
 #define XAXIDMA_BD_CTRL_TXEOF_MASK	0x04000000 /* Last tx packet */
 #define XAXIDMA_BD_CTRL_ALL_MASK	0x0C000000 /* All control bits */
 
-#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK	0x007FFFFF /* Actual len */
+#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK	GENMASK(25, 0) /* Actual len */
 #define XAXIDMA_BD_STS_COMPLETE_MASK	0x80000000 /* Completed */
 #define XAXIDMA_BD_STS_DEC_ERR_MASK	0x40000000 /* Decode error */
 #define XAXIDMA_BD_STS_SLV_ERR_MASK	0x20000000 /* Slave error */
-- 
2.49.1


^ permalink raw reply related

* [PATCH net V2 0/2] Correct BD length masks and BQL accounting for multi-BD TX packets
From: Suraj Gupta @ 2026-03-26 18:55 UTC (permalink / raw)
  To: andrew+netdev, davem, edumazet, kuba, pabeni, michal.simek,
	sean.anderson, radhey.shyam.pandey, horms
  Cc: netdev, linux-arm-kernel, linux-kernel, harini.katakam

This patch series fixes two issues in the Xilinx AXI Ethernet driver:
 1. Corrects the BD length masks to match the AXIDMA IP spec.
 2. Fixes BQL accounting for multi-BD TX packets.

---
Changes in V2:
Use GENMASK() to define the BD length masks.
---
Suraj Gupta (2):
  net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
  net: xilinx: axienet: Fix BQL accounting for multi-BD TX packets

 drivers/net/ethernet/xilinx/xilinx_axienet.h  |  7 +++++--
 .../net/ethernet/xilinx/xilinx_axienet_main.c | 20 +++++++++----------
 2 files changed, 15 insertions(+), 12 deletions(-)

-- 
2.49.1


^ permalink raw reply

* Re: [PATCH net v2] net/sched: sch_hfsc: fix divide-by-zero in rtsc_min()
From: Xiang Mei @ 2026-03-26 18:54 UTC (permalink / raw)
  To: security; +Cc: netdev, pabeni, jhs, jiri, davem, edumazet, kuba, horms,
	bestswngs
In-Reply-To: <20260326075851.3967598-1-xmei5@asu.edu>

On Thu, Mar 26, 2026 at 12:58:51AM -0700, Xiang Mei wrote:
> m2sm() converts a u32 slope to a u64 scaled value.  For large inputs
> (e.g. m1=4000000000), the result can reach 2^32.  rtsc_min() stores
> the difference of two such u64 values in a u32 variable `dsm` and
> uses it as a divisor.  When the difference is exactly 2^32 the
> truncation yields zero, causing a divide-by-zero oops in the
> concave-curve intersection path:
> 
>   Oops: divide error: 0000
>   RIP: 0010:rtsc_min (net/sched/sch_hfsc.c:601)
>   Call Trace:
>    init_ed (net/sched/sch_hfsc.c:629)
>    hfsc_enqueue (net/sched/sch_hfsc.c:1569)
>    [...]
> 
> Widen `dsm` to u64 and replace do_div() with div64_u64() so the full
> difference is preserved.
> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reported-by: Weiming Shi <bestswngs@gmail.com>
> Signed-off-by: Xiang Mei <xmei5@asu.edu>
> ---
> v2: resend to netdev ML
> 
>  net/sched/sch_hfsc.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
> index b5657ffbbf84..83b2ca2e37fc 100644
> --- a/net/sched/sch_hfsc.c
> +++ b/net/sched/sch_hfsc.c
> @@ -555,7 +555,7 @@ static void
>  rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
>  {
>  	u64 y1, y2, dx, dy;
> -	u32 dsm;
> +	u64 dsm;
>  
>  	if (isc->sm1 <= isc->sm2) {
>  		/* service curve is convex */
> @@ -598,7 +598,7 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
>  	 */
>  	dx = (y1 - y) << SM_SHIFT;
>  	dsm = isc->sm1 - isc->sm2;
> -	do_div(dx, dsm);
> +	dx = div64_u64(dx, dsm);
>  	/*
>  	 * check if (x, y1) belongs to the 1st segment of rtsc.
>  	 * if so, add the offset.
> -- 
> 2.43.0
>

Thanks for your attention for this bug.
The following information could help you to reproduce the bug:

PoC:
```sh
#!/bin/sh
ip link set lo up

tc qdisc replace dev lo root handle 1: \
    stab overhead 3000000 mtu 0 tsize 0 \
    hfsc default 1
tc class replace dev lo parent 1: classid 1:1 hfsc \
    rt m1 32gbit d 1ms m2 0bit \
    ls m1 32gbit d 1ms m2 0bit

# Send UDP to loopback (same method as C PoC)
python3 -c "
import socket,time
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.sendto(b'A'*64,('127.0.0.1',1337))  # activate class
time.sleep(1)                           # drain → idle
s.sendto(b'A'*64,('127.0.0.1',1337))  # reactivation → div-by-zero
"
```

Intended Crash:
```log
[   25.713426] Oops: divide error: 0000 [#1] SMP KASAN NOPTI
[   25.713720] CPU: 1 UID: 0 PID: 335 Comm: python3 Not tainted 7.0.0-rc4+ #4 PREEMPTLAZY
[   25.714102] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.17.0-0-gb52ca86e094
[   25.714825] RIP: 0010:rtsc_min+0x148/0x360
[   25.715034] Code: 0f 85 ad 01 00 00 48 8b 53 18 4c 01 f2 48 39 d0 0f 83 ea 00 00 00 8b 0c 24 4c c
[   25.715928] RSP: 0018:ffff888013eef438 EFLAGS: 00010206
[   25.716198] RAX: 00000f41d6000000 RBX: ffff888010e2c150 RCX: 0000000000000000
[   25.716555] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff888010e2c168
[   25.716896] RBP: ffff888010e2c1e0 R08: 0000000000000001 R09: ffff888010e2c008
[   25.717238] R10: ffff888013488000 R11: ffff888013eefb30 R12: 00000000003d0900
[   25.717724] R13: 0000000100000000 R14: 00000000002dc72a R15: 0000000017f10a4c
[   25.718065] FS:  000078cd1f4cf040(0000) GS:ffff8881781cb000(0000) knlGS:0000000000000000
[   25.718456] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   25.718766] CR2: 000078cd1f5f87d0 CR3: 0000000013fb8002 CR4: 0000000000772ef0
[   25.719118] PKRU: 55555554
[   25.719262] Call Trace:
[   25.719390]  <TASK>
[   25.719503]  ? ktime_get+0x65/0x150
[   25.719704]  init_ed+0x70/0x4d0
[   25.719870]  hfsc_enqueue+0x7bb/0xef0
[   25.720059]  ? kmalloc_reserve+0x10c/0x2c0
```

This bug is a DoS bug requiring ns_capable(CAP_NET_ADMIN).
Please let me know if you have any questions for the patch and poc.

Thanks,
Xiang

^ permalink raw reply

* [PATCH net 2/2] net: bcmgenet: fix racing timeout handler
From: justin.chen @ 2026-03-26 18:45 UTC (permalink / raw)
  To: netdev
  Cc: pabeni, kuba, edumazet, davem, andrew+netdev,
	bcm-kernel-feedback-list, florian.fainelli, opendmb, nb,
	Justin Chen
In-Reply-To: <20260326184529.1393438-1-justin.chen@brodcom.com>

From: Justin Chen <justin.chen@broadcom.com>

The bcmgenet_timeout handler tries to take down all tx queues when
a single queue times out. This is over zealous and causes many race
conditions with queues that are still chugging along. Instead lets
only restart the timed out queue.

Fixes: 13ea657806cf ("net: bcmgenet: improve TX timeout")
Signed-off-by: Justin Chen <justin.chen@broadcom.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
Tested-by: Nicolai Buchwitz <nb@tipi-net.de>
---
 .../net/ethernet/broadcom/genet/bcmgenet.c    | 22 ++++++++-----------
 1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 3e1fc3bb8297..d33c4fa071a3 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -3477,27 +3477,23 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring)
 static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue)
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
-	u32 int1_enable = 0;
-	unsigned int q;
+	struct netdev_queue *txq = netdev_get_tx_queue(dev, txqueue);
+	struct bcmgenet_tx_ring *ring = &priv->tx_rings[txqueue];
 
 	netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n");
 
-	for (q = 0; q <= priv->hw_params->tx_queues; q++)
-		bcmgenet_dump_tx_queue(&priv->tx_rings[q]);
-
-	bcmgenet_tx_reclaim_all(dev);
+	bcmgenet_dump_tx_queue(ring);
 
-	for (q = 0; q <= priv->hw_params->tx_queues; q++)
-		int1_enable |= (1 << q);
+	bcmgenet_tx_reclaim(dev, ring, true);
 
-	/* Re-enable TX interrupts if disabled */
-	bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
+	/* Re-enable the TX interrupt for this ring */
+	bcmgenet_intrl2_1_writel(priv, 1 << txqueue, INTRL2_CPU_MASK_CLEAR);
 
-	netif_trans_update(dev);
+	txq_trans_cond_update(txq);
 
-	BCMGENET_STATS64_INC((&priv->tx_rings[txqueue].stats64), errors);
+	BCMGENET_STATS64_INC((&ring->stats64), errors);
 
-	netif_tx_wake_all_queues(dev);
+	netif_tx_wake_queue(txq);
 }
 
 #define MAX_MDF_FILTER	17
-- 
2.34.1


^ permalink raw reply related

* [PATCH net 1/2] net: bcmgenet: fix leaking free_bds
From: justin.chen @ 2026-03-26 18:45 UTC (permalink / raw)
  To: netdev
  Cc: pabeni, kuba, edumazet, davem, andrew+netdev,
	bcm-kernel-feedback-list, florian.fainelli, opendmb, nb,
	Justin Chen
In-Reply-To: <20260326184529.1393438-1-justin.chen@brodcom.com>

From: Justin Chen <justin.chen@broadcom.com>

While reclaiming the tx queue we fast forward the write pointer to
drop any data in flight. These dropped frames are not added back
to the pool of free bds. We also need to tell the netdev that we
are dropping said data.

Fixes: f1bacae8b655 ("net: bcmgenet: support reclaiming unsent Tx packets")
Signed-off-by: Justin Chen <justin.chen@broadcom.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
Tested-by: Nicolai Buchwitz <nb@tipi-net.de>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 482a31e7b72b..3e1fc3bb8297 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1985,6 +1985,7 @@ static unsigned int bcmgenet_tx_reclaim(struct net_device *dev,
 		drop = (ring->prod_index - ring->c_index) & DMA_C_INDEX_MASK;
 		released += drop;
 		ring->prod_index = ring->c_index & DMA_C_INDEX_MASK;
+		ring->free_bds += drop;
 		while (drop--) {
 			cb_ptr = bcmgenet_put_txcb(priv, ring);
 			skb = cb_ptr->skb;
@@ -1996,6 +1997,7 @@ static unsigned int bcmgenet_tx_reclaim(struct net_device *dev,
 		}
 		if (skb)
 			dev_consume_skb_any(skb);
+		netdev_tx_reset_queue(netdev_get_tx_queue(dev, ring->index));
 		bcmgenet_tdma_ring_writel(priv, ring->index,
 					  ring->prod_index, TDMA_PROD_INDEX);
 		wr_ptr = ring->write_ptr * WORDS_PER_BD(priv);
-- 
2.34.1


^ permalink raw reply related

* [PATCH 0/2 net] net: bcmgenet: fix lock up when queues time out
From: justin.chen @ 2026-03-26 18:45 UTC (permalink / raw)
  To: netdev
  Cc: pabeni, kuba, edumazet, davem, andrew+netdev,
	bcm-kernel-feedback-list, florian.fainelli, opendmb, nb,
	Justin Chen

From: Justin Chen <justin.chen@broadcom.com>

We tend to timeout on our smaller queues. This will be solved later, but
occassionally when we hit the timeout handler the queues lock up entirely.
This was due a leaking and racing timeout handler that is now fixed.

Justin Chen (2):
  net: bcmgenet: fix leaking free_bds
  net: bcmgenet: fix racing timeout handler

 .../net/ethernet/broadcom/genet/bcmgenet.c    | 24 +++++++++----------
 1 file changed, 11 insertions(+), 13 deletions(-)

-- 
2.34.1


^ permalink raw reply

* Re: [PATCH v4 net 00/11] xsk: tailroom reservation and MTU validation
From: Björn Töpel @ 2026-03-26 18:22 UTC (permalink / raw)
  To: Maciej Fijalkowski, netdev
  Cc: bpf, magnus.karlsson, stfomichev, kuba, pabeni, horms,
	larysa.zaremba, aleksander.lobakin, Maciej Fijalkowski
In-Reply-To: <20260326114919.519456-1-maciej.fijalkowski@intel.com>

Maciej Fijalkowski <maciej.fijalkowski@intel.com> writes:

> v3->v4:
> - allow exact 128 bytes of space when user defined headroom is deducted
>   from total frame size
> - provide a routine for reading procfs entries within xskxceiver
>   * use it to fetch cache line size and calculate skb_shared_info size
>     on our own

All those POWER and s390 folks will love it! ;-)

> - clean up gve and igc xsk pool enablement routines
> - include mtu vs frame size * max zc segments validation in
>   xp_assign_dev()


For the series:
Reviewed-by: Björn Töpel <bjorn@kernel.org>

^ permalink raw reply

* Re: [PATCH net-next] selftests: net: Remove unnecessary backslashes in fq_band_pktlimit.sh
From: Simon Horman @ 2026-03-26 18:19 UTC (permalink / raw)
  To: Yohei Kojima
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Shuah Khan, netdev, linux-kselftest, linux-kernel
In-Reply-To: <dd0bbd48cdf468da56ec34fd61cecd4d2111d7ba.1774372510.git.yk@y-koj.net>

On Wed, Mar 25, 2026 at 02:20:28AM +0900, Yohei Kojima wrote:
> Address "grep: warning: stray \ before white space" warning from GNU
> grep 3.12. This warns the misplaced backslashes before whitespaces
> (e.g. \\' ' or '\ ') which leads to unspecified behavior [1].
> 
> We can just remove the backslashes before whitespaces as POSIX says:
> 
>   Enclosing characters in single-quotes ('') shall preserve the literal
>   value of each character within the single-quotes.
> 
> and bourne-compatible shells behave so.
> 
> [1]: https://lists.gnu.org/r/bug-gnulib/2022-05/msg00057.html
> 
> Signed-off-by: Yohei Kojima <yk@y-koj.net>
> ---
> I tested the patch with bash 5.3.9. I couldn't test it with dash because
> the test depends on a bash extension with "if [[ $# -eq 0 ]]".

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply

* Re: [PATCH v4 net 04/11] xsk: validate MTU against usable frame size on bind
From: Björn Töpel @ 2026-03-26 18:18 UTC (permalink / raw)
  To: Maciej Fijalkowski, netdev
  Cc: bpf, magnus.karlsson, stfomichev, kuba, pabeni, horms,
	larysa.zaremba, aleksander.lobakin, Maciej Fijalkowski
In-Reply-To: <20260326114919.519456-5-maciej.fijalkowski@intel.com>

Maciej Fijalkowski <maciej.fijalkowski@intel.com> writes:

> AF_XDP bind currently accepts zero-copy pool configurations without
> verifying that the device MTU fits into the usable frame space provided
> by the UMEM chunk.
>
> This becomes a problem since we started to respect tailroom which is
> subtracted from chunk_size (among with headroom). 2k chunk size might
> not provide enough space for standard 1500 MTU, so let us catch such
> settings at bind time. Furthermore, validate whether underlying HW will
> be able to satisfy configured MTU wrt XSK's frame size multiplied by
> supported Rx buffer chain length (that is exposed via
> net_device::xdp_zc_max_segs).
>
> Fixes: 24ea50127ecf ("xsk: support mbuf on ZC RX")
> Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>

Reviewed-by: Björn Töpel <bjorn@kernel.org>

^ permalink raw reply

* [PATCH v3 7/7] selftests/tc-testing: Add netem test case exercising loops
From: Stephen Hemminger @ 2026-03-26 18:01 UTC (permalink / raw)
  To: netdev
  Cc: Victor Nogueira, Jamal Hadi Salim, Stephen Hemminger, Jiri Pirko,
	Shuah Khan, William Liu, Jakub Kicinski, Savino Dicanosa,
	open list:KERNEL SELFTEST FRAMEWORK, open list
In-Reply-To: <20260326181701.308275-1-stephen@networkplumber.org>

From: Victor Nogueira <victor@mojatatu.com>

Add a netem nested duplicate test case to validate that it won't
cause an infinite loop

Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Acked-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
---
 .../tc-testing/tc-tests/qdiscs/netem.json     | 33 ++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/netem.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/netem.json
index 3c4444961488..7c954989069d 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/netem.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/netem.json
@@ -336,5 +336,36 @@
         "teardown": [
             "$TC qdisc del dev $DUMMY handle 1: root"
         ]
-    }
+    },
+    {
+        "id": "8c17",
+        "name": "Test netem's recursive duplicate",
+        "category": [
+            "qdisc",
+            "netem"
+        ],
+        "plugins": {
+            "requires": "nsPlugin"
+        },
+        "setup": [
+            "$IP link set dev $DUMMY up || true",
+            "$IP addr add 10.10.11.10/24 dev $DUMMY || true",
+            "$TC qdisc add dev $DUMMY root handle 1: netem limit 1 duplicate 100%",
+            "$TC qdisc add dev $DUMMY parent 1: handle 2: netem duplicate 100%"
+        ],
+        "cmdUnderTest": "ping -c 1 10.10.11.11 -W 0.01",
+        "expExitCode": "1",
+        "verifyCmd": "$TC -s -j qdisc ls dev $DUMMY root",
+        "matchJSON": [
+            {
+                "kind": "netem",
+                "handle": "1:",
+                "bytes": 294,
+                "packets": 3
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DUMMY handle 1: root"
+        ]
+     }
 ]
-- 
2.53.0


^ permalink raw reply related

* [PATCH v3 6/7] selftests/tc-testing: Add mirred test cases exercising loops
From: Stephen Hemminger @ 2026-03-26 18:01 UTC (permalink / raw)
  To: netdev
  Cc: Victor Nogueira, Jamal Hadi Salim, Stephen Hemminger, Jiri Pirko,
	Shuah Khan, Paolo Abeni, Jakub Kicinski,
	open list:KERNEL SELFTEST FRAMEWORK, open list
In-Reply-To: <20260326181701.308275-1-stephen@networkplumber.org>

From: Victor Nogueira <victor@mojatatu.com>

Add mirred loop test cases to validate that those will be caught and other
test cases that were previously misinterpreted as loops by mirred.

This commit adds 12 test cases:

- Redirect multiport: dummy egress -> dev1 ingress -> dummy egress (Loop)
- Redirect singleport: dev1 ingress -> dev1 egress -> dev1 ingress (Loop)
- Redirect multiport: dev1 ingress -> dummy ingress -> dev1 egress (No Loop)
- Redirect multiport: dev1 ingress -> dummy ingress -> dev1 ingress (Loop)
- Redirect multiport: dev1 ingress -> dummy egress -> dev1 ingress (Loop)
- Redirect multiport: dummy egress -> dev1 ingress -> dummy egress, different prios (Loop)
- Redirect multiport: dev1 ingress -> dummy ingress -> dummy egress -> dev1 egress (No Loop)
- Redirect multiport: dev1 ingress -> dummy egress -> dev1 egress (No Loop)
- Redirect multiport: dev1 ingress -> dummy egress -> dummy ingress (No Loop)
- Redirect singleport: dev1 ingress -> dev1 ingress (Loop)
- Redirect singleport: dummy egress -> dummy ingress (No Loop)
- Redirect multiport: dev1 ingress -> dummy ingress -> dummy egress (No Loop)

Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Acked-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
---
 .../tc-testing/tc-tests/actions/mirred.json   | 616 +++++++++++++++++-
 1 file changed, 615 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json
index b056eb966871..d0cad6571691 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json
@@ -1144,6 +1144,620 @@
         "teardown": [
             "$TC qdisc del dev $DUMMY clsact"
         ]
+    },
+    {
+        "id": "531c",
+        "name": "Redirect multiport: dummy egress -> dev1 ingress -> dummy egress (Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin"
+            ]
+        },
+        "setup": [
+            "$IP link set dev $DUMMY up || true",
+            "$IP addr add 10.10.10.10/24 dev $DUMMY || true",
+            "$TC qdisc add dev $DUMMY clsact",
+            "$TC filter add dev $DUMMY egress protocol ip prio 10 matchall action mirred ingress redirect dev $DEV1 index 1",
+            "$TC qdisc add dev $DEV1 clsact",
+            "$TC filter add dev $DEV1 ingress protocol ip prio 10 matchall action mirred egress redirect dev $DUMMY index 2"
+        ],
+        "cmdUnderTest": "ping -c1 -W0.01 -I $DUMMY 10.10.10.1",
+        "expExitCode": "1",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "ingress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 3
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DUMMY clsact",
+            "$TC qdisc del dev $DEV1 clsact"
+        ]
+    },
+    {
+        "id": "b1d7",
+        "name": "Redirect singleport: dev1 ingress -> dev1 egress -> dev1 ingress (Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin",
+                "scapyPlugin"
+            ]
+        },
+        "setup": [
+            "$TC qdisc add dev $DEV1 clsact",
+            "$TC filter add dev $DEV1 ingress protocol ip prio 10 matchall action mirred egress redirect dev $DEV1 index 1"
+        ],
+        "cmdUnderTest": "$TC filter add dev $DEV1 egress protocol ip prio 11 matchall action mirred ingress redirect dev $DEV1 index 2",
+        "scapy": [
+            {
+                "iface": "$DEV0",
+                "count": 1,
+                "packet": "Ether()/IP(dst='10.10.10.1', src='10.10.10.10')/ICMP()"
+            }
+        ],
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "egress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 3
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DEV1 clsact"
+        ]
+    },
+    {
+        "id": "c66d",
+        "name": "Redirect multiport: dev1 ingress -> dummy ingress -> dev1 egress (No Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin",
+                "scapyPlugin"
+            ]
+        },
+        "setup": [
+            "$TC qdisc add dev $DEV1 clsact",
+            "$TC filter add dev $DEV1 ingress protocol ip prio 10 matchall action mirred ingress redirect dev $DUMMY index 1",
+            "$TC qdisc add dev $DUMMY clsact"
+        ],
+        "cmdUnderTest": "$TC filter add dev $DUMMY ingress protocol ip prio 11 matchall action mirred egress redirect dev $DEV1 index 2",
+        "scapy": [
+            {
+                "iface": "$DEV0",
+                "count": 1,
+                "packet": "Ether()/IP(dst='10.10.10.1', src='10.10.10.10')/ICMP()"
+            }
+        ],
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "ingress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 1
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DEV1 clsact",
+            "$TC qdisc del dev $DUMMY clsact"
+        ]
+    },
+    {
+        "id": "aa99",
+        "name": "Redirect multiport: dev1 ingress -> dummy ingress -> dev1 ingress (Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin",
+                "scapyPlugin"
+            ]
+        },
+        "setup": [
+            "$TC qdisc add dev $DEV1 clsact",
+            "$TC filter add dev $DEV1 ingress protocol ip prio 10 matchall action mirred ingress redirect dev $DUMMY index 1",
+            "$TC qdisc add dev $DUMMY clsact"
+        ],
+        "cmdUnderTest": "$TC filter add dev $DUMMY ingress protocol ip prio 11 matchall action mirred ingress redirect dev $DEV1 index 2",
+        "scapy": [
+            {
+                "iface": "$DEV0",
+                "count": 1,
+                "packet": "Ether()/IP(dst='10.10.10.1', src='10.10.10.10')/ICMP()"
+            }
+        ],
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "ingress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 2,
+                            "overlimits": 1
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DEV1 clsact",
+            "$TC qdisc del dev $DUMMY clsact"
+        ]
+    },
+    {
+        "id": "37d7",
+        "name": "Redirect multiport: dev1 ingress -> dummy egress -> dev1 ingress (Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin",
+                "scapyPlugin"
+            ]
+        },
+        "setup": [
+            "$TC qdisc add dev $DEV1 clsact",
+            "$TC filter add dev $DEV1 ingress protocol ip prio 10 matchall action mirred egress redirect dev $DUMMY index 1",
+            "$TC qdisc add dev $DUMMY clsact"
+        ],
+        "cmdUnderTest": "$TC filter add dev $DUMMY egress protocol ip prio 11 matchall action mirred ingress redirect dev $DEV1 index 2",
+        "scapy": [
+            {
+                "iface": "$DEV0",
+                "count": 1,
+                "packet": "Ether()/IP(dst='10.10.10.1', src='10.10.10.10')/ICMP()"
+            }
+        ],
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "egress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 3
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DEV1 clsact",
+            "$TC qdisc del dev $DUMMY clsact"
+        ]
+    },
+    {
+        "id": "6d02",
+        "name": "Redirect multiport: dummy egress -> dev1 ingress -> dummy egress, different prios (Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin"
+            ]
+        },
+        "setup": [
+            "$IP link set dev $DUMMY up || true",
+            "$IP addr add 10.10.10.10/24 dev $DUMMY || true",
+            "$TC qdisc add dev $DUMMY clsact",
+            "$TC filter add dev $DUMMY egress protocol ip prio 10 matchall action mirred ingress redirect dev $DEV1 index 1",
+            "$TC qdisc add dev $DEV1 clsact",
+            "$TC filter add dev $DEV1 ingress protocol ip prio 11 matchall action mirred egress redirect dev $DUMMY index 2"
+        ],
+        "cmdUnderTest": "ping -c1 -W0.01 -I $DUMMY 10.10.10.1",
+        "expExitCode": "1",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "ingress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 3
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DUMMY clsact",
+            "$TC qdisc del dev $DEV1 clsact"
+        ]
+    },
+    {
+        "id": "8115",
+        "name": "Redirect multiport: dev1 ingress -> dummy ingress -> dummy egress -> dev1 egress (No Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin",
+                "scapyPlugin"
+            ]
+        },
+        "setup": [
+            "$TC qdisc add dev $DEV1 clsact",
+            "$TC filter add dev $DEV1 ingress protocol ip prio 10 matchall action mirred ingress redirect dev $DUMMY index 1",
+            "$TC qdisc add dev $DUMMY clsact",
+            "$TC filter add dev $DUMMY ingress protocol ip prio 11 matchall action mirred egress redirect dev $DUMMY index 2"
+        ],
+        "cmdUnderTest": "$TC filter add dev $DUMMY egress protocol ip prio 12 matchall action mirred egress redirect dev $DEV1 index 3",
+        "scapy": [
+            {
+                "iface": "$DEV0",
+                "count": 1,
+                "packet": "Ether()/IP(dst='10.10.10.1', src='10.10.10.10')/ICMP()"
+            }
+        ],
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "ingress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 1
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DEV1 clsact",
+            "$TC qdisc del dev $DUMMY clsact"
+        ]
+    },
+    {
+        "id": "9eb3",
+        "name": "Redirect multiport: dev1 ingress -> dummy egress -> dev1 egress (No Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin",
+                "scapyPlugin"
+            ]
+        },
+        "setup": [
+            "$TC qdisc add dev $DEV1 clsact",
+            "$TC filter add dev $DEV1 ingress protocol ip prio 10 matchall action mirred egress redirect dev $DUMMY index 1",
+            "$TC qdisc add dev $DUMMY clsact"
+        ],
+        "cmdUnderTest": "$TC filter add dev $DUMMY egress protocol ip prio 11 matchall action mirred egress redirect dev $DEV1 index 2",
+        "scapy": [
+            {
+                "iface": "$DEV0",
+                "count": 1,
+                "packet": "Ether()/IP(dst='10.10.10.1', src='10.10.10.10')/ICMP()"
+            }
+        ],
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "egress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 1
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DEV1 clsact",
+            "$TC qdisc del dev $DUMMY clsact"
+        ]
+    },
+    {
+        "id": "d837",
+        "name": "Redirect multiport: dev1 ingress -> dummy egress -> dummy ingress (No Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin",
+                "scapyPlugin"
+            ]
+        },
+        "setup": [
+            "$TC qdisc add dev $DEV1 clsact",
+            "$TC filter add dev $DEV1 ingress protocol ip prio 10 matchall action mirred egress redirect dev $DUMMY index 1",
+            "$TC qdisc add dev $DUMMY clsact"
+        ],
+        "cmdUnderTest": "$TC filter add dev $DUMMY egress protocol ip prio 11 matchall action mirred ingress redirect dev $DUMMY index 2",
+        "scapy": [
+            {
+                "iface": "$DEV0",
+                "count": 1,
+                "packet": "Ether()/IP(dst='10.10.10.1', src='10.10.10.10')/ICMP()"
+            }
+        ],
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "egress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 1
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DEV1 clsact",
+            "$TC qdisc del dev $DUMMY clsact"
+        ]
+    },
+    {
+        "id": "2071",
+        "name": "Redirect singleport: dev1 ingress -> dev1 ingress (Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin",
+                "scapyPlugin"
+            ]
+        },
+        "setup": [
+            "$TC qdisc add dev $DEV1 clsact"
+        ],
+        "cmdUnderTest": "$TC filter add dev $DEV1 ingress protocol ip prio 10 matchall action mirred ingress redirect dev $DEV1 index 1",
+        "scapy": [
+            {
+                "iface": "$DEV0",
+                "count": 1,
+                "packet": "Ether()/IP(dst='10.10.10.1', src='10.10.10.10')/ICMP()"
+            }
+        ],
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "ingress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 1,
+                            "overlimits": 1
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DEV1 clsact"
+        ]
+    },
+    {
+        "id": "0101",
+        "name": "Redirect singleport: dummy egress -> dummy ingress (No Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin"
+            ]
+        },
+        "setup": [
+            "$IP addr add 10.10.10.10/24 dev $DUMMY || true",
+            "$TC qdisc add dev $DUMMY clsact",
+            "$TC filter add dev $DUMMY egress protocol ip prio 11 matchall action mirred ingress redirect dev $DUMMY index 1"
+        ],
+        "cmdUnderTest": "ping -c1 -W0.01 -I $DUMMY 10.10.10.1",
+        "expExitCode": "1",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "ingress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 1
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DUMMY clsact"
+        ]
+    },
+    {
+        "id": "cf97",
+        "name": "Redirect multiport: dev1 ingress -> dummy ingress -> dummy egress (No Loop)",
+        "category": [
+            "filter",
+            "mirred"
+        ],
+        "plugins": {
+            "requires": [
+                "nsPlugin",
+                "scapyPlugin"
+            ]
+        },
+        "setup": [
+            "$TC qdisc add dev $DEV1 clsact",
+            "$TC filter add dev $DEV1 ingress protocol ip prio 10 matchall action mirred ingress redirect dev $DUMMY index 1",
+            "$TC qdisc add dev $DUMMY clsact"
+        ],
+        "cmdUnderTest": "$TC filter add dev $DUMMY ingress protocol ip prio 11 matchall action mirred egress redirect dev $DUMMY index 2",
+        "scapy": [
+            {
+                "iface": "$DEV0",
+                "count": 1,
+                "packet": "Ether()/IP(dst='10.10.10.1', src='10.10.10.10')/ICMP()"
+            }
+        ],
+        "expExitCode": "0",
+        "verifyCmd": "$TC -j -s actions get action mirred index 1",
+        "matchJSON": [
+            {
+                "total acts": 0
+            },
+            {
+                "actions": [
+                    {
+                        "order": 1,
+                        "kind": "mirred",
+                        "mirred_action": "redirect",
+                        "direction": "ingress",
+                        "index": 1,
+                        "stats": {
+                            "packets": 1
+                        },
+                        "not_in_hw": true
+                    }
+                ]
+            }
+        ],
+        "teardown": [
+            "$TC qdisc del dev $DEV1 clsact",
+            "$TC qdisc del dev $DUMMY clsact"
+        ]
     }
-
 ]
-- 
2.53.0


^ permalink raw reply related

* [PATCH v3 5/7] net/sched: Fix ethx:ingress -> ethy:egress -> ethx:ingress mirred loop
From: Stephen Hemminger @ 2026-03-26 18:01 UTC (permalink / raw)
  To: netdev
  Cc: Jamal Hadi Salim, Victor Nogueira, Stephen Hemminger, Jiri Pirko,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Toke Høiland-Jørgensen, Kuniyuki Iwashima,
	open list
In-Reply-To: <20260326181701.308275-1-stephen@networkplumber.org>

From: Jamal Hadi Salim <jhs@mojatatu.com>

When mirred redirects to ingress (from either ingress or egress) the loop
state from sched_mirred_dev array dev is lost because of 1) the packet
deferral into the backlog and 2) the fact the sched_mirred_dev array is
cleared. In such cases, if there was a loop we won't discover it.

Here's a simple test to reproduce:
ip a add dev port0 10.10.10.11/24

tc qdisc add dev port0 clsact
tc filter add dev port0 egress protocol ip \
   prio 10 matchall action mirred ingress redirect dev port1

tc qdisc add dev port1 clsact
tc filter add dev port1 ingress protocol ip \
   prio 10 matchall action mirred egress redirect dev port0

ping -c 1 -W0.01 10.10.10.10

Fixes: fe946a751d9b ("net/sched: act_mirred: add loop detection")
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
---
 net/sched/act_mirred.c | 47 +++++++++++++++++++++++++++---------------
 1 file changed, 30 insertions(+), 17 deletions(-)

diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 05e0b14b5773..001dd9275e9b 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -26,6 +26,10 @@
 #include <net/tc_act/tc_mirred.h>
 #include <net/tc_wrapper.h>
 
+#define MIRRED_DEFER_LIMIT 3
+_Static_assert(MIRRED_DEFER_LIMIT <= 3,
+	       "MIRRED_DEFER_LIMIT exceeds tc_depth bitfield width");
+
 static LIST_HEAD(mirred_list);
 static DEFINE_SPINLOCK(mirred_list_lock);
 
@@ -234,12 +238,15 @@ tcf_mirred_forward(bool at_ingress, bool want_ingress, struct sk_buff *skb)
 {
 	int err;
 
-	if (!want_ingress)
+	if (!want_ingress) {
 		err = tcf_dev_queue_xmit(skb, dev_queue_xmit);
-	else if (!at_ingress)
-		err = netif_rx(skb);
-	else
-		err = netif_receive_skb(skb);
+	} else {
+		skb->tc_depth++;
+		if (!at_ingress)
+			err = netif_rx(skb);
+		else
+			err = netif_receive_skb(skb);
+	}
 
 	return err;
 }
@@ -426,6 +433,7 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb,
 	struct netdev_xmit *xmit;
 	bool m_mac_header_xmit;
 	struct net_device *dev;
+	bool want_ingress;
 	int i, m_eaction;
 	u32 blockid;
 
@@ -434,7 +442,8 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb,
 #else
 	xmit = this_cpu_ptr(&softnet_data.xmit);
 #endif
-	if (unlikely(xmit->sched_mirred_nest >= MIRRED_NEST_LIMIT)) {
+	if (unlikely(xmit->sched_mirred_nest >= MIRRED_NEST_LIMIT ||
+		     skb->tc_depth >= MIRRED_DEFER_LIMIT)) {
 		net_warn_ratelimited("Packet exceeded mirred recursion limit on dev %s\n",
 				     netdev_name(skb->dev));
 		return TC_ACT_SHOT;
@@ -453,23 +462,27 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb,
 		tcf_action_inc_overlimit_qstats(&m->common);
 		return retval;
 	}
-	for (i = 0; i < xmit->sched_mirred_nest; i++) {
-		if (xmit->sched_mirred_dev[i] != dev)
-			continue;
-		pr_notice_once("tc mirred: loop on device %s\n",
-			       netdev_name(dev));
-		tcf_action_inc_overlimit_qstats(&m->common);
-		return retval;
-	}
 
-	xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev;
+	m_eaction = READ_ONCE(m->tcfm_eaction);
+	want_ingress = tcf_mirred_act_wants_ingress(m_eaction);
+	if (!want_ingress) {
+		for (i = 0; i < xmit->sched_mirred_nest; i++) {
+			if (xmit->sched_mirred_dev[i] != dev)
+				continue;
+			pr_notice_once("tc mirred: loop on device %s\n",
+				       netdev_name(dev));
+			tcf_action_inc_overlimit_qstats(&m->common);
+			return retval;
+		}
+		xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev;
+	}
 
 	m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit);
-	m_eaction = READ_ONCE(m->tcfm_eaction);
 
 	retval = tcf_mirred_to_dev(skb, m, dev, m_mac_header_xmit, m_eaction,
 				   retval);
-	xmit->sched_mirred_nest--;
+	if (!want_ingress)
+		xmit->sched_mirred_nest--;
 
 	return retval;
 }
-- 
2.53.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox