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