siphash is slower than an rbt lookup. we also save a bit of memory
by not allocating 1024 hash buckets.

tests? ok?

Index: if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.304
diff -u -p -r1.304 if_bridge.c
--- if_bridge.c 7 Feb 2018 11:30:01 -0000       1.304
+++ if_bridge.c 9 Feb 2018 23:18:43 -0000
@@ -154,7 +154,6 @@ bridge_clone_create(struct if_clone *ifc
 {
        struct bridge_softc *sc;
        struct ifnet *ifp;
-       int i;
 
        sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
        sc->sc_stp = bstp_create(&sc->sc_if);
@@ -168,9 +167,7 @@ bridge_clone_create(struct if_clone *ifc
        timeout_set(&sc->sc_brtimeout, bridge_rtage, sc);
        TAILQ_INIT(&sc->sc_iflist);
        TAILQ_INIT(&sc->sc_spanlist);
-       for (i = 0; i < BRIDGE_RTABLE_SIZE; i++)
-               LIST_INIT(&sc->sc_rts[i]);
-       arc4random_buf(&sc->sc_hashkey, sizeof(sc->sc_hashkey));
+       RBT_INIT(bridge_rtable, &sc->sc_rts);
        ifp = &sc->sc_if;
        snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
            unit);
Index: if_bridge.h
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.h,v
retrieving revision 1.56
diff -u -p -r1.56 if_bridge.h
--- if_bridge.h 5 Feb 2018 03:51:53 -0000       1.56
+++ if_bridge.h 9 Feb 2018 23:18:43 -0000
@@ -36,6 +36,7 @@
 #define _NET_IF_BRIDGE_H_
 
 #include <sys/timeout.h>
+#include <sys/tree.h>
 #include <net/pfvar.h>
 
 /*
@@ -447,7 +448,7 @@ struct bridge_tunneltag {
  * Bridge route node
  */
 struct bridge_rtnode {
-       LIST_ENTRY(bridge_rtnode)       brt_next;       /* next in list */
+       RBT_ENTRY(bridge_rtnode)        brt_entry;
        struct ifnet                    *brt_if;        /* destination ifs */
        u_int8_t                        brt_flags;      /* address flags */
        u_int8_t                        brt_age;        /* age counter */
@@ -455,10 +456,15 @@ struct bridge_rtnode {
        struct bridge_tunneltag         brt_tunnel;     /* tunnel endpoint */
 };
 
-#ifndef BRIDGE_RTABLE_SIZE
-#define BRIDGE_RTABLE_SIZE     1024
-#endif
-#define BRIDGE_RTABLE_MASK     (BRIDGE_RTABLE_SIZE - 1)
+RBT_HEAD(bridge_rtable, bridge_rtnode);
+
+static inline int
+bridge_rtnode_cmp(const struct bridge_rtnode *a, const struct bridge_rtnode *b)
+{
+       return (memcmp(&a->brt_addr, &b->brt_addr, sizeof(a->brt_addr)));
+}
+
+RBT_PROTOTYPE(bridge_rtable, bridge_rtnode, brt_entry, bridge_rtnode_cmp);
 
 /*
  * Software state for each bridge
@@ -468,12 +474,11 @@ struct bridge_softc {
        u_int32_t                       sc_brtmax;      /* max # addresses */
        u_int32_t                       sc_brtcnt;      /* current # addrs */
        int                             sc_brttimeout;  /* timeout ticks */
-       u_int64_t                       sc_hashkey[2];  /* siphash key */
        struct timeout                  sc_brtimeout;   /* timeout state */
        struct bstp_state               *sc_stp;        /* stp state */
        TAILQ_HEAD(, bridge_iflist)     sc_iflist;      /* interface list */
        TAILQ_HEAD(, bridge_iflist)     sc_spanlist;    /* span ports */
-       LIST_HEAD(, bridge_rtnode)      sc_rts[BRIDGE_RTABLE_SIZE];     /* hash 
table */
+       struct bridge_rtable            sc_rts;
 };
 
 extern const u_int8_t bstp_etheraddr[];
Index: bridgectl.c
===================================================================
RCS file: /cvs/src/sys/net/bridgectl.c,v
retrieving revision 1.8
diff -u -p -r1.8 bridgectl.c
--- bridgectl.c 5 Feb 2018 05:06:51 -0000       1.8
+++ bridgectl.c 9 Feb 2018 23:18:43 -0000
@@ -41,8 +41,6 @@
 #include <sys/timeout.h>
 #include <sys/kernel.h>
 
-#include <crypto/siphash.h>
-
 #include <net/if.h>
 
 #include <netinet/in.h>
@@ -173,18 +171,15 @@ struct ifnet *
 bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
     struct ifnet *ifp, int setflags, u_int8_t flags, struct mbuf *m)
 {
-       struct bridge_rtnode *p, *q;
+       struct bridge_rtnode *p;
        struct bridge_tunneltag *brtag = NULL;
-       u_int32_t h;
-       int dir;
 
        if (m != NULL) {
                /* Check if the mbuf was tagged with a tunnel endpoint addr */
                brtag = bridge_tunnel(m);
        }
 
-       h = bridge_hash(sc, ea);
-       p = LIST_FIRST(&sc->sc_rts[h]);
+       p = bridge_rtlookup(sc, ea);
        if (p == NULL) {
                if (sc->sc_brtcnt >= sc->sc_brtmax)
                        goto done;
@@ -202,105 +197,34 @@ bridge_rtupdate(struct bridge_softc *sc,
                else
                        p->brt_flags = IFBAF_DYNAMIC;
 
-               LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
+               RBT_INSERT(bridge_rtable, &sc->sc_rts, p);
                sc->sc_brtcnt++;
-               goto want;
-       }
-
-       do {
-               q = p;
-               p = LIST_NEXT(p, brt_next);
-
-               dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
-               if (dir == 0) {
-                       if (setflags) {
-                               q->brt_if = ifp;
-                               q->brt_flags = flags;
-                       } else if (!(q->brt_flags & IFBAF_STATIC))
-                               q->brt_if = ifp;
-
-                       if (q->brt_if == ifp)
-                               q->brt_age = 1;
-                       ifp = q->brt_if;
-                       bridge_copytag(brtag, &q->brt_tunnel);
-
-                       goto want;
-               }
-
-               if (dir > 0) {
-                       if (sc->sc_brtcnt >= sc->sc_brtmax)
-                               goto done;
-                       p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
-                       if (p == NULL)
-                               goto done;
-
-                       bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
+       } else {
+               if (setflags) {
                        p->brt_if = ifp;
-                       p->brt_age = 1;
-                       bridge_copytag(brtag, &p->brt_tunnel);
-
-                       if (setflags)
-                               p->brt_flags = flags;
-                       else
-                               p->brt_flags = IFBAF_DYNAMIC;
-
-                       LIST_INSERT_BEFORE(q, p, brt_next);
-                       sc->sc_brtcnt++;
-                       goto want;
-               }
-
-               if (p == NULL) {
-                       if (sc->sc_brtcnt >= sc->sc_brtmax)
-                               goto done;
-                       p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
-                       if (p == NULL)
-                               goto done;
-
-                       bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
+                       p->brt_flags = flags;
+               } else if (!(p->brt_flags & IFBAF_STATIC))
                        p->brt_if = ifp;
-                       p->brt_age = 1;
-                       bridge_copytag(brtag, &p->brt_tunnel);
 
-                       if (setflags)
-                               p->brt_flags = flags;
-                       else
-                               p->brt_flags = IFBAF_DYNAMIC;
-                       LIST_INSERT_AFTER(q, p, brt_next);
-                       sc->sc_brtcnt++;
-                       goto want;
-               }
-       } while (p != NULL);
+               if (p->brt_if == ifp)
+                       p->brt_age = 1;
+               ifp = p->brt_if;
+               bridge_copytag(brtag, &p->brt_tunnel);
+       }
 
 done:
        ifp = NULL;
-want:
        return (ifp);
 }
 
 struct bridge_rtnode *
 bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea)
 {
-       struct bridge_rtnode *p;
-       u_int32_t h;
-       int dir;
+       struct bridge_rtnode key;
 
-       h = bridge_hash(sc, ea);
-       LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
-               dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
-               if (dir == 0)
-                       return (p);
-               if (dir > 0)
-                       goto fail;
-       }
-fail:
-       return (NULL);
-}
+       key.brt_addr = *ea;
 
