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);