Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * Routing Table functions. |
4 | | * Copyright (C) 1998 Kunihiro Ishiguro |
5 | | */ |
6 | | |
7 | | #define FRR_COMPILING_TABLE_C |
8 | | |
9 | | #include <zebra.h> |
10 | | |
11 | | #include "prefix.h" |
12 | | #include "table.h" |
13 | | #include "memory.h" |
14 | | #include "sockunion.h" |
15 | | #include "libfrr_trace.h" |
16 | | |
17 | | DEFINE_MTYPE_STATIC(LIB, ROUTE_TABLE, "Route table"); |
18 | | DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node"); |
19 | | |
20 | | static void route_table_free(struct route_table *); |
21 | | |
22 | | static int route_table_hash_cmp(const struct route_node *a, |
23 | | const struct route_node *b) |
24 | 320k | { |
25 | 320k | return prefix_cmp(&a->p, &b->p); |
26 | 320k | } |
27 | | |
28 | | DECLARE_HASH(rn_hash_node, struct route_node, nodehash, route_table_hash_cmp, |
29 | | prefix_hash_key); |
30 | | /* |
31 | | * route_table_init_with_delegate |
32 | | */ |
33 | | struct route_table * |
34 | | route_table_init_with_delegate(route_table_delegate_t *delegate) |
35 | 8.51k | { |
36 | 8.51k | struct route_table *rt; |
37 | | |
38 | 8.51k | rt = XCALLOC(MTYPE_ROUTE_TABLE, sizeof(struct route_table)); |
39 | 8.51k | rt->delegate = delegate; |
40 | 8.51k | rn_hash_node_init(&rt->hash); |
41 | 8.51k | return rt; |
42 | 8.51k | } |
43 | | |
44 | | void route_table_finish(struct route_table *rt) |
45 | 0 | { |
46 | 0 | route_table_free(rt); |
47 | 0 | } |
48 | | |
49 | | /* Allocate new route node. */ |
50 | | static struct route_node *route_node_new(struct route_table *table) |
51 | 25.6k | { |
52 | 25.6k | return table->delegate->create_node(table->delegate, table); |
53 | 25.6k | } |
54 | | |
55 | | /* Allocate new route node with prefix set. */ |
56 | | static struct route_node *route_node_set(struct route_table *table, |
57 | | const struct prefix *prefix) |
58 | 13.9k | { |
59 | 13.9k | struct route_node *node; |
60 | | |
61 | 13.9k | node = route_node_new(table); |
62 | | |
63 | 13.9k | prefix_copy(&node->p, prefix); |
64 | 13.9k | node->table = table; |
65 | | |
66 | 13.9k | rn_hash_node_add(&node->table->hash, node); |
67 | | |
68 | 13.9k | return node; |
69 | 13.9k | } |
70 | | |
71 | | /* Free route node. */ |
72 | | static void route_node_free(struct route_table *table, struct route_node *node) |
73 | 13.9k | { |
74 | 13.9k | if (table->cleanup) |
75 | 0 | table->cleanup(table, node); |
76 | 13.9k | table->delegate->destroy_node(table->delegate, table, node); |
77 | 13.9k | } |
78 | | |
79 | | /* Free route table. */ |
80 | | static void route_table_free(struct route_table *rt) |
81 | 0 | { |
82 | 0 | struct route_node *tmp_node; |
83 | 0 | struct route_node *node; |
84 | |
|
85 | 0 | if (rt == NULL) |
86 | 0 | return; |
87 | | |
88 | 0 | node = rt->top; |
89 | | |
90 | | /* Bulk deletion of nodes remaining in this table. This function is not |
91 | | called until workers have completed their dependency on this table. |
92 | | A final route_unlock_node() will not be called for these nodes. */ |
93 | 0 | while (node) { |
94 | 0 | if (node->l_left) { |
95 | 0 | node = node->l_left; |
96 | 0 | continue; |
97 | 0 | } |
98 | | |
99 | 0 | if (node->l_right) { |
100 | 0 | node = node->l_right; |
101 | 0 | continue; |
102 | 0 | } |
103 | | |
104 | 0 | tmp_node = node; |
105 | 0 | node = node->parent; |
106 | |
|
107 | 0 | tmp_node->table->count--; |
108 | 0 | tmp_node->lock = |
109 | 0 | 0; /* to cause assert if unlocked after this */ |
110 | 0 | rn_hash_node_del(&rt->hash, tmp_node); |
111 | 0 | route_node_free(rt, tmp_node); |
112 | |
|
113 | 0 | if (node != NULL) { |
114 | 0 | if (node->l_left == tmp_node) |
115 | 0 | node->l_left = NULL; |
116 | 0 | else |
117 | 0 | node->l_right = NULL; |
118 | 0 | } else { |
119 | 0 | break; |
120 | 0 | } |
121 | 0 | } |
122 | |
|
123 | 0 | assert(rt->count == 0); |
124 | | |
125 | 0 | rn_hash_node_fini(&rt->hash); |
126 | 0 | XFREE(MTYPE_ROUTE_TABLE, rt); |
127 | 0 | return; |
128 | 0 | } |
129 | | |
130 | | /* Utility mask array. */ |
131 | | static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, |
132 | | 0xf8, 0xfc, 0xfe, 0xff}; |
133 | | |
134 | | /* Common prefix route genaration. */ |
135 | | static void route_common(const struct prefix *n, const struct prefix *p, |
136 | | struct prefix *new) |
137 | 11.6k | { |
138 | 11.6k | int i; |
139 | 11.6k | uint8_t diff; |
140 | 11.6k | uint8_t mask; |
141 | 11.6k | const uint8_t *np; |
142 | 11.6k | const uint8_t *pp; |
143 | 11.6k | uint8_t *newp; |
144 | | |
145 | 11.6k | if (n->family == AF_FLOWSPEC) |
146 | 0 | return prefix_copy(new, p); |
147 | 11.6k | np = (const uint8_t *)&n->u.prefix; |
148 | 11.6k | pp = (const uint8_t *)&p->u.prefix; |
149 | | |
150 | 11.6k | newp = &new->u.prefix; |
151 | | |
152 | 38.4k | for (i = 0; i < p->prefixlen / 8; i++) { |
153 | 34.3k | if (np[i] == pp[i]) |
154 | 26.8k | newp[i] = np[i]; |
155 | 7.58k | else |
156 | 7.58k | break; |
157 | 34.3k | } |
158 | | |
159 | 11.6k | new->prefixlen = i * 8; |
160 | | |
161 | 11.6k | if (new->prefixlen != p->prefixlen) { |
162 | 11.4k | diff = np[i] ^ pp[i]; |
163 | 11.4k | mask = 0x80; |
164 | 50.6k | while (new->prefixlen < p->prefixlen && !(mask & diff)) { |
165 | 39.1k | mask >>= 1; |
166 | 39.1k | new->prefixlen++; |
167 | 39.1k | } |
168 | 11.4k | newp[i] = np[i] & maskbit[new->prefixlen % 8]; |
169 | 11.4k | } |
170 | 11.6k | } |
171 | | |
172 | | static void set_link(struct route_node *node, struct route_node *new) |
173 | 34.1k | { |
174 | 34.1k | unsigned int bit = prefix_bit(&new->p.u.prefix, node->p.prefixlen); |
175 | | |
176 | 34.1k | node->link[bit] = new; |
177 | 34.1k | new->parent = node; |
178 | 34.1k | } |
179 | | |
180 | | /* Find matched prefix. */ |
181 | | struct route_node *route_node_match(struct route_table *table, |
182 | | union prefixconstptr pu) |
183 | 25.4M | { |
184 | 25.4M | const struct prefix *p = pu.p; |
185 | 25.4M | struct route_node *node; |
186 | 25.4M | struct route_node *matched; |
187 | | |
188 | 25.4M | matched = NULL; |
189 | 25.4M | node = table->top; |
190 | | |
191 | | /* Walk down tree. If there is matched route then store it to |
192 | | matched. */ |
193 | 101M | while (node && node->p.prefixlen <= p->prefixlen |
194 | 101M | && prefix_match(&node->p, p)) { |
195 | 76.3M | if (node->info) |
196 | 50.7M | matched = node; |
197 | | |
198 | 76.3M | if (node->p.prefixlen == p->prefixlen) |
199 | 99.5k | break; |
200 | | |
201 | 76.2M | node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; |
202 | 76.2M | } |
203 | | |
204 | | /* If matched route found, return it. */ |
205 | 25.4M | if (matched) |
206 | 12.5M | return route_lock_node(matched); |
207 | | |
208 | 12.8M | return NULL; |
209 | 25.4M | } |
210 | | |
211 | | struct route_node *route_node_match_ipv4(struct route_table *table, |
212 | | const struct in_addr *addr) |
213 | 0 | { |
214 | 0 | struct prefix_ipv4 p; |
215 | |
|
216 | 0 | memset(&p, 0, sizeof(p)); |
217 | 0 | p.family = AF_INET; |
218 | 0 | p.prefixlen = IPV4_MAX_BITLEN; |
219 | 0 | p.prefix = *addr; |
220 | |
|
221 | 0 | return route_node_match(table, (struct prefix *)&p); |
222 | 0 | } |
223 | | |
224 | | struct route_node *route_node_match_ipv6(struct route_table *table, |
225 | | const struct in6_addr *addr) |
226 | 0 | { |
227 | 0 | struct prefix_ipv6 p; |
228 | |
|
229 | 0 | memset(&p, 0, sizeof(p)); |
230 | 0 | p.family = AF_INET6; |
231 | 0 | p.prefixlen = IPV6_MAX_BITLEN; |
232 | 0 | p.prefix = *addr; |
233 | |
|
234 | 0 | return route_node_match(table, &p); |
235 | 0 | } |
236 | | |
237 | | /* Lookup same prefix node. Return NULL when we can't find route. */ |
238 | | struct route_node *route_node_lookup(struct route_table *table, |
239 | | union prefixconstptr pu) |
240 | 327k | { |
241 | 327k | struct route_node rn, *node; |
242 | 327k | prefix_copy(&rn.p, pu.p); |
243 | 327k | apply_mask(&rn.p); |
244 | | |
245 | 327k | node = rn_hash_node_find(&table->hash, &rn); |
246 | 327k | return (node && node->info) ? route_lock_node(node) : NULL; |
247 | 327k | } |
248 | | |
249 | | /* Lookup same prefix node. Return NULL when we can't find route. */ |
250 | | struct route_node *route_node_lookup_maynull(struct route_table *table, |
251 | | union prefixconstptr pu) |
252 | 0 | { |
253 | 0 | struct route_node rn, *node; |
254 | 0 | prefix_copy(&rn.p, pu.p); |
255 | 0 | apply_mask(&rn.p); |
256 | |
|
257 | 0 | node = rn_hash_node_find(&table->hash, &rn); |
258 | 0 | return node ? route_lock_node(node) : NULL; |
259 | 0 | } |
260 | | |
261 | | /* Add node to routing table. */ |
262 | | struct route_node *route_node_get(struct route_table *table, |
263 | | union prefixconstptr pu) |
264 | 61.5k | { |
265 | 61.5k | if (frrtrace_enabled(frr_libfrr, route_node_get)) { |
266 | 0 | char buf[PREFIX2STR_BUFFER]; |
267 | 0 | prefix2str(pu, buf, sizeof(buf)); |
268 | 0 | frrtrace(2, frr_libfrr, route_node_get, table, buf); |
269 | 0 | } |
270 | | |
271 | 61.5k | struct route_node search; |
272 | 61.5k | struct prefix *p = &search.p; |
273 | | |
274 | 61.5k | prefix_copy(p, pu.p); |
275 | 61.5k | apply_mask(p); |
276 | | |
277 | 61.5k | struct route_node *new; |
278 | 61.5k | struct route_node *node; |
279 | 61.5k | struct route_node *match; |
280 | 61.5k | uint16_t prefixlen = p->prefixlen; |
281 | 61.5k | const uint8_t *prefix = &p->u.prefix; |
282 | | |
283 | 61.5k | node = rn_hash_node_find(&table->hash, &search); |
284 | 61.5k | if (node && node->info) |
285 | 13.3k | return route_lock_node(node); |
286 | | |
287 | 48.1k | match = NULL; |
288 | 48.1k | node = table->top; |
289 | 312k | while (node && node->p.prefixlen <= prefixlen |
290 | 312k | && prefix_match(&node->p, p)) { |
291 | 295k | if (node->p.prefixlen == prefixlen) |
292 | 31.9k | return route_lock_node(node); |
293 | | |
294 | 263k | match = node; |
295 | 263k | node = node->link[prefix_bit(prefix, node->p.prefixlen)]; |
296 | 263k | } |
297 | | |
298 | 16.2k | if (node == NULL) { |
299 | 4.56k | new = route_node_set(table, p); |
300 | 4.56k | if (match) |
301 | 1.86k | set_link(match, new); |
302 | 2.69k | else |
303 | 2.69k | table->top = new; |
304 | 11.6k | } else { |
305 | 11.6k | new = route_node_new(table); |
306 | 11.6k | route_common(&node->p, p, &new->p); |
307 | 11.6k | new->p.family = p->family; |
308 | 11.6k | new->table = table; |
309 | 11.6k | set_link(new, node); |
310 | 11.6k | rn_hash_node_add(&table->hash, new); |
311 | | |
312 | 11.6k | if (match) |
313 | 11.2k | set_link(match, new); |
314 | 433 | else |
315 | 433 | table->top = new; |
316 | | |
317 | 11.6k | if (new->p.prefixlen != p->prefixlen) { |
318 | 9.38k | match = new; |
319 | 9.38k | new = route_node_set(table, p); |
320 | 9.38k | set_link(match, new); |
321 | 9.38k | table->count++; |
322 | 9.38k | } |
323 | 11.6k | } |
324 | 16.2k | table->count++; |
325 | 16.2k | route_lock_node(new); |
326 | | |
327 | 16.2k | return new; |
328 | 48.1k | } |
329 | | |
330 | | /* Delete node from the routing table. */ |
331 | | void route_node_delete(struct route_node *node) |
332 | 68.5k | { |
333 | 68.5k | struct route_node *child; |
334 | 68.5k | struct route_node *parent; |
335 | | |
336 | 68.5k | assert(node->lock == 0); |
337 | 68.5k | assert(node->info == NULL); |
338 | | |
339 | 68.5k | if (node->l_left && node->l_right) |
340 | 54.6k | return; |
341 | | |
342 | 13.9k | if (node->l_left) |
343 | 4.60k | child = node->l_left; |
344 | 9.32k | else |
345 | 9.32k | child = node->l_right; |
346 | | |
347 | 13.9k | parent = node->parent; |
348 | | |
349 | 13.9k | if (child) |
350 | 6.03k | child->parent = parent; |
351 | | |
352 | 13.9k | if (parent) { |
353 | 11.5k | if (parent->l_left == node) |
354 | 5.74k | parent->l_left = child; |
355 | 5.85k | else |
356 | 5.85k | parent->l_right = child; |
357 | 11.5k | } else |
358 | 2.33k | node->table->top = child; |
359 | | |
360 | 13.9k | node->table->count--; |
361 | | |
362 | 13.9k | rn_hash_node_del(&node->table->hash, node); |
363 | | |
364 | | /* WARNING: FRAGILE CODE! |
365 | | * route_node_free may have the side effect of free'ing the entire |
366 | | * table. |
367 | | * this is permitted only if table->count got decremented to zero above, |
368 | | * because in that case parent will also be NULL, so that we won't try |
369 | | * to |
370 | | * delete a now-stale parent below. |
371 | | * |
372 | | * cf. srcdest_srcnode_destroy() in zebra/zebra_rib.c */ |
373 | | |
374 | 13.9k | route_node_free(node->table, node); |
375 | | |
376 | | /* If parent node is stub then delete it also. */ |
377 | 13.9k | if (parent && parent->lock == 0) |
378 | 9.21k | route_node_delete(parent); |
379 | 13.9k | } |
380 | | |
381 | | /* Get first node and lock it. This function is useful when one wants |
382 | | to lookup all the node exist in the routing table. */ |
383 | | struct route_node *route_top(struct route_table *table) |
384 | 4.07k | { |
385 | | /* If there is no node in the routing table return NULL. */ |
386 | 4.07k | if (table->top == NULL) |
387 | 916 | return NULL; |
388 | | |
389 | | /* Lock the top node and return it. */ |
390 | 3.16k | route_lock_node(table->top); |
391 | 3.16k | return table->top; |
392 | 4.07k | } |
393 | | |
394 | | /* Unlock current node and lock next node then return it. */ |
395 | | struct route_node *route_next(struct route_node *node) |
396 | 37.3k | { |
397 | 37.3k | struct route_node *next; |
398 | 37.3k | struct route_node *start; |
399 | | |
400 | | /* Node may be deleted from route_unlock_node so we have to preserve |
401 | | next node's pointer. */ |
402 | | |
403 | 37.3k | if (node->l_left) { |
404 | 17.3k | next = node->l_left; |
405 | 17.3k | route_lock_node(next); |
406 | 17.3k | route_unlock_node(node); |
407 | 17.3k | return next; |
408 | 17.3k | } |
409 | 20.0k | if (node->l_right) { |
410 | 0 | next = node->l_right; |
411 | 0 | route_lock_node(next); |
412 | 0 | route_unlock_node(node); |
413 | 0 | return next; |
414 | 0 | } |
415 | | |
416 | 20.0k | start = node; |
417 | 37.0k | while (node->parent) { |
418 | 33.9k | if (node->parent->l_left == node && node->parent->l_right) { |
419 | 17.0k | next = node->parent->l_right; |
420 | 17.0k | route_lock_node(next); |
421 | 17.0k | route_unlock_node(start); |
422 | 17.0k | return next; |
423 | 17.0k | } |
424 | 16.9k | node = node->parent; |
425 | 16.9k | } |
426 | 3.03k | route_unlock_node(start); |
427 | 3.03k | return NULL; |
428 | 20.0k | } |
429 | | |
430 | | /* Unlock current node and lock next node until limit. */ |
431 | | struct route_node *route_next_until(struct route_node *node, |
432 | | const struct route_node *limit) |
433 | 0 | { |
434 | 0 | struct route_node *next; |
435 | 0 | struct route_node *start; |
436 | | |
437 | | /* Node may be deleted from route_unlock_node so we have to preserve |
438 | | next node's pointer. */ |
439 | |
|
440 | 0 | if (node->l_left) { |
441 | 0 | next = node->l_left; |
442 | 0 | route_lock_node(next); |
443 | 0 | route_unlock_node(node); |
444 | 0 | return next; |
445 | 0 | } |
446 | 0 | if (node->l_right) { |
447 | 0 | next = node->l_right; |
448 | 0 | route_lock_node(next); |
449 | 0 | route_unlock_node(node); |
450 | 0 | return next; |
451 | 0 | } |
452 | | |
453 | 0 | start = node; |
454 | 0 | while (node->parent && node != limit) { |
455 | 0 | if (node->parent->l_left == node && node->parent->l_right) { |
456 | 0 | next = node->parent->l_right; |
457 | 0 | route_lock_node(next); |
458 | 0 | route_unlock_node(start); |
459 | 0 | return next; |
460 | 0 | } |
461 | 0 | node = node->parent; |
462 | 0 | } |
463 | 0 | route_unlock_node(start); |
464 | 0 | return NULL; |
465 | 0 | } |
466 | | |
467 | | unsigned long route_table_count(struct route_table *table) |
468 | 0 | { |
469 | 0 | return table->count; |
470 | 0 | } |
471 | | |
472 | | /** |
473 | | * route_node_create |
474 | | * |
475 | | * Default function for creating a route node. |
476 | | */ |
477 | | struct route_node *route_node_create(route_table_delegate_t *delegate, |
478 | | struct route_table *table) |
479 | 22.7k | { |
480 | 22.7k | struct route_node *node; |
481 | 22.7k | node = XCALLOC(MTYPE_ROUTE_NODE, sizeof(struct route_node)); |
482 | 22.7k | return node; |
483 | 22.7k | } |
484 | | |
485 | | /** |
486 | | * route_node_destroy |
487 | | * |
488 | | * Default function for destroying a route node. |
489 | | */ |
490 | | void route_node_destroy(route_table_delegate_t *delegate, |
491 | | struct route_table *table, struct route_node *node) |
492 | 11.5k | { |
493 | 11.5k | XFREE(MTYPE_ROUTE_NODE, node); |
494 | 11.5k | } |
495 | | |
496 | | /* |
497 | | * Default delegate. |
498 | | */ |
499 | | static route_table_delegate_t default_delegate = { |
500 | | .create_node = route_node_create, |
501 | | .destroy_node = route_node_destroy}; |
502 | | |
503 | | route_table_delegate_t *route_table_get_default_delegate(void) |
504 | 0 | { |
505 | 0 | return &default_delegate; |
506 | 0 | } |
507 | | |
508 | | /* |
509 | | * route_table_init |
510 | | */ |
511 | | struct route_table *route_table_init(void) |
512 | 8.15k | { |
513 | 8.15k | return route_table_init_with_delegate(&default_delegate); |
514 | 8.15k | } |
515 | | |
516 | | /** |
517 | | * route_table_prefix_iter_cmp |
518 | | * |
519 | | * Compare two prefixes according to the order in which they appear in |
520 | | * an iteration over a tree. |
521 | | * |
522 | | * @return -1 if p1 occurs before p2 (p1 < p2) |
523 | | * 0 if the prefixes are identical (p1 == p2) |
524 | | * +1 if p1 occurs after p2 (p1 > p2) |
525 | | */ |
526 | | int route_table_prefix_iter_cmp(const struct prefix *p1, |
527 | | const struct prefix *p2) |
528 | 0 | { |
529 | 0 | struct prefix common_space; |
530 | 0 | struct prefix *common = &common_space; |
531 | |
|
532 | 0 | if (p1->prefixlen <= p2->prefixlen) { |
533 | 0 | if (prefix_match(p1, p2)) { |
534 | | |
535 | | /* |
536 | | * p1 contains p2, or is equal to it. |
537 | | */ |
538 | 0 | return (p1->prefixlen == p2->prefixlen) ? 0 : -1; |
539 | 0 | } |
540 | 0 | } else { |
541 | | |
542 | | /* |
543 | | * Check if p2 contains p1. |
544 | | */ |
545 | 0 | if (prefix_match(p2, p1)) |
546 | 0 | return 1; |
547 | 0 | } |
548 | | |
549 | 0 | route_common(p1, p2, common); |
550 | 0 | assert(common->prefixlen < p1->prefixlen); |
551 | 0 | assert(common->prefixlen < p2->prefixlen); |
552 | | |
553 | | /* |
554 | | * Both prefixes are longer than the common prefix. |
555 | | * |
556 | | * We need to check the bit after the common prefixlen to determine |
557 | | * which one comes later. |
558 | | */ |
559 | 0 | if (prefix_bit(&p1->u.prefix, common->prefixlen)) { |
560 | | |
561 | | /* |
562 | | * We branch to the right to get to p1 from the common prefix. |
563 | | */ |
564 | 0 | assert(!prefix_bit(&p2->u.prefix, common->prefixlen)); |
565 | 0 | return 1; |
566 | 0 | } |
567 | | |
568 | | /* |
569 | | * We branch to the right to get to p2 from the common prefix. |
570 | | */ |
571 | 0 | assert(prefix_bit(&p2->u.prefix, common->prefixlen)); |
572 | 0 | return -1; |
573 | 0 | } |
574 | | |
575 | | /* |
576 | | * route_get_subtree_next |
577 | | * |
578 | | * Helper function that returns the first node that follows the nodes |
579 | | * in the sub-tree under 'node' in iteration order. |
580 | | */ |
581 | | static struct route_node *route_get_subtree_next(struct route_node *node) |
582 | 0 | { |
583 | 0 | while (node->parent) { |
584 | 0 | if (node->parent->l_left == node && node->parent->l_right) |
585 | 0 | return node->parent->l_right; |
586 | | |
587 | 0 | node = node->parent; |
588 | 0 | } |
589 | | |
590 | 0 | return NULL; |
591 | 0 | } |
592 | | |
593 | | /** |
594 | | * route_table_get_next_internal |
595 | | * |
596 | | * Helper function to find the node that occurs after the given prefix in |
597 | | * order of iteration. |
598 | | * |
599 | | * @see route_table_get_next |
600 | | */ |
601 | | static struct route_node * |
602 | | route_table_get_next_internal(struct route_table *table, |
603 | | const struct prefix *p) |
604 | 0 | { |
605 | 0 | struct route_node *node, *tmp_node; |
606 | 0 | int cmp; |
607 | |
|
608 | 0 | node = table->top; |
609 | |
|
610 | 0 | while (node) { |
611 | 0 | int match; |
612 | |
|
613 | 0 | if (node->p.prefixlen < p->prefixlen) |
614 | 0 | match = prefix_match(&node->p, p); |
615 | 0 | else |
616 | 0 | match = prefix_match(p, &node->p); |
617 | |
|
618 | 0 | if (match) { |
619 | 0 | if (node->p.prefixlen == p->prefixlen) { |
620 | | |
621 | | /* |
622 | | * The prefix p exists in the tree, just return |
623 | | * the next |
624 | | * node. |
625 | | */ |
626 | 0 | route_lock_node(node); |
627 | 0 | node = route_next(node); |
628 | 0 | if (node) |
629 | 0 | route_unlock_node(node); |
630 | |
|
631 | 0 | return (node); |
632 | 0 | } |
633 | | |
634 | 0 | if (node->p.prefixlen > p->prefixlen) { |
635 | | |
636 | | /* |
637 | | * Node is in the subtree of p, and hence |
638 | | * greater than p. |
639 | | */ |
640 | 0 | return node; |
641 | 0 | } |
642 | | |
643 | | /* |
644 | | * p is in the sub-tree under node. |
645 | | */ |
646 | 0 | tmp_node = node->link[prefix_bit(&p->u.prefix, |
647 | 0 | node->p.prefixlen)]; |
648 | |
|
649 | 0 | if (tmp_node) { |
650 | 0 | node = tmp_node; |
651 | 0 | continue; |
652 | 0 | } |
653 | | |
654 | | /* |
655 | | * There are no nodes in the direction where p should |
656 | | * be. If |
657 | | * node has a right child, then it must be greater than |
658 | | * p. |
659 | | */ |
660 | 0 | if (node->l_right) |
661 | 0 | return node->l_right; |
662 | | |
663 | | /* |
664 | | * No more children to follow, go upwards looking for |
665 | | * the next |
666 | | * node. |
667 | | */ |
668 | 0 | return route_get_subtree_next(node); |
669 | 0 | } |
670 | | |
671 | | /* |
672 | | * Neither node prefix nor 'p' contains the other. |
673 | | */ |
674 | 0 | cmp = route_table_prefix_iter_cmp(&node->p, p); |
675 | 0 | if (cmp > 0) { |
676 | | |
677 | | /* |
678 | | * Node follows p in iteration order. Return it. |
679 | | */ |
680 | 0 | return node; |
681 | 0 | } |
682 | | |
683 | 0 | assert(cmp < 0); |
684 | | |
685 | | /* |
686 | | * Node and the subtree under it come before prefix p in |
687 | | * iteration order. Prefix p and its sub-tree are not present in |
688 | | * the tree. Go upwards and find the first node that follows the |
689 | | * subtree. That node will also succeed p. |
690 | | */ |
691 | 0 | return route_get_subtree_next(node); |
692 | 0 | } |
693 | | |
694 | 0 | return NULL; |
695 | 0 | } |
696 | | |
697 | | /** |
698 | | * route_table_get_next |
699 | | * |
700 | | * Find the node that occurs after the given prefix in order of |
701 | | * iteration. |
702 | | */ |
703 | | struct route_node *route_table_get_next(struct route_table *table, |
704 | | union prefixconstptr pu) |
705 | 0 | { |
706 | 0 | const struct prefix *p = pu.p; |
707 | 0 | struct route_node *node; |
708 | |
|
709 | 0 | node = route_table_get_next_internal(table, p); |
710 | 0 | if (node) { |
711 | 0 | assert(route_table_prefix_iter_cmp(&node->p, p) > 0); |
712 | 0 | route_lock_node(node); |
713 | 0 | } |
714 | 0 | return node; |
715 | 0 | } |
716 | | |
717 | | /* |
718 | | * route_table_iter_init |
719 | | */ |
720 | | void route_table_iter_init(route_table_iter_t *iter, struct route_table *table) |
721 | 0 | { |
722 | 0 | memset(iter, 0, sizeof(*iter)); |
723 | 0 | iter->state = RT_ITER_STATE_INIT; |
724 | 0 | iter->table = table; |
725 | 0 | } |
726 | | |
727 | | /* |
728 | | * route_table_iter_pause |
729 | | * |
730 | | * Pause an iteration over the table. This allows the iteration to be |
731 | | * resumed point after arbitrary additions/deletions from the table. |
732 | | * An iteration can be resumed by just calling route_table_iter_next() |
733 | | * on the iterator. |
734 | | */ |
735 | | void route_table_iter_pause(route_table_iter_t *iter) |
736 | 0 | { |
737 | 0 | switch (iter->state) { |
738 | | |
739 | 0 | case RT_ITER_STATE_INIT: |
740 | 0 | case RT_ITER_STATE_PAUSED: |
741 | 0 | case RT_ITER_STATE_DONE: |
742 | 0 | return; |
743 | | |
744 | 0 | case RT_ITER_STATE_ITERATING: |
745 | | |
746 | | /* |
747 | | * Save the prefix that we are currently at. The next call to |
748 | | * route_table_iter_next() will return the node after this |
749 | | * prefix |
750 | | * in the tree. |
751 | | */ |
752 | 0 | prefix_copy(&iter->pause_prefix, &iter->current->p); |
753 | 0 | route_unlock_node(iter->current); |
754 | 0 | iter->current = NULL; |
755 | 0 | iter->state = RT_ITER_STATE_PAUSED; |
756 | 0 | return; |
757 | | |
758 | 0 | default: |
759 | 0 | assert(0); |
760 | 0 | } |
761 | 0 | } |
762 | | |
763 | | /* |
764 | | * route_table_iter_cleanup |
765 | | * |
766 | | * Release any resources held by the iterator. |
767 | | */ |
768 | | void route_table_iter_cleanup(route_table_iter_t *iter) |
769 | 0 | { |
770 | 0 | if (iter->state == RT_ITER_STATE_ITERATING) { |
771 | 0 | route_unlock_node(iter->current); |
772 | 0 | iter->current = NULL; |
773 | 0 | } |
774 | 0 | assert(!iter->current); |
775 | | |
776 | | /* |
777 | | * Set the state to RT_ITER_STATE_DONE to make any |
778 | | * route_table_iter_next() calls on this iterator return NULL. |
779 | | */ |
780 | 0 | iter->state = RT_ITER_STATE_DONE; |
781 | 0 | } |