-u_int32_t
-bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)
-{
-       return SipHash24((SIPHASH_KEY *)sc->sc_hashkey, addr, ETHER_ADDR_LEN) &
-           BRIDGE_RTABLE_MASK;
+       return (RBT_FIND(bridge_rtable, &sc->sc_rts, &key));
 }
 
 /*
@@ -311,28 +235,18 @@ bridge_rtage(void *vsc)
 {
        struct bridge_softc *sc = vsc;
        struct bridge_rtnode *n, *p;
-       int i;
 
        KERNEL_ASSERT_LOCKED();
 
-       for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
-               n = LIST_FIRST(&sc->sc_rts[i]);
-               while (n != NULL) {
-                       if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
-                               n->brt_age = !n->brt_age;
-                               if (n->brt_age)
-                                       n->brt_age = 0;
-                               n = LIST_NEXT(n, brt_next);
-                       } else if (n->brt_age) {
-                               n->brt_age = 0;
-                               n = LIST_NEXT(n, brt_next);
-                       } else {
-                               p = LIST_NEXT(n, brt_next);
-                               LIST_REMOVE(n, brt_next);
-                               sc->sc_brtcnt--;
-                               free(n, M_DEVBUF, sizeof *n);
-                               n = p;
-                       }
+       RBT_FOREACH_SAFE(n, bridge_rtable, &sc->sc_rts, p) {
+               if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
+                       n->brt_age = 0;
+               else if (n->brt_age)
+                       n->brt_age = 0;
+               else {
+                       sc->sc_brtcnt--;
+                       RBT_REMOVE(bridge_rtable, &sc->sc_rts, n);
+                       free(n, M_DEVBUF, sizeof(*n));
                }
        }
 
@@ -345,7 +259,6 @@ bridge_rtagenode(struct ifnet *ifp, int 
 {
        struct bridge_softc *sc;
        struct bridge_rtnode *n;
-       int i;
 
        sc = ((struct bridge_iflist *)ifp->if_bridgeport)->bridge_sc;
        if (sc == NULL)
@@ -355,18 +268,17 @@ bridge_rtagenode(struct ifnet *ifp, int 
         * If the age is zero then flush, otherwise set all the expiry times to
         * age for the interface
         */
