Module Name: src
Committed By: riastradh
Date: Mon Jul 29 19:45:56 UTC 2024
Modified Files:
src/sys/net: if_wg.c
Log Message:
wg(4): Trigger session initiation in wgintr, not in wg_output.
We have to look up the session in wgintr anyway, for
wg_send_data_msg. By triggering session initiation in wgintr instead
of wg_output, we can skip the stable session lookup and reference in
wg_output -- simpler that way.
Post-fix tidying for:
PR kern/55729: net/if_wg/t_misc:wg_rekey test case fails
PR kern/56252: wg(4) state machine has race conditions
PR kern/58463: if_wg does not work when idle.
To generate a diff of this commit:
cvs rdiff -u -r1.125 -r1.126 src/sys/net/if_wg.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/net/if_wg.c
diff -u src/sys/net/if_wg.c:1.125 src/sys/net/if_wg.c:1.126
--- src/sys/net/if_wg.c:1.125 Mon Jul 29 19:44:22 2024
+++ src/sys/net/if_wg.c Mon Jul 29 19:45:56 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wg.c,v 1.125 2024/07/29 19:44:22 riastradh Exp $ */
+/* $NetBSD: if_wg.c,v 1.126 2024/07/29 19:45:56 riastradh Exp $ */
/*
* Copyright (C) Ryota Ozaki <[email protected]>
@@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.125 2024/07/29 19:44:22 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.126 2024/07/29 19:45:56 riastradh Exp $");
#ifdef _KERNEL_OPT
#include "opt_altq_enabled.h"
@@ -1911,7 +1911,7 @@ wg_send_handshake_msg_init(struct wg_sof
WG_DLOG("send_hs_msg failed, error=%d\n", error);
wg_put_session_index(wg, wgs);
m = atomic_swap_ptr(&wgp->wgp_pending, NULL);
- membar_acquire(); /* matches membar_release in wg_output */
+ membar_acquire(); /* matches membar_release in wgintr */
m_freem(m);
return;
}
@@ -2082,7 +2082,7 @@ wg_swap_sessions(struct wg_softc *wg, st
* or else the responder will never answer.
*/
if ((m = atomic_swap_ptr(&wgp->wgp_pending, NULL)) != NULL) {
- membar_acquire(); /* matches membar_release in wg_output */
+ membar_acquire(); /* matches membar_release in wgintr */
kpreempt_disable();
const uint32_t h = curcpu()->ci_index; // pktq_rps_hash(m)
M_SETCTX(m, wgp);
@@ -3708,8 +3708,28 @@ wgintr(void *cookie)
while ((m = pktq_dequeue(wg_pktq)) != NULL) {
wgp = M_GETCTX(m, struct wg_peer *);
if ((wgs = wg_get_stable_session(wgp, &psref)) == NULL) {
+ /*
+ * No established session. If we're the first
+ * to try sending data, schedule a handshake
+ * and queue the packet for when the handshake
+ * is done; otherwise just drop the packet and
+ * let the ongoing handshake attempt continue.
+ * We could queue more data packets but it's
+ * not clear that's worthwhile.
+ */
WG_TRACE("no stable session");
- wg_schedule_peer_task(wgp, WGP_TASK_SEND_INIT_MESSAGE);
+ membar_release();
+ if ((m = atomic_swap_ptr(&wgp->wgp_pending, m)) ==
+ NULL) {
+ WG_TRACE("queued first packet;"
+ " init handshake");
+ wg_schedule_peer_task(wgp,
+ WGP_TASK_SEND_INIT_MESSAGE);
+ } else {
+ membar_acquire();
+ WG_TRACE("first packet already queued,"
+ " dropping");
+ }
goto next0;
}
if (__predict_false(wg_session_hit_limits(wgs))) {
@@ -3732,7 +3752,7 @@ wg_purge_pending_packets(struct wg_peer
struct mbuf *m;
m = atomic_swap_ptr(&wgp->wgp_pending, NULL);
- membar_acquire(); /* matches membar_release in wg_output */
+ membar_acquire(); /* matches membar_release in wgintr */
m_freem(m);
#ifdef ALTQ
wg_start(&wgp->wgp_sc->wg_if);
@@ -4202,8 +4222,7 @@ wg_output(struct ifnet *ifp, struct mbuf
{
struct wg_softc *wg = ifp->if_softc;
struct wg_peer *wgp = NULL;
- struct wg_session *wgs = NULL;
- struct psref wgp_psref, wgs_psref;
+ struct psref wgp_psref;
int bound;
int error;
@@ -4240,33 +4259,7 @@ wg_output(struct ifnet *ifp, struct mbuf
m->m_pkthdr.csum_flags = 0;
m->m_pkthdr.csum_data = 0;
- /* Check whether there's an established session. */
- wgs = wg_get_stable_session(wgp, &wgs_psref);
- if (wgs == NULL) {
- /*
- * No established session. If we're the first to try
- * sending data, schedule a handshake and queue the
- * packet for when the handshake is done; otherwise
- * just drop the packet and let the ongoing handshake
- * attempt continue. We could queue more data packets
- * but it's not clear that's worthwhile.
- *
- * membar_release matches membar_acquire in
- * wg_swap_sessions, wg_purge_pending_packets, and
- * wg_send_handshake_msg_init.
- */
- membar_release();
- if ((m = atomic_swap_ptr(&wgp->wgp_pending, m)) == NULL) {
- WG_TRACE("queued first packet; init handshake");
- wg_schedule_peer_task(wgp, WGP_TASK_SEND_INIT_MESSAGE);
- } else {
- membar_acquire();
- WG_TRACE("first packet already queued, dropping");
- }
- goto out1;
- }
-
- /* There's an established session. Toss it in the queue. */
+ /* Toss it in the queue. */
#ifdef ALTQ
if (altq) {
mutex_enter(ifp->if_snd.ifq_lock);
@@ -4278,7 +4271,7 @@ wg_output(struct ifnet *ifp, struct mbuf
mutex_exit(ifp->if_snd.ifq_lock);
if (m == NULL) {
wg_start(ifp);
- goto out2;
+ goto out1;
}
}
#endif
@@ -4289,17 +4282,16 @@ wg_output(struct ifnet *ifp, struct mbuf
WGLOG(LOG_ERR, "%s: pktq full, dropping\n",
if_name(&wg->wg_if));
error = ENOBUFS;
- goto out3;
+ goto out2;
}
m = NULL; /* consumed */
error = 0;
-out3: kpreempt_enable();
+out2: kpreempt_enable();
#ifdef ALTQ
-out2:
+out1:
#endif
- wg_put_session(wgs, &wgs_psref);
-out1: wg_put_peer(wgp, &wgp_psref);
+ wg_put_peer(wgp, &wgp_psref);
out0: m_freem(m);
curlwp_bindx(bound);
return error;