Coverage Report

Created: 2025-11-11 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/pimd/pim_upstream.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * PIM for Quagga
4
 * Copyright (C) 2008  Everton da Silva Marques
5
 */
6
7
#include <zebra.h>
8
9
#include "log.h"
10
#include "zclient.h"
11
#include "memory.h"
12
#include "frrevent.h"
13
#include "linklist.h"
14
#include "vty.h"
15
#include "plist.h"
16
#include "hash.h"
17
#include "jhash.h"
18
#include "wheel.h"
19
#include "network.h"
20
21
#include "pimd.h"
22
#include "pim_pim.h"
23
#include "pim_str.h"
24
#include "pim_time.h"
25
#include "pim_iface.h"
26
#include "pim_join.h"
27
#include "pim_zlookup.h"
28
#include "pim_upstream.h"
29
#include "pim_ifchannel.h"
30
#include "pim_neighbor.h"
31
#include "pim_rpf.h"
32
#include "pim_zebra.h"
33
#include "pim_oil.h"
34
#include "pim_macro.h"
35
#include "pim_rp.h"
36
#include "pim_register.h"
37
#include "pim_msdp.h"
38
#include "pim_jp_agg.h"
39
#include "pim_nht.h"
40
#include "pim_ssm.h"
41
#include "pim_vxlan.h"
42
#include "pim_mlag.h"
43
44
static void join_timer_stop(struct pim_upstream *up);
45
static void
46
pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
47
static bool pim_upstream_sg_running_proc(struct pim_upstream *up);
48
49
/*
50
 * A (*,G) or a (*,*) is going away
51
 * remove the parent pointer from
52
 * those pointing at us
53
 */
54
static void pim_upstream_remove_children(struct pim_instance *pim,
55
           struct pim_upstream *up)
56
54.6k
{
57
54.6k
  struct pim_upstream *child;
58
59
54.6k
  if (!up->sources)
60
54.6k
    return;
61
62
0
  while (!list_isempty(up->sources)) {
63
0
    child = listnode_head(up->sources);
64
0
    listnode_delete(up->sources, child);
65
0
    if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags)) {
66
0
      PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags);
67
0
      child = pim_upstream_del(pim, child, __func__);
68
0
    }
69
0
    if (child) {
70
0
      child->parent = NULL;
71
0
      if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
72
0
        pim_upstream_mroute_iif_update(
73
0
            child->channel_oil,
74
0
            __func__);
75
0
    }
76
0
  }
77
0
  list_delete(&up->sources);
78
0
}
79
80
/*
81
 * A (*,G) or a (*,*) is being created
82
 * Find the children that would point
83
 * at us.
84
 */
85
static void pim_upstream_find_new_children(struct pim_instance *pim,
86
             struct pim_upstream *up)
87
55.2k
{
88
55.2k
  struct pim_upstream *child;
89
90
55.2k
  if (!pim_addr_is_any(up->sg.src) && !pim_addr_is_any(up->sg.grp))
91
55.0k
    return;
92
93
211
  if (pim_addr_is_any(up->sg.src) && pim_addr_is_any(up->sg.grp))
94
1
    return;
95
96
77.8k
  frr_each (rb_pim_upstream, &pim->upstream_head, child) {
97
77.8k
    if (!pim_addr_is_any(up->sg.grp) &&
98
62.4k
        !pim_addr_cmp(child->sg.grp, up->sg.grp) && (child != up)) {
99
219
      child->parent = up;
100
219
      listnode_add_sort(up->sources, child);
101
219
      if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
102
177
        pim_upstream_mroute_iif_update(
103
177
            child->channel_oil,
104
177
            __func__);
105
219
    }
106
77.8k
  }
107
210
}
108
109
/*
110
 * If we have a (*,*) || (S,*) there is no parent
111
 * If we have a (S,G), find the (*,G)
112
 * If we have a (*,G), find the (*,*)
113
 */
114
static struct pim_upstream *pim_upstream_find_parent(struct pim_instance *pim,
115
                 struct pim_upstream *child)
116
55.2k
{
117
55.2k
  pim_sgaddr any = child->sg;
118
55.2k
  struct pim_upstream *up = NULL;
119
120
  // (S,G)
121
55.2k
  if (!pim_addr_is_any(child->sg.src) &&
122
55.1k
      !pim_addr_is_any(child->sg.grp)) {
123
55.0k
    any.src = PIMADDR_ANY;
124
55.0k
    up = pim_upstream_find(pim, &any);
125
126
55.0k
    if (up)
127
54.6k
      listnode_add(up->sources, child);
128
129
    /*
130
     * In case parent is MLAG entry copy the data to child
131
     */
132
55.0k
    if (up && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)) {
133
0
      PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(child->flags);
134
0
      if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
135
0
        PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(child->flags);
136
0
      else
137
0
        PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(
138
0
          child->flags);
139
0
    }
140
141
55.0k
    return up;
142
55.0k
  }
143
144
211
  return NULL;
145
55.2k
}
146
147
static void upstream_channel_oil_detach(struct pim_upstream *up)
148
54.6k
{
149
54.6k
  struct channel_oil *channel_oil = up->channel_oil;
150
151
54.6k
  if (channel_oil) {
152
    /* Detaching from channel_oil, channel_oil may exist post del,
153
       but upstream would not keep reference of it
154
     */
155
54.6k
    channel_oil->up = NULL;
156
54.6k
    up->channel_oil = NULL;
157
158
    /* attempt to delete channel_oil; if channel_oil is being held
159
     * because of other references cleanup info such as "Mute"
160
     * inferred from the parent upstream
161
     */
162
54.6k
    pim_channel_oil_upstream_deref(channel_oil);
163
54.6k
  }
164
165
54.6k
}
166
167
static void pim_upstream_timers_stop(struct pim_upstream *up)
168
54.6k
{
169
54.6k
  EVENT_OFF(up->t_ka_timer);
170
54.6k
  EVENT_OFF(up->t_rs_timer);
171
54.6k
  EVENT_OFF(up->t_msdp_reg_timer);
172
54.6k
  EVENT_OFF(up->t_join_timer);
173
54.6k
}
174
175
struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
176
              struct pim_upstream *up, const char *name)
177
54.6k
{
178
54.6k
  struct listnode *node, *nnode;
179
54.6k
  struct pim_ifchannel *ch;
180
54.6k
  bool notify_msdp = false;
181
182
54.6k
  if (PIM_DEBUG_PIM_TRACE)
183
0
    zlog_debug(
184
54.6k
      "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
185
54.6k
      __func__, name, up->sg_str, pim->vrf->name,
186
54.6k
      up->ref_count, up->flags,
187
54.6k
      up->channel_oil->oil_ref_count);
188
189
54.6k
   assert(up->ref_count > 0);
190
191
54.6k
  --up->ref_count;
192
193
54.6k
  if (up->ref_count >= 1)
194
0
    return up;
195
196
54.6k
  if (PIM_DEBUG_TRACE)
197
0
    zlog_debug("pim_upstream free vrf:%s %s flags 0x%x",
198
54.6k
         pim->vrf->name, up->sg_str, up->flags);
199
200
54.6k
  if (pim_up_mlag_is_local(up))
201
0
    pim_mlag_up_local_del(pim, up);
202
203
54.6k
  pim_upstream_timers_stop(up);
204
205
54.6k
  if (up->join_state == PIM_UPSTREAM_JOINED) {
206
0
    pim_jp_agg_single_upstream_send(&up->rpf, up, 0);
207
208
0
    if (pim_addr_is_any(up->sg.src)) {
209
      /* if a (*, G) entry in the joined state is being
210
       * deleted we
211
       * need to notify MSDP */
212
0
      notify_msdp = true;
213
0
    }
214
0
  }
215
216
54.6k
  join_timer_stop(up);
217
54.6k
  pim_jp_agg_upstream_verification(up, false);
218
54.6k
  up->rpf.source_nexthop.interface = NULL;
219
220
54.6k
  if (!pim_addr_is_any(up->sg.src)) {
221
54.6k
    if (pim->upstream_sg_wheel)
222
54.6k
      wheel_remove_item(pim->upstream_sg_wheel, up);
223
54.6k
    notify_msdp = true;
224
54.6k
  }
225
226
54.6k
  pim_mroute_del(up->channel_oil, __func__);
227
54.6k
  upstream_channel_oil_detach(up);
228
229
54.6k
  for (ALL_LIST_ELEMENTS(up->ifchannels, node, nnode, ch))
230
0
    pim_ifchannel_delete(ch);
231
54.6k
  list_delete(&up->ifchannels);
232
233
54.6k
  pim_upstream_remove_children(pim, up);
234
54.6k
  if (up->sources)
235
0
    list_delete(&up->sources);
236
237
54.6k
  if (up->parent && up->parent->sources)
238
54.6k
    listnode_delete(up->parent->sources, up);
239
54.6k
  up->parent = NULL;
240
241
54.6k
  rb_pim_upstream_del(&pim->upstream_head, up);
242
243
54.6k
  if (notify_msdp) {
244
54.6k
    pim_msdp_up_del(pim, &up->sg);
245
54.6k
  }
246
247
  /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT
248
   * and assign up->upstream_addr as INADDR_ANY.
249
   * So before de-registering the upstream address, check if is not equal
250
   * to INADDR_ANY. This is done in order to avoid de-registering for
251
   * 255.255.255.255 which is maintained for some reason..
252
   */
253
54.6k
  if (!pim_addr_is_any(up->upstream_addr)) {
254
    /* Deregister addr with Zebra NHT */
255
26.3k
    if (PIM_DEBUG_PIM_TRACE)
256
0
      zlog_debug(
257
26.3k
        "%s: Deregister upstream %s addr %pPA with Zebra NHT",
258
26.3k
        __func__, up->sg_str, &up->upstream_addr);
259
26.3k
    pim_delete_tracked_nexthop(pim, up->upstream_addr, up, NULL);
260
26.3k
  }
261
262
54.6k
  XFREE(MTYPE_PIM_UPSTREAM, up);
263
264
54.6k
  return NULL;
265
54.6k
}
266
267
void pim_upstream_send_join(struct pim_upstream *up)
268
0
{
269
0
  if (!up->rpf.source_nexthop.interface) {
270
0
    if (PIM_DEBUG_PIM_TRACE)
271
0
      zlog_debug("%s: up %s RPF is not present", __func__,
272
0
           up->sg_str);
273
0
    return;
274
0
  }
275
276
0
  if (PIM_DEBUG_PIM_TRACE) {
277
0
    zlog_debug("%s: RPF'%s=%pPA(%s) for Interface %s", __func__,
278
0
         up->sg_str, &up->rpf.rpf_addr,
279
0
         pim_upstream_state2str(up->join_state),
280
0
         up->rpf.source_nexthop.interface->name);
281
0
    if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
282
0
      zlog_debug("%s: can't send join upstream: RPF'%s=%pPA",
283
0
           __func__, up->sg_str, &up->rpf.rpf_addr);
284
      /* warning only */
285
0
    }
286
0
  }
