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