Coverage Report

Created: 2026-05-11 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/pimd/pim_rp.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * PIM for Quagga
4
 * Copyright (C) 2015 Cumulus Networks, Inc.
5
 * Donald Sharp
6
 */
7
#include <zebra.h>
8
9
#include "lib/json.h"
10
#include "log.h"
11
#include "network.h"
12
#include "if.h"
13
#include "linklist.h"
14
#include "prefix.h"
15
#include "memory.h"
16
#include "vty.h"
17
#include "vrf.h"
18
#include "plist.h"
19
#include "nexthop.h"
20
#include "table.h"
21
#include "lib_errors.h"
22
23
#include "pimd.h"
24
#include "pim_instance.h"
25
#include "pim_vty.h"
26
#include "pim_str.h"
27
#include "pim_iface.h"
28
#include "pim_rp.h"
29
#include "pim_rpf.h"
30
#include "pim_sock.h"
31
#include "pim_memory.h"
32
#include "pim_neighbor.h"
33
#include "pim_msdp.h"
34
#include "pim_nht.h"
35
#include "pim_mroute.h"
36
#include "pim_oil.h"
37
#include "pim_zebra.h"
38
#include "pim_bsm.h"
39
#include "pim_util.h"
40
#include "pim_ssm.h"
41
#include "termtable.h"
42
43
/* Cleanup pim->rpf_hash each node data */
44
void pim_rp_list_hash_clean(void *data)
45
0
{
46
0
  struct pim_nexthop_cache *pnc = (struct pim_nexthop_cache *)data;
47
48
0
  list_delete(&pnc->rp_list);
49
50
0
  hash_clean_and_free(&pnc->upstream_hash, NULL);
51
0
  if (pnc->nexthop)
52
0
    nexthops_free(pnc->nexthop);
53
54
0
  XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc);
55
0
}
56
57
static void pim_rp_info_free(struct rp_info *rp_info)
58
0
{
59
0
  XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
60
61
0
  XFREE(MTYPE_PIM_RP, rp_info);
62
0
}
63
64
int pim_rp_list_cmp(void *v1, void *v2)
65
626k
{
66
626k
  struct rp_info *rp1 = (struct rp_info *)v1;
67
626k
  struct rp_info *rp2 = (struct rp_info *)v2;
68
626k
  int ret;
69
70
  /*
71
   * Sort by RP IP address
72
   */
73
626k
  ret = pim_addr_cmp(rp1->rp.rpf_addr, rp2->rp.rpf_addr);
74
626k
  if (ret)
75
584k
    return ret;
76
77
  /*
78
   * Sort by group IP address
79
   */
80
42.1k
  ret = prefix_cmp(&rp1->group, &rp2->group);
81
42.1k
  if (ret)
82
42.1k
    return ret;
83
84
0
  return 0;
85
42.1k
}
86
87
void pim_rp_init(struct pim_instance *pim)
88
1
{
89
1
  struct rp_info *rp_info;
90
1
  struct route_node *rn;
91
92
1
  pim->rp_list = list_new();
93
1
  pim->rp_list->del = (void (*)(void *))pim_rp_info_free;
94
1
  pim->rp_list->cmp = pim_rp_list_cmp;
95
96
1
  pim->rp_table = route_table_init();
97
98
1
  rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
99
100
1
  if (!pim_get_all_mcast_group(&rp_info->group)) {
101
0
    flog_err(EC_LIB_DEVELOPMENT,
102
0
       "Unable to convert all-multicast prefix");
103
0
    list_delete(&pim->rp_list);
104
0
    route_table_finish(pim->rp_table);
105
0
    XFREE(MTYPE_PIM_RP, rp_info);
106
0
    return;
107
0
  }
108
1
  rp_info->rp.rpf_addr = PIMADDR_ANY;
109
110
1
  listnode_add(pim->rp_list, rp_info);
111
112
1
  rn = route_node_get(pim->rp_table, &rp_info->group);
113
1
  rn->info = rp_info;
114
1
  if (PIM_DEBUG_PIM_TRACE)
115
0
    zlog_debug("Allocated: %p for rp_info: %p(%pFX) Lock: %d", rn,
116
1
         rp_info, &rp_info->group,
117
1
         route_node_get_lock_count(rn));
118
1
}
119
120
void pim_rp_free(struct pim_instance *pim)
121
0
{
122
0
  if (pim->rp_table)
123
0
    route_table_finish(pim->rp_table);
124
0
  pim->rp_table = NULL;
125
126
0
  if (pim->rp_list)
127
0
    list_delete(&pim->rp_list);
128
0
}
129
130
/*
131
 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
132
 */
133
static struct rp_info *pim_rp_find_prefix_list(struct pim_instance *pim,
134
                 pim_addr rp, const char *plist)
135
0
{
136
0
  struct listnode *node;
137
0
  struct rp_info *rp_info;
138
139
0
  for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
140
0
    if ((!pim_addr_cmp(rp, rp_info->rp.rpf_addr)) &&
141
0
        rp_info->plist && strcmp(rp_info->plist, plist) == 0) {
142
0
      return rp_info;
143
0
    }
144
0
  }
145
146
0
  return NULL;
147
0
}
148
149
/*
150
 * Return true if plist is used by any rp_info
151
 */
152
static int pim_rp_prefix_list_used(struct pim_instance *pim, const char *plist)
153
0
{
154
0
  struct listnode *node;
155
0
  struct rp_info *rp_info;
156
157
0
  for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
158
0
    if (rp_info->plist && strcmp(rp_info->plist, plist) == 0) {
159
0
      return 1;
160
0
    }
161
0
  }
162
163
0
  return 0;
164
0
}
165
166
/*
167
 * Given an RP's address, return the RP's rp_info that is an exact match for
168
 * 'group'
169
 */
170
static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, pim_addr rp,
171
           const struct prefix *group)
172
29.3k
{
173
29.3k
  struct listnode *node;
174
29.3k
  struct rp_info *rp_info;
175
176
3.17M
  for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
177
3.17M
    if ((!pim_addr_cmp(rp, rp_info->rp.rpf_addr)) &&
178
64.5k
        prefix_same(&rp_info->group, group))
179
13.5k
      return rp_info;
180
3.17M
  }
181
182
15.8k
  return NULL;
183
29.3k
}
184
185
/*
186
 * XXX: long-term issue:  we don't actually have a good "ip address-list"
187
 * implementation.  ("access-list XYZ" is the closest but honestly it's
188
 * kinda garbage.)
189
 *
190
 * So it's using a prefix-list to match an address here, which causes very
191
 * unexpected results for the user since prefix-lists by default only match
192
 * when the prefix length is an exact match too.  i.e. you'd have to add the
193
 * "le 32" and do "ip prefix-list foo permit 10.0.0.0/24 le 32"
194
 *
195
 * To avoid this pitfall, this code uses "address_mode = true" for the prefix
196
 * list match (this is the only user for that.)
197
 *
198
 * In the long run, we need to add a "ip address-list", but that's a wholly
199
 * separate bag of worms, and existing configs using ip prefix-list would
200
 * drop into the UX pitfall.
201
 */
