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