287
288
  /* send Join(S,G) to the current upstream neighbor */
289
0
  pim_jp_agg_single_upstream_send(&up->rpf, up, 1 /* join */);
290
0
}
291
292
static void on_join_timer(struct event *t)
293
0
{
294
0
  struct pim_upstream *up;
295
0
296
0
  up = EVENT_ARG(t);
297
0
298
0
  if (!up->rpf.source_nexthop.interface) {
299
0
    if (PIM_DEBUG_PIM_TRACE)
300
0
      zlog_debug("%s: up %s RPF is not present", __func__,
301
0
           up->sg_str);
302
0
    return;
303
0
  }
304
0
305
0
  /*
306
0
   * In the case of a HFR we will not ahve anyone to send this to.
307
0
   */
308
0
  if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
309
0
    return;
310
0
311
0
  /*
312
0
   * Don't send the join if the outgoing interface is a loopback
313
0
   * But since this might change leave the join timer running
314
0
   */
315
0
  if (up->rpf.source_nexthop
316
0
        .interface && !if_is_loopback(up->rpf.source_nexthop.interface))
317
0
    pim_upstream_send_join(up);
318
0
319
0
  join_timer_start(up);
320
0
}
321
322
static void join_timer_stop(struct pim_upstream *up)
323
54.6k
{
324
54.6k
  struct pim_neighbor *nbr = NULL;
325
326
54.6k
  EVENT_OFF(up->t_join_timer);
327
328
54.6k
  if (up->rpf.source_nexthop.interface)
329
0
    nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
330
0
          up->rpf.rpf_addr, true);
331
332
54.6k
  if (nbr)
333
0
    pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
334
335
54.6k
  pim_jp_agg_upstream_verification(up, false);
336
54.6k
}
337
338
void join_timer_start(struct pim_upstream *up)
339
0
{
340
0
  struct pim_neighbor *nbr = NULL;
341
342
0
  if (up->rpf.source_nexthop.interface) {
343
0
    nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
344
0
          up->rpf.rpf_addr, true);
345
346
0
    if (PIM_DEBUG_PIM_EVENTS) {
347
0
      zlog_debug(
348
0
        "%s: starting %d sec timer for upstream (S,G)=%s",
349
0
        __func__, router->t_periodic, up->sg_str);
350
0
    }
351
0
  }
352
353
0
  if (nbr)
354
0
    pim_jp_agg_add_group(nbr->upstream_jp_agg, up, 1, nbr);
355
0
  else {
356
0
    EVENT_OFF(up->t_join_timer);
357
0
    event_add_timer(router->master, on_join_timer, up,
358
0
        router->t_periodic, &up->t_join_timer);
359
0
  }
360
0
  pim_jp_agg_upstream_verification(up, true);
361
0
}
362
363
/*
364
 * This is only called when we are switching the upstream
365
 * J/P from one neighbor to another
366
 *
367
 * As such we need to remove from the old list and
368
 * add to the new list.
369
 */
370
void pim_upstream_join_timer_restart(struct pim_upstream *up,
371
             struct pim_rpf *old)
372
0
{
373
  // EVENT_OFF(up->t_join_timer);
374
0
  join_timer_start(up);
375
0
}
376
377
static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
378
             int interval_msec)
379
0
{
380
0
  if (PIM_DEBUG_PIM_EVENTS) {
381
0
    zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
382
0
         __func__, interval_msec, up->sg_str);
383
0
  }
384
385
0
  EVENT_OFF(up->t_join_timer);
386
0
  event_add_timer_msec(router->master, on_join_timer, up, interval_msec,
387
0
           &up->t_join_timer);
388
0
}
389
390
void pim_update_suppress_timers(uint32_t suppress_time)
391
0
{
392
0
  struct pim_instance *pim;
393
0
  struct vrf *vrf;
394
0
  unsigned int old_rp_ka_time;
395
396
  /* stash the old one so we know which values were manually configured */
397
0
  old_rp_ka_time =  (3 * router->register_suppress_time
398
0
         + router->register_probe_time);
399
0
  router->register_suppress_time = suppress_time;
400
401
0
  RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
402
0
    pim = vrf->info;
403
0
    if (!pim)
404
0
      continue;
405
406
    /* Only adjust if not manually configured */
407
0
    if (pim->rp_keep_alive_time == old_rp_ka_time)
408
0
      pim->rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD;
409
0
  }
410
0
}
411
412
void pim_upstream_join_suppress(struct pim_upstream *up, pim_addr rpf,
413
        int holdtime)
414
0
{
415
0
  long t_joinsuppress_msec;
416
0
  long join_timer_remain_msec = 0;
417
0
  struct pim_neighbor *nbr = NULL;
418
419
0
  if (!up->rpf.source_nexthop.interface) {
420
0
    if (PIM_DEBUG_PIM_TRACE)
421
0
      zlog_debug("%s: up %s RPF is not present", __func__,
422
0
           up->sg_str);
423
0
    return;
424
0
  }
425
426
0
  t_joinsuppress_msec =
427
0
    MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
428
0
        1000 * holdtime);
429
430
0
  if (up->t_join_timer)
431
0
    join_timer_remain_msec =
432
0
      pim_time_timer_remain_msec(up->t_join_timer);
433
0
  else {
434
    /* Remove it from jp agg from the nbr for suppression */
435
0
    nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
436
0
          up->rpf.rpf_addr, true);
437
438
0
    if (nbr) {
439
0
      join_timer_remain_msec =
440
0
        pim_time_timer_remain_msec(nbr->jp_timer);
441
0
    }
442
0
  }
443
444
0
  if (PIM_DEBUG_PIM_TRACE)
445
0
    zlog_debug(
446
0
      "%s %s: detected Join%s to RPF'(S,G)=%pPA: join_timer=%ld msec t_joinsuppress=%ld msec",
447
0
      __FILE__, __func__, up->sg_str, &rpf,
448
0
      join_timer_remain_msec, t_joinsuppress_msec);
449
450
0
  if (join_timer_remain_msec < t_joinsuppress_msec) {
451
0
    if (PIM_DEBUG_PIM_TRACE) {
452
0
      zlog_debug(
453
0
        "%s %s: suppressing Join(S,G)=%s for %ld msec",
454
0
        __FILE__, __func__, up->sg_str,
455
0
        t_joinsuppress_msec);
456
0
    }
457
458
0
    if (nbr)
459
0
      pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
460
461
0
    pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
462
0
  }
463
0
}
464
465
void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
466
                struct pim_upstream *up)
467
0
{
468
0
  long join_timer_remain_msec;
469
0
  int t_override_msec;
470
471
0
  if (!up->rpf.source_nexthop.interface) {
472
0
    if (PIM_DEBUG_PIM_TRACE)
473
0
      zlog_debug("%s: up %s RPF is not present", __func__,
474
0
           up->sg_str);
475
0
    return;
476
0
  }
477
478
0
  t_override_msec =
479
0
    pim_if_t_override_msec(up->rpf.source_nexthop.interface);
480
481
0
  if (up->t_join_timer) {
482
0
    join_timer_remain_msec =
483
0
      pim_time_timer_remain_msec(up->t_join_timer);
484
0
  } else {
485
    /* upstream join tracked with neighbor jp timer */
486
0
    struct pim_neighbor *nbr;
487
488
0
    nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
489
0
          up->rpf.rpf_addr, true);
490
491
0
    if (nbr)
492
0
      join_timer_remain_msec =
493
0
        pim_time_timer_remain_msec(nbr->jp_timer);
494
0
    else
495
      /* Manipulate such that override takes place */
496
0
      join_timer_remain_msec = t_override_msec + 1;
497
0
  }
498
499
0
  if (PIM_DEBUG_PIM_TRACE)
500
0
    zlog_debug(
501
0
      "%s: to RPF'%s=%pPA: join_timer=%ld msec t_override=%d msec",
502
0
      debug_label, up->sg_str, &up->rpf.rpf_addr,
503
0
      join_timer_remain_msec, t_override_msec);
504
505
0
  if (join_timer_remain_msec > t_override_msec) {
506
0
    if (PIM_DEBUG_PIM_TRACE) {
507
0
      zlog_debug(
508
0
        "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
509
0
        debug_label, up->sg_str, t_override_msec);
510
0
    }
511
512
0
    pim_upstream_join_timer_restart_msec(up, t_override_msec);
513
0
  }
514
0
}
515
516
static void forward_on(struct pim_upstream *up)
517
0
{
518
0
  struct listnode *chnode;
519
0
  struct listnode *chnextnode;
520
0
  struct pim_ifchannel *ch = NULL;
521
522
  /* scan (S,G) state */
523
0
  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
524
0
    if (pim_macro_chisin_oiflist(ch))
525
0
      pim_forward_start(ch);
526
527
0
  } /* scan iface channel list */
528
0
}
529
530
static void forward_off(struct pim_upstream *up)
531
0
{
532
0
  struct listnode *chnode;
533
0
  struct listnode *chnextnode;
534
0
  struct pim_ifchannel *ch;
535
536
  /* scan per-interface (S,G) state */
537
0
  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
538
539
0
    pim_forward_stop(ch);
540
541
0
  } /* scan iface channel list */
542
0
}
543
544
int pim_upstream_could_register(struct pim_upstream *up)
545
0
{
546
0
  struct pim_interface *pim_ifp = NULL;
547
548
  /* FORCE_PIMREG is a generic flag to let an app like VxLAN-AA register
549
   * a source on an upstream entry even if the source is not directly
550
   * connected on the IIF.
551
   */
552
0
  if (PIM_UPSTREAM_FLAG_TEST_FORCE_PIMREG(up->flags))
553
0
    return 1;
554
555
0
  if (up->rpf.source_nexthop.interface)
556
0
    pim_ifp = up->rpf.source_nexthop.interface->info;
557
0
  else {
558
0
    if (PIM_DEBUG_PIM_TRACE)
559
0
      zlog_debug("%s: up %s RPF is not present", __func__,
560
0
           up->sg_str);
561
0
  }
562
563
0
  if (pim_ifp && PIM_I_am_DR(pim_ifp)
564
0
      && pim_if_connected_to_source(up->rpf.source_nexthop.interface,
565
0
            up->sg.src))
566
0
    return 1;
567
568
0
  return 0;
569
0
}
570
571
/* Source registration is suppressed for SSM groups. When the SSM range changes
572
 * we re-revaluate register setup for existing upstream entries */
