aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Dunwoodie <ncon@mail.noconroy.net>2019-10-06 13:49:19 +0100
committerMatt Dunwoodie <ncon@mail.noconroy.net>2019-10-06 13:49:19 +0100
commitbf81191b615986c7728b229f47a9bede05e88e53 (patch)
tree516d7411915f982391fd02c4d86836b939637934
parentRefactoring of {s,g}et_* to *_{s,g}et (diff)
downloadwireguard-openbsd-bf81191b615986c7728b229f47a9bede05e88e53.tar.xz
wireguard-openbsd-bf81191b615986c7728b229f47a9bede05e88e53.zip
Move mutex and refcnt to fixedmap
-rw-r--r--src/fixedmap.h9
-rw-r--r--src/if_wg.c3
-rw-r--r--src/kern_wg.c85
-rw-r--r--src/wireguard.c120
-rw-r--r--src/wireguard.h2
5 files changed, 96 insertions, 123 deletions
diff --git a/src/fixedmap.h b/src/fixedmap.h
index 8398177..a7dc021 100644
--- a/src/fixedmap.h
+++ b/src/fixedmap.h
@@ -18,6 +18,7 @@
#define __FIXEDMAP_H__
#include <sys/types.h>
+#include <sys/mutex.h>
#define FM_FOREACH(item, fm) \
for (item = (fm)->map; item < (fm)->map + (fm)->size; item++)
@@ -28,20 +29,24 @@
struct fixed_map {
size_t size;
+ struct mutex mtx;
struct map_item {
enum {
FM_ITEM_EMPTY = 0,
FM_ITEM_FILLED,
} state;
uint32_t key;
+ struct refcnt refcnt;
void *value;
} *map;
};
-void fm_init(struct fixed_map *);
+void fm_init(struct fixed_map *, size_t, int);
void fm_destroy(struct fixed_map *);
+void fm_resize(struct fixed_map *, size_t);
uint32_t fm_insert(struct fixed_map *, void *);
void *fm_lookup(struct fixed_map *, uint32_t);
-void fm_remove(struct fixed_map *, uint32_t);
+void fm_put(struct fixed_map *, uint32_t);
+void fm_drop(struct fixed_map *, uint32_t);
#endif /* __FIXEDMAP_H__ */
diff --git a/src/if_wg.c b/src/if_wg.c
index 31be12a..b055e1b 100644
--- a/src/if_wg.c
+++ b/src/if_wg.c
@@ -922,7 +922,8 @@ wg_clone_create(struct if_clone * ifc, int unit)
inp->inp_upcall_arg = sc;
#endif
- wg_device_init(&sc->sc_dev, wg_peer_notify, wg_peer_queue, wg_softc_peer_clean, sc);
+ wg_device_init(&sc->sc_dev, IPL_NET, wg_peer_notify,
+ wg_peer_queue, wg_softc_peer_clean, sc);
sc->sc_taskq = taskq_create("wg", ncpus, IPL_NET, TASKQ_MPSAFE);
task_set(&sc->sc_tx_task, wg_tx_task_fn, &sc->sc_tx_queue);
diff --git a/src/kern_wg.c b/src/kern_wg.c
index 185d2c6..7b38439 100644
--- a/src/kern_wg.c
+++ b/src/kern_wg.c
@@ -165,31 +165,39 @@ bb_load(struct bloom_bucket *bb)
void fm_resize(struct fixed_map *, size_t);
void
-fm_init(struct fixed_map *fm)
+fm_init(struct fixed_map *fm, size_t size, int ipl)
{
bzero(fm, sizeof(*fm));
- fm_resize(fm, 128);
+ mtx_init(&fm->mtx, ipl);
+ fm_resize(fm, size);
}
void
fm_resize(struct fixed_map *fm, size_t size)
{
size_t i;
- size_t osize;
- struct map_item *omap;
+ size_t xsize;
+ struct map_item *xmap;
- osize = fm->size;
- omap = fm->map;
+ for (xsize = 1; xsize < size; xsize <<= 1);
- for (fm->size = 1; fm->size < size; fm->size <<= 1);
- KASSERT(fm->size >= osize);
- fm->map = mallocarray(fm->size, sizeof(*fm->map), M_DEVBUF, M_WAITOK | M_ZERO);
+ mtx_enter(&fm->mtx);
+ if (xsize < fm->size)
+ goto leave;
+ mtx_leave(&fm->mtx);
- if (omap != NULL) {
- for (i = 0; i < osize; i++)
- fm->map[omap[i].key % fm->size] = omap[i];
- free(omap, M_DEVBUF, 0);
+ xmap = mallocarray(xsize, sizeof(*xmap), M_DEVBUF, M_WAITOK | M_ZERO);
+
+ mtx_enter(&fm->mtx);
+ if (fm->map != NULL) {
+ for (i = 0; i < fm->size; i++)
+ xmap[fm->map[i].key % fm->size] = fm->map[i];
+ free(fm->map, M_DEVBUF, 0);
}
+ fm->size = xsize;
+ fm->map = xmap;
+leave:
+ mtx_leave(&fm->mtx);
}
void
@@ -204,25 +212,29 @@ fm_destroy(struct fixed_map *fm)
uint32_t
fm_insert(struct fixed_map *fm, void *v)
{
+ uint32_t id = 0;
struct map_item *item = NULL, *iter;
-retry:
+ mtx_enter(&fm->mtx);
+
FM_FOREACH_EMPTY(iter, fm) {
item = iter;
break;
}
- if (item == NULL) {
- fm_resize(fm, fm->size * 2);
- goto retry;
- }
+ if (item == NULL)
+ panic("fixed map not large enough");
+
+ while (id == 0)
+ id = (arc4random() & ~(fm->size - 1)) + (item - fm->map);
- /* TODO make not zero */
- item->key = (arc4random() & ~(fm->size - 1)) + (item - fm->map);
+ item->key = id;
item->state = FM_ITEM_FILLED;
item->value = v;
- return item->key;
+ mtx_leave(&fm->mtx);
+
+ return id;
}
void *
@@ -231,23 +243,40 @@ fm_lookup(struct fixed_map *fm, uint32_t k)
void *v = NULL;
struct map_item *item;
+ mtx_enter(&fm->mtx);
item = fm->map + (k & (fm->size - 1));
- if (item->key == k)
+ if (item->key == k) {
+ refcnt_take(&item->refcnt);
v = item->value;
+ }
+ mtx_leave(&fm->mtx);
return v;
}
void
-fm_remove(struct fixed_map *fm, uint32_t k)
+fm_put(struct fixed_map *fm, uint32_t k)
{
struct map_item *item;
+ mtx_enter(&fm->mtx);
item = fm->map + (k & (fm->size - 1));
- if (item->key == k) {
- item->state = FM_ITEM_EMPTY;
- item->value = NULL;
- item->key = 0;
- }
+ if (item->key != k)
+ panic("element should be in map");
+ refcnt_rele_wake(&item->refcnt);
+ mtx_leave(&fm->mtx);
+}
+
+void
+fm_drop(struct fixed_map *fm, uint32_t k)
+{
+ struct map_item *item;
+
+ mtx_enter(&fm->mtx);
+ item = fm->map + (k & (fm->size - 1));
+ if (item->key != k)
+ panic("element should be in map");
+ mtx_leave(&fm->mtx);
+ refcnt_finalize(&item->refcnt, "fm_drop");
}
/*
diff --git a/src/wireguard.c b/src/wireguard.c
index 2b04d16..ebba73f 100644
--- a/src/wireguard.c
+++ b/src/wireguard.c
@@ -82,15 +82,12 @@ struct wg_session *wg_peer_hs_session(struct wg_peer *);
struct wg_session *wg_peer_ks_session(struct wg_peer *);
void wg_session_drop(struct wg_session *);
-void wg_session_ref(struct wg_session *);
-void wg_peer_ref(struct wg_peer *);
void wg_peer_attach_session(struct wg_peer *, struct wg_session *);
struct wg_session *wg_device_new_session(struct wg_device *);
-struct wg_session *wg_device_ref_session(struct wg_device *, uint32_t);
/* Some crappy API */
void
-wg_device_init(struct wg_device *dev,
+wg_device_init(struct wg_device *dev, int ipl,
void (*notify_fn)(struct wg_peer *),
void (*outq_fn)(struct wg_peer *, enum wg_pkt_type, uint32_t),
void (*cleanup_fn)(struct wg_peer *), void *arg)
@@ -100,8 +97,8 @@ wg_device_init(struct wg_device *dev,
dev->d_outq = outq_fn;
dev->d_notify = notify_fn;
dev->d_cleanup = cleanup_fn;
- fm_init(&dev->d_peers);
- fm_init(&dev->d_sessions);
+ fm_init(&dev->d_peers, 4, ipl);
+ fm_init(&dev->d_sessions, 12, ipl);
rw_init(&dev->d_lock, "wg_device");
/* d_cookie_maker, d_keypair initialised to 0 */
}
@@ -138,14 +135,9 @@ wg_device_new_peer(struct wg_device *dev, struct wg_pubkey *key, void *arg)
refcnt_init(&peer->p_refcnt);
rw_init(&peer->p_lock, "wg_peer");
- rw_enter_write(&dev->d_lock);
rw_enter_write(&peer->p_lock);
peer->p_id = fm_insert(&dev->d_peers, peer);
rw_exit_write(&peer->p_lock);
- rw_exit_write(&dev->d_lock);
-
- /* Take reference to return */
- wg_peer_ref(peer);
/* All other elements of wg_peer are nulled by M_ZERO */
return peer;
@@ -160,11 +152,9 @@ wg_device_new_session(struct wg_device *dev)
getnanotime(&session->s_created);
refcnt_init(&session->s_refcnt);
- rw_enter_write(&dev->d_lock);
rw_enter_write(&session->s_lock);
session->s_local_id = fm_insert(&dev->d_sessions, session);
rw_exit_write(&session->s_lock);
- rw_exit_write(&dev->d_lock);
WGDEBUG("wg_device_new_session: %x\n", session->s_local_id);
@@ -186,92 +176,38 @@ wg_device_ref_peerkey(struct wg_device *dev, struct wg_pubkey *key)
else
peer = NULL;
}
- if (peer)
- wg_peer_ref(peer);
rw_exit_read(&dev->d_lock);
-
- return peer;
-}
-
-struct wg_peer *
-wg_device_ref_peerid(struct wg_device *dev, uint32_t id)
-{
- struct wg_peer *peer;
- rw_enter_read(&dev->d_lock);
- peer = fm_lookup(&dev->d_peers, id);
if (peer)
- wg_peer_ref(peer);
- rw_exit_read(&dev->d_lock);
- return peer;
-}
+ peer = fm_lookup(&dev->d_peers, peer->p_id);
-void
-wg_peer_ref(struct wg_peer *peer)
-{
- refcnt_take(&peer->p_refcnt);
- WGDEBUG("wg_peer_ref(%d): %x\n", peer->p_refcnt.refs, peer->p_id);
+ return peer;
}
void
wg_peer_put(struct wg_peer *peer)
{
- refcnt_rele_wake(&peer->p_refcnt);
- WGDEBUG("wg_peer_put(%d): %x\n", peer->p_refcnt.refs, peer->p_id);
+ fm_put(&peer->p_device->d_peers, peer->p_id);
}
void
wg_peer_drop(struct wg_peer *peer)
{
- /* TODO prevent lock gap */
+ fm_drop(&peer->p_device->d_peers, peer->p_id);
peer->p_device->d_cleanup(peer);
-
wg_peer_clean(peer);
-
- rw_enter_write(&peer->p_device->d_lock);
- fm_remove(&peer->p_device->d_peers, peer->p_id);
- rw_exit_write(&peer->p_device->d_lock);
- refcnt_finalize(&peer->p_refcnt, "wg_peer drop");
- WGDEBUG("wg_peer_drop(%d): %x\n", peer->p_refcnt.refs, peer->p_id);
free(peer, M_DEVBUF, sizeof(*peer));
}
-struct wg_session *
-wg_device_ref_session(struct wg_device *dev, uint32_t id)
-{
- struct wg_session *session;
- rw_enter_read(&dev->d_lock);
- session = fm_lookup(&dev->d_sessions, id);
- if (session)
- wg_session_ref(session);
- rw_exit_read(&dev->d_lock);
- return session;
-}
-
-void
-wg_session_ref(struct wg_session *session)
-{
- refcnt_take(&session->s_refcnt);
- WGDEBUG("wg_session_ref(%d): %x\n", session->s_refcnt.refs,
- session->s_local_id);
-}
-
void
wg_session_put(struct wg_session *session)
{
- refcnt_rele_wake(&session->s_refcnt);
- WGDEBUG("wg_session_put(%d): %x\n", session->s_refcnt.refs,
- session->s_local_id);
+ fm_put(&session->s_peer->p_device->d_sessions, session->s_local_id);
}
void
wg_session_drop(struct wg_session *session)
{
- rw_enter_write(&session->s_peer->p_device->d_lock);
- fm_remove(&session->s_peer->p_device->d_sessions, session->s_local_id);
- rw_exit_write(&session->s_peer->p_device->d_lock);
- refcnt_finalize(&session->s_refcnt, "wg_session drop");
- WGDEBUG("wg_session_drop(%d): %x\n", session->s_refcnt.refs,
- session->s_local_id);
+ fm_drop(&session->s_peer->p_device->d_sessions, session->s_local_id);
free(session, M_DEVBUF, sizeof(*session));
}
@@ -398,17 +334,23 @@ wg_peer_last_handshake(struct wg_peer *peer)
struct wg_session *
wg_peer_last_session(struct wg_peer *peer)
{
+ uint32_t id = 0;
struct wg_session *session;
+
rw_enter_read(&peer->p_lock);
- session = peer->p_ks_session;
- if (session != NULL &&
- (wg_timespec_timedout(&session->s_created, WG_REJECT_AFTER_TIME) ||
- session->s_keyset.k_txcounter > WG_REJECT_AFTER_MESSAGES))
- session = NULL;
- if (session != NULL)
- wg_session_ref(session);
+ if (peer->p_ks_session)
+ id = peer->p_ks_session->s_local_id;
rw_exit_read(&peer->p_lock);
- return session;
+
+ if ((session = fm_lookup(&peer->p_device->d_sessions, id)) == NULL)
+ return NULL;
+
+ if (!wg_timespec_timedout(&session->s_created, WG_REJECT_AFTER_TIME) &&
+ session->s_keyset.k_txcounter > WG_REJECT_AFTER_MESSAGES)
+ return session;
+
+ wg_session_put(session);
+ return NULL;
}
/* Crypto */
@@ -478,8 +420,6 @@ wg_device_rx_initiation(struct wg_device *dev, struct wg_msg_initiation *init,
wg_peer_attach_session(peer, session);
dev->d_outq(peer, WG_PKT_RESPONSE, session->s_local_id);
- /* Take reference to return to caller */
- wg_session_ref(session);
wg_peer_put(peer);
return WG_OK;
@@ -498,7 +438,7 @@ wg_device_rx_response(struct wg_device *dev, struct wg_msg_response *resp,
enum wg_error ret = WG_OK;
- if ((session = wg_device_ref_session(dev, resp->receiver)) == NULL)
+ if ((session = fm_lookup(&dev->d_sessions, resp->receiver)) == NULL)
return WG_ID;
rw_enter_read(&dev->d_lock);
@@ -563,7 +503,7 @@ wg_device_rx_cookie(struct wg_device *dev, struct wg_msg_cookie *cookie,
enum wg_error ret = WG_OK;
- if ((session = wg_device_ref_session(dev, cookie->receiver)) == NULL)
+ if ((session = fm_lookup(&dev->d_sessions, cookie->receiver)) == NULL)
return WG_ID;
rw_enter_write(&session->s_peer->p_lock);
@@ -600,7 +540,7 @@ wg_device_rx_transport(struct wg_device *dev, struct wg_msg_transport *msg,
uint64_t counter = letoh64(msg->counter);
struct wg_session *session;
- if ((session = wg_device_ref_session(dev, msg->receiver)) == NULL)
+ if ((session = fm_lookup(&dev->d_sessions, msg->receiver)) == NULL)
return WG_ID;
wg_session_promote(session);
@@ -647,7 +587,7 @@ wg_device_tx_initiation(struct wg_device *dev, struct wg_msg_initiation *init,
enum wg_error ret = WG_OK;
- if ((peer = wg_device_ref_peerid(dev, id)) == NULL)
+ if ((peer = fm_lookup(&dev->d_peers, id)) == NULL)
return WG_ID;
/* TODO better locking */
@@ -713,8 +653,6 @@ wg_device_tx_initiation(struct wg_device *dev, struct wg_msg_initiation *init,
wg_peer_attach_session(peer, session);
*s = session;
- /* Take reference to return to caller */
- wg_session_ref(session);
wg_peer_put(peer);
return WG_OK;
leave:
@@ -731,7 +669,7 @@ wg_device_tx_response(struct wg_device *dev, struct wg_msg_response *resp,
struct wg_handshake *hs;
struct wg_session *session;
- if ((session = wg_device_ref_session(dev, id)) == NULL)
+ if ((session = fm_lookup(&dev->d_sessions, id)) == NULL)
return WG_ID;
rw_enter_read(&session->s_peer->p_lock);
@@ -798,7 +736,7 @@ wg_device_tx_transport(struct wg_device *dev, struct wg_msg_transport *msg,
enum wg_error ret = WG_OK;
struct wg_session *session;
- if ((session = wg_device_ref_session(dev, id)) == NULL)
+ if ((session = fm_lookup(&dev->d_sessions, id)) == NULL)
return WG_ID;
rw_enter_read(&session->s_lock);
diff --git a/src/wireguard.h b/src/wireguard.h
index ecabe89..ede3403 100644
--- a/src/wireguard.h
+++ b/src/wireguard.h
@@ -242,7 +242,7 @@ static char *wg_error_str[] = {
/* WireGuard functions */
-void wg_device_init(struct wg_device *,
+void wg_device_init(struct wg_device *, int,
void (*)(struct wg_peer *),
void (*)(struct wg_peer *, enum wg_pkt_type, uint32_t),
void (*)(struct wg_peer *), void *);