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