1 1.1 christos /* $NetBSD: radix.c,v 1.1 2024/02/18 20:57:50 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 1.1 christos * 6 1.1 christos * SPDX-License-Identifier: MPL-2.0 7 1.1 christos * 8 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public 9 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this 10 1.1 christos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 1.1 christos * 12 1.1 christos * See the COPYRIGHT file distributed with this work for additional 13 1.1 christos * information regarding copyright ownership. 14 1.1 christos */ 15 1.1 christos 16 1.1 christos /* 17 1.1 christos * This source was adapted from MRT's RCS Ids: 18 1.1 christos * Id: radix.c,v 1.10.2.1 1999/11/29 05:16:24 masaki Exp 19 1.1 christos * Id: prefix.c,v 1.37.2.9 2000/03/10 02:53:19 labovit Exp 20 1.1 christos */ 21 1.1 christos 22 1.1 christos #include <inttypes.h> 23 1.1 christos 24 1.1 christos #include <isc/mem.h> 25 1.1 christos #include <isc/radix.h> 26 1.1 christos #include <isc/types.h> 27 1.1 christos #include <isc/util.h> 28 1.1 christos 29 1.1 christos #define BIT_TEST(f, b) (((f) & (b)) != 0) 30 1.1 christos 31 1.1 christos static isc_result_t 32 1.1 christos _new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family, void *dest, 33 1.1 christos int bitlen); 34 1.1 christos 35 1.1 christos static void 36 1.1 christos _deref_prefix(isc_prefix_t *prefix); 37 1.1 christos 38 1.1 christos static isc_result_t 39 1.1 christos _ref_prefix(isc_mem_t *mctx, isc_prefix_t **target, isc_prefix_t *prefix); 40 1.1 christos 41 1.1 christos static int 42 1.1 christos _comp_with_mask(void *addr, void *dest, u_int mask); 43 1.1 christos 44 1.1 christos static void 45 1.1 christos _clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func); 46 1.1 christos 47 1.1 christos static isc_result_t 48 1.1 christos _new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family, void *dest, 49 1.1 christos int bitlen) { 50 1.1 christos isc_prefix_t *prefix; 51 1.1 christos 52 1.1 christos REQUIRE(target != NULL); 53 1.1 christos 54 1.1 christos if (family != AF_INET6 && family != AF_INET && family != AF_UNSPEC) { 55 1.1 christos return (ISC_R_NOTIMPLEMENTED); 56 1.1 christos } 57 1.1 christos 58 1.1 christos prefix = isc_mem_get(mctx, sizeof(isc_prefix_t)); 59 1.1 christos 60 1.1 christos if (family == AF_INET6) { 61 1.1 christos prefix->bitlen = (bitlen >= 0) ? bitlen : 128; 62 1.1 christos memmove(&prefix->add.sin6, dest, 16); 63 1.1 christos } else { 64 1.1 christos /* AF_UNSPEC is "any" or "none"--treat it as AF_INET */ 65 1.1 christos prefix->bitlen = (bitlen >= 0) ? bitlen : 32; 66 1.1 christos memmove(&prefix->add.sin, dest, 4); 67 1.1 christos } 68 1.1 christos 69 1.1 christos prefix->family = family; 70 1.1 christos prefix->mctx = NULL; 71 1.1 christos isc_mem_attach(mctx, &prefix->mctx); 72 1.1 christos 73 1.1 christos isc_refcount_init(&prefix->refcount, 1); 74 1.1 christos 75 1.1 christos *target = prefix; 76 1.1 christos return (ISC_R_SUCCESS); 77 1.1 christos } 78 1.1 christos 79 1.1 christos static void 80 1.1 christos _deref_prefix(isc_prefix_t *prefix) { 81 1.1 christos if (prefix != NULL) { 82 1.1 christos if (isc_refcount_decrement(&prefix->refcount) == 1) { 83 1.1 christos isc_refcount_destroy(&prefix->refcount); 84 1.1 christos isc_mem_putanddetach(&prefix->mctx, prefix, 85 1.1 christos sizeof(isc_prefix_t)); 86 1.1 christos } 87 1.1 christos } 88 1.1 christos } 89 1.1 christos 90 1.1 christos static isc_result_t 91 1.1 christos _ref_prefix(isc_mem_t *mctx, isc_prefix_t **target, isc_prefix_t *prefix) { 92 1.1 christos INSIST(prefix != NULL); 93 1.1 christos INSIST((prefix->family == AF_INET && prefix->bitlen <= 32) || 94 1.1 christos (prefix->family == AF_INET6 && prefix->bitlen <= 128) || 95 1.1 christos (prefix->family == AF_UNSPEC && prefix->bitlen == 0)); 96 1.1 christos REQUIRE(target != NULL && *target == NULL); 97 1.1 christos 98 1.1 christos /* 99 1.1 christos * If this prefix is a static allocation, copy it into new memory. 100 1.1 christos * (Note, the refcount still has to be destroyed by the calling 101 1.1 christos * routine.) 102 1.1 christos */ 103 1.1 christos if (isc_refcount_current(&prefix->refcount) == 0) { 104 1.1 christos isc_result_t ret; 105 1.1 christos ret = _new_prefix(mctx, target, prefix->family, &prefix->add, 106 1.1 christos prefix->bitlen); 107 1.1 christos return (ret); 108 1.1 christos } 109 1.1 christos 110 1.1 christos isc_refcount_increment(&prefix->refcount); 111 1.1 christos 112 1.1 christos *target = prefix; 113 1.1 christos return (ISC_R_SUCCESS); 114 1.1 christos } 115 1.1 christos 116 1.1 christos static int 117 1.1 christos _comp_with_mask(void *addr, void *dest, u_int mask) { 118 1.1 christos /* Mask length of zero matches everything */ 119 1.1 christos if (mask == 0) { 120 1.1 christos return (1); 121 1.1 christos } 122 1.1 christos 123 1.1 christos if (memcmp(addr, dest, mask / 8) == 0) { 124 1.1 christos u_int n = mask / 8; 125 1.1 christos u_int m = ((~0U) << (8 - (mask % 8))); 126 1.1 christos 127 1.1 christos if ((mask % 8) == 0 || 128 1.1 christos (((u_char *)addr)[n] & m) == (((u_char *)dest)[n] & m)) 129 1.1 christos { 130 1.1 christos return (1); 131 1.1 christos } 132 1.1 christos } 133 1.1 christos return (0); 134 1.1 christos } 135 1.1 christos 136 1.1 christos isc_result_t 137 1.1 christos isc_radix_create(isc_mem_t *mctx, isc_radix_tree_t **target, int maxbits) { 138 1.1 christos isc_radix_tree_t *radix; 139 1.1 christos 140 1.1 christos REQUIRE(target != NULL && *target == NULL); 141 1.1 christos 142 1.1 christos radix = isc_mem_get(mctx, sizeof(isc_radix_tree_t)); 143 1.1 christos 144 1.1 christos radix->mctx = NULL; 145 1.1 christos isc_mem_attach(mctx, &radix->mctx); 146 1.1 christos radix->maxbits = maxbits; 147 1.1 christos radix->head = NULL; 148 1.1 christos radix->num_active_node = 0; 149 1.1 christos radix->num_added_node = 0; 150 1.1 christos RUNTIME_CHECK(maxbits <= RADIX_MAXBITS); /* XXX */ 151 1.1 christos radix->magic = RADIX_TREE_MAGIC; 152 1.1 christos *target = radix; 153 1.1 christos return (ISC_R_SUCCESS); 154 1.1 christos } 155 1.1 christos 156 1.1 christos /* 157 1.1 christos * if func is supplied, it will be called as func(node->data) 158 1.1 christos * before deleting the node 159 1.1 christos */ 160 1.1 christos 161 1.1 christos static void 162 1.1 christos _clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) { 163 1.1 christos REQUIRE(radix != NULL); 164 1.1 christos 165 1.1 christos if (radix->head != NULL) { 166 1.1 christos isc_radix_node_t *Xstack[RADIX_MAXBITS + 1]; 167 1.1 christos isc_radix_node_t **Xsp = Xstack; 168 1.1 christos isc_radix_node_t *Xrn = radix->head; 169 1.1 christos 170 1.1 christos while (Xrn != NULL) { 171 1.1 christos isc_radix_node_t *l = Xrn->l; 172 1.1 christos isc_radix_node_t *r = Xrn->r; 173 1.1 christos 174 1.1 christos if (Xrn->prefix != NULL) { 175 1.1 christos _deref_prefix(Xrn->prefix); 176 1.1 christos if (func != NULL) { 177 1.1 christos func(Xrn->data); 178 1.1 christos } 179 1.1 christos } else { 180 1.1 christos INSIST(Xrn->data[RADIX_V4] == NULL && 181 1.1 christos Xrn->data[RADIX_V6] == NULL); 182 1.1 christos } 183 1.1 christos 184 1.1 christos isc_mem_put(radix->mctx, Xrn, sizeof(*Xrn)); 185 1.1 christos radix->num_active_node--; 186 1.1 christos 187 1.1 christos if (l != NULL) { 188 1.1 christos if (r != NULL) { 189 1.1 christos *Xsp++ = r; 190 1.1 christos } 191 1.1 christos Xrn = l; 192 1.1 christos } else if (r != NULL) { 193 1.1 christos Xrn = r; 194 1.1 christos } else if (Xsp != Xstack) { 195 1.1 christos Xrn = *(--Xsp); 196 1.1 christos } else { 197 1.1 christos Xrn = NULL; 198 1.1 christos } 199 1.1 christos } 200 1.1 christos } 201 1.1 christos RUNTIME_CHECK(radix->num_active_node == 0); 202 1.1 christos } 203 1.1 christos 204 1.1 christos void 205 1.1 christos isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) { 206 1.1 christos REQUIRE(radix != NULL); 207 1.1 christos _clear_radix(radix, func); 208 1.1 christos isc_mem_putanddetach(&radix->mctx, radix, sizeof(*radix)); 209 1.1 christos } 210 1.1 christos 211 1.1 christos /* 212 1.1 christos * func will be called as func(node->prefix, node->data) 213 1.1 christos */ 214 1.1 christos void 215 1.1 christos isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func) { 216 1.1 christos isc_radix_node_t *node; 217 1.1 christos 218 1.1 christos REQUIRE(func != NULL); 219 1.1 christos 220 1.1 christos RADIX_WALK(radix->head, node) { func(node->prefix, node->data); } 221 1.1 christos RADIX_WALK_END; 222 1.1 christos } 223 1.1 christos 224 1.1 christos isc_result_t 225 1.1 christos isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target, 226 1.1 christos isc_prefix_t *prefix) { 227 1.1 christos isc_radix_node_t *node; 228 1.1 christos isc_radix_node_t *stack[RADIX_MAXBITS + 1]; 229 1.1 christos u_char *addr; 230 1.1 christos uint32_t bitlen; 231 1.1 christos int tfam = -1, cnt = 0; 232 1.1 christos 233 1.1 christos REQUIRE(radix != NULL); 234 1.1 christos REQUIRE(prefix != NULL); 235 1.1 christos REQUIRE(target != NULL && *target == NULL); 236 1.1 christos RUNTIME_CHECK(prefix->bitlen <= radix->maxbits); 237 1.1 christos 238 1.1 christos *target = NULL; 239 1.1 christos 240 1.1 christos node = radix->head; 241 1.1 christos 242 1.1 christos if (node == NULL) { 243 1.1 christos return (ISC_R_NOTFOUND); 244 1.1 christos } 245 1.1 christos 246 1.1 christos addr = isc_prefix_touchar(prefix); 247 1.1 christos bitlen = prefix->bitlen; 248 1.1 christos 249 1.1 christos while (node != NULL && node->bit < bitlen) { 250 1.1 christos if (node->prefix) { 251 1.1 christos stack[cnt++] = node; 252 1.1 christos } 253 1.1 christos 254 1.1 christos if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) 255 1.1 christos { 256 1.1 christos node = node->r; 257 1.1 christos } else { 258 1.1 christos node = node->l; 259 1.1 christos } 260 1.1 christos } 261 1.1 christos 262 1.1 christos if (node != NULL && node->prefix) { 263 1.1 christos stack[cnt++] = node; 264 1.1 christos } 265 1.1 christos 266 1.1 christos while (cnt-- > 0) { 267 1.1 christos node = stack[cnt]; 268 1.1 christos 269 1.1 christos if (prefix->bitlen < node->bit) { 270 1.1 christos continue; 271 1.1 christos } 272 1.1 christos 273 1.1 christos if (_comp_with_mask(isc_prefix_tochar(node->prefix), 274 1.1 christos isc_prefix_tochar(prefix), 275 1.1 christos node->prefix->bitlen)) 276 1.1 christos { 277 1.1 christos int fam = ISC_RADIX_FAMILY(prefix); 278 1.1 christos if (node->node_num[fam] != -1 && 279 1.1 christos ((*target == NULL) || 280 1.1 christos (*target)->node_num[tfam] > node->node_num[fam])) 281 1.1 christos { 282 1.1 christos *target = node; 283 1.1 christos tfam = fam; 284 1.1 christos } 285 1.1 christos } 286 1.1 christos } 287 1.1 christos 288 1.1 christos if (*target == NULL) { 289 1.1 christos return (ISC_R_NOTFOUND); 290 1.1 christos } else { 291 1.1 christos return (ISC_R_SUCCESS); 292 1.1 christos } 293 1.1 christos } 294 1.1 christos 295 1.1 christos isc_result_t 296 1.1 christos isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target, 297 1.1 christos isc_radix_node_t *source, isc_prefix_t *prefix) { 298 1.1 christos isc_radix_node_t *node, *new_node, *parent, *glue = NULL; 299 1.1 christos u_char *addr, *test_addr; 300 1.1 christos uint32_t bitlen, fam, check_bit, differ_bit; 301 1.1 christos uint32_t i, j, r; 302 1.1 christos isc_result_t result; 303 1.1 christos 304 1.1 christos REQUIRE(radix != NULL); 305 1.1 christos REQUIRE(target != NULL && *target == NULL); 306 1.1 christos REQUIRE(prefix != NULL || (source != NULL && source->prefix != NULL)); 307 1.1 christos RUNTIME_CHECK(prefix == NULL || prefix->bitlen <= radix->maxbits); 308 1.1 christos 309 1.1 christos if (prefix == NULL) { 310 1.1 christos prefix = source->prefix; 311 1.1 christos } 312 1.1 christos 313 1.1 christos INSIST(prefix != NULL); 314 1.1 christos 315 1.1 christos bitlen = prefix->bitlen; 316 1.1 christos fam = prefix->family; 317 1.1 christos 318 1.1 christos if (radix->head == NULL) { 319 1.1 christos node = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t)); 320 1.1 christos node->bit = bitlen; 321 1.1 christos for (i = 0; i < RADIX_FAMILIES; i++) { 322 1.1 christos node->node_num[i] = -1; 323 1.1 christos } 324 1.1 christos node->prefix = NULL; 325 1.1 christos result = _ref_prefix(radix->mctx, &node->prefix, prefix); 326 1.1 christos if (result != ISC_R_SUCCESS) { 327 1.1 christos isc_mem_put(radix->mctx, node, 328 1.1 christos sizeof(isc_radix_node_t)); 329 1.1 christos return (result); 330 1.1 christos } 331 1.1 christos node->parent = NULL; 332 1.1 christos node->l = node->r = NULL; 333 1.1 christos if (source != NULL) { 334 1.1 christos /* 335 1.1 christos * If source is non-NULL, then we're merging in a 336 1.1 christos * node from an existing radix tree. To keep 337 1.1 christos * the node_num values consistent, the calling 338 1.1 christos * function will add the total number of nodes 339 1.1 christos * added to num_added_node at the end of 340 1.1 christos * the merge operation--we don't do it here. 341 1.1 christos */ 342 1.1 christos for (i = 0; i < RADIX_FAMILIES; i++) { 343 1.1 christos if (source->node_num[i] != -1) { 344 1.1 christos node->node_num[i] = 345 1.1 christos radix->num_added_node + 346 1.1 christos source->node_num[i]; 347 1.1 christos } 348 1.1 christos node->data[i] = source->data[i]; 349 1.1 christos } 350 1.1 christos } else { 351 1.1 christos int next = ++radix->num_added_node; 352 1.1 christos if (fam == AF_UNSPEC) { 353 1.1 christos /* "any" or "none" */ 354 1.1 christos for (i = 0; i < RADIX_FAMILIES; i++) { 355 1.1 christos node->node_num[i] = next; 356 1.1 christos } 357 1.1 christos } else { 358 1.1 christos node->node_num[ISC_RADIX_FAMILY(prefix)] = next; 359 1.1 christos } 360 1.1 christos 361 1.1 christos memset(node->data, 0, sizeof(node->data)); 362 1.1 christos } 363 1.1 christos radix->head = node; 364 1.1 christos radix->num_active_node++; 365 1.1 christos *target = node; 366 1.1 christos return (ISC_R_SUCCESS); 367 1.1 christos } 368 1.1 christos 369 1.1 christos addr = isc_prefix_touchar(prefix); 370 1.1 christos node = radix->head; 371 1.1 christos 372 1.1 christos while (node->bit < bitlen || node->prefix == NULL) { 373 1.1 christos if (node->bit < radix->maxbits && 374 1.1 christos BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) 375 1.1 christos { 376 1.1 christos if (node->r == NULL) { 377 1.1 christos break; 378 1.1 christos } 379 1.1 christos node = node->r; 380 1.1 christos } else { 381 1.1 christos if (node->l == NULL) { 382 1.1 christos break; 383 1.1 christos } 384 1.1 christos node = node->l; 385 1.1 christos } 386 1.1 christos 387 1.1 christos INSIST(node != NULL); 388 1.1 christos } 389 1.1 christos 390 1.1 christos INSIST(node->prefix != NULL); 391 1.1 christos 392 1.1 christos test_addr = isc_prefix_touchar(node->prefix); 393 1.1 christos /* Find the first bit different. */ 394 1.1 christos check_bit = (node->bit < bitlen) ? node->bit : bitlen; 395 1.1 christos differ_bit = 0; 396 1.1 christos for (i = 0; i * 8 < check_bit; i++) { 397 1.1 christos if ((r = (addr[i] ^ test_addr[i])) == 0) { 398 1.1 christos differ_bit = (i + 1) * 8; 399 1.1 christos continue; 400 1.1 christos } 401 1.1 christos /* I know the better way, but for now. */ 402 1.1 christos for (j = 0; j < 8; j++) { 403 1.1 christos if (BIT_TEST(r, (0x80 >> j))) { 404 1.1 christos break; 405 1.1 christos } 406 1.1 christos } 407 1.1 christos /* Must be found. */ 408 1.1 christos INSIST(j < 8); 409 1.1 christos differ_bit = i * 8 + j; 410 1.1 christos break; 411 1.1 christos } 412 1.1 christos 413 1.1 christos if (differ_bit > check_bit) { 414 1.1 christos differ_bit = check_bit; 415 1.1 christos } 416 1.1 christos 417 1.1 christos parent = node->parent; 418 1.1 christos while (parent != NULL && parent->bit >= differ_bit) { 419 1.1 christos node = parent; 420 1.1 christos parent = node->parent; 421 1.1 christos } 422 1.1 christos 423 1.1 christos if (differ_bit == bitlen && node->bit == bitlen) { 424 1.1 christos if (node->prefix != NULL) { 425 1.1 christos /* Set node_num only if it hasn't been set before */ 426 1.1 christos if (source != NULL) { 427 1.1 christos /* Merging nodes */ 428 1.1 christos for (i = 0; i < RADIX_FAMILIES; i++) { 429 1.1 christos if (node->node_num[i] == -1 && 430 1.1 christos source->node_num[i] != -1) 431 1.1 christos { 432 1.1 christos node->node_num[i] = 433 1.1 christos radix->num_added_node + 434 1.1 christos source->node_num[i]; 435 1.1 christos node->data[i] = source->data[i]; 436 1.1 christos } 437 1.1 christos } 438 1.1 christos } else { 439 1.1 christos if (fam == AF_UNSPEC) { 440 1.1 christos /* "any" or "none" */ 441 1.1 christos int next = radix->num_added_node + 1; 442 1.1 christos for (i = 0; i < RADIX_FAMILIES; i++) { 443 1.1 christos if (node->node_num[i] == -1) { 444 1.1 christos node->node_num[i] = 445 1.1 christos next; 446 1.1 christos radix->num_added_node = 447 1.1 christos next; 448 1.1 christos } 449 1.1 christos } 450 1.1 christos } else { 451 1.1 christos int foff = ISC_RADIX_FAMILY(prefix); 452 1.1 christos if (node->node_num[foff] == -1) { 453 1.1 christos node->node_num[foff] = 454 1.1 christos ++radix->num_added_node; 455 1.1 christos } 456 1.1 christos } 457 1.1 christos } 458 1.1 christos *target = node; 459 1.1 christos return (ISC_R_SUCCESS); 460 1.1 christos } else { 461 1.1 christos result = _ref_prefix(radix->mctx, &node->prefix, 462 1.1 christos prefix); 463 1.1 christos if (result != ISC_R_SUCCESS) { 464 1.1 christos return (result); 465 1.1 christos } 466 1.1 christos } 467 1.1 christos INSIST(node->data[RADIX_V4] == NULL && 468 1.1 christos node->node_num[RADIX_V4] == -1 && 469 1.1 christos node->data[RADIX_V4] == NULL && 470 1.1 christos node->node_num[RADIX_V4] == -1); 471 1.1 christos if (source != NULL) { 472 1.1 christos /* Merging node */ 473 1.1 christos for (i = 0; i < RADIX_FAMILIES; i++) { 474 1.1 christos int cur = radix->num_added_node; 475 1.1 christos if (source->node_num[i] != -1) { 476 1.1 christos node->node_num[i] = 477 1.1 christos source->node_num[i] + cur; 478 1.1 christos node->data[i] = source->data[i]; 479 1.1 christos } 480 1.1 christos } 481 1.1 christos } else { 482 1.1 christos int next = ++radix->num_added_node; 483 1.1 christos if (fam == AF_UNSPEC) { 484 1.1 christos /* "any" or "none" */ 485 1.1 christos for (i = 0; i < RADIX_FAMILIES; i++) { 486 1.1 christos node->node_num[i] = next; 487 1.1 christos } 488 1.1 christos } else { 489 1.1 christos node->node_num[ISC_RADIX_FAMILY(prefix)] = next; 490 1.1 christos } 491 1.1 christos } 492 1.1 christos *target = node; 493 1.1 christos return (ISC_R_SUCCESS); 494 1.1 christos } 495 1.1 christos 496 1.1 christos new_node = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t)); 497 1.1 christos if (node->bit != differ_bit && bitlen != differ_bit) { 498 1.1 christos glue = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t)); 499 1.1 christos } 500 1.1 christos new_node->bit = bitlen; 501 1.1 christos new_node->prefix = NULL; 502 1.1 christos result = _ref_prefix(radix->mctx, &new_node->prefix, prefix); 503 1.1 christos if (result != ISC_R_SUCCESS) { 504 1.1 christos isc_mem_put(radix->mctx, new_node, sizeof(isc_radix_node_t)); 505 1.1 christos if (glue != NULL) { 506 1.1 christos isc_mem_put(radix->mctx, glue, 507 1.1 christos sizeof(isc_radix_node_t)); 508 1.1 christos } 509 1.1 christos return (result); 510 1.1 christos } 511 1.1 christos new_node->parent = NULL; 512 1.1 christos new_node->l = new_node->r = NULL; 513 1.1 christos for (i = 0; i < RADIX_FAMILIES; i++) { 514 1.1 christos new_node->node_num[i] = -1; 515 1.1 christos new_node->data[i] = NULL; 516 1.1 christos } 517 1.1 christos radix->num_active_node++; 518 1.1 christos 519 1.1 christos if (source != NULL) { 520 1.1 christos /* Merging node */ 521 1.1 christos for (i = 0; i < RADIX_FAMILIES; i++) { 522 1.1 christos int cur = radix->num_added_node; 523 1.1 christos if (source->node_num[i] != -1) { 524 1.1 christos new_node->node_num[i] = source->node_num[i] + 525 1.1 christos cur; 526 1.1 christos new_node->data[i] = source->data[i]; 527 1.1 christos } 528 1.1 christos } 529 1.1 christos } else { 530 1.1 christos int next = ++radix->num_added_node; 531 1.1 christos if (fam == AF_UNSPEC) { 532 1.1 christos /* "any" or "none" */ 533 1.1 christos for (i = 0; i < RADIX_FAMILIES; i++) { 534 1.1 christos new_node->node_num[i] = next; 535 1.1 christos } 536 1.1 christos } else { 537 1.1 christos new_node->node_num[ISC_RADIX_FAMILY(prefix)] = next; 538 1.1 christos } 539 1.1 christos memset(new_node->data, 0, sizeof(new_node->data)); 540 1.1 christos } 541 1.1 christos 542 1.1 christos if (node->bit == differ_bit) { 543 1.1 christos INSIST(glue == NULL); 544 1.1 christos new_node->parent = node; 545 1.1 christos if (node->bit < radix->maxbits && 546 1.1 christos BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) 547 1.1 christos { 548 1.1 christos INSIST(node->r == NULL); 549 1.1 christos node->r = new_node; 550 1.1 christos } else { 551 1.1 christos INSIST(node->l == NULL); 552 1.1 christos node->l = new_node; 553 1.1 christos } 554 1.1 christos *target = new_node; 555 1.1 christos return (ISC_R_SUCCESS); 556 1.1 christos } 557 1.1 christos 558 1.1 christos if (bitlen == differ_bit) { 559 1.1 christos INSIST(glue == NULL); 560 1.1 christos if (bitlen < radix->maxbits && 561 1.1 christos BIT_TEST(test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07))) 562 1.1 christos { 563 1.1 christos new_node->r = node; 564 1.1 christos } else { 565 1.1 christos new_node->l = node; 566 1.1 christos } 567 1.1 christos new_node->parent = node->parent; 568 1.1 christos if (node->parent == NULL) { 569 1.1 christos INSIST(radix->head == node); 570 1.1 christos radix->head = new_node; 571 1.1 christos } else if (node->parent->r == node) { 572 1.1 christos node->parent->r = new_node; 573 1.1 christos } else { 574 1.1 christos node->parent->l = new_node; 575 1.1 christos } 576 1.1 christos node->parent = new_node; 577 1.1 christos } else { 578 1.1 christos INSIST(glue != NULL); 579 1.1 christos glue->bit = differ_bit; 580 1.1 christos glue->prefix = NULL; 581 1.1 christos glue->parent = node->parent; 582 1.1 christos for (i = 0; i < RADIX_FAMILIES; i++) { 583 1.1 christos glue->data[i] = NULL; 584 1.1 christos glue->node_num[i] = -1; 585 1.1 christos } 586 1.1 christos radix->num_active_node++; 587 1.1 christos if (differ_bit < radix->maxbits && 588 1.1 christos BIT_TEST(addr[differ_bit >> 3], 0x80 >> (differ_bit & 07))) 589 1.1 christos { 590 1.1 christos glue->r = new_node; 591 1.1 christos glue->l = node; 592 1.1 christos } else { 593 1.1 christos glue->r = node; 594 1.1 christos glue->l = new_node; 595 1.1 christos } 596 1.1 christos new_node->parent = glue; 597 1.1 christos 598 1.1 christos if (node->parent == NULL) { 599 1.1 christos INSIST(radix->head == node); 600 1.1 christos radix->head = glue; 601 1.1 christos } else if (node->parent->r == node) { 602 1.1 christos node->parent->r = glue; 603 1.1 christos } else { 604 1.1 christos node->parent->l = glue; 605 1.1 christos } 606 1.1 christos node->parent = glue; 607 1.1 christos } 608 1.1 christos 609 1.1 christos *target = new_node; 610 1.1 christos return (ISC_R_SUCCESS); 611 1.1 christos } 612 1.1 christos 613 1.1 christos void 614 1.1 christos isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node) { 615 1.1 christos isc_radix_node_t *parent, *child; 616 1.1 christos 617 1.1 christos REQUIRE(radix != NULL); 618 1.1 christos REQUIRE(node != NULL); 619 1.1 christos 620 1.1 christos if (node->r && node->l) { 621 1.1 christos /* 622 1.1 christos * This might be a placeholder node -- have to check and 623 1.1 christos * make sure there is a prefix associated with it! 624 1.1 christos */ 625 1.1 christos if (node->prefix != NULL) { 626 1.1 christos _deref_prefix(node->prefix); 627 1.1 christos } 628 1.1 christos 629 1.1 christos node->prefix = NULL; 630 1.1 christos memset(node->data, 0, sizeof(node->data)); 631 1.1 christos return; 632 1.1 christos } 633 1.1 christos 634 1.1 christos if (node->r == NULL && node->l == NULL) { 635 1.1 christos parent = node->parent; 636 1.1 christos _deref_prefix(node->prefix); 637 1.1 christos 638 1.1 christos if (parent == NULL) { 639 1.1 christos INSIST(radix->head == node); 640 1.1 christos radix->head = NULL; 641 1.1 christos isc_mem_put(radix->mctx, node, sizeof(*node)); 642 1.1 christos radix->num_active_node--; 643 1.1 christos return; 644 1.1 christos } 645 1.1 christos 646 1.1 christos if (parent->r == node) { 647 1.1 christos parent->r = NULL; 648 1.1 christos child = parent->l; 649 1.1 christos } else { 650 1.1 christos INSIST(parent->l == node); 651 1.1 christos parent->l = NULL; 652 1.1 christos child = parent->r; 653 1.1 christos } 654 1.1 christos 655 1.1 christos isc_mem_put(radix->mctx, node, sizeof(*node)); 656 1.1 christos radix->num_active_node--; 657 1.1 christos 658 1.1 christos if (parent->prefix) { 659 1.1 christos return; 660 1.1 christos } 661 1.1 christos 662 1.1 christos /* We need to remove parent too. */ 663 1.1 christos if (parent->parent == NULL) { 664 1.1 christos INSIST(radix->head == parent); 665 1.1 christos radix->head = child; 666 1.1 christos } else if (parent->parent->r == parent) { 667 1.1 christos parent->parent->r = child; 668 1.1 christos } else { 669 1.1 christos INSIST(parent->parent->l == parent); 670 1.1 christos parent->parent->l = child; 671 1.1 christos } 672 1.1 christos 673 1.1 christos child->parent = parent->parent; 674 1.1 christos isc_mem_put(radix->mctx, parent, sizeof(*parent)); 675 1.1 christos radix->num_active_node--; 676 1.1 christos return; 677 1.1 christos } 678 1.1 christos 679 1.1 christos if (node->r) { 680 1.1 christos child = node->r; 681 1.1 christos } else { 682 1.1 christos INSIST(node->l != NULL); 683 1.1 christos child = node->l; 684 1.1 christos } 685 1.1 christos 686 1.1 christos parent = node->parent; 687 1.1 christos child->parent = parent; 688 1.1 christos 689 1.1 christos _deref_prefix(node->prefix); 690 1.1 christos 691 1.1 christos if (parent == NULL) { 692 1.1 christos INSIST(radix->head == node); 693 1.1 christos radix->head = child; 694 1.1 christos isc_mem_put(radix->mctx, node, sizeof(*node)); 695 1.1 christos radix->num_active_node--; 696 1.1 christos return; 697 1.1 christos } 698 1.1 christos 699 1.1 christos isc_mem_put(radix->mctx, node, sizeof(*node)); 700 1.1 christos radix->num_active_node--; 701 1.1 christos 702 1.1 christos if (parent->r == node) { 703 1.1 christos parent->r = child; 704 1.1 christos } else { 705 1.1 christos INSIST(parent->l == node); 706 1.1 christos parent->l = child; 707 1.1 christos } 708 1.1 christos } 709