Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/net wg: Use thmap(9) for peer and session lookup.



details:   https://anonhg.NetBSD.org/src/rev/d02eb5546091
branches:  trunk
changeset: 938050:d02eb5546091
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Mon Aug 31 20:23:56 2020 +0000

description:
wg: Use thmap(9) for peer and session lookup.

Make sure we also don't trip over our own shoelaces by choosing the
same session index twice.

diffstat:

 sys/net/if_wg.c |  167 ++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 132 insertions(+), 35 deletions(-)

diffs (truncated from 343 to 300 lines):

diff -r 8906cf024dd5 -r d02eb5546091 sys/net/if_wg.c
--- a/sys/net/if_wg.c   Mon Aug 31 20:22:57 2020 +0000
+++ b/sys/net/if_wg.c   Mon Aug 31 20:23:56 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_wg.c,v 1.36 2020/08/31 20:21:30 riastradh Exp $     */
+/*     $NetBSD: if_wg.c,v 1.37 2020/08/31 20:23:56 riastradh Exp $     */
 
 /*
  * Copyright (C) Ryota Ozaki <ozaki.ryota%gmail.com@localhost>
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.36 2020/08/31 20:21:30 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.37 2020/08/31 20:23:56 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -77,6 +77,7 @@
 #include <sys/sysctl.h>
 #include <sys/syslog.h>
 #include <sys/systm.h>
+#include <sys/thmap.h>
 #include <sys/time.h>
 #include <sys/timespec.h>
 
@@ -603,6 +604,9 @@
 
        int             wg_npeers;
        struct pslist_head      wg_peers;
+       struct thmap    *wg_peers_bypubkey;
+       struct thmap    *wg_peers_byname;
+       struct thmap    *wg_sessions_byindex;
        uint16_t        wg_listen_port;
 
        struct wg_worker        *wg_worker;
@@ -1159,6 +1163,52 @@
 }
 #endif
 
+static uint32_t
+wg_assign_sender_index(struct wg_softc *wg, struct wg_session *wgs)
+{
+       struct wg_peer *wgp = wgs->wgs_peer;
+       struct wg_session *wgs0;
+       uint32_t index;
+       void *garbage;
+
+       mutex_enter(wgs->wgs_lock);
+
+       /* Release the current index, if there is one.  */
+       while ((index = wgs->wgs_sender_index) != 0) {
+               /* Remove the session by index.  */
+               thmap_del(wg->wg_sessions_byindex, &index, sizeof index);
+               wgs->wgs_sender_index = 0;
+               mutex_exit(wgs->wgs_lock);
+
+               /* Wait for all thmap_gets to complete, and GC.  */
+               garbage = thmap_stage_gc(wg->wg_sessions_byindex);
+               mutex_enter(wgs->wgs_peer->wgp_lock);
+               pserialize_perform(wgp->wgp_psz);
+               mutex_exit(wgs->wgs_peer->wgp_lock);
+               thmap_gc(wg->wg_sessions_byindex, garbage);
+
+               mutex_enter(wgs->wgs_lock);
+       }
+
+restart:
+       /* Pick a uniform random nonzero index.  */
+       while (__predict_false((index = cprng_strong32()) == 0))
+               continue;
+
+       /* Try to take it.  */
+       wgs->wgs_sender_index = index;
+       wgs0 = thmap_put(wg->wg_sessions_byindex,
+           &wgs->wgs_sender_index, sizeof wgs->wgs_sender_index, wgs);
+
+       /* If someone else beat us, start over.  */
+       if (__predict_false(wgs0 != wgs))
+               goto restart;
+
+       mutex_exit(wgs->wgs_lock);
+
+       return index;
+}
+
 /*
  * Handshake patterns
  *
@@ -1192,7 +1242,7 @@
        uint8_t privkey[WG_EPHEMERAL_KEY_LEN];
 
        wgmi->wgmi_type = WG_MSG_TYPE_INIT;
-       wgmi->wgmi_sender = cprng_strong32();
+       wgmi->wgmi_sender = wg_assign_sender_index(wg, wgs);
 
        /* [W] 5.4.2: First Message: Initiator to Responder */
 
@@ -1267,7 +1317,6 @@
        memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey));
        memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash));
        memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey));
-       wgs->wgs_sender_index = wgmi->wgmi_sender;
        WG_DLOG("%s: sender=%x\n", __func__, wgs->wgs_sender_index);
 }
 
@@ -1609,7 +1658,7 @@
        memcpy(ckey, wgs->wgs_chaining_key, sizeof(ckey));
 
        wgmr->wgmr_type = WG_MSG_TYPE_RESP;
