Hi,

With a fair amount of egg on my face I have to ask to resubmit
the patch ... I tried tidying it up a bit to minimize diffs
and forgot to recompile and test one last time

here is the new patch, and I'll include my test harness after that:


--- radix.c     2012-12-21 17:21:51.000000000 -0800
+++ radix.c.rewrite     2013-01-03 18:26:01.000000000 -0800
@@ -466,6 +466,10 @@
        if (rn_debug)
                log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p);
 #endif
+       if (nodes == 0 ) {
+           *dupentry = b;
+           return x;
+       }
        t = rn_newpair(v_arg, b, nodes); 
        tt = t->rn_left;
        if ((cp[p->rn_offset] & p->rn_bmask) == 0)
@@ -967,6 +971,37 @@
        return (tt);
 }
 
+struct subtree_info {
+       walktree_f_t *  si_f;
+       void *          si_w;
+       int             si_error;
+       char *          si_maskedkey;
+       char *          si_netmask;
+       char *          si_cplim;
+};
+
+static int
+rn_walksubtree_helper(rn, w)
+       struct radix_node *rn;
+       void *w;
+{
+       struct subtree_info *si = w;
+       char *cp, *cp2 = (char *)(rn->rn_key), *cp3 = si->si_netmask; 
+
+       /* check that we are still in the subtree */
+       for (cp = si->si_maskedkey; cp < si->si_cplim; cp++) {
+               if (*cp != (*cp2++) & (*cp3++))
+                       return 1;
+       }
+       if ((si->si_error = (*(si->si_f))(rn, si->si_w)))
+               return 2;
+       return 0;
+}
+
+/* forward declaration needed below */
+static int     rn_walktree_with(struct radix_node_head *h, void *a,
+                   walktree_f_t *f, void *w);
+
 /*
  * This is the same as rn_walktree() except for the parameters and the
  * exit.
@@ -978,115 +1013,44 @@
        walktree_f_t *f;
        void *w;
 {
-       int error;
-       struct radix_node *base, *next;
-       u_char *xa = (u_char *)a;
-       u_char *xm = (u_char *)m;
-       register struct radix_node *rn, *last = 0 /* shut up gcc */;
-       int stopping = 0;
-       int lastb;
-
-       /*
-        * rn_search_m is sort-of-open-coded here. We cannot use the
-        * function because we need to keep track of the last node seen.
-        */
-       /* printf("about to search\n"); */
-       for (rn = h->rnh_treetop; rn->rn_bit >= 0; ) {
-               last = rn;
-               /* printf("rn_bit %d, rn_bmask %x, xm[rn_offset] %x\n",
-                      rn->rn_bit, rn->rn_bmask, xm[rn->rn_offset]); */
-               if (!(rn->rn_bmask & xm[rn->rn_offset])) {
-                       break;
-               }
-               if (rn->rn_bmask & xa[rn->rn_offset]) {
-                       rn = rn->rn_right;
-               } else {
-                       rn = rn->rn_left;
-               }
-       }
-       /* printf("done searching\n"); */
-
-       /*
-        * Two cases: either we stepped off the end of our mask,
-        * in which case last == rn, or we reached a leaf, in which
-        * case we want to start from the last node we looked at.
-        * Either way, last is the node we want to start from.
-        */
-       rn = last;
-       lastb = rn->rn_bit;
-
-       /* printf("rn %p, lastb %d\n", rn, lastb);*/
-
-       /*
-        * This gets complicated because we may delete the node
-        * while applying the function f to it, so we need to calculate
-        * the successor node in advance.
-        */
-       while (rn->rn_bit >= 0)
-               rn = rn->rn_left;
-
-       while (!stopping) {
-               /* printf("node %p (%d)\n", rn, rn->rn_bit); */
-               base = rn;
-               /* If at right child go back up, otherwise, go right */
-               while (rn->rn_parent->rn_right == rn
-                      && !(rn->rn_flags & RNF_ROOT)) {
-                       rn = rn->rn_parent;
-
-                       /* if went up beyond last, stop */
-                       if (rn->rn_bit <= lastb) {
-                               stopping = 1;
-                               /* printf("up too far\n"); */
-                               /*
-                                * XXX we should jump to the 'Process leaves'
-                                * part, because the values of 'rn' and 'next'
-                                * we compute will not be used. Not a big deal
-                                * because this loop will terminate, but it is
-                                * inefficient and hard to understand!
-                                */
-                       }
-               }
-               
-               /* 
-                * At the top of the tree, no need to traverse the right
-                * half, prevent the traversal of the entire tree in the
-                * case of default route.
-                */
-               if (rn->rn_parent->rn_flags & RNF_ROOT)
-                       stopping = 1;
-
-               /* Find the next *leaf* since next node might vanish, too */
-               for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
-                       rn = rn->rn_left;
-               next = rn;
-               /* Process leaves */
-               while ((rn = base) != 0) {
-                       base = rn->rn_dupedkey;
-                       /* printf("leaf %p\n", rn); */
-                       if (!(rn->rn_flags & RNF_ROOT)
-                           && (error = (*f)(rn, w)))
-                               return (error);
-               }
-               rn = next;
+       if (!m)
+               return rn_walktree_with(h, a, f, w);
 
-               if (rn->rn_flags & RNF_ROOT) {
-                       /* printf("root, stopping"); */
-                       stopping = 1;
-               }
+       char temp[64], *cp, *cp2 = a, *cp3 = m;
+       size_t length = min(LEN(a), LEN(m));
+       struct subtree_info si;
 
+       if (length > sizeof(temp)) {
+               R_Malloc(si.si_maskedkey, char *, length);
+       } else {
+               si.si_maskedkey = temp;
        }
+       si.si_f = f;
+       si.si_w = w;
+       si.si_netmask = cp3;
+       si.si_cplim = si.si_maskedkey + length;
+
+       for (cp = si.si_maskedkey; cp < si.si_cplim; cp++)
+           { *cp = *cp2++ & *cp3++; }
+
+       int return_code = rn_walktree_with
+               (h, si.si_maskedkey, rn_walksubtree_helper,  &si);
+       if (length > sizeof(temp))
+           Free(si.si_maskedkey);
+       if (return_code == 2)
+           return si.si_error;
        return 0;
 }
 
 static int