573
void pim_upstream_register_reevaluate(struct pim_instance *pim)
574
0
{
575
0
  struct pim_upstream *up;
576
577
0
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
578
    /* If FHR is set CouldRegister is True. Also check if the flow
579
     * is actually active; if it is not kat setup will trigger
580
     * source
581
     * registration whenever the flow becomes active. */
582
0
    if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) ||
583
0
      !pim_upstream_is_kat_running(up))
584
0
      continue;
585
586
0
    if (pim_is_grp_ssm(pim, up->sg.grp)) {
587
      /* clear the register state  for SSM groups */
588
0
      if (up->reg_state != PIM_REG_NOINFO) {
589
0
        if (PIM_DEBUG_PIM_EVENTS)
590
0
          zlog_debug(
591
0
            "Clear register for %s as G is now SSM",
592
0
            up->sg_str);
593
        /* remove regiface from the OIL if it is there*/
594
0
        pim_channel_del_oif(up->channel_oil,
595
0
                pim->regiface,
596
0
                PIM_OIF_FLAG_PROTO_PIM,
597
0
              __func__);
598
0
        up->reg_state = PIM_REG_NOINFO;
599
0
      }
600
0
    } else {
601
      /* register ASM sources with the RP */
602
0
      if (up->reg_state == PIM_REG_NOINFO) {
603
0
        if (PIM_DEBUG_PIM_EVENTS)
604
0
          zlog_debug(
605
0
            "Register %s as G is now ASM",
606
0
            up->sg_str);
607
0
        pim_channel_add_oif(up->channel_oil,
608
0
                pim->regiface,
609
0
                PIM_OIF_FLAG_PROTO_PIM,
610
0
              __func__);
611
0
        up->reg_state = PIM_REG_JOIN;
612
0
      }
613
0
    }
614
0
  }
615
0
}
616
617
/* RFC7761, Section 4.2 “Data Packet Forwarding Rules” says we should
618
 * forward a S -
619
 * 1. along the SPT if SPTbit is set
620
 * 2. and along the RPT if SPTbit is not set
621
 * If forwarding is hw accelerated i.e. control and dataplane components
622
 * are separate you may not be able to reliably set SPT bit on intermediate
623
 * routers while still forwarding on the (S,G,rpt).
624
 *
625
 * This macro is a slight deviation on the RFC and uses "traffic-agnostic"
626
 * criteria to decide between using the RPT vs. SPT for forwarding.
627
 */
628
void pim_upstream_update_use_rpt(struct pim_upstream *up,
629
      bool update_mroute)
630
8.86M
{
631
8.86M
  bool old_use_rpt;
632
8.86M
  bool new_use_rpt;
633
634
8.86M
  if (pim_addr_is_any(up->sg.src))
635
80
    return;
636
637
8.86M
  old_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
638
639
  /* We will use the SPT (IIF=RPF_interface(S) if -
640
   * 1. We have decided to join the SPT
641
   * 2. We are FHR
642
   * 3. Source is directly connected
643
   * 4. We are RP (parent's IIF is lo or vrf-device)
644
   * In all other cases the source will stay along the RPT and
645
   * IIF=RPF_interface(RP).
646
   */
647
8.86M
  if (up->join_state == PIM_UPSTREAM_JOINED ||
648
8.86M
      PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) ||
649
8.86M
      pim_if_connected_to_source(
650
8.86M
        up->rpf.source_nexthop.interface,
651
8.86M
        up->sg.src) ||
652
      /* XXX - need to switch this to a more efficient
653
       * lookup API
654
       */
655
8.86M
      I_am_RP(up->pim, up->sg.grp))
656
    /* use SPT */
657
270k
    PIM_UPSTREAM_FLAG_UNSET_USE_RPT(up->flags);
658
8.59M
  else
659
    /* use RPT */
660
8.59M
    PIM_UPSTREAM_FLAG_SET_USE_RPT(up->flags);
661
662
8.86M
  new_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
663
8.86M
  if (old_use_rpt != new_use_rpt) {
664
36.3k
    if (PIM_DEBUG_PIM_EVENTS)
665
0
      zlog_debug("%s switched from %s to %s",
666
36.3k
          up->sg_str,
667
36.3k
          old_use_rpt?"RPT":"SPT",
668
36.3k
          new_use_rpt?"RPT":"SPT");
669
36.3k
    if (update_mroute)
670
12.0k
      pim_upstream_mroute_add(up->channel_oil, __func__);
671
36.3k
  }
672
8.86M
}
673
674
/* some events like RP change require re-evaluation of SGrpt across
675
 * all groups
676
 */
677
void pim_upstream_reeval_use_rpt(struct pim_instance *pim)
678
18.1k
{
679
18.1k
  struct pim_upstream *up;
680
681
11.7M
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
682
11.7M
    if (pim_addr_is_any(up->sg.src))
683
2.93M
      continue;
684
685
8.83M
    pim_upstream_update_use_rpt(up, true /*update_mroute*/);
686
8.83M
  }
687
18.1k
}
688
689
void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
690
       enum pim_upstream_state new_state)
691
3.68k
{
692
3.68k
  enum pim_upstream_state old_state = up->join_state;
693
694
3.68k
  if (pim_addr_is_any(up->upstream_addr)) {
695
2.84k
    if (PIM_DEBUG_PIM_EVENTS)
696
0
      zlog_debug("%s: RPF not configured for %s", __func__,
697
2.84k
           up->sg_str);
698
2.84k
    return;
699
2.84k
  }
700
701
834
  if (!up->rpf.source_nexthop.interface)  {
702
834
    if (PIM_DEBUG_PIM_EVENTS)
703
0
      zlog_debug("%s: RP not reachable for %s", __func__,
704
834
           up->sg_str);
705
834
    return;
706
834
  }
707
708
0
  if (PIM_DEBUG_PIM_EVENTS) {
709
0
    zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
710
0
         __func__, up->sg_str,
711
0
         pim_upstream_state2str(up->join_state),
712
0
         pim_upstream_state2str(new_state));
713
0
  }
714
715
0
  up->join_state = new_state;
716
0
  if (old_state != new_state)
717
0
    up->state_transition = pim_time_monotonic_sec();
718
719
0
  pim_upstream_update_assert_tracking_desired(up);
720
721
0
  if (new_state == PIM_UPSTREAM_JOINED) {
722
0
    pim_upstream_inherited_olist_decide(pim, up);
723
0
    if (old_state != PIM_UPSTREAM_JOINED) {
724
0
      int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
725
726
0
      pim_msdp_up_join_state_changed(pim, up);
727
0
      if (pim_upstream_could_register(up)) {
728
0
        PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
729
0
        if (!old_fhr
730
0
            && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
731
0
                 up->flags)) {
732
0
          pim_upstream_keep_alive_timer_start(
733
0
            up, pim->keep_alive_time);
734
0
          pim_register_join(up);
735
0
        }
736
0
      } else {
737
0
        pim_upstream_send_join(up);
738
0
        join_timer_start(up);
739
0
      }
740
0
    }
741
0
    if (old_state != new_state)
742
0
      pim_upstream_update_use_rpt(up, true /*update_mroute*/);
743
0
  } else {
744
0
    bool old_use_rpt;
745
0
    bool new_use_rpt;
746
0
    bool send_xg_jp = false;
747
748
0
    forward_off(up);
749
    /*
750
     * RFC 4601 Sec 4.5.7:
751
     * JoinDesired(S,G) -> False, set SPTbit to false.
752
     */
753
0
    if (!pim_addr_is_any(up->sg.src))
754
0
      up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
755
756
0
    if (old_state == PIM_UPSTREAM_JOINED)
757
0
      pim_msdp_up_join_state_changed(pim, up);
758
759
0
    if (old_state != new_state) {
760
0
      old_use_rpt =
761
0
        !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
762
0
      pim_upstream_update_use_rpt(up, true /*update_mroute*/);
763
0
      new_use_rpt =
764
0
        !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
765
0
      if (new_use_rpt &&
766
0
          (new_use_rpt != old_use_rpt) &&
767
0
          up->parent)
768
        /* we have decided to switch from the SPT back
769
         * to the RPT which means we need to cancel
770
         * any previously sent SGrpt prunes immediately
771
         */
772
0
        send_xg_jp = true;
773
0
    }
774
775
    /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
776
       RP.
777
       If I am RP for G then send S,G prune to its IIF. */
778
0
    if (pim_upstream_is_sg_rpt(up) && up->parent &&
779
0
        !I_am_RP(pim, up->sg.grp))
780
0
      send_xg_jp = true;
781
782
0
    pim_jp_agg_single_upstream_send(&up->rpf, up, 0 /* prune */);
783
784
0
    if (send_xg_jp) {
785
0
      if (PIM_DEBUG_PIM_TRACE_DETAIL)
786
0
        zlog_debug(
787
0
          "re-join RPT; *,G IIF %s S,G IIF %s ",
788
0
          up->parent->rpf.source_nexthop.interface ?
789
0
          up->parent->rpf.source_nexthop.interface->name
790
0
          : "Unknown",
791
0
          up->rpf.source_nexthop.interface ?
792
0
          up->rpf.source_nexthop.interface->name :
793
0
          "Unknown");
794
0
      pim_jp_agg_single_upstream_send(&up->parent->rpf,
795
0
              up->parent,
796
0
              1 /* (W,G) Join */);
797
0
    }
798
0
    join_timer_stop(up);
799
0
  }
800
0
}
801
802
int pim_upstream_compare(const struct pim_upstream *up1,
803
       const struct pim_upstream *up2)
804
2.06M
{
805
2.06M
  return pim_sgaddr_cmp(up1->sg, up2->sg);
806
2.06M
}
807
808
void pim_upstream_fill_static_iif(struct pim_upstream *up,
809
        struct interface *incoming)
810
0
{
811
0
  up->rpf.source_nexthop.interface = incoming;
812
813
  /* reset other parameters to matched a connected incoming interface */
814
0
  up->rpf.source_nexthop.mrib_nexthop_addr = PIMADDR_ANY;
815
0
  up->rpf.source_nexthop.mrib_metric_preference =
816
0
    ZEBRA_CONNECT_DISTANCE_DEFAULT;
817
0
  up->rpf.source_nexthop.mrib_route_metric = 0;
818
0
  up->rpf.rpf_addr = PIMADDR_ANY;
819
0
}
820
821
static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
822
               pim_sgaddr *sg,
823
               struct interface *incoming,
824
               int flags,
825
               struct pim_ifchannel *ch)
