Clarifications required in rn_delete

Dheeraj Kandula dkandula at gmail.com
Tue Feb 26 16:56:43 UTC 2013


Hey All,
     I have been reading through the routing path code in FreeBSD 9.1 and
have a few questions while adding and deleting a route using rn_addroute()
and rn_delete(). My questions are highlighted in bold.

In the code fragment below - part of rn_delete() function:

b = -1 - tt->rn_bit;
    t = saved_tt->rn_parent;
    if (b > t->rn_bit)
        goto on1; /* Wasn't lifted at all */
    do {
        x = t;
        t = t->rn_parent;
    } while (b <= t->rn_bit && x != top);
    for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
        if (m == saved_m) {
            *mp = m->rm_mklist;
            MKFree(m);
            break;
        }
    if (m == 0) {
        log(LOG_ERR, "rn_delete: couldn't find our annotation\n");
        if (tt->rn_flags & RNF_NORMAL)
            return (0); /* Dangling ref to us */
    }


the node "m" inside the for loop is removed from x's rn_mklist and inserted
into rn_mkfreelist.

*Shouldn't a test for the rm_refs similar to code below - part of
rn_delete() too - be performed.??*

/*
     * Demote routes attached to us.
     */
    if (t->rn_mklist) {
        if (x->rn_bit >= 0) {
            for (mp = &x->rn_mklist; (m = *mp);)
                mp = &m->rm_mklist;
            *mp = t->rn_mklist;
        } else {
            /* If there are any key,mask pairs in a sibling
               duped-key chain, some subset will appear sorted
               in the same order attached to our mklist */
            for (m = t->rn_mklist; m && x; x = x->rn_dupedkey)
                if (m == x->rn_mklist) {
                    struct radix_mask *mm = m->rm_mklist;
                    x->rn_mklist = 0;
          *          if (--(m->rm_refs) < 0)
                        MKFree(m);*
                    m = mm;
                }
            if (m)
                log(LOG_ERR,
                    "rn_delete: Orphaned Mask %p at %p\n",
                    m, x);
        }
    }

My understanding is that for leaf nodes that represent a network route,
there will be only one radix_mask node in the linked list.

When a new route is being added i.e. rn_addroute(), the other child of the
new route's parent i.e. the sibling of the new route's node, can be either
a leaf or an internal node.

The scenarios are described below:

1. Leaf Node.
    a. If it is a leaf that is a network route and no duplicate routes at x
i.e. x->rn_dupedkey is NULL, a new radix_mask node is created when the
rn_bit is >= the new route's rn_bit i.e. x->rn_bit >= b_leaf and
x->rn_mklist == 0.

/* Promote general routes from below */
    if (x->rn_bit < 0) {
        for (mp = &t->rn_mklist; x; x = x->rn_dupedkey)
        if (x->rn_mask && (x->rn_bit >= b_leaf) && x->rn_mklist == 0) {
            *mp = m = rn_new_radix_mask(x, 0);
            if (m)
                mp = &m->rm_mklist;
        }
    }

    b. If it is a leaf that is a network node and there are duplicate
routes at  x i.e. x->rn_dupedkey is NON-NULL, a new radix_mask node is
added for every node in the duplicate linked list if. x->rn_bit >= b_leaf.
as per the code above in case a.

2. Internal Node:

If it is an internal node and the x->rn_mklist is NON-NULL, the linked list
headed by x->rn_mklist is traversed and the traversal is discontinued only
if m->rm_bit >= b_leaf.

 else if (x->rn_mklist) {
        /*
         * Skip over masks whose index is > that of new node
         */
        for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
            if (m->rm_bit >= b_leaf)
                break;
        t->rn_mklist = m; *mp = 0;
    }

Here x will always be an internal node and hence if (m->rm_bit >= b_leaf)
will always fail as b_leaf is a signed short and rm_bit is a signed short
too and b_leaf is negative as b_leaf is -1 -t->rn_bit. *Isn't it? Is this a
bug in the code.*

Dheeraj


More information about the freebsd-net mailing list