netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net] igc: Prevent garbled TX queue with XDP ZEROCOPY
@ 2023-06-26 11:34 Florian Kauer
  2023-06-26 13:16 ` Maciej Fijalkowski
  2023-06-26 13:24 ` Simon Horman
  0 siblings, 2 replies; 5+ messages in thread
From: Florian Kauer @ 2023-06-26 11:34 UTC (permalink / raw)
  To: Jesse Brandeburg, Tony Nguyen, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Vedang Patel, Maciej Fijalkowski,
	Jithu Joseph, Andre Guedes
  Cc: intel-wired-lan, netdev, linux-kernel, kurt, florian.kauer

When the TX queue is used both by an application using
AF_XDP with ZEROCOPY as well as a second non-XDP application
generating high traffic, the queue pointers can get in
an invalid state. Most importantly, it can happen that
next_to_use points to an entry where next_to_watch != 0.

However, the implementation assumes at several places
that this is never the case, so if it does hold,
bad things happen. In particular, within the loop inside
of igc_clean_tx_irq(), next_to_clean can overtake next_to_use.
Finally, this prevents any further transmission via
this queue and it never gets unblocked or signaled.
Secondly, if the queue is in this garbled state,
the inner loop of igc_clean_tx_ring() will never terminate,
completely hogging a CPU core.

The reason is that igc_xdp_xmit_zc() reads next_to_use
before aquiring the lock, and writing it back
(potentially unmodified) later. If it got modified
before locking, the outdated next_to_use is written
pointing to an entry that was already used elsewhere
(and thus next_to_watch got written).

Fixes: 9acf59a752d4 ("igc: Enable TX via AF_XDP zero-copy")
Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Reviewed-by: Kurt Kanzenbach <kurt@linutronix.de>
Tested-by: Kurt Kanzenbach <kurt@linutronix.de>
---
 drivers/net/ethernet/intel/igc/igc_main.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index eb4f0e562f60..2eff073ee771 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -2791,7 +2791,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
 	struct netdev_queue *nq = txring_txq(ring);
 	union igc_adv_tx_desc *tx_desc = NULL;
 	int cpu = smp_processor_id();
-	u16 ntu = ring->next_to_use;
+	u16 ntu;
 	struct xdp_desc xdp_desc;
 	u16 budget;
 
@@ -2800,6 +2800,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
 
 	__netif_tx_lock(nq, cpu);
 
+	ntu = ring->next_to_use;
 	budget = igc_desc_unused(ring);
 
 	while (xsk_tx_peek_desc(pool, &xdp_desc) && budget--) {
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH net] igc: Prevent garbled TX queue with XDP ZEROCOPY
  2023-06-26 11:34 Florian Kauer
@ 2023-06-26 13:16 ` Maciej Fijalkowski
  2023-06-26 13:24 ` Simon Horman
  1 sibling, 0 replies; 5+ messages in thread
From: Maciej Fijalkowski @ 2023-06-26 13:16 UTC (permalink / raw)
  To: Florian Kauer
  Cc: Jesse Brandeburg, Tony Nguyen, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Vedang Patel, Jithu Joseph,
	Andre Guedes, intel-wired-lan, netdev, linux-kernel, kurt

On Mon, Jun 26, 2023 at 01:34:29PM +0200, Florian Kauer wrote:

Hi Florian,

> When the TX queue is used both by an application using
> AF_XDP with ZEROCOPY as well as a second non-XDP application
> generating high traffic, the queue pointers can get in
> an invalid state. Most importantly, it can happen that
> next_to_use points to an entry where next_to_watch != 0.

Although what you are fixing is clearly a bug, I don't follow the
paragraph above - what does it mean that next_to_watch is not 0? What is
the purpose of it within igc driver?

Another thing is that even though txq is shared between XSK ZC and normal
app it feels that a lot of unnecessary logic is executed for XSK ZC (when
running igc_clean_tx_irq()) but that's just a side comment to consider
implementing a separate routine for XSK ZC Tx cleaning.

