Coverage Report

Created: 2026-01-01 06:18

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
50.9k
{
57
50.9k
  struct pim_upstream *child;
58
59
50.9k
  if (!up->sources)
60
50.9k
    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
51.5k
{
88
51.5k
  struct pim_upstream *child;
89
90
51.5k
  if (!pim_addr_is_any(up->sg.src) && !pim_addr_is_any(up->sg.grp))
91
51.3k
    return;
92
93
212
  if (pim_addr_is_any(up->sg.src) && pim_addr_is_any(up->sg.grp))
94
1
    return;
95
96
73.1k
  frr_each (rb_pim_upstream, &pim->upstream_head, child) {
97
73.1k
    if (!pim_addr_is_any(up->sg.grp) &&
98
58.7k
        !pim_addr_cmp(child->sg.grp, up->sg.grp) && (child != up)) {
99
211
      child->parent = up;
100
211
      listnode_add_sort(up->sources, child);
101
211
      if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
102
128
        pim_upstream_mroute_iif_update(
103
128
            child->channel_oil,
104
128
            __func__);
105
211
    }
106
73.1k
  }
107
211
}
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
51.5k
{
117
51.5k
  pim_sgaddr any = child->sg;
118
51.5k
  struct pim_upstream *up = NULL;
119
120
  // (S,G)
121
51.5k
  if (!pim_addr_is_any(child->sg.src) &&
122
51.4k
      !pim_addr_is_any(child->sg.grp)) {
123
51.3k
    any.src = PIMADDR_ANY;
124
51.3k
    up = pim_upstream_find(pim, &any);
125
126
51.3k
    if (up)
127
50.9k
      listnode_add(up->sources, child);
128
129
    /*
130
     * In case parent is MLAG entry copy the data to child
131
     */
132
51.3k
    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
51.3k
    return up;
142
51.3k
  }
143
144
212
  return NULL;
145
51.5k
}
146
147
static void upstream_channel_oil_detach(struct pim_upstream *up)
148
50.9k
{
149
50.9k
  struct channel_oil *channel_oil = up->channel_oil;
150
151
50.9k
  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
50.9k
    channel_oil->up = NULL;
156
50.9k
    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
50.9k
    pim_channel_oil_upstream_deref(channel_oil);
163
50.9k
  }
164
165
50.9k
}
166
167
static void pim_upstream_timers_stop(struct pim_upstream *up)
168
50.9k
{
169
50.9k
  EVENT_OFF(up->t_ka_timer);
170
50.9k
  EVENT_OFF(up->t_rs_timer);
171
50.9k
  EVENT_OFF(up->t_msdp_reg_timer);
172
50.9k
  EVENT_OFF(up->t_join_timer);
173
50.9k
}
174
175
struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
176
              struct pim_upstream *up, const char *name)
