1 /* $NetBSD: radix.c,v 1.8 2015/07/08 17:28:59 christos Exp $ */
4 * Copyright (C) 2007-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
22 * This source was adapted from MRT's RCS Ids:
23 * Id: radix.c,v 1.10.2.1 1999/11/29 05:16:24 masaki Exp
24 * Id: prefix.c,v 1.37.2.9 2000/03/10 02:53:19 labovit Exp
30 #include <isc/types.h>
32 #include <isc/radix.h>
35 _new_prefix(isc_mem_t
*mctx
, isc_prefix_t
**target
, int family
,
36 void *dest
, int bitlen
);
39 _deref_prefix(isc_prefix_t
*prefix
);
42 _ref_prefix(isc_mem_t
*mctx
, isc_prefix_t
**target
, isc_prefix_t
*prefix
);
45 _comp_with_mask(void *addr
, void *dest
, u_int mask
);
48 _clear_radix(isc_radix_tree_t
*radix
, isc_radix_destroyfunc_t func
);
51 _new_prefix(isc_mem_t
*mctx
, isc_prefix_t
**target
, int family
, void *dest
,
56 REQUIRE(target
!= NULL
);
58 if (family
!= AF_INET6
&& family
!= AF_INET
&& family
!= AF_UNSPEC
)
59 return (ISC_R_NOTIMPLEMENTED
);
61 prefix
= isc_mem_get(mctx
, sizeof(isc_prefix_t
));
63 return (ISC_R_NOMEMORY
);
65 if (family
== AF_INET6
) {
66 prefix
->bitlen
= (bitlen
>= 0) ? bitlen
: 128;
67 memmove(&prefix
->add
.sin6
, dest
, 16);
69 /* AF_UNSPEC is "any" or "none"--treat it as AF_INET */
70 prefix
->bitlen
= (bitlen
>= 0) ? bitlen
: 32;
71 memmove(&prefix
->add
.sin
, dest
, 4);
74 prefix
->family
= family
;
76 isc_mem_attach(mctx
, &prefix
->mctx
);
78 isc_refcount_init(&prefix
->refcount
, 1);
81 return (ISC_R_SUCCESS
);
85 _deref_prefix(isc_prefix_t
*prefix
) {
91 isc_refcount_decrement(&prefix
->refcount
, &refs
);
94 isc_refcount_destroy(&prefix
->refcount
);
95 isc_mem_putanddetach(&prefix
->mctx
, prefix
,
96 sizeof(isc_prefix_t
));
101 _ref_prefix(isc_mem_t
*mctx
, isc_prefix_t
**target
, isc_prefix_t
*prefix
) {
102 INSIST(prefix
!= NULL
);
103 INSIST((prefix
->family
== AF_INET
&& prefix
->bitlen
<= 32) ||
104 (prefix
->family
== AF_INET6
&& prefix
->bitlen
<= 128) ||
105 (prefix
->family
== AF_UNSPEC
&& prefix
->bitlen
== 0));
106 REQUIRE(target
!= NULL
&& *target
== NULL
);
109 * If this prefix is a static allocation, copy it into new memory.
110 * (Note, the refcount still has to be destroyed by the calling
113 if (isc_refcount_current(&prefix
->refcount
) == 0) {
115 ret
= _new_prefix(mctx
, target
, prefix
->family
,
116 &prefix
->add
, prefix
->bitlen
);
120 isc_refcount_increment(&prefix
->refcount
, NULL
);
123 return (ISC_R_SUCCESS
);
127 _comp_with_mask(void *addr
, void *dest
, u_int mask
) {
129 /* Mask length of zero matches everything */
133 if (memcmp(addr
, dest
, mask
/ 8) == 0) {
135 int m
= ((~0) << (8 - (mask
% 8)));
137 if ((mask
% 8) == 0 ||
138 (((u_char
*)addr
)[n
] & m
) == (((u_char
*)dest
)[n
] & m
))
145 isc_radix_create(isc_mem_t
*mctx
, isc_radix_tree_t
**target
, int maxbits
) {
146 isc_radix_tree_t
*radix
;
148 REQUIRE(target
!= NULL
&& *target
== NULL
);
150 radix
= isc_mem_get(mctx
, sizeof(isc_radix_tree_t
));
152 return (ISC_R_NOMEMORY
);
155 isc_mem_attach(mctx
, &radix
->mctx
);
156 radix
->maxbits
= maxbits
;
158 radix
->num_active_node
= 0;
159 radix
->num_added_node
= 0;
160 RUNTIME_CHECK(maxbits
<= RADIX_MAXBITS
); /* XXX */
161 radix
->magic
= RADIX_TREE_MAGIC
;
163 return (ISC_R_SUCCESS
);
167 * if func is supplied, it will be called as func(node->data)
168 * before deleting the node
172 _clear_radix(isc_radix_tree_t
*radix
, isc_radix_destroyfunc_t func
) {
174 REQUIRE(radix
!= NULL
);
176 if (radix
->head
!= NULL
) {
177 isc_radix_node_t
*Xstack
[RADIX_MAXBITS
+1];
178 isc_radix_node_t
**Xsp
= Xstack
;
179 isc_radix_node_t
*Xrn
= radix
->head
;
181 while (Xrn
!= NULL
) {
182 isc_radix_node_t
*l
= Xrn
->l
;
183 isc_radix_node_t
*r
= Xrn
->r
;
185 if (Xrn
->prefix
!= NULL
) {
186 _deref_prefix(Xrn
->prefix
);
187 if (func
!= NULL
&& (Xrn
->data
[0] != NULL
||
188 Xrn
->data
[1] != NULL
))
191 INSIST(Xrn
->data
[0] == NULL
&&
192 Xrn
->data
[1] == NULL
);
195 isc_mem_put(radix
->mctx
, Xrn
, sizeof(*Xrn
));
196 radix
->num_active_node
--;
203 } else if (r
!= NULL
) {
205 } else if (Xsp
!= Xstack
) {
212 RUNTIME_CHECK(radix
->num_active_node
== 0);
217 isc_radix_destroy(isc_radix_tree_t
*radix
, isc_radix_destroyfunc_t func
) {
218 REQUIRE(radix
!= NULL
);
219 _clear_radix(radix
, func
);
220 isc_mem_putanddetach(&radix
->mctx
, radix
, sizeof(*radix
));
225 * func will be called as func(node->prefix, node->data)
228 isc_radix_process(isc_radix_tree_t
*radix
, isc_radix_processfunc_t func
) {
229 isc_radix_node_t
*node
;
231 REQUIRE(func
!= NULL
);
233 RADIX_WALK(radix
->head
, node
) {
234 func(node
->prefix
, node
->data
);
240 isc_radix_search(isc_radix_tree_t
*radix
, isc_radix_node_t
**target
,
241 isc_prefix_t
*prefix
)
243 isc_radix_node_t
*node
;
244 isc_radix_node_t
*stack
[RADIX_MAXBITS
+ 1];
250 REQUIRE(radix
!= NULL
);
251 REQUIRE(prefix
!= NULL
);
252 REQUIRE(target
!= NULL
&& *target
== NULL
);
253 RUNTIME_CHECK(prefix
->bitlen
<= radix
->maxbits
);
257 if (radix
->head
== NULL
) {
258 return (ISC_R_NOTFOUND
);
262 addr
= isc_prefix_touchar(prefix
);
263 bitlen
= prefix
->bitlen
;
265 while (node
->bit
< bitlen
) {
269 if (BIT_TEST(addr
[node
->bit
>> 3], 0x80 >> (node
->bit
& 0x07)))
278 if (node
&& node
->prefix
)
284 if (prefix
->bitlen
< node
->bit
)
287 if (_comp_with_mask(isc_prefix_tochar(node
->prefix
),
288 isc_prefix_tochar(prefix
),
289 node
->prefix
->bitlen
)) {
290 if (node
->node_num
[ISC_IS6(prefix
->family
)] != -1 &&
291 ((*target
== NULL
) ||
292 (*target
)->node_num
[ISC_IS6(tfamily
)] >
293 node
->node_num
[ISC_IS6(prefix
->family
)])) {
295 tfamily
= prefix
->family
;
300 if (*target
== NULL
) {
301 return (ISC_R_NOTFOUND
);
303 return (ISC_R_SUCCESS
);
308 isc_radix_insert(isc_radix_tree_t
*radix
, isc_radix_node_t
**target
,
309 isc_radix_node_t
*source
, isc_prefix_t
*prefix
)
311 isc_radix_node_t
*node
, *new_node
, *parent
, *glue
= NULL
;
312 u_char
*addr
, *test_addr
;
313 isc_uint32_t bitlen
, fam
, check_bit
, differ_bit
;
314 isc_uint32_t i
, j
, r
;
317 REQUIRE(radix
!= NULL
);
318 REQUIRE(target
!= NULL
&& *target
== NULL
);
319 REQUIRE(prefix
!= NULL
|| (source
!= NULL
&& source
->prefix
!= NULL
));
320 RUNTIME_CHECK(prefix
== NULL
|| prefix
->bitlen
<= radix
->maxbits
);
323 prefix
= source
->prefix
;
325 INSIST(prefix
!= NULL
);
327 bitlen
= prefix
->bitlen
;
328 fam
= prefix
->family
;
330 if (radix
->head
== NULL
) {
331 node
= isc_mem_get(radix
->mctx
, sizeof(isc_radix_node_t
));
333 return (ISC_R_NOMEMORY
);
335 node
->node_num
[0] = node
->node_num
[1] = -1;
337 result
= _ref_prefix(radix
->mctx
, &node
->prefix
, prefix
);
338 if (result
!= ISC_R_SUCCESS
) {
339 isc_mem_put(radix
->mctx
, node
,
340 sizeof(isc_radix_node_t
));
344 node
->l
= node
->r
= NULL
;
345 if (source
!= NULL
) {
347 * If source is non-NULL, then we're merging in a
348 * node from an existing radix tree. To keep
349 * the node_num values consistent, the calling
350 * function will add the total number of nodes
351 * added to num_added_node at the end of
352 * the merge operation--we don't do it here.
354 if (source
->node_num
[0] != -1)
355 node
->node_num
[0] = radix
->num_added_node
+
357 if (source
->node_num
[1] != -1)
358 node
->node_num
[1] = radix
->num_added_node
+
360 node
->data
[0] = source
->data
[0];
361 node
->data
[1] = source
->data
[1];
363 if (fam
== AF_UNSPEC
) {
364 /* "any" or "none" */
365 node
->node_num
[0] = node
->node_num
[1] =
366 ++radix
->num_added_node
;
368 node
->node_num
[ISC_IS6(fam
)] =
369 ++radix
->num_added_node
;
371 node
->data
[0] = NULL
;
372 node
->data
[1] = NULL
;
375 radix
->num_active_node
++;
377 return (ISC_R_SUCCESS
);
380 addr
= isc_prefix_touchar(prefix
);
383 while (node
->bit
< bitlen
|| node
->prefix
== NULL
) {
384 if (node
->bit
< radix
->maxbits
&&
385 BIT_TEST(addr
[node
->bit
>> 3], 0x80 >> (node
->bit
& 0x07)))
396 INSIST(node
!= NULL
);
399 INSIST(node
->prefix
!= NULL
);
401 test_addr
= isc_prefix_touchar(node
->prefix
);
402 /* Find the first bit different. */
403 check_bit
= (node
->bit
< bitlen
) ? node
->bit
: bitlen
;
405 for (i
= 0; i
*8 < check_bit
; i
++) {
406 if ((r
= (addr
[i
] ^ test_addr
[i
])) == 0) {
407 differ_bit
= (i
+ 1) * 8;
410 /* I know the better way, but for now. */
411 for (j
= 0; j
< 8; j
++) {
412 if (BIT_TEST (r
, (0x80 >> j
)))
417 differ_bit
= i
* 8 + j
;
421 if (differ_bit
> check_bit
)
422 differ_bit
= check_bit
;
424 parent
= node
->parent
;
425 while (parent
!= NULL
&& parent
->bit
>= differ_bit
) {
427 parent
= node
->parent
;
430 if (differ_bit
== bitlen
&& node
->bit
== bitlen
) {
431 if (node
->prefix
!= NULL
) {
432 /* Set node_num only if it hasn't been set before */
433 if (source
!= NULL
) {
435 if (node
->node_num
[0] == -1 &&
436 source
->node_num
[0] != -1) {
438 radix
->num_added_node
+
440 node
->data
[0] = source
->data
[0];
442 if (node
->node_num
[1] == -1 &&
443 source
->node_num
[0] != -1) {
445 radix
->num_added_node
+
447 node
->data
[1] = source
->data
[1];
450 if (fam
== AF_UNSPEC
) {
451 /* "any" or "none" */
452 int next
= radix
->num_added_node
+ 1;
453 if (node
->node_num
[0] == -1) {
454 node
->node_num
[0] = next
;
455 radix
->num_added_node
= next
;
457 if (node
->node_num
[1] == -1) {
458 node
->node_num
[1] = next
;
459 radix
->num_added_node
= next
;
462 if (node
->node_num
[ISC_IS6(fam
)] == -1)
463 node
->node_num
[ISC_IS6(fam
)]
464 = ++radix
->num_added_node
;
468 return (ISC_R_SUCCESS
);
470 result
= _ref_prefix(radix
->mctx
,
471 &node
->prefix
, prefix
);
472 if (result
!= ISC_R_SUCCESS
)
475 INSIST(node
->data
[0] == NULL
&& node
->node_num
[0] == -1 &&
476 node
->data
[1] == NULL
&& node
->node_num
[1] == -1);
477 if (source
!= NULL
) {
479 if (source
->node_num
[0] != -1) {
480 node
->node_num
[0] = radix
->num_added_node
+
482 node
->data
[0] = source
->data
[0];
484 if (source
->node_num
[1] != -1) {
485 node
->node_num
[1] = radix
->num_added_node
+
487 node
->data
[1] = source
->data
[1];
490 if (fam
== AF_UNSPEC
) {
491 /* "any" or "none" */
492 node
->node_num
[0] = node
->node_num
[1] =
493 ++radix
->num_added_node
;
495 node
->node_num
[ISC_IS6(fam
)] =
496 ++radix
->num_added_node
;
500 return (ISC_R_SUCCESS
);
503 new_node
= isc_mem_get(radix
->mctx
, sizeof(isc_radix_node_t
));
504 if (new_node
== NULL
)
505 return (ISC_R_NOMEMORY
);
506 if (node
->bit
!= differ_bit
&& bitlen
!= differ_bit
) {
507 glue
= isc_mem_get(radix
->mctx
, sizeof(isc_radix_node_t
));
509 isc_mem_put(radix
->mctx
, new_node
,
510 sizeof(isc_radix_node_t
));
511 return (ISC_R_NOMEMORY
);
514 new_node
->bit
= bitlen
;
515 new_node
->prefix
= NULL
;
516 result
= _ref_prefix(radix
->mctx
, &new_node
->prefix
, prefix
);
517 if (result
!= ISC_R_SUCCESS
) {
518 isc_mem_put(radix
->mctx
, new_node
, sizeof(isc_radix_node_t
));
520 isc_mem_put(radix
->mctx
, glue
,
521 sizeof(isc_radix_node_t
));
524 new_node
->parent
= NULL
;
525 new_node
->l
= new_node
->r
= NULL
;
526 new_node
->node_num
[0] = new_node
->node_num
[1] = -1;
527 radix
->num_active_node
++;
529 if (source
!= NULL
) {
531 if (source
->node_num
[0] != -1)
532 new_node
->node_num
[0] = radix
->num_added_node
+
534 if (source
->node_num
[1] != -1)
535 new_node
->node_num
[1] = radix
->num_added_node
+
537 new_node
->data
[0] = source
->data
[0];
538 new_node
->data
[1] = source
->data
[1];
540 if (fam
== AF_UNSPEC
) {
541 /* "any" or "none" */
542 new_node
->node_num
[0] = new_node
->node_num
[1] =
543 ++radix
->num_added_node
;
545 new_node
->node_num
[ISC_IS6(fam
)] =
546 ++radix
->num_added_node
;
548 new_node
->data
[0] = NULL
;
549 new_node
->data
[1] = NULL
;
552 if (node
->bit
== differ_bit
) {
553 INSIST(glue
== NULL
);
554 new_node
->parent
= node
;
555 if (node
->bit
< radix
->maxbits
&&
556 BIT_TEST(addr
[node
->bit
>> 3], 0x80 >> (node
->bit
& 0x07)))
558 INSIST(node
->r
== NULL
);
561 INSIST(node
->l
== NULL
);
565 return (ISC_R_SUCCESS
);
568 if (bitlen
== differ_bit
) {
569 INSIST(glue
== NULL
);
570 if (bitlen
< radix
->maxbits
&&
571 BIT_TEST(test_addr
[bitlen
>> 3], 0x80 >> (bitlen
& 0x07))) {
576 new_node
->parent
= node
->parent
;
577 if (node
->parent
== NULL
) {
578 INSIST(radix
->head
== node
);
579 radix
->head
= new_node
;
580 } else if (node
->parent
->r
== node
) {
581 node
->parent
->r
= new_node
;
583 node
->parent
->l
= new_node
;
585 node
->parent
= new_node
;
587 INSIST(glue
!= NULL
);
588 glue
->bit
= differ_bit
;
590 glue
->parent
= node
->parent
;
591 glue
->data
[0] = glue
->data
[1] = NULL
;
592 glue
->node_num
[0] = glue
->node_num
[1] = -1;
593 radix
->num_active_node
++;
594 if (differ_bit
< radix
->maxbits
&&
595 BIT_TEST(addr
[differ_bit
>>3], 0x80 >> (differ_bit
& 07))) {
602 new_node
->parent
= glue
;
604 if (node
->parent
== NULL
) {
605 INSIST(radix
->head
== node
);
607 } else if (node
->parent
->r
== node
) {
608 node
->parent
->r
= glue
;
610 node
->parent
->l
= glue
;
616 return (ISC_R_SUCCESS
);
620 isc_radix_remove(isc_radix_tree_t
*radix
, isc_radix_node_t
*node
) {
621 isc_radix_node_t
*parent
, *child
;
623 REQUIRE(radix
!= NULL
);
624 REQUIRE(node
!= NULL
);
626 if (node
->r
&& node
->l
) {
628 * This might be a placeholder node -- have to check and
629 * make sure there is a prefix associated with it!
631 if (node
->prefix
!= NULL
)
632 _deref_prefix(node
->prefix
);
635 node
->data
[0] = node
->data
[1] = NULL
;
639 if (node
->r
== NULL
&& node
->l
== NULL
) {
640 parent
= node
->parent
;
641 _deref_prefix(node
->prefix
);
643 if (parent
== NULL
) {
644 INSIST(radix
->head
== node
);
646 isc_mem_put(radix
->mctx
, node
, sizeof(*node
));
647 radix
->num_active_node
--;
651 if (parent
->r
== node
) {
655 INSIST(parent
->l
== node
);
660 isc_mem_put(radix
->mctx
, node
, sizeof(*node
));
661 radix
->num_active_node
--;
666 /* We need to remove parent too. */
667 if (parent
->parent
== NULL
) {
668 INSIST(radix
->head
== parent
);
670 } else if (parent
->parent
->r
== parent
) {
671 parent
->parent
->r
= child
;
673 INSIST(parent
->parent
->l
== parent
);
674 parent
->parent
->l
= child
;
677 child
->parent
= parent
->parent
;
678 isc_mem_put(radix
->mctx
, parent
, sizeof(*parent
));
679 radix
->num_active_node
--;
686 INSIST(node
->l
!= NULL
);
690 parent
= node
->parent
;
691 child
->parent
= parent
;
693 _deref_prefix(node
->prefix
);
695 if (parent
== NULL
) {
696 INSIST(radix
->head
== node
);
698 isc_mem_put(radix
->mctx
, node
, sizeof(*node
));
699 radix
->num_active_node
--;
703 isc_mem_put(radix
->mctx
, node
, sizeof(*node
));
704 radix
->num_active_node
--;
706 if (parent
->r
== node
) {
709 INSIST(parent
->l
== node
);