]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_nexthop.c
Merge pull request #3153 from adharkar/frr-scount
[mirror_frr.git] / bgpd / bgp_nexthop.c
1 /* BGP nexthop scan
2 * Copyright (C) 2000 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "command.h"
24 #include "thread.h"
25 #include "prefix.h"
26 #include "zclient.h"
27 #include "stream.h"
28 #include "network.h"
29 #include "log.h"
30 #include "memory.h"
31 #include "hash.h"
32 #include "jhash.h"
33 #include "nexthop.h"
34 #include "queue.h"
35 #include "filter.h"
36
37 #include "bgpd/bgpd.h"
38 #include "bgpd/bgp_table.h"
39 #include "bgpd/bgp_route.h"
40 #include "bgpd/bgp_attr.h"
41 #include "bgpd/bgp_nexthop.h"
42 #include "bgpd/bgp_nht.h"
43 #include "bgpd/bgp_debug.h"
44 #include "bgpd/bgp_damp.h"
45 #include "bgpd/bgp_fsm.h"
46 #include "bgpd/bgp_vty.h"
47 #include "zebra/rib.h"
48 #include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */
49
50 DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Address Intf String");
51
52 char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size)
53 {
54 prefix2str(&(bnc->node->p), buf, size);
55 return buf;
56 }
57
58 void bnc_nexthop_free(struct bgp_nexthop_cache *bnc)
59 {
60 nexthops_free(bnc->nexthop);
61 }
62
63 struct bgp_nexthop_cache *bnc_new(void)
64 {
65 struct bgp_nexthop_cache *bnc;
66
67 bnc = XCALLOC(MTYPE_BGP_NEXTHOP_CACHE,
68 sizeof(struct bgp_nexthop_cache));
69 LIST_INIT(&(bnc->paths));
70 return bnc;
71 }
72
73 void bnc_free(struct bgp_nexthop_cache *bnc)
74 {
75 bnc_nexthop_free(bnc);
76 XFREE(MTYPE_BGP_NEXTHOP_CACHE, bnc);
77 }
78
79 /* Reset and free all BGP nexthop cache. */
80 static void bgp_nexthop_cache_reset(struct bgp_table *table)
81 {
82 struct bgp_node *rn;
83 struct bgp_nexthop_cache *bnc;
84
85 for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
86 bnc = bgp_nexthop_get_node_info(rn);
87 if (bnc != NULL) {
88 bnc_free(bnc);
89 bgp_nexthop_set_node_info(rn, NULL);
90 bgp_unlock_node(rn);
91 }
92 }
93 }
94
95 static void *bgp_tip_hash_alloc(void *p)
96 {
97 const struct in_addr *val = (const struct in_addr *)p;
98 struct tip_addr *addr;
99
100 addr = XMALLOC(MTYPE_TIP_ADDR, sizeof(struct tip_addr));
101 addr->refcnt = 0;
102 addr->addr.s_addr = val->s_addr;
103
104 return addr;
105 }
106
107 static void bgp_tip_hash_free(void *addr)
108 {
109 XFREE(MTYPE_TIP_ADDR, addr);
110 }
111
112 static unsigned int bgp_tip_hash_key_make(void *p)
113 {
114 const struct tip_addr *addr = p;
115
116 return jhash_1word(addr->addr.s_addr, 0);
117 }
118
119 static int bgp_tip_hash_cmp(const void *p1, const void *p2)
120 {
121 const struct tip_addr *addr1 = p1;
122 const struct tip_addr *addr2 = p2;
123
124 return addr1->addr.s_addr == addr2->addr.s_addr;
125 }
126
127 void bgp_tip_hash_init(struct bgp *bgp)
128 {
129 bgp->tip_hash = hash_create(bgp_tip_hash_key_make, bgp_tip_hash_cmp,
130 "BGP TIP hash");
131 }
132
133 void bgp_tip_hash_destroy(struct bgp *bgp)
134 {
135 if (bgp->tip_hash == NULL)
136 return;
137 hash_clean(bgp->tip_hash, bgp_tip_hash_free);
138 hash_free(bgp->tip_hash);
139 bgp->tip_hash = NULL;
140 }
141
142 void bgp_tip_add(struct bgp *bgp, struct in_addr *tip)
143 {
144 struct tip_addr tmp;
145 struct tip_addr *addr;
146
147 tmp.addr = *tip;
148
149 addr = hash_get(bgp->tip_hash, &tmp, bgp_tip_hash_alloc);
150 if (!addr)
151 return;
152
153 addr->refcnt++;
154 }
155
156 void bgp_tip_del(struct bgp *bgp, struct in_addr *tip)
157 {
158 struct tip_addr tmp;
159 struct tip_addr *addr;
160
161 tmp.addr = *tip;
162
163 addr = hash_lookup(bgp->tip_hash, &tmp);
164 /* may have been deleted earlier by bgp_interface_down() */
165 if (addr == NULL)
166 return;
167
168 addr->refcnt--;
169
170 if (addr->refcnt == 0) {
171 hash_release(bgp->tip_hash, addr);
172 XFREE(MTYPE_TIP_ADDR, addr);
173 }
174 }
175
176 /* BGP own address structure */
177 struct bgp_addr {
178 struct in_addr addr;
179 struct list *ifp_name_list;
180 };
181
182 static void show_address_entry(struct hash_backet *backet, void *args)
183 {
184 struct vty *vty = (struct vty *)args;
185 struct bgp_addr *addr = (struct bgp_addr *)backet->data;
186 char *name;
187 struct listnode *node;
188
189 vty_out(vty, "addr: %s, count: %d : ", inet_ntoa(addr->addr),
190 addr->ifp_name_list->count);
191
192 for (ALL_LIST_ELEMENTS_RO(addr->ifp_name_list, node, name)) {
193 vty_out(vty, " %s,", name);
194 }
195
196 vty_out(vty, "\n");
197 }
198
199 void bgp_nexthop_show_address_hash(struct vty *vty, struct bgp *bgp)
200 {
201 hash_iterate(bgp->address_hash,
202 (void (*)(struct hash_backet *, void *))show_address_entry,
203 vty);
204 }
205
206 static void bgp_address_hash_string_del(void *val)
207 {
208 char *data = val;
209
210 XFREE(MTYPE_MARTIAN_STRING, data);
211 }
212
213 static void *bgp_address_hash_alloc(void *p)
214 {
215 const struct in_addr *val = (const struct in_addr *)p;
216 struct bgp_addr *addr;
217
218 addr = XMALLOC(MTYPE_BGP_ADDR, sizeof(struct bgp_addr));
219 addr->addr.s_addr = val->s_addr;
220
221 addr->ifp_name_list = list_new();
222 addr->ifp_name_list->del = bgp_address_hash_string_del;
223
224 return addr;
225 }
226
227 static void bgp_address_hash_free(void *data)
228 {
229 struct bgp_addr *addr = data;
230
231 list_delete(&addr->ifp_name_list);
232 XFREE(MTYPE_BGP_ADDR, addr);
233 }
234
235 static unsigned int bgp_address_hash_key_make(void *p)
236 {
237 const struct bgp_addr *addr = p;
238
239 return jhash_1word(addr->addr.s_addr, 0);
240 }
241
242 static int bgp_address_hash_cmp(const void *p1, const void *p2)
243 {
244 const struct bgp_addr *addr1 = p1;
245 const struct bgp_addr *addr2 = p2;
246
247 return addr1->addr.s_addr == addr2->addr.s_addr;
248 }
249
250 void bgp_address_init(struct bgp *bgp)
251 {
252 bgp->address_hash =
253 hash_create(bgp_address_hash_key_make, bgp_address_hash_cmp,
254 "BGP Address Hash");
255 }
256
257 void bgp_address_destroy(struct bgp *bgp)
258 {
259 if (bgp->address_hash == NULL)
260 return;
261 hash_clean(bgp->address_hash, bgp_address_hash_free);
262 hash_free(bgp->address_hash);
263 bgp->address_hash = NULL;
264 }
265
266 static void bgp_address_add(struct bgp *bgp, struct connected *ifc,
267 struct prefix *p)
268 {
269 struct bgp_addr tmp;
270 struct bgp_addr *addr;
271 struct listnode *node;
272 char *name;
273
274 tmp.addr = p->u.prefix4;
275
276 addr = hash_get(bgp->address_hash, &tmp, bgp_address_hash_alloc);
277
278 for (ALL_LIST_ELEMENTS_RO(addr->ifp_name_list, node, name)) {
279 if (strcmp(ifc->ifp->name, name) == 0)
280 break;
281 }
282 if (!node) {
283 name = XSTRDUP(MTYPE_MARTIAN_STRING, ifc->ifp->name);
284 listnode_add(addr->ifp_name_list, name);
285 }
286 }
287
288 static void bgp_address_del(struct bgp *bgp, struct connected *ifc,
289 struct prefix *p)
290 {
291 struct bgp_addr tmp;
292 struct bgp_addr *addr;
293 struct listnode *node;
294 char *name;
295
296 tmp.addr = p->u.prefix4;
297
298 addr = hash_lookup(bgp->address_hash, &tmp);
299 /* may have been deleted earlier by bgp_interface_down() */
300 if (addr == NULL)
301 return;
302
303 for (ALL_LIST_ELEMENTS_RO(addr->ifp_name_list, node, name)) {
304 if (strcmp(ifc->ifp->name, name) == 0)
305 break;
306 }
307
308 if (node) {
309 list_delete_node(addr->ifp_name_list, node);
310 XFREE(MTYPE_MARTIAN_STRING, name);
311 }
312
313 if (addr->ifp_name_list->count == 0) {
314 hash_release(bgp->address_hash, addr);
315 list_delete(&addr->ifp_name_list);
316 XFREE(MTYPE_BGP_ADDR, addr);
317 }
318 }
319
320
321 struct bgp_connected_ref {
322 unsigned int refcnt;
323 };
324
325 void bgp_connected_add(struct bgp *bgp, struct connected *ifc)
326 {
327 struct prefix p;
328 struct prefix *addr;
329 struct bgp_node *rn;
330 struct bgp_connected_ref *bc;
331 struct listnode *node, *nnode;
332 struct peer *peer;
333
334 addr = ifc->address;
335
336 p = *(CONNECTED_PREFIX(ifc));
337 if (addr->family == AF_INET) {
338 apply_mask_ipv4((struct prefix_ipv4 *)&p);
339
340 if (prefix_ipv4_any((struct prefix_ipv4 *)&p))
341 return;
342
343 bgp_address_add(bgp, ifc, addr);
344
345 rn = bgp_node_get(bgp->connected_table[AFI_IP],
346 (struct prefix *)&p);
347 bc = bgp_connected_get_node_info(rn);
348 if (bc)
349 bc->refcnt++;
350 else {
351 bc = XCALLOC(MTYPE_BGP_CONN,
352 sizeof(struct bgp_connected_ref));
353 bc->refcnt = 1;
354 bgp_connected_set_node_info(rn, bc);
355 }
356
357 for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
358 if (peer->conf_if
359 && (strcmp(peer->conf_if, ifc->ifp->name) == 0)
360 && peer->status != Established
361 && !CHECK_FLAG(peer->flags,
362 PEER_FLAG_IFPEER_V6ONLY)) {
363 if (peer_active(peer))
364 BGP_EVENT_ADD(peer, BGP_Stop);
365 BGP_EVENT_ADD(peer, BGP_Start);
366 }
367 }
368 } else if (addr->family == AF_INET6) {
369 apply_mask_ipv6((struct prefix_ipv6 *)&p);
370
371 if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6))
372 return;
373
374 if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
375 return;
376
377 rn = bgp_node_get(bgp->connected_table[AFI_IP6],
378 (struct prefix *)&p);
379
380 bc = bgp_connected_get_node_info(rn);
381 if (bc)
382 bc->refcnt++;
383 else {
384 bc = XCALLOC(MTYPE_BGP_CONN,
385 sizeof(struct bgp_connected_ref));
386 bc->refcnt = 1;
387 bgp_connected_set_node_info(rn, bc);
388 }
389 }
390 }
391
392 void bgp_connected_delete(struct bgp *bgp, struct connected *ifc)
393 {
394 struct prefix p;
395 struct prefix *addr;
396 struct bgp_node *rn = NULL;
397 struct bgp_connected_ref *bc;
398
399 addr = ifc->address;
400
401 p = *(CONNECTED_PREFIX(ifc));
402 apply_mask(&p);
403 if (addr->family == AF_INET) {
404 if (prefix_ipv4_any((struct prefix_ipv4 *)&p))
405 return;
406
407 bgp_address_del(bgp, ifc, addr);
408
409 rn = bgp_node_lookup(bgp->connected_table[AFI_IP], &p);
410 } else if (addr->family == AF_INET6) {
411 if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6))
412 return;
413
414 if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
415 return;
416
417 rn = bgp_node_lookup(bgp->connected_table[AFI_IP6],
418 (struct prefix *)&p);
419 }
420
421 if (!rn)
422 return;
423
424 bc = bgp_connected_get_node_info(rn);
425 bc->refcnt--;
426 if (bc->refcnt == 0) {
427 XFREE(MTYPE_BGP_CONN, bc);
428 bgp_connected_set_node_info(rn, NULL);
429 }
430 bgp_unlock_node(rn);
431 bgp_unlock_node(rn);
432 }
433
434 static void bgp_connected_cleanup(struct route_table *table,
435 struct route_node *rn)
436 {
437 struct bgp_connected_ref *bc;
438 struct bgp_node *bn = bgp_node_from_rnode(rn);
439
440 bc = bgp_connected_get_node_info(bn);
441 if (!bc)
442 return;
443
444 bc->refcnt--;
445 if (bc->refcnt == 0) {
446 XFREE(MTYPE_BGP_CONN, bc);
447 bgp_connected_set_node_info(bn, NULL);
448 }
449 }
450
451 int bgp_nexthop_self(struct bgp *bgp, struct in_addr nh_addr)
452 {
453 struct bgp_addr tmp, *addr;
454 struct tip_addr tmp_tip, *tip;
455
456 tmp.addr = nh_addr;
457
458 addr = hash_lookup(bgp->address_hash, &tmp);
459 if (addr)
460 return 1;
461
462 tmp_tip.addr = nh_addr;
463 tip = hash_lookup(bgp->tip_hash, &tmp_tip);
464 if (tip)
465 return 1;
466
467 return 0;
468 }
469
470 int bgp_multiaccess_check_v4(struct in_addr nexthop, struct peer *peer)
471 {
472 struct bgp_node *rn1;
473 struct bgp_node *rn2;
474 struct prefix p;
475 int ret;
476
477 p.family = AF_INET;
478 p.prefixlen = IPV4_MAX_BITLEN;
479 p.u.prefix4 = nexthop;
480
481 rn1 = bgp_node_match(peer->bgp->connected_table[AFI_IP], &p);
482 if (!rn1)
483 return 0;
484
485 p.family = AF_INET;
486 p.prefixlen = IPV4_MAX_BITLEN;
487 p.u.prefix4 = peer->su.sin.sin_addr;
488
489 rn2 = bgp_node_match(peer->bgp->connected_table[AFI_IP], &p);
490 if (!rn2) {
491 bgp_unlock_node(rn1);
492 return 0;
493 }
494
495 ret = (rn1 == rn2) ? 1 : 0;
496
497 bgp_unlock_node(rn1);
498 bgp_unlock_node(rn2);
499
500 return (ret);
501 }
502
503 int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
504 struct update_subgroup *subgrp)
505 {
506 struct bgp_node *rn1, *rn2;
507 struct peer_af *paf;
508 struct prefix p, np;
509 struct bgp *bgp;
510
511 np.family = AF_INET;
512 np.prefixlen = IPV4_MAX_BITLEN;
513 np.u.prefix4 = nexthop;
514
515 p.family = AF_INET;
516 p.prefixlen = IPV4_MAX_BITLEN;
517
518 bgp = SUBGRP_INST(subgrp);
519 rn1 = bgp_node_match(bgp->connected_table[AFI_IP], &np);
520 if (!rn1)
521 return 0;
522
523 SUBGRP_FOREACH_PEER (subgrp, paf) {
524 p.u.prefix4 = paf->peer->su.sin.sin_addr;
525
526 rn2 = bgp_node_match(bgp->connected_table[AFI_IP], &p);
527 if (rn1 == rn2) {
528 bgp_unlock_node(rn1);
529 bgp_unlock_node(rn2);
530 return 1;
531 }
532
533 if (rn2)
534 bgp_unlock_node(rn2);
535 }
536
537 bgp_unlock_node(rn1);
538 return 0;
539 }
540
541 static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
542 struct bgp_nexthop_cache *bnc)
543 {
544 char buf[PREFIX2STR_BUFFER];
545 struct nexthop *nexthop;
546
547 for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next)
548 switch (nexthop->type) {
549 case NEXTHOP_TYPE_IPV6:
550 vty_out(vty, " gate %s\n",
551 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
552 sizeof(buf)));
553 break;
554 case NEXTHOP_TYPE_IPV6_IFINDEX:
555 vty_out(vty, " gate %s, if %s\n",
556 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
557 sizeof(buf)),
558 ifindex2ifname(nexthop->ifindex, bgp->vrf_id));
559 break;
560 case NEXTHOP_TYPE_IPV4:
561 vty_out(vty, " gate %s\n",
562 inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
563 sizeof(buf)));
564 break;
565 case NEXTHOP_TYPE_IFINDEX:
566 vty_out(vty, " if %s\n",
567 ifindex2ifname(nexthop->ifindex, bgp->vrf_id));
568 break;
569 case NEXTHOP_TYPE_IPV4_IFINDEX:
570 vty_out(vty, " gate %s, if %s\n",
571 inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
572 sizeof(buf)),
573 ifindex2ifname(nexthop->ifindex, bgp->vrf_id));
574 break;
575 case NEXTHOP_TYPE_BLACKHOLE:
576 vty_out(vty, " blackhole\n");
577 break;
578 default:
579 vty_out(vty, " invalid nexthop type %u\n",
580 nexthop->type);
581 }
582 }
583
584 static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail)
585 {
586 struct bgp_node *rn;
587 struct bgp_nexthop_cache *bnc;
588 char buf[PREFIX2STR_BUFFER];
589 time_t tbuf;
590 afi_t afi;
591
592 vty_out(vty, "Current BGP nexthop cache:\n");
593 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
594 if (!bgp->nexthop_cache_table[afi])
595 continue;
596
597 for (rn = bgp_table_top(bgp->nexthop_cache_table[afi]); rn;
598 rn = bgp_route_next(rn)) {
599 bnc = bgp_nexthop_get_node_info(rn);
600 if (!bnc)
601 continue;
602
603 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
604 vty_out(vty,
605 " %s valid [IGP metric %d], #paths %d\n",
606 inet_ntop(rn->p.family,
607 &rn->p.u.prefix, buf,
608 sizeof(buf)),
609 bnc->metric, bnc->path_count);
610
611 if (!detail)
612 continue;
613
614 bgp_show_nexthops_detail(vty, bgp, bnc);
615
616 } else {
617 vty_out(vty, " %s invalid\n",
618 inet_ntop(rn->p.family,
619 &rn->p.u.prefix, buf,
620 sizeof(buf)));
621 if (CHECK_FLAG(bnc->flags,
622 BGP_NEXTHOP_CONNECTED))
623 vty_out(vty, " Must be Connected\n");
624 }
625 tbuf = time(NULL) - (bgp_clock() - bnc->last_update);
626 vty_out(vty, " Last update: %s", ctime(&tbuf));
627 vty_out(vty, "\n");
628 }
629 }
630 }
631
632 static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,
633 int detail)
634 {
635 struct bgp *bgp;
636
637 if (name)
638 bgp = bgp_lookup_by_name(name);
639 else
640 bgp = bgp_get_default();
641 if (!bgp) {
642 vty_out(vty, "%% No such BGP instance exist\n");
643 return CMD_WARNING;
644 }
645
646 bgp_show_nexthops(vty, bgp, detail);
647
648 return CMD_SUCCESS;
649 }
650
651 static void bgp_show_all_instances_nexthops_vty(struct vty *vty)
652 {
653 struct listnode *node, *nnode;
654 struct bgp *bgp;
655
656 for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
657 vty_out(vty, "\nInstance %s:\n",
658 (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
659 ? "Default"
660 : bgp->name);
661 bgp_show_nexthops(vty, bgp, 0);
662 }
663 }
664
665 DEFUN (show_ip_bgp_nexthop,
666 show_ip_bgp_nexthop_cmd,
667 "show [ip] bgp [<view|vrf> VIEWVRFNAME] nexthop [detail]",
668 SHOW_STR
669 IP_STR
670 BGP_STR
671 BGP_INSTANCE_HELP_STR
672 "BGP nexthop table\n"
673 "Show detailed information\n")
674 {
675 int idx = 0;
676 char *vrf = NULL;
677
678 if (argv_find(argv, argc, "view", &idx)
679 || argv_find(argv, argc, "vrf", &idx))
680 vrf = argv[++idx]->arg;
681 int detail = argv_find(argv, argc, "detail", &idx) ? 1 : 0;
682 return show_ip_bgp_nexthop_table(vty, vrf, detail);
683 }
684
685 DEFUN (show_ip_bgp_instance_all_nexthop,
686 show_ip_bgp_instance_all_nexthop_cmd,
687 "show [ip] bgp <view|vrf> all nexthop",
688 SHOW_STR
689 IP_STR
690 BGP_STR
691 BGP_INSTANCE_ALL_HELP_STR
692 "BGP nexthop table\n")
693 {
694 bgp_show_all_instances_nexthops_vty(vty);
695 return CMD_SUCCESS;
696 }
697
698 void bgp_scan_init(struct bgp *bgp)
699 {
700 afi_t afi;
701
702 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
703 bgp->nexthop_cache_table[afi] =
704 bgp_table_init(bgp, afi, SAFI_UNICAST);
705 bgp->connected_table[afi] = bgp_table_init(bgp, afi,
706 SAFI_UNICAST);
707 bgp->import_check_table[afi] =
708 bgp_table_init(bgp, afi, SAFI_UNICAST);
709 }
710 }
711
712 void bgp_scan_vty_init(void)
713 {
714 install_element(VIEW_NODE, &show_ip_bgp_nexthop_cmd);
715 install_element(VIEW_NODE, &show_ip_bgp_instance_all_nexthop_cmd);
716 }
717
718 void bgp_scan_finish(struct bgp *bgp)
719 {
720 afi_t afi;
721
722 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
723 /* Only the current one needs to be reset. */
724 bgp_nexthop_cache_reset(bgp->nexthop_cache_table[afi]);
725 bgp_table_unlock(bgp->nexthop_cache_table[afi]);
726 bgp->nexthop_cache_table[afi] = NULL;
727
728 bgp->connected_table[afi]->route_table->cleanup =
729 bgp_connected_cleanup;
730 bgp_table_unlock(bgp->connected_table[afi]);
731 bgp->connected_table[afi] = NULL;
732
733 bgp_table_unlock(bgp->import_check_table[afi]);
734 bgp->import_check_table[afi] = NULL;
735 }
736 }