177
50.9k
{
178
50.9k
  struct listnode *node, *nnode;
179
50.9k
  struct pim_ifchannel *ch;
180
50.9k
  bool notify_msdp = false;
181
182
50.9k
  if (PIM_DEBUG_PIM_TRACE)
183
0
    zlog_debug(
184
50.9k
      "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
185
50.9k
      __func__, name, up->sg_str, pim->vrf->name,
186
50.9k
      up->ref_count, up->flags,
187
50.9k
      up->channel_oil->oil_ref_count);
188
189
50.9k
   assert(up->ref_count > 0);
190
191
50.9k
  --up->ref_count;
192
193
50.9k
  if (up->ref_count >= 1)
194
0
    return up;
195
196
50.9k
  if (PIM_DEBUG_TRACE)
197
0
    zlog_debug("pim_upstream free vrf:%s %s flags 0x%x",
198
50.9k
         pim->vrf->name, up->sg_str, up->flags);
199
200
50.9k
  if (pim_up_mlag_is_local(up))
201
0
    pim_mlag_up_local_del(pim, up);
202
203
50.9k
  pim_upstream_timers_stop(up);
204
205
50.9k
  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
50.9k
  join_timer_stop(up);
217
50.9k
  pim_jp_agg_upstream_verification(up, false);
218
50.9k
  up->rpf.source_nexthop.interface = NULL;
219
220
50.9k
  if (!pim_addr_is_any(up->sg.src)) {
221
50.9k
    if (pim->upstream_sg_wheel)
222
50.9k
      wheel_remove_item(pim->upstream_sg_wheel, up);
223
50.9k
    notify_msdp = true;
224
50.9k
  }
225
226
50.9k
  pim_mroute_del(up->channel_oil, __func__);
227
50.9k
  upstream_channel_oil_detach(up);
228
229
50.9k
  for (ALL_LIST_ELEMENTS(up->ifchannels, node, nnode, ch))
230
0
    pim_ifchannel_delete(ch);
231
50.9k
  list_delete(&up->ifchannels);
232
233
50.9k
  pim_upstream_remove_children(pim, up);
234
50.9k
  if (up->sources)
235
0
    list_delete(&up->sources);
236
237
50.9k
  if (up->parent && up->parent->sources)
238
50.9k
    listnode_delete(up->parent->sources, up);
239
50.9k
  up->parent = NULL;
240
241
50.9k
  rb_pim_upstream_del(&pim->upstream_head, up);
242
243
50.9k
  if (notify_msdp) {
244
50.9k
    pim_msdp_up_del(pim, &up->sg);
245
50.9k
  }
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
50.9k
  if (!pim_addr_is_any(up->upstream_addr)) {
254
    /* Deregister addr with Zebra NHT */
255
29.3k
    if (PIM_DEBUG_PIM_TRACE)
256
0
      zlog_debug(
257
29.3k
        "%s: Deregister upstream %s addr %pPA with Zebra NHT",
258
29.3k
        __func__, up->sg_str, &up->upstream_addr);
259
29.3k
    pim_delete_tracked_nexthop(pim, up->upstream_addr, up, NULL);
260
29.3k
  }
261
262
50.9k
  XFREE(MTYPE_PIM_UPSTREAM, up);
263
264
50.9k
  return NULL;
265
50.9k
}
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
50.9k
{
324
50.9k
  struct pim_neighbor *nbr = NULL;
325
326
50.9k
  EVENT_OFF(up->t_join_timer);
327
328
50.9k
  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
50.9k
  if (nbr)
333
0
    pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
334
335
50.9k
  pim_jp_agg_upstream_verification(up, false);
336
50.9k
}
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
7.48M
{
631
7.48M
  bool old_use_rpt;
632
7.48M
  bool new_use_rpt;
633
634
7.48M
  if (pim_addr_is_any(up->sg.src))
635
76
    return;
636
637
7.48M
  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
7.48M
  if (up->join_state == PIM_UPSTREAM_JOINED ||
648
7.48M
      PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) ||
649
7.48M
      pim_if_connected_to_source(
650
7.48M
        up->rpf.source_nexthop.interface,
651
7.48M
        up->sg.src) ||
652
      /* XXX - need to switch this to a more efficient
653
       * lookup API
654
       */
655
7.48M
      I_am_RP(up->pim, up->sg.grp))
656
    /* use SPT */
657
50.9k
    PIM_UPSTREAM_FLAG_UNSET_USE_RPT(up->flags);
658
7.43M
  else
659
    /* use RPT */
660
7.43M
    PIM_UPSTREAM_FLAG_SET_USE_RPT(up->flags);
661
662
7.48M
  new_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
663
7.48M
  if (old_use_rpt != new_use_rpt) {
664
37.2k
    if (PIM_DEBUG_PIM_EVENTS)
665
0
      zlog_debug("%s switched from %s to %s",
666
37.2k
          up->sg_str,
667
37.2k
          old_use_rpt?"RPT":"SPT",
668
37.2k
          new_use_rpt?"RPT":"SPT");
669
37.2k
    if (update_mroute)
670
9.33k
      pim_upstream_mroute_add(up->channel_oil, __func__);
671
37.2k
  }
672
7.48M
}
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
15.8k
{
679
15.8k
  struct pim_upstream *up;
680
681
10.0M
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
682
10.0M
    if (pim_addr_is_any(up->sg.src))
683
2.54M
      continue;
684
685
7.45M
    pim_upstream_update_use_rpt(up, true /*update_mroute*/);
686
7.45M
  }
687
15.8k
}
688
689
void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
690
       enum pim_upstream_state new_state)
