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