radix_ipf.c revision 1.1 1 1.1 christos /* $NetBSD: radix_ipf.c,v 1.1 2012/03/23 20:37:04 christos Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Copyright (C) 2012 by Darren Reed.
5 1.1 christos *
6 1.1 christos * See the IPFILTER.LICENCE file for details on licencing.
7 1.1 christos */
8 1.1 christos #include <sys/types.h>
9 1.1 christos #include <sys/time.h>
10 1.1 christos #include <sys/socket.h>
11 1.1 christos #include <sys/param.h>
12 1.1 christos #include <netinet/in.h>
13 1.1 christos #include <net/if.h>
14 1.1 christos #if !defined(_KERNEL)
15 1.1 christos # include <stddef.h>
16 1.1 christos # include <stdlib.h>
17 1.1 christos # include <strings.h>
18 1.1 christos # include <string.h>
19 1.1 christos #endif
20 1.1 christos #include "netinet/ip_compat.h"
21 1.1 christos #include "netinet/ip_fil.h"
22 1.1 christos #ifdef RDX_DEBUG
23 1.1 christos # include <arpa/inet.h>
24 1.1 christos # include <stdlib.h>
25 1.1 christos # include <stdio.h>
26 1.1 christos #endif
27 1.1 christos #include "netinet/radix_ipf.h"
28 1.1 christos
29 1.1 christos #define ADF_OFF offsetof(addrfamily_t, adf_addr)
30 1.1 christos #define ADF_OFF_BITS (ADF_OFF << 3)
31 1.1 christos
32 1.1 christos static ipf_rdx_node_t *ipf_rx_insert __P((ipf_rdx_head_t *,
33 1.1 christos ipf_rdx_node_t nodes[2], int *));
34 1.1 christos static void ipf_rx_attach_mask __P((ipf_rdx_node_t *, ipf_rdx_mask_t *));
35 1.1 christos static int count_mask_bits __P((addrfamily_t *, u_32_t **));
36 1.1 christos static void buildnodes __P((addrfamily_t *, addrfamily_t *,
37 1.1 christos ipf_rdx_node_t n[2]));
38 1.1 christos static ipf_rdx_node_t *ipf_rx_find_addr __P((ipf_rdx_node_t *, u_32_t *));
39 1.1 christos static ipf_rdx_node_t *ipf_rx_lookup __P((ipf_rdx_head_t *, addrfamily_t *,
40 1.1 christos addrfamily_t *));
41 1.1 christos static ipf_rdx_node_t *ipf_rx_match __P((ipf_rdx_head_t *, addrfamily_t *));
42 1.1 christos
43 1.1 christos /*
44 1.1 christos * Foreword.
45 1.1 christos * ---------
46 1.1 christos * The code in this file has been written to target using the addrfamily_t
47 1.1 christos * data structure to house the address information and no other. Thus there
48 1.1 christos * are certain aspects of thise code (such as offsets to the address itself)
49 1.1 christos * that are hard coded here whilst they might be more variable elsewhere.
50 1.1 christos * Similarly, this code enforces no maximum key length as that's implied by
51 1.1 christos * all keys needing to be stored in addrfamily_t.
52 1.1 christos */
53 1.1 christos
54 1.1 christos /* ------------------------------------------------------------------------ */
55 1.1 christos /* Function: count_mask_bits */
56 1.1 christos /* Returns: number of consecutive bits starting at "mask". */
57 1.1 christos /* */
58 1.1 christos /* Count the number of bits set in the address section of addrfamily_t and */
59 1.1 christos /* return both that number and a pointer to the last word with a bit set if */
60 1.1 christos /* lastp is not NULL. The bit count is performed using network byte order */
61 1.1 christos /* as the guide for which bit is the most significant bit. */
62 1.1 christos /* ------------------------------------------------------------------------ */
63 1.1 christos static int
64 1.1 christos count_mask_bits(mask, lastp)
65 1.1 christos addrfamily_t *mask;
66 1.1 christos u_32_t **lastp;
67 1.1 christos {
68 1.1 christos u_32_t *mp = (u_32_t *)&mask->adf_addr;
69 1.1 christos u_32_t m;
70 1.1 christos int count = 0;
71 1.1 christos int mlen;
72 1.1 christos
73 1.1 christos mlen = mask->adf_len - offsetof(addrfamily_t, adf_addr);
74 1.1 christos for (mlen = mask->adf_len; mlen > 0; mlen -= 4, mp++) {
75 1.1 christos if ((m = ntohl(*mp)) == 0)
76 1.1 christos break;
77 1.1 christos if (lastp != NULL)
78 1.1 christos *lastp = mp;
79 1.1 christos for (; m & 0x80000000; m <<= 1)
80 1.1 christos count++;
81 1.1 christos }
82 1.1 christos
83 1.1 christos return count;
84 1.1 christos }
85 1.1 christos
86 1.1 christos
87 1.1 christos /* ------------------------------------------------------------------------ */
88 1.1 christos /* Function: buildnodes */
89 1.1 christos /* Returns: Nil */
90 1.1 christos /* Parameters: addr(I) - network address for this radix node */
91 1.1 christos /* mask(I) - netmask associated with the above address */
92 1.1 christos /* nodes(O) - pair of ipf_rdx_node_t's to initialise with data */
93 1.1 christos /* associated with addr and mask. */
94 1.1 christos /* */
95 1.1 christos /* Initialise the fields in a pair of radix tree nodes according to the */
96 1.1 christos /* data supplied in the paramters "addr" and "mask". It is expected that */
97 1.1 christos /* "mask" will contain a consecutive string of bits set. Masks with gaps in */
98 1.1 christos /* the middle are not handled by this implementation. */
99 1.1 christos /* ------------------------------------------------------------------------ */
100 1.1 christos static void
101 1.1 christos buildnodes(addr, mask, nodes)
102 1.1 christos addrfamily_t *addr, *mask;
103 1.1 christos ipf_rdx_node_t nodes[2];
104 1.1 christos {
105 1.1 christos u_32_t maskbits;
106 1.1 christos u_32_t lastbits;
107 1.1 christos u_32_t lastmask;
108 1.1 christos u_32_t *last;
109 1.1 christos int masklen;
110 1.1 christos
111 1.1 christos last = NULL;
112 1.1 christos maskbits = count_mask_bits(mask, &last);
113 1.1 christos if (last == NULL) {
114 1.1 christos masklen = 0;
115 1.1 christos lastmask = 0;
116 1.1 christos } else {
117 1.1 christos masklen = last - (u_32_t *)mask;
118 1.1 christos lastmask = *last;
119 1.1 christos }
120 1.1 christos lastbits = maskbits & 0x1f;
121 1.1 christos
122 1.1 christos bzero(&nodes[0], sizeof(ipf_rdx_node_t) * 2);
123 1.1 christos nodes[0].maskbitcount = maskbits;
124 1.1 christos nodes[0].index = -1 - (ADF_OFF_BITS + maskbits);
125 1.1 christos nodes[0].addrkey = (u_32_t *)addr;
126 1.1 christos nodes[0].maskkey = (u_32_t *)mask;
127 1.1 christos nodes[0].addroff = nodes[0].addrkey + masklen;
128 1.1 christos nodes[0].maskoff = nodes[0].maskkey + masklen;
129 1.1 christos nodes[0].parent = &nodes[1];
130 1.1 christos nodes[0].offset = masklen;
131 1.1 christos nodes[0].lastmask = lastmask;
132 1.1 christos nodes[1].offset = masklen;
133 1.1 christos nodes[1].left = &nodes[0];
134 1.1 christos nodes[1].maskbitcount = maskbits;
135 1.1 christos #ifdef RDX_DEBUG
136 1.1 christos (void) strcpy(nodes[0].name, "_BUILD.0");
137 1.1 christos (void) strcpy(nodes[1].name, "_BUILD.1");
138 1.1 christos #endif
139 1.1 christos }
140 1.1 christos
141 1.1 christos
142 1.1 christos /* ------------------------------------------------------------------------ */
143 1.1 christos /* Function: ipf_rx_find_addr */
144 1.1 christos /* Returns: ipf_rdx_node_t * - pointer to a node in the radix tree. */
145 1.1 christos /* Parameters: tree(I) - pointer to first right node in tree to search */
146 1.1 christos /* addr(I) - pointer to address to match */
147 1.1 christos /* */
148 1.1 christos /* Walk the radix tree given by "tree", looking for a leaf node that is a */
149 1.1 christos /* match for the address given by "addr". */
150 1.1 christos /* ------------------------------------------------------------------------ */
151 1.1 christos static ipf_rdx_node_t *
152 1.1 christos ipf_rx_find_addr(tree, addr)
153 1.1 christos ipf_rdx_node_t *tree;
154 1.1 christos u_32_t *addr;
155 1.1 christos {
156 1.1 christos ipf_rdx_node_t *cur;
157 1.1 christos
158 1.1 christos for (cur = tree; cur->index >= 0;) {
159 1.1 christos if (cur->bitmask & addr[cur->offset]) {
160 1.1 christos cur = cur->right;
161 1.1 christos } else {
162 1.1 christos cur = cur->left;
163 1.1 christos }
164 1.1 christos }
165 1.1 christos
166 1.1 christos return (cur);
167 1.1 christos }
168 1.1 christos
169 1.1 christos
170 1.1 christos /* ------------------------------------------------------------------------ */
171 1.1 christos /* Function: ipf_rx_match */
172 1.1 christos /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
173 1.1 christos /* added to the tree. */
174 1.1 christos /* Paramters: head(I) - pointer to tree head to search */
175 1.1 christos /* addr(I) - pointer to address to find */
176 1.1 christos /* */
177 1.1 christos /* Search the radix tree for the best match to the address pointed to by */
178 1.1 christos /* "addr" and return a pointer to that node. This search will not match the */
179 1.1 christos /* address information stored in either of the root leaves as neither of */
180 1.1 christos /* them are considered to be part of the tree of data being stored. */
181 1.1 christos /* ------------------------------------------------------------------------ */
182 1.1 christos static ipf_rdx_node_t *
183 1.1 christos ipf_rx_match(head, addr)
184 1.1 christos ipf_rdx_head_t *head;
185 1.1 christos addrfamily_t *addr;
186 1.1 christos {
187 1.1 christos ipf_rdx_mask_t *masknode;
188 1.1 christos ipf_rdx_node_t *prev;
189 1.1 christos ipf_rdx_node_t *node;
190 1.1 christos ipf_rdx_node_t *cur;
191 1.1 christos u_32_t *data;
192 1.1 christos u_32_t *mask;
193 1.1 christos u_32_t *key;
194 1.1 christos u_32_t *end;
195 1.1 christos int len;
196 1.1 christos int i;
197 1.1 christos
198 1.1 christos len = addr->adf_len;
199 1.1 christos end = (u_32_t *)((u_char *)addr + len);
200 1.1 christos node = ipf_rx_find_addr(head->root, (u_32_t *)addr);
201 1.1 christos
202 1.1 christos /*
203 1.1 christos * Search the dupkey list for a potential match.
204 1.1 christos */
205 1.1 christos for (cur = node; (cur != NULL) && (cur->root == 0); cur = cur->dupkey) {
206 1.1 christos data = cur[0].addroff;
207 1.1 christos mask = cur[0].maskoff;
208 1.1 christos key = (u_32_t *)addr + cur[0].offset;
209 1.1 christos for (; key < end; data++, key++, mask++)
210 1.1 christos if ((*key & *mask) != *data)
211 1.1 christos break;
212 1.1 christos if ((end == key) && (cur->root == 0))
213 1.1 christos return (cur); /* Equal keys */
214 1.1 christos }
215 1.1 christos prev = node->parent;
216 1.1 christos key = (u_32_t *)addr;
217 1.1 christos
218 1.1 christos for (node = prev; node->root == 0; node = node->parent) {
219 1.1 christos /*
220 1.1 christos * We know that the node hasn't matched so therefore only
221 1.1 christos * the entries in the mask list are searched, not the top
222 1.1 christos * node nor the dupkey list.
223 1.1 christos */
224 1.1 christos masknode = node->masks;
225 1.1 christos for (; masknode != NULL; masknode = masknode->next) {
226 1.1 christos if (masknode->maskbitcount > node->maskbitcount)
227 1.1 christos continue;
228 1.1 christos cur = masknode->node;
229 1.1 christos for (i = ADF_OFF >> 2; i <= node->offset; i++) {
230 1.1 christos if ((key[i] & masknode->mask[i]) ==
231 1.1 christos cur->addrkey[i])
232 1.1 christos return (cur);
233 1.1 christos }
234 1.1 christos }
235 1.1 christos }
236 1.1 christos
237 1.1 christos return NULL;
238 1.1 christos }
239 1.1 christos
240 1.1 christos
241 1.1 christos /* ------------------------------------------------------------------------ */
242 1.1 christos /* Function: ipf_rx_lookup */
243 1.1 christos /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
244 1.1 christos /* added to the tree. */
245 1.1 christos /* Paramters: head(I) - pointer to tree head to search */
246 1.1 christos /* addr(I) - address part of the key to match */
247 1.1 christos /* mask(I) - netmask part of the key to match */
248 1.1 christos /* */
249 1.1 christos /* ipf_rx_lookup searches for an exact match on (addr,mask). The intention */
250 1.1 christos /* is to see if a given key is in the tree, not to see if a route exists. */
251 1.1 christos /* ------------------------------------------------------------------------ */
252 1.1 christos ipf_rdx_node_t *
253 1.1 christos ipf_rx_lookup(head, addr, mask)
254 1.1 christos ipf_rdx_head_t *head;
255 1.1 christos addrfamily_t *addr, *mask;
256 1.1 christos {
257 1.1 christos ipf_rdx_node_t *found;
258 1.1 christos ipf_rdx_node_t *node;
259 1.1 christos u_32_t *akey;
260 1.1 christos int count;
261 1.1 christos
262 1.1 christos found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
263 1.1 christos if (found->root == 1)
264 1.1 christos return NULL;
265 1.1 christos
266 1.1 christos /*
267 1.1 christos * It is possible to find a matching address in the tree but for the
268 1.1 christos * netmask to not match. If the netmask does not match and there is
269 1.1 christos * no list of alternatives present at dupkey, return a failure.
270 1.1 christos */
271 1.1 christos count = count_mask_bits(mask, NULL);
272 1.1 christos if (count != found->maskbitcount && found->dupkey == NULL)
273 1.1 christos return (NULL);
274 1.1 christos
275 1.1 christos akey = (u_32_t *)addr;
276 1.1 christos if ((found->addrkey[found->offset] & found->maskkey[found->offset]) !=
277 1.1 christos akey[found->offset])
278 1.1 christos return NULL;
279 1.1 christos
280 1.1 christos if (found->dupkey != NULL) {
281 1.1 christos node = found;
282 1.1 christos while (node != NULL && node->maskbitcount != count)
283 1.1 christos node = node->dupkey;
284 1.1 christos if (node == NULL)
285 1.1 christos return (NULL);
286 1.1 christos found = node;
287 1.1 christos }
288 1.1 christos return found;
289 1.1 christos }
290 1.1 christos
291 1.1 christos
292 1.1 christos /* ------------------------------------------------------------------------ */
293 1.1 christos /* Function: ipf_rx_attach_mask */
294 1.1 christos /* Returns: Nil */
295 1.1 christos /* Parameters: node(I) - pointer to a radix tree node */
296 1.1 christos /* mask(I) - pointer to mask structure to add */
297 1.1 christos /* */
298 1.1 christos /* Add the netmask to the given node in an ordering where the most specific */
299 1.1 christos /* netmask is at the top of the list. */
300 1.1 christos /* ------------------------------------------------------------------------ */
301 1.1 christos static void
302 1.1 christos ipf_rx_attach_mask(node, mask)
303 1.1 christos ipf_rdx_node_t *node;
304 1.1 christos ipf_rdx_mask_t *mask;
305 1.1 christos {
306 1.1 christos ipf_rdx_mask_t **pm;
307 1.1 christos ipf_rdx_mask_t *m;
308 1.1 christos
309 1.1 christos for (pm = &node->masks; (m = *pm) != NULL; pm = &m->next)
310 1.1 christos if (m->maskbitcount < mask->maskbitcount)
311 1.1 christos break;
312 1.1 christos mask->next = *pm;
313 1.1 christos *pm = mask;
314 1.1 christos }
315 1.1 christos
316 1.1 christos
317 1.1 christos /* ------------------------------------------------------------------------ */
318 1.1 christos /* Function: ipf_rx_insert */
319 1.1 christos /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
320 1.1 christos /* added to the tree. */
321 1.1 christos /* Paramters: head(I) - pointer to tree head to add nodes to */
322 1.1 christos /* nodes(I) - pointer to radix nodes to be added */
323 1.1 christos /* dup(O) - set to 1 if node is a duplicate, else 0. */
324 1.1 christos /* */
325 1.1 christos /* Add the new radix tree entry that owns nodes[] to the tree given by head.*/
326 1.1 christos /* If there is already a matching key in the table, "dup" will be set to 1 */
327 1.1 christos /* and the existing node pointer returned if there is a complete key match. */
328 1.1 christos /* A complete key match is a matching of all key data that is presented by */
329 1.1 christos /* by the netmask. */
330 1.1 christos /* ------------------------------------------------------------------------ */
331 1.1 christos static ipf_rdx_node_t *
332 1.1 christos ipf_rx_insert(head, nodes, dup)
333 1.1 christos ipf_rdx_head_t *head;
334 1.1 christos ipf_rdx_node_t nodes[2];
335 1.1 christos int *dup;
336 1.1 christos {
337 1.1 christos ipf_rdx_mask_t **pmask;
338 1.1 christos ipf_rdx_node_t *node;
339 1.1 christos ipf_rdx_node_t *prev;
340 1.1 christos ipf_rdx_mask_t *mask;
341 1.1 christos ipf_rdx_node_t *cur;
342 1.1 christos u_32_t nodemask;
343 1.1 christos u_32_t *addr;
344 1.1 christos u_32_t *data;
345 1.1 christos int nodebits;
346 1.1 christos u_32_t *key;
347 1.1 christos u_32_t *end;
348 1.1 christos u_32_t bits;
349 1.1 christos int nodekey;
350 1.1 christos int nodeoff;
351 1.1 christos int nlen;
352 1.1 christos int len;
353 1.1 christos
354 1.1 christos addr = nodes[0].addrkey;
355 1.1 christos
356 1.1 christos node = ipf_rx_find_addr(head->root, addr);
357 1.1 christos len = ((addrfamily_t *)addr)->adf_len;
358 1.1 christos key = (u_32_t *)&((addrfamily_t *)addr)->adf_addr;
359 1.1 christos data= (u_32_t *)&((addrfamily_t *)node->addrkey)->adf_addr;
360 1.1 christos end = (u_32_t *)((u_char *)addr + len);
361 1.1 christos for (; key < end; data++, key++)
362 1.1 christos if (*key != *data)
363 1.1 christos break;
364 1.1 christos if (end == data) {
365 1.1 christos *dup = 1;
366 1.1 christos return (node); /* Equal keys */
367 1.1 christos }
368 1.1 christos *dup = 0;
369 1.1 christos
370 1.1 christos bits = (ntohl(*data) ^ ntohl(*key));
371 1.1 christos for (nlen = 0; bits != 0; nlen++) {
372 1.1 christos if ((bits & 0x80000000) != 0)
373 1.1 christos break;
374 1.1 christos bits <<= 1;
375 1.1 christos }
376 1.1 christos nlen += ADF_OFF_BITS;
377 1.1 christos nodes[1].index = nlen;
378 1.1 christos nodes[1].bitmask = htonl(0x80000000 >> (nlen & 0x1f));
379 1.1 christos
380 1.1 christos /*
381 1.1 christos * Walk through the tree and look for the correct place to attach
382 1.1 christos * this node. ipf_rx_fin_addr is not used here because the place
383 1.1 christos * to attach this node may be an internal node (same key, different
384 1.1 christos * netmask.) Additionally, the depth of the search is forcibly limited
385 1.1 christos * here to not exceed the netmask, so that a short netmask will be
386 1.1 christos * added higher up the tree even if there are lower branches.
387 1.1 christos */
388 1.1 christos cur = head->root;
389 1.1 christos key = nodes[0].addrkey;
390 1.1 christos do {
391 1.1 christos prev = cur;
392 1.1 christos if (key[cur->offset] & cur->bitmask) {
393 1.1 christos cur = cur->right;
394 1.1 christos } else {
395 1.1 christos cur = cur->left;
396 1.1 christos }
397 1.1 christos } while (nlen > (unsigned)cur->index);
398 1.1 christos
399 1.1 christos if ((key[prev->offset] & prev->bitmask) == 0) {
400 1.1 christos prev->left = &nodes[1];
401 1.1 christos } else {
402 1.1 christos prev->right = &nodes[1];
403 1.1 christos }
404 1.1 christos cur->parent = &nodes[1];
405 1.1 christos nodes[1].parent = prev;
406 1.1 christos if ((key[cur->offset] & nodes[1].bitmask) == 0) {
407 1.1 christos nodes[1].right = cur;
408 1.1 christos } else {
409 1.1 christos nodes[1].right = &nodes[0];
410 1.1 christos nodes[1].left = cur;
411 1.1 christos }
412 1.1 christos
413 1.1 christos nodeoff = nodes[0].offset;
414 1.1 christos nodekey = nodes[0].addrkey[nodeoff];
415 1.1 christos nodemask = nodes[0].lastmask;
416 1.1 christos nodebits = nodes[0].maskbitcount;
417 1.1 christos prev = NULL;
418 1.1 christos /*
419 1.1 christos * Find the node up the tree with the largest pattern that still
420 1.1 christos * matches the node being inserted to see if this mask can be
421 1.1 christos * moved there.
422 1.1 christos */
423 1.1 christos for (cur = nodes[1].parent; cur->root == 0; cur = cur->parent) {
424 1.1 christos if (cur->maskbitcount <= nodebits)
425 1.1 christos break;
426 1.1 christos if (((cur - 1)->addrkey[nodeoff] & nodemask) != nodekey)
427 1.1 christos break;
428 1.1 christos prev = cur;
429 1.1 christos }
430 1.1 christos
431 1.1 christos KMALLOC(mask, ipf_rdx_mask_t *);
432 1.1 christos if (mask == NULL)
433 1.1 christos return NULL;
434 1.1 christos bzero(mask, sizeof(*mask));
435 1.1 christos mask->next = NULL;
436 1.1 christos mask->node = &nodes[0];
437 1.1 christos mask->maskbitcount = nodebits;
438 1.1 christos mask->mask = nodes[0].maskkey;
439 1.1 christos nodes[0].mymask = mask;
440 1.1 christos
441 1.1 christos if (prev != NULL) {
442 1.1 christos ipf_rdx_mask_t *m;
443 1.1 christos
444 1.1 christos for (pmask = &prev->masks; (m = *pmask) != NULL;
445 1.1 christos pmask = &m->next) {
446 1.1 christos if (m->maskbitcount < nodebits)
447 1.1 christos break;
448 1.1 christos }
449 1.1 christos } else {
450 1.1 christos /*
451 1.1 christos * No higher up nodes qualify, so attach mask locally.
452 1.1 christos */
453 1.1 christos pmask = &nodes[0].masks;
454 1.1 christos }
455 1.1 christos mask->next = *pmask;
456 1.1 christos *pmask = mask;
457 1.1 christos
458 1.1 christos /*
459 1.1 christos * Search the mask list on each child to see if there are any masks
460 1.1 christos * there that can be moved up to this newly inserted node.
461 1.1 christos */
462 1.1 christos cur = nodes[1].right;
463 1.1 christos if (cur->root == 0) {
464 1.1 christos for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
465 1.1 christos if (mask->maskbitcount < nodebits) {
466 1.1 christos *pmask = mask->next;
467 1.1 christos ipf_rx_attach_mask(&nodes[0], mask);
468 1.1 christos } else {
469 1.1 christos pmask = &mask->next;
470 1.1 christos }
471 1.1 christos }
472 1.1 christos }
473 1.1 christos cur = nodes[1].left;
474 1.1 christos if (cur->root == 0 && cur != &nodes[0]) {
475 1.1 christos for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
476 1.1 christos if (mask->maskbitcount < nodebits) {
477 1.1 christos *pmask = mask->next;
478 1.1 christos ipf_rx_attach_mask(&nodes[0], mask);
479 1.1 christos } else {
480 1.1 christos pmask = &mask->next;
481 1.1 christos }
482 1.1 christos }
483 1.1 christos }
484 1.1 christos return (&nodes[0]);
485 1.1 christos }
486 1.1 christos
487 1.1 christos /* ------------------------------------------------------------------------ */
488 1.1 christos /* Function: ipf_rx_addroute */
489 1.1 christos /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
490 1.1 christos /* added to the tree. */
491 1.1 christos /* Paramters: head(I) - pointer to tree head to search */
492 1.1 christos /* addr(I) - address portion of "route" to add */
493 1.1 christos /* mask(I) - netmask portion of "route" to add */
494 1.1 christos /* nodes(I) - radix tree data nodes inside allocate structure */
495 1.1 christos /* */
496 1.1 christos /* Attempt to add a node to the radix tree. The key for the node is the */
497 1.1 christos /* (addr,mask). No memory allocation for the radix nodes themselves is */
498 1.1 christos /* performed here, the data structure that this radix node is being used to */
499 1.1 christos /* find is expected to house the node data itself however the call to */
500 1.1 christos /* ipf_rx_insert() will attempt to allocate memory in order for netmask to */
501 1.1 christos /* be promoted further up the tree. */
502 1.1 christos /* In this case, the ip_pool_node_t structure from ip_pool.h contains both */
503 1.1 christos /* the key material (addr,mask) and the radix tree nodes[]. */
504 1.1 christos /* */
505 1.1 christos /* The mechanics of inserting the node into the tree is handled by the */
506 1.1 christos /* function ipf_rx_insert() above. Here, the code deals with the case */
507 1.1 christos /* where the data to be inserted is a duplicate. */
508 1.1 christos /* ------------------------------------------------------------------------ */
509 1.1 christos ipf_rdx_node_t *
510 1.1 christos ipf_rx_addroute(head, addr, mask, nodes)
511 1.1 christos ipf_rdx_head_t *head;
512 1.1 christos addrfamily_t *addr, *mask;
513 1.1 christos ipf_rdx_node_t *nodes;
514 1.1 christos {
515 1.1 christos ipf_rdx_node_t *node;
516 1.1 christos ipf_rdx_node_t *prev;
517 1.1 christos ipf_rdx_node_t *x;
518 1.1 christos int dup;
519 1.1 christos
520 1.1 christos buildnodes(addr, mask, nodes);
521 1.1 christos x = ipf_rx_insert(head, nodes, &dup);
522 1.1 christos if (x == NULL)
523 1.1 christos return NULL;
524 1.1 christos
525 1.1 christos if (dup == 1) {
526 1.1 christos node = &nodes[0];
527 1.1 christos prev = NULL;
528 1.1 christos /*
529 1.1 christos * The duplicate list is kept sorted with the longest
530 1.1 christos * mask at the top, meaning that the most specific entry
531 1.1 christos * in the listis found first. This list thus allows for
532 1.1 christos * duplicates such as 128.128.0.0/32 and 128.128.0.0/16.
533 1.1 christos */
534 1.1 christos while ((x != NULL) && (x->maskbitcount > node->maskbitcount)) {
535 1.1 christos prev = x;
536 1.1 christos x = x->dupkey;
537 1.1 christos }
538 1.1 christos
539 1.1 christos /*
540 1.1 christos * Is it a complete duplicate? If so, return NULL and
541 1.1 christos * fail the insert. Otherwise, insert it into the list
542 1.1 christos * of netmasks active for this key.
543 1.1 christos */
544 1.1 christos if ((x != NULL) && (x->maskbitcount == node->maskbitcount))
545 1.1 christos return (NULL);
546 1.1 christos
547 1.1 christos if (prev != NULL) {
548 1.1 christos nodes[0].dupkey = x;
549 1.1 christos prev->dupkey = &nodes[0];
550 1.1 christos nodes[0].parent = prev;
551 1.1 christos if (x != NULL)
552 1.1 christos x->parent = &nodes[0];
553 1.1 christos } else {
554 1.1 christos nodes[0].dupkey = x->dupkey;
555 1.1 christos prev = x->parent;
556 1.1 christos nodes[0].parent = prev;
557 1.1 christos x->parent = &nodes[0];
558 1.1 christos if (prev->left == x)
559 1.1 christos prev->left = &nodes[0];
560 1.1 christos else
561 1.1 christos prev->right = &nodes[0];
562 1.1 christos }
563 1.1 christos }
564 1.1 christos
565 1.1 christos return &nodes[0];
566 1.1 christos }
567 1.1 christos
568 1.1 christos
569 1.1 christos /* ------------------------------------------------------------------------ */
570 1.1 christos /* Function: ipf_rx_delete */
571 1.1 christos /* Returns: ipf_rdx_node_t * - NULL on error, else node removed from */
572 1.1 christos /* the tree. */
573 1.1 christos /* Paramters: head(I) - pointer to tree head to search */
574 1.1 christos /* addr(I) - pointer to the address part of the key */
575 1.1 christos /* mask(I) - pointer to the netmask part of the key */
576 1.1 christos /* */
577 1.1 christos /* Search for an entry in the radix tree that is an exact match for (addr, */
578 1.1 christos /* mask) and remove it if it exists. In the case where (addr,mask) is a not */
579 1.1 christos /* a unique key, the tree structure itself is not changed - only the list */
580 1.1 christos /* of duplicate keys. */
581 1.1 christos /* ------------------------------------------------------------------------ */
582 1.1 christos ipf_rdx_node_t *
583 1.1 christos ipf_rx_delete(head, addr, mask)
584 1.1 christos ipf_rdx_head_t *head;
585 1.1 christos addrfamily_t *addr, *mask;
586 1.1 christos {
587 1.1 christos ipf_rdx_mask_t **pmask;
588 1.1 christos ipf_rdx_node_t *parent;
589 1.1 christos ipf_rdx_node_t *found;
590 1.1 christos ipf_rdx_node_t *prev;
591 1.1 christos ipf_rdx_node_t *node;
592 1.1 christos ipf_rdx_node_t *cur;
593 1.1 christos ipf_rdx_mask_t *m;
594 1.1 christos int count;
595 1.1 christos
596 1.1 christos found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
597 1.1 christos if (found->root == 1)
598 1.1 christos return NULL;
599 1.1 christos count = count_mask_bits(mask, NULL);
600 1.1 christos parent = found->parent;
601 1.1 christos if (found->dupkey != NULL) {
602 1.1 christos node = found;
603 1.1 christos while (node != NULL && node->maskbitcount != count)
604 1.1 christos node = node->dupkey;
605 1.1 christos if (node == NULL)
606 1.1 christos return (NULL);
607 1.1 christos if (node != found) {
608 1.1 christos /*
609 1.1 christos * Remove from the dupkey list. Here, "parent" is
610 1.1 christos * the previous node on the list (rather than tree)
611 1.1 christos * and "dupkey" is the next node on the list.
612 1.1 christos */
613 1.1 christos parent = node->parent;
614 1.1 christos parent->dupkey = node->dupkey;
615 1.1 christos node->dupkey->parent = parent;
616 1.1 christos } else {
617 1.1 christos /*
618 1.1 christos *
619 1.1 christos * When removing the top node of the dupkey list,
620 1.1 christos * the pointers at the top of the list that point
621 1.1 christos * to other tree nodes need to be preserved and
622 1.1 christos * any children must have their parent updated.
623 1.1 christos */
624 1.1 christos node = node->dupkey;
625 1.1 christos node->parent = found->parent;
626 1.1 christos node->right = found->right;
627 1.1 christos node->left = found->left;
628 1.1 christos found->right->parent = node;
629 1.1 christos found->left->parent = node;
630 1.1 christos if (parent->left == found)
631 1.1 christos parent->left = node;
632 1.1 christos else
633 1.1 christos parent->right= node;
634 1.1 christos }
635 1.1 christos } else {
636 1.1 christos if (count != found->maskbitcount)
637 1.1 christos return (NULL);
638 1.1 christos /*
639 1.1 christos * Remove the node from the tree and reconnect the subtree
640 1.1 christos * below.
641 1.1 christos */
642 1.1 christos /*
643 1.1 christos * If there is a tree to the left, look for something to
644 1.1 christos * attach in place of "found".
645 1.1 christos */
646 1.1 christos prev = found + 1;
647 1.1 christos if (parent != found + 1) {
648 1.1 christos cur = parent->parent;
649 1.1 christos if (cur->right == parent) {
650 1.1 christos if (prev->right != parent)
651 1.1 christos prev->right->parent = parent;
652 1.1 christos if (cur != prev) {
653 1.1 christos if (parent->left != parent - 1) {
654 1.1 christos cur->right = parent->left;
655 1.1 christos parent->left->parent = cur;
656 1.1 christos } else {
657 1.1 christos cur->right = parent - 1;
658 1.1 christos (parent - 1)->parent = cur;
659 1.1 christos }
660 1.1 christos }
661 1.1 christos
662 1.1 christos if (cur != prev) {
663 1.1 christos if (parent->left == found)
664 1.1 christos (parent - 1)->parent = parent;
665 1.1 christos }
666 1.1 christos if (prev->parent->right == prev) {
667 1.1 christos prev->parent->right = parent;
668 1.1 christos } else {
669 1.1 christos prev->parent->left = parent;
670 1.1 christos }
671 1.1 christos if (prev->left->index > 0) {
672 1.1 christos prev->left->parent = parent;
673 1.1 christos if (parent->left != found)
674 1.1 christos parent->right = parent->left;
675 1.1 christos parent->left = prev->left;
676 1.1 christos }
677 1.1 christos if (prev->right->index > 0) {
678 1.1 christos if (prev->right != parent) {
679 1.1 christos prev->right->parent = parent;
680 1.1 christos parent->right = prev->right;
681 1.1 christos } else if (parent->left->index < 0) {
682 1.1 christos parent->right = parent - 1;
683 1.1 christos }
684 1.1 christos } else if (parent->right == found) {
685 1.1 christos parent->right = parent - 1;
686 1.1 christos }
687 1.1 christos parent->parent = prev->parent;
688 1.1 christos } else {
689 1.1 christos parent->left = parent - 1;
690 1.1 christos
691 1.1 christos if (cur->parent->right == cur)
692 1.1 christos cur->parent->right = parent;
693 1.1 christos else
694 1.1 christos cur->parent->left = parent;
695 1.1 christos cur->right->parent = parent;
696 1.1 christos parent->parent = cur->parent;
697 1.1 christos parent->right = cur->right;
698 1.1 christos }
699 1.1 christos parent->bitmask = prev->bitmask;
700 1.1 christos parent->offset = prev->offset;
701 1.1 christos parent->index = prev->index;
702 1.1 christos } else {
703 1.1 christos /*
704 1.1 christos * We found an edge node.
705 1.1 christos */
706 1.1 christos cur = parent->parent;
707 1.1 christos if (cur->left == parent) {
708 1.1 christos if (parent->left == found) {
709 1.1 christos cur->left = parent->right;
710 1.1 christos parent->right->parent = cur;
711 1.1 christos } else {
712 1.1 christos cur->left = parent->left;
713 1.1 christos parent->left->parent = cur;
714 1.1 christos }
715 1.1 christos } else {
716 1.1 christos if (parent->right != found) {
717 1.1 christos cur->right = parent->right;
718 1.1 christos parent->right->parent = cur;
719 1.1 christos } else {
720 1.1 christos cur->right = parent->left;
721 1.1 christos prev->left->parent = cur;
722 1.1 christos }
723 1.1 christos }
724 1.1 christos }
725 1.1 christos }
726 1.1 christos
727 1.1 christos /*
728 1.1 christos * Remove mask associated with this node.
729 1.1 christos */
730 1.1 christos for (cur = parent; cur->root == 0; cur = cur->parent) {
731 1.1 christos ipf_rdx_mask_t **pm;
732 1.1 christos
733 1.1 christos if (cur->maskbitcount <= found->maskbitcount)
734 1.1 christos break;
735 1.1 christos if (((cur - 1)->addrkey[found->offset] & found->bitmask) !=
736 1.1 christos found->addrkey[found->offset])
737 1.1 christos break;
738 1.1 christos for (pm = &cur->masks; (m = *pm) != NULL; )
739 1.1 christos if (m->node == cur) {
740 1.1 christos *pm = m->next;
741 1.1 christos break;
742 1.1 christos } else {
743 1.1 christos pm = &m->next;
744 1.1 christos }
745 1.1 christos }
746 1.1 christos KFREE(found->mymask);
747 1.1 christos
748 1.1 christos /*
749 1.1 christos * Masks that have been brought up to this node from below need to
750 1.1 christos * be sent back down.
751 1.1 christos */
752 1.1 christos for (pmask = &parent->masks; (m = *pmask) != NULL; ) {
753 1.1 christos *pmask = m->next;
754 1.1 christos cur = m->node;
755 1.1 christos if (cur == found)
756 1.1 christos continue;
757 1.1 christos if (found->addrkey[cur->offset] & cur->lastmask) {
758 1.1 christos ipf_rx_attach_mask(parent->right, m);
759 1.1 christos } else if (parent->left != found) {
760 1.1 christos ipf_rx_attach_mask(parent->left, m);
761 1.1 christos }
762 1.1 christos }
763 1.1 christos
764 1.1 christos return (found);
765 1.1 christos }
766 1.1 christos
767 1.1 christos
768 1.1 christos /* ------------------------------------------------------------------------ */
769 1.1 christos /* Function: ipf_rx_walktree */
770 1.1 christos /* Returns: Nil */
771 1.1 christos /* Paramters: head(I) - pointer to tree head to search */
772 1.1 christos /* walker(I) - function to call for each node in the tree */
773 1.1 christos /* arg(I) - parameter to pass to walker, in addition to the */
774 1.1 christos /* node pointer */
775 1.1 christos /* */
776 1.1 christos /* A standard tree walking function except that it is iterative, rather */
777 1.1 christos /* than recursive and tracks the next node in case the "walker" function */
778 1.1 christos /* should happen to delete and free the current node. It thus goes without */
779 1.1 christos /* saying that the "walker" function is not permitted to cause any change */
780 1.1 christos /* in the validity of the data found at either the left or right child. */
781 1.1 christos /* ------------------------------------------------------------------------ */
782 1.1 christos void
783 1.1 christos ipf_rx_walktree(head, walker, arg)
784 1.1 christos ipf_rdx_head_t *head;
785 1.1 christos radix_walk_func_t walker;
786 1.1 christos void *arg;
787 1.1 christos {
788 1.1 christos ipf_rdx_node_t *next;
789 1.1 christos ipf_rdx_node_t *node = head->root;
790 1.1 christos ipf_rdx_node_t *base;
791 1.1 christos
792 1.1 christos while (node->index >= 0)
793 1.1 christos node = node->left;
794 1.1 christos
795 1.1 christos for (;;) {
796 1.1 christos base = node;
797 1.1 christos while ((node->parent->right == node) && (node->root == 0))
798 1.1 christos node = node->parent;
799 1.1 christos
800 1.1 christos for (node = node->parent->right; node->index >= 0; )
801 1.1 christos node = node->left;
802 1.1 christos next = node;
803 1.1 christos
804 1.1 christos for (node = base; node != NULL; node = base) {
805 1.1 christos base = node->dupkey;
806 1.1 christos if (node->root == 0)
807 1.1 christos walker(node, arg);
808 1.1 christos }
809 1.1 christos node = next;
810 1.1 christos if (node->root)
811 1.1 christos return;
812 1.1 christos }
813 1.1 christos }
814 1.1 christos
815 1.1 christos
816 1.1 christos /* ------------------------------------------------------------------------ */
817 1.1 christos /* Function: ipf_rx_inithead */
818 1.1 christos /* Returns: int - 0 = success, else failure */
819 1.1 christos /* Paramters: softr(I) - pointer to radix context */
820 1.1 christos /* headp(O) - location for where to store allocated tree head */
821 1.1 christos /* */
822 1.1 christos /* This function allocates and initialises a radix tree head structure. */
823 1.1 christos /* As a traditional radix tree, node 0 is used as the "0" sentinel and node */
824 1.1 christos /* "2" is used as the all ones sentinel, leaving node "1" as the root from */
825 1.1 christos /* which the tree is hung with node "0" on its left and node "2" to the */
826 1.1 christos /* right. The context, "softr", is used here to provide a common source of */
827 1.1 christos /* the zeroes and ones data rather than have one per head. */
828 1.1 christos /* ------------------------------------------------------------------------ */
829 1.1 christos int
830 1.1 christos ipf_rx_inithead(softr, headp)
831 1.1 christos radix_softc_t *softr;
832 1.1 christos ipf_rdx_head_t **headp;
833 1.1 christos {
834 1.1 christos ipf_rdx_head_t *ptr;
835 1.1 christos ipf_rdx_node_t *node;
836 1.1 christos
837 1.1 christos KMALLOC(ptr, ipf_rdx_head_t *);
838 1.1 christos *headp = ptr;
839 1.1 christos if (ptr == NULL)
840 1.1 christos return -1;
841 1.1 christos bzero(ptr, sizeof(*ptr));
842 1.1 christos node = ptr->nodes;
843 1.1 christos ptr->root = node + 1;
844 1.1 christos node[0].index = ADF_OFF_BITS;
845 1.1 christos node[0].index = -1 - node[0].index;
846 1.1 christos node[1].index = ADF_OFF_BITS;
847 1.1 christos node[2].index = node[0].index;
848 1.1 christos node[0].parent = node + 1;
849 1.1 christos node[1].parent = node + 1;
850 1.1 christos node[2].parent = node + 1;
851 1.1 christos node[1].bitmask = htonl(0x80000000);
852 1.1 christos node[0].root = 1;
853 1.1 christos node[1].root = 1;
854 1.1 christos node[2].root = 1;
855 1.1 christos node[0].offset = ADF_OFF_BITS >> 5;
856 1.1 christos node[1].offset = ADF_OFF_BITS >> 5;
857 1.1 christos node[2].offset = ADF_OFF_BITS >> 5;
858 1.1 christos node[1].left = &node[0];
859 1.1 christos node[1].right = &node[2];
860 1.1 christos node[0].addrkey = (u_32_t *)softr->zeros;
861 1.1 christos node[2].addrkey = (u_32_t *)softr->ones;
862 1.1 christos #ifdef RDX_DEBUG
863 1.1 christos (void) strcpy(node[0].name, "0_ROOT");
864 1.1 christos (void) strcpy(node[1].name, "1_ROOT");
865 1.1 christos (void) strcpy(node[2].name, "2_ROOT");
866 1.1 christos #endif
867 1.1 christos
868 1.1 christos ptr->addaddr = ipf_rx_addroute;
869 1.1 christos ptr->deladdr = ipf_rx_delete;
870 1.1 christos ptr->lookup = ipf_rx_lookup;
871 1.1 christos ptr->matchaddr = ipf_rx_match;
872 1.1 christos ptr->walktree = ipf_rx_walktree;
873 1.1 christos return 0;
874 1.1 christos }
875 1.1 christos
876 1.1 christos void
877 1.1 christos ipf_rx_freehead(head)
878 1.1 christos ipf_rdx_head_t *head;
879 1.1 christos {
880 1.1 christos KFREE(head);
881 1.1 christos }
882 1.1 christos
883 1.1 christos void *
884 1.1 christos ipf_rx_create()
885 1.1 christos {
886 1.1 christos radix_softc_t *softr;
887 1.1 christos
888 1.1 christos KMALLOC(softr, radix_softc_t *);
889 1.1 christos if (softr == NULL)
890 1.1 christos return NULL;
891 1.1 christos bzero((char *)softr, sizeof(*softr));
892 1.1 christos
893 1.1 christos return softr;
894 1.1 christos }
895 1.1 christos
896 1.1 christos int
897 1.1 christos ipf_rx_init(ctx)
898 1.1 christos void *ctx;
899 1.1 christos {
900 1.1 christos radix_softc_t *softr = ctx;
901 1.1 christos
902 1.1 christos KMALLOCS(softr->zeros, u_char *, 3 * sizeof(addrfamily_t));
903 1.1 christos if (softr->zeros == NULL)
904 1.1 christos return (-1);
905 1.1 christos softr->ones = softr->zeros + sizeof(addrfamily_t);
906 1.1 christos memset(softr->ones, 0xff, sizeof(addrfamily_t));
907 1.1 christos return (0);
908 1.1 christos }
909 1.1 christos
910 1.1 christos void
911 1.1 christos ipf_rx_destroy(ctx)
912 1.1 christos void *ctx;
913 1.1 christos {
914 1.1 christos radix_softc_t *softr = ctx;
915 1.1 christos
916 1.1 christos if (softr->zeros != NULL)
917 1.1 christos KFREES(softr->zeros, 3 * sizeof(addrfamily_t));
918 1.1 christos KFREE(softr);
919 1.1 christos }
920 1.1 christos
921 1.1 christos /* ====================================================================== */
922 1.1 christos
923 1.1 christos #ifdef RDX_DEBUG
924 1.1 christos
925 1.1 christos #define NAME(x) ((x)->index < 0 ? (x)->name : (x)->name)
926 1.1 christos #define GNAME(y) ((y) == NULL ? "NULL" : NAME(y))
927 1.1 christos
928 1.1 christos typedef struct myst {
929 1.1 christos struct ipf_rdx_node nodes[2];
930 1.1 christos addrfamily_t dst;
931 1.1 christos addrfamily_t mask;
932 1.1 christos struct myst *next;
933 1.1 christos int printed;
934 1.1 christos } myst_t;
935 1.1 christos
936 1.1 christos static int nodecount = 0;
937 1.1 christos myst_t *myst_top = NULL;
938 1.1 christos
939 1.1 christos void add_addr(ipf_rdx_head_t *, int , int);
940 1.1 christos void checktree(ipf_rdx_head_t *);
941 1.1 christos void delete_addr(ipf_rdx_head_t *rnh, int item);
942 1.1 christos void dumptree(ipf_rdx_head_t *rnh);
943 1.1 christos void nodeprinter(ipf_rdx_node_t *, void *);
944 1.1 christos void printroots(ipf_rdx_head_t *);
945 1.1 christos void random_add(ipf_rdx_head_t *);
946 1.1 christos void random_delete(ipf_rdx_head_t *);
947 1.1 christos void test_addr(ipf_rdx_head_t *rnh, int pref, u_32_t addr, int);
948 1.1 christos
949 1.1 christos static void
950 1.1 christos ipf_rx_freenode(node, arg)
951 1.1 christos ipf_rdx_node_t *node;
952 1.1 christos void *arg;
953 1.1 christos {
954 1.1 christos ipf_rdx_head_t *head = arg;
955 1.1 christos ipf_rdx_node_t *rv;
956 1.1 christos myst_t *stp;
957 1.1 christos
958 1.1 christos stp = (myst_t *)node;
959 1.1 christos rv = ipf_rx_delete(head, &stp->dst, &stp->mask);
960 1.1 christos if (rv != NULL) {
961 1.1 christos free(rv);
962 1.1 christos }
963 1.1 christos }
964 1.1 christos
965 1.1 christos void
966 1.1 christos nodeprinter(node, arg)
967 1.1 christos ipf_rdx_node_t *node;
968 1.1 christos void *arg;
969 1.1 christos {
970 1.1 christos myst_t *stp = (myst_t *)node;
971 1.1 christos
972 1.1 christos printf("Node %-9.9s L %-9.9s R %-9.9s P %9.9s/%-9.9s %s/%d\n",
973 1.1 christos node[0].name,
974 1.1 christos GNAME(node[1].left), GNAME(node[1].right),
975 1.1 christos GNAME(node[0].parent), GNAME(node[1].parent),
976 1.1 christos inet_ntoa(stp->dst.adf_addr.in4), node[0].maskbitcount);
977 1.1 christos }
978 1.1 christos
979 1.1 christos void
980 1.1 christos printnode(stp)
981 1.1 christos myst_t *stp;
982 1.1 christos {
983 1.1 christos ipf_rdx_node_t *node = &stp->nodes[0];
984 1.1 christos
985 1.1 christos if (stp->nodes[0].index > 0)
986 1.1 christos stp = (myst_t *)&stp->nodes[-1];
987 1.1 christos
988 1.1 christos printf("Node %-9.9s ", node[0].name);
989 1.1 christos printf("L %-9.9s ", GNAME(node[1].left));
990 1.1 christos printf("R %-9.9s ", GNAME(node[1].right));
991 1.1 christos printf("P %9.9s", GNAME(node[0].parent));
992 1.1 christos printf("/%-9.9s ", GNAME(node[1].parent));
993 1.1 christos printf("%s\n", inet_ntoa(stp->dst.adf_addr.in4));
994 1.1 christos }
995 1.1 christos
996 1.1 christos char *ttable[22][3] = {
997 1.1 christos { "127.192.0.0", "255.255.255.0", "d" },
998 1.1 christos { "127.128.0.0", "255.255.255.0", "d" },
999 1.1 christos { "127.96.0.0", "255.255.255.0", "d" },
1000 1.1 christos { "127.80.0.0", "255.255.255.0", "d" },
1001 1.1 christos { "127.72.0.0", "255.255.255.0", "d" },
1002 1.1 christos { "127.64.0.0", "255.255.255.0", "d" },
1003 1.1 christos { "127.56.0.0", "255.255.255.0", "d" },
1004 1.1 christos { "127.48.0.0", "255.255.255.0", "d" },
1005 1.1 christos { "127.40.0.0", "255.255.255.0", "d" },
1006 1.1 christos { "127.32.0.0", "255.255.255.0", "d" },
1007 1.1 christos { "127.24.0.0", "255.255.255.0", "d" },
1008 1.1 christos { "127.16.0.0", "255.255.255.0", "d" },
1009 1.1 christos { "127.8.0.0", "255.255.255.0", "d" },
1010 1.1 christos { "124.0.0.0", "255.0.0.0", "d" },
1011 1.1 christos { "125.0.0.0", "255.0.0.0", "d" },
1012 1.1 christos { "126.0.0.0", "255.0.0.0", "d" },
1013 1.1 christos { "127.0.0.0", "255.0.0.0", "d" },
1014 1.1 christos { "10.0.0.0", "255.0.0.0", "d" },
1015 1.1 christos { "128.250.0.0", "255.255.0.0", "d" },
1016 1.1 christos { "192.168.0.0", "255.255.0.0", "d" },
1017 1.1 christos { "192.168.1.0", "255.255.255.0", "d" },
1018 1.1 christos { NULL, NULL }
1019 1.1 christos };
1020 1.1 christos
1021 1.1 christos char *mtable[15][1] = {
1022 1.1 christos { "9.0.0.0" },
1023 1.1 christos { "9.0.0.1" },
1024 1.1 christos { "11.0.0.0" },
1025 1.1 christos { "11.0.0.1" },
1026 1.1 christos { "127.0.0.1" },
1027 1.1 christos { "127.0.1.0" },
1028 1.1 christos { "255.255.255.0" },
1029 1.1 christos { "126.0.0.1" },
1030 1.1 christos { "128.251.0.0" },
1031 1.1 christos { "128.251.0.1" },
1032 1.1 christos { "128.251.255.255" },
1033 1.1 christos { "129.250.0.0" },
1034 1.1 christos { "129.250.0.1" },
1035 1.1 christos { "192.168.255.255" },
1036 1.1 christos { NULL }
1037 1.1 christos };
1038 1.1 christos
1039 1.1 christos int forder[22] = {
1040 1.1 christos 14, 13, 12, 5, 10, 3, 19, 7, 4, 20, 8,
1041 1.1 christos 2, 17, 9, 16, 11, 15, 1, 6, 18, 0, 21
1042 1.1 christos };
1043 1.1 christos
1044 1.1 christos void
1045 1.1 christos printroots(rnh)
1046 1.1 christos ipf_rdx_head_t *rnh;
1047 1.1 christos {
1048 1.1 christos printf("Root.0.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1049 1.1 christos GNAME(&rnh->nodes[0]),
1050 1.1 christos rnh->nodes[0].index, GNAME(rnh->nodes[0].parent),
1051 1.1 christos GNAME(rnh->nodes[0].left), GNAME(rnh->nodes[0].right));
1052 1.1 christos printf("Root.1.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1053 1.1 christos GNAME(&rnh->nodes[1]),
1054 1.1 christos rnh->nodes[1].index, GNAME(rnh->nodes[1].parent),
1055 1.1 christos GNAME(rnh->nodes[1].left), GNAME(rnh->nodes[1].right));
1056 1.1 christos printf("Root.2.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
1057 1.1 christos GNAME(&rnh->nodes[2]),
1058 1.1 christos rnh->nodes[2].index, GNAME(rnh->nodes[2].parent),
1059 1.1 christos GNAME(rnh->nodes[2].left), GNAME(rnh->nodes[2].right));
1060 1.1 christos }
1061 1.1 christos
1062 1.1 christos int
1063 1.1 christos main(int argc, char *argv[])
1064 1.1 christos {
1065 1.1 christos ipf_rdx_head_t *rnh;
1066 1.1 christos radix_softc_t *ctx;
1067 1.1 christos int j;
1068 1.1 christos int i;
1069 1.1 christos
1070 1.1 christos rnh = NULL;
1071 1.1 christos
1072 1.1 christos ctx = ipf_rx_create();
1073 1.1 christos ipf_rx_init(ctx);
1074 1.1 christos ipf_rx_inithead(ctx, &rnh);
1075 1.1 christos
1076 1.1 christos printf("=== ADD-0 ===\n");
1077 1.1 christos for (i = 0; ttable[i][0] != NULL; i++) {
1078 1.1 christos add_addr(rnh, i, i);
1079 1.1 christos checktree(rnh);
1080 1.1 christos }
1081 1.1 christos ipf_rx_walktree(rnh, nodeprinter, NULL);
1082 1.1 christos printf("=== DELETE-0 ===\n");
1083 1.1 christos for (i = 0; ttable[i][0] != NULL; i++) {
1084 1.1 christos delete_addr(rnh, i);
1085 1.1 christos ipf_rx_walktree(rnh, nodeprinter, NULL);
1086 1.1 christos }
1087 1.1 christos printf("=== ADD-1 ===\n");
1088 1.1 christos for (i = 0; ttable[i][0] != NULL; i++) {
1089 1.1 christos add_addr(rnh, i, forder[i]);
1090 1.1 christos checktree(rnh);
1091 1.1 christos }
1092 1.1 christos printroots(rnh);
1093 1.1 christos dumptree(rnh);
1094 1.1 christos ipf_rx_walktree(rnh, nodeprinter, NULL);
1095 1.1 christos printf("=== TEST-1 ===\n");
1096 1.1 christos for (i = 0; ttable[i][0] != NULL; i++) {
1097 1.1 christos test_addr(rnh, i, inet_addr(ttable[i][0]), -1);
1098 1.1 christos }
1099 1.1 christos
1100 1.1 christos printf("=== TEST-2 ===\n");
1101 1.1 christos for (i = 0; mtable[i][0] != NULL; i++) {
1102 1.1 christos test_addr(rnh, i, inet_addr(mtable[i][0]), -1);
1103 1.1 christos }
1104 1.1 christos printf("=== DELETE-1 ===\n");
1105 1.1 christos for (i = 0; ttable[i][0] != NULL; i++) {
1106 1.1 christos if (ttable[i][2][0] != 'd')
1107 1.1 christos continue;
1108 1.1 christos delete_addr(rnh, i);
1109 1.1 christos for (j = 0; ttable[j][0] != NULL; j++) {
1110 1.1 christos test_addr(rnh, i, inet_addr(ttable[j][0]), 3);
1111 1.1 christos }
1112 1.1 christos ipf_rx_walktree(rnh, nodeprinter, NULL);
1113 1.1 christos }
1114 1.1 christos
1115 1.1 christos printroots(rnh);
1116 1.1 christos dumptree(rnh);
1117 1.1 christos
1118 1.1 christos printf("=== ADD-2 ===\n");
1119 1.1 christos random_add(rnh);
1120 1.1 christos checktree(rnh);
1121 1.1 christos printroots(rnh);
1122 1.1 christos dumptree(rnh);
1123 1.1 christos ipf_rx_walktree(rnh, nodeprinter, NULL);
1124 1.1 christos printf("=== DELETE-2 ===\n");
1125 1.1 christos random_delete(rnh);
1126 1.1 christos checktree(rnh);
1127 1.1 christos printroots(rnh);
1128 1.1 christos dumptree(rnh);
1129 1.1 christos
1130 1.1 christos ipf_rx_walktree(rnh, ipf_rx_freenode, rnh);
1131 1.1 christos
1132 1.1 christos return 0;
1133 1.1 christos }
1134 1.1 christos
1135 1.1 christos void
1136 1.1 christos dumptree(rnh)
1137 1.1 christos ipf_rdx_head_t *rnh;
1138 1.1 christos {
1139 1.1 christos myst_t *stp;
1140 1.1 christos
1141 1.1 christos printf("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");
1142 1.1 christos for (stp = myst_top; stp; stp = stp->next)
1143 1.1 christos printnode(stp);
1144 1.1 christos printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
1145 1.1 christos }
1146 1.1 christos
1147 1.1 christos void
1148 1.1 christos test_addr(rnh, pref, addr, limit)
1149 1.1 christos ipf_rdx_head_t *rnh;
1150 1.1 christos int pref;
1151 1.1 christos u_32_t addr;
1152 1.1 christos {
1153 1.1 christos static int extras[14] = { 0, -1, 1, 3, 5, 8, 9,
1154 1.1 christos 15, 16, 19, 255, 256, 65535, 65536
1155 1.1 christos };
1156 1.1 christos ipf_rdx_node_t *rn;
1157 1.1 christos addrfamily_t af;
1158 1.1 christos myst_t *stp;
1159 1.1 christos int i;
1160 1.1 christos
1161 1.1 christos memset(&af, 0, sizeof(af));
1162 1.1 christos af.adf_len = sizeof(af.adf_addr);
1163 1.1 christos if (limit < 0 || limit > 14)
1164 1.1 christos limit = 14;
1165 1.1 christos
1166 1.1 christos for (i = 0; i < limit; i++) {
1167 1.1 christos af.adf_addr.in4.s_addr = htonl(ntohl(addr) + extras[i]);
1168 1.1 christos printf("%d.%d.LOOKUP(%s)", pref, i, inet_ntoa(af.adf_addr.in4));
1169 1.1 christos rn = ipf_rx_match(rnh, &af);
1170 1.1 christos stp = (myst_t *)rn;
1171 1.1 christos printf(" = %s (%s/%d)\n", GNAME(rn),
1172 1.1 christos rn ? inet_ntoa(stp->dst.adf_addr.in4) : "NULL",
1173 1.1 christos rn ? rn->maskbitcount : 0);
1174 1.1 christos }
1175 1.1 christos }
1176 1.1 christos
1177 1.1 christos void
1178 1.1 christos delete_addr(rnh, item)
1179 1.1 christos ipf_rdx_head_t *rnh;
1180 1.1 christos int item;
1181 1.1 christos {
1182 1.1 christos ipf_rdx_node_t *rn;
1183 1.1 christos addrfamily_t mask;
1184 1.1 christos addrfamily_t af;
1185 1.1 christos myst_t **pstp;
1186 1.1 christos myst_t *stp;
1187 1.1 christos
1188 1.1 christos memset(&af, 0, sizeof(af));
1189 1.1 christos memset(&mask, 0, sizeof(mask));
1190 1.1 christos af.adf_family = AF_INET;
1191 1.1 christos af.adf_len = sizeof(af.adf_addr);
1192 1.1 christos mask.adf_len = sizeof(mask.adf_addr);
1193 1.1 christos
1194 1.1 christos af.adf_addr.in4.s_addr = inet_addr(ttable[item][0]);
1195 1.1 christos mask.adf_addr.in4.s_addr = inet_addr(ttable[item][1]);
1196 1.1 christos printf("DELETE(%s)\n", inet_ntoa(af.adf_addr.in4));
1197 1.1 christos rn = ipf_rx_delete(rnh, &af, &mask);
1198 1.1 christos printf("%d.delete(%s) = %s\n", item,
1199 1.1 christos inet_ntoa(af.adf_addr.in4), GNAME(rn));
1200 1.1 christos
1201 1.1 christos for (pstp = &myst_top; (stp = *pstp) != NULL; pstp = &stp->next)
1202 1.1 christos if (stp == (myst_t *)rn)
1203 1.1 christos break;
1204 1.1 christos *pstp = stp->next;
1205 1.1 christos free(stp);
1206 1.1 christos nodecount--;
1207 1.1 christos checktree(rnh);
1208 1.1 christos }
1209 1.1 christos
1210 1.1 christos void
1211 1.1 christos add_addr(rnh, n, item)
1212 1.1 christos ipf_rdx_head_t *rnh;
1213 1.1 christos int n, item;
1214 1.1 christos {
1215 1.1 christos ipf_rdx_node_t *rn;
1216 1.1 christos myst_t *stp;
1217 1.1 christos
1218 1.1 christos stp = calloc(1, sizeof(*stp));
1219 1.1 christos rn = (ipf_rdx_node_t *)stp;
1220 1.1 christos stp->dst.adf_family = AF_INET;
1221 1.1 christos stp->dst.adf_len = sizeof(stp->dst.adf_addr);
1222 1.1 christos stp->dst.adf_addr.in4.s_addr = inet_addr(ttable[item][0]);
1223 1.1 christos memset(&stp->mask, 0xff, offsetof(addrfamily_t, adf_addr));
1224 1.1 christos stp->mask.adf_len = sizeof(stp->mask.adf_addr);
1225 1.1 christos stp->mask.adf_addr.in4.s_addr = inet_addr(ttable[item][1]);
1226 1.1 christos stp->next = myst_top;
1227 1.1 christos myst_top = stp;
1228 1.1 christos (void) sprintf(rn[0].name, "_BORN.0");
1229 1.1 christos (void) sprintf(rn[1].name, "_BORN.1");
1230 1.1 christos rn = ipf_rx_addroute(rnh, &stp->dst, &stp->mask, stp->nodes);
1231 1.1 christos (void) sprintf(rn[0].name, "%d_NODE.0", item);
1232 1.1 christos (void) sprintf(rn[1].name, "%d_NODE.1", item);
1233 1.1 christos printf("ADD %d/%d %s/%s\n", n, item, rn[0].name, rn[1].name);
1234 1.1 christos nodecount++;
1235 1.1 christos checktree(rnh);
1236 1.1 christos }
1237 1.1 christos
1238 1.1 christos void
1239 1.1 christos checktree(ipf_rdx_head_t *head)
1240 1.1 christos {
1241 1.1 christos myst_t *s1;
1242 1.1 christos ipf_rdx_node_t *rn;
1243 1.1 christos
1244 1.1 christos if (nodecount <= 1)
1245 1.1 christos return;
1246 1.1 christos
1247 1.1 christos for (s1 = myst_top; s1 != NULL; s1 = s1->next) {
1248 1.1 christos int fault = 0;
1249 1.1 christos rn = &s1->nodes[1];
1250 1.1 christos if (rn->right->parent != rn)
1251 1.1 christos fault |= 1;
1252 1.1 christos if (rn->left->parent != rn)
1253 1.1 christos fault |= 2;
1254 1.1 christos if (rn->parent->left != rn && rn->parent->right != rn)
1255 1.1 christos fault |= 4;
1256 1.1 christos if (fault != 0) {
1257 1.1 christos printf("FAULT %#x %s\n", fault, rn->name);
1258 1.1 christos printroots(head);
1259 1.1 christos dumptree(head);
1260 1.1 christos ipf_rx_walktree(head, nodeprinter, NULL);
1261 1.1 christos }
1262 1.1 christos }
1263 1.1 christos }
1264 1.1 christos
1265 1.1 christos int *
1266 1.1 christos randomize(int *pnitems)
1267 1.1 christos {
1268 1.1 christos int *order;
1269 1.1 christos int nitems;
1270 1.1 christos int choice;
1271 1.1 christos int j;
1272 1.1 christos int i;
1273 1.1 christos
1274 1.1 christos nitems = sizeof(ttable) / sizeof(ttable[0]);
1275 1.1 christos *pnitems = nitems;
1276 1.1 christos order = calloc(nitems, sizeof(*order));
1277 1.1 christos srandom(getpid() * time(NULL));
1278 1.1 christos memset(order, 0xff, nitems * sizeof(*order));
1279 1.1 christos order[21] = 21;
1280 1.1 christos for (i = 0; i < nitems - 1; i++) {
1281 1.1 christos do {
1282 1.1 christos choice = rand() % (nitems - 1);
1283 1.1 christos for (j = 0; j < nitems; j++)
1284 1.1 christos if (order[j] == choice)
1285 1.1 christos break;
1286 1.1 christos } while (j != nitems);
1287 1.1 christos order[i] = choice;
1288 1.1 christos }
1289 1.1 christos
1290 1.1 christos return order;
1291 1.1 christos }
1292 1.1 christos
1293 1.1 christos void
1294 1.1 christos random_add(rnh)
1295 1.1 christos ipf_rdx_head_t *rnh;
1296 1.1 christos {
1297 1.1 christos int *order;
1298 1.1 christos int nitems;
1299 1.1 christos int i;
1300 1.1 christos
1301 1.1 christos order = randomize(&nitems);
1302 1.1 christos
1303 1.1 christos for (i = 0; i < nitems - 1; i++) {
1304 1.1 christos add_addr(rnh, i, order[i]);
1305 1.1 christos checktree(rnh);
1306 1.1 christos }
1307 1.1 christos }
1308 1.1 christos
1309 1.1 christos void
1310 1.1 christos random_delete(rnh)
1311 1.1 christos ipf_rdx_head_t *rnh;
1312 1.1 christos {
1313 1.1 christos int *order;
1314 1.1 christos int nitems;
1315 1.1 christos int i;
1316 1.1 christos
1317 1.1 christos order = randomize(&nitems);
1318 1.1 christos
1319 1.1 christos for (i = 0; i < nitems - 1; i++) {
1320 1.1 christos delete_addr(rnh, i);
1321 1.1 christos checktree(rnh);
1322 1.1 christos }
1323 1.1 christos }
1324 1.1 christos #endif /* RDX_DEBUG */
1325