]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_nexthop.c
Merge pull request #13017 from SaiGomathiN/12744
[mirror_frr.git] / bgpd / bgp_nexthop.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* BGP nexthop scan
3 * Copyright (C) 2000 Kunihiro Ishiguro
4 */
5
6 #include <zebra.h>
7
8 #include "command.h"
9 #include "frrevent.h"
10 #include "prefix.h"
11 #include "lib/json.h"
12 #include "zclient.h"
13 #include "stream.h"
14 #include "network.h"
15 #include "log.h"
16 #include "memory.h"
17 #include "hash.h"
18 #include "jhash.h"
19 #include "nexthop.h"
20 #include "queue.h"
21 #include "filter.h"
22 #include "printfrr.h"
23
24 #include "bgpd/bgpd.h"
25 #include "bgpd/bgp_route.h"
26 #include "bgpd/bgp_attr.h"
27 #include "bgpd/bgp_nexthop.h"
28 #include "bgpd/bgp_nht.h"
29 #include "bgpd/bgp_debug.h"
30 #include "bgpd/bgp_damp.h"
31 #include "bgpd/bgp_fsm.h"
32 #include "bgpd/bgp_vty.h"
33 #include "bgpd/bgp_rd.h"
34
35 DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Addr Intf String");
36
37 int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
38 const struct bgp_nexthop_cache *b)
39 {
40 if (a->srte_color < b->srte_color)
41 return -1;
42 if (a->srte_color > b->srte_color)
43 return 1;
44
45 if (a->ifindex < b->ifindex)
46 return -1;
47 if (a->ifindex > b->ifindex)
48 return 1;
49
50 return prefix_cmp(&a->prefix, &b->prefix);
51 }
52
53 void bnc_nexthop_free(struct bgp_nexthop_cache *bnc)
54 {
55 nexthops_free(bnc->nexthop);
56 }
57
58 struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree,
59 struct prefix *prefix, uint32_t srte_color,
60 ifindex_t ifindex)
61 {
62 struct bgp_nexthop_cache *bnc;
63
64 bnc = XCALLOC(MTYPE_BGP_NEXTHOP_CACHE,
65 sizeof(struct bgp_nexthop_cache));
66 bnc->prefix = *prefix;
67 bnc->ifindex = ifindex;
68 bnc->srte_color = srte_color;
69 bnc->tree = tree;
70 LIST_INIT(&(bnc->paths));
71 bgp_nexthop_cache_add(tree, bnc);
72
73 return bnc;
74 }
75
76 bool bnc_existing_for_prefix(struct bgp_nexthop_cache *bnc)
77 {
78 struct bgp_nexthop_cache *bnc_tmp;
79
80 frr_each (bgp_nexthop_cache, bnc->tree, bnc_tmp) {
81 if (bnc_tmp == bnc)
82 continue;
83 if (prefix_cmp(&bnc->prefix, &bnc_tmp->prefix) == 0)
84 return true;
85 }
86 return false;
87 }
88
89 void bnc_free(struct bgp_nexthop_cache *bnc)
90 {
91 bnc_nexthop_free(bnc);
92 bgp_nexthop_cache_del(bnc->tree, bnc);
93 XFREE(MTYPE_BGP_NEXTHOP_CACHE, bnc);
94 }
95
96 struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree,
97 struct prefix *prefix, uint32_t srte_color,
98 ifindex_t ifindex)
99 {
100 struct bgp_nexthop_cache bnc = {};
101
102 if (!tree)
103 return NULL;
104
105 bnc.prefix = *prefix;
106 bnc.srte_color = srte_color;
107 bnc.ifindex = ifindex;
108 return bgp_nexthop_cache_find(tree, &bnc);
109 }
110
111 /* Reset and free all BGP nexthop cache. */
112 static void bgp_nexthop_cache_reset(struct bgp_nexthop_cache_head *tree)
113 {
114 struct bgp_nexthop_cache *bnc;
115
116 while (bgp_nexthop_cache_count(tree) > 0) {
117 bnc = bgp_nexthop_cache_first(tree);
118
119 while (!LIST_EMPTY(&(bnc->paths))) {
120 struct bgp_path_info *path = LIST_FIRST(&(bnc->paths));
121
122 path_nh_map(path, bnc, false);
123 }
124
125 bnc_free(bnc);
126 }
127 }
128
129 static void *bgp_tip_hash_alloc(void *p)
130 {
131 const struct in_addr *val = (const struct in_addr *)p;
132 struct tip_addr *addr;
133
134 addr = XMALLOC(MTYPE_TIP_ADDR, sizeof(struct tip_addr));
135 addr->refcnt = 0;
136 addr->addr.s_addr = val->s_addr;
137
138 return addr;
139 }
140
141 static void bgp_tip_hash_free(void *addr)
142 {
143 XFREE(MTYPE_TIP_ADDR, addr);
144 }
145
146 static unsigned int bgp_tip_hash_key_make(const void *p)
147 {
148 const struct tip_addr *addr = p;
149
150 return jhash_1word(addr->addr.s_addr, 0);
151 }
152
153 static bool bgp_tip_hash_cmp(const void *p1, const void *p2)
154 {
155 const struct tip_addr *addr1 = p1;
156 const struct tip_addr *addr2 = p2;
157
158 return addr1->addr.s_addr == addr2->addr.s_addr;
159 }
160
161 void bgp_tip_hash_init(struct bgp *bgp)
162 {
163 bgp->tip_hash = hash_create(bgp_tip_hash_key_make, bgp_tip_hash_cmp,
164 "BGP TIP hash");
165 }
166
167 void bgp_tip_hash_destroy(struct bgp *bgp)
168 {
169 hash_clean_and_free(&bgp->tip_hash, bgp_tip_hash_free);
170 }
171
172 /* Add/Update Tunnel-IP entry of bgp martian next-hop table.
173 *
174 * Returns true only if we add a _new_ TIP so the caller knows that an
175 * actionable change has occurred. If we find an existing TIP then we
176 * only need to update the refcnt, since the collection of known TIPs
177 * has not changed.
178 */
179 bool bgp_tip_add(struct bgp *bgp, struct in_addr *tip)
180 {
181 struct tip_addr tmp;
182 struct tip_addr *addr;
183 bool tip_added = false;
184
185 tmp.addr = *tip;
186
187 addr = hash_lookup(bgp->tip_hash, &tmp);
188 if (!addr) {
189 addr = hash_get(bgp->tip_hash, &tmp, bgp_tip_hash_alloc);
190 tip_added = true;
191 }
192
193 addr->refcnt++;
194
195 return tip_added;
196 }
197
198 void bgp_tip_del(struct bgp *bgp, struct in_addr *tip)
199 {
200 struct tip_addr tmp;
201 struct tip_addr *addr;
202
203 tmp.addr = *tip;
204
205 addr = hash_lookup(bgp->tip_hash, &tmp);
206 /* may have been deleted earlier by bgp_interface_down() */
207 if (addr == NULL)
208 return;
209
210 addr->refcnt--;
211
212 if (addr->refcnt == 0) {
213 hash_release(bgp->tip_hash, addr);
214 XFREE(MTYPE_TIP_ADDR, addr);
215 }
216 }
217
218 /* BGP own address structure */
219 struct bgp_addr {
220 struct prefix p;
221 struct list *ifp_name_list;
222 };
223
224 static void show_address_entry(struct hash_bucket *bucket, void *args)
225 {
226 struct vty *vty = (struct vty *)args;
227 struct bgp_addr *addr = (struct bgp_addr *)bucket->data;
228 char *name;
229 struct listnode *node;
230 char str[INET6_ADDRSTRLEN] = {0};
231
232 vty_out(vty, "addr: %s, count: %d : ",
233 inet_ntop(addr->p.family, &(addr->p.u.prefix),
234 str, INET6_ADDRSTRLEN),
235 addr->ifp_name_list->count);
236
237 for (ALL_LIST_ELEMENTS_RO(addr->ifp_name_list, node, name)) {
238 vty_out(vty, " %s,", name);
239 }
240
241 vty_out(vty, "\n");
242 }
243
244 void bgp_nexthop_show_address_hash(struct vty *vty, struct bgp *bgp)
245 {
246 hash_iterate(bgp->address_hash,
247 (void (*)(struct hash_bucket *, void *))show_address_entry,
248 vty);
249 }
250
251 static void bgp_address_hash_string_del(void *val)
252 {
253 char *data = val;
254
255 XFREE(MTYPE_MARTIAN_STRING, data);
256 }
257
258 static void *bgp_address_hash_alloc(void *p)
259 {
260 struct bgp_addr *copy_addr = p;
261 struct bgp_addr *addr = NULL;
262
263 addr = XMALLOC(MTYPE_BGP_ADDR, sizeof(struct bgp_addr));
264 prefix_copy(&addr->p, &copy_addr->p);
265
266 addr->ifp_name_list = list_new();
267 addr->ifp_name_list->del = bgp_address_hash_string_del;
268
269 return addr;
270 }
271
272 static void bgp_address_hash_free(void *data)
273 {
274 struct bgp_addr *addr = data;
275
276 list_delete(&addr->ifp_name_list);
277 XFREE(MTYPE_BGP_ADDR, addr);
278 }
279
280 static unsigned int bgp_address_hash_key_make(const void *p)
281 {
282 const struct bgp_addr *addr = p;
283
284 return prefix_hash_key(&addr->p);
285 }
286
287 static bool bgp_address_hash_cmp(const void *p1, const void *p2)
288 {
289 const struct bgp_addr *addr1 = p1;
290 const struct bgp_addr *addr2 = p2;
291
292 return prefix_same(&addr1->p, &addr2->p);
293 }
294
295 void bgp_address_init(struct bgp *bgp)
296 {
297 bgp->address_hash =
298 hash_create(bgp_address_hash_key_make, bgp_address_hash_cmp,
299 "BGP Connected Address Hash");
300 }
301
302 void bgp_address_destroy(struct bgp *bgp)
303 {
304 hash_clean_and_free(&bgp->address_hash, bgp_address_hash_free);
305 }
306
307 static void bgp_address_add(struct bgp *bgp, struct connected *ifc,
308 struct prefix *p)
309 {
310 struct bgp_addr tmp;
311 struct bgp_addr *addr;
312 struct listnode *node;
313 char *name;
314
315 tmp.p = *p;
316
317 if (tmp.p.family == AF_INET)
318 tmp.p.prefixlen = IPV4_MAX_BITLEN;
319 else if (tmp.p.family == AF_INET6)
320 tmp.p.prefixlen = IPV6_MAX_BITLEN;
321
322 addr = hash_get(bgp->address_hash, &tmp, bgp_address_hash_alloc);
323
324 for (ALL_LIST_ELEMENTS_RO(addr->ifp_name_list, node, name)) {
325 if (strcmp(ifc->ifp->name, name) == 0)
326 break;
327 }
328 if (!node) {
329 name = XSTRDUP(MTYPE_MARTIAN_STRING, ifc->ifp->name);
330 listnode_add(addr->ifp_name_list, name);
331 }
332 }
333
334 static void bgp_address_del(struct bgp *bgp, struct connected *ifc,
335 struct prefix *p)
336 {
337 struct bgp_addr tmp;
338 struct bgp_addr *addr;
339 struct listnode *node;
340 char *name;
341
342 tmp.p = *p;
343
344 if (tmp.p.family == AF_INET)
345 tmp.p.prefixlen = IPV4_MAX_BITLEN;
346 else if (tmp.p.family == AF_INET6)
347 tmp.p.prefixlen = IPV6_MAX_BITLEN;
348
349 addr = hash_lookup(bgp->address_hash, &tmp);
350 /* may have been deleted earlier by bgp_interface_down() */
351 if (addr == NULL)
352 return;
353
354 for (ALL_LIST_ELEMENTS_RO(addr->ifp_name_list, node, name)) {
355 if (strcmp(ifc->ifp->name, name) == 0)
356 break;
357 }
358
359 if (node) {
360 list_delete_node(addr->ifp_name_list, node);
361 XFREE(MTYPE_MARTIAN_STRING, name);
362 }
363
364 if (addr->ifp_name_list->count == 0) {
365 hash_release(bgp->address_hash, addr);
366 list_delete(&addr->ifp_name_list);
367 XFREE(MTYPE_BGP_ADDR, addr);
368 }
369 }
370
371
372 struct bgp_connected_ref {
373 unsigned int refcnt;
374 };
375
376 void bgp_connected_add(struct bgp *bgp, struct connected *ifc)
377 {
378 struct prefix p;
379 struct prefix *addr;
380 struct bgp_dest *dest;
381 struct bgp_connected_ref *bc;
382 struct listnode *node, *nnode;
383 struct peer *peer;
384
385 addr = ifc->address;
386
387 p = *(CONNECTED_PREFIX(ifc));
388 if (addr->family == AF_INET) {
389 apply_mask_ipv4((struct prefix_ipv4 *)&p);
390
391 if (prefix_ipv4_any((struct prefix_ipv4 *)&p))
392 return;
393
394 bgp_address_add(bgp, ifc, addr);
395
396 dest = bgp_node_get(bgp->connected_table[AFI_IP], &p);
397 bc = bgp_dest_get_bgp_connected_ref_info(dest);
398 if (bc)
399 bc->refcnt++;
400 else {
401 bc = XCALLOC(MTYPE_BGP_CONN,
402 sizeof(struct bgp_connected_ref));
403 bc->refcnt = 1;
404 bgp_dest_set_bgp_connected_ref_info(dest, bc);
405 }
406
407 for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
408 if (peer->conf_if
409 && (strcmp(peer->conf_if, ifc->ifp->name) == 0)
410 && !peer_established(peer)
411 && !CHECK_FLAG(peer->flags,
412 PEER_FLAG_IFPEER_V6ONLY)) {
413 if (peer_active(peer))
414 BGP_EVENT_ADD(peer, BGP_Stop);
415 BGP_EVENT_ADD(peer, BGP_Start);
416 }
417 }
418 } else if (addr->family == AF_INET6) {
419 apply_mask_ipv6((struct prefix_ipv6 *)&p);
420
421 if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6))
422 return;
423
424 if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
425 return;
426
427 bgp_address_add(bgp, ifc, addr);
428
429 dest = bgp_node_get(bgp->connected_table[AFI_IP6], &p);
430
431 bc = bgp_dest_get_bgp_connected_ref_info(dest);
432 if (bc)
433 bc->refcnt++;
434 else {
435 bc = XCALLOC(MTYPE_BGP_CONN,
436 sizeof(struct bgp_connected_ref));
437 bc->refcnt = 1;
438 bgp_dest_set_bgp_connected_ref_info(dest, bc);
439 }
440 }
441 }
442
443 void bgp_connected_delete(struct bgp *bgp, struct connected *ifc)
444 {
445 struct prefix p;
446 struct prefix *addr;
447 struct bgp_dest *dest = NULL;
448 struct bgp_connected_ref *bc;
449
450 addr = ifc->address;
451
452 p = *(CONNECTED_PREFIX(ifc));
453 apply_mask(&p);
454 if (addr->family == AF_INET) {
455 if (prefix_ipv4_any((struct prefix_ipv4 *)&p))
456 return;
457
458 bgp_address_del(bgp, ifc, addr);
459
460 dest = bgp_node_lookup(bgp->connected_table[AFI_IP], &p);
461 } else if (addr->family == AF_INET6) {
462 if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6))
463 return;
464
465 if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
466 return;
467
468 bgp_address_del(bgp, ifc, addr);
469
470 dest = bgp_node_lookup(bgp->connected_table[AFI_IP6], &p);
471 }
472
473 if (!dest)
474 return;
475
476 bc = bgp_dest_get_bgp_connected_ref_info(dest);
477 bc->refcnt--;
478 if (bc->refcnt == 0) {
479 XFREE(MTYPE_BGP_CONN, bc);
480 bgp_dest_set_bgp_connected_ref_info(dest, NULL);
481 }
482 bgp_dest_unlock_node(dest);
483 bgp_dest_unlock_node(dest);
484 }
485
486 static void bgp_connected_cleanup(struct route_table *table,
487 struct route_node *rn)
488 {
489 struct bgp_connected_ref *bc;
490 struct bgp_dest *bn = bgp_dest_from_rnode(rn);
491
492 bc = bgp_dest_get_bgp_connected_ref_info(bn);
493 if (!bc)
494 return;
495
496 XFREE(MTYPE_BGP_CONN, bc);
497 bgp_dest_set_bgp_connected_ref_info(bn, NULL);
498 }
499
500 bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type,
501 uint8_t sub_type, struct attr *attr,
502 struct bgp_dest *dest)
503 {
504 uint8_t new_afi = afi == AFI_IP ? AF_INET : AF_INET6;
505 struct bgp_addr tmp_addr = {{0}}, *addr = NULL;
506 struct tip_addr tmp_tip, *tip = NULL;
507 const struct prefix *p = bgp_dest_get_prefix(dest);
508 bool is_bgp_static_route =
509 ((type == ZEBRA_ROUTE_BGP) && (sub_type == BGP_ROUTE_STATIC))
510 ? true
511 : false;
512
513 if (!is_bgp_static_route)
514 new_afi = BGP_ATTR_NEXTHOP_AFI_IP6(attr) ? AF_INET6 : AF_INET;
515
516 tmp_addr.p.family = new_afi;
517 switch (new_afi) {
518 case AF_INET:
519 if (is_bgp_static_route) {
520 tmp_addr.p.u.prefix4 = p->u.prefix4;
521 tmp_addr.p.prefixlen = p->prefixlen;
522 } else {
523 /* Here we need to find out which nexthop to be used*/
524 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
525 tmp_addr.p.u.prefix4 = attr->nexthop;
526 tmp_addr.p.prefixlen = IPV4_MAX_BITLEN;
527 } else if ((attr->mp_nexthop_len)
528 && ((attr->mp_nexthop_len
529 == BGP_ATTR_NHLEN_IPV4)
530 || (attr->mp_nexthop_len
531 == BGP_ATTR_NHLEN_VPNV4))) {
532 tmp_addr.p.u.prefix4 =
533 attr->mp_nexthop_global_in;
534 tmp_addr.p.prefixlen = IPV4_MAX_BITLEN;
535 } else
536 return false;
537 }
538 break;
539 case AF_INET6:
540 if (is_bgp_static_route) {
541 tmp_addr.p.u.prefix6 = p->u.prefix6;
542 tmp_addr.p.prefixlen = p->prefixlen;
543 } else {
544 tmp_addr.p.u.prefix6 = attr->mp_nexthop_global;
545 tmp_addr.p.prefixlen = IPV6_MAX_BITLEN;
546 }
547 break;
548 default:
549 break;
550 }
551
552 addr = hash_lookup(bgp->address_hash, &tmp_addr);
553 if (addr)
554 return true;
555
556 if (new_afi == AF_INET && hashcount(bgp->tip_hash)) {
557 memset(&tmp_tip, 0, sizeof(tmp_tip));
558 tmp_tip.addr = attr->nexthop;
559
560 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
561 tmp_tip.addr = attr->nexthop;
562 } else if ((attr->mp_nexthop_len) &&
563 ((attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4)
564 || (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV4))) {
565 tmp_tip.addr = attr->mp_nexthop_global_in;
566 }
567
568 tip = hash_lookup(bgp->tip_hash, &tmp_tip);
569 if (tip)
570 return true;
571 }
572
573 return false;
574 }
575
576 bool bgp_multiaccess_check_v4(struct in_addr nexthop, struct peer *peer)
577 {
578 struct bgp_dest *dest1;
579 struct bgp_dest *dest2;
580 struct prefix p;
581 int ret;
582
583 p.family = AF_INET;
584 p.prefixlen = IPV4_MAX_BITLEN;
585 p.u.prefix4 = nexthop;
586
587 dest1 = bgp_node_match(peer->bgp->connected_table[AFI_IP], &p);
588 if (!dest1)
589 return false;
590
591 p.family = AF_INET;
592 p.prefixlen = IPV4_MAX_BITLEN;
593 p.u.prefix4 = peer->su.sin.sin_addr;
594
595 dest2 = bgp_node_match(peer->bgp->connected_table[AFI_IP], &p);
596 if (!dest2) {
597 bgp_dest_unlock_node(dest1);
598 return false;
599 }
600
601 ret = (dest1 == dest2);
602
603 bgp_dest_unlock_node(dest1);
604 bgp_dest_unlock_node(dest2);
605
606 return ret;
607 }
608
609 bool bgp_multiaccess_check_v6(struct in6_addr nexthop, struct peer *peer)
610 {
611 struct bgp_dest *dest1;
612 struct bgp_dest *dest2;
613 struct prefix p;
614 int ret;
615
616 p.family = AF_INET6;
617 p.prefixlen = IPV6_MAX_BITLEN;
618 p.u.prefix6 = nexthop;
619
620 dest1 = bgp_node_match(peer->bgp->connected_table[AFI_IP6], &p);
621 if (!dest1)
622 return false;
623
624 p.family = AF_INET6;
625 p.prefixlen = IPV6_MAX_BITLEN;
626 p.u.prefix6 = peer->su.sin6.sin6_addr;
627
628 dest2 = bgp_node_match(peer->bgp->connected_table[AFI_IP6], &p);
629 if (!dest2) {
630 bgp_dest_unlock_node(dest1);
631 return false;
632 }
633
634 ret = (dest1 == dest2);
635
636 bgp_dest_unlock_node(dest1);
637 bgp_dest_unlock_node(dest2);
638
639 return ret;
640 }
641
642 bool bgp_subgrp_multiaccess_check_v6(struct in6_addr nexthop,
643 struct update_subgroup *subgrp,
644 struct peer *exclude)
645 {
646 struct bgp_dest *dest1 = NULL, *dest2 = NULL;
647 struct peer_af *paf = NULL;
648 struct prefix p = {0}, np = {0};
649 struct bgp *bgp = NULL;
650
651 np.family = AF_INET6;
652 np.prefixlen = IPV6_MAX_BITLEN;
653 np.u.prefix6 = nexthop;
654
655 p.family = AF_INET;
656 p.prefixlen = IPV6_MAX_BITLEN;
657
658 bgp = SUBGRP_INST(subgrp);
659 dest1 = bgp_node_match(bgp->connected_table[AFI_IP6], &np);
660 if (!dest1)
661 return false;
662
663 SUBGRP_FOREACH_PEER (subgrp, paf) {
664 /* Skip peer we're told to exclude - e.g., source of route. */
665 if (paf->peer == exclude)
666 continue;
667
668 p.u.prefix6 = paf->peer->su.sin6.sin6_addr;
669 dest2 = bgp_node_match(bgp->connected_table[AFI_IP6], &p);
670 if (dest1 == dest2) {
671 bgp_dest_unlock_node(dest1);
672 bgp_dest_unlock_node(dest2);
673 return true;
674 }
675
676 if (dest2)
677 bgp_dest_unlock_node(dest2);
678 }
679
680 bgp_dest_unlock_node(dest1);
681 return false;
682 }
683
684 bool bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
685 struct update_subgroup *subgrp,
686 struct peer *exclude)
687 {
688 struct bgp_dest *dest1, *dest2;
689 struct peer_af *paf;
690 struct prefix p, np;
691 struct bgp *bgp;
692
693 np.family = AF_INET;
694 np.prefixlen = IPV4_MAX_BITLEN;
695 np.u.prefix4 = nexthop;
696
697 p.family = AF_INET;
698 p.prefixlen = IPV4_MAX_BITLEN;
699
700 bgp = SUBGRP_INST(subgrp);
701 dest1 = bgp_node_match(bgp->connected_table[AFI_IP], &np);
702 if (!dest1)
703 return false;
704
705 SUBGRP_FOREACH_PEER (subgrp, paf) {
706 /* Skip peer we're told to exclude - e.g., source of route. */
707 if (paf->peer == exclude)
708 continue;
709
710 p.u.prefix4 = paf->peer->su.sin.sin_addr;
711
712 dest2 = bgp_node_match(bgp->connected_table[AFI_IP], &p);
713 if (dest1 == dest2) {
714 bgp_dest_unlock_node(dest1);
715 bgp_dest_unlock_node(dest2);
716 return true;
717 }
718
719 if (dest2)
720 bgp_dest_unlock_node(dest2);
721 }
722
723 bgp_dest_unlock_node(dest1);
724 return false;
725 }
726
727 static void bgp_show_bgp_path_info_flags(uint32_t flags, json_object *json)
728 {
729 json_object *json_flags = NULL;
730
731 if (!json)
732 return;
733
734 json_flags = json_object_new_object();
735 json_object_boolean_add(json_flags, "igpChanged",
736 CHECK_FLAG(flags, BGP_PATH_IGP_CHANGED));
737 json_object_boolean_add(json_flags, "damped",
738 CHECK_FLAG(flags, BGP_PATH_DAMPED));
739 json_object_boolean_add(json_flags, "history",
740 CHECK_FLAG(flags, BGP_PATH_HISTORY));
741 json_object_boolean_add(json_flags, "bestpath",
742 CHECK_FLAG(flags, BGP_PATH_SELECTED));
743 json_object_boolean_add(json_flags, "valid",
744 CHECK_FLAG(flags, BGP_PATH_VALID));
745 json_object_boolean_add(json_flags, "attrChanged",
746 CHECK_FLAG(flags, BGP_PATH_ATTR_CHANGED));
747 json_object_boolean_add(json_flags, "deterministicMedCheck",
748 CHECK_FLAG(flags, BGP_PATH_DMED_CHECK));
749 json_object_boolean_add(json_flags, "deterministicMedSelected",
750 CHECK_FLAG(flags, BGP_PATH_DMED_SELECTED));
751 json_object_boolean_add(json_flags, "stale",
752 CHECK_FLAG(flags, BGP_PATH_STALE));
753 json_object_boolean_add(json_flags, "removed",
754 CHECK_FLAG(flags, BGP_PATH_REMOVED));
755 json_object_boolean_add(json_flags, "counted",
756 CHECK_FLAG(flags, BGP_PATH_COUNTED));
757 json_object_boolean_add(json_flags, "multipath",
758 CHECK_FLAG(flags, BGP_PATH_MULTIPATH));
759 json_object_boolean_add(json_flags, "multipathChanged",
760 CHECK_FLAG(flags, BGP_PATH_MULTIPATH_CHG));
761 json_object_boolean_add(json_flags, "ribAttributeChanged",
762 CHECK_FLAG(flags, BGP_PATH_RIB_ATTR_CHG));
763 json_object_boolean_add(json_flags, "nexthopSelf",
764 CHECK_FLAG(flags, BGP_PATH_ANNC_NH_SELF));
765 json_object_boolean_add(json_flags, "linkBandwidthChanged",
766 CHECK_FLAG(flags, BGP_PATH_LINK_BW_CHG));
767 json_object_boolean_add(json_flags, "acceptOwn",
768 CHECK_FLAG(flags, BGP_PATH_ACCEPT_OWN));
769 json_object_object_add(json, "flags", json_flags);
770 }
771
772 static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
773 struct bgp_nexthop_cache *bnc,
774 json_object *json)
775 {
776 struct bgp_dest *dest;
777 struct bgp_path_info *path;
778 afi_t afi;
779 safi_t safi;
780 struct bgp_table *table;
781 struct bgp *bgp_path;
782 json_object *paths = NULL;
783 json_object *json_path = NULL;
784
785 if (json)
786 paths = json_object_new_array();
787 else
788 vty_out(vty, " Paths:\n");
789 LIST_FOREACH (path, &(bnc->paths), nh_thread) {
790 dest = path->net;
791 assert(dest && bgp_dest_table(dest));
792 afi = family2afi(bgp_dest_get_prefix(dest)->family);
793 table = bgp_dest_table(dest);
794 safi = table->safi;
795 bgp_path = table->bgp;
796
797
798 if (json) {
799 json_path = json_object_new_object();
800 json_object_string_add(json_path, "afi", afi2str(afi));
801 json_object_string_add(json_path, "safi",
802 safi2str(safi));
803 json_object_string_addf(json_path, "prefix", "%pBD",
804 dest);
805 if (dest->pdest)
806 json_object_string_addf(
807 json_path, "rd",
808 BGP_RD_AS_FORMAT(bgp->asnotation),
809 (struct prefix_rd *)bgp_dest_get_prefix(
810 dest->pdest));
811 json_object_string_add(
812 json_path, "vrf",
813 vrf_id_to_name(bgp_path->vrf_id));
814 bgp_show_bgp_path_info_flags(path->flags, json_path);
815 json_object_array_add(paths, json_path);
816 continue;
817 }
818 if (dest->pdest) {
819 vty_out(vty, " %d/%d %pBD RD ", afi, safi, dest);
820 vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
821 (struct prefix_rd *)bgp_dest_get_prefix(
822 dest->pdest));
823 vty_out(vty, " %s flags 0x%x\n", bgp_path->name_pretty,
824 path->flags);
825 } else
826 vty_out(vty, " %d/%d %pBD %s flags 0x%x\n",
827 afi, safi, dest, bgp_path->name_pretty, path->flags);
828 }
829 if (json)
830 json_object_object_add(json, "paths", paths);
831 }
832
833 static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
834 struct bgp_nexthop_cache *bnc,
835 json_object *json)
836 {
837 struct nexthop *nexthop;
838 json_object *json_gates = NULL;
839 json_object *json_gate = NULL;
840
841 if (json)
842 json_gates = json_object_new_array();
843 for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) {
844 if (json) {
845 json_gate = json_object_new_object();
846 switch (nexthop->type) {
847 case NEXTHOP_TYPE_IPV6:
848 json_object_string_addf(json_gate, "ip", "%pI6",
849 &nexthop->gate.ipv6);
850 break;
851 case NEXTHOP_TYPE_IPV6_IFINDEX:
852 json_object_string_addf(json_gate, "ip", "%pI6",
853 &nexthop->gate.ipv6);
854 json_object_string_add(
855 json_gate, "interfaceName",
856 ifindex2ifname(
857 bnc->ifindex ? bnc->ifindex
858 : nexthop->ifindex,
859 bgp->vrf_id));
860 break;
861 case NEXTHOP_TYPE_IPV4:
862 json_object_string_addf(json_gate, "ip", "%pI4",
863 &nexthop->gate.ipv4);
864 break;
865 case NEXTHOP_TYPE_IFINDEX:
866 json_object_string_add(
867 json_gate, "interfaceName",
868 ifindex2ifname(
869 bnc->ifindex ? bnc->ifindex
870 : nexthop->ifindex,
871 bgp->vrf_id));
872 break;
873 case NEXTHOP_TYPE_IPV4_IFINDEX:
874 json_object_string_addf(json_gate, "ip", "%pI4",
875 &nexthop->gate.ipv4);
876 json_object_string_add(
877 json_gate, "interfaceName",
878 ifindex2ifname(
879 bnc->ifindex ? bnc->ifindex
880 : nexthop->ifindex,
881 bgp->vrf_id));
882 break;
883 case NEXTHOP_TYPE_BLACKHOLE:
884 json_object_boolean_true_add(json_gate,
885 "unreachable");
886 switch (nexthop->bh_type) {
887 case BLACKHOLE_REJECT:
888 json_object_boolean_true_add(json_gate,
889 "reject");
890 break;
891 case BLACKHOLE_ADMINPROHIB:
892 json_object_boolean_true_add(
893 json_gate, "adminProhibited");
894 break;
895 case BLACKHOLE_NULL:
896 json_object_boolean_true_add(
897 json_gate, "blackhole");
898 break;
899 case BLACKHOLE_UNSPEC:
900 break;
901 }
902 break;
903 default:
904 break;
905 }
906 json_object_array_add(json_gates, json_gate);
907 continue;
908 }
909 switch (nexthop->type) {
910 case NEXTHOP_TYPE_IPV6:
911 vty_out(vty, " gate %pI6\n", &nexthop->gate.ipv6);
912 break;
913 case NEXTHOP_TYPE_IPV6_IFINDEX:
914 vty_out(vty, " gate %pI6, if %s\n",
915 &nexthop->gate.ipv6,
916 ifindex2ifname(bnc->ifindex ? bnc->ifindex
917 : nexthop->ifindex,
918 bgp->vrf_id));
919 break;
920 case NEXTHOP_TYPE_IPV4:
921 vty_out(vty, " gate %pI4\n", &nexthop->gate.ipv4);
922 break;
923 case NEXTHOP_TYPE_IFINDEX:
924 vty_out(vty, " if %s\n",
925 ifindex2ifname(bnc->ifindex ? bnc->ifindex
926 : nexthop->ifindex,
927 bgp->vrf_id));
928 break;
929 case NEXTHOP_TYPE_IPV4_IFINDEX:
930 vty_out(vty, " gate %pI4, if %s\n",
931 &nexthop->gate.ipv4,
932 ifindex2ifname(bnc->ifindex ? bnc->ifindex
933 : nexthop->ifindex,
934 bgp->vrf_id));
935 break;
936 case NEXTHOP_TYPE_BLACKHOLE:
937 vty_out(vty, " blackhole\n");
938 break;
939 default:
940 vty_out(vty, " invalid nexthop type %u\n",
941 nexthop->type);
942 }
943 }
944 if (json)
945 json_object_object_add(json, "nexthops", json_gates);
946 }
947
948 static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
949 struct bgp_nexthop_cache *bnc, bool specific,
950 json_object *json)
951 {
952 char buf[PREFIX2STR_BUFFER];
953 time_t tbuf;
954 struct peer *peer;
955 json_object *json_last_update = NULL;
956 json_object *json_nexthop = NULL;
957
958 peer = (struct peer *)bnc->nht_info;
959
960 if (json)
961 json_nexthop = json_object_new_object();
962 if (bnc->srte_color) {
963 if (json)
964 json_object_int_add(json_nexthop, "srteColor",
965 bnc->srte_color);
966 else
967 vty_out(vty, " SR-TE color %u -", bnc->srte_color);
968 }
969 inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, buf, sizeof(buf));
970 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
971 if (json) {
972 json_object_boolean_true_add(json_nexthop, "valid");
973 json_object_boolean_true_add(json_nexthop, "complete");
974 json_object_int_add(json_nexthop, "igpMetric",
975 bnc->metric);
976 json_object_int_add(json_nexthop, "pathCount",
977 bnc->path_count);
978 if (peer)
979 json_object_string_add(json_nexthop, "peer",
980 peer->host);
981 if (bnc->is_evpn_gwip_nexthop)
982 json_object_boolean_true_add(json_nexthop,
983 "isEvpnGatewayIp");
984 } else {
985 vty_out(vty, " %s valid [IGP metric %d], #paths %d",
986 buf, bnc->metric, bnc->path_count);
987 if (peer)
988 vty_out(vty, ", peer %s", peer->host);
989 if (bnc->is_evpn_gwip_nexthop)
990 vty_out(vty, " EVPN Gateway IP");
991 vty_out(vty, "\n");
992 }
993 bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop);
994 } else if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) {
995 if (json) {
996 json_object_boolean_true_add(json_nexthop, "valid");
997 json_object_boolean_false_add(json_nexthop, "complete");
998 json_object_int_add(json_nexthop, "igpMetric",
999 bnc->metric);
1000 json_object_int_add(json_nexthop, "pathCount",
1001 bnc->path_count);
1002 if (bnc->is_evpn_gwip_nexthop)
1003 json_object_boolean_true_add(json_nexthop,
1004 "isEvpnGatewayIp");
1005 } else {
1006 vty_out(vty,
1007 " %s overlay index unresolved [IGP metric %d], #paths %d",
1008 buf, bnc->metric, bnc->path_count);
1009 if (bnc->is_evpn_gwip_nexthop)
1010 vty_out(vty, " EVPN Gateway IP");
1011 vty_out(vty, "\n");
1012 }
1013 bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop);
1014 } else {
1015 if (json) {
1016 json_object_boolean_false_add(json_nexthop, "valid");
1017 json_object_boolean_false_add(json_nexthop, "complete");
1018 json_object_int_add(json_nexthop, "pathCount",
1019 bnc->path_count);
1020 if (peer)
1021 json_object_string_add(json_nexthop, "peer",
1022 peer->host);
1023 if (bnc->is_evpn_gwip_nexthop)
1024 json_object_boolean_true_add(json_nexthop,
1025 "isEvpnGatewayIp");
1026 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
1027 json_object_boolean_false_add(json_nexthop,
1028 "isConnected");
1029 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
1030 json_object_boolean_false_add(json_nexthop,
1031 "isRegistered");
1032 } else {
1033 vty_out(vty, " %s invalid, #paths %d", buf,
1034 bnc->path_count);
1035 if (peer)
1036 vty_out(vty, ", peer %s", peer->host);
1037 if (bnc->is_evpn_gwip_nexthop)
1038 vty_out(vty, " EVPN Gateway IP");
1039 vty_out(vty, "\n");
1040 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
1041 vty_out(vty, " Must be Connected\n");
1042 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
1043 vty_out(vty, " Is not Registered\n");
1044 }
1045 }
1046 tbuf = time(NULL) - (monotime(NULL) - bnc->last_update);
1047 if (json) {
1048 if (!specific) {
1049 json_last_update = json_object_new_object();
1050 json_object_int_add(json_last_update, "epoch", tbuf);
1051 json_object_string_add(json_last_update, "string",
1052 ctime(&tbuf));
1053 json_object_object_add(json_nexthop, "lastUpdate",
1054 json_last_update);
1055 } else {
1056 json_object_int_add(json_nexthop, "lastUpdate", tbuf);
1057 }
1058 } else {
1059 vty_out(vty, " Last update: %s", ctime(&tbuf));
1060 }
1061
1062 /* show paths dependent on nexthop, if needed. */
1063 if (specific)
1064 bgp_show_nexthop_paths(vty, bgp, bnc, json_nexthop);
1065 if (json)
1066 json_object_object_add(json, buf, json_nexthop);
1067 }
1068
1069 static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp,
1070 bool import_table, json_object *json, afi_t afi,
1071 bool detail)
1072 {
1073 struct bgp_nexthop_cache *bnc;
1074 struct bgp_nexthop_cache_head(*tree)[AFI_MAX];
1075 json_object *json_afi = NULL;
1076 bool found = false;
1077
1078 if (!json) {
1079 if (import_table)
1080 vty_out(vty, "Current BGP import check cache:\n");
1081 else
1082 vty_out(vty, "Current BGP nexthop cache:\n");
1083 }
1084 if (import_table)
1085 tree = &bgp->import_check_table;
1086 else
1087 tree = &bgp->nexthop_cache_table;
1088
1089 if (afi == AFI_IP || afi == AFI_IP6) {
1090 if (json)
1091 json_afi = json_object_new_object();
1092 frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) {
1093 bgp_show_nexthop(vty, bgp, bnc, detail, json_afi);
1094 found = true;
1095 }
1096 if (found && json)
1097 json_object_object_add(
1098 json, (afi == AFI_IP) ? "ipv4" : "ipv6",
1099 json_afi);
1100 return;
1101 }
1102
1103 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
1104 if (json && (afi == AFI_IP || afi == AFI_IP6))
1105 json_afi = json_object_new_object();
1106 frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc)
1107 bgp_show_nexthop(vty, bgp, bnc, detail, json_afi);
1108 if (json && (afi == AFI_IP || afi == AFI_IP6))
1109 json_object_object_add(
1110 json, (afi == AFI_IP) ? "ipv4" : "ipv6",
1111 json_afi);
1112 }
1113 }
1114
1115 static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,
1116 const char *nhopip_str, bool import_table,
1117 json_object *json, afi_t afi, bool detail)
1118 {
1119 struct bgp *bgp;
1120
1121 if (name && !strmatch(name, VRF_DEFAULT_NAME))
1122 bgp = bgp_lookup_by_name(name);
1123 else
1124 bgp = bgp_get_default();
1125 if (!bgp) {
1126 if (!json)
1127 vty_out(vty, "%% No such BGP instance exist\n");
1128 return CMD_WARNING;
1129 }
1130
1131 if (nhopip_str) {
1132 struct prefix nhop;
1133 struct bgp_nexthop_cache_head (*tree)[AFI_MAX];
1134 struct bgp_nexthop_cache *bnc;
1135 bool found = false;
1136 json_object *json_afi = NULL;
1137
1138 if (!str2prefix(nhopip_str, &nhop)) {
1139 if (!json)
1140 vty_out(vty, "nexthop address is malformed\n");
1141 return CMD_WARNING;
1142 }
1143 tree = import_table ? &bgp->import_check_table
1144 : &bgp->nexthop_cache_table;
1145 if (json)
1146 json_afi = json_object_new_object();
1147 frr_each (bgp_nexthop_cache, &(*tree)[family2afi(nhop.family)],
1148 bnc) {
1149 if (prefix_cmp(&bnc->prefix, &nhop))
1150 continue;
1151 bgp_show_nexthop(vty, bgp, bnc, true, json_afi);
1152 found = true;
1153 }
1154 if (json)
1155 json_object_object_add(
1156 json,
1157 (family2afi(nhop.family) == AFI_IP) ? "ipv4"
1158 : "ipv6",
1159 json_afi);
1160 if (!found && !json)
1161 vty_out(vty, "nexthop %s does not have entry\n",
1162 nhopip_str);
1163 } else
1164 bgp_show_nexthops(vty, bgp, import_table, json, afi, detail);
1165
1166 return CMD_SUCCESS;
1167 }
1168
1169 static void bgp_show_all_instances_nexthops_vty(struct vty *vty,
1170 json_object *json, afi_t afi,
1171 bool detail)
1172 {
1173 struct listnode *node, *nnode;
1174 struct bgp *bgp;
1175 const char *inst_name;
1176 json_object *json_instance = NULL;
1177
1178 for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
1179 inst_name = (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
1180 ? VRF_DEFAULT_NAME
1181 : bgp->name;
1182 if (json)
1183 json_instance = json_object_new_object();
1184 else
1185 vty_out(vty, "\nInstance %s:\n", inst_name);
1186
1187 bgp_show_nexthops(vty, bgp, false, json_instance, afi, detail);
1188
1189 if (json)
1190 json_object_object_add(json, inst_name, json_instance);
1191 }
1192 }
1193
1194 #include "bgpd/bgp_nexthop_clippy.c"
1195
1196 DEFPY (show_ip_bgp_nexthop,
1197 show_ip_bgp_nexthop_cmd,
1198 "show [ip] bgp [<view|vrf> VIEWVRFNAME$vrf] nexthop [<A.B.C.D|X:X::X:X>$nhop] [<ipv4$afi [A.B.C.D$nhop]|ipv6$afi [X:X::X:X$nhop]>] [detail$detail] [json$uj]",
1199 SHOW_STR
1200 IP_STR
1201 BGP_STR
1202 BGP_INSTANCE_HELP_STR
1203 "BGP nexthop table\n"
1204 "IPv4 nexthop address\n"
1205 "IPv6 nexthop address\n"
1206 "BGP nexthop IPv4 table\n"
1207 "IPv4 nexthop address\n"
1208 "BGP nexthop IPv6 table\n"
1209 "IPv6 nexthop address\n"
1210 "Show detailed information\n"
1211 JSON_STR)
1212 {
1213 int rc = 0;
1214 json_object *json = NULL;
1215 afi_t afiz = AFI_UNSPEC;
1216
1217 if (uj)
1218 json = json_object_new_object();
1219
1220 if (afi)
1221 afiz = bgp_vty_afi_from_str(afi);
1222
1223 rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_str, false, json, afiz,
1224 detail);
1225
1226 if (uj)
1227 vty_json(vty, json);
1228
1229 return rc;
1230 }
1231
1232 DEFPY (show_ip_bgp_import_check,
1233 show_ip_bgp_import_check_cmd,
1234 "show [ip] bgp [<view|vrf> VIEWVRFNAME$vrf] import-check-table [detail$detail] [json$uj]",
1235 SHOW_STR
1236 IP_STR
1237 BGP_STR
1238 BGP_INSTANCE_HELP_STR
1239 "BGP import check table\n"
1240 "Show detailed information\n"
1241 JSON_STR)
1242 {
1243 int rc = 0;
1244 json_object *json = NULL;
1245
1246 if (uj)
1247 json = json_object_new_object();
1248
1249 rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, json, AFI_UNSPEC,
1250 detail);
1251
1252 if (uj)
1253 vty_json(vty, json);
1254
1255 return rc;
1256 }
1257
1258 DEFPY (show_ip_bgp_instance_all_nexthop,
1259 show_ip_bgp_instance_all_nexthop_cmd,
1260 "show [ip] bgp <view|vrf> all nexthop [<ipv4|ipv6>$afi] [detail$detail] [json$uj]",
1261 SHOW_STR
1262 IP_STR
1263 BGP_STR
1264 BGP_INSTANCE_ALL_HELP_STR
1265 "BGP nexthop table\n"
1266 "BGP IPv4 nexthop table\n"
1267 "BGP IPv6 nexthop table\n"
1268 "Show detailed information\n"
1269 JSON_STR)
1270 {
1271 json_object *json = NULL;
1272 afi_t afiz = AFI_UNSPEC;
1273
1274 if (uj)
1275 json = json_object_new_object();
1276
1277 if (afi)
1278 afiz = bgp_vty_afi_from_str(afi);
1279
1280 bgp_show_all_instances_nexthops_vty(vty, json, afiz, detail);
1281
1282 if (uj)
1283 vty_json(vty, json);
1284
1285 return CMD_SUCCESS;
1286 }
1287
1288 void bgp_scan_init(struct bgp *bgp)
1289 {
1290 afi_t afi;
1291
1292 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
1293 bgp_nexthop_cache_init(&bgp->nexthop_cache_table[afi]);
1294 bgp_nexthop_cache_init(&bgp->import_check_table[afi]);
1295 bgp->connected_table[afi] = bgp_table_init(bgp, afi,
1296 SAFI_UNICAST);
1297 }
1298 }
1299
1300 void bgp_scan_vty_init(void)
1301 {
1302 install_element(VIEW_NODE, &show_ip_bgp_nexthop_cmd);
1303 install_element(VIEW_NODE, &show_ip_bgp_import_check_cmd);
1304 install_element(VIEW_NODE, &show_ip_bgp_instance_all_nexthop_cmd);
1305 }
1306
1307 void bgp_scan_finish(struct bgp *bgp)
1308 {
1309 afi_t afi;
1310
1311 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
1312 /* Only the current one needs to be reset. */
1313 bgp_nexthop_cache_reset(&bgp->nexthop_cache_table[afi]);
1314 bgp_nexthop_cache_reset(&bgp->import_check_table[afi]);
1315
1316 bgp->connected_table[afi]->route_table->cleanup =
1317 bgp_connected_cleanup;
1318 bgp_table_unlock(bgp->connected_table[afi]);
1319 bgp->connected_table[afi] = NULL;
1320 }
1321 }
1322
1323 char *bgp_nexthop_dump_bnc_flags(struct bgp_nexthop_cache *bnc, char *buf,
1324 size_t len)
1325 {
1326 if (bnc->flags == 0) {
1327 snprintfrr(buf, len, "None ");
1328 return buf;
1329 }
1330
1331 snprintfrr(buf, len, "%s%s%s%s%s%s%s",
1332 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) ? "Valid " : "",
1333 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED) ? "Reg " : "",
1334 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED) ? "Conn " : "",
1335 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED) ? "Notify "
1336 : "",
1337 CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE) ? "Static " : "",
1338 CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)
1339 ? "Static Exact "
1340 : "",
1341 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID)
1342 ? "Label Valid "
1343 : "");
1344
1345 return buf;
1346 }
1347
1348 char *bgp_nexthop_dump_bnc_change_flags(struct bgp_nexthop_cache *bnc,
1349 char *buf, size_t len)
1350 {
1351 if (bnc->flags == 0) {
1352 snprintfrr(buf, len, "None ");
1353 return buf;
1354 }
1355
1356 snprintfrr(buf, len, "%s%s%s",
1357 CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)
1358 ? "Changed "
1359 : "",
1360 CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED)
1361 ? "Metric "
1362 : "",
1363 CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CONNECTED_CHANGED)
1364 ? "Connected "
1365 : "");
1366
1367 return buf;
1368 }