Rewrite the logic around the dymanic array of routing tables to help
authormpi <mpi@openbsd.org>
Wed, 14 Oct 2015 10:09:30 +0000 (10:09 +0000)
committermpi <mpi@openbsd.org>
Wed, 14 Oct 2015 10:09:30 +0000 (10:09 +0000)
turning rtable_get(9) MP-safe.

Use only one per-AF array, as suggested by claudio@, pointing to an
array of pointers to the routing table heads.

Routing tables are now allocated/initialized per-AF.  This will let
us allocate routing table on-demand instead of always having an
AF_INET, AF_MPLS and AF_INET table as soon as a new rtableID is used.

This also get rid of the "void ***" madness.

ok dlg@, jmatthew@

sys/net/art.c
sys/net/art.h
sys/net/route.c
sys/net/rtable.c

index 74f13a0..0f8c118 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: art.c,v 1.4 2015/10/07 10:50:35 mpi Exp $ */
+/*     $OpenBSD: art.c,v 1.5 2015/10/14 10:09:30 mpi Exp $ */
 
 /*
  * Copyright (c) 2015 Martin Pieuchot
@@ -79,7 +79,7 @@ int                    art_table_walk(struct art_table *,
  * Per routing table initialization API function.
  */
 struct art_root *
-art_attach(unsigned int rtableid, int off)
+art_alloc(unsigned int rtableid, int off)
 {
        struct art_root         *ar;
        int                      i;
index 0c97e96..d433d47 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: art.h,v 1.3 2015/10/07 10:50:35 mpi Exp $ */
+/* $OpenBSD: art.h,v 1.4 2015/10/14 10:09:30 mpi Exp $ */
 
 /*
  * Copyright (c) 2015 Martin Pieuchot
@@ -50,7 +50,7 @@ struct art_node {
 };
 
 void            art_init(void);
-struct art_root        *art_attach(unsigned int, int);
+struct art_root        *art_alloc(unsigned int, int);
 struct art_node *art_insert(struct art_root *, struct art_node *, uint8_t *,
                     int);
 struct art_node *art_delete(struct art_root *, struct art_node *, uint8_t *,
index 861a432..fcf6281 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: route.c,v 1.250 2015/10/13 09:59:37 mpi Exp $ */
+/*     $OpenBSD: route.c,v 1.251 2015/10/14 10:09:30 mpi Exp $ */
 /*     $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $      */
 
 /*
 /* Give some jitter to hash, to avoid synchronization between routers. */
 static uint32_t                rt_hashjitter;
 
-extern void         ***rtables;
 extern unsigned int    rtables_id_max;
 
 struct rtstat          rtstat;
@@ -1657,9 +1656,6 @@ rt_if_track(struct ifnet *ifp)
        int i;
        u_int tid;
 
-       if (rtables == NULL)
-               return;
-
        for (tid = 0; tid <= rtables_id_max; tid++) {
                /* skip rtables that are not in the rdomain of the ifp */
                if (rtable_l2(tid) != ifp->if_rdomain)
index 7aee943..90a8cc1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rtable.c,v 1.11 2015/10/07 11:39:49 mpi Exp $ */
+/*     $OpenBSD: rtable.c,v 1.12 2015/10/14 10:09:30 mpi Exp $ */
 
 /*
  * Copyright (c) 2014-2015 Martin Pieuchot
 #include <net/route.h>
 
 uint8_t                   af2idx[AF_MAX+1];    /* To only allocate supported AF */
-uint8_t                   af2idx_max = 1;      /* Must have NULL at index 0 */
+uint8_t                   af2idx_max;
 
-void           ***rtables;             /* Array of routing tables */
-unsigned int      rtables_id_max = 0;
-unsigned int     *rtables2dom;         /* rtable to domain lookup table */
+union rtmap {
+       void            **tbl;
+       unsigned int     *dom;
+};
+
+union rtmap      *rtmap;               /* Array of per domain routing table */
+unsigned int      rtables_id_max;
 
 void              rtable_init_backend(unsigned int);
-int               rtable_attach(unsigned int, sa_family_t, 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_get(unsigned int, sa_family_t);
-void              rtable_set(unsigned int, sa_family_t, void *);
 
 void
 rtable_init(void)
@@ -46,6 +51,8 @@ rtable_init(void)
        unsigned int     keylen = 0;
        int              i;
 
+       /* We use index 0 for the rtable/rdomain map. */
+       af2idx_max = 1;
        memset(af2idx, 0, sizeof(af2idx));
 
        /*
@@ -57,92 +64,139 @@ rtable_init(void)
                        af2idx[dp->dom_family] = af2idx_max++;
                if (dp->dom_rtkeylen > keylen)
                        keylen = dp->dom_rtkeylen;
+
+       }
+
+       rtables_id_max = 0;
+       rtmap = mallocarray(af2idx_max + 1, sizeof(*rtmap), M_RTABLE, M_WAITOK);
+
+       /* 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);
        }
 
        rtable_init_backend(keylen);
 }
 
+void
+rtable_grow(unsigned int id, sa_family_t af)
+{
+       void            **tbl, **ntbl;
+       int               i;
+
+       KASSERT(id > rtables_id_max);
+
+       KERNEL_ASSERT_LOCKED();
+
+       tbl = rtmap[af2idx[af]].tbl;
+       ntbl = mallocarray(id + 1, sizeof(rtmap[0].tbl), M_RTABLE, M_WAITOK);
+
+       for (i = 0; i < rtables_id_max + 1; i++)
+               ntbl[i] = tbl[i];
+
+       while (i < id + 1) {
+               ntbl[i] = NULL;
+               i++;
+       }
+
+       rtmap[af2idx[af]].tbl = ntbl;
+       free(tbl, M_RTABLE, (rtables_id_max + 1) * sizeof(rtmap[0].tbl));
+}
+
 int
 rtable_add(unsigned int id)
 {
-       struct domain   *dp;
-       void            *p, *q;
-       int              i, rv = 0;
+       struct domain    *dp;
+       void             *rtbl;
+       sa_family_t       af;
+       unsigned int      off;
+       int               i;
 
-       if (id > RT_TABLEID_MAX)
+       if (id > RT_TABLEID_MAX || rtable_exists(id))
                return (EINVAL);
 
-       if (id == 0 || id > rtables_id_max) {
-               if ((p = mallocarray(id + 1, sizeof(void *), M_RTABLE,
-                   M_NOWAIT|M_ZERO)) == NULL)
-                       return (ENOMEM);
+       for (i = 0; (dp = domains[i]) != NULL; i++) {
+               if (dp->dom_rtoffset == 0)
+                       continue;
+
+               af = dp->dom_family;
+               off = dp->dom_rtoffset;
+
+               if (id > rtables_id_max)
+                       rtable_grow(id, af);
 
-               if ((q = mallocarray(id + 1, sizeof(unsigned int), M_RTABLE,
-                   M_NOWAIT|M_ZERO)) == NULL) {
-                       free(p, M_RTABLE, (id + 1) * sizeof(void *));
+               rtbl = rtable_alloc(id, af, off);
+               if (rtbl == NULL)
                        return (ENOMEM);
-               }
-               if (rtables) {
-                       memcpy(p, rtables, (rtables_id_max+1) * sizeof(void *));
-                       free(rtables, M_RTABLE,
-                           (rtables_id_max+1) * sizeof(void *));
-
-                       memcpy(q, rtables2dom,
-                           (rtables_id_max+1) * sizeof(unsigned int));
-                       free(rtables2dom, M_RTABLE,
-                           (rtables_id_max+1) * sizeof(unsigned int));
-               }
-               rtables = p;
-               rtables2dom = q;
+
+               rtmap[af2idx[af]].tbl[id] = rtbl;
+       }
+
+       /* Reflect possible growth. */
+       if (id > rtables_id_max) {
+               rtable_grow(id, 0);
                rtables_id_max = id;
        }
 
-       if (rtables[id] != NULL)        /* already exists */
-               return (EEXIST);
+       /* Use main rtable/rdomain by default. */
+       rtmap[0].dom[id] = 0;
+
 
-       rtables2dom[id] = 0;    /* use main table/domain by default */
-       rtables[id] = mallocarray(af2idx_max + 1, sizeof(void *), M_RTABLE,
-           M_NOWAIT|M_ZERO);
-       if (rtables[id] == NULL)
-               return (ENOMEM);
+       return (0);
+}
+
+void
+rtable_del(unsigned int id)
+{
+       struct domain    *dp;
+       sa_family_t       af;
+       int               i;
+
+       if (id > rtables_id_max || !rtable_exists(id))
+               return;
 
-       /* Per domain initialization. */
        for (i = 0; (dp = domains[i]) != NULL; i++) {
                if (dp->dom_rtoffset == 0)
                        continue;
-               rv |= rtable_attach(id, dp->dom_family, dp->dom_rtoffset);
-       }
 
-       return (rv);
+               af = dp->dom_family;
+
+               rtable_free(id);
+               rtmap[af2idx[af]].tbl[id] = NULL;
+       }
 }
+
 void *
 rtable_get(unsigned int rtableid, sa_family_t af)
 {
-       if (rtableid > rtables_id_max)
+       if (af >= nitems(af2idx) || rtableid > rtables_id_max)
                return (NULL);
-       return (rtables[rtableid] ? rtables[rtableid][af2idx[af]] : NULL);
-}
 
-void
-rtable_set(unsigned int rtableid, sa_family_t af, void *p)
-{
-       if (rtableid > rtables_id_max)
-               return;
+       if (af2idx[af] == 0 || rtmap[af2idx[af]].tbl == NULL)
+               return (NULL);
 
-       if (rtables[rtableid])
-               rtables[rtableid][af2idx[af]] = p;
+       return (rtmap[af2idx[af]].tbl[rtableid]);
 }
 
 int
 rtable_exists(unsigned int rtableid)
 {
+       struct domain   *dp;
+       int              i;
+
        if (rtableid > rtables_id_max)
                return (0);
 
-       if (rtables[rtableid] == NULL)
-               return (0);
+       for (i = 0; (dp = domains[i]) != NULL; i++) {
+               if (dp->dom_rtoffset == 0)
+                       continue;
 
-       return (1);
+               if (rtable_get(rtableid, dp->dom_family) != NULL)
+                       return (1);
+       }
+
+       return (0);
 }
 
 unsigned int
@@ -151,7 +205,7 @@ rtable_l2(unsigned int rtableid)
        if (rtableid > rtables_id_max)
                return (0);
 
-       return (rtables2dom[rtableid]);
+       return (rtmap[0].dom[rtableid]);
 }
 
 void