-       wgmr->wgmr_sender = cprng_strong32();
+       wgmr->wgmr_sender = wg_assign_sender_index(wg, wgs);
        wgmr->wgmr_receiver = wgmi->wgmi_sender;
 
        /* [W] 5.4.3 Second Message: Responder to Initiator */
@@ -1680,7 +1729,6 @@
        memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey));
        memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey));
        memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey));
-       wgs->wgs_sender_index = wgmr->wgmr_sender;
        wgs->wgs_receiver_index = wgmi->wgmi_sender;
        WG_DLOG("sender=%x\n", wgs->wgs_sender_index);
        WG_DLOG("receiver=%x\n", wgs->wgs_receiver_index);
@@ -1906,12 +1954,7 @@
        struct wg_peer *wgp;
 
        int s = pserialize_read_enter();
-       /* XXX O(n) */
-       WG_PEER_READER_FOREACH(wgp, wg) {
-               if (consttime_memequal(wgp->wgp_pubkey, pubkey,
-                       sizeof(wgp->wgp_pubkey)))
-                       break;
-       }
+       wgp = thmap_get(wg->wg_peers_bypubkey, pubkey, WG_STATIC_KEY_LEN);
        if (wgp != NULL)
                wg_get_peer(wgp, psref);
        pserialize_read_exit(s);