691
11.7k
{
692
11.7k
  enum pim_upstream_state old_state = up->join_state;
693
694
11.7k
  if (pim_addr_is_any(up->upstream_addr)) {
695
10.9k
    if (PIM_DEBUG_PIM_EVENTS)
696
0
      zlog_debug("%s: RPF not configured for %s", __func__,
697
10.9k
           up->sg_str);
698
10.9k
    return;
699
10.9k
  }
700
701
877
  if (!up->rpf.source_nexthop.interface)  {
702
877
    if (PIM_DEBUG_PIM_EVENTS)
703
0
      zlog_debug("%s: RP not reachable for %s", __func__,
704
877
           up->sg_str);
705
877
    return;
706
877
  }
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.01M
{
805
2.01M
  return pim_sgaddr_cmp(up1->sg, up2->sg);
806
2.01M
}
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
51.5k
{
827
51.5k
  enum pim_rpf_result rpf_result;
828
51.5k
  struct pim_interface *pim_ifp;
829
51.5k
  struct pim_upstream *up;
830
831
51.5k
  up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
832
833
51.5k
  up->pim = pim;
834
51.5k
  up->sg = *sg;
835
51.5k
  snprintfrr(up->sg_str, sizeof(up->sg_str), "%pSG", sg);
836
51.5k
  if (ch)
837
51.5k
    ch->upstream = up;
838
839
51.5k
  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
51.5k
  if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
844
51.5k
              sg->grp)) {
845
21.9k
    if (PIM_DEBUG_PIM_TRACE)
846
0
      zlog_debug("%s: Received a (*,G) with no RP configured",
847
21.9k
           __func__);
848
21.9k
  }
849
850
51.5k
  up->parent = pim_upstream_find_parent(pim, up);
851
51.5k
  if (pim_addr_is_any(up->sg.src)) {
852
170
    up->sources = list_new();
853
170
    up->sources->cmp =
854
170
      (int (*)(void *, void *))pim_upstream_compare;
855
170
  } else
856
51.4k
    up->sources = NULL;
857
858
51.5k
  pim_upstream_find_new_children(pim, up);
859
51.5k
  up->flags = flags;
860
51.5k
  up->ref_count = 1;
861
51.5k
  up->t_join_timer = NULL;
862
51.5k
  up->t_ka_timer = NULL;
863
51.5k
  up->t_rs_timer = NULL;
864
51.5k
  up->t_msdp_reg_timer = NULL;
865
51.5k
  up->join_state = PIM_UPSTREAM_NOTJOINED;
866
51.5k
  up->reg_state = PIM_REG_NOINFO;
867
51.5k
  up->state_transition = pim_time_monotonic_sec();
868
51.5k
  up->channel_oil = pim_channel_oil_add(pim, &up->sg, __func__);
869
51.5k
  up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
870
871
51.5k
  up->rpf.source_nexthop.interface = NULL;
872
51.5k
  up->rpf.source_nexthop.mrib_nexthop_addr = PIMADDR_ANY;
873
51.5k
  up->rpf.source_nexthop.mrib_metric_preference =
874
51.5k
    router->infinite_assert_metric.metric_preference;
875
51.5k
  up->rpf.source_nexthop.mrib_route_metric =
876
51.5k
    router->infinite_assert_metric.route_metric;
877
51.5k
  up->rpf.rpf_addr = PIMADDR_ANY;
878
51.5k
  up->ifchannels = list_new();
879
51.5k
  up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
880
881
51.5k
  if (!pim_addr_is_any(up->sg.src)) {
882
51.4k
    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
51.4k
    if (up->parent
888
50.9k
        && 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
51.4k
  }
897
898
51.5k
  if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)
899
51.5k
      || 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
