blob: 19b5d1b18e060c8ad88a5948084411fae273f813 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
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
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -070030static void route_node_delete (struct route_node *);
31static void route_table_free (struct route_table *);
paul718e3742002-12-13 20:15:29 +000032
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -070033
34/*
35 * route_table_init_with_delegate
36 */
paul718e3742002-12-13 20:15:29 +000037struct route_table *
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -070038route_table_init_with_delegate (route_table_delegate_t *delegate)
paul718e3742002-12-13 20:15:29 +000039{
40 struct route_table *rt;
41
42 rt = XCALLOC (MTYPE_ROUTE_TABLE, sizeof (struct route_table));
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -070043 rt->delegate = delegate;
paul718e3742002-12-13 20:15:29 +000044 return rt;
45}
46
47void
48route_table_finish (struct route_table *rt)
49{
50 route_table_free (rt);
51}
52
53/* Allocate new route node. */
paul8cc41982005-05-06 21:25:49 +000054static struct route_node *
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -070055route_node_new (struct route_table *table)
paul718e3742002-12-13 20:15:29 +000056{
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -070057 return table->delegate->create_node (table->delegate, table);
paul718e3742002-12-13 20:15:29 +000058}
59
60/* Allocate new route node with prefix set. */
paul8cc41982005-05-06 21:25:49 +000061static struct route_node *
paul718e3742002-12-13 20:15:29 +000062route_node_set (struct route_table *table, struct prefix *prefix)
63{
64 struct route_node *node;
65
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -070066 node = route_node_new (table);
paul718e3742002-12-13 20:15:29 +000067
68 prefix_copy (&node->p, prefix);
69 node->table = table;
70
71 return node;
72}
73
74/* Free route node. */
paul8cc41982005-05-06 21:25:49 +000075static void
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -070076route_node_free (struct route_table *table, struct route_node *node)
paul718e3742002-12-13 20:15:29 +000077{
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -070078 table->delegate->destroy_node (table->delegate, table, node);
paul718e3742002-12-13 20:15:29 +000079}
80
81/* Free route table. */
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -070082static void
paul718e3742002-12-13 20:15:29 +000083route_table_free (struct route_table *rt)
84{
85 struct route_node *tmp_node;
86 struct route_node *node;
87
88 if (rt == NULL)
89 return;
90
91 node = rt->top;
92
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -070093 /* 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. */
paul718e3742002-12-13 20:15:29 +000096 while (node)
97 {
98 if (node->l_left)
99 {
100 node = node->l_left;
101 continue;
102 }
103
104 if (node->l_right)
105 {
106 node = node->l_right;
107 continue;
108 }
109
110 tmp_node = node;
111 node = node->parent;
112
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -0700113 tmp_node->table->count--;
114 tmp_node->lock = 0; /* to cause assert if unlocked after this */
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -0700115 route_node_free (rt, tmp_node);
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -0700116
paul718e3742002-12-13 20:15:29 +0000117 if (node != NULL)
118 {
119 if (node->l_left == tmp_node)
120 node->l_left = NULL;
121 else
122 node->l_right = NULL;
paul718e3742002-12-13 20:15:29 +0000123 }
124 else
125 {
paul718e3742002-12-13 20:15:29 +0000126 break;
127 }
128 }
129
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -0700130 assert (rt->count == 0);
131
paul718e3742002-12-13 20:15:29 +0000132 XFREE (MTYPE_ROUTE_TABLE, rt);
133 return;
134}
135
136/* Utility mask array. */
Stephen Hemminger38cc00c2009-12-08 12:00:50 +0300137static const u_char maskbit[] =
paul718e3742002-12-13 20:15:29 +0000138{
139 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
140};
141
142/* Common prefix route genaration. */
143static void
144route_common (struct prefix *n, struct prefix *p, struct prefix *new)
145{
146 int i;
147 u_char diff;
148 u_char mask;
149
150 u_char *np = (u_char *)&n->u.prefix;
151 u_char *pp = (u_char *)&p->u.prefix;
152 u_char *newp = (u_char *)&new->u.prefix;
153
154 for (i = 0; i < p->prefixlen / 8; i++)
155 {
156 if (np[i] == pp[i])
157 newp[i] = np[i];
158 else
159 break;
160 }
161
162 new->prefixlen = i * 8;
163
164 if (new->prefixlen != p->prefixlen)
165 {
166 diff = np[i] ^ pp[i];
167 mask = 0x80;
168 while (new->prefixlen < p->prefixlen && !(mask & diff))
169 {
170 mask >>= 1;
171 new->prefixlen++;
172 }
173 newp[i] = np[i] & maskbit[new->prefixlen % 8];
174 }
175}
176
paul718e3742002-12-13 20:15:29 +0000177static void
178set_link (struct route_node *node, struct route_node *new)
179{
Stephen Hemminger1352ef32009-12-09 14:43:17 +0300180 unsigned int bit = prefix_bit (&new->p.u.prefix, node->p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000181
182 node->link[bit] = new;
183 new->parent = node;
184}
185
186/* Lock node. */
187struct route_node *
188route_lock_node (struct route_node *node)
189{
190 node->lock++;
191 return node;
192}
193
194/* Unlock node. */
195void
196route_unlock_node (struct route_node *node)
197{
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -0700198 assert (node->lock > 0);
paul718e3742002-12-13 20:15:29 +0000199 node->lock--;
200
201 if (node->lock == 0)
202 route_node_delete (node);
203}
204
paul718e3742002-12-13 20:15:29 +0000205/* Find matched prefix. */
206struct route_node *
Stephen Hemminger38cc00c2009-12-08 12:00:50 +0300207route_node_match (const struct route_table *table, const struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000208{
209 struct route_node *node;
210 struct route_node *matched;
211
212 matched = NULL;
213 node = table->top;
214
215 /* Walk down tree. If there is matched route then store it to
216 matched. */
217 while (node && node->p.prefixlen <= p->prefixlen &&
218 prefix_match (&node->p, p))
219 {
220 if (node->info)
221 matched = node;
Paul Jakmaf8416812010-04-13 22:42:33 +0100222
223 if (node->p.prefixlen == p->prefixlen)
224 break;
225
Stephen Hemminger1352ef32009-12-09 14:43:17 +0300226 node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
paul718e3742002-12-13 20:15:29 +0000227 }
228
229 /* If matched route found, return it. */
230 if (matched)
231 return route_lock_node (matched);
232
233 return NULL;
234}
235
236struct route_node *
Stephen Hemminger38cc00c2009-12-08 12:00:50 +0300237route_node_match_ipv4 (const struct route_table *table,
238 const struct in_addr *addr)
paul718e3742002-12-13 20:15:29 +0000239{
240 struct prefix_ipv4 p;
241
242 memset (&p, 0, sizeof (struct prefix_ipv4));
243 p.family = AF_INET;
244 p.prefixlen = IPV4_MAX_PREFIXLEN;
245 p.prefix = *addr;
246
247 return route_node_match (table, (struct prefix *) &p);
248}
249
250#ifdef HAVE_IPV6
251struct route_node *
Stephen Hemminger38cc00c2009-12-08 12:00:50 +0300252route_node_match_ipv6 (const struct route_table *table,
253 const struct in6_addr *addr)
paul718e3742002-12-13 20:15:29 +0000254{
255 struct prefix_ipv6 p;
256
257 memset (&p, 0, sizeof (struct prefix_ipv6));
258 p.family = AF_INET6;
259 p.prefixlen = IPV6_MAX_PREFIXLEN;
260 p.prefix = *addr;
261
262 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. */
267struct route_node *
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -0700268route_node_lookup (const struct route_table *table, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000269{
270 struct route_node *node;
Jorge Boncompte [DTI2]47d3b602012-05-07 16:53:11 +0000271 u_char prefixlen = p->prefixlen;
272 const u_char *prefix = &p->u.prefix;
paul718e3742002-12-13 20:15:29 +0000273
274 node = table->top;
275
Jorge Boncompte [DTI2]47d3b602012-05-07 16:53:11 +0000276 while (node && node->p.prefixlen <= prefixlen &&
paul718e3742002-12-13 20:15:29 +0000277 prefix_match (&node->p, p))
278 {
Jorge Boncompte [DTI2]47d3b602012-05-07 16:53:11 +0000279 if (node->p.prefixlen == prefixlen)
Paul Jakmaf8416812010-04-13 22:42:33 +0100280 return node->info ? route_lock_node (node) : NULL;
paul718e3742002-12-13 20:15:29 +0000281
Jorge Boncompte [DTI2]47d3b602012-05-07 16:53:11 +0000282 node = node->link[prefix_bit(prefix, node->p.prefixlen)];
paul718e3742002-12-13 20:15:29 +0000283 }
284
285 return NULL;
286}
287
288/* Add node to routing table. */
289struct route_node *
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -0700290route_node_get (struct route_table *const table, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000291{
292 struct route_node *new;
293 struct route_node *node;
294 struct route_node *match;
Jorge Boncompte [DTI2]47d3b602012-05-07 16:53:11 +0000295 u_char prefixlen = p->prefixlen;
296 const u_char *prefix = &p->u.prefix;
paul718e3742002-12-13 20:15:29 +0000297
298 match = NULL;
299 node = table->top;
Jorge Boncompte [DTI2]47d3b602012-05-07 16:53:11 +0000300 while (node && node->p.prefixlen <= prefixlen &&
paul718e3742002-12-13 20:15:29 +0000301 prefix_match (&node->p, p))
302 {
Jorge Boncompte [DTI2]47d3b602012-05-07 16:53:11 +0000303 if (node->p.prefixlen == prefixlen)
Paul Jakmaf8416812010-04-13 22:42:33 +0100304 return route_lock_node (node);
Jorge Boncompte [DTI2]47d3b602012-05-07 16:53:11 +0000305
paul718e3742002-12-13 20:15:29 +0000306 match = node;
Jorge Boncompte [DTI2]47d3b602012-05-07 16:53:11 +0000307 node = node->link[prefix_bit(prefix, node->p.prefixlen)];
paul718e3742002-12-13 20:15:29 +0000308 }
309
310 if (node == NULL)
311 {
312 new = route_node_set (table, p);
313 if (match)
314 set_link (match, new);
315 else
316 table->top = new;
317 }
318 else
319 {
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -0700320 new = route_node_new (table);
paul718e3742002-12-13 20:15:29 +0000321 route_common (&node->p, p, &new->p);
322 new->p.family = p->family;
323 new->table = table;
324 set_link (new, node);
325
326 if (match)
327 set_link (match, new);
328 else
329 table->top = new;
330
331 if (new->p.prefixlen != p->prefixlen)
332 {
333 match = new;
334 new = route_node_set (table, p);
335 set_link (match, new);
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -0700336 table->count++;
paul718e3742002-12-13 20:15:29 +0000337 }
338 }
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -0700339 table->count++;
paul718e3742002-12-13 20:15:29 +0000340 route_lock_node (new);
341
342 return new;
343}
344
345/* Delete node from the routing table. */
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -0700346static void
paul718e3742002-12-13 20:15:29 +0000347route_node_delete (struct route_node *node)
348{
349 struct route_node *child;
350 struct route_node *parent;
351
352 assert (node->lock == 0);
353 assert (node->info == NULL);
354
355 if (node->l_left && node->l_right)
356 return;
357
358 if (node->l_left)
359 child = node->l_left;
360 else
361 child = node->l_right;
362
363 parent = node->parent;
364
365 if (child)
366 child->parent = parent;
367
368 if (parent)
369 {
370 if (parent->l_left == node)
371 parent->l_left = child;
372 else
373 parent->l_right = child;
374 }
375 else
376 node->table->top = child;
377
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -0700378 node->table->count--;
379
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -0700380 route_node_free (node->table, node);
paul718e3742002-12-13 20:15:29 +0000381
382 /* If parent node is stub then delete it also. */
383 if (parent && parent->lock == 0)
384 route_node_delete (parent);
385}
386
387/* Get fist node and lock it. This function is useful when one want
388 to lookup all the node exist in the routing table. */
389struct route_node *
390route_top (struct route_table *table)
391{
392 /* If there is no node in the routing table return NULL. */
393 if (table->top == NULL)
394 return NULL;
395
396 /* Lock the top node and return it. */
397 route_lock_node (table->top);
398 return table->top;
399}
400
401/* Unlock current node and lock next node then return it. */
402struct route_node *
403route_next (struct route_node *node)
404{
405 struct route_node *next;
406 struct route_node *start;
407
408 /* Node may be deleted from route_unlock_node so we have to preserve
409 next node's pointer. */
410
411 if (node->l_left)
412 {
413 next = node->l_left;
414 route_lock_node (next);
415 route_unlock_node (node);
416 return next;
417 }
418 if (node->l_right)
419 {
420 next = node->l_right;
421 route_lock_node (next);
422 route_unlock_node (node);
423 return next;
424 }
425
426 start = node;
427 while (node->parent)
428 {
429 if (node->parent->l_left == node && node->parent->l_right)
430 {
431 next = node->parent->l_right;
432 route_lock_node (next);
433 route_unlock_node (start);
434 return next;
435 }
436 node = node->parent;
437 }
438 route_unlock_node (start);
439 return NULL;
440}
441
442/* Unlock current node and lock next node until limit. */
443struct route_node *
444route_next_until (struct route_node *node, struct route_node *limit)
445{
446 struct route_node *next;
447 struct route_node *start;
448
449 /* Node may be deleted from route_unlock_node so we have to preserve
450 next node's pointer. */
451
452 if (node->l_left)
453 {
454 next = node->l_left;
455 route_lock_node (next);
456 route_unlock_node (node);
457 return next;
458 }
459 if (node->l_right)
460 {
461 next = node->l_right;
462 route_lock_node (next);
463 route_unlock_node (node);
464 return next;
465 }
466
467 start = node;
468 while (node->parent && node != limit)
469 {
470 if (node->parent->l_left == node && node->parent->l_right)
471 {
472 next = node->parent->l_right;
473 route_lock_node (next);
474 route_unlock_node (start);
475 return next;
476 }
477 node = node->parent;
478 }
479 route_unlock_node (start);
480 return NULL;
481}
Avneesh Sachdev3eb8ef32012-08-17 08:19:47 -0700482
483unsigned long
484route_table_count (const struct route_table *table)
485{
486 return table->count;
487}
Avneesh Sachdevf9c1b7b2012-08-17 08:19:48 -0700488
489/**
490 * route_node_create
491 *
492 * Default function for creating a route node.
493 */
494static struct route_node *
495route_node_create (route_table_delegate_t *delegate,
496 struct route_table *table)
497{
498 struct route_node *node;
499 node = XCALLOC (MTYPE_ROUTE_NODE, sizeof (struct route_node));
500 return node;
501}
502
503/**
504 * route_node_destroy
505 *
506 * Default function for destroying a route node.
507 */
508static void
509route_node_destroy (route_table_delegate_t *delegate,
510 struct route_table *table, struct route_node *node)
511{
512 XFREE (MTYPE_ROUTE_NODE, node);
513}
514
515/*
516 * Default delegate.
517 */
518static route_table_delegate_t default_delegate = {
519 .create_node = route_node_create,
520 .destroy_node = route_node_destroy
521};
522
523/*
524 * route_table_init
525 */
526struct route_table *
527route_table_init (void)
528{
529 return route_table_init_with_delegate (&default_delegate);
530}
Avneesh Sachdev28971c82012-08-17 08:19:50 -0700531
532/**
533 * route_table_prefix_iter_cmp
534 *
535 * Compare two prefixes according to the order in which they appear in
536 * an iteration over a tree.
537 *
538 * @return -1 if p1 occurs before p2 (p1 < p2)
539 * 0 if the prefixes are identical (p1 == p2)
540 * +1 if p1 occurs after p2 (p1 > p2)
541 */
542int
543route_table_prefix_iter_cmp (struct prefix *p1, struct prefix *p2)
544{
545 struct prefix common_space;
546 struct prefix *common = &common_space;
547
548 if (p1->prefixlen <= p2->prefixlen)
549 {
550 if (prefix_match (p1, p2))
551 {
552
553 /*
554 * p1 contains p2, or is equal to it.
555 */
556 return (p1->prefixlen == p2->prefixlen) ? 0 : -1;
557 }
558 }
559 else
560 {
561
562 /*
563 * Check if p2 contains p1.
564 */
565 if (prefix_match (p2, p1))
566 return 1;
567 }
568
569 route_common (p1, p2, common);
570 assert (common->prefixlen < p1->prefixlen);
571 assert (common->prefixlen < p2->prefixlen);
572
573 /*
574 * Both prefixes are longer than the common prefix.
575 *
576 * We need to check the bit after the common prefixlen to determine
577 * which one comes later.
578 */
579 if (prefix_bit (&p1->u.prefix, common->prefixlen))
580 {
581
582 /*
583 * We branch to the right to get to p1 from the common prefix.
584 */
585 assert (!prefix_bit (&p2->u.prefix, common->prefixlen));
586 return 1;
587 }
588
589 /*
590 * We branch to the right to get to p2 from the common prefix.
591 */
592 assert (prefix_bit (&p2->u.prefix, common->prefixlen));
593 return -1;
594}
595
596/*
597 * route_get_subtree_next
598 *
599 * Helper function that returns the first node that follows the nodes
600 * in the sub-tree under 'node' in iteration order.
601 */
602static struct route_node *
603route_get_subtree_next (struct route_node *node)
604{
605 while (node->parent)
606 {
607 if (node->parent->l_left == node && node->parent->l_right)
608 return node->parent->l_right;
609
610 node = node->parent;
611 }
612
613 return NULL;
614}
615
616/**
617 * route_table_get_next_internal
618 *
619 * Helper function to find the node that occurs after the given prefix in
620 * order of iteration.
621 *
622 * @see route_table_get_next
623 */
624static struct route_node *
625route_table_get_next_internal (const struct route_table *table,
626 struct prefix *p)
627{
628 struct route_node *node, *tmp_node;
629 u_char prefixlen;
630 int cmp;
631
632 prefixlen = p->prefixlen;
633
634 node = table->top;
635
636 while (node)
637 {
638 int match;
639
640 if (node->p.prefixlen < p->prefixlen)
641 match = prefix_match (&node->p, p);
642 else
643 match = prefix_match (p, &node->p);
644
645 if (match)
646 {
647 if (node->p.prefixlen == p->prefixlen)
648 {
649
650 /*
651 * The prefix p exists in the tree, just return the next
652 * node.
653 */
654 route_lock_node (node);
655 node = route_next (node);
656 if (node)
657 route_unlock_node (node);
658
659 return (node);
660 }
661
662 if (node->p.prefixlen > p->prefixlen)
663 {
664
665 /*
666 * Node is in the subtree of p, and hence greater than p.
667 */
668 return node;
669 }
670
671 /*
672 * p is in the sub-tree under node.
673 */
674 tmp_node = node->link[prefix_bit (&p->u.prefix, node->p.prefixlen)];
675
676 if (tmp_node)
677 {
678 node = tmp_node;
679 continue;
680 }
681
682 /*
683 * There are no nodes in the direction where p should be. If
684 * node has a right child, then it must be greater than p.
685 */
686 if (node->l_right)
687 return node->l_right;
688
689 /*
690 * No more children to follow, go upwards looking for the next
691 * node.
692 */
693 return route_get_subtree_next (node);
694 }
695
696 /*
697 * Neither node prefix nor 'p' contains the other.
698 */
699 cmp = route_table_prefix_iter_cmp (&node->p, p);
700 if (cmp > 0)
701 {
702
703 /*
704 * Node follows p in iteration order. Return it.
705 */
706 return node;
707 }
708
709 assert (cmp < 0);
710
711 /*
712 * Node and the subtree under it come before prefix p in
713 * iteration order. Prefix p and its sub-tree are not present in
714 * the tree. Go upwards and find the first node that follows the
715 * subtree. That node will also succeed p.
716 */
717 return route_get_subtree_next (node);
718 }
719
720 return NULL;
721}
722
723/**
724 * route_table_get_next
725 *
726 * Find the node that occurs after the given prefix in order of
727 * iteration.
728 */
729struct route_node *
730route_table_get_next (const struct route_table *table, struct prefix *p)
731{
732 struct route_node *node;
733
734 node = route_table_get_next_internal (table, p);
735 if (node)
736 {
737 assert (route_table_prefix_iter_cmp (&node->p, p) > 0);
738 route_lock_node (node);
739 }
740 return node;
741}
742
743/*
744 * route_table_iter_init
745 */
746void
747route_table_iter_init (route_table_iter_t * iter, struct route_table *table)
748{
749 memset (iter, 0, sizeof (*iter));
750 iter->state = RT_ITER_STATE_INIT;
751 iter->table = table;
752}
753
754/*
755 * route_table_iter_pause
756 *
757 * Pause an iteration over the table. This allows the iteration to be
758 * resumed point after arbitrary additions/deletions from the table.
759 * An iteration can be resumed by just calling route_table_iter_next()
760 * on the iterator.
761 */
762void
763route_table_iter_pause (route_table_iter_t * iter)
764{
765 switch (iter->state)
766 {
767
768 case RT_ITER_STATE_INIT:
769 case RT_ITER_STATE_PAUSED:
770 case RT_ITER_STATE_DONE:
771 return;
772
773 case RT_ITER_STATE_ITERATING:
774
775 /*
776 * Save the prefix that we are currently at. The next call to
777 * route_table_iter_next() will return the node after this prefix
778 * in the tree.
779 */
780 prefix_copy (&iter->pause_prefix, &iter->current->p);
781 route_unlock_node (iter->current);
782 iter->current = NULL;
783 iter->state = RT_ITER_STATE_PAUSED;
784 return;
785
786 default:
787 assert (0);
788 }
789
790}
791
792/*
793 * route_table_iter_cleanup
794 *
795 * Release any resources held by the iterator.
796 */
797void
798route_table_iter_cleanup (route_table_iter_t * iter)
799{
800 if (iter->state == RT_ITER_STATE_ITERATING)
801 {
802 route_unlock_node (iter->current);
803 iter->current = NULL;
804 }
805 assert (!iter->current);
806
807 /*
808 * Set the state to RT_ITER_STATE_DONE to make any
809 * route_table_iter_next() calls on this iterator return NULL.
810 */
811 iter->state = RT_ITER_STATE_DONE;
812}