202
203
#include "lib/plist_int.h"
204
205
/*
206
 * Given a group, return the rp_info for that group
207
 */
208
struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
209
                 const struct prefix *group)
210
25.7M
{
211
25.7M
  struct listnode *node;
212
25.7M
  struct rp_info *best = NULL;
213
25.7M
  struct rp_info *rp_info;
214
25.7M
  struct prefix_list *plist;
215
25.7M
  const struct prefix *bp;
216
25.7M
  const struct prefix_list_entry *entry;
217
25.7M
  struct route_node *rn;
218
219
25.7M
  bp = NULL;
220
4.77G
  for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
221
4.77G
    if (rp_info->plist) {
222
0
      plist = prefix_list_lookup(PIM_AFI, rp_info->plist);
223
224
0
      if (prefix_list_apply_ext(plist, &entry, group, true)
225
0
          == PREFIX_DENY || !entry)
226
0
        continue;
227
228
0
      if (!best) {
229
0
        best = rp_info;
230
0
        bp = &entry->prefix;
231
0
        continue;
232
0
      }
233
234
0
      if (bp && bp->prefixlen < entry->prefix.prefixlen) {
235
0
        best = rp_info;
236
0
        bp = &entry->prefix;
237
0
      }
238
0
    }
239
4.77G
  }
240
241
25.7M
  rn = route_node_match(pim->rp_table, group);
242
25.7M
  if (!rn) {
243
13.4M
    flog_err(
244
13.4M
      EC_LIB_DEVELOPMENT,
245
13.4M
      "%s: BUG We should have found default group information",
246
13.4M
      __func__);
247
13.4M
    return best;
248
13.4M
  }
249
250
12.3M
  rp_info = rn->info;
251
12.3M
  if (PIM_DEBUG_PIM_TRACE) {
252
0
    if (best)
253
0
      zlog_debug(
254
0
        "Lookedup(%pFX): prefix_list match %s, rn %p found: %pFX",
255
0
        group, best->plist, rn, &rp_info->group);
256
0
    else
257
0
      zlog_debug("Lookedup(%pFX): rn %p found:%pFX", group,
258
0
           rn, &rp_info->group);
259
0
  }
260
261
12.3M
  route_unlock_node(rn);
262
263
  /*
264
   * rp's with prefix lists have the group as 224.0.0.0/4 which will
265
   * match anything.  So if we have a rp_info that should match a prefix
266
   * list then if we do match then best should be the answer( even
267
   * if it is NULL )
268
   */
269
12.3M
  if (!rp_info || (rp_info && rp_info->plist))
270
0
    return best;
271
272
  /*
273
   * So we have a non plist rp_info found in the lookup and no plists
274
   * at all to be choosen, return it!
275
   */
276
12.3M
  if (!best)
277
12.3M
    return rp_info;
278
279
  /*
280
   * If we have a matching non prefix list and a matching prefix
281
   * list we should return the actual rp_info that has the LPM
282
   * If they are equal, use the prefix-list( but let's hope
283
   * the end-operator doesn't do this )
284
   */
285
0
  if (rp_info->group.prefixlen > bp->prefixlen)
286
0
    best = rp_info;
287
288
0
  return best;
289
12.3M
}
290
291
/*
292
 * When the user makes "ip pim rp" configuration changes or if they change the
293
 * prefix-list(s) used by these statements we must tickle the upstream state
294
 * for each group to make them re-lookup who their RP should be.
295
 *
296
 * This is a placeholder function for now.
297
 */
298
void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim)
299
26.8k
{
300
26.8k
  pim_msdp_i_am_rp_changed(pim);
301
26.8k
  pim_upstream_reeval_use_rpt(pim);
302
26.8k
}
303
304
void pim_rp_prefix_list_update(struct pim_instance *pim,
305
             struct prefix_list *plist)
306
0
{
307
0
  struct listnode *node;
308
0
  struct rp_info *rp_info;
309
0
  int refresh_needed = 0;
310
311
0
  for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
312
0
    if (rp_info->plist
313
0
        && strcmp(rp_info->plist, prefix_list_name(plist)) == 0) {
314
0
      refresh_needed = 1;
315
0
      break;
316
0
    }
317
0
  }
318
319
0
  if (refresh_needed)
320
0
    pim_rp_refresh_group_to_rp_mapping(pim);
321
0
}
322
323
static int pim_rp_check_interface_addrs(struct rp_info *rp_info,
324
          struct pim_interface *pim_ifp)
325
36.5k
{
326
36.5k
  struct listnode *node;
327
36.5k
  struct pim_secondary_addr *sec_addr;
328
36.5k
  pim_addr sec_paddr;
329
330
36.5k
  if (!pim_addr_cmp(pim_ifp->primary_address, rp_info->rp.rpf_addr))
331
1.23k
    return 1;
332
333
35.3k
  if (!pim_ifp->sec_addr_list) {
334
0
    return 0;
335
0
  }
336
337
35.3k
  for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
338
0
    sec_paddr = pim_addr_from_prefix(&sec_addr->addr);
339
    /* If an RP-address is self, It should be enough to say
340
     * I am RP the prefix-length should not matter here */
341
0
    if (!pim_addr_cmp(sec_paddr, rp_info->rp.rpf_addr))
342
0
      return 1;
343
0
  }
344
345
35.3k
  return 0;
346
35.3k
}
347
348
static void pim_rp_check_interfaces(struct pim_instance *pim,
349
            struct rp_info *rp_info)
350
18.2k
{
351
18.2k
  struct interface *ifp;
352
353
18.2k
  rp_info->i_am_rp = 0;
354
36.5k
  FOR_ALL_INTERFACES (pim->vrf, ifp) {
355
36.5k
    struct pim_interface *pim_ifp = ifp->info;
356
357
36.5k
    if (!pim_ifp)
358
0
      continue;
359
360
36.5k
    if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
361
1.23k
      rp_info->i_am_rp = 1;
362
1.23k
    }
363
36.5k
  }
364
18.2k
}
365
366
void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up)
367
125k
{
368
125k
  struct pim_rpf old_rpf;
369
125k
  enum pim_rpf_result rpf_result;
370
125k
  pim_addr old_upstream_addr;
371
125k
  pim_addr new_upstream_addr;
372
373
125k
  old_upstream_addr = up->upstream_addr;
374
125k
  pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src,
375
125k
         up->sg.grp);
