On Wed, Jun 22, 2011 at 01:21:28PM +0200, Camiel Dobbelaar wrote:
> 
> Hi Bret,
> 
> one comment from inspection, is the part below related to the RB tree?
> Or a seperate optimization?
> 
> On 22-6-2011 12:21, Bret S. Lambert wrote:
> 
> > @@ -1109,33 +1119,12 @@ bridge_output(struct ifnet *ifp, struct 
> >                             used = 1;
> >                             mc = m;
> >                     } else {
> > -                           struct mbuf *m1, *m2, *mx;
> > -
> > -                           m1 = m_copym2(m, 0, ETHER_HDR_LEN,
> > -                               M_DONTWAIT);
> > -                           if (m1 == NULL) {
> > -                                   sc->sc_if.if_oerrors++;
> > -                                   continue;
> > -                           }
> > -                           m2 = m_copym2(m, ETHER_HDR_LEN,
> > +                           mc = m_copym2(m, 0,
> >                                 M_COPYALL, M_DONTWAIT);
> > -                           if (m2 == NULL) {
> > -                                   m_freem(m1);
> > +                           if (mc == NULL) {
> >                                     sc->sc_if.if_oerrors++;
> >                                     continue;
> >                             }
> > -
> > -                           for (mx = m1; mx->m_next != NULL; mx = 
> > mx->m_next)
> > -                                   /*EMPTY*/;
> > -                           mx->m_next = m2;
> > -
> > -                           if (m1->m_flags & M_PKTHDR) {
> > -                                   len = 0;
> > -                                   for (mx = m1; mx != NULL; mx = 
> > mx->m_next)
> > -                                           len += mx->m_len;
> > -                                   m1->m_pkthdr.len = len;
> > -                           }
> > -                           mc = m1;
> >                     }
> >  
> >                     error = bridge_ifenqueue(sc, dst_if, mc);
> 

Ack; had sent an older diff before I had ripped this out. Please ignore,
and use the following updated diff. Apologies for the noise.

Index: if_bridge.h
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.h,v
retrieving revision 1.34
diff -u -p -r1.34 if_bridge.h
--- if_bridge.h 20 Nov 2010 14:23:09 -0000      1.34
+++ if_bridge.h 22 Jun 2011 12:46:52 -0000
@@ -396,7 +396,7 @@ struct bridge_iflist {
  * Bridge route node
  */
 struct bridge_rtnode {
-       LIST_ENTRY(bridge_rtnode)       brt_next;       /* next in list */
+       RB_ENTRY(bridge_rtnode)         brt_entry;      /* entry in rb tree */
        struct                          ifnet *brt_if;  /* destination ifs */
        u_int8_t                        brt_flags;      /* address flags */
        u_int8_t                        brt_age;        /* age counter */
@@ -422,7 +422,7 @@ struct bridge_softc {
        struct timeout                  sc_brtimeout;   /* timeout state */
        struct bstp_state               *sc_stp;        /* stp state */
        LIST_HEAD(, bridge_iflist)      sc_iflist;      /* interface list */
-       LIST_HEAD(, bridge_rtnode)      sc_rts[BRIDGE_RTABLE_SIZE];     /* hash 
table */
+       RB_HEAD(brt_tree, bridge_rtnode) sc_rts;        /* route tree */
        LIST_HEAD(, bridge_iflist)      sc_spanlist;    /* span ports */
 };
 
Index: if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.188
diff -u -p -r1.188 if_bridge.c
--- if_bridge.c 4 Nov 2010 23:07:15 -0000       1.188
+++ if_bridge.c 22 Jun 2011 12:46:52 -0000
@@ -45,6 +45,7 @@
 #include <sys/ioctl.h>
 #include <sys/errno.h>
 #include <sys/kernel.h>
+#include <sys/tree.h>
 #include <machine/cpu.h>
 
 #include <net/if.h>
@@ -135,7 +136,7 @@ int bridge_rtfind(struct bridge_softc *,
 void   bridge_rtage(struct bridge_softc *);
 void   bridge_rttrim(struct bridge_softc *);
 int    bridge_rtdaddr(struct bridge_softc *, struct ether_addr *);
-int    bridge_rtflush(struct bridge_softc *, int);
+void   bridge_rtflush(struct bridge_softc *, int);
 struct ifnet * bridge_rtupdate(struct bridge_softc *,
     struct ether_addr *, struct ifnet *ifp, int, u_int8_t);
 struct ifnet * bridge_rtlookup(struct bridge_softc *,
@@ -180,6 +181,16 @@ LIST_HEAD(, bridge_softc) bridge_list;
 struct if_clone bridge_cloner =
     IF_CLONE_INITIALIZER("bridge", bridge_clone_create, bridge_clone_destroy);
 
+static __inline int brt_cmp(struct bridge_rtnode *, struct bridge_rtnode *);
+RB_PROTOTYPE(brt_tree, bridge_rtnode, brt_entry, brt_cmp);
+RB_GENERATE(brt_tree, bridge_rtnode, brt_entry, brt_cmp);
+
+static __inline int
+brt_cmp(struct bridge_rtnode *a, struct bridge_rtnode *b)
+{
+       return (memcmp(&a->brt_addr, &b->brt_addr, sizeof(a->brt_addr)));
+}
+
 /* ARGSUSED */
 void
 bridgeattach(int n)
@@ -193,7 +204,7 @@ bridge_clone_create(struct if_clone *ifc
 {
        struct bridge_softc *sc;
        struct ifnet *ifp;
-       int i, s;
+       int s;
 
        sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO);
        if (!sc)
@@ -210,8 +221,7 @@ bridge_clone_create(struct if_clone *ifc
        timeout_set(&sc->sc_brtimeout, bridge_timer, sc);
        LIST_INIT(&sc->sc_iflist);
        LIST_INIT(&sc->sc_spanlist);
-       for (i = 0; i < BRIDGE_RTABLE_SIZE; i++)
-               LIST_INIT(&sc->sc_rts[i]);
+       RB_INIT(&sc->sc_rts);
        sc->sc_hashkey = arc4random();
        ifp = &sc->sc_if;
        snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
@@ -559,7 +569,7 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                if ((error = suser(curproc, 0)) != 0)
                        break;
 
-               error = bridge_rtflush(sc, req->ifbr_ifsflags);
+               bridge_rtflush(sc, req->ifbr_ifsflags);
                break;
        case SIOCBRDGSADDR:
                if ((error = suser(curproc, 0)) != 0)
@@ -1774,151 +1784,46 @@ struct ifnet *
 bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
     struct ifnet *ifp, int setflags, u_int8_t flags)
 {
-       struct bridge_rtnode *p, *q;
-       u_int32_t h;
-       int dir;
-
-       h = bridge_hash(sc, ea);
-       p = LIST_FIRST(&sc->sc_rts[h]);
-       if (p == LIST_END(&sc->sc_rts[h])) {
+       struct bridge_rtnode *brt, tmp;
+
+       bcopy(ea, &tmp.brt_addr, sizeof(*ea));
+
+       if ((brt = RB_FIND(brt_tree, &sc->sc_rts, &tmp)) == NULL) {
+
                if (sc->sc_brtcnt >= sc->sc_brtmax)
-                       goto done;
-               p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
-               if (p == NULL)
-                       goto done;
+                       goto fail;
+               if ((brt = malloc(sizeof(*brt), M_DEVBUF, M_NOWAIT)) == NULL)
+                       goto fail;
 
-               bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
-               p->brt_if = ifp;
-               p->brt_age = 1;
+               bcopy(ea, &brt->brt_addr, sizeof(brt->brt_addr));
+               brt->brt_if = ifp;
+               brt->brt_age = 1;
 
                if (setflags)
-                       p->brt_flags = flags;
+                       brt->brt_flags = flags;
                else
-                       p->brt_flags = IFBAF_DYNAMIC;
+                       brt->brt_flags = IFBAF_DYNAMIC;
 
-               LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
+               RB_INSERT(brt_tree, &sc->sc_rts, brt);
                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;
-                       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));
-                       p->brt_if = ifp;
-                       p->brt_age = 1;
-
-                       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 == LIST_END(&sc->sc_rts[h])) {
-                       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_if = ifp;
-                       p->brt_age = 1;
-
-                       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 != LIST_END(&sc->sc_rts[h]));
-
-done:
-       ifp = NULL;
-want:
-       return (ifp);
+       return (brt->brt_if);
+fail:
+       return (NULL);
 }
 
 struct ifnet *
 bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea)
 {
-       struct bridge_rtnode *p;
-       u_int32_t h;
-       int dir;
-
-       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->brt_if);
-               if (dir > 0)
-                       goto fail;
-       }
-fail:
-       return (NULL);
-}
+       struct bridge_rtnode *brt, tmp;
 
-/*
- * The following hash function is adapted from 'Hash Functions' by Bob Jenkins
- * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
- * "You may use this code any way you wish, private, educational, or
- *  commercial.  It's free."
- */
-#define        mix(a,b,c) \
-       do {                                            \
-               a -= b; a -= c; a ^= (c >> 13);         \
-               b -= c; b -= a; b ^= (a << 8);          \
-               c -= a; c -= b; c ^= (b >> 13);         \
-               a -= b; a -= c; a ^= (c >> 12);         \
-               b -= c; b -= a; b ^= (a << 16);         \
-               c -= a; c -= b; c ^= (b >> 5);          \
-               a -= b; a -= c; a ^= (c >> 3);          \
-               b -= c; b -= a; b ^= (a << 10);         \
-               c -= a; c -= b; c ^= (b >> 15);         \
-       } while (0)
-
-u_int32_t
-bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)
-{
-       u_int32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_hashkey;
-
-       b += addr->ether_addr_octet[5] << 8;
-       b += addr->ether_addr_octet[4];
-       a += addr->ether_addr_octet[3] << 24;
-       a += addr->ether_addr_octet[2] << 16;
-       a += addr->ether_addr_octet[1] << 8;
-       a += addr->ether_addr_octet[0];
+       bcopy(ea, &tmp.brt_addr, sizeof(*ea));
+
+       if ((brt = RB_FIND(brt_tree, &sc->sc_rts, &tmp)))
+               return (brt->brt_if);
 
-       mix(a, b, c);
-       return (c & BRIDGE_RTABLE_MASK);
+       return (NULL);
 }
 
 /*
@@ -1929,7 +1834,6 @@ void
 bridge_rttrim(struct bridge_softc *sc)
 {
        struct bridge_rtnode *n, *p;
-       int i;
 
        /*
         * Make sure we have to trim the address table
@@ -1945,18 +1849,14 @@ bridge_rttrim(struct bridge_softc *sc)
        if (sc->sc_brtcnt <= sc->sc_brtmax)
                return;
 
-       for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
-               n = LIST_FIRST(&sc->sc_rts[i]);
-               while (n != LIST_END(&sc->sc_rts[i])) {
-                       p = LIST_NEXT(n, brt_next);
-                       if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
-                               LIST_REMOVE(n, brt_next);
-                               sc->sc_brtcnt--;
-                               free(n, M_DEVBUF);
-                               if (sc->sc_brtcnt <= sc->sc_brtmax)
-                                       return;
-                       }
-                       n = p;
+       for (n = RB_MIN(brt_tree, &sc->sc_rts); n != NULL; n = p) {
+               p = RB_NEXT(brt_tree, &sc->sc_rts, n);
+               if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
+                       RB_REMOVE(brt_tree, &sc->sc_rts, n);
+                       sc->sc_brtcnt--;
+                       free(n, M_DEVBUF);
+                       if (sc->sc_brtcnt <= sc->sc_brtmax)
+                               return;
                }
        }
 }
@@ -1979,26 +1879,19 @@ void
 bridge_rtage(struct bridge_softc *sc)
 {
        struct bridge_rtnode *n, *p;
-       int i;
 
-       for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
-               n = LIST_FIRST(&sc->sc_rts[i]);
-               while (n != LIST_END(&sc->sc_rts[i])) {
-                       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) {
+       for (n = RB_MIN(brt_tree, &sc->sc_rts); n != NULL; n = p) {
+               p = RB_NEXT(brt_tree, &sc->sc_rts, n);
+               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 {
-                               p = LIST_NEXT(n, brt_next);
-                               LIST_REMOVE(n, brt_next);
-                               sc->sc_brtcnt--;
-                               free(n, M_DEVBUF);
-                               n = p;
-                       }
+               } else if (n->brt_age) {
+                       n->brt_age = 0;
+               } else {
+                       RB_REMOVE(brt_tree, &sc->sc_rts, n);
+                       sc->sc_brtcnt--;
+                       free(n, M_DEVBUF);
                }
        }
 
@@ -2011,7 +1904,6 @@ bridge_rtagenode(struct ifnet *ifp, int 
 {
        struct bridge_softc *sc = (struct bridge_softc *)ifp->if_bridge;
        struct bridge_rtnode *n;
-       int i;
 
        if (sc == NULL)
                return;
@@ -2023,14 +1915,12 @@ bridge_rtagenode(struct ifnet *ifp, int 
        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;
-                       }
+               RB_FOREACH(n, brt_tree, &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;
                }
        }
 }
@@ -2040,28 +1930,20 @@ bridge_rtagenode(struct ifnet *ifp, int 
 /*
  * Remove all dynamic addresses from the cache
  */
-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 != LIST_END(&sc->sc_rts[i])) {
-                       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);
-                               n = p;
-                       } else
-                               n = LIST_NEXT(n, brt_next);
+       for (n = RB_MIN(brt_tree, &sc->sc_rts); n != NULL; n = p) {
+               p = RB_NEXT(brt_tree, &sc->sc_rts, n);
+
+               if (full || (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
+                       RB_REMOVE(brt_tree, &sc->sc_rts, n);
+                       sc->sc_brtcnt--;
+                       free(n, M_DEVBUF);
                }
        }
-
-       return (0);
 }
 
 /*
@@ -2070,54 +1952,44 @@ 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 *brt, tmp;
 
-       h = bridge_hash(sc, ea);
-       LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
-               if (bcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
-                       LIST_REMOVE(p, brt_next);
-                       sc->sc_brtcnt--;
-                       free(p, M_DEVBUF);
-                       return (0);
-               }
-       }
+       bcopy(ea, &tmp.brt_addr, sizeof(*ea));
+
+       if ((brt = RB_FIND(brt_tree, &sc->sc_rts, &tmp)) == NULL)
+               return (ENOENT);
 
-       return (ENOENT);
+       RB_REMOVE(brt_tree, &sc->sc_rts, brt);
+       sc->sc_brtcnt--;
+       free(brt, M_DEVBUF);
+
+       return (0);
 }
+
 /*
  * Delete routes to a specific interface member.
  */
 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.
