]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
*: Convert event.h to frrevent.h
[mirror_frr.git] / pimd / pim_upstream.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
12e41d03 2/*
896014f4
DL
3 * PIM for Quagga
4 * Copyright (C) 2008 Everton da Silva Marques
896014f4 5 */
12e41d03
DL
6
7#include <zebra.h>
8
12e41d03
DL
9#include "log.h"
10#include "zclient.h"
11#include "memory.h"
24a58196 12#include "frrevent.h"
12e41d03 13#include "linklist.h"
dfe43e25
DW
14#include "vty.h"
15#include "plist.h"
0f588989
DS
16#include "hash.h"
17#include "jhash.h"
9c5e4d62 18#include "wheel.h"
5920b3eb 19#include "network.h"
12e41d03
DL
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"
8f5f5e91 35#include "pim_rp.h"
627ed2a3 36#include "pim_register.h"
3c72d654 37#include "pim_msdp.h"
982bff89 38#include "pim_jp_agg.h"
1bc98276 39#include "pim_nht.h"
15a5dafe 40#include "pim_ssm.h"
b9f3a51c 41#include "pim_vxlan.h"
05ca004b 42#include "pim_mlag.h"
12e41d03 43
982bff89 44static void join_timer_stop(struct pim_upstream *up);
d62a17ae 45static void
46pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
ea6d91c8 47static bool pim_upstream_sg_running_proc(struct pim_upstream *up);
12e41d03 48
cfa91a87
DS
49/*
50 * A (*,G) or a (*,*) is going away
51 * remove the parent pointer from
52 * those pointing at us
53 */
9b29ea95
DS
54static void pim_upstream_remove_children(struct pim_instance *pim,
55 struct pim_upstream *up)
cfa91a87 56{
d62a17ae 57 struct pim_upstream *child;
58
59 if (!up->sources)
60 return;
61
62 while (!list_isempty(up->sources)) {
63 child = listnode_head(up->sources);
64 listnode_delete(up->sources, child);
65 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags)) {
66 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags);
15569c58 67 child = pim_upstream_del(pim, child, __func__);
d62a17ae 68 }
70c86421 69 if (child) {
d62a17ae 70 child->parent = NULL;
70c86421
AK
71 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
72 pim_upstream_mroute_iif_update(
73 child->channel_oil,
74 __func__);
75 }
d62a17ae 76 }
6a154c88 77 list_delete(&up->sources);
cfa91a87
DS
78}
79
80/*
81 * A (*,G) or a (*,*) is being created
82 * Find the children that would point
83 * at us.
84 */
9b29ea95
DS
85static void pim_upstream_find_new_children(struct pim_instance *pim,
86 struct pim_upstream *up)
cfa91a87 87{
d62a17ae 88 struct pim_upstream *child;
d62a17ae 89
2a27f13b 90 if (!pim_addr_is_any(up->sg.src) && !pim_addr_is_any(up->sg.grp))
d62a17ae 91 return;
92
2a27f13b 93 if (pim_addr_is_any(up->sg.src) && pim_addr_is_any(up->sg.grp))
d62a17ae 94 return;
95
dd3364cb 96 frr_each (rb_pim_upstream, &pim->upstream_head, child) {
2a27f13b 97 if (!pim_addr_is_any(up->sg.grp) &&
032a7412 98 !pim_addr_cmp(child->sg.grp, up->sg.grp) && (child != up)) {
d62a17ae 99 child->parent = up;
100 listnode_add_sort(up->sources, child);
70c86421
AK
101 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
102 pim_upstream_mroute_iif_update(
103 child->channel_oil,
104 __func__);
d62a17ae 105 }
03417ccd 106 }
cfa91a87
DS
107}
108
4d99418b
DS
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 */
9b29ea95
DS
114static struct pim_upstream *pim_upstream_find_parent(struct pim_instance *pim,
115 struct pim_upstream *child)
4d99418b 116{
6fff2cc6 117 pim_sgaddr any = child->sg;
d62a17ae 118 struct pim_upstream *up = NULL;
4d99418b 119
d62a17ae 120 // (S,G)
2a27f13b
DL
121 if (!pim_addr_is_any(child->sg.src) &&
122 !pim_addr_is_any(child->sg.grp)) {
bca160c6 123 any.src = PIMADDR_ANY;
9b29ea95 124 up = pim_upstream_find(pim, &any);
03417ccd 125
d62a17ae 126 if (up)
127 listnode_add(up->sources, child);
03417ccd 128
22c35834
SK
129 /*
130 * In case parent is MLAG entry copy the data to child
131 */
132 if (up && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)) {
133 PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(child->flags);
134 if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
135 PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(child->flags);
136 else
137 PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(
138 child->flags);
139 }
140
d62a17ae 141 return up;
142 }
4d99418b 143
d62a17ae 144 return NULL;
4d99418b
DS
145}
146
12e41d03
DL
147static void upstream_channel_oil_detach(struct pim_upstream *up)
148{
a155fed5
AK
149 struct channel_oil *channel_oil = up->channel_oil;
150
151 if (channel_oil) {
d62a17ae 152 /* Detaching from channel_oil, channel_oil may exist post del,
153 but upstream would not keep reference of it
154 */
a155fed5 155 channel_oil->up = NULL;
d62a17ae 156 up->channel_oil = NULL;
a155fed5
AK
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 pim_channel_oil_upstream_deref(channel_oil);
d62a17ae 163 }
a155fed5 164
12e41d03
DL
165}
166
ccaa4cce
DS
167static void pim_upstream_timers_stop(struct pim_upstream *up)
168{
e16d030c
DS
169 EVENT_OFF(up->t_ka_timer);
170 EVENT_OFF(up->t_rs_timer);
171 EVENT_OFF(up->t_msdp_reg_timer);
172 EVENT_OFF(up->t_join_timer);
ccaa4cce
DS
173}
174
9b29ea95
DS
175struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
176 struct pim_upstream *up, const char *name)
12e41d03 177{
7692c5ae
DS
178 struct listnode *node, *nnode;
179 struct pim_ifchannel *ch;
d62a17ae 180 bool notify_msdp = false;
d62a17ae 181
23fc858a 182 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 183 zlog_debug(
8dbdb215 184 "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
5e81f5dd 185 __func__, name, up->sg_str, pim->vrf->name,
996c9314
LB
186 up->ref_count, up->flags,
187 up->channel_oil->oil_ref_count);
d62a17ae 188
e83f3b31 189 assert(up->ref_count > 0);
190
d62a17ae 191 --up->ref_count;
192
193 if (up->ref_count >= 1)
194 return up;
195
c5cdf069 196 if (PIM_DEBUG_TRACE)
dd3364cb
DS
197 zlog_debug("pim_upstream free vrf:%s %s flags 0x%x",
198 pim->vrf->name, up->sg_str, up->flags);
c5cdf069 199
95586137
AK
200 if (pim_up_mlag_is_local(up))
201 pim_mlag_up_local_del(pim, up);
202
ccaa4cce 203 pim_upstream_timers_stop(up);
d62a17ae 204
205 if (up->join_state == PIM_UPSTREAM_JOINED) {
206 pim_jp_agg_single_upstream_send(&up->rpf, up, 0);
207
2a27f13b 208 if (pim_addr_is_any(up->sg.src)) {
d62a17ae 209 /* if a (*, G) entry in the joined state is being
210 * deleted we
211 * need to notify MSDP */
212 notify_msdp = true;
213 }
214 }
215
216 join_timer_stop(up);
217 pim_jp_agg_upstream_verification(up, false);
218 up->rpf.source_nexthop.interface = NULL;
219
2a27f13b 220 if (!pim_addr_is_any(up->sg.src)) {
391b8b08
DS
221 if (pim->upstream_sg_wheel)
222 wheel_remove_item(pim->upstream_sg_wheel, up);
d62a17ae 223 notify_msdp = true;
224 }
225
5e81f5dd 226 pim_mroute_del(up->channel_oil, __func__);
d62a17ae 227 upstream_channel_oil_detach(up);
228
7692c5ae
DS
229 for (ALL_LIST_ELEMENTS(up->ifchannels, node, nnode, ch))
230 pim_ifchannel_delete(ch);
6a154c88 231 list_delete(&up->ifchannels);
d62a17ae 232
7692c5ae
DS
233 pim_upstream_remove_children(pim, up);
234 if (up->sources)
6a154c88 235 list_delete(&up->sources);
7692c5ae 236
d62a17ae 237 if (up->parent && up->parent->sources)
238 listnode_delete(up->parent->sources, up);
239 up->parent = NULL;
240
dd3364cb 241 rb_pim_upstream_del(&pim->upstream_head, up);
d62a17ae 242
243 if (notify_msdp) {
472ad383 244 pim_msdp_up_del(pim, &up->sg);
d62a17ae 245 }
246
246445a3
SP
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 */
01adb431 253 if (!pim_addr_is_any(up->upstream_addr)) {
246445a3 254 /* Deregister addr with Zebra NHT */
2dbe669b 255 if (PIM_DEBUG_PIM_TRACE)
5e81f5dd 256 zlog_debug(
028583e9 257 "%s: Deregister upstream %s addr %pPA with Zebra NHT",
258 __func__, up->sg_str, &up->upstream_addr);
e6e53006 259 pim_delete_tracked_nexthop(pim, up->upstream_addr, up, NULL);
d62a17ae 260 }
d62a17ae 261
172e45dc 262 XFREE(MTYPE_PIM_UPSTREAM, up);
d62a17ae 263
264 return NULL;
12e41d03
DL
265}
266
d62a17ae 267void pim_upstream_send_join(struct pim_upstream *up)
12e41d03 268{
957d93ea 269 if (!up->rpf.source_nexthop.interface) {
23fc858a 270 if (PIM_DEBUG_PIM_TRACE)
15569c58
DA
271 zlog_debug("%s: up %s RPF is not present", __func__,
272 up->sg_str);
957d93ea
SP
273 return;
274 }
275
23fc858a 276 if (PIM_DEBUG_PIM_TRACE) {
028583e9 277 zlog_debug("%s: RPF'%s=%pPA(%s) for Interface %s", __func__,
278 up->sg_str, &up->rpf.rpf_addr,
d62a17ae 279 pim_upstream_state2str(up->join_state),
280 up->rpf.source_nexthop.interface->name);
281 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
028583e9 282 zlog_debug("%s: can't send join upstream: RPF'%s=%pPA",
283 __func__, up->sg_str, &up->rpf.rpf_addr);
d62a17ae 284 /* warning only */
285 }
286 }
287
288 /* send Join(S,G) to the current upstream neighbor */
289 pim_jp_agg_single_upstream_send(&up->rpf, up, 1 /* join */);
12e41d03
DL
290}
291
e6685141 292static void on_join_timer(struct event *t)
12e41d03 293{
d62a17ae 294 struct pim_upstream *up;
12e41d03 295
e16d030c 296 up = EVENT_ARG(t);
12e41d03 297
957d93ea 298 if (!up->rpf.source_nexthop.interface) {
23fc858a 299 if (PIM_DEBUG_PIM_TRACE)
15569c58
DA
300 zlog_debug("%s: up %s RPF is not present", __func__,
301 up->sg_str);
cc9f21da 302 return;
957d93ea
SP
303 }
304
d62a17ae 305 /*
306 * In the case of a HFR we will not ahve anyone to send this to.
307 */
308 if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
cc9f21da 309 return;
bb6e291f 310
d62a17ae 311 /*
312 * Don't send the join if the outgoing interface is a loopback
313 * But since this might change leave the join timer running
314 */
315 if (up->rpf.source_nexthop
316 .interface && !if_is_loopback(up->rpf.source_nexthop.interface))
317 pim_upstream_send_join(up);
12e41d03 318
d62a17ae 319 join_timer_start(up);
12e41d03
DL
320}
321
982bff89 322static void join_timer_stop(struct pim_upstream *up)
12e41d03 323{
47e3ce59 324 struct pim_neighbor *nbr = NULL;
957d93ea 325
e16d030c 326 EVENT_OFF(up->t_join_timer);
7eb90689 327
47e3ce59 328 if (up->rpf.source_nexthop.interface)
028583e9 329 nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
d77da853 330 up->rpf.rpf_addr, true);
982bff89 331
d62a17ae 332 if (nbr)
c5cdf069 333 pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
982bff89 334
d62a17ae 335 pim_jp_agg_upstream_verification(up, false);
982bff89
DS
336}
337
d62a17ae 338void join_timer_start(struct pim_upstream *up)
982bff89 339{
d62a17ae 340 struct pim_neighbor *nbr = NULL;
341
342 if (up->rpf.source_nexthop.interface) {
028583e9 343 nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
d77da853 344 up->rpf.rpf_addr, true);
d62a17ae 345
346 if (PIM_DEBUG_PIM_EVENTS) {
347 zlog_debug(
348 "%s: starting %d sec timer for upstream (S,G)=%s",
15569c58 349 __func__, router->t_periodic, up->sg_str);
d62a17ae 350 }
351 }
352
353 if (nbr)
c5cdf069 354 pim_jp_agg_add_group(nbr->upstream_jp_agg, up, 1, nbr);
d62a17ae 355 else {
e16d030c 356 EVENT_OFF(up->t_join_timer);
907a2395
DS
357 event_add_timer(router->master, on_join_timer, up,
358 router->t_periodic, &up->t_join_timer);
d62a17ae 359 }
360 pim_jp_agg_upstream_verification(up, true);
12e41d03
DL
361}
362
982bff89
DS
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 */
d62a17ae 370void pim_upstream_join_timer_restart(struct pim_upstream *up,
371 struct pim_rpf *old)
12e41d03 372{
e16d030c 373 // EVENT_OFF(up->t_join_timer);
d62a17ae 374 join_timer_start(up);
12e41d03
DL
375}
376
377static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
378 int interval_msec)
379{
d62a17ae 380 if (PIM_DEBUG_PIM_EVENTS) {
381 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
15569c58 382 __func__, interval_msec, up->sg_str);
d62a17ae 383 }
384
e16d030c 385 EVENT_OFF(up->t_join_timer);
907a2395
DS
386 event_add_timer_msec(router->master, on_join_timer, up, interval_msec,
387 &up->t_join_timer);
12e41d03
DL
388}
389
3f1f8641
DS
390void pim_update_suppress_timers(uint32_t suppress_time)
391{
392 struct pim_instance *pim;
393 struct vrf *vrf;
394 unsigned int old_rp_ka_time;
395
396 /* stash the old one so we know which values were manually configured */
397 old_rp_ka_time = (3 * router->register_suppress_time
398 + router->register_probe_time);
399 router->register_suppress_time = suppress_time;
400
401 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
402 pim = vrf->info;
403 if (!pim)
404 continue;
405
406 /* Only adjust if not manually configured */
407 if (pim->rp_keep_alive_time == old_rp_ka_time)
408 pim->rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD;
409 }
410}
411
028583e9 412void pim_upstream_join_suppress(struct pim_upstream *up, pim_addr rpf,
fd3af229 413 int holdtime)
12e41d03 414{
d62a17ae 415 long t_joinsuppress_msec;
810cbaf7 416 long join_timer_remain_msec = 0;
417 struct pim_neighbor *nbr = NULL;
d62a17ae 418
957d93ea 419 if (!up->rpf.source_nexthop.interface) {
23fc858a 420 if (PIM_DEBUG_PIM_TRACE)
15569c58
DA
421 zlog_debug("%s: up %s RPF is not present", __func__,
422 up->sg_str);
957d93ea
SP
423 return;
424 }
425
d62a17ae 426 t_joinsuppress_msec =
427 MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
428 1000 * holdtime);
429
810cbaf7 430 if (up->t_join_timer)
431 join_timer_remain_msec =
432 pim_time_timer_remain_msec(up->t_join_timer);
433 else {
434 /* Remove it from jp agg from the nbr for suppression */
028583e9 435 nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
d77da853
SP
436 up->rpf.rpf_addr, true);
437
810cbaf7 438 if (nbr) {
439 join_timer_remain_msec =
440 pim_time_timer_remain_msec(nbr->jp_timer);
441 }
442 }
d62a17ae 443
028583e9 444 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 445 zlog_debug(
028583e9 446 "%s %s: detected Join%s to RPF'(S,G)=%pPA: join_timer=%ld msec t_joinsuppress=%ld msec",
447 __FILE__, __func__, up->sg_str, &rpf,
d62a17ae 448 join_timer_remain_msec, t_joinsuppress_msec);
d62a17ae 449
450 if (join_timer_remain_msec < t_joinsuppress_msec) {
23fc858a 451 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 452 zlog_debug(
453 "%s %s: suppressing Join(S,G)=%s for %ld msec",
15569c58 454 __FILE__, __func__, up->sg_str,
d62a17ae 455 t_joinsuppress_msec);
456 }
457
810cbaf7 458 if (nbr)
459 pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
460
d62a17ae 461 pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
462 }
12e41d03
DL
463}
464
465void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
d62a17ae 466 struct pim_upstream *up)
12e41d03 467{
d62a17ae 468 long join_timer_remain_msec;
469 int t_override_msec;
470
957d93ea 471 if (!up->rpf.source_nexthop.interface) {
23fc858a 472 if (PIM_DEBUG_PIM_TRACE)
15569c58
DA
473 zlog_debug("%s: up %s RPF is not present", __func__,
474 up->sg_str);
957d93ea
SP
475 return;
476 }
477
d62a17ae 478 t_override_msec =
479 pim_if_t_override_msec(up->rpf.source_nexthop.interface);
480
af9106e5 481 if (up->t_join_timer) {
482 join_timer_remain_msec =
483 pim_time_timer_remain_msec(up->t_join_timer);
484 } else {
485 /* upstream join tracked with neighbor jp timer */
486 struct pim_neighbor *nbr;
487
028583e9 488 nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
d77da853
SP
489 up->rpf.rpf_addr, true);
490
af9106e5 491 if (nbr)
492 join_timer_remain_msec =
493 pim_time_timer_remain_msec(nbr->jp_timer);
494 else
495 /* Manipulate such that override takes place */
496 join_timer_remain_msec = t_override_msec + 1;
497 }
498
028583e9 499 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 500 zlog_debug(
028583e9 501 "%s: to RPF'%s=%pPA: join_timer=%ld msec t_override=%d msec",
502 debug_label, up->sg_str, &up->rpf.rpf_addr,
d62a17ae 503 join_timer_remain_msec, t_override_msec);
d62a17ae 504
505 if (join_timer_remain_msec > t_override_msec) {
23fc858a 506 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 507 zlog_debug(
508 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
509 debug_label, up->sg_str, t_override_msec);
510 }
511
512 pim_upstream_join_timer_restart_msec(up, t_override_msec);
513 }
12e41d03
DL
514}
515
516static void forward_on(struct pim_upstream *up)
517{
d62a17ae 518 struct listnode *chnode;
519 struct listnode *chnextnode;
520 struct pim_ifchannel *ch = NULL;
12e41d03 521
d62a17ae 522 /* scan (S,G) state */
523 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
524 if (pim_macro_chisin_oiflist(ch))
525 pim_forward_start(ch);
12e41d03 526
d62a17ae 527 } /* scan iface channel list */
12e41d03
DL
528}
529
530static void forward_off(struct pim_upstream *up)
531{
d62a17ae 532 struct listnode *chnode;
533 struct listnode *chnextnode;
534 struct pim_ifchannel *ch;
12e41d03 535
d62a17ae 536 /* scan per-interface (S,G) state */
537 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
12e41d03 538
86696f7b 539 pim_forward_stop(ch);
12e41d03 540
d62a17ae 541 } /* scan iface channel list */
12e41d03
DL
542}
543
46a9ea8b 544int pim_upstream_could_register(struct pim_upstream *up)
bb6e291f 545{
d62a17ae 546 struct pim_interface *pim_ifp = NULL;
547
8eeaef9b
AK
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 if (PIM_UPSTREAM_FLAG_TEST_FORCE_PIMREG(up->flags))
553 return 1;
554
d62a17ae 555 if (up->rpf.source_nexthop.interface)
556 pim_ifp = up->rpf.source_nexthop.interface->info;
557 else {
23fc858a 558 if (PIM_DEBUG_PIM_TRACE)
15569c58
DA
559 zlog_debug("%s: up %s RPF is not present", __func__,
560 up->sg_str);
d62a17ae 561 }
bb6e291f 562
d62a17ae 563 if (pim_ifp && PIM_I_am_DR(pim_ifp)
564 && pim_if_connected_to_source(up->rpf.source_nexthop.interface,
565 up->sg.src))
566 return 1;
bb6e291f 567
d62a17ae 568 return 0;
bb6e291f
DS
569}
570
0437e105 571/* Source registration is suppressed for SSM groups. When the SSM range changes
15a5dafe 572 * we re-revaluate register setup for existing upstream entries */
9b29ea95 573void pim_upstream_register_reevaluate(struct pim_instance *pim)
15a5dafe 574{
d62a17ae 575 struct pim_upstream *up;
576
dd3364cb 577 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
d62a17ae 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. */
ec836533
AK
582 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) ||
583 !pim_upstream_is_kat_running(up))
d62a17ae 584 continue;
585
6f439a70 586 if (pim_is_grp_ssm(pim, up->sg.grp)) {
d62a17ae 587 /* clear the register state for SSM groups */
588 if (up->reg_state != PIM_REG_NOINFO) {
589 if (PIM_DEBUG_PIM_EVENTS)
590 zlog_debug(
591 "Clear register for %s as G is now SSM",
592 up->sg_str);
593 /* remove regiface from the OIL if it is there*/
594 pim_channel_del_oif(up->channel_oil,
9b29ea95 595 pim->regiface,
1b249e70
AK
596 PIM_OIF_FLAG_PROTO_PIM,
597 __func__);
d62a17ae 598 up->reg_state = PIM_REG_NOINFO;
599 }
600 } else {
601 /* register ASM sources with the RP */
602 if (up->reg_state == PIM_REG_NOINFO) {
603 if (PIM_DEBUG_PIM_EVENTS)
604 zlog_debug(
605 "Register %s as G is now ASM",
606 up->sg_str);
607 pim_channel_add_oif(up->channel_oil,
9b29ea95 608 pim->regiface,
1b249e70
AK
609 PIM_OIF_FLAG_PROTO_PIM,
610 __func__);
d62a17ae 611 up->reg_state = PIM_REG_JOIN;
612 }
613 }
614 }
15a5dafe 615}
616
69e3538c
AK
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
07b12758 623 * routers while still forwarding on the (S,G,rpt).
69e3538c
AK
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 */
628void pim_upstream_update_use_rpt(struct pim_upstream *up,
629 bool update_mroute)
630{
631 bool old_use_rpt;
632 bool new_use_rpt;
633
2a27f13b 634 if (pim_addr_is_any(up->sg.src))
69e3538c
AK
635 return;
636
637 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 if (up->join_state == PIM_UPSTREAM_JOINED ||
648 PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) ||
649 pim_if_connected_to_source(
650 up->rpf.source_nexthop.interface,
651 up->sg.src) ||
652 /* XXX - need to switch this to a more efficient
653 * lookup API
654 */
655 I_am_RP(up->pim, up->sg.grp))
656 /* use SPT */
657 PIM_UPSTREAM_FLAG_UNSET_USE_RPT(up->flags);
658 else
659 /* use RPT */
660 PIM_UPSTREAM_FLAG_SET_USE_RPT(up->flags);
661
662 new_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
663 if (old_use_rpt != new_use_rpt) {
664 if (PIM_DEBUG_PIM_EVENTS)
665 zlog_debug("%s switched from %s to %s",
666 up->sg_str,
667 old_use_rpt?"RPT":"SPT",
668 new_use_rpt?"RPT":"SPT");
669 if (update_mroute)
670 pim_upstream_mroute_add(up->channel_oil, __func__);
671 }
672}
673
a749b900
AK
674/* some events like RP change require re-evaluation of SGrpt across
675 * all groups
676 */
677void pim_upstream_reeval_use_rpt(struct pim_instance *pim)
678{
679 struct pim_upstream *up;
a749b900 680
dd3364cb 681 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2a27f13b 682 if (pim_addr_is_any(up->sg.src))
a749b900
AK
683 continue;
684
685 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
686 }
687}
688
1eca8576 689void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
d62a17ae 690 enum pim_upstream_state new_state)
12e41d03 691{
d62a17ae 692 enum pim_upstream_state old_state = up->join_state;
693
01adb431 694 if (pim_addr_is_any(up->upstream_addr)) {
47e3ce59 695 if (PIM_DEBUG_PIM_EVENTS)
15569c58
DA
696 zlog_debug("%s: RPF not configured for %s", __func__,
697 up->sg_str);
957d93ea
SP
698 return;
699 }
700
701 if (!up->rpf.source_nexthop.interface) {
47e3ce59 702 if (PIM_DEBUG_PIM_EVENTS)
15569c58
DA
703 zlog_debug("%s: RP not reachable for %s", __func__,
704 up->sg_str);
957d93ea
SP
705 return;
706 }
707
d62a17ae 708 if (PIM_DEBUG_PIM_EVENTS) {
709 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
15569c58 710 __func__, up->sg_str,
d62a17ae 711 pim_upstream_state2str(up->join_state),
712 pim_upstream_state2str(new_state));
713 }
714
715 up->join_state = new_state;
716 if (old_state != new_state)
717 up->state_transition = pim_time_monotonic_sec();
718
719 pim_upstream_update_assert_tracking_desired(up);
720
721 if (new_state == PIM_UPSTREAM_JOINED) {
b077f571 722 pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 723 if (old_state != PIM_UPSTREAM_JOINED) {
724 int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
b077f571 725
1eca8576 726 pim_msdp_up_join_state_changed(pim, up);
d62a17ae 727 if (pim_upstream_could_register(up)) {
728 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
729 if (!old_fhr
730 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
731 up->flags)) {
732 pim_upstream_keep_alive_timer_start(
19b807ca 733 up, pim->keep_alive_time);
d62a17ae 734 pim_register_join(up);
735 }
736 } else {
737 pim_upstream_send_join(up);
738 join_timer_start(up);
739 }
d62a17ae 740 }
c692bd2a
AK
741 if (old_state != new_state)
742 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
d62a17ae 743 } else {
c692bd2a
AK
744 bool old_use_rpt;
745 bool new_use_rpt;
746 bool send_xg_jp = false;
d62a17ae 747
748 forward_off(up);
195427c8
MR
749 /*
750 * RFC 4601 Sec 4.5.7:
751 * JoinDesired(S,G) -> False, set SPTbit to false.
752 */
2a27f13b 753 if (!pim_addr_is_any(up->sg.src))
195427c8
MR
754 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
755
d62a17ae 756 if (old_state == PIM_UPSTREAM_JOINED)
1eca8576 757 pim_msdp_up_join_state_changed(pim, up);
d62a17ae 758
c692bd2a
AK
759 if (old_state != new_state) {
760 old_use_rpt =
761 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
762 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
763 new_use_rpt =
764 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
765 if (new_use_rpt &&
766 (new_use_rpt != old_use_rpt) &&
767 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 send_xg_jp = true;
773 }
774
d62a17ae 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. */
c692bd2a
AK
778 if (pim_upstream_is_sg_rpt(up) && up->parent &&
779 !I_am_RP(pim, up->sg.grp))
780 send_xg_jp = true;
0a4497f1 781
782 pim_jp_agg_single_upstream_send(&up->rpf, up, 0 /* prune */);
c692bd2a
AK
783
784 if (send_xg_jp) {
d62a17ae 785 if (PIM_DEBUG_PIM_TRACE_DETAIL)
786 zlog_debug(
c692bd2a 787 "re-join RPT; *,G IIF %s S,G IIF %s ",
957d93ea
SP
788 up->parent->rpf.source_nexthop.interface ?
789 up->parent->rpf.source_nexthop.interface->name
790 : "Unknown",
791 up->rpf.source_nexthop.interface ?
792 up->rpf.source_nexthop.interface->name :
793 "Unknown");
d62a17ae 794 pim_jp_agg_single_upstream_send(&up->parent->rpf,
795 up->parent,
796 1 /* (W,G) Join */);
c692bd2a 797 }
d62a17ae 798 join_timer_stop(up);
799 }
12e41d03
DL
800}
801
dd3364cb
DS
802int pim_upstream_compare(const struct pim_upstream *up1,
803 const struct pim_upstream *up2)
03417ccd 804{
62f59b58 805 return pim_sgaddr_cmp(up1->sg, up2->sg);
03417ccd
DS
806}
807
6a5de0ad
AK
808void pim_upstream_fill_static_iif(struct pim_upstream *up,
809 struct interface *incoming)
810{
811 up->rpf.source_nexthop.interface = incoming;
812
813 /* reset other parameters to matched a connected incoming interface */
d8a2f466 814 up->rpf.source_nexthop.mrib_nexthop_addr = PIMADDR_ANY;
6a5de0ad
AK
815 up->rpf.source_nexthop.mrib_metric_preference =
816 ZEBRA_CONNECT_DISTANCE_DEFAULT;
817 up->rpf.source_nexthop.mrib_route_metric = 0;
028583e9 818 up->rpf.rpf_addr = PIMADDR_ANY;
6a5de0ad
AK
819}
820
2002dcdb 821static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
6fff2cc6 822 pim_sgaddr *sg,
2002dcdb 823 struct interface *incoming,
0885a9f1
DS
824 int flags,
825 struct pim_ifchannel *ch)
12e41d03 826{
d62a17ae 827 enum pim_rpf_result rpf_result;
828 struct pim_interface *pim_ifp;
829 struct pim_upstream *up;
830
831 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
d62a17ae 832
69e3538c 833 up->pim = pim;
d62a17ae 834 up->sg = *sg;
9bace5c2 835 snprintfrr(up->sg_str, sizeof(up->sg_str), "%pSG", sg);
0885a9f1
DS
836 if (ch)
837 ch->upstream = up;
838
dd3364cb 839 rb_pim_upstream_add(&pim->upstream_head, up);
732c209c
SP
840 /* Set up->upstream_addr as INADDR_ANY, if RP is not
841 * configured and retain the upstream data structure
842 */
d9c9a9ee
DS
843 if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
844 sg->grp)) {
23fc858a 845 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 846 zlog_debug("%s: Received a (*,G) with no RP configured",
15569c58 847 __func__);
d62a17ae 848 }
849
9b29ea95 850 up->parent = pim_upstream_find_parent(pim, up);
2a27f13b 851 if (pim_addr_is_any(up->sg.src)) {
d62a17ae 852 up->sources = list_new();
dd3364cb
DS
853 up->sources->cmp =
854 (int (*)(void *, void *))pim_upstream_compare;
d62a17ae 855 } else
856 up->sources = NULL;
857
9b29ea95 858 pim_upstream_find_new_children(pim, up);
d62a17ae 859 up->flags = flags;
860 up->ref_count = 1;
861 up->t_join_timer = NULL;
862 up->t_ka_timer = NULL;
863 up->t_rs_timer = NULL;
864 up->t_msdp_reg_timer = NULL;
865 up->join_state = PIM_UPSTREAM_NOTJOINED;
866 up->reg_state = PIM_REG_NOINFO;
867 up->state_transition = pim_time_monotonic_sec();
15569c58 868 up->channel_oil = pim_channel_oil_add(pim, &up->sg, __func__);
d62a17ae 869 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
870
871 up->rpf.source_nexthop.interface = NULL;
d8a2f466 872 up->rpf.source_nexthop.mrib_nexthop_addr = PIMADDR_ANY;
d62a17ae 873 up->rpf.source_nexthop.mrib_metric_preference =
d17612dd 874 router->infinite_assert_metric.metric_preference;
d62a17ae 875 up->rpf.source_nexthop.mrib_route_metric =
d17612dd 876 router->infinite_assert_metric.route_metric;
028583e9 877 up->rpf.rpf_addr = PIMADDR_ANY;
d62a17ae 878 up->ifchannels = list_new();
879 up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
880
2a27f13b 881 if (!pim_addr_is_any(up->sg.src)) {
9b29ea95 882 wheel_add_item(pim->upstream_sg_wheel, up);
d62a17ae 883
ec85b101
AK
884 /* Inherit the DF role from the parent (*, G) entry for
885 * VxLAN BUM groups
886 */
887 if (up->parent
888 && PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->parent->flags)
889 && PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->parent->flags)) {
890 PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(up->flags);
891 if (PIM_DEBUG_VXLAN)
892 zlog_debug(
893 "upstream %s inherited mlag non-df flag from parent",
894 up->sg_str);
895 }
896 }
897
02434c43
DS
898 if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)
899 || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
6a5de0ad
AK
900 pim_upstream_fill_static_iif(up, incoming);
901 pim_ifp = up->rpf.source_nexthop.interface->info;
902 assert(pim_ifp);
35d6862d
AK
903 pim_upstream_update_use_rpt(up,
904 false /*update_mroute*/);
7984af18 905 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
02434c43
DS
906
907 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags))
908 pim_upstream_keep_alive_timer_start(
909 up, pim->keep_alive_time);
01adb431 910 } else if (!pim_addr_is_any(up->upstream_addr)) {
35d6862d
AK
911 pim_upstream_update_use_rpt(up,
912 false /*update_mroute*/);
8c55c132 913 rpf_result = pim_rpf_update(pim, up, NULL, __func__);
732c209c 914 if (rpf_result == PIM_RPF_FAILURE) {
23fc858a 915 if (PIM_DEBUG_PIM_TRACE)
732c209c
SP
916 zlog_debug(
917 "%s: Attempting to create upstream(%s), Unable to RPF for source",
15569c58 918 __func__, up->sg_str);
d62a17ae 919 }
920
8d0f0b02
MR
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 if (up->rpf.source_nexthop.interface &&
929 !(pim_upstream_empty_inherited_olist(up) && (ch != NULL) &&
930 PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))) {
35d6862d
AK
931 pim_upstream_mroute_iif_update(up->channel_oil,
932 __func__);
732c209c 933 }
d62a17ae 934 }
935
05ca004b
AK
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 */
22c35834
SK
940 if (pim_up_mlag_is_local(up)
941 || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
05ca004b
AK
942 pim_mlag_up_local_add(pim, up);
943
23fc858a 944 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 945 zlog_debug(
fd3af229 946 "%s: Created Upstream %s upstream_addr %pPAs ref count %d increment",
ee2bbf7c 947 __func__, up->sg_str, &up->upstream_addr,
15569c58 948 up->ref_count);
d62a17ae 949 }
950
951 return up;
12e41d03
DL
952}
953
05ca004b
AK
954uint32_t pim_up_mlag_local_cost(struct pim_upstream *up)
955{
22c35834
SK
956 if (!(pim_up_mlag_is_local(up))
957 && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
05ca004b
AK
958 return router->infinite_assert_metric.route_metric;
959
f03999ca
AK
960 if ((up->rpf.source_nexthop.interface ==
961 up->pim->vxlan.peerlink_rif) &&
962 (up->rpf.source_nexthop.mrib_route_metric <
963 (router->infinite_assert_metric.route_metric -
964 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC)))
965 return up->rpf.source_nexthop.mrib_route_metric +
966 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC;
967
05ca004b
AK
968 return up->rpf.source_nexthop.mrib_route_metric;
969}
970
971uint32_t pim_up_mlag_peer_cost(struct pim_upstream *up)
972{
973 if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
974 return router->infinite_assert_metric.route_metric;
975
976 return up->mlag.peer_mrib_metric;
977}
978
6fff2cc6 979struct pim_upstream *pim_upstream_find(struct pim_instance *pim, pim_sgaddr *sg)
12e41d03 980{
d62a17ae 981 struct pim_upstream lookup;
982 struct pim_upstream *up = NULL;
12e41d03 983
d62a17ae 984 lookup.sg = *sg;
dd3364cb 985 up = rb_pim_upstream_find(&pim->upstream_head, &lookup);
d62a17ae 986 return up;
12e41d03
DL
987}
988
6fff2cc6
DL
989struct pim_upstream *pim_upstream_find_or_add(pim_sgaddr *sg,
990 struct interface *incoming,
991 int flags, const char *name)
e711cd3c 992{
69e3538c 993 struct pim_interface *pim_ifp = incoming->info;
d62a17ae 994
69e3538c
AK
995 return (pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name,
996 NULL));
e711cd3c
DS
997}
998
d62a17ae 999void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name)
1bf16443 1000{
05ca004b
AK
1001 /* if a local MLAG reference is being created we need to send the mroute
1002 * to the peer
1003 */
1004 if (!PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->flags) &&
1005 PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags)) {
1006 PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(up->flags);
1007 pim_mlag_up_local_add(up->pim, up);
1008 }
1009
69e3538c
AK
1010 /* when we go from non-FHR to FHR we need to re-eval traffic
1011 * forwarding path
1012 */
1013 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) &&
1014 PIM_UPSTREAM_FLAG_TEST_FHR(flags)) {
1015 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1016 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
1017 }
1018
41a115e4
AK
1019 /* re-eval joinDesired; clearing peer-msdp-sa flag can
1020 * cause JD to change
1021 */
1022 if (!PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags) &&
1023 PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags)) {
1024 PIM_UPSTREAM_FLAG_SET_SRC_MSDP(up->flags);
1025 pim_upstream_update_join_desired(up->pim, up);
1026 }
1027
d62a17ae 1028 up->flags |= flags;
1029 ++up->ref_count;
23fc858a 1030 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1031 zlog_debug("%s(%s): upstream %s ref count %d increment",
15569c58 1032 __func__, name, up->sg_str, up->ref_count);
1bf16443 1033}
1034
6fff2cc6 1035struct pim_upstream *pim_upstream_add(struct pim_instance *pim, pim_sgaddr *sg,
d62a17ae 1036 struct interface *incoming, int flags,
0885a9f1
DS
1037 const char *name,
1038 struct pim_ifchannel *ch)
12e41d03 1039{
d62a17ae 1040 struct pim_upstream *up = NULL;
1041 int found = 0;
9b29ea95 1042
2002dcdb 1043 up = pim_upstream_find(pim, sg);
d62a17ae 1044 if (up) {
1045 pim_upstream_ref(up, flags, name);
1046 found = 1;
1047 } else {
0885a9f1 1048 up = pim_upstream_new(pim, sg, incoming, flags, ch);
d62a17ae 1049 }
1050
23fc858a 1051 if (PIM_DEBUG_PIM_TRACE) {
e89de028
DS
1052 zlog_debug(
1053 "%s(%s): %s, iif %pPA (%s) found: %d: ref_count: %d",
1054 __func__, name, up->sg_str, &up->rpf.rpf_addr,
1055 up->rpf.source_nexthop.interface ? up->rpf.source_nexthop
1056 .interface->name
1057 : "Unknown",
1058 found, up->ref_count);
d62a17ae 1059 }
12e41d03 1060
d62a17ae 1061 return up;
12e41d03
DL
1062}
1063
a53a9b3e
AK
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 */
1071int pim_upstream_eval_inherit_if(struct pim_upstream *up,
1072 struct pim_ifchannel *ch,
1073 struct pim_ifchannel *starch)
1074{
1075 /* if there is an explicit prune for this interface we cannot
1076 * add it to the OIL
1077 */
1078 if (ch) {
1079 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1080 return 0;
1081 }
1082
1083 /* Check if the OIF can be inherited fron the (*,G) entry
1084 */
1085 if (starch) {
1086 if (!pim_macro_ch_lost_assert(starch)
1087 && pim_macro_chisin_joins_or_include(starch))
1088 return 1;
1089 }
1090
1091 return 0;
1092}
1093
c8fc07cb
DS
1094/*
1095 * Passed in up must be the upstream for ch. starch is NULL if no
1096 * information
1097 */
d62a17ae 1098int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
1099 struct pim_ifchannel *ch,
1100 struct pim_ifchannel *starch)
7a3ddda5 1101{
d62a17ae 1102 if (ch) {
1103 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1104 return 0;
1105
1106 if (!pim_macro_ch_lost_assert(ch)
1107 && pim_macro_chisin_joins_or_include(ch))
1108 return 1;
1109 }
1110
1111 /*
1112 * joins (*,G)
1113 */
1114 if (starch) {
a53a9b3e
AK
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
d62a17ae 1120 if (PIM_IF_FLAG_TEST_S_G_RPT(starch->upstream->flags))
1121 return 0;
a53a9b3e 1122#endif
d62a17ae 1123
1124 if (!pim_macro_ch_lost_assert(starch)
1125 && pim_macro_chisin_joins_or_include(starch))
1126 return 1;
1127 }
1128
1129 return 0;
7a3ddda5
DS
1130}
1131
a53a9b3e
AK
1132/* Returns true if immediate OIL is empty and is used to evaluate
1133 * JoinDesired. See pim_upstream_evaluate_join_desired.
12e41d03 1134 */
a53a9b3e 1135static bool pim_upstream_empty_immediate_olist(struct pim_instance *pim,
9b29ea95 1136 struct pim_upstream *up)
12e41d03 1137{
d62a17ae 1138 struct interface *ifp;
a53a9b3e 1139 struct pim_ifchannel *ch;
12e41d03 1140
451fda4f 1141 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 1142 if (!ifp->info)
1143 continue;
c8fc07cb 1144
d62a17ae 1145 ch = pim_ifchannel_find(ifp, &up->sg);
a53a9b3e 1146 if (!ch)
d62a17ae 1147 continue;
12e41d03 1148
a53a9b3e
AK
1149 /* If we have even one immediate OIF we can return with
1150 * not-empty
1151 */
1152 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1153 NULL /* starch */))
1154 return false;
d62a17ae 1155 } /* scan iface channel list */
12e41d03 1156
a53a9b3e
AK
1157 /* immediate_oil is empty */
1158 return true;
1159}
1160
41a115e4
AK
1161
1162static inline bool pim_upstream_is_msdp_peer_sa(struct pim_upstream *up)
1163{
1164 return PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags);
1165}
1166
a53a9b3e
AK
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 */
286bbbec 1181bool pim_upstream_evaluate_join_desired(struct pim_instance *pim,
a53a9b3e
AK
1182 struct pim_upstream *up)
1183{
1184 bool empty_imm_oil;
1185 bool empty_inh_oil;
1186
1187 empty_imm_oil = pim_upstream_empty_immediate_olist(pim, up);
1188
1189 /* (*,G) */
2a27f13b 1190 if (pim_addr_is_any(up->sg.src))
a53a9b3e
AK
1191 return !empty_imm_oil;
1192
1193 /* (S,G) */
1194 if (!empty_imm_oil)
1195 return true;
1196 empty_inh_oil = pim_upstream_empty_inherited_olist(up);
1197 if (!empty_inh_oil &&
1198 (pim_upstream_is_kat_running(up) ||
41a115e4 1199 pim_upstream_is_msdp_peer_sa(up)))
a53a9b3e
AK
1200 return true;
1201
1202 return false;
12e41d03
DL
1203}
1204
1205/*
1206 See also pim_upstream_evaluate_join_desired() above.
1207*/
9b29ea95
DS
1208void pim_upstream_update_join_desired(struct pim_instance *pim,
1209 struct pim_upstream *up)
12e41d03 1210{
d62a17ae 1211 int was_join_desired; /* boolean */
1212 int is_join_desired; /* boolean */
1213
1214 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
1215
9b29ea95 1216 is_join_desired = pim_upstream_evaluate_join_desired(pim, up);
d62a17ae 1217 if (is_join_desired)
1218 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
1219 else
1220 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
1221
1222 /* switched from false to true */
47e3ce59 1223 if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) {
1eca8576 1224 pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
d62a17ae 1225 return;
1226 }
1227
1228 /* switched from true to false */
1229 if (!is_join_desired && was_join_desired) {
1eca8576 1230 pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
d62a17ae 1231 return;
1232 }
12e41d03
DL
1233}
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*/
9b29ea95 1244void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
101b3104 1245 pim_addr neigh_addr)
12e41d03 1246{
d62a17ae 1247 struct pim_upstream *up;
1248
1249 /*
1250 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1251 */
dd3364cb 1252 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
101b3104
DL
1253 pim_addr rpf_addr;
1254
028583e9 1255 rpf_addr = up->rpf.rpf_addr;
101b3104
DL
1256
1257 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1258 zlog_debug(
101b3104 1259 "%s: matching neigh=%pPA against upstream (S,G)=%s[%s] joined=%d rpf_addr=%pPA",
9bb93fa0
DL
1260 __func__, &neigh_addr, up->sg_str,
1261 pim->vrf->name,
d62a17ae 1262 up->join_state == PIM_UPSTREAM_JOINED,
101b3104 1263 &rpf_addr);
d62a17ae 1264
1265 /* consider only (S,G) upstream in Joined state */
1266 if (up->join_state != PIM_UPSTREAM_JOINED)
1267 continue;
1268
1269 /* match RPF'(S,G)=neigh_addr */
101b3104 1270 if (pim_addr_cmp(rpf_addr, neigh_addr))
d62a17ae 1271 continue;
1272
1273 pim_upstream_join_timer_decrease_to_t_override(
1274 "RPF'(S,G) GenID change", up);
1275 }
12e41d03
DL
1276}
1277
1278
1279void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
1280 struct interface *old_rpf_ifp)
1281{
d62a17ae 1282 struct listnode *chnode;
1283 struct listnode *chnextnode;
1284 struct pim_ifchannel *ch;
1285
1286 /* search all ifchannels */
1287 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1288 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
1289 if (
1290 /* RPF_interface(S) was NOT I */
1291 (old_rpf_ifp == ch->interface) &&
1292 /* RPF_interface(S) stopped being I */
1293 (ch->upstream->rpf.source_nexthop
957d93ea
SP
1294 .interface) &&
1295 (ch->upstream->rpf.source_nexthop
1296 .interface != ch->interface)) {
d62a17ae 1297 assert_action_a5(ch);
1298 }
1299 } /* PIM_IFASSERT_I_AM_LOSER */
1300
1301 pim_ifchannel_update_assert_tracking_desired(ch);
1302 }
12e41d03
DL
1303}
1304
1305void pim_upstream_update_could_assert(struct pim_upstream *up)
1306{
d62a17ae 1307 struct listnode *chnode;
1308 struct listnode *chnextnode;
1309 struct pim_ifchannel *ch;
1310
1311 /* scan per-interface (S,G) state */
1312 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1313 pim_ifchannel_update_could_assert(ch);
1314 } /* scan iface channel list */
12e41d03
DL
1315}
1316
1317void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
1318{
d62a17ae 1319 struct listnode *chnode;
1320 struct listnode *chnextnode;
1321 struct pim_ifchannel *ch;
12e41d03 1322
d62a17ae 1323 /* scan per-interface (S,G) state */
1324 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1325 pim_ifchannel_update_my_assert_metric(ch);
12e41d03 1326
d62a17ae 1327 } /* scan iface channel list */
12e41d03
DL
1328}
1329
1330static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
1331{
d62a17ae 1332 struct listnode *chnode;
1333 struct listnode *chnextnode;
1334 struct pim_interface *pim_ifp;
1335 struct pim_ifchannel *ch;
1336
1337 /* scan per-interface (S,G) state */
1338 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1339 if (!ch->interface)
1340 continue;
1341 pim_ifp = ch->interface->info;
1342 if (!pim_ifp)
1343 continue;
1344
1345 pim_ifchannel_update_assert_tracking_desired(ch);
1346
1347 } /* scan iface channel list */
12e41d03 1348}
f14248dd 1349
1bf16443 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 */
9b29ea95
DS
1353static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim,
1354 struct pim_upstream *up)
1bf16443 1355{
d62a17ae 1356 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
1357 return;
1358
23fc858a 1359 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1360 zlog_debug("kat expired on %s; clear fhr reg state",
1361 up->sg_str);
1362
1363 /* stop reg-stop timer */
e16d030c 1364 EVENT_OFF(up->t_rs_timer);
d62a17ae 1365 /* remove regiface from the OIL if it is there*/
9b29ea95 1366 pim_channel_del_oif(up->channel_oil, pim->regiface,
1b249e70 1367 PIM_OIF_FLAG_PROTO_PIM, __func__);
d62a17ae 1368 /* clear the register state */
1369 up->reg_state = PIM_REG_NOINFO;
1370 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
1bf16443 1371}
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 */
1376static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
1377{
d62a17ae 1378 if (pim_upstream_could_register(up)) {
23fc858a 1379 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1380 zlog_debug(
1381 "kat started on %s; set fhr reg state to joined",
1382 up->sg_str);
1383
1384 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1385 if (up->reg_state == PIM_REG_NOINFO)
1386 pim_register_join(up);
69e3538c 1387 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
d62a17ae 1388 }
1bf16443 1389}
1390
f14248dd
DS
1391/*
1392 * On an RP, the PMBR value must be cleared when the
1393 * Keepalive Timer expires
1bf16443 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.
f14248dd 1396 */
ff459c36
AK
1397struct pim_upstream *pim_upstream_keep_alive_timer_proc(
1398 struct pim_upstream *up)
f14248dd 1399{
8e5f97e3 1400 struct pim_instance *pim;
d62a17ae 1401
8e5f97e3 1402 pim = up->channel_oil->pim;
d62a17ae 1403
820b4a40
AK
1404 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 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
ff459c36 1409 return up;
820b4a40
AK
1410 }
1411
8e5f97e3 1412 if (I_am_RP(pim, up->sg.grp)) {
d62a17ae 1413 /*
d139e9e8 1414 * Handle Border Router
d62a17ae 1415 * We need to do more here :)
1416 * But this is the start.
1417 */
1418 }
1419
1420 /* source is no longer active - pull the SA from MSDP's cache */
472ad383 1421 pim_msdp_sa_local_del(pim, &up->sg);
d62a17ae 1422
a53a9b3e
AK
1423 /* JoinDesired can change when KAT is started or stopped */
1424 pim_upstream_update_join_desired(pim, up);
1425
d62a17ae 1426 /* if entry was created because of activity we need to deref it */
1427 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
8e5f97e3 1428 pim_upstream_fhr_kat_expiry(pim, up);
23fc858a 1429 if (PIM_DEBUG_PIM_TRACE)
996c9314
LB
1430 zlog_debug(
1431 "kat expired on %s[%s]; remove stream reference",
1432 up->sg_str, pim->vrf->name);
d62a17ae 1433 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
e3e532dd 1434
1435 /* Return if upstream entry got deleted.*/
15569c58 1436 if (!pim_upstream_del(pim, up, __func__))
e3e532dd 1437 return NULL;
1438 }
02434c43
DS
1439 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
1440 PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up->flags);
1441
15569c58 1442 if (!pim_upstream_del(pim, up, __func__))
02434c43
DS
1443 return NULL;
1444 }
1445
e3e532dd 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 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
8022df6a
DS
1451 struct pim_upstream *parent = up->parent;
1452
d62a17ae 1453 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
15569c58 1454 up = pim_upstream_del(pim, up, __func__);
8022df6a
DS
1455
1456 if (parent) {
996c9314
LB
1457 pim_jp_agg_single_upstream_send(&parent->rpf, parent,
1458 true);
8022df6a 1459 }
d62a17ae 1460 }
1461
ff459c36
AK
1462 return up;
1463}
e6685141 1464static void pim_upstream_keep_alive_timer(struct event *t)
ff459c36
AK
1465{
1466 struct pim_upstream *up;
1467
e16d030c 1468 up = EVENT_ARG(t);
ff459c36 1469
ea6d91c8
AK
1470 /* pull the stats and re-check */
1471 if (pim_upstream_sg_running_proc(up))
1472 /* kat was restarted because of new activity */
cc9f21da 1473 return;
ea6d91c8 1474
ff459c36 1475 pim_upstream_keep_alive_timer_proc(up);
f14248dd
DS
1476}
1477
d62a17ae 1478void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time)
f14248dd 1479{
d62a17ae 1480 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
23fc858a 1481 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1482 zlog_debug("kat start on %s with no stream reference",
1483 up->sg_str);
1484 }
e16d030c 1485 EVENT_OFF(up->t_ka_timer);
907a2395
DS
1486 event_add_timer(router->master, pim_upstream_keep_alive_timer, up, time,
1487 &up->t_ka_timer);
d62a17ae 1488
1489 /* any time keepalive is started against a SG we will have to
1490 * re-evaluate our active source database */
1491 pim_msdp_sa_local_update(up);
a53a9b3e
AK
1492 /* JoinDesired can change when KAT is started or stopped */
1493 pim_upstream_update_join_desired(up->pim, up);
1bf16443 1494}
1495
1496/* MSDP on RP needs to know if a source is registerable to this RP */
e6685141 1497static void pim_upstream_msdp_reg_timer(struct event *t)
1bf16443 1498{
e16d030c 1499 struct pim_upstream *up = EVENT_ARG(t);
472ad383 1500 struct pim_instance *pim = up->channel_oil->pim;
1bf16443 1501
d62a17ae 1502 /* source is no longer active - pull the SA from MSDP's cache */
472ad383 1503 pim_msdp_sa_local_del(pim, &up->sg);
1bf16443 1504}
cc9f21da 1505
d62a17ae 1506void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1bf16443 1507{
e16d030c 1508 EVENT_OFF(up->t_msdp_reg_timer);
907a2395
DS
1509 event_add_timer(router->master, pim_upstream_msdp_reg_timer, up,
1510 PIM_MSDP_REG_RXED_PERIOD, &up->t_msdp_reg_timer);
1bf16443 1511
d62a17ae 1512 pim_msdp_sa_local_update(up);
f14248dd 1513}
cb40b272
DS
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 */
2ef4ed70 1543int pim_upstream_switch_to_spt_desired_on_rp(struct pim_instance *pim,
6fff2cc6 1544 pim_sgaddr *sg)
cb40b272 1545{
8e5f97e3 1546 if (I_am_RP(pim, sg->grp))
d62a17ae 1547 return 1;
a3b58b4a 1548
d62a17ae 1549 return 0;
cb40b272 1550}
d7259eac 1551
d62a17ae 1552int pim_upstream_is_sg_rpt(struct pim_upstream *up)
80d9c3a0 1553{
d62a17ae 1554 struct listnode *chnode;
1555 struct pim_ifchannel *ch;
f21597f0 1556
d62a17ae 1557 for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) {
1558 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1559 return 1;
1560 }
e43b8697 1561
d62a17ae 1562 return 0;
80d9c3a0 1563}
3a66b17b
DS
1564/*
1565 * After receiving a packet set SPTbit:
1566 * void
1567 * Update_SPTbit(S,G,iif) {
1568 * if ( iif == RPF_interface(S)
2951a7a4
QY
1569 * AND JoinDesired(S,G) == true
1570 * AND ( DirectlyConnected(S) == true
3a66b17b
DS
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) ) {
2951a7a4 1576 * Set SPTbit(S,G) to true
3a66b17b
DS
1577 * }
1578 * }
1579 */
d62a17ae 1580void pim_upstream_set_sptbit(struct pim_upstream *up,
1581 struct interface *incoming)
3a66b17b 1582{
d62a17ae 1583 struct pim_upstream *starup = up->parent;
1584
1585 // iif == RPF_interfvace(S)
1586 if (up->rpf.source_nexthop.interface != incoming) {
23fc858a 1587 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1588 zlog_debug(
1589 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
15569c58 1590 __func__, incoming->name,
d62a17ae 1591 up->rpf.source_nexthop.interface->name);
1592 return;
1593 }
1594
2951a7a4 1595 // AND JoinDesired(S,G) == true
6f0f014f 1596 if (!pim_upstream_evaluate_join_desired(up->channel_oil->pim, up)) {
23fc858a 1597 if (PIM_DEBUG_PIM_TRACE)
15569c58
DA
1598 zlog_debug("%s: %s Join is not Desired", __func__,
1599 up->sg_str);
6f0f014f
DS
1600 return;
1601 }
d62a17ae 1602
2951a7a4 1603 // DirectlyConnected(S) == true
d62a17ae 1604 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1605 up->sg.src)) {
23fc858a 1606 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1607 zlog_debug("%s: %s is directly connected to the source",
15569c58 1608 __func__, up->sg_str);
d62a17ae 1609 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1610 return;
1611 }
1612
1613 // OR RPF_interface(S) != RPF_interface(RP(G))
1614 if (!starup
1615 || up->rpf.source_nexthop
1616 .interface != starup->rpf.source_nexthop.interface) {
2de05c60
DS
1617 struct pim_upstream *starup = up->parent;
1618
23fc858a 1619 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1620 zlog_debug(
1621 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
15569c58 1622 __func__, up->sg_str);
d62a17ae 1623 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
2de05c60
DS
1624
1625 pim_jp_agg_single_upstream_send(&starup->rpf, starup, true);
d62a17ae 1626 return;
1627 }
1628
1629 // OR inherited_olist(S,G,rpt) == NULL
1630 if (pim_upstream_is_sg_rpt(up)
1631 && pim_upstream_empty_inherited_olist(up)) {
23fc858a 1632 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1633 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
15569c58 1634 __func__, up->sg_str);
d62a17ae 1635 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1636 return;
1637 }
1638
1639 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1640 // ( RPF'(S,G) != NULL ) )
1641 if (up->parent && pim_rpf_is_same(&up->rpf, &up->parent->rpf)) {
23fc858a 1642 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1643 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
15569c58 1644 __func__, up->sg_str);
d62a17ae 1645 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1646 return;
1647 }
1648
1649 return;
3a66b17b 1650}
80d9c3a0 1651
d62a17ae 1652const char *pim_upstream_state2str(enum pim_upstream_state join_state)
d7259eac 1653{
d62a17ae 1654 switch (join_state) {
1655 case PIM_UPSTREAM_NOTJOINED:
1656 return "NotJoined";
d62a17ae 1657 case PIM_UPSTREAM_JOINED:
1658 return "Joined";
d62a17ae 1659 }
1660 return "Unknown";
d7259eac 1661}
627ed2a3 1662
c35b7e6b
QY
1663const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str,
1664 size_t state_str_len)
e0e127b0 1665{
d62a17ae 1666 switch (reg_state) {
1667 case PIM_REG_NOINFO:
c35b7e6b 1668 strlcpy(state_str, "RegNoInfo", state_str_len);
d62a17ae 1669 break;
1670 case PIM_REG_JOIN:
c35b7e6b 1671 strlcpy(state_str, "RegJoined", state_str_len);
d62a17ae 1672 break;
1673 case PIM_REG_JOIN_PENDING:
c35b7e6b 1674 strlcpy(state_str, "RegJoinPend", state_str_len);
d62a17ae 1675 break;
1676 case PIM_REG_PRUNE:
c35b7e6b 1677 strlcpy(state_str, "RegPrune", state_str_len);
d62a17ae 1678 break;
d62a17ae 1679 }
1680 return state_str;
e0e127b0 1681}
1682
e6685141 1683static void pim_upstream_register_stop_timer(struct event *t)
627ed2a3 1684{
d62a17ae 1685 struct pim_interface *pim_ifp;
8e5f97e3 1686 struct pim_instance *pim;
d62a17ae 1687 struct pim_upstream *up;
e16d030c 1688 up = EVENT_ARG(t);
8e5f97e3 1689 pim = up->channel_oil->pim;
d62a17ae 1690
23fc858a 1691 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 1692 char state_str[PIM_REG_STATE_STR_LEN];
8dbdb215 1693 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
15569c58
DA
1694 __func__, up->sg_str, pim->vrf->name,
1695 pim_reg_state2str(up->reg_state, state_str,
1696 sizeof(state_str)));
d62a17ae 1697 }
1698
1699 switch (up->reg_state) {
1700 case PIM_REG_JOIN_PENDING:
1701 up->reg_state = PIM_REG_JOIN;
8e5f97e3 1702 pim_channel_add_oif(up->channel_oil, pim->regiface,
1b249e70
AK
1703 PIM_OIF_FLAG_PROTO_PIM,
1704 __func__);
2951a7a4 1705 pim_vxlan_update_sg_reg_state(pim, up, true /*reg_join*/);
d62a17ae 1706 break;
1707 case PIM_REG_JOIN:
1708 break;
1709 case PIM_REG_PRUNE:
cf575d09 1710 /* This is equalent to Couldreg -> False */
957d93ea 1711 if (!up->rpf.source_nexthop.interface) {
23fc858a 1712 if (PIM_DEBUG_PIM_TRACE)
957d93ea 1713 zlog_debug("%s: up %s RPF is not present",
15569c58 1714 __func__, up->sg_str);
cf575d09 1715 up->reg_state = PIM_REG_NOINFO;
cc9f21da 1716 return;
957d93ea
SP
1717 }
1718
d62a17ae 1719 pim_ifp = up->rpf.source_nexthop.interface->info;
1720 if (!pim_ifp) {
23fc858a 1721 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1722 zlog_debug(
1723 "%s: Interface: %s is not configured for pim",
15569c58 1724 __func__,
d62a17ae 1725 up->rpf.source_nexthop.interface->name);
cc9f21da 1726 return;
d62a17ae 1727 }
1728 up->reg_state = PIM_REG_JOIN_PENDING;
1729 pim_upstream_start_register_stop_timer(up, 1);
1730
1731 if (((up->channel_oil->cc.lastused / 100)
2f5b0028 1732 > pim->keep_alive_time)
d9c9a9ee 1733 && (I_am_RP(pim_ifp->pim, up->sg.grp))) {
23fc858a 1734 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1735 zlog_debug(
1736 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
15569c58 1737 __func__);
cc9f21da 1738 return;
d62a17ae 1739 }
aea1f845 1740 pim_null_register_send(up);
d62a17ae 1741 break;
e1d1b1de 1742 case PIM_REG_NOINFO:
d62a17ae 1743 break;
70e7fda8 1744 }
627ed2a3
DS
1745}
1746
d62a17ae 1747void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
1748 int null_register)
627ed2a3 1749{
d62a17ae 1750 uint32_t time;
1751
e16d030c 1752 EVENT_OFF(up->t_rs_timer);
d62a17ae 1753
1754 if (!null_register) {
e8b7548c
CH
1755 uint32_t lower = (0.5 * router->register_suppress_time);
1756 uint32_t upper = (1.5 * router->register_suppress_time);
1757 time = lower + (frr_weak_random() % (upper - lower + 1));
1758 /* Make sure we don't wrap around */
1759 if (time >= router->register_probe_time)
1760 time -= router->register_probe_time;
1761 else
1762 time = 0;
d62a17ae 1763 } else
e8b7548c 1764 time = router->register_probe_time;
d62a17ae 1765
23fc858a 1766 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 1767 zlog_debug(
1768 "%s: (S,G)=%s Starting upstream register stop timer %d",
15569c58 1769 __func__, up->sg_str, time);
d62a17ae 1770 }
907a2395
DS
1771 event_add_timer(router->master, pim_upstream_register_stop_timer, up,
1772 time, &up->t_rs_timer);
627ed2a3 1773}
4fdc8f36 1774
9b29ea95
DS
1775int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
1776 struct pim_upstream *up)
4fdc8f36 1777{
d62a17ae 1778 struct interface *ifp;
d62a17ae 1779 struct pim_ifchannel *ch, *starch;
d62a17ae 1780 struct pim_upstream *starup = up->parent;
1781 int output_intf = 0;
1782
46dd6edb 1783 if (!up->rpf.source_nexthop.interface)
23fc858a 1784 if (PIM_DEBUG_PIM_TRACE)
15569c58
DA
1785 zlog_debug("%s: up %s RPF is not present", __func__,
1786 up->sg_str);
d62a17ae 1787
451fda4f 1788 FOR_ALL_INTERFACES (pim->vrf, ifp) {
22c35834 1789 struct pim_interface *pim_ifp;
d62a17ae 1790 if (!ifp->info)
1791 continue;
1792
1793 ch = pim_ifchannel_find(ifp, &up->sg);
1794
1795 if (starup)
1796 starch = pim_ifchannel_find(ifp, &starup->sg);
1797 else
1798 starch = NULL;
1799
1800 if (!ch && !starch)
1801 continue;
1802
22c35834
SK
1803 pim_ifp = ifp->info;
1804 if (PIM_I_am_DualActive(pim_ifp)
1805 && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)
1806 && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
1807 || !PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags)))
1808 continue;
d62a17ae 1809 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1810 starch)) {
9443810e 1811 int flag = 0;
d62a17ae 1812
1813 if (!ch)
1814 flag = PIM_OIF_FLAG_PROTO_STAR;
9443810e
SP
1815 else {
1816 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
80a82b56 1817 flag = PIM_OIF_FLAG_PROTO_GM;
9443810e
SP
1818 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
1819 flag |= PIM_OIF_FLAG_PROTO_PIM;
5428f5ac
MR
1820 if (starch)
1821 flag |= PIM_OIF_FLAG_PROTO_STAR;
9443810e 1822 }
d62a17ae 1823
1b249e70
AK
1824 pim_channel_add_oif(up->channel_oil, ifp, flag,
1825 __func__);
d62a17ae 1826 output_intf++;
1827 }
1828 }
1829
1830 return output_intf;
b5183fd1
DS
1831}
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 */
9b29ea95
DS
1849int pim_upstream_inherited_olist(struct pim_instance *pim,
1850 struct pim_upstream *up)
b5183fd1 1851{
9b29ea95 1852 int output_intf = pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 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 */
a53a9b3e
AK
1860 pim_upstream_update_join_desired(pim, up);
1861
1862 if (!output_intf)
d62a17ae 1863 forward_on(up);
1864
1865 return output_intf;
4fdc8f36 1866}
d3dd1804 1867
d62a17ae 1868int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
80d9c3a0 1869{
d62a17ae 1870 return pim_channel_oil_empty(up->channel_oil);
80d9c3a0
DS
1871}
1872
d3dd1804
DS
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 */
9b29ea95 1879void pim_upstream_find_new_rpf(struct pim_instance *pim)
d3dd1804 1880{
d62a17ae 1881 struct pim_upstream *up;
7ef66af9
AK
1882 struct pim_rpf old;
1883 enum pim_rpf_result rpf_result;
d62a17ae 1884
1885 /*
1886 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1887 */
dd3364cb 1888 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
01adb431 1889 if (pim_addr_is_any(up->upstream_addr)) {
23fc858a 1890 if (PIM_DEBUG_PIM_TRACE)
957d93ea 1891 zlog_debug(
15569c58
DA
1892 "%s: RP not configured for Upstream %s",
1893 __func__, up->sg_str);
957d93ea
SP
1894 continue;
1895 }
1896
d62a17ae 1897 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
23fc858a 1898 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1899 zlog_debug(
957d93ea 1900 "%s: Upstream %s without a path to send join, checking",
15569c58 1901 __func__, up->sg_str);
075a475e
AK
1902 old.source_nexthop.interface =
1903 up->rpf.source_nexthop.interface;
7ef66af9 1904 rpf_result = pim_rpf_update(pim, up, &old, __func__);
b36576e4
AK
1905 if (rpf_result == PIM_RPF_CHANGED ||
1906 (rpf_result == PIM_RPF_FAILURE &&
1907 old.source_nexthop.interface))
7ef66af9
AK
1908 pim_zebra_upstream_rpf_changed(pim, up, &old);
1909 /* update kernel multicast forwarding cache (MFC) */
075a475e
AK
1910 pim_upstream_mroute_iif_update(up->channel_oil,
1911 __func__);
d62a17ae 1912 }
d3dd1804 1913 }
7ef66af9 1914 pim_zebra_update_all_interfaces(pim);
d3dd1804 1915}
0f588989 1916
d8b87afe 1917unsigned int pim_upstream_hash_key(const void *arg)
0f588989 1918{
d8b87afe 1919 const struct pim_upstream *up = arg;
0f588989 1920
62f59b58 1921 return pim_sgaddr_hash(up->sg, 0);
0f588989
DS
1922}
1923
9b29ea95 1924void pim_upstream_terminate(struct pim_instance *pim)
0f588989 1925{
172e45dc
DS
1926 struct pim_upstream *up;
1927
dd3364cb 1928 while ((up = rb_pim_upstream_first(&pim->upstream_head))) {
30247bd6
MR
1929 if (pim_upstream_del(pim, up, __func__))
1930 pim_upstream_timers_stop(up);
172e45dc 1931 }
0f588989 1932
dd3364cb 1933 rb_pim_upstream_fini(&pim->upstream_head);
0c68972d
DS
1934
1935 if (pim->upstream_sg_wheel)
1936 wheel_delete(pim->upstream_sg_wheel);
1937 pim->upstream_sg_wheel = NULL;
0f588989
DS
1938}
1939
74df8d6d 1940bool pim_upstream_equal(const void *arg1, const void *arg2)
0f588989 1941{
d62a17ae 1942 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1943 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
0f588989 1944
62f59b58 1945 return !pim_sgaddr_cmp(up1->sg, up2->sg);
0f588989
DS
1946}
1947
1bf16443 1948/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1949 * the cases where kat has to be restarted on rxing traffic -
1950 *
2951a7a4 1951 * if( DirectlyConnected(S) == true AND iif == RPF_interface(S) ) {
1bf16443 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 */
1962static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1963{
cfa8f7eb
AK
1964 struct channel_oil *c_oil = up->channel_oil;
1965 struct interface *ifp = up->rpf.source_nexthop.interface;
1966 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 if (!ifp)
1974 return false;
1975
1976 pim_ifp = ifp->info;
a9338fa4 1977 if (pim_ifp->mroute_vif_index != *oil_parent(c_oil))
cfa8f7eb 1978 return false;
8e5f97e3 1979
a1be0939 1980 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
d62a17ae 1981 up->sg.src)) {
1982 return true;
1983 }
1984
1985 if ((up->join_state == PIM_UPSTREAM_JOINED)
cfa8f7eb
AK
1986 && !pim_upstream_empty_inherited_olist(up)) {
1987 return true;
d62a17ae 1988 }
1989
1990 return false;
1bf16443 1991}
1992
ea6d91c8 1993static bool pim_upstream_sg_running_proc(struct pim_upstream *up)
9c5e4d62 1994{
ea6d91c8
AK
1995 bool rv = false;
1996 struct pim_instance *pim = up->pim;
d62a17ae 1997
ea6d91c8
AK
1998 if (!up->channel_oil->installed)
1999 return rv;
d62a17ae 2000
d62a17ae 2001 pim_mroute_update_counters(up->channel_oil);
2002
2003 // Have we seen packets?
2004 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
2005 && (up->channel_oil->cc.lastused / 100 > 30)) {
23fc858a 2006 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 2007 zlog_debug(
8dbdb215 2008 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
15569c58 2009 __func__, up->sg_str, pim->vrf->name,
d62a17ae 2010 up->channel_oil->cc.oldpktcnt,
2011 up->channel_oil->cc.pktcnt,
2012 up->channel_oil->cc.lastused / 100);
2013 }
ea6d91c8 2014 return rv;
e43b8697 2015 }
d62a17ae 2016
2017 if (pim_upstream_kat_start_ok(up)) {
2018 /* Add a source reference to the stream if
2019 * one doesn't already exist */
2020 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
23fc858a 2021 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 2022 zlog_debug(
8dbdb215
DS
2023 "source reference created on kat restart %s[%s]",
2024 up->sg_str, pim->vrf->name);
d62a17ae 2025
15569c58
DA
2026 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
2027 __func__);
d62a17ae 2028 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
2029 pim_upstream_fhr_kat_start(up);
2030 }
19b807ca 2031 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
ea6d91c8
AK
2032 rv = true;
2033 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
19b807ca 2034 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
ea6d91c8
AK
2035 rv = true;
2036 }
d62a17ae 2037
957d93ea
SP
2038 if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) &&
2039 (up->rpf.source_nexthop.interface)) {
d62a17ae 2040 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
db89f2a3 2041 pim_upstream_update_could_assert(up);
850a9f99 2042 }
ea6d91c8
AK
2043
2044 return rv;
2045}
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 */
2051static void pim_upstream_sg_running(void *arg)
2052{
2053 struct pim_upstream *up = (struct pim_upstream *)arg;
2054 struct pim_instance *pim = up->channel_oil->pim;
2055
2056 // No packet can have arrived here if this is the case
2057 if (!up->channel_oil->installed) {
2058 if (PIM_DEBUG_TRACE)
2059 zlog_debug("%s: %s%s is not installed in mroute",
2060 __func__, up->sg_str, pim->vrf->name);
2061 return;
2062 }
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 if (up->channel_oil->oil_inherited_rescan) {
2073 if (PIM_DEBUG_TRACE)
2074 zlog_debug(
2075 "%s: Handling unscanned inherited_olist for %s[%s]",
2076 __func__, up->sg_str, pim->vrf->name);
2077 pim_upstream_inherited_olist_decide(pim, up);
2078 up->channel_oil->oil_inherited_rescan = 0;
2079 }
2080
2081 pim_upstream_sg_running_proc(up);
9c5e4d62
DS
2082}
2083
9b29ea95 2084void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim)
a7b2b1e2 2085{
d62a17ae 2086 struct pim_upstream *up;
a7b2b1e2 2087
dd3364cb 2088 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2a27f13b 2089 if (!pim_addr_is_any(up->sg.src))
d62a17ae 2090 continue;
a7b2b1e2 2091
448139e7 2092 if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags))
d62a17ae 2093 continue;
a7b2b1e2 2094
9b29ea95 2095 pim_channel_add_oif(up->channel_oil, pim->regiface,
80a82b56 2096 PIM_OIF_FLAG_PROTO_GM, __func__);
d62a17ae 2097 }
a7b2b1e2
DS
2098}
2099
9b29ea95
DS
2100void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
2101 struct prefix_list *pl)
df94f9a9 2102{
d62a17ae 2103 const char *pname = prefix_list_name(pl);
df94f9a9 2104
9b29ea95
DS
2105 if (pim->spt.plist && strcmp(pim->spt.plist, pname) == 0) {
2106 pim_upstream_remove_lhr_star_pimreg(pim, pname);
d62a17ae 2107 }
df94f9a9
DS
2108}
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 */
9b29ea95
DS
2122void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
2123 const char *nlist)
a7b2b1e2 2124{
d62a17ae 2125 struct pim_upstream *up;
d62a17ae 2126 struct prefix_list *np;
2127 struct prefix g;
2128 enum prefix_list_type apply_new;
2129
c631920c 2130 np = prefix_list_lookup(PIM_AFI, nlist);
d62a17ae 2131
dd3364cb 2132 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2a27f13b 2133 if (!pim_addr_is_any(up->sg.src))
d62a17ae 2134 continue;
2135
448139e7 2136 if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags))
d62a17ae 2137 continue;
2138
2139 if (!nlist) {
9b29ea95 2140 pim_channel_del_oif(up->channel_oil, pim->regiface,
80a82b56 2141 PIM_OIF_FLAG_PROTO_GM, __func__);
d62a17ae 2142 continue;
2143 }
c631920c 2144 pim_addr_to_prefix(&g, up->sg.grp);
ab2f9e89 2145 apply_new = prefix_list_apply_ext(np, NULL, &g, true);
d62a17ae 2146 if (apply_new == PREFIX_DENY)
9b29ea95 2147 pim_channel_add_oif(up->channel_oil, pim->regiface,
80a82b56 2148 PIM_OIF_FLAG_PROTO_GM, __func__);
d62a17ae 2149 else
9b29ea95 2150 pim_channel_del_oif(up->channel_oil, pim->regiface,
80a82b56 2151 PIM_OIF_FLAG_PROTO_GM, __func__);
d62a17ae 2152 }
a7b2b1e2
DS
2153}
2154
9b29ea95 2155void pim_upstream_init(struct pim_instance *pim)
0f588989 2156{
c2cfa843 2157 char name[64];
9fb302f4 2158
772270f3 2159 snprintf(name, sizeof(name), "PIM %s Timer Wheel", pim->vrf->name);
9b29ea95 2160 pim->upstream_sg_wheel =
36417fcc 2161 wheel_init(router->master, 31000, 100, pim_upstream_hash_key,
c2cfa843 2162 pim_upstream_sg_running, name);
9fb302f4 2163
dd3364cb 2164 rb_pim_upstream_init(&pim->upstream_head);
0f588989 2165}