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