fb0d340e250becdb48c9ad3562758caed7d79044
* Copyright (c) 1988, 1989, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
* @(#)radix.c 8.2.2.1 (Berkeley) %G%
* Routines to build and maintain radix trees for routing lookups.
#define M_DONTWAIT M_NOWAIT
struct radix_node_head
*mask_rnhead
;
static char *rn_zeros
, *rn_ones
;
#define rn_masktop (mask_rnhead->rnh_treetop)
#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l))
* The data structure for the keys is a radix tree with one way
* branching removed. The index rn_b at an internal node n represents a bit
* position to be tested. The tree is arranged so that all descendants
* of a node n have keys whose bits all agree up to position rn_b - 1.
* (We say the index of n is rn_b.)
* There is at least one descendant which has a one bit at position rn_b,
* and at least one with a zero there.
* A route is determined by a pair of key and mask. We require that the
* bit-wise logical and of the key and mask to be the key.
* We define the index of a route to associated with the mask to be
* the first bit number in the mask where 0 occurs (with bit number 0
* representing the highest order bit).
* We say a mask is normal if every bit is 0, past the index of the mask.
* If a node n has a descendant (k, m) with index(m) == index(n) == rn_b,
* and m is a normal mask, then the route applies to every descendant of n.
* If the index(m) < rn_b, this implies the trailing last few bits of k
* before bit b are all 0, (and hence consequently true of every descendant
* of n), so the route applies to all descendants of the node as well.
* This version of the code assumes that all masks are normal,
* and consequently the only thing that needs to be stored about a mask
* is its length. This version also permits mapped, and fixed length
* elements to be entered into the tree.
register struct radix_node
*x
;
for (x
= top
, v
= v_arg
; x
->rn_b
>= 0;) {
if (x
->rn_bmask
& v
[x
->rn_off
])
static char search_bits
[] = {0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};
rn_search_unmapped(v_arg
, head
)
struct radix_node_head
*head
;
register struct radix_node
*x
= head
->rnh_treetop
;
for (v
= v_arg
; x
->rn_b
>= 0;) {
index
= x
->rn_b
+ head
->rnh_offset
;
if (search_bits
[index
& 7] & v
[index
>> 3])
* This routine is used elsewhere in the kernel concerning
* best matches for interfaces and is no longer used in the
register caddr_t m
= m_arg
, n
= n_arg
;
register caddr_t lim
, lim2
= lim
= n
+ *(u_char
*)n
;
int longer
= (*(u_char
*)n
++) - (int)(*(u_char
*)m
++);
if (masks_are_equal
&& (longer
< 0))
for (lim2
= m
- longer
; m
< lim2
; )
return (!masks_are_equal
);
static int low_bits
[] = {1, 3, 7, 15, 31, 63, 127, 255};
static int mask_bits
[] = {1, 2, 4, 8, 16, 32, 64, 128};
rn_lookup(v_arg
, m_arg
, head
)
struct radix_node_head
*head
;
register struct radix_node
*x
;
#define x1(a,n) ( a > ((1 << (n + 1)) - 1) ? n+1 : n)
#define x2(a,n) (( a > ((1 << (2 + n)) - 1)) ? x1(a,n+2) : x1(a,n))
#define x4(a,n) (( a > ((1 << (4 + n)) - 1)) ? x2(a,n+4) : x2(a,n))
#define x8(a,n) (( a > ((1 << (8 + n)) - 1)) ? x4(a,n+8) : x4(a,n))
#define x16(a,n) ((a > (((1 << n) - 1)+(65535 << n))) ? x8(a,n+16) : x8(a,n))
if ((x
= rn_addmask(m_arg
, 1, head
->rnh_treetop
->rn_off
)) == 0)
x
= rn_match(v_arg
, head
);
while (x
&& x
->rn_mask
!= netmask
)
rn_satsifies_leaf(trial
, leaf
, skip
)
register struct radix_node
*leaf
;
register char *cp
= trial
, *cp2
= leaf
->rn_key
, *cp3
= leaf
->rn_mask
;
int length
= min(*(u_char
*)cp
, *(u_char
*)cp2
);
length
= min(length
, *(u_char
*)cp3
);
cplim
= cp
+ length
; cp3
+= skip
; cp2
+= skip
;
for (cp
+= skip
; cp
< cplim
; cp
++, cp2
++, cp3
++)
rn_mapped_bits_matched(t_a
, r_a
, rnh
, masklen
)
void *t_a
; /* Under scrutiny, assumed mapped */
void *r_a
; /* being compared to, not mapped */
struct radix_node_head
*rnh
; /* has offset for ref, map for trial */
int masklen
; /* only need this many bits to match*/
register struct radix_index_table
*table
= rnh
->rnh_table
;
u_char
*trial
= t_a
; /* Under scrutiny, assumed mapped */
u_char
*ref
= r_a
; /* being compared to, not mapped */
#ifdef utterly_straightforward_way_of_doing_this
for (; table
->limit
; table
++) {
for (; matched
< table
->limit
; matched
++) {
if (matched
>= masklen
- 1)
k
= matched
+ table
->offset
;
l
= matched
+ rnh
->rnh_offset
;
/* is bit l of ref == bit k of trial */
if (((ref
[l
>> 3] >> (7 - (l
& 7))) ^
(trial
[k
>> 3] >> (7 - (k
& 7)))) & 1)
int test_info
, trial_bits
, ref_bits
, limit
, sum_bits
, delta
;
for (; table
->limit
; table
++) {
limit
= MIN(masklen
, table
->limit
);
while (matched
< limit
) {
k
= matched
+ table
->offset
;
l
= matched
+ rnh
->rnh_offset
;
trial_bits
= 7 - (k
& 7);
delta
= MIN(MIN(trial_bits
, ref_bits
), limit
- matched
);
sum_bits
= trial_bits
+ ref_bits
;
test_info
= ((int)ref
[k
>> 3]) << ref_bits
;
test_info
^= ((int)trial
[l
>> 3]) << trial_bits
;
test_info
&= low_bits
[sum_bits
];
test_info
&= ~low_bits
[sum_bits
- delta
];
int count
, mask
= mask_bits
[sum_bits
];
for (count
= delta
; count
>= 0; count
--) {
printf("Bits_matched: should never get here!");
#if defined(IPPROTO_IP) && defined(IPVERSION) /* #include <netinet/i{n,p}.h>" */
int ip_mapped_bits_matched
(void *t_a
, void *r_a
, struct radix_node_head
*rnh
, int masklen
)
struct sockaddr_in
*ref
= r_a
;
u_long bits
= trial
->sin_addr
.s_addr
^ ip
->ip_dst
.s_adddr
;
if (bits
== 0) return (32); /* expected case !*/
rn_mapped_set_mask(index
, rn
, rnh
)
register struct radix_node
*rn
;
register struct radix_node_head
*rnh
;
register struct radix_index_table
*table
;
for (table
= rnh
->rnh_table
; table
->limit
&& index
< table
->limit
;)
rn
->rn_bmask
= mask_bits
[7 - (index
& 7)];
rn
->rn_off
= (index
>> 3);
rn_unmapped_bits_matched(t_a
, r_a
, rnh
, masklen
)
void *t_a
; /* Under scrutiny, assumed mapped */
void *r_a
; /* being compared to, not mapped */
struct radix_node_head
*rnh
; /* has offset for ref, map for trial */
int masklen
; /* only need this many bits to match*/
register u_char
*cp1
, *cp2
, *limit
;
int offset
= rnh
->rnh_offset
>> 3;/* XXX: off must be n * 8 */
u_char
*trial
= t_a
; /* Under scrutiny, assumed mapped */
u_char
*ref
= r_a
; /* being compared to, not mapped */
limit
= cp1
+ ((masklen
+ 7) >> 3);
for (cp2
= ref
+ offset
; cp1
< limit
;)
test_info
= cp1
[-1] ^ cp2
[-1];
matched
= (cp1
- trial
- offset
) << 3;
for (; test_info
; matched
--)
rn_unmapped_set_mask(index
, rn
, rnh
)
register struct radix_node
*rn
;
register struct radix_node_head
*rnh
;
index
+= rnh
->rnh_offset
;
rn
->rn_bmask
= mask_bits
[7 - (index
& 7)];
rn
->rn_off
= (index
>> 3);
struct radix_node_head
*head
;
register char *cp
= (char *)(v_arg
);
register struct radix_node
*m
, *t
= head
->rnh_treetop
;
struct radix_node
*saved_t
, *top
= t
;
* Open code rn_search(v, top) to avoid overhead of extra
if (t
->rn_bmask
& cp
[t
->rn_off
])
bits_matched
= (*head
->rnh_bits_matched
)
(v_arg
, t
->rn_key
, head
, -1 - t
->rn_b
);
rn_b
= -1 - bits_matched
; /* XXX: compatability */
* Check this node, and any other duped keys.
* We want to match the most specific possible mask, so
* duplicates are sorted longest mask to shortest.
vlen
= *(u_char
*)t
->rn_mask
;
for (saved_t
= t
; t
; t
= t
->rn_dupedkey
)
/* if (bits_matched >= mask_index) */
* This extra grot is in case we are explicitly asked
* to look up the default. Ugh!
if ((t
->rn_flags
& RNF_ROOT
) && t
->rn_dupedkey
)
/* start searching up the tree */
for (m
= t
->rn_mklist
; m
; m
= m
->rn_mklist
)
/* if (bits_matched >= mask_index) */
struct radix_node
*rn_clist
;
rn_newpair1(v
, b
, nodes
, rnh
)
struct radix_node nodes
[2];
struct radix_node_head
*rnh
;
register struct radix_node
*tt
= nodes
, *t
= tt
+ 1;
t
->rn_b
= b
; t
->rn_l
= tt
;
(*rnh
->rnh_set_mask
)(b
, t
, rnh
);
tt
->rn_b
= -1; tt
->rn_key
= (caddr_t
)v
; tt
->rn_p
= t
;
tt
->rn_flags
= t
->rn_flags
= RNF_ACTIVE
;
tt
->rn_info
= rn_nodenum
++; t
->rn_info
= rn_nodenum
++;
tt
->rn_twin
= t
; tt
->rn_ybro
= rn_clist
; rn_clist
= tt
;
#define DEFAULT(a, b) (a > 0 ? a : b)
#define VLEN(v, h) ((DEFAULT(h->rnh_addrsize, *(u_char *)v) << 3) - h->rnh_offset)
rn_insert(v_arg
, head
, dupentry
, nodes
)
register struct radix_node_head
*head
;
struct radix_node nodes
[2];
caddr_t v
= (caddr_t
)v_arg
, cp
= (head
->rnh_offset
>> 3) + v
;
register struct radix_node
*t
= rn_search_unmapped(v
, head
);
register struct radix_node
*p
, *x
;
int b
, vlen
= VLEN(v
, head
);
* Find first bit at which v and t->rn_key differ
b
= rn_unmapped_bits_matched(v
, t
->rn_key
, head
, vlen
);
* Find appropriate node after which to insert new key
log(LOG_DEBUG
, "rn_insert: Going In:\n"), traverse(p
);
t
= rn_newpair1(v
, b
, nodes
, head
);
* If we went to the left during the matching process,
* the spliced-in node will still be on the left.
* If the first bit of the input string that didn't match
* was set, put the new leaf to the right of the new node.
if (cp
[b
>> 3] & search_bits
[b
& 7]) {
t
->rn_r
= nodes
; t
->rn_l
= x
;
log(LOG_DEBUG
, "rn_insert: Coming Out:\n"), traverse(p
);
* Here mostly for compatability's sake with
* the previous networking code, which expects to find masks.
rn_masksubr(n_arg
, v_arg
, skip
, head
, len_p
)
struct radix_node_head
*head
;
caddr_t netmask
= (caddr_t
)n_arg
, v
= v_arg
;
register struct radix_node
*x
= rn_masktop
;
register caddr_t cp
, cplim
;
register int b
= 0, mlen
, j
;
int maskduplicated
, m0
, isnormal
;
struct radix_node
*saved_x
;
static int last_zeroed
= 0;
struct radix_node
*saved_x
;
Bzero(addmask_key
+ m0
, last_zeroed
- m0
);
*addmask_key
= last_zeroed
= mlen
;
x
= rn_search(addmask_key
, rn_masktop
);
if (Bcmp(addmask_key
, x
->rn_key
, mlen
) != 0)
for (j
= skip
<< 3; j
> ((unsigned)x
->rn_b
);)
x
= rn_search(netmask
, x
);
mlen
= *(u_char
*)netmask
;
Bcmp(netmask
+ skip
, x
->rn_key
+ skip
, mlen
- skip
) == 0)
R_Malloc(x
, struct radix_node
*, max_keylen
+ 2 * sizeof (*x
));
Bzero(x
, max_keylen
+ 2 * sizeof (*x
));
Bcopy(rn_ones
, cp
+ 1, skip
- 1);
x
= rn_insert(cp
, mask_rnhead
, &maskduplicated
, x
);
mlen
= rn_unmapped_bits_matched(cp
, rn_ones
, head
, mlen
<< 3);
printf("rn_addmask1: impossible dup");
b
+= (cp
- netmask
) << 3;
*len_p
= (-1 - x
->rn_b
) - head
->rnh_offset
;
static int /* XXX: arbitrary ordering for non-contiguous masks */
rn_lexobetter(m_arg
, n_arg
)
register u_char
*mp
= m_arg
, *np
= n_arg
, *lim
;
return 1; /* not really, but need to check longer one first */
for (lim
= mp
+ *mp
; mp
< lim
;)
static struct radix_mask
*
rn_new_radix_mask(tt
, next
)
register struct radix_node
*tt
;
register struct radix_mask
*next
;
register struct radix_mask
*m
;
log(LOG_ERR
, "Mask for route not entered\n");
m
->rm_flags
= tt
->rn_flags
;
if (tt
->rn_flags
& RNF_NORMAL
)
m
->rm_mask
= tt
->rn_mask
;
rn_addroute(v_arg
, n_arg
, head
, treenodes
)
struct radix_node_head
*head
;
struct radix_node treenodes
[2];
caddr_t v
= (caddr_t
)v_arg
, netmask
= (caddr_t
)n_arg
;
register struct radix_node
*m
, *us
= treenodes
;
struct radix_node
*t
, *tt
, *x
, *base
, *top
= head
->rnh_treetop
;
struct radix_node
*s
/*sibling*/, *p
/*parent*/, **mp
;
int masklen
, masklen_leaf
, mlen
, keyduplicated
= 0;
* This version assumes contiguous masks and only cares about
* the index of the mask, if present.
(void) rn_masksubr(v_arg
, n_arg
, (head
->rnh_offset
>> 3), head
, &masklen
);
masklen_leaf
= -1 - masklen
;
base
= tt
= rn_insert(v
, head
, &keyduplicated
, treenodes
);
* Deal with duplicated keys: attach node to previous instance
* We sort the nodes so that the longest mask comes first.
* Examine each node and continue past any where the
* mask length is greater than the new one;
* since we are storing -1 - masklength, the sense
* of the test is reversed.
for (; tt
&& (tt
->rn_b
<= masklen_leaf
);
x
= tt
, tt
= tt
->rn_dupedkey
)
if (tt
->rn_mask
== netmask
)
return (0); /* mask is also duplicated */
/* link in at head of list */
p
->rn_l
= us
; else p
->rn_r
= us
;
us
->rn_dupedkey
= x
->rn_dupedkey
;
t
=tt
+1; tt
->rn_info
= rn_nodenum
++; t
->rn_info
= rn_nodenum
++;
tt
->rn_twin
= t
; tt
->rn_ybro
= rn_clist
; rn_clist
= tt
;
us
->rn_key
= (caddr_t
) v
;
us
->rn_flags
= RNF_ACTIVE
;
* Annotate tree about masks.
if (*mp
= m
= rn_new_radix_mask(x
, 0))
} else if (s
->rn_mklist
) {
* Skip over masks whose index is > that of new node
for (mp
= &(s
->rn_mklist
); m
= *mp
; mp
= &m
->rn_mklist
)
p
->rn_mklist
= m
; *mp
= 0;
/* Add new route to highest possible ancestor's list */
if ((netmask
== 0) || (masklen
> p
->rn_b
))
return us
; /* can't lift at all */
} while (masklen
<= t
->rn_b
&& x
!= top
);
* Search through routes associated with node to
* insert new route according to index.
* Need same criteria as when sorting dupedkeys to avoid
* double loop on deletion.
for (mp
= &x
->rn_mklist
; m
= *mp
; mp
= &m
->rn_mklist
) {
if (m
->rn_b
> masklen_leaf
)
if (m
->rn_b
< masklen_leaf
)
if (m
->rn_b
== masklen_leaf
) {
printf("rn_addroute: impossible duplicate mask\n");
rn_delete(v_arg
, n_arg
, head
)
struct radix_node_head
*head
;
register struct radix_node
*t
, *p
, *x
, *tt
;
struct radix_node
*m
, *saved_m
, **mp
;
struct radix_node
*dupedkey
, *base
, *top
= head
->rnh_treetop
;
int b
, head_off
= head
->rnh_offset
>> 3, masklen
, masklen_leaf
;
int vlen
= VLEN(v_arg
, head
) >> 3;
base
= tt
= rn_search_unmapped(v_arg
, head
);
if (tt
== 0 || Bcmp(v
+ head_off
, tt
->rn_key
+ head_off
, vlen
))
(void) rn_masksubr(v_arg
, n_arg
, head_off
, head
, &masklen
);
masklen_leaf
= -1 - masklen
;
while (tt
->rn_b
!= masklen_leaf
)
if ((tt
= tt
->rn_dupedkey
) == 0)
* Delete our route from mask lists.
if (tt
->rn_mask
== 0 || masklen
> t
->rn_b
)
goto on1
; /* Wasn't lifted at all */
} while (masklen
<= p
->rn_b
&& x
!= top
);
for (mp
= &x
->rn_mklist
; m
= *mp
; mp
= &m
->rn_mklist
)
log(LOG_ERR
, "rn_delete: couldn't find our annotation\n");
if (tt
->rn_flags
& RNF_NORMAL
)
return (0); /* Dangling ref to us */
if (tt
->rn_flags
& RNF_ROOT
)
/* Get us out of the creation list */
for (t
= rn_clist
; t
&& t
->rn_ybro
!= tt
; t
= t
->rn_ybro
) {}
if (t
) t
->rn_ybro
= tt
->rn_ybro
;
if (dupedkey
= saved_tt
->rn_dupedkey
) {
x
= dupedkey
; x
->rn_p
= t
;
if (t
->rn_l
== tt
) t
->rn_l
= x
; else t
->rn_r
= x
;
for (x
= base
; x
&& x
->rn_dupedkey
!= tt
;)
if (x
) x
->rn_dupedkey
= tt
->rn_dupedkey
;
else log(LOG_ERR
, "rn_delete: couldn't find us\n");
if (x
->rn_flags
& RNF_ACTIVE
) {
/* Find inactive node to clober among this chain. */
for (t
= base
; t
; t
= x
->rn_dupedkey
)
if ((t
[1].rn_flags
& RNF_ACTIVE
) == 0)
printf("rn_delete: lost inactive node");
if (t
->rn_l
== tt
) x
= t
->rn_r
; else x
= t
->rn_l
;
if (p
->rn_r
== t
) p
->rn_r
= x
; else p
->rn_l
= x
;
* Demote routes attached to us.
for (mp
= &x
->rn_mklist
; m
= *mp
;)
* We may be holding an active internal node in the tree.
b
= t
->rn_info
; *t
= *x
; t
->rn_info
= b
;
t
->rn_l
->rn_p
= t
; t
->rn_r
->rn_p
= t
;
if (p
->rn_l
== x
) p
->rn_l
= t
; else p
->rn_r
= t
;
tt
->rn_flags
&= ~RNF_ACTIVE
;
tt
[1].rn_flags
&= ~RNF_ACTIVE
;
struct radix_node_head
*h
;
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
* the successor node in advance.
/* First time through node, go left */
/* If at right child go back up, otherwise, go right */
while (rn
->rn_p
->rn_r
== rn
&& (rn
->rn_flags
& RNF_ROOT
) == 0)
/* Find the next *leaf* since next node might vanish, too */
for (rn
= rn
->rn_p
->rn_r
; rn
->rn_b
>= 0;)
if (!(rn
->rn_flags
& RNF_ROOT
) && (error
= (*f
)(rn
, w
)))
if (rn
->rn_flags
& RNF_ROOT
)
register struct radix_node_head
*rnh
;
register struct radix_node
*t
, *tt
, *ttt
;
R_Malloc(rnh
, struct radix_node_head
*, sizeof (*rnh
));
Bzero(rnh
, sizeof (*rnh
));
t
= rn_newpair1(rn_zeros
, 0, rnh
->rnh_nodes
, rnh
);
ttt
= rnh
->rnh_nodes
+ 2;
tt
->rn_flags
= t
->rn_flags
= RNF_ROOT
| RNF_ACTIVE
;
rnh
->rnh_addaddr
= rn_addroute
;
rnh
->rnh_deladdr
= rn_delete
;
rnh
->rnh_matchaddr
= rn_match
;
rnh
->rnh_lookup
= rn_lookup
;
rnh
->rnh_walktree
= rn_walktree
;
rnh
->rnh_bits_matched
= rn_unmapped_bits_matched
;
rnh
->rnh_set_mask
= rn_unmapped_set_mask
;
for (dom
= domains
; dom
; dom
= dom
->dom_next
)
if (dom
->dom_maxrtkey
> max_keylen
)
max_keylen
= dom
->dom_maxrtkey
;
"rn_init: radix functions require max_keylen be set\n");
R_Malloc(rn_zeros
, char *, 3 * max_keylen
);
Bzero(rn_zeros
, 2 * max_keylen
);
rn_ones
= cp
= rn_zeros
+ max_keylen
;
if (rn_inithead((void **)&mask_rnhead
, 0) == 0)