summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormpi <mpi@openbsd.org>2015-11-27 11:52:44 +0000
committermpi <mpi@openbsd.org>2015-11-27 11:52:44 +0000
commit95346806c04cbe6275d166a9065bc39361d53ec4 (patch)
tree58fe9aeab4a9f02aa66d65275823d7d149df4c7e
parentAttach the iPhone 6 as ugen(4), from Laurent GUALDI. (diff)
downloadwireguard-openbsd-95346806c04cbe6275d166a9065bc39361d53ec4.tar.xz
wireguard-openbsd-95346806c04cbe6275d166a9065bc39361d53ec4.zip
Protect the growth of the routing table arrays used by rtable_get()
with SRPs. This is a simplified version of the dynamically sizeable array of pointers used by if_get() because routing table heads are never freed. ok dlg@
-rw-r--r--sys/net/if.c4
-rw-r--r--sys/net/route.c8
-rw-r--r--sys/net/rtable.c263
3 files changed, 182 insertions, 93 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index a3128706d7d..2d8aedc017a 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if.c,v 1.413 2015/11/25 03:10:00 dlg Exp $ */
+/* $OpenBSD: if.c,v 1.414 2015/11/27 11:52:44 mpi Exp $ */
/* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */
/*
@@ -378,7 +378,7 @@ if_map_dtor(void *null, void *m)
unsigned int i;
/*
- * dont need the kernel lock to use update_locked since this is
+ * dont need to serialize the use of update_locked since this is
* the last reference to this map. there's nothing to race against.
*/
for (i = 0; i < if_map->limit; i++)
diff --git a/sys/net/route.c b/sys/net/route.c
index 535b8e59367..b534bc83d03 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.276 2015/11/23 10:52:43 mpi Exp $ */
+/* $OpenBSD: route.c,v 1.277 2015/11/27 11:52:44 mpi Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
@@ -140,7 +140,7 @@
/* Give some jitter to hash, to avoid synchronization between routers. */
static uint32_t rt_hashjitter;
-extern unsigned int rtables_id_max;
+extern unsigned int rtmap_limit;
struct rtstat rtstat;
int rttrash; /* routes not in table but not freed */
@@ -1662,7 +1662,7 @@ rt_if_remove(struct ifnet *ifp)
int i;
u_int tid;
- for (tid = 0; tid <= rtables_id_max; tid++) {
+ for (tid = 0; tid < rtmap_limit; tid++) {
/* skip rtables that are not in the rdomain of the ifp */
if (rtable_l2(tid) != ifp->if_rdomain)
continue;
@@ -1702,7 +1702,7 @@ rt_if_track(struct ifnet *ifp)
int i;
u_int tid;
- for (tid = 0; tid <= rtables_id_max; tid++) {
+ for (tid = 0; tid < rtmap_limit; tid++) {
/* skip rtables that are not in the rdomain of the ifp */
if (rtable_l2(tid) != ifp->if_rdomain)
continue;
diff --git a/sys/net/rtable.c b/sys/net/rtable.c
index 214a23abfaa..b9fb7ce22d5 100644
--- a/sys/net/rtable.c
+++ b/sys/net/rtable.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtable.c,v 1.25 2015/11/24 12:06:30 mpi Exp $ */
+/* $OpenBSD: rtable.c,v 1.26 2015/11/27 11:52:44 mpi Exp $ */
/*
* Copyright (c) 2014-2015 Martin Pieuchot
@@ -31,92 +31,160 @@
#include <net/rtable.h>
#include <net/route.h>
+/*
+ * Per AF array.
+ *
+ * afmap rtmap/dommp
+ * ----------- --------- -----
+ * | 0 |--------> | 0 | 0 | ... | 0 | Array mapping rtableid (=index)
+ * ----------- --------- ----- to rdomain (=value).
+ * | AF_INET |.
+ * ----------- `. .---------. .---------.
+ * ... `----> | rtable0 | ... | rtableN | Array of pointers for
+ * ----------- '---------' '---------' IPv4 routing tables
+ * | AF_MPLS | indexed by ``rtableid''.
+ * -----------
+ */
+struct srp *afmap;
uint8_t af2idx[AF_MAX+1]; /* To only allocate supported AF */
uint8_t af2idx_max;
-union rtmap {
- void **tbl;
- unsigned int *dom;
+/* Array of routing table pointers. */
+struct rtmap {
+ unsigned int limit;
+ void **tbl;
};
-union rtmap *rtmap; /* Array of per domain routing table */
-unsigned int rtables_id_max;
+/* Array of rtableid -> rdomain mapping. */
+struct dommp {
+ unsigned int limit;
+ unsigned int *dom;
+};
+
+unsigned int rtmap_limit = 0;
+
+void rtmap_init(void);
+void rtmap_grow(unsigned int, sa_family_t);
+void rtmap_dtor(void *, void *);
+
+struct srp_gc rtmap_gc = SRP_GC_INITIALIZER(rtmap_dtor, NULL);
void rtable_init_backend(unsigned int);
void *rtable_alloc(unsigned int, sa_family_t, unsigned int);
-void rtable_free(unsigned int);
-void rtable_grow(unsigned int, sa_family_t);
+void rtable_free(unsigned int, sa_family_t);
void *rtable_get(unsigned int, sa_family_t);
void rtable_put(void *);
void
-rtable_init(void)
+rtmap_init(void)
{
struct domain *dp;
- unsigned int keylen = 0;
int i;
- /* We use index 0 for the rtable/rdomain map. */
- af2idx_max = 1;
- memset(af2idx, 0, sizeof(af2idx));
-
- /*
- * Compute the maximum supported key length in case the routing
- * table backend needs it.
- */
+ /* Start with a single table for every domain that requires it. */
for (i = 0; (dp = domains[i]) != NULL; i++) {
- if (dp->dom_rtoffset)
- af2idx[dp->dom_family] = af2idx_max++;
- if (dp->dom_rtkeylen > keylen)
- keylen = dp->dom_rtkeylen;
+ if (dp->dom_rtoffset == 0)
+ continue;
+ rtmap_grow(1, dp->dom_family);
}
- rtables_id_max = 0;
- rtmap = mallocarray(af2idx_max + 1, sizeof(*rtmap), M_RTABLE, M_WAITOK);
+ /* Initialize the rtableid->rdomain mapping table. */
+ rtmap_grow(1, 0);
- /* Start with a single table for every domain that requires it. */
- for (i = 0; i < af2idx_max + 1; i++) {
- rtmap[i].tbl = mallocarray(1, sizeof(rtmap[0].tbl),
- M_RTABLE, M_WAITOK|M_ZERO);
+ rtmap_limit = 1;
+}
+
+/*
+ * Grow the size of the array of routing table for AF ``af'' to ``nlimit''.
+ */
+void
+rtmap_grow(unsigned int nlimit, sa_family_t af)
+{
+ struct rtmap *map, *nmap;
+ int i;
+
+ KERNEL_ASSERT_LOCKED();
+
+ KASSERT(nlimit > rtmap_limit);
+
+ nmap = malloc(sizeof(*nmap), M_RTABLE, M_WAITOK);
+ nmap->limit = nlimit;
+ nmap->tbl = mallocarray(nlimit, sizeof(*nmap[0].tbl), M_RTABLE,
+ M_WAITOK|M_ZERO);
+
+ map = srp_get_locked(&afmap[af2idx[af]]);
+ if (map != NULL) {
+ KASSERT(map->limit == rtmap_limit);
+
+ for (i = 0; i < map->limit; i++)
+ nmap->tbl[i] = map->tbl[i];
}
- rtable_init_backend(keylen);
+ srp_update_locked(&rtmap_gc, &afmap[af2idx[af]], nmap);
}
void
-rtable_grow(unsigned int id, sa_family_t af)
+rtmap_dtor(void *null, void *xmap)
{
- void **tbl, **ntbl;
- int i;
+ struct rtmap *map = xmap;
- KASSERT(id > rtables_id_max);
+ /*
+ * doesnt need to be serialized since this is the last reference
+ * to this map. there's nothing to race against.
+ */
+ free(map->tbl, M_RTABLE, map->limit * sizeof(*map[0].tbl));
+ free(map, M_RTABLE, sizeof(*map));
+}
- KERNEL_ASSERT_LOCKED();
+void
+rtable_init(void)
+{
+ struct domain *dp;
+ unsigned int keylen = 0;
+ int i;
+
+ /* We use index 0 for the rtable/rdomain map. */
+ af2idx_max = 1;
+ memset(af2idx, 0, sizeof(af2idx));
- tbl = rtmap[af2idx[af]].tbl;
- ntbl = mallocarray(id + 1, sizeof(rtmap[0].tbl), M_RTABLE, M_WAITOK);
+ /*
+ * Compute the maximum supported key length in case the routing
+ * table backend needs it.
+ */
+ for (i = 0; (dp = domains[i]) != NULL; i++) {
+ if (dp->dom_rtoffset == 0)
+ continue;
- for (i = 0; i < rtables_id_max + 1; i++)
- ntbl[i] = tbl[i];
+ af2idx[dp->dom_family] = af2idx_max++;
+ if (dp->dom_rtkeylen > keylen)
+ keylen = dp->dom_rtkeylen;
- while (i < id + 1) {
- ntbl[i] = NULL;
- i++;
}
+ rtable_init_backend(keylen);
+
+ /*
+ * Allocate AF-to-id table now that we now how many AFs this
+ * kernel supports.
+ */
+ afmap = mallocarray(af2idx_max + 1, sizeof(*afmap), M_RTABLE,
+ M_WAITOK|M_ZERO);
- rtmap[af2idx[af]].tbl = ntbl;
- free(tbl, M_RTABLE, (rtables_id_max + 1) * sizeof(rtmap[0].tbl));
+ rtmap_init();
}
int
rtable_add(unsigned int id)
{
- struct domain *dp;
- void *rtbl;
- sa_family_t af;
- unsigned int off;
- int i;
+ struct domain *dp;
+ void *tbl;
+ struct rtmap *map;
+ struct dommp *dmm;
+ sa_family_t af;
+ unsigned int off;
+ int i;
+
+ KERNEL_ASSERT_LOCKED();
if (id > RT_TABLEID_MAX)
return (EINVAL);
@@ -131,25 +199,26 @@ rtable_add(unsigned int id)
af = dp->dom_family;
off = dp->dom_rtoffset;
- if (id > rtables_id_max)
- rtable_grow(id, af);
+ if (id >= rtmap_limit)
+ rtmap_grow(id + 1, af);
- rtbl = rtable_alloc(id, af, off);
- if (rtbl == NULL)
+ tbl = rtable_alloc(id, af, off);
+ if (tbl == NULL)
return (ENOMEM);
- rtmap[af2idx[af]].tbl[id] = rtbl;
+ map = srp_get_locked(&afmap[af2idx[af]]);
+ map->tbl[id] = tbl;
}
/* Reflect possible growth. */
- if (id > rtables_id_max) {
- rtable_grow(id, 0);
- rtables_id_max = id;
+ if (id >= rtmap_limit) {
+ rtmap_grow(id + 1, 0);
+ rtmap_limit = id + 1;
}
/* Use main rtable/rdomain by default. */
- rtmap[0].dom[id] = 0;
-
+ dmm = srp_get_locked(&afmap[0]);
+ dmm->dom[id] = 0;
return (0);
}
@@ -157,39 +226,32 @@ rtable_add(unsigned int id)
void
rtable_del(unsigned int id)
{
- struct domain *dp;
- sa_family_t af;
- int i;
-
- if (id > rtables_id_max || !rtable_exists(id))
- return;
+ struct domain *dp;
+ int i;
for (i = 0; (dp = domains[i]) != NULL; i++) {
if (dp->dom_rtoffset == 0)
continue;
- af = dp->dom_family;
-
- rtable_free(id);
- rtmap[af2idx[af]].tbl[id] = NULL;
+ rtable_free(id, dp->dom_family);
}
}
void *
rtable_get(unsigned int rtableid, sa_family_t af)
{
- if (af >= nitems(af2idx) || rtableid > rtables_id_max)
- return (NULL);
+ struct rtmap *map;
+ void *tbl = NULL;
- if (af2idx[af] == 0 || rtmap[af2idx[af]].tbl == NULL)
+ if (af >= nitems(af2idx) || af2idx[af] == 0)
return (NULL);
- return (rtmap[af2idx[af]].tbl[rtableid]);
-}
+ map = srp_enter(&afmap[af2idx[af]]);
+ if (rtableid < map->limit)
+ tbl = map->tbl[rtableid];
+ srp_leave(&afmap[af2idx[af]], map);
-void
-rtable_put(void *tbl)
-{
+ return (tbl);
}
int
@@ -199,9 +261,6 @@ rtable_exists(unsigned int rtableid)
void *tbl;
int i, exist = 0;
- if (rtableid > rtables_id_max)
- return (0);
-
for (i = 0; (dp = domains[i]) != NULL; i++) {
if (dp->dom_rtoffset == 0)
continue;
@@ -221,19 +280,29 @@ rtable_exists(unsigned int rtableid)
unsigned int
rtable_l2(unsigned int rtableid)
{
- if (rtableid > rtables_id_max)
- return (0);
+ struct dommp *dmm;
+ unsigned int rdomain = 0;
- return (rtmap[0].dom[rtableid]);
+ dmm = srp_enter(&afmap[0]);
+ if (rtableid < dmm->limit)
+ rdomain = dmm->dom[rtableid];
+ srp_leave(&afmap[0], dmm);
+
+ return (rdomain);
}
void
-rtable_l2set(unsigned int rtableid, unsigned int parent)
+rtable_l2set(unsigned int rtableid, unsigned int rdomain)
{
- if (!rtable_exists(rtableid) || !rtable_exists(parent))
+ struct dommp *dmm;
+
+ KERNEL_ASSERT_LOCKED();
+
+ if (!rtable_exists(rtableid) || !rtable_exists(rdomain))
return;
- rtmap[0].dom[rtableid] = parent;
+ dmm = srp_get_locked(&afmap[0]);
+ dmm->dom[rtableid] = rdomain;
}
#ifndef ART
@@ -259,7 +328,12 @@ rtable_alloc(unsigned int rtableid, sa_family_t af, unsigned int off)
}
void
-rtable_free(unsigned int rtableid)
+rtable_free(unsigned int rtableid, sa_family_t af)
+{
+}
+
+void
+rtable_put(void *tbl)
{
}
@@ -489,7 +563,22 @@ rtable_alloc(unsigned int rtableid, sa_family_t af, unsigned int off)
}
void
-rtable_free(unsigned int rtableid)
+rtable_free(unsigned int rtableid, sa_family_t af)
+{
+ struct art_root *ar = NULL;
+ struct rtmap *map;
+
+ KERNEL_ASSERT_LOCKED();
+
+ map = srp_get_locked(&afmap[af2idx[af]]);
+ if (rtableid < map->limit) {
+ ar = map->tbl[rtableid];
+ KASSERT(ar->ar_root == NULL);
+ }
+}
+
+void
+rtable_put(void *tbl)
{
}