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