826
55.2k
{
827
55.2k
  enum pim_rpf_result rpf_result;
828
55.2k
  struct pim_interface *pim_ifp;
829
55.2k
  struct pim_upstream *up;
830
831
55.2k
  up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
832
833
55.2k
  up->pim = pim;
834
55.2k
  up->sg = *sg;
835
55.2k
  snprintfrr(up->sg_str, sizeof(up->sg_str), "%pSG", sg);
836
55.2k
  if (ch)
837
55.2k
    ch->upstream = up;
838
839
55.2k
  rb_pim_upstream_add(&pim->upstream_head, up);
840
  /* Set up->upstream_addr as INADDR_ANY, if RP is not
841
   * configured and retain the upstream data structure
842
   */
843
55.2k
  if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
844
55.2k
              sg->grp)) {
845
28.6k
    if (PIM_DEBUG_PIM_TRACE)
846
0
      zlog_debug("%s: Received a (*,G) with no RP configured",
847
28.6k
           __func__);
848
28.6k
  }
849
850
55.2k
  up->parent = pim_upstream_find_parent(pim, up);
851
55.2k
  if (pim_addr_is_any(up->sg.src)) {
852
169
    up->sources = list_new();
853
169
    up->sources->cmp =
854
169
      (int (*)(void *, void *))pim_upstream_compare;
855
169
  } else
856
55.1k
    up->sources = NULL;
857
858
55.2k
  pim_upstream_find_new_children(pim, up);
859
55.2k
  up->flags = flags;
860
55.2k
  up->ref_count = 1;
861
55.2k
  up->t_join_timer = NULL;
862
55.2k
  up->t_ka_timer = NULL;
863
55.2k
  up->t_rs_timer = NULL;
864
55.2k
  up->t_msdp_reg_timer = NULL;
865
55.2k
  up->join_state = PIM_UPSTREAM_NOTJOINED;
866
55.2k
  up->reg_state = PIM_REG_NOINFO;
867
55.2k
  up->state_transition = pim_time_monotonic_sec();
868
55.2k
  up->channel_oil = pim_channel_oil_add(pim, &up->sg, __func__);
869
55.2k
  up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
870
871
55.2k
  up->rpf.source_nexthop.interface = NULL;
872
55.2k
  up->rpf.source_nexthop.mrib_nexthop_addr = PIMADDR_ANY;
873
55.2k
  up->rpf.source_nexthop.mrib_metric_preference =
874
55.2k
    router->infinite_assert_metric.metric_preference;
875
55.2k
  up->rpf.source_nexthop.mrib_route_metric =
876
55.2k
    router->infinite_assert_metric.route_metric;
877
55.2k
  up->rpf.rpf_addr = PIMADDR_ANY;
878
55.2k
  up->ifchannels = list_new();
879
55.2k
  up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
880
881
55.2k
  if (!pim_addr_is_any(up->sg.src)) {
882
55.1k
    wheel_add_item(pim->upstream_sg_wheel, up);
883
884
    /* Inherit the DF role from the parent (*, G) entry for
885
     * VxLAN BUM groups
886
     */
887
55.1k
    if (up->parent
888
54.6k
        && PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->parent->flags)
889
0
        && PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->parent->flags)) {
890
0
      PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(up->flags);
891
0
      if (PIM_DEBUG_VXLAN)
892
0
        zlog_debug(
893
0
          "upstream %s inherited mlag non-df flag from parent",
894
0
          up->sg_str);
895
0
    }
896
55.1k
  }
897
898
55.2k
  if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)
899
55.2k
      || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
900
0
    pim_upstream_fill_static_iif(up, incoming);
901
0
    pim_ifp = up->rpf.source_nexthop.interface->info;
902
0
    assert(pim_ifp);
903
0
    pim_upstream_update_use_rpt(up,
904
0
        false /*update_mroute*/);
905
0
    pim_upstream_mroute_iif_update(up->channel_oil, __func__);
906
907
0
    if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags))
908
0
      pim_upstream_keep_alive_timer_start(
909
0
        up, pim->keep_alive_time);
910
55.2k
  } else if (!pim_addr_is_any(up->upstream_addr)) {
911
26.6k
    pim_upstream_update_use_rpt(up,
912
26.6k
        false /*update_mroute*/);
913
26.6k
    rpf_result = pim_rpf_update(pim, up, NULL, __func__);
914
26.6k
    if (rpf_result == PIM_RPF_FAILURE) {
915
26.6k
      if (PIM_DEBUG_PIM_TRACE)
916
0
        zlog_debug(
917
26.6k
          "%s: Attempting to create upstream(%s), Unable to RPF for source",
918
26.6k
          __func__, up->sg_str);
919
26.6k
    }
920
921
    /* Consider a case where (S,G,rpt) prune is received and this
922
     * upstream is getting created due to that, then as per RFC
923
     * until prune pending time we need to behave same as NOINFO
924
     * state, therefore do not install if OIF is NULL until then
925
     * This is for PIM Conformance PIM-SM 16.3 fix
926
     * When the prune pending timer pop, this mroute will get
927
     * installed with none as OIF */
928
26.6k
    if (up->rpf.source_nexthop.interface &&
929
0
        !(pim_upstream_empty_inherited_olist(up) && (ch != NULL) &&
930
0
          PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))) {
931
0
      pim_upstream_mroute_iif_update(up->channel_oil,
932
0
          __func__);
933
0
    }
934
26.6k
  }
935
936
  /* send the entry to the MLAG peer */
937
  /* XXX - duplicate send is possible here if pim_rpf_update
938
   * successfully resolved the nexthop
939
   */
940
55.2k
  if (pim_up_mlag_is_local(up)
941
55.2k
      || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
942
0
    pim_mlag_up_local_add(pim, up);
943
944
55.2k
  if (PIM_DEBUG_PIM_TRACE) {
945
0
    zlog_debug(
946
0
      "%s: Created Upstream %s upstream_addr %pPAs ref count %d increment",
947
0
      __func__, up->sg_str, &up->upstream_addr,
948
0
      up->ref_count);
949
0
  }
950
951
55.2k
  return up;
952
55.2k
}
953
954
uint32_t pim_up_mlag_local_cost(struct pim_upstream *up)
955
282k
{
956
282k
  if (!(pim_up_mlag_is_local(up))
957
282k
      && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
958
282k
    return router->infinite_assert_metric.route_metric;
959
960
0
  if ((up->rpf.source_nexthop.interface ==
961
0
        up->pim->vxlan.peerlink_rif) &&
962
0
      (up->rpf.source_nexthop.mrib_route_metric <
963
0
       (router->infinite_assert_metric.route_metric -
964
0
        PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC)))
965
0
    return up->rpf.source_nexthop.mrib_route_metric +
966
0
      PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC;
967
968
0
  return up->rpf.source_nexthop.mrib_route_metric;
969
0
}
970
971
uint32_t pim_up_mlag_peer_cost(struct pim_upstream *up)
972
0
{
973
0
  if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
974
0
    return router->infinite_assert_metric.route_metric;
975
976
0
  return up->mlag.peer_mrib_metric;
977
0
}
978
979
struct pim_upstream *pim_upstream_find(struct pim_instance *pim, pim_sgaddr *sg)
980
166k
{
981
166k
  struct pim_upstream lookup;
982
166k
  struct pim_upstream *up = NULL;
983
984
166k
  lookup.sg = *sg;
985
166k
  up = rb_pim_upstream_find(&pim->upstream_head, &lookup);
986
166k
  return up;
987
166k
}
988
989
struct pim_upstream *pim_upstream_find_or_add(pim_sgaddr *sg,
990
                struct interface *incoming,
991
                int flags, const char *name)
992
0
{
993
0
  struct pim_interface *pim_ifp = incoming->info;
994
995
0
  return (pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name,
996
0
        NULL));
997
0
}
998
999
void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name)
1000
0
{
1001
  /* if a local MLAG reference is being created we need to send the mroute
1002
   * to the peer
1003
   */
1004
0
  if (!PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->flags) &&
1005
0
      PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags)) {
1006
0
    PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(up->flags);
1007
0
    pim_mlag_up_local_add(up->pim, up);
1008
0
  }
1009
1010
  /* when we go from non-FHR to FHR we need to re-eval traffic
1011
   * forwarding path
1012
   */
1013
0
  if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) &&
1014
0
      PIM_UPSTREAM_FLAG_TEST_FHR(flags)) {
1015
0
    PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1016
0
    pim_upstream_update_use_rpt(up, true /*update_mroute*/);
1017
0
  }
1018
1019
  /* re-eval joinDesired; clearing peer-msdp-sa flag can
1020
   * cause JD to change
1021
   */
1022
0
  if (!PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags) &&
1023
0
      PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags)) {
1024
0
    PIM_UPSTREAM_FLAG_SET_SRC_MSDP(up->flags);
1025
0
    pim_upstream_update_join_desired(up->pim, up);
1026
0
  }
1027
1028
0
  up->flags |= flags;
1029
0
  ++up->ref_count;
1030
0
  if (PIM_DEBUG_PIM_TRACE)
1031
0
    zlog_debug("%s(%s): upstream %s ref count %d increment",
1032
0
         __func__, name, up->sg_str, up->ref_count);
1033
0
}
1034
1035
struct pim_upstream *pim_upstream_add(struct pim_instance *pim, pim_sgaddr *sg,
1036
              struct interface *incoming, int flags,
1037
              const char *name,
1038
              struct pim_ifchannel *ch)
1039
55.2k
{
1040
55.2k
  struct pim_upstream *up = NULL;
1041
55.2k
  int found = 0;
1042
1043
55.2k
  up = pim_upstream_find(pim, sg);
1044
55.2k
  if (up) {
1045
0
    pim_upstream_ref(up, flags, name);
1046
0
    found = 1;
1047
55.2k
  } else {
1048
55.2k
    up = pim_upstream_new(pim, sg, incoming, flags, ch);
1049
55.2k
  }
1050
1051
55.2k
  if (PIM_DEBUG_PIM_TRACE) {
1052
0
    zlog_debug(
1053
0
      "%s(%s): %s, iif %pPA (%s) found: %d: ref_count: %d",
1054
0
      __func__, name, up->sg_str, &up->rpf.rpf_addr,
1055
0
      up->rpf.source_nexthop.interface ? up->rpf.source_nexthop
1056
0
                   .interface->name
1057
0
               : "Unknown",
1058
0
      found, up->ref_count);
1059
0
  }
1060
1061
55.2k
  return up;
1062
55.2k
}
1063
1064
/*
1065
 * Passed in up must be the upstream for ch.  starch is NULL if no
1066
 * information
1067
 * This function is copied over from
1068
 * pim_upstream_evaluate_join_desired_interface but limited to
1069
 * parent (*,G)'s includes/joins.
1070
 */