51.5k
  } else if (!pim_addr_is_any(up->upstream_addr)) {
911
29.6k
    pim_upstream_update_use_rpt(up,
912
29.6k
        false /*update_mroute*/);
913
29.6k
    rpf_result = pim_rpf_update(pim, up, NULL, __func__);
914
29.6k
    if (rpf_result == PIM_RPF_FAILURE) {
915
29.6k
      if (PIM_DEBUG_PIM_TRACE)
916
0
        zlog_debug(
917
29.6k
          "%s: Attempting to create upstream(%s), Unable to RPF for source",
918
29.6k
          __func__, up->sg_str);
919
29.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
29.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
29.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
51.5k
  if (pim_up_mlag_is_local(up)
941
51.5k
      || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
942
0
    pim_mlag_up_local_add(pim, up);
943
944
51.5k
  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
51.5k
  return up;
952
51.5k
}
953
954
uint32_t pim_up_mlag_local_cost(struct pim_upstream *up)
955
732k
{
956
732k
  if (!(pim_up_mlag_is_local(up))
957
732k
      && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
958
732k
    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
155k
{
981
155k
  struct pim_upstream lookup;
982
155k
  struct pim_upstream *up = NULL;
983
984
155k
  lookup.sg = *sg;
985
155k
  up = rb_pim_upstream_find(&pim->upstream_head, &lookup);
986
155k
  return up;
987
155k
}
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
51.5k
{
1040
51.5k
  struct pim_upstream *up = NULL;
1041
51.5k
  int found = 0;
1042
1043
51.5k
  up = pim_upstream_find(pim, sg);
1044
51.5k
  if (up) {
1045
0
    pim_upstream_ref(up, flags, name);
1046
0
    found = 1;
1047
51.5k
  } else {
1048
51.5k
    up = pim_upstream_new(pim, sg, incoming, flags, ch);
1049
51.5k
  }
1050
1051
51.5k
  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
51.5k
  return up;
1062
51.5k
}
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
11.3k
{
1075
  /* if there is an explicit prune for this interface we cannot
1076
   * add it to the OIL
1077
   */
1078
11.3k
  if (ch) {
1079
11.3k
    if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1080
3.37k
      return 0;
1081
11.3k
  }
1082
1083
  /* Check if the OIF can be inherited fron the (*,G) entry
1084
   */
1085
7.97k
  if (starch) {
1086
7.97k
    if (!pim_macro_ch_lost_assert(starch)
1087
7.97k
        && pim_macro_chisin_joins_or_include(starch))
1088
7.97k
      return 1;
1089
7.97k
  }
1090
1091
0
  return 0;
1092
7.97k
}
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
121k
{
1102
121k
  if (ch) {
1103
121k
    if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1104
56.4k
      return 0;
1105
1106
64.8k
    if (!pim_macro_ch_lost_assert(ch)
1107
64.8k
        && pim_macro_chisin_joins_or_include(ch))
1108
13.7k
      return 1;
1109
64.8k
  }
1110
1111
  /*
1112
   * joins (*,G)
1113
   */
1114
51.1k
  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
50.9k
    if (!pim_macro_ch_lost_assert(starch)
1125
50.9k
        && pim_macro_chisin_joins_or_include(starch))
1126
50.9k
      return 1;
1127
50.9k
  }
1128
1129
236
  return 0;
1130
51.1k
}
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
67.9k
{
1138
67.9k
  struct interface *ifp;
1139
67.9k
  struct pim_ifchannel *ch;
1140
1141
124k
  FOR_ALL_INTERFACES (pim->vrf, ifp) {
1142
124k
    if (!ifp->info)
1143
0
      continue;
1144
1145
124k
    ch = pim_ifchannel_find(ifp, &up->sg);
1146
124k
    if (!ch)
1147
56.6k
      continue;
1148
1149
    /* If we have even one immediate OIF we can return with
1150
     * not-empty
1151
     */
1152
67.9k
    if (pim_upstream_evaluate_join_desired_interface(up, ch,
1153
67.9k
              NULL /* starch */))
1154
11.2k
      return false;
1155
67.9k
  } /* scan iface channel list */
1156
1157
  /* immediate_oil is empty */
1158
56.6k
  return true;
1159
67.9k
}
1160
1161
1162
static inline bool pim_upstream_is_msdp_peer_sa(struct pim_upstream *up)
1163
263
{
1164
263
  return PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags);
1165
263
}
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
67.9k
{
1184
67.9k
  bool empty_imm_oil;
1185
67.9k
  bool empty_inh_oil;
1186
1187
67.9k
  empty_imm_oil = pim_upstream_empty_immediate_olist(pim, up);
1188
1189
  /* (*,G) */
1190
67.9k
  if (pim_addr_is_any(up->sg.src))
1191
2.32k
    return !empty_imm_oil;
1192
1193
  /* (S,G) */
1194
65.5k
  if (!empty_imm_oil)
1195
8.96k
    return true;
1196
56.6k
  empty_inh_oil = pim_upstream_empty_inherited_olist(up);
1197
56.6k
  if (!empty_inh_oil &&
1198
263
      (pim_upstream_is_kat_running(up) ||
1199
263
       pim_upstream_is_msdp_peer_sa(up)))
1200
0
    return true;
1201
1202
56.6k
  return false;
1203
56.6k
}
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
67.9k
{
1211
67.9k
  int was_join_desired; /* boolean */
1212
67.9k
  int is_join_desired;  /* boolean */
1213
1214
67.9k
  was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
1215
1216
67.9k
  is_join_desired = pim_upstream_evaluate_join_desired(pim, up);
1217
67.9k
  if (is_join_desired)
1218
11.2k
    PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
1219
56.6k
  else
1220
56.6k
    PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
1221
1222
  /* switched from false to true */
1223
67.9k
  if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) {
1224
11.2k
    pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
1225
11.2k
    return;
1226
11.2k
  }
1227
1228
  /* switched from true to false */
1229
56.6k
  if (!is_join_desired && was_join_desired) {
1230
557
    pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
1231
557
    return;
1232
557
  }
1233
56.6k
}
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
83
{
1247
83
  struct pim_upstream *up;
1248
1249
  /*
1250
   * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1251
   */
1252
3.76k
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1253
3.76k
    pim_addr rpf_addr;
1254
1255
3.76k
    rpf_addr = up->rpf.rpf_addr;
1256
1257
3.76k
    if (PIM_DEBUG_PIM_TRACE)
1258
0
      zlog_debug(
1259
3.76k
        "%s: matching neigh=%pPA against upstream (S,G)=%s[%s] joined=%d rpf_addr=%pPA",
1260
3.76k
        __func__, &neigh_addr, up->sg_str,
1261
3.76k
        pim->vrf->name,
1262
3.76k
        up->join_state == PIM_UPSTREAM_JOINED,
1263
3.76k
        &rpf_addr);
1264
1265
    /* consider only (S,G) upstream in Joined state */
1266
3.76k
    if (up->join_state != PIM_UPSTREAM_JOINED)
1267
3.76k
      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
83
}
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
62.2k
{
1870
62.2k
  return pim_channel_oil_empty(up->channel_oil);
1871
62.2k
}
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
264
{
1881
264
  struct pim_upstream *up;
1882
264
  struct pim_rpf old;
1883
264
  enum pim_rpf_result rpf_result;
1884
1885
  /*
1886
   * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1887
   */
1888
21.7k
  frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1889
21.7k
    if (pim_addr_is_any(up->upstream_addr)) {
1890
11.2k
      if (PIM_DEBUG_PIM_TRACE)
1891
0
        zlog_debug(
1892
11.2k
          "%s: RP not configured for Upstream %s",
1893
11.2k
          __func__, up->sg_str);
1894
11.2k
      continue;
1895
11.2k
    }
1896
1897
10.4k
    if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
1898
10.4k
      if (PIM_DEBUG_PIM_TRACE)
1899
0
        zlog_debug(
1900
10.4k
          "%s: Upstream %s without a path to send join, checking",
1901
10.4k
          __func__, up->sg_str);
1902
10.4k
      old.source_nexthop.interface =
1903
10.4k
        up->rpf.source_nexthop.interface;
1904
10.4k
      rpf_result = pim_rpf_update(pim, up, &old, __func__);
1905
10.4k
      if (rpf_result == PIM_RPF_CHANGED ||
1906
10.4k
          (rpf_result == PIM_RPF_FAILURE &&
1907
10.4k
           old.source_nexthop.interface))
1908
0
        pim_zebra_upstream_rpf_changed(pim, up, &old);
1909
      /* update kernel multicast forwarding cache (MFC) */
1910
10.4k
      pim_upstream_mroute_iif_update(up->channel_oil,
1911
10.4k
          __func__);
1912
10.4k
    }
1913
10.4k
  }
1914
264
  pim_zebra_update_all_interfaces(pim);
1915
264
}
1916
1917
unsigned int pim_upstream_hash_key(const void *arg)
1918
879k
{
1919
879k
  const struct pim_upstream *up = arg;
1920
1921
879k
  return pim_sgaddr_hash(up->sg, 0);
1922
879k
}
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
365k
{
1942
365k
  const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1943
365k
  const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1944
1945
365k
  return !pim_sgaddr_cmp(up1->sg, up2->sg);
1946
365k
}
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
}