376
377
125k
  if (PIM_DEBUG_PIM_TRACE)
378
0
    zlog_debug("%s: pim upstream update for old upstream %pPA",
379
125k
         __func__, &old_upstream_addr);
380
381
125k
  if (!pim_addr_cmp(old_upstream_addr, new_upstream_addr))
382
89.4k
    return;
383
384
  /* Lets consider a case, where a PIM upstream has a better RP as a
385
   * result of a new RP configuration with more precise group range.
386
   * This upstream has to be added to the upstream hash of new RP's
387
   * NHT(pnc) and has to be removed from old RP's NHT upstream hash
388
   */
389
35.6k
  if (!pim_addr_is_any(old_upstream_addr)) {
390
    /* Deregister addr with Zebra NHT */
391
26.9k
    if (PIM_DEBUG_PIM_TRACE)
392
0
      zlog_debug(
393
26.9k
        "%s: Deregister upstream %s addr %pPA with Zebra NHT",
394
26.9k
        __func__, up->sg_str, &old_upstream_addr);
395
26.9k
    pim_delete_tracked_nexthop(pim, old_upstream_addr, up, NULL);
396
26.9k
  }
397
398
  /* Update the upstream address */
399
35.6k
  up->upstream_addr = new_upstream_addr;
400
401
35.6k
  old_rpf.source_nexthop.interface = up->rpf.source_nexthop.interface;
402
403
35.6k
  rpf_result = pim_rpf_update(pim, up, &old_rpf, __func__);
404
35.6k
  if (rpf_result == PIM_RPF_FAILURE)
405
35.0k
    pim_mroute_del(up->channel_oil, __func__);
406
407
  /* update kernel multicast forwarding cache (MFC) */
408
35.6k
  if (up->rpf.source_nexthop.interface && up->channel_oil)
409
0
    pim_upstream_mroute_iif_update(up->channel_oil, __func__);
410
411
35.6k
  if (rpf_result == PIM_RPF_CHANGED ||
412
35.6k
      (rpf_result == PIM_RPF_FAILURE &&
413
35.0k
       old_rpf.source_nexthop.interface))
414
0
    pim_zebra_upstream_rpf_changed(pim, up, &old_rpf);
415
416
35.6k
}
417
418
int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group,
419
         const char *plist, enum rp_source rp_src_flag)
420
29.2k
{
421
29.2k
  int result = 0;
422
29.2k
  struct rp_info *rp_info;
423
29.2k
  struct rp_info *rp_all;
424
29.2k
  struct prefix group_all;
425
29.2k
  struct listnode *node, *nnode;
426
29.2k
  struct rp_info *tmp_rp_info;
427
29.2k
  char buffer[BUFSIZ];
428
29.2k
  pim_addr nht_p;
429
29.2k
  struct route_node *rn = NULL;
430
29.2k
  struct pim_upstream *up;
431
29.2k
  bool upstream_updated = false;
432
433
29.2k
  if (pim_addr_is_any(rp_addr))
434
3.42k
    return PIM_RP_BAD_ADDRESS;
435
436
25.8k
  rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
437
438
25.8k
  rp_info->rp.rpf_addr = rp_addr;
439
25.8k
  prefix_copy(&rp_info->group, &group);
440
25.8k
  rp_info->rp_src = rp_src_flag;
441
442
25.8k
  if (plist) {
443
    /*
444
     * Return if the prefix-list is already configured for this RP
445
     */
446
0
    if (pim_rp_find_prefix_list(pim, rp_addr, plist)) {
447
0
      XFREE(MTYPE_PIM_RP, rp_info);
448
0
      return PIM_SUCCESS;
449
0
    }
450
451
    /*
452
     * Barf if the prefix-list is already configured for an RP
453
     */
454
0
    if (pim_rp_prefix_list_used(pim, plist)) {
455
0
      XFREE(MTYPE_PIM_RP, rp_info);
456
0
      return PIM_RP_PFXLIST_IN_USE;
457
0
    }
458
459
    /*
460
     * Free any existing rp_info entries for this RP
461
     */
462
0
    for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
463
0
               tmp_rp_info)) {
464
0
      if (!pim_addr_cmp(rp_info->rp.rpf_addr,
465
0
            tmp_rp_info->rp.rpf_addr)) {
466
0
        if (tmp_rp_info->plist)
467
0
          pim_rp_del_config(pim, rp_addr, NULL,
468
0
                tmp_rp_info->plist);
469
0
        else
470
0
          pim_rp_del_config(
471
0
            pim, rp_addr,
472
0
            prefix2str(&tmp_rp_info->group,
473
0
                 buffer, BUFSIZ),
474
0
            NULL);
475
0
      }
476
0
    }
477
478
0
    rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist);
479
25.8k
  } else {
480
481
25.8k
    if (!pim_get_all_mcast_group(&group_all)) {
482
0
      XFREE(MTYPE_PIM_RP, rp_info);
483
0
      return PIM_GROUP_BAD_ADDRESS;
484
0
    }
485
25.8k
    rp_all = pim_rp_find_match_group(pim, &group_all);
486
487
    /*
488
     * Barf if group is a non-multicast subnet
489
     */
490
25.8k
    if (!prefix_match(&rp_all->group, &rp_info->group)) {
491
7.54k
      XFREE(MTYPE_PIM_RP, rp_info);
492
7.54k
      return PIM_GROUP_BAD_ADDRESS;
493
7.54k
    }
494
495
    /*
496
     * Remove any prefix-list rp_info entries for this RP
497
     */
498
18.2k
    for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
499
3.34M
               tmp_rp_info)) {
500
3.34M
      if (tmp_rp_info->plist &&
501
0
          (!pim_addr_cmp(rp_info->rp.rpf_addr,
502
0
             tmp_rp_info->rp.rpf_addr))) {
503
0
        pim_rp_del_config(pim, rp_addr, NULL,
504
0
              tmp_rp_info->plist);
505
0
      }
506
3.34M
    }
507
508
    /*
509
     * Take over the 224.0.0.0/4 group if the rp is INADDR_ANY
510
     */
