Coverage Report

Created: 2026-01-01 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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, &copy_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
}