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