> 
> However, the implementation assumes at several places
> that this is never the case, so if it does hold,
> bad things happen. In particular, within the loop inside
> of igc_clean_tx_irq(), next_to_clean can overtake next_to_use.
> Finally, this prevents any further transmission via
> this queue and it never gets unblocked or signaled.
> Secondly, if the queue is in this garbled state,
> the inner loop of igc_clean_tx_ring() will never terminate,
> completely hogging a CPU core.
> 
> The reason is that igc_xdp_xmit_zc() reads next_to_use
> before aquiring the lock, and writing it back
> (potentially unmodified) later. If it got modified
> before locking, the outdated next_to_use is written
> pointing to an entry that was already used elsewhere
> (and thus next_to_watch got written).
> 
> Fixes: 9acf59a752d4 ("igc: Enable TX via AF_XDP zero-copy")
> Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
> Reviewed-by: Kurt Kanzenbach <kurt@linutronix.de>
> Tested-by: Kurt Kanzenbach <kurt@linutronix.de>
> ---
>  drivers/net/ethernet/intel/igc/igc_main.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
> index eb4f0e562f60..2eff073ee771 100644
> --- a/drivers/net/ethernet/intel/igc/igc_main.c
> +++ b/drivers/net/ethernet/intel/igc/igc_main.c
> @@ -2791,7 +2791,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
>  	struct netdev_queue *nq = txring_txq(ring);
>  	union igc_adv_tx_desc *tx_desc = NULL;
>  	int cpu = smp_processor_id();
> -	u16 ntu = ring->next_to_use;
> +	u16 ntu;
>  	struct xdp_desc xdp_desc;
>  	u16 budget;

You are breaking RCT here.

>  
> @@ -2800,6 +2800,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
>  
>  	__netif_tx_lock(nq, cpu);
>  
> +	ntu = ring->next_to_use;
>  	budget = igc_desc_unused(ring);
>  
>  	while (xsk_tx_peek_desc(pool, &xdp_desc) && budget--) {
> -- 
> 2.39.2
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net] igc: Prevent garbled TX queue with XDP ZEROCOPY
  2023-06-26 11:34 Florian Kauer
  2023-06-26 13:16 ` Maciej Fijalkowski
@ 2023-06-26 13:24 ` Simon Horman
  1 sibling, 0 replies; 5+ messages in thread
From: Simon Horman @ 2023-06-26 13:24 UTC (permalink / raw)
  To: Florian Kauer
  Cc: Jesse Brandeburg, Tony Nguyen, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Vedang Patel, Maciej Fijalkowski,
	Jithu Joseph, Andre Guedes, intel-wired-lan, netdev, linux-kernel,
	kurt

On Mon, Jun 26, 2023 at 01:34:29PM +0200, Florian Kauer wrote:
> When the TX queue is used both by an application using
> AF_XDP with ZEROCOPY as well as a second non-XDP application
> generating high traffic, the queue pointers can get in
> an invalid state. Most importantly, it can happen that
> next_to_use points to an entry where next_to_watch != 0.
> 
> However, the implementation assumes at several places
> that this is never the case, so if it does hold,
> bad things happen. In particular, within the loop inside
> of igc_clean_tx_irq(), next_to_clean can overtake next_to_use.
> Finally, this prevents any further transmission via
> this queue and it never gets unblocked or signaled.
> Secondly, if the queue is in this garbled state,
> the inner loop of igc_clean_tx_ring() will never terminate,
> completely hogging a CPU core.
> 
> The reason is that igc_xdp_xmit_zc() reads next_to_use
> before aquiring the lock, and writing it back

Hi Florian,

a minor nit via checkpatch --codespell: aquiring -> acquiring

> (potentially unmodified) later. If it got modified
> before locking, the outdated next_to_use is written
> pointing to an entry that was already used elsewhere
> (and thus next_to_watch got written).
> 
> Fixes: 9acf59a752d4 ("igc: Enable TX via AF_XDP zero-copy")
> Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
> Reviewed-by: Kurt Kanzenbach <kurt@linutronix.de>
> Tested-by: Kurt Kanzenbach <kurt@linutronix.de>