511
18.2k
    if (prefix_same(&rp_all->group, &rp_info->group) &&
512
9.52k
        pim_rpf_addr_is_inaddr_any(&rp_all->rp)) {
513
9.52k
      rp_all->rp.rpf_addr = rp_info->rp.rpf_addr;
514
9.52k
      rp_all->rp_src = rp_src_flag;
515
9.52k
      XFREE(MTYPE_PIM_RP, rp_info);
516
517
      /* Register addr with Zebra NHT */
518
9.52k
      nht_p = rp_all->rp.rpf_addr;
519
9.52k
      if (PIM_DEBUG_PIM_NHT_RP)
520
0
        zlog_debug(
521
9.52k
          "%s: NHT Register rp_all addr %pPA grp %pFX ",
522
9.52k
          __func__, &nht_p, &rp_all->group);
523
524
6.29M
      frr_each (rb_pim_upstream, &pim->upstream_head, up) {
525
        /* Find (*, G) upstream whose RP is not
526
         * configured yet
527
         */
528
6.29M
        if (pim_addr_is_any(up->upstream_addr) &&
529
3.21M
            pim_addr_is_any(up->sg.src)) {
530
847k
          struct prefix grp;
531
847k
          struct rp_info *trp_info;
532
533
847k
          pim_addr_to_prefix(&grp, up->sg.grp);
534
847k
          trp_info = pim_rp_find_match_group(
535
847k
            pim, &grp);
536
847k
          if (trp_info == rp_all) {
537
4.45k
            pim_upstream_update(pim, up);
538
4.45k
            upstream_updated = true;
539
4.45k
          }
540
847k
        }
541
6.29M
      }
542
9.52k
      if (upstream_updated)
543
437
        pim_zebra_update_all_interfaces(pim);
544
545
9.52k
      pim_rp_check_interfaces(pim, rp_all);
546
9.52k
      pim_rp_refresh_group_to_rp_mapping(pim);
547
9.52k
      pim_find_or_track_nexthop(pim, nht_p, NULL, rp_all,
548
9.52k
              NULL);
549
550
9.52k
      if (!pim_ecmp_nexthop_lookup(pim,
551
9.52k
                 &rp_all->rp.source_nexthop,
552
9.52k
                 nht_p, &rp_all->group, 1))
553
9.52k
        return PIM_RP_NO_PATH;
554
0
      return PIM_SUCCESS;
555
9.52k
    }
556
557
    /*
558
     * Return if the group is already configured for this RP
559
     */
560
8.76k
    tmp_rp_info = pim_rp_find_exact(pim, rp_addr, &rp_info->group);
561
8.76k
    if (tmp_rp_info) {
562
0
      if ((tmp_rp_info->rp_src != rp_src_flag)
563
0
          && (rp_src_flag == RP_SRC_STATIC))
564
0
        tmp_rp_info->rp_src = rp_src_flag;
565
0
      XFREE(MTYPE_PIM_RP, rp_info);
566
0
      return result;
567
0
    }
568
569
    /*
570
     * Barf if this group is already covered by some other RP
571
     */
572
8.76k
    tmp_rp_info = pim_rp_find_match_group(pim, &rp_info->group);
573
574
8.76k
    if (tmp_rp_info) {
575
8.76k
      if (tmp_rp_info->plist) {
576
0
        XFREE(MTYPE_PIM_RP, rp_info);
577
0
        return PIM_GROUP_PFXLIST_OVERLAP;
578
8.76k
      } else {
579
        /*
580
         * If the only RP that covers this group is an
581
         * RP configured for
582
         * 224.0.0.0/4 that is fine, ignore that one.
583
         * For all others
584
         * though we must return PIM_GROUP_OVERLAP
585
         */
586
8.76k
        if (prefix_same(&rp_info->group,
587
8.76k
            &tmp_rp_info->group)) {
588
0
          if ((rp_src_flag == RP_SRC_STATIC)
589
0
              && (tmp_rp_info->rp_src
590
0
            == RP_SRC_STATIC)) {
591
0
            XFREE(MTYPE_PIM_RP, rp_info);
592
0
            return PIM_GROUP_OVERLAP;
593
0
          }
594
595
0
          result = pim_rp_change(
596
0
            pim, rp_addr,
597
0
            tmp_rp_info->group,
598
0
            rp_src_flag);
599
0
          XFREE(MTYPE_PIM_RP, rp_info);
600
0
          return result;
601
0
        }
602
8.76k
      }
603
8.76k
    }
604
8.76k
  }
605
606
8.76k
  listnode_add_sort(pim->rp_list, rp_info);
607
608
8.76k
  if (!rp_info->plist) {
609
8.76k
    rn = route_node_get(pim->rp_table, &rp_info->group);
610
8.76k
    rn->info = rp_info;
611
8.76k
  }
612
613
8.76k
  if (PIM_DEBUG_PIM_TRACE)
614
0
    zlog_debug("Allocated: %p for rp_info: %p(%pFX) Lock: %d", rn,
615
8.76k
         rp_info, &rp_info->group,
616
8.76k
         rn ? route_node_get_lock_count(rn) : 0);
617
618
5.60M
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
619
5.60M
    if (pim_addr_is_any(up->sg.src)) {
620
1.44M
      struct prefix grp;
621
1.44M
      struct rp_info *trp_info;
622
623
1.44M
      pim_addr_to_prefix(&grp, up->sg.grp);
624
1.44M
      trp_info = pim_rp_find_match_group(pim, &grp);
625
626
1.44M
      if (trp_info == rp_info) {
627
6.13k
        pim_upstream_update(pim, up);
628
6.13k
        upstream_updated = true;
629
6.13k
      }
630
1.44M
    }
631
5.60M
  }
632
633
8.76k
  if (upstream_updated)
634
5.52k
    pim_zebra_update_all_interfaces(pim);
635
636
8.76k
  pim_rp_check_interfaces(pim, rp_info);
637
8.76k
  pim_rp_refresh_group_to_rp_mapping(pim);
638
639
  /* Register addr with Zebra NHT */
640
8.76k
  nht_p = rp_info->rp.rpf_addr;
641
8.76k
  if (PIM_DEBUG_PIM_NHT_RP)
642
0
    zlog_debug("%s: NHT Register RP addr %pPA grp %pFX with Zebra ",
643
8.76k
         __func__, &nht_p, &rp_info->group);
644
8.76k
  pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
645
8.76k
  if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, nht_p,
646
8.76k
             &rp_info->group, 1))
647
8.76k
    return PIM_RP_NO_PATH;
648
649
0
  return PIM_SUCCESS;
650
8.76k
}
651
652
void pim_rp_del_config(struct pim_instance *pim, pim_addr rp_addr,
653
           const char *group_range, const char *plist)
654
0
{
655
0
  struct prefix group;
656
0
  int result;
657
658
0
  if (group_range == NULL)
659
0
    result = pim_get_all_mcast_group(&group);
660
0
  else
661
0
    result = str2prefix(group_range, &group);
662
663
0
  if (!result) {
664
0
    if (PIM_DEBUG_PIM_TRACE)
665
0
      zlog_debug(
666
0
        "%s: String to prefix failed for %pPAs group",
667
0
        __func__, &rp_addr);
668
0
    return;
669
0
  }
670
671
0
  pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC);
672
0
}
673
674
int pim_rp_del(struct pim_instance *pim, pim_addr rp_addr, struct prefix group,
675
         const char *plist, enum rp_source rp_src_flag)