@@ -2087,24 +2130,10 @@
 wg_lookup_session_by_index(struct wg_softc *wg, const uint32_t index,
     struct psref *psref)
 {
-       struct wg_peer *wgp;
        struct wg_session *wgs;
 
        int s = pserialize_read_enter();
-       /* XXX O(n) */
-       WG_PEER_READER_FOREACH(wgp, wg) {
-               wgs = wgp->wgp_session_stable;
-               WG_DLOG("index=%x wgs_sender_index=%x\n",
-                   index, wgs->wgs_sender_index);
-               if (wgs->wgs_sender_index == index)
-                       break;
-               wgs = wgp->wgp_session_unstable;
-               WG_DLOG("index=%x wgs_sender_index=%x\n",
-                   index, wgs->wgs_sender_index);
-               if (wgs->wgs_sender_index == index)
-                       break;
-               wgs = NULL;
-       }
+       wgs = thmap_get(wg->wg_sessions_byindex, &index, sizeof index);
        if (wgs != NULL)
                psref_acquire(psref, &wgs->wgs_psref, wg_psref_class);
        pserialize_read_exit(s);
@@ -3262,7 +3291,10 @@
 {
        struct wg_session *wgs;
        struct wg_softc *wg = wgp->wgp_sc;
-
+       uint32_t index;
+       void *garbage;
+
+       /* Prevent new packets from this peer on any source address.  */
        rw_enter(wg->wg_rwlock, RW_WRITER);
        for (int i = 0; i < wgp->wgp_n_allowedips; i++) {
                struct wg_allowedip *wga = &wgp->wgp_allowedips[i];
@@ -3281,11 +3313,29 @@
        }
        rw_exit(wg->wg_rwlock);
 
+       /* Halt all packet processing and timeouts.  */
        softint_disestablish(wgp->wgp_si);
        callout_halt(&wgp->wgp_rekey_timer, NULL);
        callout_halt(&wgp->wgp_handshake_timeout_timer, NULL);
        callout_halt(&wgp->wgp_session_dtor_timer, NULL);
 
+       /* Remove the sessions by index.  */
+       if ((index = wgp->wgp_session_stable->wgs_sender_index) != 0) {
+               thmap_del(wg->wg_sessions_byindex, &index, sizeof index);
+               wgp->wgp_session_stable->wgs_sender_index = 0;
+       }
+       if ((index = wgp->wgp_session_unstable->wgs_sender_index) != 0) {
+               thmap_del(wg->wg_sessions_byindex, &index, sizeof index);
+               wgp->wgp_session_unstable->wgs_sender_index = 0;
+       }
+
+       /* Wait for all thmap_gets to complete, and GC.  */
+       garbage = thmap_stage_gc(wg->wg_sessions_byindex);
+       mutex_enter(wgp->wgp_lock);
+       pserialize_perform(wgp->wgp_psz);
+       mutex_exit(wgp->wgp_lock);
+       thmap_gc(wg->wg_sessions_byindex, garbage);
+
        wgs = wgp->wgp_session_unstable;
        psref_target_destroy(&wgs->wgs_psref, wg_psref_class);
        mutex_obj_free(wgs->wgs_lock);
@@ -3295,6 +3345,7 @@
        mutex_destroy(&wgs->wgs_send_counter_lock);
 #endif
        kmem_free(wgs, sizeof(*wgs));
+
        wgs = wgp->wgp_session_stable;
        psref_target_destroy(&wgs->wgs_psref, wg_psref_class);
        mutex_obj_free(wgs->wgs_lock);
@@ -3320,11 +3371,23 @@
 static void
 wg_destroy_all_peers(struct wg_softc *wg)
 {
-       struct wg_peer *wgp;
+       struct wg_peer *wgp, *wgp0 __diagused;
+       void *garbage_byname, *garbage_bypubkey;
 
 restart:
+       garbage_byname = garbage_bypubkey = NULL;
        mutex_enter(wg->wg_lock);
        WG_PEER_WRITER_FOREACH(wgp, wg) {
+               if (wgp->wgp_name[0]) {
+                       wgp0 = thmap_del(wg->wg_peers_byname, wgp->wgp_name,
+                           strlen(wgp->wgp_name));
+                       KASSERT(wgp0 == wgp);
+                       garbage_byname = thmap_stage_gc(wg->wg_peers_byname);
+               }
+               wgp0 = thmap_del(wg->wg_peers_bypubkey, wgp->wgp_pubkey,
+                   sizeof(wgp->wgp_pubkey));
+               KASSERT(wgp0 == wgp);
+               garbage_bypubkey = thmap_stage_gc(wg->wg_peers_bypubkey);
                WG_PEER_WRITER_REMOVE(wgp);
                wg->wg_npeers--;
                mutex_enter(wgp->wgp_lock);
@@ -3342,6 +3405,8 @@
        psref_target_destroy(&wgp->wgp_psref, wg_psref_class);
 
        wg_destroy_peer(wgp);
+       thmap_gc(wg->wg_peers_byname, garbage_byname);
+       thmap_gc(wg->wg_peers_bypubkey, garbage_bypubkey);
 
        goto restart;
 }
@@ -3349,14 +3414,17 @@
 static int
 wg_destroy_peer_name(struct wg_softc *wg, const char *name)
 {
-       struct wg_peer *wgp;
+       struct wg_peer *wgp, *wgp0 __diagused;
+       void *garbage_byname, *garbage_bypubkey;
 
        mutex_enter(wg->wg_lock);
-       WG_PEER_WRITER_FOREACH(wgp, wg) {
-               if (strcmp(wgp->wgp_name, name) == 0)
-                       break;
-       }
+       wgp = thmap_del(wg->wg_peers_byname, name, strlen(name));
        if (wgp != NULL) {
+               wgp0 = thmap_del(wg->wg_peers_bypubkey, wgp->wgp_pubkey,
+                   sizeof(wgp->wgp_pubkey));
+               KASSERT(wgp0 == wgp);
+               garbage_byname = thmap_stage_gc(wg->wg_peers_byname);
+               garbage_bypubkey = thmap_stage_gc(wg->wg_peers_bypubkey);
                WG_PEER_WRITER_REMOVE(wgp);
                wg->wg_npeers--;
                mutex_enter(wgp->wgp_lock);
@@ -3373,6 +3441,8 @@
        psref_target_destroy(&wgp->wgp_psref, wg_psref_class);
 
        wg_destroy_peer(wgp);
+       thmap_gc(wg->wg_peers_byname, garbage_byname);
+       thmap_gc(wg->wg_peers_bypubkey, garbage_bypubkey);
 
        return 0;
 }
@@ -3432,6 +3502,9 @@
 #endif
 
        PSLIST_INIT(&wg->wg_peers);
+       wg->wg_peers_bypubkey = thmap_create(0, NULL, THMAP_NOCOPY);
+       wg->wg_peers_byname = thmap_create(0, NULL, THMAP_NOCOPY);
+       wg->wg_sessions_byindex = thmap_create(0, NULL, THMAP_NOCOPY);
        wg->wg_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
        wg->wg_rwlock = rw_obj_alloc();
        wg->wg_ops = &wg_ops_rumpkernel;
@@ -3445,6 +3518,9 @@
                        free(wg->wg_rtable_ipv6, M_RTABLE);
                PSLIST_DESTROY(&wg->wg_peers);
                mutex_obj_free(wg->wg_lock);
+               thmap_destroy(wg->wg_sessions_byindex);
+               thmap_destroy(wg->wg_peers_byname);
+               thmap_destroy(wg->wg_peers_bypubkey);
                kmem_free(wg, sizeof(struct wg_softc));
                return error;
        }
@@ -3482,6 +3558,9 @@



Home | Main Index | Thread Index | Old Index