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