676
20.6k
{
677
20.6k
  struct prefix g_all;
678
20.6k
  struct rp_info *rp_info;
679
20.6k
  struct rp_info *rp_all;
680
20.6k
  pim_addr nht_p;
681
20.6k
  struct route_node *rn;
682
20.6k
  bool was_plist = false;
683
20.6k
  struct rp_info *trp_info;
684
20.6k
  struct pim_upstream *up;
685
20.6k
  struct bsgrp_node *bsgrp = NULL;
686
20.6k
  struct bsm_rpinfo *bsrp = NULL;
687
20.6k
  bool upstream_updated = false;
688
689
20.6k
  if (plist)
690
0
    rp_info = pim_rp_find_prefix_list(pim, rp_addr, plist);
691
20.6k
  else
692
20.6k
    rp_info = pim_rp_find_exact(pim, rp_addr, &group);
693
694
20.6k
  if (!rp_info)
695
7.05k
    return PIM_RP_NOT_FOUND;
696
697
13.5k
  if (rp_info->plist) {
698
0
    XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
699
0
    was_plist = true;
700
0
  }
701
702
13.5k
  if (PIM_DEBUG_PIM_TRACE)
703
0
    zlog_debug("%s: Delete RP %pPA for the group %pFX", __func__,
704
13.5k
         &rp_addr, &group);
705
706
  /* While static RP is getting deleted, we need to check if dynamic RP
707
   * present for the same group in BSM RP table, then install the dynamic
708
   * RP for the group node into the main rp table
709
   */
710
13.5k
  if (rp_src_flag == RP_SRC_STATIC) {
711
0
    bsgrp = pim_bsm_get_bsgrp_node(&pim->global_scope, &group);
712
713
0
    if (bsgrp) {
714
0
      bsrp = bsm_rpinfos_first(bsgrp->bsrp_list);
715
0
      if (bsrp) {
716
0
        if (PIM_DEBUG_PIM_TRACE)
717
0
          zlog_debug(
718
0
            "%s: BSM RP %pPA found for the group %pFX",
719
0
            __func__, &bsrp->rp_address,
720
0
            &group);
721
0
        return pim_rp_change(pim, bsrp->rp_address,
722
0
                 group, RP_SRC_BSR);
723
0
      }
724
0
    } else {
725
0
      if (PIM_DEBUG_PIM_TRACE)
726
0
        zlog_debug(
727
0
          "%s: BSM RP not found for the group %pFX",
728
0
          __func__, &group);
729
0
    }
730
0
  }
731
732
  /* Deregister addr with Zebra NHT */
733
13.5k
  nht_p = rp_info->rp.rpf_addr;
734
13.5k
  if (PIM_DEBUG_PIM_NHT_RP)
735
0
    zlog_debug("%s: Deregister RP addr %pPA with Zebra ", __func__,
736
13.5k
         &nht_p);
737
13.5k
  pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info);
738
739
13.5k
  if (!pim_get_all_mcast_group(&g_all))
740
0
    return PIM_RP_BAD_ADDRESS;
741
742
13.5k
  rp_all = pim_rp_find_match_group(pim, &g_all);
743
744
13.5k
  if (rp_all == rp_info) {
745
3.24M
    frr_each (rb_pim_upstream, &pim->upstream_head, up) {
746
      /* Find the upstream (*, G) whose upstream address is
747
       * same as the deleted RP
748
       */
749
3.24M
      pim_addr rpf_addr;
750
751
3.24M
      rpf_addr = rp_info->rp.rpf_addr;
752
3.24M
      if (!pim_addr_cmp(up->upstream_addr, rpf_addr) &&
753
158k
          pim_addr_is_any(up->sg.src)) {
754
46.1k
        struct prefix grp;
755
756
46.1k
        pim_addr_to_prefix(&grp, up->sg.grp);
757
46.1k
        trp_info = pim_rp_find_match_group(pim, &grp);
758
46.1k
        if (trp_info == rp_all) {
759
4.88k
          pim_upstream_rpf_clear(pim, up);
760
4.88k
          up->upstream_addr = PIMADDR_ANY;
761
4.88k
        }
762
46.1k
      }
763
3.24M
    }
764
5.00k
    rp_all->rp.rpf_addr = PIMADDR_ANY;
765
5.00k
    rp_all->i_am_rp = 0;
766
5.00k
    return PIM_SUCCESS;
767
5.00k
  }
768
769
8.56k
  listnode_delete(pim->rp_list, rp_info);
770
771
8.56k
  if (!was_plist) {
772
8.56k
    rn = route_node_get(pim->rp_table, &rp_info->group);
773
8.56k
    if (rn) {
774
8.56k
      if (rn->info != rp_info)
775
0
        flog_err(
776
8.56k
          EC_LIB_DEVELOPMENT,
777
8.56k
          "Expected rn->info to be equal to rp_info");
778
779
8.56k
      if (PIM_DEBUG_PIM_TRACE)
780
0
        zlog_debug(
781
8.56k
          "%s:Found for Freeing: %p for rp_info: %p(%pFX) Lock: %d",
782
8.56k
          __func__, rn, rp_info, &rp_info->group,
783
8.56k
          route_node_get_lock_count(rn));
784
785
8.56k
      rn->info = NULL;
786
8.56k
      route_unlock_node(rn);
787
8.56k
      route_unlock_node(rn);
788
8.56k
    }
789
8.56k
  }
790
791
8.56k
  pim_rp_refresh_group_to_rp_mapping(pim);
792
793
5.54M
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
794
    /* Find the upstream (*, G) whose upstream address is same as
795
     * the deleted RP
796
     */
797
5.54M
    pim_addr rpf_addr;
798
799
5.54M
    rpf_addr = rp_info->rp.rpf_addr;
800
5.54M
    if (!pim_addr_cmp(up->upstream_addr, rpf_addr) &&
801
113k
        pim_addr_is_any(up->sg.src)) {
802
99.6k
      struct prefix grp;
803
804
99.6k
      pim_addr_to_prefix(&grp, up->sg.grp);
805
99.6k
      trp_info = pim_rp_find_match_group(pim, &grp);
806
807
99.6k
      if (!trp_info)
808
4.82k
        continue;
809
810
      /* RP not found for the group grp */
811
94.8k
      if (pim_rpf_addr_is_inaddr_any(&trp_info->rp)) {
812
3.71k
        pim_upstream_rpf_clear(pim, up);
813
3.71k
        pim_rp_set_upstream_addr(
814
3.71k
          pim, &up->upstream_addr, up->sg.src,
815
3.71k
          up->sg.grp);
816
3.71k
      }
817
818
      /* RP found for the group grp */
819
91.1k
      else {
820
91.1k
        pim_upstream_update(pim, up);
821
91.1k
        upstream_updated = true;
822
91.1k
      }
823
94.8k
    }