-rn_walktree(h, f, w)
-       struct radix_node_head *h;
+rn_walktree1(rn, skipfirst, f, w)
+       struct radix_node *rn;
+       int skipfirst;
        walktree_f_t *f;
        void *w;
 {
        int error;
        struct radix_node *base, *next;
-       register struct radix_node *rn = h->rnh_treetop;
        /*
         * This gets complicated because we may delete the node
         * while applying the function f to it, so we need to calculate
@@ -1105,6 +1069,10 @@
                /* Find the next *leaf* since next node might vanish, too */
                for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
                        rn = rn->rn_left;
+               if (skipfirst) {
+                   skipfirst = 0;
+                   continue;
+               }
                next = rn;
                /* Process leaves */
                while ((rn = base)) {
@@ -1120,6 +1088,42 @@
        /* NOTREACHED */
 }
 
+static int
+rn_walktree(h, f, w)
+       struct radix_node_head *h;
+       walktree_f_t *f;
+       void *w;
+{
+       return rn_walktree1(h->rnh_treetop, 0, f, w);
+}
+
+/*
+ * Walk the tree starting with or after v, (without masking).
+ */
+static int
+rn_walktree_with(h, v_arg, f, w)
+       struct radix_node_head *h;
+       void *v_arg;
+       walktree_f_t *f;
+       void *w;
+{
+       int b, skipfirst = 0;
+       caddr_t v = v_arg;
+       struct radix_node *x = rn_insert(v_arg, h, &b, (struct radix_node *)0);
+       if (b != 1) {
+               /* our value matches every child of x up to, but !including b */
+               if (v[b >> 3] & (0x80 >> ( b & 7 )) ) {
+                   /* value will be > so start *after* rightmost child */
+                   skipfirst = 1;
+                   while (x->rn_bit > 0) { x = x->rn_right; }
+               } else {
+                   /* value < any child so start with leftmost child */
+                   while (x->rn_bit > 0) { x = x->rn_left; }
+               }
+       } /* b == 1 means exact match so we start with it */
+       return rn_walktree1(x, skipfirst, f, w);
+}
+
 /*
  * Allocate and initialize an empty tree. This has 3 nodes, which are
  * part of the radix_node_head (in the order <left,root,right>) and are

<end of patch>
<test harness follows>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <strings.h>

#define KASSERT(cond, list)  { if (cond) printf list ; }
#include "radix.c"
#include  <net/ethernet.h>
#include  <errno.h>

struct radix_node_head *rnh;

struct testdata {
        char *addr;
        char *mask;
        u_short         vd_vlan;
} samples[] = {
    { "128.32.9.0", "255.255.255.0" },
    { "128.32.8.0", "255.255.255.0" },
    { "128.32.8.1", 0 },
    { "128.32.8.3", 0 },
    { 0, 0 }
};

struct treedata {
    struct radix_node tree_glue[2];
    struct sockaddr_in tree_addr;
    struct sockaddr_in tree_mask;
};

void
debauch(char *addr, struct sockaddr_in *sin) /* lead into sin */
{
    /* bzero(sin, sizeof(*sin)); pedantically, already zeroed */ 
    sin->sin_len =  sizeof (*sin);
    sin->sin_family = AF_INET;
    (void) inet_aton(addr, &sin->sin_addr);
}

void
install(struct testdata *td)
{
    struct sockaddr_in *mask_p = 0;
    struct treedata *tr;

    R_Zalloc(tr, struct treedata *, sizeof(*tr));
    debauch(td->addr, &tr->tree_addr);
    if (td->mask) {
        debauch(td->mask, &tr->tree_mask);
        mask_p = &tr->tree_mask;
    }
    (void) rnh->rnh_addaddr(&(tr->tree_addr), mask_p, rnh, tr->tree_glue);
}

int
p_helper(struct radix_node *rn, void *v)
{
    struct treedata *tr = (struct treedata *)rn;
    printf("addr %s\n", inet_ntoa(tr->tree_addr.sin_addr));
    return (0);
}

struct sockaddr_in sample_mask, inthetree, notintree, middle;
#ifndef offsetof
    #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
#endif

main() 
{
    rn_init(sizeof sample_mask);
    rn_inithead((void **)&rnh, 8 * offsetof(struct sockaddr_in, sin_addr));

    debauch("255.255.255.0", &sample_mask);
    debauch("128.32.9.0", &inthetree);
    debauch("128.32.25.0", &notintree);
    debauch("128.32.8.2", &middle);

    struct testdata *td;
    for (td = samples; td->addr; td++)
        install(td);

    printf("inthetree case\n");
    rnh->rnh_walktree_from(rnh, &inthetree, &sample_mask, p_helper, 0);
    printf("notintree case\n");
    rnh->rnh_walktree_from(rnh, &notintree, &sample_mask, p_helper, 0);
    printf("new middle case\n");
    rnh->rnh_walktree_from(rnh, &middle, 0, p_helper, 0);
/*
    printf("walksubtree does\n");
    rn_walksubtree(rnh, &inthetree, &sample_mask, p_helper, 0);
    printf("walksubtree does\n");
    rn_walksubtree(rnh, &notintree, &sample_mask, p_helper, 0);
*/
    exit(0);
}

_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "[email protected]"

Reply via email to