1071
int pim_upstream_eval_inherit_if(struct pim_upstream *up,
1072
             struct pim_ifchannel *ch,
1073
             struct pim_ifchannel *starch)
1074
3.15k
{
1075
  /* if there is an explicit prune for this interface we cannot
1076
   * add it to the OIL
1077
   */
1078
3.15k
  if (ch) {
1079
3.15k
    if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1080
1.64k
      return 0;
1081
3.15k
  }
1082
1083
  /* Check if the OIF can be inherited fron the (*,G) entry
1084
   */
1085
1.51k
  if (starch) {
1086
1.51k
    if (!pim_macro_ch_lost_assert(starch)
1087
1.51k
        && pim_macro_chisin_joins_or_include(starch))
1088
1.51k
      return 1;
1089
1.51k
  }
1090
1091
0
  return 0;
1092
1.51k
}
1093
1094
/*
1095
 * Passed in up must be the upstream for ch.  starch is NULL if no
1096
 * information
1097
 */
1098
int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
1099
             struct pim_ifchannel *ch,
1100
             struct pim_ifchannel *starch)
1101
118k
{
1102
118k
  if (ch) {
1103
118k
    if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1104
59.0k
      return 0;
1105
1106
59.7k
    if (!pim_macro_ch_lost_assert(ch)
1107
59.7k
        && pim_macro_chisin_joins_or_include(ch))
1108
5.07k
      return 1;
1109
59.7k
  }
1110
1111
  /*
1112
   * joins (*,G)
1113
   */
1114
54.6k
  if (starch) {
1115
    /* XXX: check on this with donald
1116
     * we are looking for PIM_IF_FLAG_MASK_S_G_RPT in
1117
     * upstream flags?
1118
     */
1119
#if 0
1120
    if (PIM_IF_FLAG_TEST_S_G_RPT(starch->upstream->flags))
1121
      return 0;
1122
#endif
1123
1124
54.6k
    if (!pim_macro_ch_lost_assert(starch)
1125
54.6k
        && pim_macro_chisin_joins_or_include(starch))
1126
54.6k
      return 1;
1127
54.6k
  }
1128
1129
52
  return 0;
1130
54.6k
}
1131
1132
/* Returns true if immediate OIL is empty and is used to evaluate
1133
 * JoinDesired. See pim_upstream_evaluate_join_desired.
1134
 */
1135
static bool pim_upstream_empty_immediate_olist(struct pim_instance *pim,
1136
               struct pim_upstream *up)
1137
62.5k
{
1138
62.5k
  struct interface *ifp;
1139
62.5k
  struct pim_ifchannel *ch;
1140
1141
121k
  FOR_ALL_INTERFACES (pim->vrf, ifp) {
1142
121k
    if (!ifp->info)
1143
0
      continue;
1144
1145
121k
    ch = pim_ifchannel_find(ifp, &up->sg);
1146
121k
    if (!ch)
1147
59.0k
      continue;
1148
1149
    /* If we have even one immediate OIF we can return with
1150
     * not-empty
1151
     */
1152
62.5k
    if (pim_upstream_evaluate_join_desired_interface(up, ch,
1153
62.5k
              NULL /* starch */))
1154
3.47k
      return false;
1155
62.5k
  } /* scan iface channel list */
1156
1157
  /* immediate_oil is empty */
1158
59.0k
  return true;
1159
62.5k
}
1160
1161
1162
static inline bool pim_upstream_is_msdp_peer_sa(struct pim_upstream *up)
1163
48
{
1164
48
  return PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags);
1165
48
}
1166
1167
/*
1168
 *   bool JoinDesired(*,G) {
1169
 *       if (immediate_olist(*,G) != NULL)
1170
 *           return TRUE
1171
 *       else
1172
 *           return FALSE
1173
 *   }
1174
 *
1175
 *   bool JoinDesired(S,G) {
1176
 *       return( immediate_olist(S,G) != NULL
1177
 *           OR ( KeepaliveTimer(S,G) is running
1178
 *           AND inherited_olist(S,G) != NULL ) )
1179
 *   }
1180
 */
1181
bool pim_upstream_evaluate_join_desired(struct pim_instance *pim,
1182
               struct pim_upstream *up)
1183
62.5k
{
1184
62.5k
  bool empty_imm_oil;
1185
62.5k
  bool empty_inh_oil;
1186
1187
62.5k
  empty_imm_oil = pim_upstream_empty_immediate_olist(pim, up);
1188
1189
  /* (*,G) */
1190
62.5k
  if (pim_addr_is_any(up->sg.src))
1191
1.50k
    return !empty_imm_oil;
1192
1193
  /* (S,G) */
1194
61.0k
  if (!empty_imm_oil)
1195
2.03k
    return true;
1196
59.0k
  empty_inh_oil = pim_upstream_empty_inherited_olist(up);
1197
59.0k
  if (!empty_inh_oil &&
1198
48
      (pim_upstream_is_kat_running(up) ||
1199
48
       pim_upstream_is_msdp_peer_sa(up)))
1200
0
    return true;
1201
1202
59.0k
  return false;
1203
59.0k
}
1204
1205
/*
1206
  See also pim_upstream_evaluate_join_desired() above.
1207
*/
1208
void pim_upstream_update_join_desired(struct pim_instance *pim,
1209
              struct pim_upstream *up)
1210
62.5k
{
1211
62.5k
  int was_join_desired; /* boolean */
1212
62.5k
  int is_join_desired;  /* boolean */
1213
1214
62.5k
  was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
1215
1216
62.5k
  is_join_desired = pim_upstream_evaluate_join_desired(pim, up);
1217
62.5k
  if (is_join_desired)
1218
3.47k
    PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
1219
59.0k
  else
1220
59.0k
    PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
1221
1222
  /* switched from false to true */
1223
62.5k
  if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) {
1224
3.47k
    pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
1225
3.47k
    return;
1226
3.47k
  }
1227
1228
  /* switched from true to false */
1229
59.0k
  if (!is_join_desired && was_join_desired) {
1230
209
    pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
1231
209
    return;
1232
209
  }
1233
59.0k
}
1234
1235
/*
1236
  RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
1237
  Transitions from Joined State
1238
  RPF'(S,G) GenID changes
1239
1240
  The upstream (S,G) state machine remains in Joined state.  If the
1241
  Join Timer is set to expire in more than t_override seconds, reset
1242
  it so that it expires after t_override seconds.
1243
*/
1244
void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
1245
            pim_addr neigh_addr)
1246
70
{
1247
70
  struct pim_upstream *up;
1248
1249
  /*
1250
   * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1251
   */
1252
5.39k
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1253
5.39k
    pim_addr rpf_addr;
1254
1255
5.39k
    rpf_addr = up->rpf.rpf_addr;
1256
1257
5.39k
    if (PIM_DEBUG_PIM_TRACE)
1258
0
      zlog_debug(
1259
5.39k
        "%s: matching neigh=%pPA against upstream (S,G)=%s[%s] joined=%d rpf_addr=%pPA",
1260
5.39k
        __func__, &neigh_addr, up->sg_str,
1261
5.39k
        pim->vrf->name,
1262
5.39k
        up->join_state == PIM_UPSTREAM_JOINED,
1263
5.39k
        &rpf_addr);
1264
1265
    /* consider only (S,G) upstream in Joined state */
1266
5.39k
    if (up->join_state != PIM_UPSTREAM_JOINED)
1267
5.39k
      continue;
1268
1269
    /* match RPF'(S,G)=neigh_addr */
1270
0
    if (pim_addr_cmp(rpf_addr, neigh_addr))
1271
0
      continue;
1272
1273
0
    pim_upstream_join_timer_decrease_to_t_override(
1274
0
      "RPF'(S,G) GenID change", up);
1275
0
  }
1276
70
}
1277
1278
1279
void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
1280
          struct interface *old_rpf_ifp)
1281
0
{
1282
0
  struct listnode *chnode;
1283
0
  struct listnode *chnextnode;
1284
0
  struct pim_ifchannel *ch;
1285
1286
  /* search all ifchannels */
1287
0
  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1288
0
    if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
1289
0
      if (
1290
        /* RPF_interface(S) was NOT I */
1291
0
        (old_rpf_ifp == ch->interface) &&
1292
        /* RPF_interface(S) stopped being I */
1293
0
        (ch->upstream->rpf.source_nexthop
1294
0
          .interface) &&
1295
0
        (ch->upstream->rpf.source_nexthop
1296
0
          .interface != ch->interface)) {
1297
0
        assert_action_a5(ch);
1298
0
      }
1299
0
    } /* PIM_IFASSERT_I_AM_LOSER */
1300
1301
0
    pim_ifchannel_update_assert_tracking_desired(ch);
1302
0
  }
1303
0
}
1304
1305
void pim_upstream_update_could_assert(struct pim_upstream *up)
1306
0
{
1307
0
  struct listnode *chnode;
1308
0
  struct listnode *chnextnode;
1309
0
  struct pim_ifchannel *ch;
1310
1311
  /* scan per-interface (S,G) state */
1312
0
  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1313
0
    pim_ifchannel_update_could_assert(ch);
1314
0
  } /* scan iface channel list */
1315
0
}
1316
1317
void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
1318
0
{
1319
0
  struct listnode *chnode;
1320
0
  struct listnode *chnextnode;
1321
0
  struct pim_ifchannel *ch;
1322
1323
  /* scan per-interface (S,G) state */
1324
0
  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1325
0
    pim_ifchannel_update_my_assert_metric(ch);
1326
1327
0
  } /* scan iface channel list */
1328
0
}
1329
1330
static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
1331
0
{
1332
0
  struct listnode *chnode;
1333
0
  struct listnode *chnextnode;
1334
0
  struct pim_interface *pim_ifp;
1335
0
  struct pim_ifchannel *ch;
1336
1337
  /* scan per-interface (S,G) state */
1338
0
  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1339
0
    if (!ch->interface)
1340
0
      continue;
1341
0
    pim_ifp = ch->interface->info;
1342
0
    if (!pim_ifp)
1343
0
      continue;
1344
1345
0
    pim_ifchannel_update_assert_tracking_desired(ch);
1346
1347
0
  } /* scan iface channel list */
1348
0
}
1349
1350
/* When kat is stopped CouldRegister goes to false so we need to
1351
 * transition  the (S, G) on FHR to NI state and remove reg tunnel
1352
 * from the OIL */
1353
static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim,
1354
          struct pim_upstream *up)