824
5.54M
  }
825
826
8.56k
  if (upstream_updated)
827
4.69k
    pim_zebra_update_all_interfaces(pim);
828
829
8.56k
  XFREE(MTYPE_PIM_RP, rp_info);
830
8.56k
  return PIM_SUCCESS;
831
13.5k
}
832
833
int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr,
834
      struct prefix group, enum rp_source rp_src_flag)
835
26.1k
{
836
26.1k
  pim_addr nht_p;
837
26.1k
  struct route_node *rn;
838
26.1k
  int result = 0;
839
26.1k
  struct rp_info *rp_info = NULL;
840
26.1k
  struct pim_upstream *up;
841
26.1k
  bool upstream_updated = false;
842
26.1k
  pim_addr old_rp_addr;
843
844
26.1k
  rn = route_node_lookup(pim->rp_table, &group);
845
26.1k
  if (!rn) {
846
0
    result = pim_rp_new(pim, new_rp_addr, group, NULL, rp_src_flag);
847
0
    return result;
848
0
  }
849
850
26.1k
  rp_info = rn->info;
851
852
26.1k
  if (!rp_info) {
853
0
    route_unlock_node(rn);
854
0
    result = pim_rp_new(pim, new_rp_addr, group, NULL, rp_src_flag);
855
0
    return result;
856
0
  }
857
858
26.1k
  old_rp_addr = rp_info->rp.rpf_addr;
859
26.1k
  if (!pim_addr_cmp(new_rp_addr, old_rp_addr)) {
860
4.90k
    if (rp_info->rp_src != rp_src_flag) {
861
0
      rp_info->rp_src = rp_src_flag;
862
0
      route_unlock_node(rn);
863
0
      return PIM_SUCCESS;
864
0
    }
865
4.90k
  }
866
867
  /* Deregister old RP addr with Zebra NHT */
868
869
26.1k
  if (!pim_addr_is_any(old_rp_addr)) {
870
19.2k
    nht_p = rp_info->rp.rpf_addr;
871
19.2k
    if (PIM_DEBUG_PIM_NHT_RP)
872
0
      zlog_debug("%s: Deregister RP addr %pPA with Zebra ",
873
19.2k
           __func__, &nht_p);
874
19.2k
    pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info);
875
19.2k
  }
876
877
26.1k
  pim_rp_nexthop_del(rp_info);
878
26.1k
  listnode_delete(pim->rp_list, rp_info);
879
  /* Update the new RP address*/
880
881
26.1k
  rp_info->rp.rpf_addr = new_rp_addr;
882
26.1k
  rp_info->rp_src = rp_src_flag;
883
26.1k
  rp_info->i_am_rp = 0;
884
885
26.1k
  listnode_add_sort(pim->rp_list, rp_info);
886
887
17.3M
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
888
17.3M
    if (pim_addr_is_any(up->sg.src)) {
889
4.43M
      struct prefix grp;
890
4.43M
      struct rp_info *trp_info;
891
892
4.43M
      pim_addr_to_prefix(&grp, up->sg.grp);
893
4.43M
      trp_info = pim_rp_find_match_group(pim, &grp);
894
895
4.43M
      if (trp_info == rp_info) {
896
23.3k
        pim_upstream_update(pim, up);
897
23.3k
        upstream_updated = true;
898
23.3k
      }
899
4.43M
    }
900
17.3M
  }
901
902
26.1k
  if (upstream_updated)
903
1.12k
    pim_zebra_update_all_interfaces(pim);
904
905
  /* Register new RP addr with Zebra NHT */
906
26.1k
  nht_p = rp_info->rp.rpf_addr;
907
26.1k
  if (PIM_DEBUG_PIM_NHT_RP)
908
0
    zlog_debug("%s: NHT Register RP addr %pPA grp %pFX with Zebra ",
909
26.1k
         __func__, &nht_p, &rp_info->group);
910
911
26.1k
  pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
912
26.1k
  if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, nht_p,
913
26.1k
             &rp_info->group, 1)) {
914
26.1k
    route_unlock_node(rn);
915
26.1k
    return PIM_RP_NO_PATH;
916
26.1k
  }
917
918
0
  pim_rp_check_interfaces(pim, rp_info);
919
920
0
  route_unlock_node(rn);
921
922
0
  pim_rp_refresh_group_to_rp_mapping(pim);
923
924
0
  return result;
925
26.1k
}
926
927
void pim_rp_setup(struct pim_instance *pim)
928
212
{
929
212
  struct listnode *node;
930
212
  struct rp_info *rp_info;
931
212
  pim_addr nht_p;
932
933
6.08k
  for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
934
6.08k
    if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
935
172
      continue;
936
937
5.91k
    nht_p = rp_info->rp.rpf_addr;
938
939
5.91k
    pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
940
5.91k
    if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
941
5.91k
               nht_p, &rp_info->group, 1)) {
942
5.91k
      if (PIM_DEBUG_PIM_NHT_RP)
943
0
        zlog_debug(
944
5.91k
          "Unable to lookup nexthop for rp specified");
945
5.91k
      pim_rp_nexthop_del(rp_info);
946
5.91k
    }
947
5.91k
  }
948
212
}
949
950
/*
951
 * Checks to see if we should elect ourself the actual RP when new if
952
 * addresses are added against an interface.
953
 */
954
void pim_rp_check_on_if_add(struct pim_interface *pim_ifp)
955
0
{
956
0
  struct listnode *node;
957
0
  struct rp_info *rp_info;
958
0
  bool i_am_rp_changed = false;
959
0
  struct pim_instance *pim = pim_ifp->pim;
960
961
0
  if (pim->rp_list == NULL)
962
0
    return;
963
964
0
  for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
965
0
    if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
966
0
      continue;
967
968
    /* if i_am_rp is already set nothing to be done (adding new
969
     * addresses
970
     * is not going to make a difference). */
971
0
    if (rp_info->i_am_rp) {
972
0
      continue;
973
0
    }
974
975
0
    if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
976
0
      i_am_rp_changed = true;
977
0
      rp_info->i_am_rp = 1;
978
0
      if (PIM_DEBUG_PIM_NHT_RP)
979
0
        zlog_debug("%s: %pPA: i am rp", __func__,
980
0
             &rp_info->rp.rpf_addr);
981
0
    }
982
0
  }
983
984
0
  if (i_am_rp_changed) {
985
0
    pim_msdp_i_am_rp_changed(pim);
986
0
    pim_upstream_reeval_use_rpt(pim);
987
0
  }
988
0
}
989
990
/* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
991
 * are removed. Removing numbers is an uncommon event in an active network
992
 * so I have made no attempt to optimize it. */
