radix.c revision 1.1 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