1355
0
{
1356
0
  if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
1357
0
    return;
1358
1359
0
  if (PIM_DEBUG_PIM_TRACE)
1360
0
    zlog_debug("kat expired on %s; clear fhr reg state",
1361
0
         up->sg_str);
1362
1363
  /* stop reg-stop timer */
1364
0
  EVENT_OFF(up->t_rs_timer);
1365
  /* remove regiface from the OIL if it is there*/
1366
0
  pim_channel_del_oif(up->channel_oil, pim->regiface,
1367
0
          PIM_OIF_FLAG_PROTO_PIM, __func__);
1368
  /* clear the register state */
1369
0
  up->reg_state = PIM_REG_NOINFO;
1370
0
  PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
1371
0
}
1372
1373
/* When kat is started CouldRegister can go to true. And if it does we
1374
 * need to transition  the (S, G) on FHR to JOINED state and add reg tunnel
1375
 * to the OIL */
1376
static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
1377
0
{
1378
0
  if (pim_upstream_could_register(up)) {
1379
0
    if (PIM_DEBUG_PIM_TRACE)
1380
0
      zlog_debug(
1381
0
        "kat started on %s; set fhr reg state to joined",
1382
0
        up->sg_str);
1383
1384
0
    PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1385
0
    if (up->reg_state == PIM_REG_NOINFO)
1386
0
      pim_register_join(up);
1387
0
    pim_upstream_update_use_rpt(up, true /*update_mroute*/);
1388
0
  }
1389
0
}
1390
1391
/*
1392
 * On an RP, the PMBR value must be cleared when the
1393
 * Keepalive Timer expires
1394
 * KAT expiry indicates that flow is inactive. If the flow was created or
1395
 * maintained by activity now is the time to deref it.
1396
 */
1397
struct pim_upstream *pim_upstream_keep_alive_timer_proc(
1398
    struct pim_upstream *up)
1399
0
{
1400
0
  struct pim_instance *pim;
1401
1402
0
  pim = up->channel_oil->pim;
1403
1404
0
  if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up->flags)) {
1405
    /* if the router is a PIM vxlan encapsulator we prevent expiry
1406
     * of KAT as the mroute is pre-setup without any traffic
1407
     */
1408
0
    pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
1409
0
    return up;
1410
0
  }
1411
1412
0
  if (I_am_RP(pim, up->sg.grp)) {
1413
    /*
1414
     * Handle Border Router
1415
     * We need to do more here :)
1416
     * But this is the start.
1417
     */
1418
0
  }
1419
1420
  /* source is no longer active - pull the SA from MSDP's cache */
1421
0
  pim_msdp_sa_local_del(pim, &up->sg);
1422
1423
  /* JoinDesired can change when KAT is started or stopped */
1424
0
  pim_upstream_update_join_desired(pim, up);
1425
1426
  /* if entry was created because of activity we need to deref it */
1427
0
  if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1428
0
    pim_upstream_fhr_kat_expiry(pim, up);
1429
0
    if (PIM_DEBUG_PIM_TRACE)
1430
0
      zlog_debug(
1431
0
        "kat expired on %s[%s]; remove stream reference",
1432
0
        up->sg_str, pim->vrf->name);
1433
0
    PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
1434
1435
    /* Return if upstream entry got deleted.*/
1436
0
    if (!pim_upstream_del(pim, up, __func__))
1437
0
      return NULL;
1438
0
  }
1439
0
  if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
1440
0
    PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up->flags);
1441
1442
0
    if (!pim_upstream_del(pim, up, __func__))
1443
0
      return NULL;
1444
0
  }
1445
1446
  /* upstream reference would have been added to track the local
1447
   * membership if it is LHR. We have to clear it when KAT expires.
1448
   * Otherwise would result in stale entry with uncleared ref count.
1449
   */
1450
0
  if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
1451
0
    struct pim_upstream *parent = up->parent;
1452
1453
0
    PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
1454
0
    up = pim_upstream_del(pim, up, __func__);
1455
1456
0
    if (parent) {
1457
0
      pim_jp_agg_single_upstream_send(&parent->rpf, parent,
1458
0
              true);
1459
0
    }
1460
0
  }
1461
1462
0
  return up;
1463
0
}
1464
static void pim_upstream_keep_alive_timer(struct event *t)
1465
0
{
1466
0
  struct pim_upstream *up;
1467
0
1468
0
  up = EVENT_ARG(t);
1469
0
1470
0
  /* pull the stats and re-check */
1471
0
  if (pim_upstream_sg_running_proc(up))
1472
0
    /* kat was restarted because of new activity */
1473
0
    return;
1474
0
1475
0
  pim_upstream_keep_alive_timer_proc(up);
1476
0
}
1477
1478
void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time)
1479
0
{
1480
0
  if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1481
0
    if (PIM_DEBUG_PIM_TRACE)
1482
0
      zlog_debug("kat start on %s with no stream reference",
1483
0
           up->sg_str);
1484
0
  }
1485
0
  EVENT_OFF(up->t_ka_timer);
1486
0
  event_add_timer(router->master, pim_upstream_keep_alive_timer, up, time,
1487
0
      &up->t_ka_timer);
1488
1489
  /* any time keepalive is started against a SG we will have to
1490
   * re-evaluate our active source database */
1491
0
  pim_msdp_sa_local_update(up);
1492
  /* JoinDesired can change when KAT is started or stopped */
1493
0
  pim_upstream_update_join_desired(up->pim, up);
1494
0
}
1495
1496
/* MSDP on RP needs to know if a source is registerable to this RP */
1497
static void pim_upstream_msdp_reg_timer(struct event *t)
1498
0
{
1499
0
  struct pim_upstream *up = EVENT_ARG(t);
1500
0
  struct pim_instance *pim = up->channel_oil->pim;
1501
0
1502
0
  /* source is no longer active - pull the SA from MSDP's cache */
1503
0
  pim_msdp_sa_local_del(pim, &up->sg);
1504
0
}
1505
1506
void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1507
0
{
1508
0
  EVENT_OFF(up->t_msdp_reg_timer);
1509
0
  event_add_timer(router->master, pim_upstream_msdp_reg_timer, up,
1510
0
      PIM_MSDP_REG_RXED_PERIOD, &up->t_msdp_reg_timer);
1511
1512
0
  pim_msdp_sa_local_update(up);
1513
0
}
1514
1515
/*
1516
 * 4.2.1 Last-Hop Switchover to the SPT
1517
 *
1518
 *  In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1519
 *  RP.  Once traffic from sources to joined groups arrives at a last-hop
1520
 *  router, it has the option of switching to receive the traffic on a
1521
 *  shortest path tree (SPT).
1522
 *
1523
 *  The decision for a router to switch to the SPT is controlled as
1524
 *  follows:
1525
 *
1526
 *    void
1527
 *    CheckSwitchToSpt(S,G) {
1528
 *      if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1529
 *             (+) pim_include(S,G) != NULL )
1530
 *           AND SwitchToSptDesired(S,G) ) {
1531
 *             # Note: Restarting the KAT will result in the SPT switch
1532
 *             set KeepaliveTimer(S,G) to Keepalive_Period
1533
 *      }
1534
 *    }
1535
 *
1536
 *  SwitchToSptDesired(S,G) is a policy function that is implementation
1537
 *  defined.  An "infinite threshold" policy can be implemented by making
1538
 *  SwitchToSptDesired(S,G) return false all the time.  A "switch on
1539
 *  first packet" policy can be implemented by making
1540
 *  SwitchToSptDesired(S,G) return true once a single packet has been
1541
 *  received for the source and group.
1542
 */
1543
int pim_upstream_switch_to_spt_desired_on_rp(struct pim_instance *pim,
1544
               pim_sgaddr *sg)
1545
0
{
1546
0
  if (I_am_RP(pim, sg->grp))
1547
0
    return 1;
1548
1549
0
  return 0;
1550
0
}
1551
1552
int pim_upstream_is_sg_rpt(struct pim_upstream *up)
1553
0
{
1554
0
  struct listnode *chnode;
1555
0
  struct pim_ifchannel *ch;
1556
1557
0
  for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) {
1558
0
    if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1559
0
      return 1;
1560
0
  }
1561
1562
0
  return 0;
1563
0
}
1564
/*
1565
 *  After receiving a packet set SPTbit:
1566
 *   void
1567
 *   Update_SPTbit(S,G,iif) {
1568
 *     if ( iif == RPF_interface(S)
1569
 *           AND JoinDesired(S,G) == true
1570
 *           AND ( DirectlyConnected(S) == true
1571
 *                 OR RPF_interface(S) != RPF_interface(RP(G))
1572
 *                 OR inherited_olist(S,G,rpt) == NULL
1573
 *                 OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1574
 *                      ( RPF'(S,G) != NULL ) )
1575
 *                 OR ( I_Am_Assert_Loser(S,G,iif) ) {
1576
 *        Set SPTbit(S,G) to true
1577
 *     }
1578
 *   }
1579
 */
1580
void pim_upstream_set_sptbit(struct pim_upstream *up,
1581
           struct interface *incoming)
1582
0
{
1583
0
  struct pim_upstream *starup = up->parent;
1584
1585
  // iif == RPF_interfvace(S)
1586
0
  if (up->rpf.source_nexthop.interface != incoming) {
1587
0
    if (PIM_DEBUG_PIM_TRACE)
1588
0
      zlog_debug(
1589
0
        "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1590
0
        __func__, incoming->name,
1591
0
        up->rpf.source_nexthop.interface->name);
1592
0
    return;
1593
0
  }
1594
1595
  // AND JoinDesired(S,G) == true
1596
0
  if (!pim_upstream_evaluate_join_desired(up->channel_oil->pim, up)) {
1597
0
    if (PIM_DEBUG_PIM_TRACE)
1598
0
      zlog_debug("%s: %s Join is not Desired", __func__,
1599
0
           up->sg_str);
1600
0
    return;
1601
0
  }
1602
1603
  // DirectlyConnected(S) == true
1604
0
  if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1605
0
               up->sg.src)) {
1606
0
    if (PIM_DEBUG_PIM_TRACE)
1607
0
      zlog_debug("%s: %s is directly connected to the source",
1608
0
           __func__, up->sg_str);
1609
0
    up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1610
0
    return;
1611
0
  }
1612
1613
  // OR RPF_interface(S) != RPF_interface(RP(G))
1614
0
  if (!starup
1615
0
      || up->rpf.source_nexthop
1616
0
             .interface != starup->rpf.source_nexthop.interface) {
1617
0
    struct pim_upstream *starup = up->parent;
1618
1619
0
    if (PIM_DEBUG_PIM_TRACE)
1620
0
      zlog_debug(
1621
0
        "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1622
0
        __func__, up->sg_str);
1623
0
    up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1624
1625
0
    pim_jp_agg_single_upstream_send(&starup->rpf, starup, true);
1626
0
    return;
1627
0
  }