993
void pim_i_am_rp_re_evaluate(struct pim_instance *pim)
994
0
{
995
0
  struct listnode *node;
996
0
  struct rp_info *rp_info;
997
0
  bool i_am_rp_changed = false;
998
0
  int old_i_am_rp;
999
1000
0
  if (pim->rp_list == NULL)
1001
0
    return;
1002
1003
0
  for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
1004
0
    if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
1005
0
      continue;
1006
1007
0
    old_i_am_rp = rp_info->i_am_rp;
1008
0
    pim_rp_check_interfaces(pim, rp_info);
1009
1010
0
    if (old_i_am_rp != rp_info->i_am_rp) {
1011
0
      i_am_rp_changed = true;
1012
0
      if (PIM_DEBUG_PIM_NHT_RP) {
1013
0
        if (rp_info->i_am_rp)
1014
0
          zlog_debug("%s: %pPA: i am rp",
1015
0
               __func__,
1016
0
               &rp_info->rp.rpf_addr);
1017
0
        else
1018
0
          zlog_debug(
1019
0
            "%s: %pPA: i am no longer rp",
1020
0
            __func__,
1021
0
            &rp_info->rp.rpf_addr);
1022
0
      }
1023
0
    }
1024
0
  }
1025
1026
0
  if (i_am_rp_changed) {
1027
0
    pim_msdp_i_am_rp_changed(pim);
1028
0
    pim_upstream_reeval_use_rpt(pim);
1029
0
  }
1030
0
}
1031
1032
/*
1033
 * I_am_RP(G) is true if the group-to-RP mapping indicates that
1034
 * this router is the RP for the group.
1035
 *
1036
 * Since we only have static RP, all groups are part of this RP
1037
 */
1038
int pim_rp_i_am_rp(struct pim_instance *pim, pim_addr group)
1039
13.0M
{
1040
13.0M
  struct prefix g;
1041
13.0M
  struct rp_info *rp_info;
1042
1043
13.0M
  memset(&g, 0, sizeof(g));
1044
13.0M
  pim_addr_to_prefix(&g, group);
1045
13.0M
  rp_info = pim_rp_find_match_group(pim, &g);
1046
1047
13.0M
  if (rp_info)
1048
6.48M
    return rp_info->i_am_rp;
1049
6.55M
  return 0;
1050
13.0M
}
1051
1052
/*
1053
 * RP(G)
1054
 *
1055
 * Return the RP that the Group belongs too.
1056
 */
1057
struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group)
1058
802
{
1059
802
  struct prefix g;
1060
802
  struct rp_info *rp_info;
1061
1062
802
  memset(&g, 0, sizeof(g));
1063
802
  pim_addr_to_prefix(&g, group);
1064
1065
802
  rp_info = pim_rp_find_match_group(pim, &g);
1066
1067
802
  if (rp_info) {
1068
435
    pim_addr nht_p;
1069
1070
435
    if (pim_addr_is_any(rp_info->rp.rpf_addr)) {
1071
29
      if (PIM_DEBUG_PIM_NHT_RP)
1072
0
        zlog_debug(
1073
29
          "%s: Skipping NHT Register since RP is not configured for the group %pPA",
1074
29
          __func__, &group);
1075
29
      return &rp_info->rp;
1076
29
    }
1077
1078
    /* Register addr with Zebra NHT */
1079
406
    nht_p = rp_info->rp.rpf_addr;
1080
406
    if (PIM_DEBUG_PIM_NHT_RP)
1081
0
      zlog_debug(
1082
406
        "%s: NHT Register RP addr %pPA grp %pFX with Zebra",
1083
406
        __func__, &nht_p, &rp_info->group);
1084
406
    pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
1085
406
    pim_rpf_set_refresh_time(pim);
1086
406
    (void)pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
1087
406
                nht_p, &rp_info->group, 1);
1088
406
    return (&rp_info->rp);
1089
435
  }
1090
1091
  // About to Go Down
1092
367
  return NULL;
1093
802
}
1094
1095
/*
1096
 * Set the upstream IP address we want to talk to based upon
1097
 * the rp configured and the source address
1098
 *
1099
 * If we have don't have a RP configured and the source address is *
1100
 * then set the upstream addr as INADDR_ANY and return failure.
1101
 *
1102
 */
1103
int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up,
1104
           pim_addr source, pim_addr group)
1105
171k
{
1106
171k
  struct rp_info *rp_info;
1107
171k
  struct prefix g;
1108
1109
171k
  memset(&g, 0, sizeof(g));
1110
1111
171k
  pim_addr_to_prefix(&g, group);
1112
1113
171k
  rp_info = pim_rp_find_match_group(pim, &g);
1114
1115
171k
  if (!rp_info || ((pim_rpf_addr_is_inaddr_any(&rp_info->rp)) &&
1116
22.6k
       (pim_addr_is_any(source)))) {
1117
22.6k
    if (PIM_DEBUG_PIM_NHT_RP)
1118
0
      zlog_debug("%s: Received a (*,G) with no RP configured",
1119
22.6k
           __func__);
1120
22.6k
    *up = PIMADDR_ANY;
1121
22.6k
    return 0;
1122
22.6k
  }
1123
1124
149k
  if (pim_addr_is_any(source))
1125
123k
    *up = rp_info->rp.rpf_addr;
1126
25.4k
  else
1127
25.4k
    *up = source;
1128
1129
149k
  return 1;
1130
171k
}
1131
1132
int pim_rp_config_write(struct pim_instance *pim, struct vty *vty,
1133
      const char *spaces)
1134
0
{
1135
0
  struct listnode *node;
1136
0
  struct rp_info *rp_info;
1137
0
  int count = 0;
1138
0
  pim_addr rp_addr;
1139
1140
0
  for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
1141
0
    if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
1142
0
      continue;
1143
1144
0
    if (rp_info->rp_src == RP_SRC_BSR)
1145
0
      continue;
1146
1147
0
    rp_addr = rp_info->rp.rpf_addr;
1148
0
    if (rp_info->plist)
1149
0
      vty_out(vty,
1150
0
        "%s" PIM_AF_NAME
1151
0
        " pim rp %pPA prefix-list %s\n",
1152
0
        spaces, &rp_addr, rp_info->plist);
1153
0
    else
1154
0
      vty_out(vty, "%s" PIM_AF_NAME " pim rp %pPA %pFX\n",
1155
0
        spaces, &rp_addr, &rp_info->group);
1156
0
    count++;
1157
0
  }
1158
1159
0
  return count;
1160
0
}
1161
1162
void pim_rp_show_information(struct pim_instance *pim, struct prefix *range,
1163
           struct vty *vty, json_object *json)