-       if (age == 0)
+       if (age == 0) {
                bridge_rtdelete(sc, ifp, 1);
-       else {
-               for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
-                       LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
-                               /* Cap the expiry time to 'age' */
-                               if (n->brt_if == ifp &&
-                                   n->brt_age > time_uptime + age &&
-                                   (n->brt_flags & IFBAF_TYPEMASK) == 
IFBAF_DYNAMIC)
-                                       n->brt_age = time_uptime + age;
-                       }
-               }
+               return;
+       }
+
+       RBT_FOREACH(n, bridge_rtable, &sc->sc_rts) {
+               /* Cap the expiry time to 'age' */
+               if (n->brt_if == ifp &&
+                   n->brt_age > time_uptime + age &&
+                   (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
+                       n->brt_age = time_uptime + age;
        }
 }
 
@@ -376,22 +288,16 @@ bridge_rtagenode(struct ifnet *ifp, int 
 void
 bridge_rtflush(struct bridge_softc *sc, int full)
 {
-       int i;
        struct bridge_rtnode *p, *n;
 
-       for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
-               n = LIST_FIRST(&sc->sc_rts[i]);
-               while (n != NULL) {
-                       if (full ||
-                           (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
-                               p = LIST_NEXT(n, brt_next);
-                               LIST_REMOVE(n, brt_next);
-                               sc->sc_brtcnt--;
-                               free(n, M_DEVBUF, sizeof *n);
-                               n = p;
-                       } else
-                               n = LIST_NEXT(n, brt_next);
+       RBT_FOREACH_SAFE(n, bridge_rtable, &sc->sc_rts, p) {
+               if ((n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
+                       /* only deleting dynamics */
+                       continue;
                }
+
+               sc->sc_brtcnt--;
+               RBT_REMOVE(bridge_rtable, &sc->sc_rts, n);
        }
 }
 
@@ -401,20 +307,17 @@ bridge_rtflush(struct bridge_softc *sc, 
 int
 bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea)
 {
-       int h;
-       struct bridge_rtnode *p;
+       struct bridge_rtnode *n;
 
-       h = bridge_hash(sc, ea);
-       LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
-               if (memcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
-                       LIST_REMOVE(p, brt_next);
-                       sc->sc_brtcnt--;
-                       free(p, M_DEVBUF, sizeof *p);
-                       return (0);
-               }
-       }
+       n = bridge_rtlookup(sc, ea);
+       if (n == NULL)
+               return (ENOENT);
 
-       return (ENOENT);
+       sc->sc_brtcnt--;
+       RBT_REMOVE(bridge_rtable, &sc->sc_rts, n);
+       free(n, M_DEVBUF, sizeof(*n));
+
+       return (0);
 }
 
 /*
@@ -423,33 +326,25 @@ bridge_rtdaddr(struct bridge_softc *sc, 
 void
 bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly)
 {
-       int i;
        struct bridge_rtnode *n, *p;
 
        /*
         * Loop through all of the hash buckets and traverse each
         * chain looking for routes to this interface.
         */
-       for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
-               n = LIST_FIRST(&sc->sc_rts[i]);
-               while (n != NULL) {
-                       if (n->brt_if != ifp) {
-                               /* Not ours */
-                               n = LIST_NEXT(n, brt_next);
-                               continue;
-                       }
-                       if (dynonly &&
-                           (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
-                               /* only deleting dynamics */
-                               n = LIST_NEXT(n, brt_next);
-                               continue;
-                       }
-                       p = LIST_NEXT(n, brt_next);
-                       LIST_REMOVE(n, brt_next);
-                       sc->sc_brtcnt--;
-                       free(n, M_DEVBUF, sizeof *n);
-                       n = p;
+       RBT_FOREACH_SAFE(n, bridge_rtable, &sc->sc_rts, p) {
+               if (n->brt_if != ifp) {
+                       /* Not ours */
+                       continue;
                }
+               if (dynonly &&
+                   (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
+                       /* only deleting dynamics */
+                       continue;
+               }
+
+               sc->sc_brtcnt--;
+               RBT_REMOVE(bridge_rtable, &sc->sc_rts, n);
        }
 }
 
@@ -459,40 +354,42 @@ bridge_rtdelete(struct bridge_softc *sc,
 int
 bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
 {
-       int i, error = 0, onlycnt = 0;
-       u_int32_t cnt = 0;
        struct bridge_rtnode *n;
        struct ifbareq bareq;
+       int error = 0;
+       int cnt = 0;
 
-       if (baconf->ifbac_len == 0)
-               onlycnt = 1;
+       if (baconf->ifbac_len == 0) {
+               cnt = sc->sc_brtcnt;
+               goto done;
+       }
 
-       for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
-               LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
-                       if (!onlycnt) {
-                               if (baconf->ifbac_len < sizeof(struct ifbareq))
-                                       goto done;
-                               bcopy(sc->sc_if.if_xname, bareq.ifba_name,
-                                   sizeof(bareq.ifba_name));
-                               bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
-                                   sizeof(bareq.ifba_ifsname));
-                               bcopy(&n->brt_addr, &bareq.ifba_dst,
-                                   sizeof(bareq.ifba_dst));
-                               bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa,
-                                   sstosa(&bareq.ifba_dstsa));
-                               bareq.ifba_age = n->brt_age;
-                               bareq.ifba_flags = n->brt_flags;
-                               error = copyout((caddr_t)&bareq,
-                                   (caddr_t)(baconf->ifbac_req + cnt), 
sizeof(bareq));
-                               if (error)
-                                       goto done;
-                               baconf->ifbac_len -= sizeof(struct ifbareq);
-                       }
-                       cnt++;
-               }
+       RBT_FOREACH(n, bridge_rtable, &sc->sc_rts) {
+               if (baconf->ifbac_len < sizeof(bareq))
+                       goto done;
+
+               bcopy(sc->sc_if.if_xname, bareq.ifba_name,
+                   sizeof(bareq.ifba_name));
+               bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
+                   sizeof(bareq.ifba_ifsname));
+               bcopy(&n->brt_addr, &bareq.ifba_dst,
+                   sizeof(bareq.ifba_dst));
+               bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa,
+                   sstosa(&bareq.ifba_dstsa));
+               bareq.ifba_age = n->brt_age;
+               bareq.ifba_flags = n->brt_flags;
+
+               error = copyout(&bareq, baconf->ifbac_req + cnt,
+                   sizeof(bareq));
+               if (error)
+                       goto done;
+
+               baconf->ifbac_len -= sizeof(bareq);
+               cnt++;
        }
+
 done:
-       baconf->ifbac_len = cnt * sizeof(struct ifbareq);
+       baconf->ifbac_len = cnt * sizeof(bareq);
        return (error);
 }
 
@@ -757,3 +654,5 @@ bridge_flushrule(struct bridge_iflist *b
                free(p, M_DEVBUF, sizeof *p);
        }
 }
+
+RBT_GENERATE(bridge_rtable, bridge_rtnode, brt_entry, bridge_rtnode_cmp);

Reply via email to