/src/bind9/lib/isc/radix.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) Internet Systems Consortium, Inc. ("ISC") |
3 | | * |
4 | | * SPDX-License-Identifier: MPL-2.0 |
5 | | * |
6 | | * This Source Code Form is subject to the terms of the Mozilla Public |
7 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
8 | | * file, you can obtain one at https://mozilla.org/MPL/2.0/. |
9 | | * |
10 | | * See the COPYRIGHT file distributed with this work for additional |
11 | | * information regarding copyright ownership. |
12 | | */ |
13 | | |
14 | | #include <inttypes.h> |
15 | | |
16 | | #include <isc/bit.h> |
17 | | #include <isc/mem.h> |
18 | | #include <isc/radix.h> |
19 | | #include <isc/types.h> |
20 | | #include <isc/util.h> |
21 | | |
22 | | static int |
23 | 0 | comp_with_mask(void *addr, void *dest, unsigned int mask) { |
24 | | /* Mask length of zero matches everything */ |
25 | 0 | if (mask == 0) { |
26 | 0 | return 1; |
27 | 0 | } |
28 | | |
29 | 0 | if (memcmp(addr, dest, mask / 8) == 0) { |
30 | 0 | unsigned int n = mask / 8; |
31 | 0 | unsigned int m = ((~0U) << (8 - (mask % 8))); |
32 | |
|
33 | 0 | if ((mask % 8) == 0 || |
34 | 0 | (((uint8_t *)addr)[n] & m) == (((uint8_t *)dest)[n] & m)) |
35 | 0 | { |
36 | 0 | return 1; |
37 | 0 | } |
38 | 0 | } |
39 | 0 | return 0; |
40 | 0 | } |
41 | | |
42 | | static isc_radix_node_t * |
43 | 0 | radix_node_create(isc_mem_t *mctx, isc_prefix_t *prefix, uint8_t bit) { |
44 | 0 | isc_radix_node_t *node = isc_mem_get(mctx, sizeof(*node)); |
45 | 0 | *node = (isc_radix_node_t){ |
46 | 0 | .bit = bit, |
47 | 0 | .node_num = { -1, -1 }, |
48 | 0 | }; |
49 | 0 | if (prefix != NULL) { |
50 | 0 | node->prefix = *prefix; |
51 | 0 | } |
52 | 0 | return node; |
53 | 0 | } |
54 | | |
55 | | void |
56 | 4 | isc_radix_create(isc_mem_t *mctx, isc_radix_tree_t **target, uint8_t maxbits) { |
57 | 4 | REQUIRE(target != NULL && *target == NULL); |
58 | 4 | RUNTIME_CHECK(maxbits <= RADIX_MAXBITS); |
59 | | |
60 | 4 | isc_radix_tree_t *radix = isc_mem_get(mctx, sizeof(isc_radix_tree_t)); |
61 | 4 | *radix = (isc_radix_tree_t){ |
62 | 4 | .maxbits = maxbits, |
63 | 4 | .magic = RADIX_TREE_MAGIC, |
64 | 4 | }; |
65 | 4 | isc_mem_attach(mctx, &radix->mctx); |
66 | 4 | *target = radix; |
67 | 4 | } |
68 | | |
69 | | /* |
70 | | * if func is supplied, it will be called as func(node->data) |
71 | | * before deleting the node |
72 | | */ |
73 | | |
74 | | static void |
75 | 0 | clear_radix(isc_radix_tree_t *radix) { |
76 | 0 | REQUIRE(radix != NULL); |
77 | |
|
78 | 0 | isc_radix_node_t *stack[RADIX_MAXBITS + 1]; |
79 | 0 | isc_radix_node_t **sp = stack; |
80 | 0 | isc_radix_node_t *cur = radix->head; |
81 | |
|
82 | 0 | while (cur != NULL) { |
83 | 0 | isc_radix_node_t *l = cur->left; |
84 | 0 | isc_radix_node_t *r = cur->right; |
85 | |
|
86 | 0 | isc_mem_put(radix->mctx, cur, sizeof(*cur)); |
87 | 0 | radix->num_active_node--; |
88 | |
|
89 | 0 | if (l != NULL) { |
90 | 0 | if (r != NULL) { |
91 | 0 | *sp++ = r; |
92 | 0 | } |
93 | 0 | cur = l; |
94 | 0 | } else if (r != NULL) { |
95 | 0 | cur = r; |
96 | 0 | } else if (sp != stack) { |
97 | 0 | cur = *(--sp); |
98 | 0 | } else { |
99 | 0 | cur = NULL; |
100 | 0 | } |
101 | 0 | } |
102 | |
|
103 | 0 | RUNTIME_CHECK(radix->num_active_node == 0); |
104 | 0 | } |
105 | | |
106 | | void |
107 | 0 | isc_radix_destroy(isc_radix_tree_t *radix) { |
108 | 0 | REQUIRE(radix != NULL); |
109 | 0 | clear_radix(radix); |
110 | 0 | isc_mem_putanddetach(&radix->mctx, radix, sizeof(*radix)); |
111 | 0 | } |
112 | | |
113 | | void |
114 | | isc_radix_foreach(isc_radix_tree_t *radix, isc_radix_foreachfunc_t func, |
115 | 0 | void *arg) { |
116 | 0 | REQUIRE(radix != NULL); |
117 | 0 | REQUIRE(func != NULL); |
118 | |
|
119 | 0 | isc_radix_node_t *stack[RADIX_MAXBITS + 1]; |
120 | 0 | isc_radix_node_t **sp = stack; |
121 | 0 | isc_radix_node_t *cur = radix->head; |
122 | |
|
123 | 0 | while (cur != NULL) { |
124 | 0 | if (cur->prefix.family != 0) { |
125 | 0 | func(cur, arg); |
126 | 0 | } |
127 | |
|
128 | 0 | if (cur->left != NULL) { |
129 | 0 | if (cur->right != NULL) { |
130 | 0 | *sp++ = cur->right; |
131 | 0 | } |
132 | 0 | cur = cur->left; |
133 | 0 | } else if (cur->right != NULL) { |
134 | 0 | cur = cur->right; |
135 | 0 | } else if (sp != stack) { |
136 | 0 | cur = *(--sp); |
137 | 0 | } else { |
138 | 0 | cur = NULL; |
139 | 0 | } |
140 | 0 | } |
141 | 0 | } |
142 | | |
143 | | isc_result_t |
144 | | isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target, |
145 | 0 | isc_prefix_t *prefix) { |
146 | 0 | isc_radix_node_t *stack[RADIX_MAXBITS + 1]; |
147 | 0 | int cnt = 0; |
148 | |
|
149 | 0 | REQUIRE(radix != NULL); |
150 | 0 | REQUIRE(prefix != NULL); |
151 | 0 | REQUIRE(target != NULL && *target == NULL); |
152 | 0 | RUNTIME_CHECK(prefix->bitlen <= radix->maxbits); |
153 | |
|
154 | 0 | *target = NULL; |
155 | |
|
156 | 0 | if (radix->head == NULL) { |
157 | 0 | return ISC_R_NOTFOUND; |
158 | 0 | } |
159 | | |
160 | | /* Walk the tree collecting candidate nodes. */ |
161 | 0 | uint8_t *addr = isc_prefix_touint8(prefix); |
162 | 0 | uint8_t bitlen = prefix->bitlen; |
163 | 0 | isc_radix_node_t *node = radix->head; |
164 | |
|
165 | 0 | while (node != NULL && node->bit < bitlen) { |
166 | 0 | if (node->prefix.family != 0) { |
167 | 0 | stack[cnt++] = node; |
168 | 0 | } |
169 | |
|
170 | 0 | if (isc_prefix_bit_isset(addr, node->bit)) { |
171 | 0 | node = node->right; |
172 | 0 | } else { |
173 | 0 | node = node->left; |
174 | 0 | } |
175 | 0 | } |
176 | |
|
177 | 0 | if (node != NULL && node->prefix.family != 0) { |
178 | 0 | stack[cnt++] = node; |
179 | 0 | } |
180 | | |
181 | | /* Find the first-inserted matching node among the candidates. */ |
182 | 0 | int tfam = -1; |
183 | 0 | while (cnt-- > 0) { |
184 | 0 | node = stack[cnt]; |
185 | |
|
186 | 0 | if (prefix->bitlen < node->bit) { |
187 | 0 | continue; |
188 | 0 | } |
189 | | |
190 | 0 | if (comp_with_mask(isc_prefix_touint8(&node->prefix), |
191 | 0 | isc_prefix_touint8(prefix), |
192 | 0 | node->prefix.bitlen)) |
193 | 0 | { |
194 | 0 | int fam = ISC_RADIX_FAMILY(prefix); |
195 | 0 | if (node->node_num[fam] != -1 && |
196 | 0 | ((*target == NULL) || |
197 | 0 | (*target)->node_num[tfam] > node->node_num[fam])) |
198 | 0 | { |
199 | 0 | *target = node; |
200 | 0 | tfam = fam; |
201 | 0 | } |
202 | 0 | } |
203 | 0 | } |
204 | |
|
205 | 0 | if (*target == NULL) { |
206 | 0 | return ISC_R_NOTFOUND; |
207 | 0 | } |
208 | | |
209 | 0 | return ISC_R_SUCCESS; |
210 | 0 | } |
211 | | |
212 | | void |
213 | | isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target, |
214 | 0 | isc_radix_node_t *source, isc_prefix_t *prefix) { |
215 | 0 | isc_radix_node_t *node; |
216 | |
|
217 | 0 | REQUIRE(radix != NULL); |
218 | 0 | REQUIRE(target != NULL && *target == NULL); |
219 | 0 | REQUIRE(prefix != NULL || |
220 | 0 | (source != NULL && source->prefix.family != 0)); |
221 | 0 | RUNTIME_CHECK(prefix == NULL || prefix->bitlen <= radix->maxbits); |
222 | |
|
223 | 0 | if (prefix == NULL) { |
224 | 0 | prefix = &source->prefix; |
225 | 0 | } |
226 | |
|
227 | 0 | INSIST(prefix != NULL); |
228 | |
|
229 | 0 | uint8_t bitlen = prefix->bitlen; |
230 | |
|
231 | 0 | if (radix->head == NULL) { |
232 | 0 | node = radix_node_create(radix->mctx, prefix, bitlen); |
233 | 0 | if (source != NULL) { |
234 | | /* |
235 | | * If source is non-NULL, then we're merging in a |
236 | | * node from an existing radix tree. To keep |
237 | | * the node_num values consistent, the calling |
238 | | * function will add the total number of nodes |
239 | | * added to num_added_node at the end of |
240 | | * the merge operation--we don't do it here. |
241 | | */ |
242 | 0 | for (size_t i = 0; i < RADIX_FAMILIES; i++) { |
243 | 0 | if (source->node_num[i] != -1) { |
244 | 0 | node->node_num[i] = |
245 | 0 | radix->num_added_node + |
246 | 0 | source->node_num[i]; |
247 | 0 | } |
248 | 0 | node->match[i] = source->match[i]; |
249 | 0 | } |
250 | 0 | } else { |
251 | 0 | int next = ++radix->num_added_node; |
252 | 0 | node->node_num[ISC_RADIX_FAMILY(prefix)] = next; |
253 | 0 | } |
254 | 0 | radix->head = node; |
255 | 0 | radix->num_active_node++; |
256 | 0 | *target = node; |
257 | 0 | return; |
258 | 0 | } |
259 | | |
260 | 0 | uint8_t *addr = isc_prefix_touint8(prefix); |
261 | 0 | node = radix->head; |
262 | |
|
263 | 0 | while (node->bit < bitlen || node->prefix.family == 0) { |
264 | 0 | if (node->bit < radix->maxbits && |
265 | 0 | isc_prefix_bit_isset(addr, node->bit)) |
266 | 0 | { |
267 | 0 | if (node->right == NULL) { |
268 | 0 | break; |
269 | 0 | } |
270 | 0 | node = node->right; |
271 | 0 | } else { |
272 | 0 | if (node->left == NULL) { |
273 | 0 | break; |
274 | 0 | } |
275 | 0 | node = node->left; |
276 | 0 | } |
277 | | |
278 | 0 | INSIST(node != NULL); |
279 | 0 | } |
280 | |
|
281 | 0 | INSIST(node->prefix.family != 0); |
282 | | |
283 | | /* Find the first bit different. */ |
284 | 0 | uint8_t *test_addr = isc_prefix_touint8(&node->prefix); |
285 | 0 | uint8_t check_bit = (node->bit < bitlen) ? node->bit : bitlen; |
286 | 0 | uint8_t differ_bit = 0; |
287 | 0 | for (size_t i = 0; i * 8 < check_bit; i++) { |
288 | 0 | uint8_t r = addr[i] ^ test_addr[i]; |
289 | 0 | if (r == 0) { |
290 | 0 | differ_bit = (i + 1) * 8; |
291 | 0 | continue; |
292 | 0 | } |
293 | 0 | differ_bit = i * 8 + (stdc_leading_zeros((unsigned int)r) - 24); |
294 | 0 | break; |
295 | 0 | } |
296 | |
|
297 | 0 | if (differ_bit > check_bit) { |
298 | 0 | differ_bit = check_bit; |
299 | 0 | } |
300 | |
|
301 | 0 | isc_radix_node_t *parent = node->parent; |
302 | 0 | while (parent != NULL && parent->bit >= differ_bit) { |
303 | 0 | node = parent; |
304 | 0 | parent = node->parent; |
305 | 0 | } |
306 | |
|
307 | 0 | if (differ_bit == bitlen && node->bit == bitlen) { |
308 | 0 | if (node->prefix.family != 0) { |
309 | | /* Set node_num only if it hasn't been set before */ |
310 | 0 | if (source != NULL) { |
311 | | /* Merging nodes */ |
312 | 0 | for (size_t i = 0; i < RADIX_FAMILIES; i++) { |
313 | 0 | if (node->node_num[i] == -1 && |
314 | 0 | source->node_num[i] != -1) |
315 | 0 | { |
316 | 0 | node->node_num[i] = |
317 | 0 | radix->num_added_node + |
318 | 0 | source->node_num[i]; |
319 | 0 | node->match[i] = |
320 | 0 | source->match[i]; |
321 | 0 | } |
322 | 0 | } |
323 | 0 | } else { |
324 | 0 | int foff = ISC_RADIX_FAMILY(prefix); |
325 | 0 | if (node->node_num[foff] == -1) { |
326 | 0 | node->node_num[foff] = |
327 | 0 | ++radix->num_added_node; |
328 | 0 | } |
329 | 0 | } |
330 | 0 | *target = node; |
331 | 0 | return; |
332 | 0 | } else { |
333 | 0 | node->prefix = *prefix; |
334 | 0 | } |
335 | 0 | INSIST(node->match[RADIX_V4] == RADIX_UNSET && |
336 | 0 | node->node_num[RADIX_V4] == -1 && |
337 | 0 | node->match[RADIX_V6] == RADIX_UNSET && |
338 | 0 | node->node_num[RADIX_V6] == -1); |
339 | 0 | if (source != NULL) { |
340 | | /* Merging node */ |
341 | 0 | for (size_t i = 0; i < RADIX_FAMILIES; i++) { |
342 | 0 | int cur = radix->num_added_node; |
343 | 0 | if (source->node_num[i] != -1) { |
344 | 0 | node->node_num[i] = |
345 | 0 | source->node_num[i] + cur; |
346 | 0 | node->match[i] = source->match[i]; |
347 | 0 | } |
348 | 0 | } |
349 | 0 | } else { |
350 | 0 | int next = ++radix->num_added_node; |
351 | 0 | node->node_num[ISC_RADIX_FAMILY(prefix)] = next; |
352 | 0 | } |
353 | 0 | *target = node; |
354 | 0 | return; |
355 | 0 | } |
356 | | |
357 | 0 | isc_radix_node_t *new_node = radix_node_create(radix->mctx, prefix, |
358 | 0 | bitlen); |
359 | 0 | isc_radix_node_t *glue = NULL; |
360 | 0 | if (node->bit != differ_bit && bitlen != differ_bit) { |
361 | 0 | glue = radix_node_create(radix->mctx, NULL, differ_bit); |
362 | 0 | } |
363 | 0 | radix->num_active_node++; |
364 | |
|
365 | 0 | if (source != NULL) { |
366 | | /* Merging node */ |
367 | 0 | for (size_t i = 0; i < RADIX_FAMILIES; i++) { |
368 | 0 | int cur = radix->num_added_node; |
369 | 0 | if (source->node_num[i] != -1) { |
370 | 0 | new_node->node_num[i] = source->node_num[i] + |
371 | 0 | cur; |
372 | 0 | new_node->match[i] = source->match[i]; |
373 | 0 | } |
374 | 0 | } |
375 | 0 | } else { |
376 | 0 | int next = ++radix->num_added_node; |
377 | 0 | new_node->node_num[ISC_RADIX_FAMILY(prefix)] = next; |
378 | 0 | } |
379 | |
|
380 | 0 | if (node->bit == differ_bit) { |
381 | 0 | INSIST(glue == NULL); |
382 | 0 | new_node->parent = node; |
383 | 0 | if (node->bit < radix->maxbits && |
384 | 0 | isc_prefix_bit_isset(addr, node->bit)) |
385 | 0 | { |
386 | 0 | INSIST(node->right == NULL); |
387 | 0 | node->right = new_node; |
388 | 0 | } else { |
389 | 0 | INSIST(node->left == NULL); |
390 | 0 | node->left = new_node; |
391 | 0 | } |
392 | 0 | *target = new_node; |
393 | 0 | return; |
394 | 0 | } |
395 | | |
396 | 0 | if (bitlen == differ_bit) { |
397 | 0 | INSIST(glue == NULL); |
398 | 0 | if (bitlen < radix->maxbits && |
399 | 0 | isc_prefix_bit_isset(test_addr, bitlen)) |
400 | 0 | { |
401 | 0 | new_node->right = node; |
402 | 0 | } else { |
403 | 0 | new_node->left = node; |
404 | 0 | } |
405 | 0 | new_node->parent = node->parent; |
406 | 0 | if (node->parent == NULL) { |
407 | 0 | INSIST(radix->head == node); |
408 | 0 | radix->head = new_node; |
409 | 0 | } else if (node->parent->right == node) { |
410 | 0 | node->parent->right = new_node; |
411 | 0 | } else { |
412 | 0 | node->parent->left = new_node; |
413 | 0 | } |
414 | 0 | node->parent = new_node; |
415 | 0 | } else { |
416 | 0 | INSIST(glue != NULL); |
417 | 0 | glue->parent = node->parent; |
418 | 0 | radix->num_active_node++; |
419 | 0 | if (differ_bit < radix->maxbits && |
420 | 0 | isc_prefix_bit_isset(addr, differ_bit)) |
421 | 0 | { |
422 | 0 | glue->right = new_node; |
423 | 0 | glue->left = node; |
424 | 0 | } else { |
425 | 0 | glue->right = node; |
426 | 0 | glue->left = new_node; |
427 | 0 | } |
428 | 0 | new_node->parent = glue; |
429 | |
|
430 | 0 | if (node->parent == NULL) { |
431 | 0 | INSIST(radix->head == node); |
432 | 0 | radix->head = glue; |
433 | 0 | } else if (node->parent->right == node) { |
434 | 0 | node->parent->right = glue; |
435 | 0 | } else { |
436 | 0 | INSIST(node->parent->left == node); |
437 | 0 | node->parent->left = glue; |
438 | 0 | } |
439 | 0 | node->parent = glue; |
440 | 0 | } |
441 | |
|
442 | 0 | *target = new_node; |
443 | 0 | return; |
444 | 0 | } |
445 | | |
446 | | void |
447 | 0 | isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node) { |
448 | 0 | isc_radix_node_t *parent, *child; |
449 | |
|
450 | 0 | REQUIRE(radix != NULL); |
451 | 0 | REQUIRE(node != NULL); |
452 | |
|
453 | 0 | if (node->right && node->left) { |
454 | | /* |
455 | | * This might be a placeholder node -- have to check and |
456 | | * make sure there is a prefix associated with it! |
457 | | */ |
458 | 0 | memset(&node->prefix, 0, sizeof(node->prefix)); |
459 | 0 | node->match[RADIX_V4] = RADIX_UNSET; |
460 | 0 | node->match[RADIX_V6] = RADIX_UNSET; |
461 | 0 | return; |
462 | 0 | } |
463 | | |
464 | 0 | if (node->right == NULL && node->left == NULL) { |
465 | 0 | parent = node->parent; |
466 | |
|
467 | 0 | if (parent == NULL) { |
468 | 0 | INSIST(radix->head == node); |
469 | 0 | radix->head = NULL; |
470 | 0 | isc_mem_put(radix->mctx, node, sizeof(*node)); |
471 | 0 | radix->num_active_node--; |
472 | 0 | return; |
473 | 0 | } |
474 | | |
475 | 0 | if (parent->right == node) { |
476 | 0 | parent->right = NULL; |
477 | 0 | child = parent->left; |
478 | 0 | } else { |
479 | 0 | INSIST(parent->left == node); |
480 | 0 | parent->left = NULL; |
481 | 0 | child = parent->right; |
482 | 0 | } |
483 | |
|
484 | 0 | isc_mem_put(radix->mctx, node, sizeof(*node)); |
485 | 0 | radix->num_active_node--; |
486 | |
|
487 | 0 | if (parent->prefix.family != 0) { |
488 | 0 | return; |
489 | 0 | } |
490 | | |
491 | | /* We need to remove parent too. */ |
492 | 0 | if (parent->parent == NULL) { |
493 | 0 | INSIST(radix->head == parent); |
494 | 0 | radix->head = child; |
495 | 0 | } else if (parent->parent->right == parent) { |
496 | 0 | parent->parent->right = child; |
497 | 0 | } else { |
498 | 0 | INSIST(parent->parent->left == parent); |
499 | 0 | parent->parent->left = child; |
500 | 0 | } |
501 | |
|
502 | 0 | child->parent = parent->parent; |
503 | 0 | isc_mem_put(radix->mctx, parent, sizeof(*parent)); |
504 | 0 | radix->num_active_node--; |
505 | 0 | return; |
506 | 0 | } |
507 | | |
508 | 0 | if (node->right) { |
509 | 0 | child = node->right; |
510 | 0 | } else { |
511 | 0 | INSIST(node->left != NULL); |
512 | 0 | child = node->left; |
513 | 0 | } |
514 | |
|
515 | 0 | parent = node->parent; |
516 | 0 | child->parent = parent; |
517 | |
|
518 | 0 | if (parent == NULL) { |
519 | 0 | INSIST(radix->head == node); |
520 | 0 | radix->head = child; |
521 | 0 | isc_mem_put(radix->mctx, node, sizeof(*node)); |
522 | 0 | radix->num_active_node--; |
523 | 0 | return; |
524 | 0 | } |
525 | | |
526 | 0 | if (parent->right == node) { |
527 | 0 | parent->right = child; |
528 | 0 | } else { |
529 | 0 | INSIST(parent->left == node); |
530 | 0 | parent->left = child; |
531 | 0 | } |
532 | |
|
533 | | isc_mem_put(radix->mctx, node, sizeof(*node)); |
534 | 0 | radix->num_active_node--; |
535 | 0 | } |