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