1164
0
{
1165
0
  struct rp_info *rp_info;
1166
0
  struct rp_info *prev_rp_info = NULL;
1167
0
  struct listnode *node;
1168
0
  struct ttable *tt = NULL;
1169
0
  char *table = NULL;
1170
0
  char source[7];
1171
0
  char grp[INET6_ADDRSTRLEN];
1172
1173
0
  json_object *json_rp_rows = NULL;
1174
0
  json_object *json_row = NULL;
1175
1176
0
  if (!json) {
1177
    /* Prepare table. */
1178
0
    tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1179
0
    ttable_add_row(
1180
0
      tt,
1181
0
      "RP address|group/prefix-list|OIF|I am RP|Source|Group-Type");
1182
0
    tt->style.cell.rpad = 2;
1183
0
    tt->style.corner = '+';
1184
0
    ttable_restyle(tt);
1185
0
  }
1186
1187
0
  for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
1188
0
    if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
1189
0
      continue;
1190
1191
0
#if PIM_IPV == 4
1192
0
    pim_addr group = rp_info->group.u.prefix4;
1193
#else
1194
    pim_addr group = rp_info->group.u.prefix6;
1195
#endif
1196
0
    const char *group_type =
1197
0
      pim_is_grp_ssm(pim, group) ? "SSM" : "ASM";
1198
1199
0
    if (range && !prefix_match(&rp_info->group, range))
1200
0
      continue;
1201
1202
0
    if (rp_info->rp_src == RP_SRC_STATIC)
1203
0
      strlcpy(source, "Static", sizeof(source));
1204
0
    else if (rp_info->rp_src == RP_SRC_BSR)
1205
0
      strlcpy(source, "BSR", sizeof(source));
1206
0
    else
1207
0
      strlcpy(source, "None", sizeof(source));
1208
0
    if (json) {
1209
      /*
1210
       * If we have moved on to a new RP then add the
1211
       * entry for the previous RP
1212
       */
1213
0
      if (prev_rp_info &&
1214
0
          (pim_addr_cmp(prev_rp_info->rp.rpf_addr,
1215
0
            rp_info->rp.rpf_addr))) {
1216
0
        json_object_object_addf(
1217
0
          json, json_rp_rows, "%pPA",
1218
0
          &prev_rp_info->rp.rpf_addr);
1219
0
        json_rp_rows = NULL;
1220
0
      }
1221
1222
0
      if (!json_rp_rows)
1223
0
        json_rp_rows = json_object_new_array();
1224
1225
0
      json_row = json_object_new_object();
1226
0
      json_object_string_addf(json_row, "rpAddress", "%pPA",
1227
0
            &rp_info->rp.rpf_addr);
1228
0
      if (rp_info->rp.source_nexthop.interface)
1229
0
        json_object_string_add(
1230
0
          json_row, "outboundInterface",
1231
0
          rp_info->rp.source_nexthop
1232
0
            .interface->name);
1233
0
      else
1234
0
        json_object_string_add(json_row,
1235
0
                   "outboundInterface",
1236
0
                   "Unknown");
1237
0
      if (rp_info->i_am_rp)
1238
0
        json_object_boolean_true_add(json_row, "iAmRP");
1239
0
      else
1240
0
        json_object_boolean_false_add(json_row,
1241
0
                    "iAmRP");
1242
1243
0
      if (rp_info->plist)
1244
0
        json_object_string_add(json_row, "prefixList",
1245
0
                   rp_info->plist);
1246
0
      else
1247
0
        json_object_string_addf(json_row, "group",
1248
0
              "%pFX",
1249
0
              &rp_info->group);
1250
0
      json_object_string_add(json_row, "source", source);
1251
0
      json_object_string_add(json_row, "groupType",
1252
0
                 group_type);
1253
1254
0
      json_object_array_add(json_rp_rows, json_row);
1255
0
    } else {
1256
0
      prefix2str(&rp_info->group, grp, sizeof(grp));
1257
0
      ttable_add_row(tt, "%pPA|%s|%s|%s|%s|%s",
1258
0
            &rp_info->rp.rpf_addr,
1259
0
            rp_info->plist
1260
0
            ? rp_info->plist
1261
0
            : grp,
1262
0
            rp_info->rp.source_nexthop.interface
1263
0
            ? rp_info->rp.source_nexthop
1264
0
            .interface->name
1265
0
            : "Unknown",
1266
0
            rp_info->i_am_rp
1267
0
            ? "yes"
1268
0
            : "no",
1269
0
            source, group_type);
1270
0
    }
1271
0
    prev_rp_info = rp_info;
1272
0
  }
1273
1274
  /* Dump the generated table. */
1275
0
  if (!json) {
1276
0
    table = ttable_dump(tt, "\n");
1277
0
    vty_out(vty, "%s\n", table);
1278
0
    XFREE(MTYPE_TMP, table);
1279
0
    ttable_del(tt);
1280
0
  } else {
1281
0
    if (prev_rp_info && json_rp_rows)
1282
0
      json_object_object_addf(json, json_rp_rows, "%pPA",
1283
0
            &prev_rp_info->rp.rpf_addr);
1284
0
  }
1285
0
}
1286
1287
void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr)
1288
212
{
1289
212
  struct listnode *node = NULL;
1290
212
  struct rp_info *rp_info = NULL;
1291
212
  struct nexthop *nh_node = NULL;
1292
212
  pim_addr nht_p;
1293
212
  struct pim_nexthop_cache pnc;
1294
1295
6.08k
  for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
1296
6.08k
    if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
1297
172
      continue;
1298
1299
5.91k
    nht_p = rp_info->rp.rpf_addr;
1300
5.91k
    memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
1301
5.91k
    if (!pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, &pnc))
1302
5.91k
      continue;
1303
1304
0
    for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
1305
0
#if PIM_IPV == 4
1306
0
      if (!pim_addr_is_any(nh_node->gate.ipv4))
1307
0
        continue;
1308
#else
1309
      if (!pim_addr_is_any(nh_node->gate.ipv6))
1310
        continue;
1311
#endif
1312
1313
0
      struct interface *ifp1 = if_lookup_by_index(
1314
0
        nh_node->ifindex, pim->vrf->vrf_id);
1315
1316
0
      if (nbr->interface != ifp1)
1317
0
        continue;
1318
1319
0
#if PIM_IPV == 4
1320
0
      nh_node->gate.ipv4 = nbr->source_addr;
1321
#else
1322
      nh_node->gate.ipv6 = nbr->source_addr;
1323
#endif
1324
0
      if (PIM_DEBUG_PIM_NHT_RP)
1325
0
        zlog_debug(
1326
0
          "%s: addr %pPA new nexthop addr %pPAs interface %s",
1327
0
          __func__, &nht_p, &nbr->source_addr,
1328
0
          ifp1->name);
1329
0
    }
1330
0
  }
1331
212
}