1628
1629
  // OR inherited_olist(S,G,rpt) == NULL
1630
0
  if (pim_upstream_is_sg_rpt(up)
1631
0
      && pim_upstream_empty_inherited_olist(up)) {
1632
0
    if (PIM_DEBUG_PIM_TRACE)
1633
0
      zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1634
0
           __func__, up->sg_str);
1635
0
    up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1636
0
    return;
1637
0
  }
1638
1639
  // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1640
  //      ( RPF'(S,G) != NULL ) )
1641
0
  if (up->parent && pim_rpf_is_same(&up->rpf, &up->parent->rpf)) {
1642
0
    if (PIM_DEBUG_PIM_TRACE)
1643
0
      zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1644
0
           __func__, up->sg_str);
1645
0
    up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1646
0
    return;
1647
0
  }
1648
1649
0
  return;
1650
0
}
1651
1652
const char *pim_upstream_state2str(enum pim_upstream_state join_state)
1653
0
{
1654
0
  switch (join_state) {
1655
0
  case PIM_UPSTREAM_NOTJOINED:
1656
0
    return "NotJoined";
1657
0
  case PIM_UPSTREAM_JOINED:
1658
0
    return "Joined";
1659
0
  }
1660
0
  return "Unknown";
1661
0
}
1662
1663
const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str,
1664
            size_t state_str_len)
1665
0
{
1666
0
  switch (reg_state) {
1667
0
  case PIM_REG_NOINFO:
1668
0
    strlcpy(state_str, "RegNoInfo", state_str_len);
1669
0
    break;
1670
0
  case PIM_REG_JOIN:
1671
0
    strlcpy(state_str, "RegJoined", state_str_len);
1672
0
    break;
1673
0
  case PIM_REG_JOIN_PENDING:
1674
0
    strlcpy(state_str, "RegJoinPend", state_str_len);
1675
0
    break;
1676
0
  case PIM_REG_PRUNE:
1677
0
    strlcpy(state_str, "RegPrune", state_str_len);
1678
0
    break;
1679
0
  }
1680
0
  return state_str;
1681
0
}
1682
1683
static void pim_upstream_register_stop_timer(struct event *t)
1684
0
{
1685
0
  struct pim_interface *pim_ifp;
1686
0
  struct pim_instance *pim;
1687
0
  struct pim_upstream *up;
1688
0
  up = EVENT_ARG(t);
1689
0
  pim = up->channel_oil->pim;
1690
0
1691
0
  if (PIM_DEBUG_PIM_TRACE) {
1692
0
    char state_str[PIM_REG_STATE_STR_LEN];
1693
0
    zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1694
0
         __func__, up->sg_str, pim->vrf->name,
1695
0
         pim_reg_state2str(up->reg_state, state_str,
1696
0
               sizeof(state_str)));
1697
0
  }
1698
0
1699
0
  switch (up->reg_state) {
1700
0
  case PIM_REG_JOIN_PENDING:
1701
0
    up->reg_state = PIM_REG_JOIN;
1702
0
    pim_channel_add_oif(up->channel_oil, pim->regiface,
1703
0
            PIM_OIF_FLAG_PROTO_PIM,
1704
0
          __func__);
1705
0
    pim_vxlan_update_sg_reg_state(pim, up, true /*reg_join*/);
1706
0
    break;
1707
0
  case PIM_REG_JOIN:
1708
0
    break;
1709
0
  case PIM_REG_PRUNE:
1710
0
    /* This is equalent to Couldreg -> False */
1711
0
    if (!up->rpf.source_nexthop.interface) {
1712
0
      if (PIM_DEBUG_PIM_TRACE)
1713
0
        zlog_debug("%s: up %s RPF is not present",
1714
0
             __func__, up->sg_str);
1715
0
      up->reg_state = PIM_REG_NOINFO;
1716
0
      return;
1717
0
    }
1718
0
1719
0
    pim_ifp = up->rpf.source_nexthop.interface->info;
1720
0
    if (!pim_ifp) {
1721
0
      if (PIM_DEBUG_PIM_TRACE)
1722
0
        zlog_debug(
1723
0
          "%s: Interface: %s is not configured for pim",
1724
0
          __func__,
1725
0
          up->rpf.source_nexthop.interface->name);
1726
0
      return;
1727
0
    }
1728
0
    up->reg_state = PIM_REG_JOIN_PENDING;
1729
0
    pim_upstream_start_register_stop_timer(up, 1);
1730
0
1731
0
    if (((up->channel_oil->cc.lastused / 100)
1732
0
         > pim->keep_alive_time)
1733
0
        && (I_am_RP(pim_ifp->pim, up->sg.grp))) {
1734
0
      if (PIM_DEBUG_PIM_TRACE)
1735
0
        zlog_debug(
1736
0
          "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1737
0
          __func__);
1738
0
      return;
1739
0
    }
1740
0
    pim_null_register_send(up);
1741
0
    break;
1742
0
  case PIM_REG_NOINFO:
1743
0
    break;
1744
0
  }
1745
0
}
1746
1747
void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
1748
              int null_register)
1749
0
{
1750
0
  uint32_t time;
1751
1752
0
  EVENT_OFF(up->t_rs_timer);
1753
1754
0
  if (!null_register) {
1755
0
    uint32_t lower = (0.5 * router->register_suppress_time);
1756
0
    uint32_t upper = (1.5 * router->register_suppress_time);
1757
0
    time = lower + (frr_weak_random() % (upper - lower + 1));
1758
    /* Make sure we don't wrap around */
1759
0
    if (time >= router->register_probe_time)
1760
0
      time -= router->register_probe_time;
1761
0
    else
1762
0
      time = 0;
1763
0
  } else
1764
0
    time = router->register_probe_time;
1765
1766
0
  if (PIM_DEBUG_PIM_TRACE) {
1767
0
    zlog_debug(
1768
0
      "%s: (S,G)=%s Starting upstream register stop timer %d",
1769
0
      __func__, up->sg_str, time);
1770
0
  }
1771
0
  event_add_timer(router->master, pim_upstream_register_stop_timer, up,
1772
0
      time, &up->t_rs_timer);
1773
0
}
1774
1775
int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
1776
          struct pim_upstream *up)
1777
0
{
1778
0
  struct interface *ifp;
1779
0
  struct pim_ifchannel *ch, *starch;
1780
0
  struct pim_upstream *starup = up->parent;
1781
0
  int output_intf = 0;
1782
1783
0
  if (!up->rpf.source_nexthop.interface)
1784
0
    if (PIM_DEBUG_PIM_TRACE)
1785
0
      zlog_debug("%s: up %s RPF is not present", __func__,
1786
0
           up->sg_str);
1787
1788
0
  FOR_ALL_INTERFACES (pim->vrf, ifp) {
1789
0
    struct pim_interface *pim_ifp;
1790
0
    if (!ifp->info)
1791
0
      continue;
1792
1793
0
    ch = pim_ifchannel_find(ifp, &up->sg);
1794
1795
0
    if (starup)
1796
0
      starch = pim_ifchannel_find(ifp, &starup->sg);
1797
0
    else
1798
0
      starch = NULL;
1799
1800
0
    if (!ch && !starch)
1801
0
      continue;
1802
1803
0
    pim_ifp = ifp->info;
1804
0
    if (PIM_I_am_DualActive(pim_ifp)
1805
0
        && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)
1806
0
        && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
1807
0
      || !PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags)))
1808
0
      continue;
1809
0
    if (pim_upstream_evaluate_join_desired_interface(up, ch,
1810
0
                 starch)) {
1811
0
      int flag = 0;
1812
1813
0
      if (!ch)
1814
0
        flag = PIM_OIF_FLAG_PROTO_STAR;
1815
0
      else {
1816
0
        if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
1817
0
          flag = PIM_OIF_FLAG_PROTO_GM;
1818
0
        if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
1819
0
          flag |= PIM_OIF_FLAG_PROTO_PIM;
1820
0
        if (starch)
1821
0
          flag |= PIM_OIF_FLAG_PROTO_STAR;
1822
0
      }
1823
1824
0
      pim_channel_add_oif(up->channel_oil, ifp, flag,
1825
0
          __func__);
1826
0
      output_intf++;
1827
0
    }
1828
0
  }
1829
1830
0
  return output_intf;
1831
0
}
1832
1833
/*
1834
 * For a given upstream, determine the inherited_olist
1835
 * and apply it.
1836
 *
1837
 * inherited_olist(S,G,rpt) =
1838
 *           ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1839
 *      (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1840
 *      (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1841
 *
1842
 *  inherited_olist(S,G) =
1843
 *      inherited_olist(S,G,rpt) (+)
1844
 *      joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1845
 *
1846
 * return 1 if there are any output interfaces
1847
 * return 0 if there are not any output interfaces
1848
 */
1849
int pim_upstream_inherited_olist(struct pim_instance *pim,
1850
         struct pim_upstream *up)
1851
0
{
1852
0
  int output_intf = pim_upstream_inherited_olist_decide(pim, up);
1853
1854
  /*
1855
   * If we have output_intf switch state to Join and work like normal
1856
   * If we don't have an output_intf that means we are probably a
1857
   * switch on a stick so turn on forwarding to just accept the
1858
   * incoming packets so we don't bother the other stuff!
1859
   */
1860
0
  pim_upstream_update_join_desired(pim, up);
1861
1862
0
  if (!output_intf)
1863
0
    forward_on(up);
1864
1865
0
  return output_intf;
1866
0
}
1867
1868
int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
1869
63.3k
{
1870
63.3k
  return pim_channel_oil_empty(up->channel_oil);
1871
63.3k
}
1872
1873
/*
1874
 * When we have a new neighbor,
1875
 * find upstreams that don't have their rpf_addr
1876
 * set and see if the new neighbor allows
1877
 * the join to be sent
1878
 */
