[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20211208173205.zajfvg6zvi4g5kln@linutronix.de>
Date: Wed, 8 Dec 2021 18:32:05 +0100
From: Sebastian Andrzej Siewior <bigeasy@...utronix.de>
To: wireguard@...ts.zx2c4.com, netdev@...r.kernel.org
Cc: "Jason A. Donenfeld" <Jason@...c4.com>,
"David S. Miller" <davem@...emloft.net>,
Jakub Kicinski <kuba@...nel.org>,
Thomas Gleixner <tglx@...utronix.de>,
Peter Zijlstra <peterz@...radead.org>
Subject: [RFC] wiregard RX packet processing.
I didn't understand everything, I just stumbled upon this while looking
for something else and don't have the time to figure everything out.
Also I might haven taken a wrong turn somewhere…
need_resched() is something you want avoid unless you write core code.
On a PREEMPT kernel you never observe true here and cond_resched() is a
nop. On non-PREEMPT kernels need_resched() can return true/ false _and_
should_resched() (which is part of cond_resched()) returns only true if
the same bit is true. This means invoking only cond_resched() saves one
read access. Bonus points: On x86 that bit is folded into the preemption
counter so you avoid reading that bit entirely plus the whole thing is
optimized away on a PREEMPT kernel.
wg_queue_enqueue_per_peer_rx() enqueues somehow skb for NAPI processing
(this bit I haven't figured out yet but it has to) and then invokes
napi_schedule(). This napi_schedule() wasn't meant to be invoked from
preemptible context, only from an actual IRQ handler:
- if NAPI is already active (which can only happen if it is running on a
remote CPU) then nothing happens. Good.
- if NAPI is idle then __napi_schedule() will "schedule" it. Here is
the thing: You are in process context (kworker) so nothing happens
right away: NET_RX_SOFTIRQ is set for the local CPU and NAPI struct is
added to the list. Now you need to wait until a random interrupt
appears which will notice that a softirq bit is set and will process
it. So it will happen eventually…
I would suggest to either:
- add a comment that this is know and it doesn't not matter because
$REASON. I would imagine you might want to batch multiple skbs but…
- add a BH disable section around wg_queue_enqueue_per_peer_rx() (see
below). That bh-enable() will invoke pending softirqs which in your
case should invoke wg_packet_rx_poll() where you see only one skb.
diff --git a/drivers/net/wireguard/receive.c b/drivers/net/wireguard/receive.c
index 7b8df406c7737..64e4ca1ded108 100644
--- a/drivers/net/wireguard/receive.c
+++ b/drivers/net/wireguard/receive.c
@@ -507,9 +507,11 @@ void wg_packet_decrypt_worker(struct work_struct *work)
enum packet_state state =
likely(decrypt_packet(skb, PACKET_CB(skb)->keypair)) ?
PACKET_STATE_CRYPTED : PACKET_STATE_DEAD;
+ local_bh_disable();
wg_queue_enqueue_per_peer_rx(skb, state);
- if (need_resched())
- cond_resched();
+ local_bh_enable();
+
+ cond_resched();
}
}
Sebastian
Powered by blists - more mailing lists