@@ -160,7 +214,7 @@ rtable_l2set(unsigned int rtableid, unsigned int parent)
        if (!rtable_exists(rtableid) || !rtable_exists(parent))
                return;
 
-       rtables2dom[rtableid] = parent;
+       rtmap[0].dom[rtableid] = parent;
 }
 
 #ifndef ART
@@ -170,27 +224,24 @@ rtable_init_backend(unsigned int keylen)
        rn_init(keylen); /* initialize all zeroes, all ones, mask table */
 }
 
-int
-rtable_attach(unsigned int rtableid, sa_family_t af, int off)
+void *
+rtable_alloc(unsigned int rtableid, sa_family_t af, unsigned int off)
 {
-       struct radix_node_head *rnh;
-       int rv = 1;
-
-       rnh = rtable_get(rtableid, af);
-       if (rnh != NULL)
-               return (EEXIST);
+       struct radix_node_head *rnh = NULL;
 
        if (rn_inithead((void **)&rnh, off)) {
 #ifndef SMALL_KERNEL
                rnh->rnh_multipath = 1;
 #endif /* SMALL_KERNEL */
                rnh->rnh_rtableid = rtableid;
-               rv = 0;
        }
 
-       rtable_set(rtableid, af, rnh);
+       return (rnh);
+}
 
-       return (rv);
+void
+rtable_free(unsigned int rtableid)
+{
 }
 
 struct rtentry *
@@ -393,22 +444,15 @@ rtable_init_backend(unsigned int keylen)
        pool_init(&an_pool, sizeof(struct art_node), 0, 0, 0, "art node", NULL);
 }
 
-int
-rtable_attach(unsigned int rtableid, sa_family_t af, int off)
+void *
+rtable_alloc(unsigned int rtableid, sa_family_t af, unsigned int off)
 {
-       struct art_root                 *ar;
-
-       ar = rtable_get(rtableid, af);
-       if (ar != NULL)
-               return (EEXIST);
-
-       ar = art_attach(rtableid, off);
-       if (ar == NULL)
-               return (ENOMEM);
-
-       rtable_set(rtableid, af, ar);
+       return (art_alloc(rtableid, off));
+}
 
-       return (0);
+void
+rtable_free(unsigned int rtableid)
+{
 }
 
 struct rtentry *