...

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net] igc: Prevent garbled TX queue with XDP ZEROCOPY
@ 2023-07-17 17:54 Tony Nguyen
  2023-07-19  2:10 ` patchwork-bot+netdevbpf
  0 siblings, 1 reply; 5+ messages in thread
From: Tony Nguyen @ 2023-07-17 17:54 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, netdev
  Cc: Florian Kauer, anthony.l.nguyen, maciej.fijalkowski,
	magnus.karlsson, ast, daniel, hawk, john.fastabend, bpf,
	sasha.neftin, Kurt Kanzenbach, Vinicius Costa Gomes, Simon Horman,
	Naama Meir

From: Florian Kauer <florian.kauer@linutronix.de>

In normal operation, each populated queue item has
next_to_watch pointing to the last TX desc of the packet,
while each cleaned item has it set to 0. In particular,
next_to_use that points to the next (necessarily clean)
item to use has next_to_watch set to 0.

When the TX queue is used both by an application using
AF_XDP with ZEROCOPY as well as a second non-XDP application
generating high traffic, the queue pointers can get in
an invalid state where next_to_use points to an item
where next_to_watch is NOT set to 0.

However, the implementation assumes at several places
that this is never the case, so if it does hold,
bad things happen. In particular, within the loop inside
of igc_clean_tx_irq(), next_to_clean can overtake next_to_use.
Finally, this prevents any further transmission via
this queue and it never gets unblocked or signaled.
Secondly, if the queue is in this garbled state,
the inner loop of igc_clean_tx_ring() will never terminate,
completely hogging a CPU core.

The reason is that igc_xdp_xmit_zc() reads next_to_use
before acquiring the lock, and writing it back
(potentially unmodified) later. If it got modified
before locking, the outdated next_to_use is written
pointing to an item that was already used elsewhere
(and thus next_to_watch got written).

Fixes: 9acf59a752d4 ("igc: Enable TX via AF_XDP zero-copy")
Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Reviewed-by: Kurt Kanzenbach <kurt@linutronix.de>
Tested-by: Kurt Kanzenbach <kurt@linutronix.de>
Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Tested-by: Naama Meir <naamax.meir@linux.intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/igc/igc_main.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 9f93f0f4f752..f36bc2a1849a 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -2828,9 +2828,8 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
 	struct netdev_queue *nq = txring_txq(ring);
 	union igc_adv_tx_desc *tx_desc = NULL;
 	int cpu = smp_processor_id();
-	u16 ntu = ring->next_to_use;
 	struct xdp_desc xdp_desc;
-	u16 budget;
+	u16 budget, ntu;
 
 	if (!netif_carrier_ok(ring->netdev))
 		return;
@@ -2840,6 +2839,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
 	/* Avoid transmit queue timeout since we share it with the slow path */
 	txq_trans_cond_update(nq);
 
+	ntu = ring->next_to_use;
 	budget = igc_desc_unused(ring);
 
 	while (xsk_tx_peek_desc(pool, &xdp_desc) && budget--) {
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH net] igc: Prevent garbled TX queue with XDP ZEROCOPY
  2023-07-17 17:54 [PATCH net] igc: Prevent garbled TX queue with XDP ZEROCOPY Tony Nguyen
@ 2023-07-19  2:10 ` patchwork-bot+netdevbpf
  0 siblings, 0 replies; 5+ messages in thread
From: patchwork-bot+netdevbpf @ 2023-07-19  2:10 UTC (permalink / raw)
  To: Tony Nguyen
  Cc: davem, kuba, pabeni, edumazet, netdev, florian.kauer,
	maciej.fijalkowski, magnus.karlsson, ast, daniel, hawk,
	john.fastabend, bpf, sasha.neftin, kurt, vinicius.gomes,
	simon.horman, naamax.meir

Hello:

This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Mon, 17 Jul 2023 10:54:44 -0700 you wrote:
> From: Florian Kauer <florian.kauer@linutronix.de>
> 
> In normal operation, each populated queue item has
> next_to_watch pointing to the last TX desc of the packet,
> while each cleaned item has it set to 0. In particular,
> next_to_use that points to the next (necessarily clean)
> item to use has next_to_watch set to 0.
> 
> [...]

Here is the summary with links:
  - [net] igc: Prevent garbled TX queue with XDP ZEROCOPY
    https://git.kernel.org/netdev/net/c/78adb4bcf99e

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-07-19  2:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-07-17 17:54 [PATCH net] igc: Prevent garbled TX queue with XDP ZEROCOPY Tony Nguyen
2023-07-19  2:10 ` patchwork-bot+netdevbpf
  -- strict thread matches above, loose matches on Subject: below --
2023-06-26 11:34 Florian Kauer
2023-06-26 13:16 ` Maciej Fijalkowski
2023-06-26 13:24 ` Simon Horman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).