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