1879
void pim_upstream_find_new_rpf(struct pim_instance *pim)
1880
212
{
1881
212
  struct pim_upstream *up;
1882
212
  struct pim_rpf old;
1883
212
  enum pim_rpf_result rpf_result;
1884
1885
  /*
1886
   * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1887
   */
1888
18.8k
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1889
18.8k
    if (pim_addr_is_any(up->upstream_addr)) {
1890
8.84k
      if (PIM_DEBUG_PIM_TRACE)
1891
0
        zlog_debug(
1892
8.84k
          "%s: RP not configured for Upstream %s",
1893
8.84k
          __func__, up->sg_str);
1894
8.84k
      continue;
1895
8.84k
    }
1896
1897
9.97k
    if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
1898
9.97k
      if (PIM_DEBUG_PIM_TRACE)
1899
0
        zlog_debug(
1900
9.97k
          "%s: Upstream %s without a path to send join, checking",
1901
9.97k
          __func__, up->sg_str);
1902
9.97k
      old.source_nexthop.interface =
1903
9.97k
        up->rpf.source_nexthop.interface;
1904
9.97k
      rpf_result = pim_rpf_update(pim, up, &old, __func__);
1905
9.97k
      if (rpf_result == PIM_RPF_CHANGED ||
1906
9.97k
          (rpf_result == PIM_RPF_FAILURE &&
1907
9.97k
           old.source_nexthop.interface))
1908
0
        pim_zebra_upstream_rpf_changed(pim, up, &old);
1909
      /* update kernel multicast forwarding cache (MFC) */
1910
9.97k
      pim_upstream_mroute_iif_update(up->channel_oil,
1911
9.97k
          __func__);
1912
9.97k
    }
1913
9.97k
  }
1914
212
  pim_zebra_update_all_interfaces(pim);
1915
212
}
1916
1917
unsigned int pim_upstream_hash_key(const void *arg)
1918
402k
{
1919
402k
  const struct pim_upstream *up = arg;
1920
1921
402k
  return pim_sgaddr_hash(up->sg, 0);
1922
402k
}
1923
1924
void pim_upstream_terminate(struct pim_instance *pim)
1925
0
{
1926
0
  struct pim_upstream *up;
1927
1928
0
  while ((up = rb_pim_upstream_first(&pim->upstream_head))) {
1929
0
    if (pim_upstream_del(pim, up, __func__))
1930
0
      pim_upstream_timers_stop(up);
1931
0
  }
1932
1933
0
  rb_pim_upstream_fini(&pim->upstream_head);
1934
1935
0
  if (pim->upstream_sg_wheel)
1936
0
    wheel_delete(pim->upstream_sg_wheel);
1937
0
  pim->upstream_sg_wheel = NULL;
1938
0
}
1939
1940
bool pim_upstream_equal(const void *arg1, const void *arg2)
1941
140k
{
1942
140k
  const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1943
140k
  const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1944
1945
140k
  return !pim_sgaddr_cmp(up1->sg, up2->sg);
1946
140k
}
1947
1948
/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1949
 * the cases where kat has to be restarted on rxing traffic -
1950
 *
1951
 * if( DirectlyConnected(S) == true AND iif == RPF_interface(S) ) {
1952
 * set KeepaliveTimer(S,G) to Keepalive_Period
1953
 * # Note: a register state transition or UpstreamJPState(S,G)
1954
 * # transition may happen as a result of restarting
1955
 * # KeepaliveTimer, and must be dealt with here.
1956
 * }
1957
 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1958
 * inherited_olist(S,G) != NULL ) {
1959
 * set KeepaliveTimer(S,G) to Keepalive_Period
1960
 * }
1961
 */
1962
static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1963
0
{
1964
0
  struct channel_oil *c_oil = up->channel_oil;
1965
0
  struct interface *ifp = up->rpf.source_nexthop.interface;
1966
0
  struct pim_interface *pim_ifp;
1967
1968
  /* "iif == RPF_interface(S)" check is not easy to do as the info
1969
   * we get from the kernel/ASIC is really a "lookup/key hit".
1970
   * So we will do an approximate check here to avoid starting KAT
1971
   * because of (S,G,rpt) forwarding on a non-LHR.
1972
   */
1973
0
  if (!ifp)
1974
0
    return false;
1975
1976
0
  pim_ifp = ifp->info;
1977
0
  if (pim_ifp->mroute_vif_index != *oil_parent(c_oil))
1978
0
    return false;
1979
1980
0
  if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1981
0
               up->sg.src)) {
1982
0
    return true;
1983
0
  }
1984
1985
0
  if ((up->join_state == PIM_UPSTREAM_JOINED)
1986
0
      && !pim_upstream_empty_inherited_olist(up)) {
1987
0
    return true;
1988
0
  }
1989
1990
0
  return false;
1991
0
}
1992
1993
static bool pim_upstream_sg_running_proc(struct pim_upstream *up)
1994
0
{
1995
0
  bool rv = false;
1996
0
  struct pim_instance *pim = up->pim;
1997
1998
0
  if (!up->channel_oil->installed)
1999
0
    return rv;
2000
2001
0
  pim_mroute_update_counters(up->channel_oil);
2002
2003
  // Have we seen packets?
2004
0
  if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
2005
0
      && (up->channel_oil->cc.lastused / 100 > 30)) {
2006
0
    if (PIM_DEBUG_PIM_TRACE) {
2007
0
      zlog_debug(
2008
0
        "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
2009
0
        __func__, up->sg_str, pim->vrf->name,
2010
0
        up->channel_oil->cc.oldpktcnt,
2011
0
        up->channel_oil->cc.pktcnt,
2012
0
        up->channel_oil->cc.lastused / 100);
2013
0
    }
2014
0
    return rv;
2015
0
  }
2016
2017
0
  if (pim_upstream_kat_start_ok(up)) {
2018
    /* Add a source reference to the stream if
2019
     * one doesn't already exist */
2020
0
    if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
2021
0
      if (PIM_DEBUG_PIM_TRACE)
2022
0
        zlog_debug(
2023
0
          "source reference created on kat restart %s[%s]",
2024
0
          up->sg_str, pim->vrf->name);
2025
2026
0
      pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
2027
0
           __func__);
2028
0
      PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
2029
0
      pim_upstream_fhr_kat_start(up);
2030
0
    }
2031
0
    pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
2032
0
    rv = true;
2033
0
  } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
2034
0
    pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
2035
0
    rv = true;
2036
0
  }
2037
2038
0
  if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) &&
2039
0
      (up->rpf.source_nexthop.interface)) {
2040
0
    pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
2041
0
    pim_upstream_update_could_assert(up);
2042
0
  }
2043
2044
0
  return rv;
2045
0
}
2046
2047
/*
2048
 * Code to check and see if we've received packets on a S,G mroute
2049
 * and if so to set the SPT bit appropriately
2050
 */
2051
static void pim_upstream_sg_running(void *arg)
2052
0
{
2053
0
  struct pim_upstream *up = (struct pim_upstream *)arg;
2054
0
  struct pim_instance *pim = up->channel_oil->pim;
2055
2056
  // No packet can have arrived here if this is the case
2057
0
  if (!up->channel_oil->installed) {
2058
0
    if (PIM_DEBUG_TRACE)
2059
0
      zlog_debug("%s: %s%s is not installed in mroute",
2060
0
           __func__, up->sg_str, pim->vrf->name);
2061
0
    return;
2062
0
  }
2063
2064
  /*
2065
   * This is a bit of a hack
2066
   * We've noted that we should rescan but
2067
   * we've missed the window for doing so in
2068
   * pim_zebra.c for some reason.  I am
2069
   * only doing this at this point in time
2070
   * to get us up and working for the moment
2071
   */
2072
0
  if (up->channel_oil->oil_inherited_rescan) {
2073
0
    if (PIM_DEBUG_TRACE)
2074
0
      zlog_debug(
2075
0
        "%s: Handling unscanned inherited_olist for %s[%s]",
2076
0
        __func__, up->sg_str, pim->vrf->name);
2077
0
    pim_upstream_inherited_olist_decide(pim, up);
2078
0
    up->channel_oil->oil_inherited_rescan = 0;
2079
0
  }
2080
2081
0
  pim_upstream_sg_running_proc(up);
2082
0
}
2083
2084
void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim)
2085
0
{
2086
0
  struct pim_upstream *up;
2087
2088
0
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2089
0
    if (!pim_addr_is_any(up->sg.src))
2090
0
      continue;
2091
2092
0
    if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags))
2093
0
      continue;
2094
2095
0
    pim_channel_add_oif(up->channel_oil, pim->regiface,
2096
0
            PIM_OIF_FLAG_PROTO_GM, __func__);
2097
0
  }
2098
0
}
2099
2100
void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
2101
           struct prefix_list *pl)
2102
0
{
2103
0
  const char *pname = prefix_list_name(pl);
2104
2105
0
  if (pim->spt.plist && strcmp(pim->spt.plist, pname) == 0) {
2106
0
    pim_upstream_remove_lhr_star_pimreg(pim, pname);
2107
0
  }
2108
0
}
2109
2110
/*
2111
 * nlist -> The new prefix list
2112
 *
2113
 * Per Group Application of pimreg to the OIL
2114
 * If the prefix list tells us DENY then
2115
 * we need to Switchover to SPT immediate
2116
 * so add the pimreg.
2117
 * If the prefix list tells us to ACCEPT than
2118
 * we need to Never do the SPT so remove
2119
 * the interface
2120
 *
2121
 */
2122
void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
2123
           const char *nlist)
2124
0
{
2125
0
  struct pim_upstream *up;
2126
0
  struct prefix_list *np;
2127
0
  struct prefix g;
2128
0
  enum prefix_list_type apply_new;
2129
2130
0
  np = prefix_list_lookup(PIM_AFI, nlist);
2131
2132
0
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2133
0
    if (!pim_addr_is_any(up->sg.src))
2134
0
      continue;
2135
2136
0
    if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags))
2137
0
      continue;
2138
2139
0
    if (!nlist) {
2140
0
      pim_channel_del_oif(up->channel_oil, pim->regiface,
2141
0
              PIM_OIF_FLAG_PROTO_GM, __func__);
2142
0
      continue;
2143
0
    }
2144
0
    pim_addr_to_prefix(&g, up->sg.grp);
2145
0
    apply_new = prefix_list_apply_ext(np, NULL, &g, true);
2146
0
    if (apply_new == PREFIX_DENY)
2147
0
      pim_channel_add_oif(up->channel_oil, pim->regiface,
2148
0
              PIM_OIF_FLAG_PROTO_GM, __func__);
2149
0
    else
2150
0
      pim_channel_del_oif(up->channel_oil, pim->regiface,
2151
0
              PIM_OIF_FLAG_PROTO_GM, __func__);
2152
0
  }
2153
0
}
2154
2155
void pim_upstream_init(struct pim_instance *pim)
2156
1
{
2157
1
  char name[64];
2158
2159
1
  snprintf(name, sizeof(name), "PIM %s Timer Wheel", pim->vrf->name);
2160
1
  pim->upstream_sg_wheel =
2161
1
    wheel_init(router->master, 31000, 100, pim_upstream_hash_key,
2162
1
         pim_upstream_sg_running, name);
2163
2164
1
  rb_pim_upstream_init(&pim->upstream_head);
2165
1
}