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