1c398230bSWarner Losh /*-
251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni *
4df8bae1dSRodney W. Grimes * Copyright (c) 1988, 1989, 1993
5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved.
6df8bae1dSRodney W. Grimes *
7df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without
8df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions
9df8bae1dSRodney W. Grimes * are met:
10df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer.
12df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
14df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
16df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software
17df8bae1dSRodney W. Grimes * without specific prior written permission.
18df8bae1dSRodney W. Grimes *
19df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29df8bae1dSRodney W. Grimes * SUCH DAMAGE.
30df8bae1dSRodney W. Grimes */
31df8bae1dSRodney W. Grimes
32df8bae1dSRodney W. Grimes /*
33df8bae1dSRodney W. Grimes * Routines to build and maintain radix trees for routing lookups.
34df8bae1dSRodney W. Grimes */
35df8bae1dSRodney W. Grimes #include <sys/param.h>
36664a31e4SPeter Wemm #ifdef _KERNEL
378480e03dSJeffrey Hsu #include <sys/lock.h>
388480e03dSJeffrey Hsu #include <sys/mutex.h>
3920efcfc6SAndrey V. Elsukov #include <sys/rmlock.h>
40df8bae1dSRodney W. Grimes #include <sys/systm.h>
41df8bae1dSRodney W. Grimes #include <sys/malloc.h>
422f688f82SPaul Traina #include <sys/syslog.h>
43df8bae1dSRodney W. Grimes #include <net/radix.h>
44a50f6188SLuigi Rizzo #else /* !_KERNEL */
45a50f6188SLuigi Rizzo #include <stdio.h>
46a50f6188SLuigi Rizzo #include <strings.h>
47a50f6188SLuigi Rizzo #include <stdlib.h>
48a50f6188SLuigi Rizzo #define log(x, arg...) fprintf(stderr, ## arg)
49a50f6188SLuigi Rizzo #define panic(x) fprintf(stderr, "PANIC: %s", x), exit(1)
50a50f6188SLuigi Rizzo #define min(a, b) ((a) < (b) ? (a) : (b) )
51a50f6188SLuigi Rizzo #include <net/radix.h>
52a50f6188SLuigi Rizzo #endif /* !_KERNEL */
53e440aed9SQing Li
54f708ef1bSPoul-Henning Kamp static struct radix_node
5561eee0e2SAlexander V. Chernikov *rn_insert(void *, struct radix_head *, int *,
56929ddbbbSAlfred Perlstein struct radix_node [2]),
57929ddbbbSAlfred Perlstein *rn_newpair(void *, int, struct radix_node[2]),
58*97ffaff8SAlexander V. Chernikov *rn_search(const void *, struct radix_node *),
59*97ffaff8SAlexander V. Chernikov *rn_search_m(const void *, struct radix_node *, void *);
60*97ffaff8SAlexander V. Chernikov static struct radix_node *rn_addmask(const void *, struct radix_mask_head *, int,int);
61ce7609a4SBruce Evans
6261eee0e2SAlexander V. Chernikov static void rn_detachhead_internal(struct radix_head *);
63df8bae1dSRodney W. Grimes
6465a17d74SAlexander V. Chernikov #define RADIX_MAX_KEY_LEN 32
65485b4cbaSLuigi Rizzo
6665a17d74SAlexander V. Chernikov static char rn_zeros[RADIX_MAX_KEY_LEN];
6765a17d74SAlexander V. Chernikov static char rn_ones[RADIX_MAX_KEY_LEN] = {
6865a17d74SAlexander V. Chernikov -1, -1, -1, -1, -1, -1, -1, -1,
6965a17d74SAlexander V. Chernikov -1, -1, -1, -1, -1, -1, -1, -1,
7065a17d74SAlexander V. Chernikov -1, -1, -1, -1, -1, -1, -1, -1,
7165a17d74SAlexander V. Chernikov -1, -1, -1, -1, -1, -1, -1, -1,
7265a17d74SAlexander V. Chernikov };
73485b4cbaSLuigi Rizzo
74*97ffaff8SAlexander V. Chernikov static int rn_lexobetter(const void *m_arg, const void *n_arg);
75ce7609a4SBruce Evans static struct radix_mask *
76929ddbbbSAlfred Perlstein rn_new_radix_mask(struct radix_node *tt,
77929ddbbbSAlfred Perlstein struct radix_mask *next);
78*97ffaff8SAlexander V. Chernikov static int rn_satisfies_leaf(const char *trial, struct radix_node *leaf,
79929ddbbbSAlfred Perlstein int skip);
80ce7609a4SBruce Evans
81df8bae1dSRodney W. Grimes /*
82df8bae1dSRodney W. Grimes * The data structure for the keys is a radix tree with one way
831a11e63eSGarrett Wollman * branching removed. The index rn_bit at an internal node n represents a bit
84df8bae1dSRodney W. Grimes * position to be tested. The tree is arranged so that all descendants
851a11e63eSGarrett Wollman * of a node n have keys whose bits all agree up to position rn_bit - 1.
861a11e63eSGarrett Wollman * (We say the index of n is rn_bit.)
87df8bae1dSRodney W. Grimes *
881a11e63eSGarrett Wollman * There is at least one descendant which has a one bit at position rn_bit,
89df8bae1dSRodney W. Grimes * and at least one with a zero there.
90df8bae1dSRodney W. Grimes *
91df8bae1dSRodney W. Grimes * A route is determined by a pair of key and mask. We require that the
92df8bae1dSRodney W. Grimes * bit-wise logical and of the key and mask to be the key.
93df8bae1dSRodney W. Grimes * We define the index of a route to associated with the mask to be
94df8bae1dSRodney W. Grimes * the first bit number in the mask where 0 occurs (with bit number 0
95df8bae1dSRodney W. Grimes * representing the highest order bit).
96df8bae1dSRodney W. Grimes *
97df8bae1dSRodney W. Grimes * We say a mask is normal if every bit is 0, past the index of the mask.
981a11e63eSGarrett Wollman * If a node n has a descendant (k, m) with index(m) == index(n) == rn_bit,
99df8bae1dSRodney W. Grimes * and m is a normal mask, then the route applies to every descendant of n.
1001a11e63eSGarrett Wollman * If the index(m) < rn_bit, this implies the trailing last few bits of k
101df8bae1dSRodney W. Grimes * before bit b are all 0, (and hence consequently true of every descendant
102df8bae1dSRodney W. Grimes * of n), so the route applies to all descendants of the node as well.
103df8bae1dSRodney W. Grimes *
1042f688f82SPaul Traina * Similar logic shows that a non-normal mask m such that
105df8bae1dSRodney W. Grimes * index(m) <= index(n) could potentially apply to many children of n.
106df8bae1dSRodney W. Grimes * Thus, for each non-host route, we attach its mask to a list at an internal
107df8bae1dSRodney W. Grimes * node as high in the tree as we can go.
1082f688f82SPaul Traina *
1092f688f82SPaul Traina * The present version of the code makes use of normal routes in short-
1102f688f82SPaul Traina * circuiting an explict mask and compare operation when testing whether
1112f688f82SPaul Traina * a key satisfies a normal route, and also in remembering the unique leaf
1122f688f82SPaul Traina * that governs a subtree.
113df8bae1dSRodney W. Grimes */
114df8bae1dSRodney W. Grimes
11504f05de9SLuigi Rizzo /*
11604f05de9SLuigi Rizzo * Most of the functions in this code assume that the key/mask arguments
11704f05de9SLuigi Rizzo * are sockaddr-like structures, where the first byte is an u_char
11804f05de9SLuigi Rizzo * indicating the size of the entire structure.
11904f05de9SLuigi Rizzo *
12004f05de9SLuigi Rizzo * To make the assumption more explicit, we use the LEN() macro to access
12104f05de9SLuigi Rizzo * this field. It is safe to pass an expression with side effects
12204f05de9SLuigi Rizzo * to LEN() as the argument is evaluated only once.
12322efc80fSLuigi Rizzo * We cast the result to int as this is the dominant usage.
12404f05de9SLuigi Rizzo */
12522efc80fSLuigi Rizzo #define LEN(x) ( (int) (*(const u_char *)(x)) )
12604f05de9SLuigi Rizzo
12704f05de9SLuigi Rizzo /*
12804f05de9SLuigi Rizzo * XXX THIS NEEDS TO BE FIXED
12904f05de9SLuigi Rizzo * In the code, pointers to keys and masks are passed as either
13004f05de9SLuigi Rizzo * 'void *' (because callers use to pass pointers of various kinds), or
13104f05de9SLuigi Rizzo * 'caddr_t' (which is fine for pointer arithmetics, but not very
13204f05de9SLuigi Rizzo * clean when you dereference it to access data). Furthermore, caddr_t
13304f05de9SLuigi Rizzo * is really 'char *', while the natural type to operate on keys and
13404f05de9SLuigi Rizzo * masks would be 'u_char'. This mismatch require a lot of casts and
13504f05de9SLuigi Rizzo * intermediate variables to adapt types that clutter the code.
13604f05de9SLuigi Rizzo */
13704f05de9SLuigi Rizzo
13804f05de9SLuigi Rizzo /*
13904f05de9SLuigi Rizzo * Search a node in the tree matching the key.
14004f05de9SLuigi Rizzo */
141f708ef1bSPoul-Henning Kamp static struct radix_node *
rn_search(const void * v_arg,struct radix_node * head)142*97ffaff8SAlexander V. Chernikov rn_search(const void *v_arg, struct radix_node *head)
143df8bae1dSRodney W. Grimes {
144868f984cSAlexander V. Chernikov struct radix_node *x;
145*97ffaff8SAlexander V. Chernikov c_caddr_t v;
146df8bae1dSRodney W. Grimes
1471a11e63eSGarrett Wollman for (x = head, v = v_arg; x->rn_bit >= 0;) {
1481a11e63eSGarrett Wollman if (x->rn_bmask & v[x->rn_offset])
1491a11e63eSGarrett Wollman x = x->rn_right;
150df8bae1dSRodney W. Grimes else
1511a11e63eSGarrett Wollman x = x->rn_left;
152df8bae1dSRodney W. Grimes }
153df8bae1dSRodney W. Grimes return (x);
154a0f1e323SBruce Evans }
155df8bae1dSRodney W. Grimes
15604f05de9SLuigi Rizzo /*
15704f05de9SLuigi Rizzo * Same as above, but with an additional mask.
15804f05de9SLuigi Rizzo * XXX note this function is used only once.
15904f05de9SLuigi Rizzo */
160f708ef1bSPoul-Henning Kamp static struct radix_node *
rn_search_m(const void * v_arg,struct radix_node * head,void * m_arg)161*97ffaff8SAlexander V. Chernikov rn_search_m(const void *v_arg, struct radix_node *head, void *m_arg)
162df8bae1dSRodney W. Grimes {
163868f984cSAlexander V. Chernikov struct radix_node *x;
164*97ffaff8SAlexander V. Chernikov c_caddr_t v = v_arg, m = m_arg;
165df8bae1dSRodney W. Grimes
1661a11e63eSGarrett Wollman for (x = head; x->rn_bit >= 0;) {
1671a11e63eSGarrett Wollman if ((x->rn_bmask & m[x->rn_offset]) &&
1681a11e63eSGarrett Wollman (x->rn_bmask & v[x->rn_offset]))
1691a11e63eSGarrett Wollman x = x->rn_right;
170df8bae1dSRodney W. Grimes else
1711a11e63eSGarrett Wollman x = x->rn_left;
172df8bae1dSRodney W. Grimes }
173868f984cSAlexander V. Chernikov return (x);
174a0f1e323SBruce Evans }
175df8bae1dSRodney W. Grimes
176df8bae1dSRodney W. Grimes int
rn_refines(const void * m_arg,const void * n_arg)177*97ffaff8SAlexander V. Chernikov rn_refines(const void *m_arg, const void *n_arg)
178df8bae1dSRodney W. Grimes {
179*97ffaff8SAlexander V. Chernikov c_caddr_t m = m_arg, n = n_arg;
180*97ffaff8SAlexander V. Chernikov c_caddr_t lim, lim2 = lim = n + LEN(n);
18122efc80fSLuigi Rizzo int longer = LEN(n++) - LEN(m++);
182df8bae1dSRodney W. Grimes int masks_are_equal = 1;
183df8bae1dSRodney W. Grimes
184df8bae1dSRodney W. Grimes if (longer > 0)
185df8bae1dSRodney W. Grimes lim -= longer;
186df8bae1dSRodney W. Grimes while (n < lim) {
187df8bae1dSRodney W. Grimes if (*n & ~(*m))
188868f984cSAlexander V. Chernikov return (0);
189df8bae1dSRodney W. Grimes if (*n++ != *m++)
190df8bae1dSRodney W. Grimes masks_are_equal = 0;
191df8bae1dSRodney W. Grimes }
192df8bae1dSRodney W. Grimes while (n < lim2)
193df8bae1dSRodney W. Grimes if (*n++)
194868f984cSAlexander V. Chernikov return (0);
195df8bae1dSRodney W. Grimes if (masks_are_equal && (longer < 0))
196df8bae1dSRodney W. Grimes for (lim2 = m - longer; m < lim2; )
197df8bae1dSRodney W. Grimes if (*m++)
198868f984cSAlexander V. Chernikov return (1);
199df8bae1dSRodney W. Grimes return (!masks_are_equal);
200df8bae1dSRodney W. Grimes }
201df8bae1dSRodney W. Grimes
2025a2f4cbdSAlexander V. Chernikov /*
2035a2f4cbdSAlexander V. Chernikov * Search for exact match in given @head.
2045a2f4cbdSAlexander V. Chernikov * Assume host bits are cleared in @v_arg if @m_arg is not NULL
2055a2f4cbdSAlexander V. Chernikov * Note that prefixes with /32 or /128 masks are treated differently
2065a2f4cbdSAlexander V. Chernikov * from host routes.
2075a2f4cbdSAlexander V. Chernikov */
2082f688f82SPaul Traina struct radix_node *
rn_lookup(const void * v_arg,const void * m_arg,struct radix_head * head)209*97ffaff8SAlexander V. Chernikov rn_lookup(const void *v_arg, const void *m_arg, struct radix_head *head)
2102f688f82SPaul Traina {
211868f984cSAlexander V. Chernikov struct radix_node *x;
2125a2f4cbdSAlexander V. Chernikov caddr_t netmask;
2132f688f82SPaul Traina
2145a2f4cbdSAlexander V. Chernikov if (m_arg != NULL) {
2155a2f4cbdSAlexander V. Chernikov /*
2165a2f4cbdSAlexander V. Chernikov * Most common case: search exact prefix/mask
2175a2f4cbdSAlexander V. Chernikov */
21865a17d74SAlexander V. Chernikov x = rn_addmask(m_arg, head->rnh_masks, 1,
21965a17d74SAlexander V. Chernikov head->rnh_treetop->rn_offset);
2205a2f4cbdSAlexander V. Chernikov if (x == NULL)
2215a2f4cbdSAlexander V. Chernikov return (NULL);
2222f688f82SPaul Traina netmask = x->rn_key;
2235a2f4cbdSAlexander V. Chernikov
2242f688f82SPaul Traina x = rn_match(v_arg, head);
2255a2f4cbdSAlexander V. Chernikov
2265a2f4cbdSAlexander V. Chernikov while (x != NULL && x->rn_mask != netmask)
2272f688f82SPaul Traina x = x->rn_dupedkey;
2285a2f4cbdSAlexander V. Chernikov
2295a2f4cbdSAlexander V. Chernikov return (x);
2302f688f82SPaul Traina }
2315a2f4cbdSAlexander V. Chernikov
2325a2f4cbdSAlexander V. Chernikov /*
2335a2f4cbdSAlexander V. Chernikov * Search for host address.
2345a2f4cbdSAlexander V. Chernikov */
2355a2f4cbdSAlexander V. Chernikov if ((x = rn_match(v_arg, head)) == NULL)
2365a2f4cbdSAlexander V. Chernikov return (NULL);
2375a2f4cbdSAlexander V. Chernikov
2385a2f4cbdSAlexander V. Chernikov /* Check if found key is the same */
2395a2f4cbdSAlexander V. Chernikov if (LEN(x->rn_key) != LEN(v_arg) || bcmp(x->rn_key, v_arg, LEN(v_arg)))
2405a2f4cbdSAlexander V. Chernikov return (NULL);
2415a2f4cbdSAlexander V. Chernikov
2425a2f4cbdSAlexander V. Chernikov /* Check if this is not host route */
2435a2f4cbdSAlexander V. Chernikov if (x->rn_mask != NULL)
2445a2f4cbdSAlexander V. Chernikov return (NULL);
2455a2f4cbdSAlexander V. Chernikov
246868f984cSAlexander V. Chernikov return (x);
2472f688f82SPaul Traina }
2482f688f82SPaul Traina
2492f688f82SPaul Traina static int
rn_satisfies_leaf(const char * trial,struct radix_node * leaf,int skip)250*97ffaff8SAlexander V. Chernikov rn_satisfies_leaf(const char *trial, struct radix_node *leaf, int skip)
2512f688f82SPaul Traina {
252*97ffaff8SAlexander V. Chernikov const char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask;
253*97ffaff8SAlexander V. Chernikov const char *cplim;
25404f05de9SLuigi Rizzo int length = min(LEN(cp), LEN(cp2));
2552f688f82SPaul Traina
25622efc80fSLuigi Rizzo if (cp3 == NULL)
2572f688f82SPaul Traina cp3 = rn_ones;
2582f688f82SPaul Traina else
25922efc80fSLuigi Rizzo length = min(length, LEN(cp3));
2602f688f82SPaul Traina cplim = cp + length; cp3 += skip; cp2 += skip;
2612f688f82SPaul Traina for (cp += skip; cp < cplim; cp++, cp2++, cp3++)
2622f688f82SPaul Traina if ((*cp ^ *cp2) & *cp3)
263868f984cSAlexander V. Chernikov return (0);
264868f984cSAlexander V. Chernikov return (1);
2652f688f82SPaul Traina }
266df8bae1dSRodney W. Grimes
2675a2f4cbdSAlexander V. Chernikov /*
2685a2f4cbdSAlexander V. Chernikov * Search for longest-prefix match in given @head
2695a2f4cbdSAlexander V. Chernikov */
270df8bae1dSRodney W. Grimes struct radix_node *
rn_match(const void * v_arg,struct radix_head * head)271*97ffaff8SAlexander V. Chernikov rn_match(const void *v_arg, struct radix_head *head)
272df8bae1dSRodney W. Grimes {
273*97ffaff8SAlexander V. Chernikov c_caddr_t v = v_arg;
274868f984cSAlexander V. Chernikov struct radix_node *t = head->rnh_treetop, *x;
275*97ffaff8SAlexander V. Chernikov c_caddr_t cp = v, cp2;
276*97ffaff8SAlexander V. Chernikov c_caddr_t cplim;
277df8bae1dSRodney W. Grimes struct radix_node *saved_t, *top = t;
27804f05de9SLuigi Rizzo int off = t->rn_offset, vlen = LEN(cp), matched_off;
279868f984cSAlexander V. Chernikov int test, b, rn_bit;
280df8bae1dSRodney W. Grimes
281df8bae1dSRodney W. Grimes /*
282df8bae1dSRodney W. Grimes * Open code rn_search(v, top) to avoid overhead of extra
283df8bae1dSRodney W. Grimes * subroutine call.
284df8bae1dSRodney W. Grimes */
2851a11e63eSGarrett Wollman for (; t->rn_bit >= 0; ) {
2861a11e63eSGarrett Wollman if (t->rn_bmask & cp[t->rn_offset])
2871a11e63eSGarrett Wollman t = t->rn_right;
288df8bae1dSRodney W. Grimes else
2891a11e63eSGarrett Wollman t = t->rn_left;
290df8bae1dSRodney W. Grimes }
291df8bae1dSRodney W. Grimes /*
292df8bae1dSRodney W. Grimes * See if we match exactly as a host destination
2932f688f82SPaul Traina * or at least learn how many bits match, for normal mask finesse.
2942f688f82SPaul Traina *
2952f688f82SPaul Traina * It doesn't hurt us to limit how many bytes to check
2962f688f82SPaul Traina * to the length of the mask, since if it matches we had a genuine
2972f688f82SPaul Traina * match and the leaf we have is the most specific one anyway;
2982f688f82SPaul Traina * if it didn't match with a shorter length it would fail
2992f688f82SPaul Traina * with a long one. This wins big for class B&C netmasks which
3002f688f82SPaul Traina * are probably the most common case...
301df8bae1dSRodney W. Grimes */
3022f688f82SPaul Traina if (t->rn_mask)
3032f688f82SPaul Traina vlen = *(u_char *)t->rn_mask;
304df8bae1dSRodney W. Grimes cp += off; cp2 = t->rn_key + off; cplim = v + vlen;
305df8bae1dSRodney W. Grimes for (; cp < cplim; cp++, cp2++)
306df8bae1dSRodney W. Grimes if (*cp != *cp2)
307df8bae1dSRodney W. Grimes goto on1;
308df8bae1dSRodney W. Grimes /*
309df8bae1dSRodney W. Grimes * This extra grot is in case we are explicitly asked
310df8bae1dSRodney W. Grimes * to look up the default. Ugh!
311cce2eb6aSPierre Beyssac *
312cce2eb6aSPierre Beyssac * Never return the root node itself, it seems to cause a
313cce2eb6aSPierre Beyssac * lot of confusion.
314df8bae1dSRodney W. Grimes */
315cce2eb6aSPierre Beyssac if (t->rn_flags & RNF_ROOT)
316df8bae1dSRodney W. Grimes t = t->rn_dupedkey;
317868f984cSAlexander V. Chernikov return (t);
318df8bae1dSRodney W. Grimes on1:
3192f688f82SPaul Traina test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */
3202f688f82SPaul Traina for (b = 7; (test >>= 1) > 0;)
3212f688f82SPaul Traina b--;
322df8bae1dSRodney W. Grimes matched_off = cp - v;
3232f688f82SPaul Traina b += matched_off << 3;
3241a11e63eSGarrett Wollman rn_bit = -1 - b;
325df8bae1dSRodney W. Grimes /*
3262f688f82SPaul Traina * If there is a host route in a duped-key chain, it will be first.
3272f688f82SPaul Traina */
3282f688f82SPaul Traina if ((saved_t = t)->rn_mask == 0)
3292f688f82SPaul Traina t = t->rn_dupedkey;
3302f688f82SPaul Traina for (; t; t = t->rn_dupedkey)
3312f688f82SPaul Traina /*
3322f688f82SPaul Traina * Even if we don't match exactly as a host,
333df8bae1dSRodney W. Grimes * we may match if the leaf we wound up at is
334df8bae1dSRodney W. Grimes * a route to a net.
335df8bae1dSRodney W. Grimes */
3362f688f82SPaul Traina if (t->rn_flags & RNF_NORMAL) {
3371a11e63eSGarrett Wollman if (rn_bit <= t->rn_bit)
338868f984cSAlexander V. Chernikov return (t);
339d68189dfSRuslan Ermilov } else if (rn_satisfies_leaf(v, t, matched_off))
340868f984cSAlexander V. Chernikov return (t);
341df8bae1dSRodney W. Grimes t = saved_t;
342df8bae1dSRodney W. Grimes /* start searching up the tree */
343df8bae1dSRodney W. Grimes do {
344868f984cSAlexander V. Chernikov struct radix_mask *m;
3451a11e63eSGarrett Wollman t = t->rn_parent;
346df440948SPoul-Henning Kamp m = t->rn_mklist;
347df8bae1dSRodney W. Grimes /*
3482f688f82SPaul Traina * If non-contiguous masks ever become important
3492f688f82SPaul Traina * we can restore the masking and open coding of
3502f688f82SPaul Traina * the search and satisfaction test and put the
3512f688f82SPaul Traina * calculation of "off" back before the "do".
352df8bae1dSRodney W. Grimes */
3531a11e63eSGarrett Wollman while (m) {
3542f688f82SPaul Traina if (m->rm_flags & RNF_NORMAL) {
3551a11e63eSGarrett Wollman if (rn_bit <= m->rm_bit)
3562f688f82SPaul Traina return (m->rm_leaf);
3572f688f82SPaul Traina } else {
3581a11e63eSGarrett Wollman off = min(t->rn_offset, matched_off);
3592f688f82SPaul Traina x = rn_search_m(v, t, m->rm_mask);
360df8bae1dSRodney W. Grimes while (x && x->rn_mask != m->rm_mask)
361df8bae1dSRodney W. Grimes x = x->rn_dupedkey;
362d68189dfSRuslan Ermilov if (x && rn_satisfies_leaf(v, x, off))
363868f984cSAlexander V. Chernikov return (x);
3642f688f82SPaul Traina }
3652f688f82SPaul Traina m = m->rm_mklist;
366df8bae1dSRodney W. Grimes }
367df8bae1dSRodney W. Grimes } while (t != top);
368868f984cSAlexander V. Chernikov return (0);
369a0f1e323SBruce Evans }
370df8bae1dSRodney W. Grimes
37136e15b71SAlexander V. Chernikov /*
37236e15b71SAlexander V. Chernikov * Returns the next (wider) prefix for the key defined by @rn
37336e15b71SAlexander V. Chernikov * if exists.
37436e15b71SAlexander V. Chernikov */
37536e15b71SAlexander V. Chernikov struct radix_node *
rn_nextprefix(struct radix_node * rn)37636e15b71SAlexander V. Chernikov rn_nextprefix(struct radix_node *rn)
37736e15b71SAlexander V. Chernikov {
37836e15b71SAlexander V. Chernikov for (rn = rn->rn_dupedkey; rn != NULL; rn = rn->rn_dupedkey) {
37936e15b71SAlexander V. Chernikov if (!(rn->rn_flags & RNF_ROOT))
38036e15b71SAlexander V. Chernikov return (rn);
38136e15b71SAlexander V. Chernikov }
38236e15b71SAlexander V. Chernikov return (NULL);
38336e15b71SAlexander V. Chernikov }
38436e15b71SAlexander V. Chernikov
385df8bae1dSRodney W. Grimes #ifdef RN_DEBUG
386df8bae1dSRodney W. Grimes int rn_nodenum;
387df8bae1dSRodney W. Grimes struct radix_node *rn_clist;
388df8bae1dSRodney W. Grimes int rn_saveinfo;
389df8bae1dSRodney W. Grimes int rn_debug = 1;
390df8bae1dSRodney W. Grimes #endif
391df8bae1dSRodney W. Grimes
39204f05de9SLuigi Rizzo /*
39304f05de9SLuigi Rizzo * Whenever we add a new leaf to the tree, we also add a parent node,
39404f05de9SLuigi Rizzo * so we allocate them as an array of two elements: the first one must be
39504f05de9SLuigi Rizzo * the leaf (see RNTORT() in route.c), the second one is the parent.
39604f05de9SLuigi Rizzo * This routine initializes the relevant fields of the nodes, so that
39704f05de9SLuigi Rizzo * the leaf is the left child of the parent node, and both nodes have
39804f05de9SLuigi Rizzo * (almost) all all fields filled as appropriate.
39904f05de9SLuigi Rizzo * (XXX some fields are left unset, see the '#if 0' section).
40004f05de9SLuigi Rizzo * The function returns a pointer to the parent node.
40104f05de9SLuigi Rizzo */
40204f05de9SLuigi Rizzo
403f708ef1bSPoul-Henning Kamp static struct radix_node *
rn_newpair(void * v,int b,struct radix_node nodes[2])404868f984cSAlexander V. Chernikov rn_newpair(void *v, int b, struct radix_node nodes[2])
405df8bae1dSRodney W. Grimes {
406868f984cSAlexander V. Chernikov struct radix_node *tt = nodes, *t = tt + 1;
4071a11e63eSGarrett Wollman t->rn_bit = b;
4081a11e63eSGarrett Wollman t->rn_bmask = 0x80 >> (b & 7);
4091a11e63eSGarrett Wollman t->rn_left = tt;
4101a11e63eSGarrett Wollman t->rn_offset = b >> 3;
41104f05de9SLuigi Rizzo
41204f05de9SLuigi Rizzo #if 0 /* XXX perhaps we should fill these fields as well. */
41304f05de9SLuigi Rizzo t->rn_parent = t->rn_right = NULL;
41404f05de9SLuigi Rizzo
41504f05de9SLuigi Rizzo tt->rn_mask = NULL;
41604f05de9SLuigi Rizzo tt->rn_dupedkey = NULL;
41704f05de9SLuigi Rizzo tt->rn_bmask = 0;
41804f05de9SLuigi Rizzo #endif
4191a11e63eSGarrett Wollman tt->rn_bit = -1;
4201a11e63eSGarrett Wollman tt->rn_key = (caddr_t)v;
4211a11e63eSGarrett Wollman tt->rn_parent = t;
422df8bae1dSRodney W. Grimes tt->rn_flags = t->rn_flags = RNF_ACTIVE;
4239d31ac12SGarrett Wollman tt->rn_mklist = t->rn_mklist = 0;
424df8bae1dSRodney W. Grimes #ifdef RN_DEBUG
425df8bae1dSRodney W. Grimes tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
4261a11e63eSGarrett Wollman tt->rn_twin = t;
4271a11e63eSGarrett Wollman tt->rn_ybro = rn_clist;
4281a11e63eSGarrett Wollman rn_clist = tt;
429df8bae1dSRodney W. Grimes #endif
430868f984cSAlexander V. Chernikov return (t);
431df8bae1dSRodney W. Grimes }
432df8bae1dSRodney W. Grimes
433f708ef1bSPoul-Henning Kamp static struct radix_node *
rn_insert(void * v_arg,struct radix_head * head,int * dupentry,struct radix_node nodes[2])43461eee0e2SAlexander V. Chernikov rn_insert(void *v_arg, struct radix_head *head, int *dupentry,
435868f984cSAlexander V. Chernikov struct radix_node nodes[2])
436df8bae1dSRodney W. Grimes {
437df8bae1dSRodney W. Grimes caddr_t v = v_arg;
438df8bae1dSRodney W. Grimes struct radix_node *top = head->rnh_treetop;
43922efc80fSLuigi Rizzo int head_off = top->rn_offset, vlen = LEN(v);
440868f984cSAlexander V. Chernikov struct radix_node *t = rn_search(v_arg, top);
441868f984cSAlexander V. Chernikov caddr_t cp = v + head_off;
44263dceebeSAlexander V. Chernikov unsigned b;
443868f984cSAlexander V. Chernikov struct radix_node *p, *tt, *x;
444df8bae1dSRodney W. Grimes /*
4452f688f82SPaul Traina * Find first bit at which v and t->rn_key differ
446df8bae1dSRodney W. Grimes */
447868f984cSAlexander V. Chernikov caddr_t cp2 = t->rn_key + head_off;
448868f984cSAlexander V. Chernikov int cmp_res;
449df8bae1dSRodney W. Grimes caddr_t cplim = v + vlen;
450df8bae1dSRodney W. Grimes
451df8bae1dSRodney W. Grimes while (cp < cplim)
452df8bae1dSRodney W. Grimes if (*cp2++ != *cp++)
453df8bae1dSRodney W. Grimes goto on1;
454df8bae1dSRodney W. Grimes *dupentry = 1;
455868f984cSAlexander V. Chernikov return (t);
456df8bae1dSRodney W. Grimes on1:
457df8bae1dSRodney W. Grimes *dupentry = 0;
458df8bae1dSRodney W. Grimes cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
459df8bae1dSRodney W. Grimes for (b = (cp - v) << 3; cmp_res; b--)
460df8bae1dSRodney W. Grimes cmp_res >>= 1;
461868f984cSAlexander V. Chernikov
462868f984cSAlexander V. Chernikov x = top;
463df8bae1dSRodney W. Grimes cp = v;
464df8bae1dSRodney W. Grimes do {
465df8bae1dSRodney W. Grimes p = x;
4661a11e63eSGarrett Wollman if (cp[x->rn_offset] & x->rn_bmask)
4671a11e63eSGarrett Wollman x = x->rn_right;
4681a11e63eSGarrett Wollman else
4691a11e63eSGarrett Wollman x = x->rn_left;
4701a11e63eSGarrett Wollman } while (b > (unsigned) x->rn_bit);
4711a11e63eSGarrett Wollman /* x->rn_bit < b && x->rn_bit >= 0 */
472df8bae1dSRodney W. Grimes #ifdef RN_DEBUG
473df8bae1dSRodney W. Grimes if (rn_debug)
4742f688f82SPaul Traina log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p);
475df8bae1dSRodney W. Grimes #endif
4761a11e63eSGarrett Wollman t = rn_newpair(v_arg, b, nodes);
4771a11e63eSGarrett Wollman tt = t->rn_left;
4781a11e63eSGarrett Wollman if ((cp[p->rn_offset] & p->rn_bmask) == 0)
4791a11e63eSGarrett Wollman p->rn_left = t;
480df8bae1dSRodney W. Grimes else
4811a11e63eSGarrett Wollman p->rn_right = t;
4821a11e63eSGarrett Wollman x->rn_parent = t;
4831a11e63eSGarrett Wollman t->rn_parent = p; /* frees x, p as temp vars below */
4841a11e63eSGarrett Wollman if ((cp[t->rn_offset] & t->rn_bmask) == 0) {
4851a11e63eSGarrett Wollman t->rn_right = x;
486df8bae1dSRodney W. Grimes } else {
4871a11e63eSGarrett Wollman t->rn_right = tt;
4881a11e63eSGarrett Wollman t->rn_left = x;
489df8bae1dSRodney W. Grimes }
490df8bae1dSRodney W. Grimes #ifdef RN_DEBUG
491df8bae1dSRodney W. Grimes if (rn_debug)
4922f688f82SPaul Traina log(LOG_DEBUG, "rn_insert: Coming Out:\n"), traverse(p);
493df8bae1dSRodney W. Grimes #endif
494df8bae1dSRodney W. Grimes return (tt);
495df8bae1dSRodney W. Grimes }
496df8bae1dSRodney W. Grimes
4974a3fc6e2SMitchell Horne static struct radix_node *
rn_addmask(const void * n_arg,struct radix_mask_head * maskhead,int search,int skip)498*97ffaff8SAlexander V. Chernikov rn_addmask(const void *n_arg, struct radix_mask_head *maskhead, int search, int skip)
499df8bae1dSRodney W. Grimes {
500*97ffaff8SAlexander V. Chernikov const unsigned char *netmask = n_arg;
501*97ffaff8SAlexander V. Chernikov const unsigned char *c, *clim;
502*97ffaff8SAlexander V. Chernikov unsigned char *cp;
50378aed5e8SAlexander V. Chernikov struct radix_node *x;
50478aed5e8SAlexander V. Chernikov int b = 0, mlen, j;
50565a17d74SAlexander V. Chernikov int maskduplicated, isnormal;
5062f688f82SPaul Traina struct radix_node *saved_x;
50778aed5e8SAlexander V. Chernikov unsigned char addmask_key[RADIX_MAX_KEY_LEN];
508df8bae1dSRodney W. Grimes
50965a17d74SAlexander V. Chernikov if ((mlen = LEN(netmask)) > RADIX_MAX_KEY_LEN)
51065a17d74SAlexander V. Chernikov mlen = RADIX_MAX_KEY_LEN;
5112f688f82SPaul Traina if (skip == 0)
5122f688f82SPaul Traina skip = 1;
5132f688f82SPaul Traina if (mlen <= skip)
51461eee0e2SAlexander V. Chernikov return (maskhead->mask_nodes);
51565a17d74SAlexander V. Chernikov
51665a17d74SAlexander V. Chernikov bzero(addmask_key, RADIX_MAX_KEY_LEN);
5172f688f82SPaul Traina if (skip > 1)
518485b4cbaSLuigi Rizzo bcopy(rn_ones + 1, addmask_key + 1, skip - 1);
519485b4cbaSLuigi Rizzo bcopy(netmask + skip, addmask_key + skip, mlen - skip);
5202f688f82SPaul Traina /*
5212f688f82SPaul Traina * Trim trailing zeroes.
5222f688f82SPaul Traina */
5232f688f82SPaul Traina for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;)
5242f688f82SPaul Traina cp--;
5252f688f82SPaul Traina mlen = cp - addmask_key;
52665a17d74SAlexander V. Chernikov if (mlen <= skip)
52761eee0e2SAlexander V. Chernikov return (maskhead->mask_nodes);
52865a17d74SAlexander V. Chernikov *addmask_key = mlen;
52961eee0e2SAlexander V. Chernikov x = rn_search(addmask_key, maskhead->head.rnh_treetop);
530485b4cbaSLuigi Rizzo if (bcmp(addmask_key, x->rn_key, mlen) != 0)
531155d72c4SPedro F. Giffuni x = NULL;
5322f688f82SPaul Traina if (x || search)
5332f688f82SPaul Traina return (x);
53465a17d74SAlexander V. Chernikov R_Zalloc(x, struct radix_node *, RADIX_MAX_KEY_LEN + 2 * sizeof (*x));
535155d72c4SPedro F. Giffuni if ((saved_x = x) == NULL)
536df8bae1dSRodney W. Grimes return (0);
53711a5be0fSLuigi Rizzo netmask = cp = (unsigned char *)(x + 2);
538485b4cbaSLuigi Rizzo bcopy(addmask_key, cp, mlen);
53961eee0e2SAlexander V. Chernikov x = rn_insert(cp, &maskhead->head, &maskduplicated, x);
5402f688f82SPaul Traina if (maskduplicated) {
5412f688f82SPaul Traina log(LOG_ERR, "rn_addmask: mask impossibly already in tree");
5428b15f615SLuiz Otavio O Souza R_Free(saved_x);
543df8bae1dSRodney W. Grimes return (x);
544df8bae1dSRodney W. Grimes }
5452f688f82SPaul Traina /*
5462f688f82SPaul Traina * Calculate index of mask, and check for normalcy.
5479aed3aa3SLuigi Rizzo * First find the first byte with a 0 bit, then if there are
5489aed3aa3SLuigi Rizzo * more bits left (remember we already trimmed the trailing 0's),
54978aed5e8SAlexander V. Chernikov * the bits should be contiguous, otherwise we have got
5509aed3aa3SLuigi Rizzo * a non-contiguous mask.
5512f688f82SPaul Traina */
55278aed5e8SAlexander V. Chernikov #define CONTIG(_c) (((~(_c) + 1) & (_c)) == (unsigned char)(~(_c) + 1))
553*97ffaff8SAlexander V. Chernikov clim = netmask + mlen;
5549aed3aa3SLuigi Rizzo isnormal = 1;
555*97ffaff8SAlexander V. Chernikov for (c = netmask + skip; (c < clim) && *(const u_char *)c == 0xff;)
556*97ffaff8SAlexander V. Chernikov c++;
557*97ffaff8SAlexander V. Chernikov if (c != clim) {
558*97ffaff8SAlexander V. Chernikov for (j = 0x80; (j & *c) != 0; j >>= 1)
5592f688f82SPaul Traina b++;
560*97ffaff8SAlexander V. Chernikov if (!CONTIG(*c) || c != (clim - 1))
5612f688f82SPaul Traina isnormal = 0;
5622f688f82SPaul Traina }
563*97ffaff8SAlexander V. Chernikov b += (c - netmask) << 3;
5641a11e63eSGarrett Wollman x->rn_bit = -1 - b;
5652f688f82SPaul Traina if (isnormal)
5662f688f82SPaul Traina x->rn_flags |= RNF_NORMAL;
5672f688f82SPaul Traina return (x);
5682f688f82SPaul Traina }
5692f688f82SPaul Traina
5702f688f82SPaul Traina static int /* XXX: arbitrary ordering for non-contiguous masks */
rn_lexobetter(const void * m_arg,const void * n_arg)571*97ffaff8SAlexander V. Chernikov rn_lexobetter(const void *m_arg, const void *n_arg)
5722f688f82SPaul Traina {
573*97ffaff8SAlexander V. Chernikov const u_char *mp = m_arg, *np = n_arg, *lim;
5742f688f82SPaul Traina
57504f05de9SLuigi Rizzo if (LEN(mp) > LEN(np))
576868f984cSAlexander V. Chernikov return (1); /* not really, but need to check longer one first */
57704f05de9SLuigi Rizzo if (LEN(mp) == LEN(np))
57804f05de9SLuigi Rizzo for (lim = mp + LEN(mp); mp < lim;)
5792f688f82SPaul Traina if (*mp++ > *np++)
580868f984cSAlexander V. Chernikov return (1);
581868f984cSAlexander V. Chernikov return (0);
5822f688f82SPaul Traina }
5832f688f82SPaul Traina
5842f688f82SPaul Traina static struct radix_mask *
rn_new_radix_mask(struct radix_node * tt,struct radix_mask * next)585868f984cSAlexander V. Chernikov rn_new_radix_mask(struct radix_node *tt, struct radix_mask *next)
5862f688f82SPaul Traina {
587868f984cSAlexander V. Chernikov struct radix_mask *m;
5882f688f82SPaul Traina
58965a17d74SAlexander V. Chernikov R_Malloc(m, struct radix_mask *, sizeof (struct radix_mask));
590868f984cSAlexander V. Chernikov if (m == NULL) {
59165a17d74SAlexander V. Chernikov log(LOG_ERR, "Failed to allocate route mask\n");
5922f688f82SPaul Traina return (0);
5932f688f82SPaul Traina }
59465a17d74SAlexander V. Chernikov bzero(m, sizeof(*m));
5951a11e63eSGarrett Wollman m->rm_bit = tt->rn_bit;
5962f688f82SPaul Traina m->rm_flags = tt->rn_flags;
5972f688f82SPaul Traina if (tt->rn_flags & RNF_NORMAL)
5982f688f82SPaul Traina m->rm_leaf = tt;
5992f688f82SPaul Traina else
6002f688f82SPaul Traina m->rm_mask = tt->rn_mask;
6012f688f82SPaul Traina m->rm_mklist = next;
6022f688f82SPaul Traina tt->rn_mklist = m;
603868f984cSAlexander V. Chernikov return (m);
6042f688f82SPaul Traina }
605df8bae1dSRodney W. Grimes
606df8bae1dSRodney W. Grimes struct radix_node *
rn_addroute(void * v_arg,const void * n_arg,struct radix_head * head,struct radix_node treenodes[2])607*97ffaff8SAlexander V. Chernikov rn_addroute(void *v_arg, const void *n_arg, struct radix_head *head,
608868f984cSAlexander V. Chernikov struct radix_node treenodes[2])
609df8bae1dSRodney W. Grimes {
610*97ffaff8SAlexander V. Chernikov caddr_t v = (caddr_t)v_arg, netmask = NULL;
611155d72c4SPedro F. Giffuni struct radix_node *t, *x = NULL, *tt;
612df8bae1dSRodney W. Grimes struct radix_node *saved_tt, *top = head->rnh_treetop;
6132f688f82SPaul Traina short b = 0, b_leaf = 0;
6142f688f82SPaul Traina int keyduplicated;
6152f688f82SPaul Traina caddr_t mmask;
616df8bae1dSRodney W. Grimes struct radix_mask *m, **mp;
617df8bae1dSRodney W. Grimes
618df8bae1dSRodney W. Grimes /*
619df8bae1dSRodney W. Grimes * In dealing with non-contiguous masks, there may be
620df8bae1dSRodney W. Grimes * many different routes which have the same mask.
621df8bae1dSRodney W. Grimes * We will find it useful to have a unique pointer to
622df8bae1dSRodney W. Grimes * the mask to speed avoiding duplicate references at
623df8bae1dSRodney W. Grimes * nodes and possibly save time in calculating indices.
624df8bae1dSRodney W. Grimes */
625*97ffaff8SAlexander V. Chernikov if (n_arg) {
626*97ffaff8SAlexander V. Chernikov x = rn_addmask(n_arg, head->rnh_masks, 0, top->rn_offset);
62765a17d74SAlexander V. Chernikov if (x == NULL)
628df8bae1dSRodney W. Grimes return (0);
6291a11e63eSGarrett Wollman b_leaf = x->rn_bit;
6301a11e63eSGarrett Wollman b = -1 - x->rn_bit;
6312f688f82SPaul Traina netmask = x->rn_key;
632df8bae1dSRodney W. Grimes }
633df8bae1dSRodney W. Grimes /*
634df8bae1dSRodney W. Grimes * Deal with duplicated keys: attach node to previous instance
635df8bae1dSRodney W. Grimes */
636df8bae1dSRodney W. Grimes saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
637df8bae1dSRodney W. Grimes if (keyduplicated) {
6382f688f82SPaul Traina for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) {
639df8bae1dSRodney W. Grimes if (tt->rn_mask == netmask)
640df8bae1dSRodney W. Grimes return (0);
641df8bae1dSRodney W. Grimes if (netmask == 0 ||
6422f688f82SPaul Traina (tt->rn_mask &&
6431a11e63eSGarrett Wollman ((b_leaf < tt->rn_bit) /* index(netmask) > node */
6441a11e63eSGarrett Wollman || rn_refines(netmask, tt->rn_mask)
6451a11e63eSGarrett Wollman || rn_lexobetter(netmask, tt->rn_mask))))
646df8bae1dSRodney W. Grimes break;
6472f688f82SPaul Traina }
648df8bae1dSRodney W. Grimes /*
649df8bae1dSRodney W. Grimes * If the mask is not duplicated, we wouldn't
650df8bae1dSRodney W. Grimes * find it among possible duplicate key entries
651df8bae1dSRodney W. Grimes * anyway, so the above test doesn't hurt.
652df8bae1dSRodney W. Grimes *
653df8bae1dSRodney W. Grimes * We sort the masks for a duplicated key the same way as
654df8bae1dSRodney W. Grimes * in a masklist -- most specific to least specific.
655df8bae1dSRodney W. Grimes * This may require the unfortunate nuisance of relocating
656df8bae1dSRodney W. Grimes * the head of the list.
657053e2342SRuslan Ermilov *
658053e2342SRuslan Ermilov * We also reverse, or doubly link the list through the
659053e2342SRuslan Ermilov * parent pointer.
660df8bae1dSRodney W. Grimes */
6612f688f82SPaul Traina if (tt == saved_tt) {
662df8bae1dSRodney W. Grimes struct radix_node *xx = x;
663df8bae1dSRodney W. Grimes /* link in at head of list */
664df8bae1dSRodney W. Grimes (tt = treenodes)->rn_dupedkey = t;
665df8bae1dSRodney W. Grimes tt->rn_flags = t->rn_flags;
6661a11e63eSGarrett Wollman tt->rn_parent = x = t->rn_parent;
6671a11e63eSGarrett Wollman t->rn_parent = tt; /* parent */
6681a11e63eSGarrett Wollman if (x->rn_left == t)
6691a11e63eSGarrett Wollman x->rn_left = tt;
6701a11e63eSGarrett Wollman else
6711a11e63eSGarrett Wollman x->rn_right = tt;
672df8bae1dSRodney W. Grimes saved_tt = tt; x = xx;
673df8bae1dSRodney W. Grimes } else {
674df8bae1dSRodney W. Grimes (tt = treenodes)->rn_dupedkey = t->rn_dupedkey;
675df8bae1dSRodney W. Grimes t->rn_dupedkey = tt;
6761a11e63eSGarrett Wollman tt->rn_parent = t; /* parent */
6772f688f82SPaul Traina if (tt->rn_dupedkey) /* parent */
6781a11e63eSGarrett Wollman tt->rn_dupedkey->rn_parent = tt; /* parent */
679df8bae1dSRodney W. Grimes }
680df8bae1dSRodney W. Grimes #ifdef RN_DEBUG
681df8bae1dSRodney W. Grimes t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
682df8bae1dSRodney W. Grimes tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
683df8bae1dSRodney W. Grimes #endif
684df8bae1dSRodney W. Grimes tt->rn_key = (caddr_t) v;
6851a11e63eSGarrett Wollman tt->rn_bit = -1;
6862f688f82SPaul Traina tt->rn_flags = RNF_ACTIVE;
687df8bae1dSRodney W. Grimes }
688df8bae1dSRodney W. Grimes /*
689df8bae1dSRodney W. Grimes * Put mask in tree.
690df8bae1dSRodney W. Grimes */
691df8bae1dSRodney W. Grimes if (netmask) {
692df8bae1dSRodney W. Grimes tt->rn_mask = netmask;
6931a11e63eSGarrett Wollman tt->rn_bit = x->rn_bit;
6942f688f82SPaul Traina tt->rn_flags |= x->rn_flags & RNF_NORMAL;
695df8bae1dSRodney W. Grimes }
6961a11e63eSGarrett Wollman t = saved_tt->rn_parent;
6972f688f82SPaul Traina if (keyduplicated)
6982f688f82SPaul Traina goto on2;
6991a11e63eSGarrett Wollman b_leaf = -1 - t->rn_bit;
7001a11e63eSGarrett Wollman if (t->rn_right == saved_tt)
7011a11e63eSGarrett Wollman x = t->rn_left;
7021a11e63eSGarrett Wollman else
7031a11e63eSGarrett Wollman x = t->rn_right;
704df8bae1dSRodney W. Grimes /* Promote general routes from below */
7051a11e63eSGarrett Wollman if (x->rn_bit < 0) {
7062f688f82SPaul Traina for (mp = &t->rn_mklist; x; x = x->rn_dupedkey)
7071a11e63eSGarrett Wollman if (x->rn_mask && (x->rn_bit >= b_leaf) && x->rn_mklist == 0) {
7082f688f82SPaul Traina *mp = m = rn_new_radix_mask(x, 0);
7092f688f82SPaul Traina if (m)
7102f688f82SPaul Traina mp = &m->rm_mklist;
711df8bae1dSRodney W. Grimes }
712df8bae1dSRodney W. Grimes } else if (x->rn_mklist) {
713df8bae1dSRodney W. Grimes /*
714df8bae1dSRodney W. Grimes * Skip over masks whose index is > that of new node
715df8bae1dSRodney W. Grimes */
7162f688f82SPaul Traina for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
7171a11e63eSGarrett Wollman if (m->rm_bit >= b_leaf)
718df8bae1dSRodney W. Grimes break;
719155d72c4SPedro F. Giffuni t->rn_mklist = m; *mp = NULL;
720df8bae1dSRodney W. Grimes }
7212f688f82SPaul Traina on2:
722df8bae1dSRodney W. Grimes /* Add new route to highest possible ancestor's list */
7231a11e63eSGarrett Wollman if ((netmask == 0) || (b > t->rn_bit ))
724868f984cSAlexander V. Chernikov return (tt); /* can't lift at all */
7251a11e63eSGarrett Wollman b_leaf = tt->rn_bit;
726df8bae1dSRodney W. Grimes do {
727df8bae1dSRodney W. Grimes x = t;
7281a11e63eSGarrett Wollman t = t->rn_parent;
7291a11e63eSGarrett Wollman } while (b <= t->rn_bit && x != top);
730df8bae1dSRodney W. Grimes /*
731df8bae1dSRodney W. Grimes * Search through routes associated with node to
732df8bae1dSRodney W. Grimes * insert new route according to index.
7332f688f82SPaul Traina * Need same criteria as when sorting dupedkeys to avoid
7342f688f82SPaul Traina * double loop on deletion.
735df8bae1dSRodney W. Grimes */
7362f688f82SPaul Traina for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) {
7371a11e63eSGarrett Wollman if (m->rm_bit < b_leaf)
738df8bae1dSRodney W. Grimes continue;
7391a11e63eSGarrett Wollman if (m->rm_bit > b_leaf)
740df8bae1dSRodney W. Grimes break;
7412f688f82SPaul Traina if (m->rm_flags & RNF_NORMAL) {
7422f688f82SPaul Traina mmask = m->rm_leaf->rn_mask;
7432f688f82SPaul Traina if (tt->rn_flags & RNF_NORMAL) {
7442f688f82SPaul Traina log(LOG_ERR,
74588ff5695SSUZUKI Shinsuke "Non-unique normal route, mask not entered\n");
746868f984cSAlexander V. Chernikov return (tt);
7472f688f82SPaul Traina }
7482f688f82SPaul Traina } else
7492f688f82SPaul Traina mmask = m->rm_mask;
7502f688f82SPaul Traina if (mmask == netmask) {
751df8bae1dSRodney W. Grimes m->rm_refs++;
752df8bae1dSRodney W. Grimes tt->rn_mklist = m;
753868f984cSAlexander V. Chernikov return (tt);
754df8bae1dSRodney W. Grimes }
7551a11e63eSGarrett Wollman if (rn_refines(netmask, mmask)
7561a11e63eSGarrett Wollman || rn_lexobetter(netmask, mmask))
757df8bae1dSRodney W. Grimes break;
758df8bae1dSRodney W. Grimes }
7592f688f82SPaul Traina *mp = rn_new_radix_mask(tt, *mp);
760868f984cSAlexander V. Chernikov return (tt);
761df8bae1dSRodney W. Grimes }
762df8bae1dSRodney W. Grimes
763a0f1e323SBruce Evans struct radix_node *
rn_delete(const void * v_arg,const void * netmask_arg,struct radix_head * head)764*97ffaff8SAlexander V. Chernikov rn_delete(const void *v_arg, const void *netmask_arg, struct radix_head *head)
765df8bae1dSRodney W. Grimes {
766868f984cSAlexander V. Chernikov struct radix_node *t, *p, *x, *tt;
767df8bae1dSRodney W. Grimes struct radix_mask *m, *saved_m, **mp;
768df8bae1dSRodney W. Grimes struct radix_node *dupedkey, *saved_tt, *top;
769*97ffaff8SAlexander V. Chernikov c_caddr_t v;
770*97ffaff8SAlexander V. Chernikov c_caddr_t netmask;
771df8bae1dSRodney W. Grimes int b, head_off, vlen;
772df8bae1dSRodney W. Grimes
773df8bae1dSRodney W. Grimes v = v_arg;
774df8bae1dSRodney W. Grimes netmask = netmask_arg;
775df8bae1dSRodney W. Grimes x = head->rnh_treetop;
776df8bae1dSRodney W. Grimes tt = rn_search(v, x);
7771a11e63eSGarrett Wollman head_off = x->rn_offset;
77804f05de9SLuigi Rizzo vlen = LEN(v);
779df8bae1dSRodney W. Grimes saved_tt = tt;
780df8bae1dSRodney W. Grimes top = x;
781155d72c4SPedro F. Giffuni if (tt == NULL ||
782485b4cbaSLuigi Rizzo bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))
783df8bae1dSRodney W. Grimes return (0);
784df8bae1dSRodney W. Grimes /*
785df8bae1dSRodney W. Grimes * Delete our route from mask lists.
786df8bae1dSRodney W. Grimes */
7872f688f82SPaul Traina if (netmask) {
78865a17d74SAlexander V. Chernikov x = rn_addmask(netmask, head->rnh_masks, 1, head_off);
78965a17d74SAlexander V. Chernikov if (x == NULL)
7902f688f82SPaul Traina return (0);
7912f688f82SPaul Traina netmask = x->rn_key;
792df8bae1dSRodney W. Grimes while (tt->rn_mask != netmask)
793155d72c4SPedro F. Giffuni if ((tt = tt->rn_dupedkey) == NULL)
794df8bae1dSRodney W. Grimes return (0);
795df8bae1dSRodney W. Grimes }
796155d72c4SPedro F. Giffuni if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == NULL)
797df8bae1dSRodney W. Grimes goto on1;
7982f688f82SPaul Traina if (tt->rn_flags & RNF_NORMAL) {
7992f688f82SPaul Traina if (m->rm_leaf != tt || m->rm_refs > 0) {
8002f688f82SPaul Traina log(LOG_ERR, "rn_delete: inconsistent annotation\n");
801868f984cSAlexander V. Chernikov return (0); /* dangling ref could cause disaster */
8022f688f82SPaul Traina }
8032f688f82SPaul Traina } else {
804df8bae1dSRodney W. Grimes if (m->rm_mask != tt->rn_mask) {
8052f688f82SPaul Traina log(LOG_ERR, "rn_delete: inconsistent annotation\n");
806df8bae1dSRodney W. Grimes goto on1;
807df8bae1dSRodney W. Grimes }
808df8bae1dSRodney W. Grimes if (--m->rm_refs >= 0)
809df8bae1dSRodney W. Grimes goto on1;
8102f688f82SPaul Traina }
8111a11e63eSGarrett Wollman b = -1 - tt->rn_bit;
8121a11e63eSGarrett Wollman t = saved_tt->rn_parent;
8131a11e63eSGarrett Wollman if (b > t->rn_bit)
814df8bae1dSRodney W. Grimes goto on1; /* Wasn't lifted at all */
815df8bae1dSRodney W. Grimes do {
816df8bae1dSRodney W. Grimes x = t;
8171a11e63eSGarrett Wollman t = t->rn_parent;
8181a11e63eSGarrett Wollman } while (b <= t->rn_bit && x != top);
8192f688f82SPaul Traina for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
820df8bae1dSRodney W. Grimes if (m == saved_m) {
821df8bae1dSRodney W. Grimes *mp = m->rm_mklist;
8228b15f615SLuiz Otavio O Souza R_Free(m);
823df8bae1dSRodney W. Grimes break;
824df8bae1dSRodney W. Grimes }
825155d72c4SPedro F. Giffuni if (m == NULL) {
8262f688f82SPaul Traina log(LOG_ERR, "rn_delete: couldn't find our annotation\n");
8272f688f82SPaul Traina if (tt->rn_flags & RNF_NORMAL)
8282f688f82SPaul Traina return (0); /* Dangling ref to us */
8292f688f82SPaul Traina }
830df8bae1dSRodney W. Grimes on1:
831df8bae1dSRodney W. Grimes /*
832df8bae1dSRodney W. Grimes * Eliminate us from tree
833df8bae1dSRodney W. Grimes */
834df8bae1dSRodney W. Grimes if (tt->rn_flags & RNF_ROOT)
835df8bae1dSRodney W. Grimes return (0);
836df8bae1dSRodney W. Grimes #ifdef RN_DEBUG
837df8bae1dSRodney W. Grimes /* Get us out of the creation list */
838df8bae1dSRodney W. Grimes for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {}
839df8bae1dSRodney W. Grimes if (t) t->rn_ybro = tt->rn_ybro;
840df8bae1dSRodney W. Grimes #endif
8411a11e63eSGarrett Wollman t = tt->rn_parent;
8422f688f82SPaul Traina dupedkey = saved_tt->rn_dupedkey;
843df8bae1dSRodney W. Grimes if (dupedkey) {
8442f688f82SPaul Traina /*
845053e2342SRuslan Ermilov * Here, tt is the deletion target and
846053e2342SRuslan Ermilov * saved_tt is the head of the dupekey chain.
8472f688f82SPaul Traina */
848df8bae1dSRodney W. Grimes if (tt == saved_tt) {
8492f688f82SPaul Traina /* remove from head of chain */
8501a11e63eSGarrett Wollman x = dupedkey; x->rn_parent = t;
8511a11e63eSGarrett Wollman if (t->rn_left == tt)
8521a11e63eSGarrett Wollman t->rn_left = x;
8531a11e63eSGarrett Wollman else
8541a11e63eSGarrett Wollman t->rn_right = x;
855df8bae1dSRodney W. Grimes } else {
8562f688f82SPaul Traina /* find node in front of tt on the chain */
857df8bae1dSRodney W. Grimes for (x = p = saved_tt; p && p->rn_dupedkey != tt;)
858df8bae1dSRodney W. Grimes p = p->rn_dupedkey;
8592f688f82SPaul Traina if (p) {
8602f688f82SPaul Traina p->rn_dupedkey = tt->rn_dupedkey;
8612f688f82SPaul Traina if (tt->rn_dupedkey) /* parent */
8621a11e63eSGarrett Wollman tt->rn_dupedkey->rn_parent = p;
8631a11e63eSGarrett Wollman /* parent */
8642f688f82SPaul Traina } else log(LOG_ERR, "rn_delete: couldn't find us\n");
865df8bae1dSRodney W. Grimes }
866df8bae1dSRodney W. Grimes t = tt + 1;
867df8bae1dSRodney W. Grimes if (t->rn_flags & RNF_ACTIVE) {
868df8bae1dSRodney W. Grimes #ifndef RN_DEBUG
8691a11e63eSGarrett Wollman *++x = *t;
8701a11e63eSGarrett Wollman p = t->rn_parent;
871df8bae1dSRodney W. Grimes #else
8721a11e63eSGarrett Wollman b = t->rn_info;
8731a11e63eSGarrett Wollman *++x = *t;
8741a11e63eSGarrett Wollman t->rn_info = b;
8751a11e63eSGarrett Wollman p = t->rn_parent;
876df8bae1dSRodney W. Grimes #endif
8771a11e63eSGarrett Wollman if (p->rn_left == t)
8781a11e63eSGarrett Wollman p->rn_left = x;
8791a11e63eSGarrett Wollman else
8801a11e63eSGarrett Wollman p->rn_right = x;
8811a11e63eSGarrett Wollman x->rn_left->rn_parent = x;
8821a11e63eSGarrett Wollman x->rn_right->rn_parent = x;
883df8bae1dSRodney W. Grimes }
884df8bae1dSRodney W. Grimes goto out;
885df8bae1dSRodney W. Grimes }
8861a11e63eSGarrett Wollman if (t->rn_left == tt)
8871a11e63eSGarrett Wollman x = t->rn_right;
8881a11e63eSGarrett Wollman else
8891a11e63eSGarrett Wollman x = t->rn_left;
8901a11e63eSGarrett Wollman p = t->rn_parent;
8911a11e63eSGarrett Wollman if (p->rn_right == t)
8921a11e63eSGarrett Wollman p->rn_right = x;
8931a11e63eSGarrett Wollman else
8941a11e63eSGarrett Wollman p->rn_left = x;
8951a11e63eSGarrett Wollman x->rn_parent = p;
896df8bae1dSRodney W. Grimes /*
897df8bae1dSRodney W. Grimes * Demote routes attached to us.
898df8bae1dSRodney W. Grimes */
899df8bae1dSRodney W. Grimes if (t->rn_mklist) {
9001a11e63eSGarrett Wollman if (x->rn_bit >= 0) {
9012f688f82SPaul Traina for (mp = &x->rn_mklist; (m = *mp);)
902df8bae1dSRodney W. Grimes mp = &m->rm_mklist;
903df8bae1dSRodney W. Grimes *mp = t->rn_mklist;
904df8bae1dSRodney W. Grimes } else {
9052f688f82SPaul Traina /* If there are any key,mask pairs in a sibling
9062f688f82SPaul Traina duped-key chain, some subset will appear sorted
9072f688f82SPaul Traina in the same order attached to our mklist */
9082f688f82SPaul Traina for (m = t->rn_mklist; m && x; x = x->rn_dupedkey)
9092f688f82SPaul Traina if (m == x->rn_mklist) {
910df8bae1dSRodney W. Grimes struct radix_mask *mm = m->rm_mklist;
911df8bae1dSRodney W. Grimes x->rn_mklist = 0;
9122f688f82SPaul Traina if (--(m->rm_refs) < 0)
9138b15f615SLuiz Otavio O Souza R_Free(m);
914df8bae1dSRodney W. Grimes m = mm;
915df8bae1dSRodney W. Grimes }
9162f688f82SPaul Traina if (m)
917da218192SBruce Evans log(LOG_ERR,
918da218192SBruce Evans "rn_delete: Orphaned Mask %p at %p\n",
9197bc22882SLuigi Rizzo m, x);
920df8bae1dSRodney W. Grimes }
921df8bae1dSRodney W. Grimes }
922df8bae1dSRodney W. Grimes /*
923df8bae1dSRodney W. Grimes * We may be holding an active internal node in the tree.
924df8bae1dSRodney W. Grimes */
925df8bae1dSRodney W. Grimes x = tt + 1;
926df8bae1dSRodney W. Grimes if (t != x) {
927df8bae1dSRodney W. Grimes #ifndef RN_DEBUG
928df8bae1dSRodney W. Grimes *t = *x;
929df8bae1dSRodney W. Grimes #else
9301a11e63eSGarrett Wollman b = t->rn_info;
9311a11e63eSGarrett Wollman *t = *x;
9321a11e63eSGarrett Wollman t->rn_info = b;
933df8bae1dSRodney W. Grimes #endif
9341a11e63eSGarrett Wollman t->rn_left->rn_parent = t;
9351a11e63eSGarrett Wollman t->rn_right->rn_parent = t;
9361a11e63eSGarrett Wollman p = x->rn_parent;
9371a11e63eSGarrett Wollman if (p->rn_left == x)
9381a11e63eSGarrett Wollman p->rn_left = t;
9391a11e63eSGarrett Wollman else
9401a11e63eSGarrett Wollman p->rn_right = t;
941df8bae1dSRodney W. Grimes }
942df8bae1dSRodney W. Grimes out:
943df8bae1dSRodney W. Grimes tt->rn_flags &= ~RNF_ACTIVE;
944df8bae1dSRodney W. Grimes tt[1].rn_flags &= ~RNF_ACTIVE;
945df8bae1dSRodney W. Grimes return (tt);
946df8bae1dSRodney W. Grimes }
947df8bae1dSRodney W. Grimes
948c2bed6a3SGarrett Wollman /*
949c2bed6a3SGarrett Wollman * This is the same as rn_walktree() except for the parameters and the
950c2bed6a3SGarrett Wollman * exit.
951c2bed6a3SGarrett Wollman */
95261eee0e2SAlexander V. Chernikov int
rn_walktree_from(struct radix_head * h,void * a,void * m,walktree_f_t * f,void * w)95361eee0e2SAlexander V. Chernikov rn_walktree_from(struct radix_head *h, void *a, void *m,
954868f984cSAlexander V. Chernikov walktree_f_t *f, void *w)
955c2bed6a3SGarrett Wollman {
956c2bed6a3SGarrett Wollman int error;
957c2bed6a3SGarrett Wollman struct radix_node *base, *next;
958c2bed6a3SGarrett Wollman u_char *xa = (u_char *)a;
959c2bed6a3SGarrett Wollman u_char *xm = (u_char *)m;
960868f984cSAlexander V. Chernikov struct radix_node *rn, *last = NULL; /* shut up gcc */
961c2bed6a3SGarrett Wollman int stopping = 0;
962c2bed6a3SGarrett Wollman int lastb;
963c2bed6a3SGarrett Wollman
96432fb15e8SAlexander V. Chernikov KASSERT(m != NULL, ("%s: mask needs to be specified", __func__));
96532fb15e8SAlexander V. Chernikov
966c2bed6a3SGarrett Wollman /*
96704f05de9SLuigi Rizzo * rn_search_m is sort-of-open-coded here. We cannot use the
96804f05de9SLuigi Rizzo * function because we need to keep track of the last node seen.
969c2bed6a3SGarrett Wollman */
9703545b048SGarrett Wollman /* printf("about to search\n"); */
9711a11e63eSGarrett Wollman for (rn = h->rnh_treetop; rn->rn_bit >= 0; ) {
972c2bed6a3SGarrett Wollman last = rn;
9731a11e63eSGarrett Wollman /* printf("rn_bit %d, rn_bmask %x, xm[rn_offset] %x\n",
9741a11e63eSGarrett Wollman rn->rn_bit, rn->rn_bmask, xm[rn->rn_offset]); */
9751a11e63eSGarrett Wollman if (!(rn->rn_bmask & xm[rn->rn_offset])) {
976c2bed6a3SGarrett Wollman break;
9773545b048SGarrett Wollman }
9781a11e63eSGarrett Wollman if (rn->rn_bmask & xa[rn->rn_offset]) {
9791a11e63eSGarrett Wollman rn = rn->rn_right;
980c2bed6a3SGarrett Wollman } else {
9811a11e63eSGarrett Wollman rn = rn->rn_left;
982c2bed6a3SGarrett Wollman }
983c2bed6a3SGarrett Wollman }
9843545b048SGarrett Wollman /* printf("done searching\n"); */
985c2bed6a3SGarrett Wollman
986c2bed6a3SGarrett Wollman /*
987c2bed6a3SGarrett Wollman * Two cases: either we stepped off the end of our mask,
988c2bed6a3SGarrett Wollman * in which case last == rn, or we reached a leaf, in which
98932fb15e8SAlexander V. Chernikov * case we want to start from the leaf.
990c2bed6a3SGarrett Wollman */
99132fb15e8SAlexander V. Chernikov if (rn->rn_bit >= 0)
992c2bed6a3SGarrett Wollman rn = last;
99332fb15e8SAlexander V. Chernikov lastb = last->rn_bit;
994c2bed6a3SGarrett Wollman
9953545b048SGarrett Wollman /* printf("rn %p, lastb %d\n", rn, lastb);*/
9963545b048SGarrett Wollman
997c2bed6a3SGarrett Wollman /*
998c2bed6a3SGarrett Wollman * This gets complicated because we may delete the node
999c2bed6a3SGarrett Wollman * while applying the function f to it, so we need to calculate
1000c2bed6a3SGarrett Wollman * the successor node in advance.
1001c2bed6a3SGarrett Wollman */
10021a11e63eSGarrett Wollman while (rn->rn_bit >= 0)
10031a11e63eSGarrett Wollman rn = rn->rn_left;
1004c2bed6a3SGarrett Wollman
1005c2bed6a3SGarrett Wollman while (!stopping) {
10061a11e63eSGarrett Wollman /* printf("node %p (%d)\n", rn, rn->rn_bit); */
1007c2bed6a3SGarrett Wollman base = rn;
1008c2bed6a3SGarrett Wollman /* If at right child go back up, otherwise, go right */
10091a11e63eSGarrett Wollman while (rn->rn_parent->rn_right == rn
10101a11e63eSGarrett Wollman && !(rn->rn_flags & RNF_ROOT)) {
10111a11e63eSGarrett Wollman rn = rn->rn_parent;
1012c2bed6a3SGarrett Wollman
1013c2bed6a3SGarrett Wollman /* if went up beyond last, stop */
10146b7b44acSQing Li if (rn->rn_bit <= lastb) {
1015c2bed6a3SGarrett Wollman stopping = 1;
10163545b048SGarrett Wollman /* printf("up too far\n"); */
101704f05de9SLuigi Rizzo /*
101804f05de9SLuigi Rizzo * XXX we should jump to the 'Process leaves'
101904f05de9SLuigi Rizzo * part, because the values of 'rn' and 'next'
102004f05de9SLuigi Rizzo * we compute will not be used. Not a big deal
102104f05de9SLuigi Rizzo * because this loop will terminate, but it is
102204f05de9SLuigi Rizzo * inefficient and hard to understand!
102304f05de9SLuigi Rizzo */
1024c2bed6a3SGarrett Wollman }
1025c2bed6a3SGarrett Wollman }
1026c2bed6a3SGarrett Wollman
10276b7b44acSQing Li /*
10286b7b44acSQing Li * At the top of the tree, no need to traverse the right
10296b7b44acSQing Li * half, prevent the traversal of the entire tree in the
10306b7b44acSQing Li * case of default route.
10316b7b44acSQing Li */
10326b7b44acSQing Li if (rn->rn_parent->rn_flags & RNF_ROOT)
10336b7b44acSQing Li stopping = 1;
10346b7b44acSQing Li
1035c2bed6a3SGarrett Wollman /* Find the next *leaf* since next node might vanish, too */
10361a11e63eSGarrett Wollman for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
10371a11e63eSGarrett Wollman rn = rn->rn_left;
1038c2bed6a3SGarrett Wollman next = rn;
1039c2bed6a3SGarrett Wollman /* Process leaves */
1040155d72c4SPedro F. Giffuni while ((rn = base) != NULL) {
1041c2bed6a3SGarrett Wollman base = rn->rn_dupedkey;
10423545b048SGarrett Wollman /* printf("leaf %p\n", rn); */
1043c2bed6a3SGarrett Wollman if (!(rn->rn_flags & RNF_ROOT)
1044c2bed6a3SGarrett Wollman && (error = (*f)(rn, w)))
1045c2bed6a3SGarrett Wollman return (error);
1046c2bed6a3SGarrett Wollman }
1047c2bed6a3SGarrett Wollman rn = next;
10483545b048SGarrett Wollman
10493545b048SGarrett Wollman if (rn->rn_flags & RNF_ROOT) {
10503545b048SGarrett Wollman /* printf("root, stopping"); */
10513545b048SGarrett Wollman stopping = 1;
10523545b048SGarrett Wollman }
1053c2bed6a3SGarrett Wollman }
1054868f984cSAlexander V. Chernikov return (0);
1055c2bed6a3SGarrett Wollman }
1056c2bed6a3SGarrett Wollman
105761eee0e2SAlexander V. Chernikov int
rn_walktree(struct radix_head * h,walktree_f_t * f,void * w)105861eee0e2SAlexander V. Chernikov rn_walktree(struct radix_head *h, walktree_f_t *f, void *w)
1059df8bae1dSRodney W. Grimes {
1060df8bae1dSRodney W. Grimes int error;
1061df8bae1dSRodney W. Grimes struct radix_node *base, *next;
1062868f984cSAlexander V. Chernikov struct radix_node *rn = h->rnh_treetop;
1063df8bae1dSRodney W. Grimes /*
1064df8bae1dSRodney W. Grimes * This gets complicated because we may delete the node
1065df8bae1dSRodney W. Grimes * while applying the function f to it, so we need to calculate
1066df8bae1dSRodney W. Grimes * the successor node in advance.
1067df8bae1dSRodney W. Grimes */
1068e1344b96SKip Macy
1069df8bae1dSRodney W. Grimes /* First time through node, go left */
10701a11e63eSGarrett Wollman while (rn->rn_bit >= 0)
10711a11e63eSGarrett Wollman rn = rn->rn_left;
1072df8bae1dSRodney W. Grimes for (;;) {
1073df8bae1dSRodney W. Grimes base = rn;
1074df8bae1dSRodney W. Grimes /* If at right child go back up, otherwise, go right */
10751a11e63eSGarrett Wollman while (rn->rn_parent->rn_right == rn
10761a11e63eSGarrett Wollman && (rn->rn_flags & RNF_ROOT) == 0)
10771a11e63eSGarrett Wollman rn = rn->rn_parent;
1078df8bae1dSRodney W. Grimes /* Find the next *leaf* since next node might vanish, too */
10791a11e63eSGarrett Wollman for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
10801a11e63eSGarrett Wollman rn = rn->rn_left;
1081df8bae1dSRodney W. Grimes next = rn;
1082df8bae1dSRodney W. Grimes /* Process leaves */
10832f688f82SPaul Traina while ((rn = base)) {
1084df8bae1dSRodney W. Grimes base = rn->rn_dupedkey;
10851a11e63eSGarrett Wollman if (!(rn->rn_flags & RNF_ROOT)
10861a11e63eSGarrett Wollman && (error = (*f)(rn, w)))
1087df8bae1dSRodney W. Grimes return (error);
1088df8bae1dSRodney W. Grimes }
1089df8bae1dSRodney W. Grimes rn = next;
1090df8bae1dSRodney W. Grimes if (rn->rn_flags & RNF_ROOT)
1091df8bae1dSRodney W. Grimes return (0);
1092df8bae1dSRodney W. Grimes }
1093df8bae1dSRodney W. Grimes /* NOTREACHED */
1094df8bae1dSRodney W. Grimes }
1095df8bae1dSRodney W. Grimes
109604f05de9SLuigi Rizzo /*
109761eee0e2SAlexander V. Chernikov * Initialize an empty tree. This has 3 nodes, which are passed
109861eee0e2SAlexander V. Chernikov * via base_nodes (in the order <left,root,right>) and are
109904f05de9SLuigi Rizzo * marked RNF_ROOT so they cannot be freed.
110004f05de9SLuigi Rizzo * The leaves have all-zero and all-one keys, with significant
110104f05de9SLuigi Rizzo * bits starting at 'off'.
110204f05de9SLuigi Rizzo */
110361eee0e2SAlexander V. Chernikov void
rn_inithead_internal(struct radix_head * rh,struct radix_node * base_nodes,int off)110461eee0e2SAlexander V. Chernikov rn_inithead_internal(struct radix_head *rh, struct radix_node *base_nodes, int off)
1105df8bae1dSRodney W. Grimes {
1106868f984cSAlexander V. Chernikov struct radix_node *t, *tt, *ttt;
110761eee0e2SAlexander V. Chernikov
110861eee0e2SAlexander V. Chernikov t = rn_newpair(rn_zeros, off, base_nodes);
110961eee0e2SAlexander V. Chernikov ttt = base_nodes + 2;
11101a11e63eSGarrett Wollman t->rn_right = ttt;
11111a11e63eSGarrett Wollman t->rn_parent = t;
111261eee0e2SAlexander V. Chernikov tt = t->rn_left; /* ... which in turn is base_nodes */
1113df8bae1dSRodney W. Grimes tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;
11141a11e63eSGarrett Wollman tt->rn_bit = -1 - off;
1115df8bae1dSRodney W. Grimes *ttt = *tt;
1116df8bae1dSRodney W. Grimes ttt->rn_key = rn_ones;
111761eee0e2SAlexander V. Chernikov
111861eee0e2SAlexander V. Chernikov rh->rnh_treetop = t;
111961eee0e2SAlexander V. Chernikov }
112061eee0e2SAlexander V. Chernikov
112161eee0e2SAlexander V. Chernikov static void
rn_detachhead_internal(struct radix_head * head)112261eee0e2SAlexander V. Chernikov rn_detachhead_internal(struct radix_head *head)
112361eee0e2SAlexander V. Chernikov {
112461eee0e2SAlexander V. Chernikov
112561eee0e2SAlexander V. Chernikov KASSERT((head != NULL),
112661eee0e2SAlexander V. Chernikov ("%s: head already freed", __func__));
112761eee0e2SAlexander V. Chernikov
112861eee0e2SAlexander V. Chernikov /* Free <left,root,right> nodes. */
112961eee0e2SAlexander V. Chernikov R_Free(head);
113061eee0e2SAlexander V. Chernikov }
113161eee0e2SAlexander V. Chernikov
113261eee0e2SAlexander V. Chernikov /* Functions used by 'struct radix_node_head' users */
113361eee0e2SAlexander V. Chernikov
113461eee0e2SAlexander V. Chernikov int
rn_inithead(void ** head,int off)113561eee0e2SAlexander V. Chernikov rn_inithead(void **head, int off)
113661eee0e2SAlexander V. Chernikov {
113761eee0e2SAlexander V. Chernikov struct radix_node_head *rnh;
113861eee0e2SAlexander V. Chernikov struct radix_mask_head *rmh;
113961eee0e2SAlexander V. Chernikov
114061eee0e2SAlexander V. Chernikov rnh = *head;
114161eee0e2SAlexander V. Chernikov rmh = NULL;
114261eee0e2SAlexander V. Chernikov
114361eee0e2SAlexander V. Chernikov if (*head != NULL)
114461eee0e2SAlexander V. Chernikov return (1);
114561eee0e2SAlexander V. Chernikov
114661eee0e2SAlexander V. Chernikov R_Zalloc(rnh, struct radix_node_head *, sizeof (*rnh));
114761eee0e2SAlexander V. Chernikov R_Zalloc(rmh, struct radix_mask_head *, sizeof (*rmh));
114861eee0e2SAlexander V. Chernikov if (rnh == NULL || rmh == NULL) {
114961eee0e2SAlexander V. Chernikov if (rnh != NULL)
115061eee0e2SAlexander V. Chernikov R_Free(rnh);
1151856d8ddbSConrad Meyer if (rmh != NULL)
1152856d8ddbSConrad Meyer R_Free(rmh);
115361eee0e2SAlexander V. Chernikov return (0);
115461eee0e2SAlexander V. Chernikov }
115561eee0e2SAlexander V. Chernikov
115661eee0e2SAlexander V. Chernikov /* Init trees */
115761eee0e2SAlexander V. Chernikov rn_inithead_internal(&rnh->rh, rnh->rnh_nodes, off);
115861eee0e2SAlexander V. Chernikov rn_inithead_internal(&rmh->head, rmh->mask_nodes, 0);
115961eee0e2SAlexander V. Chernikov *head = rnh;
116061eee0e2SAlexander V. Chernikov rnh->rh.rnh_masks = rmh;
116161eee0e2SAlexander V. Chernikov
116261eee0e2SAlexander V. Chernikov /* Finally, set base callbacks */
1163df8bae1dSRodney W. Grimes rnh->rnh_addaddr = rn_addroute;
1164df8bae1dSRodney W. Grimes rnh->rnh_deladdr = rn_delete;
1165df8bae1dSRodney W. Grimes rnh->rnh_matchaddr = rn_match;
11662f688f82SPaul Traina rnh->rnh_lookup = rn_lookup;
1167df8bae1dSRodney W. Grimes rnh->rnh_walktree = rn_walktree;
1168c2bed6a3SGarrett Wollman rnh->rnh_walktree_from = rn_walktree_from;
116965a17d74SAlexander V. Chernikov
11701bb635b0SBjoern A. Zeeb return (1);
11711bb635b0SBjoern A. Zeeb }
11721bb635b0SBjoern A. Zeeb
11738b1af054SAlexander V. Chernikov static int
rn_freeentry(struct radix_node * rn,void * arg)11748b1af054SAlexander V. Chernikov rn_freeentry(struct radix_node *rn, void *arg)
11758b1af054SAlexander V. Chernikov {
117661eee0e2SAlexander V. Chernikov struct radix_head * const rnh = arg;
11778b1af054SAlexander V. Chernikov struct radix_node *x;
11788b1af054SAlexander V. Chernikov
11798b1af054SAlexander V. Chernikov x = (struct radix_node *)rn_delete(rn + 2, NULL, rnh);
11808b1af054SAlexander V. Chernikov if (x != NULL)
11818b15f615SLuiz Otavio O Souza R_Free(x);
11828b1af054SAlexander V. Chernikov return (0);
11838b1af054SAlexander V. Chernikov }
11848b1af054SAlexander V. Chernikov
118565a17d74SAlexander V. Chernikov int
rn_detachhead(void ** head)118665a17d74SAlexander V. Chernikov rn_detachhead(void **head)
1187df8bae1dSRodney W. Grimes {
118865a17d74SAlexander V. Chernikov struct radix_node_head *rnh;
1189df8bae1dSRodney W. Grimes
119065a17d74SAlexander V. Chernikov KASSERT((head != NULL && *head != NULL),
119165a17d74SAlexander V. Chernikov ("%s: head already freed", __func__));
119265a17d74SAlexander V. Chernikov
119361eee0e2SAlexander V. Chernikov rnh = (struct radix_node_head *)(*head);
119465a17d74SAlexander V. Chernikov
119561eee0e2SAlexander V. Chernikov rn_walktree(&rnh->rh.rnh_masks->head, rn_freeentry, rnh->rh.rnh_masks);
119661eee0e2SAlexander V. Chernikov rn_detachhead_internal(&rnh->rh.rnh_masks->head);
119761eee0e2SAlexander V. Chernikov rn_detachhead_internal(&rnh->rh);
119861eee0e2SAlexander V. Chernikov
119961eee0e2SAlexander V. Chernikov *head = NULL;
120061eee0e2SAlexander V. Chernikov
120165a17d74SAlexander V. Chernikov return (1);
1202df8bae1dSRodney W. Grimes }
1203