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