+        * traverse tree looking for routes to this interface.
         */
-       for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
-               n = LIST_FIRST(&sc->sc_rts[i]);
-               while (n != LIST_END(&sc->sc_rts[i])) {
-                       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);
-                       n = p;
-               }
+       for (n = RB_MIN(brt_tree, &sc->sc_rts); n != NULL; n = p) {
+               p = RB_NEXT(brt_tree, &sc->sc_rts, n);
+
+               if (n->brt_if != ifp)
+                       continue;
+
+               if (dynonly &&
+                   (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC)
+                       continue;
+
+               RB_REMOVE(brt_tree, &sc->sc_rts, n);
+               sc->sc_brtcnt--;
+               free(n, M_DEVBUF);
        }
 }
 
@@ -2127,35 +1999,33 @@ 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;
+       struct bridge_rtnode *brt;
+       int error = 0, onlycnt = 0;
+       u_int32_t cnt = 0;
 
        if (baconf->ifbac_len == 0)
                onlycnt = 1;
 
-       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));
-                               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++;
+       RB_FOREACH(brt, brt_tree, &sc->sc_rts) {
+               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(brt->brt_if->if_xname, bareq.ifba_ifsname,
+                           sizeof(bareq.ifba_ifsname));
+                       bcopy(&brt->brt_addr, &bareq.ifba_dst,
+                           sizeof(bareq.ifba_dst));
+                       bareq.ifba_age = brt->brt_age;
+                       bareq.ifba_flags = brt->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++;
        }
 done:
        baconf->ifbac_len = cnt * sizeof(struct ifbareq);

Reply via email to