3 * Copyright (C) 2008 Everton da Silva Marques
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.
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.
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
38 #include "pim_iface.h"
40 #include "pim_zlookup.h"
41 #include "pim_upstream.h"
42 #include "pim_ifchannel.h"
43 #include "pim_neighbor.h"
45 #include "pim_zebra.h"
47 #include "pim_macro.h"
50 #include "pim_register.h"
52 #include "pim_jp_agg.h"
55 #include "pim_vxlan.h"
58 static void join_timer_stop(struct pim_upstream
*up
);
60 pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
);
61 static bool pim_upstream_sg_running_proc(struct pim_upstream
*up
);
64 * A (*,G) or a (*,*) is going away
65 * remove the parent pointer from
66 * those pointing at us
68 static void pim_upstream_remove_children(struct pim_instance
*pim
,
69 struct pim_upstream
*up
)
71 struct pim_upstream
*child
;
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
);
81 child
= pim_upstream_del(pim
, child
, __func__
);
85 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
86 pim_upstream_mroute_iif_update(
91 list_delete(&up
->sources
);
95 * A (*,G) or a (*,*) is being created
96 * Find the children that would point
99 static void pim_upstream_find_new_children(struct pim_instance
*pim
,
100 struct pim_upstream
*up
)
102 struct pim_upstream
*child
;
104 if ((up
->sg
.src
.s_addr
!= INADDR_ANY
)
105 && (up
->sg
.grp
.s_addr
!= INADDR_ANY
))
108 if ((up
->sg
.src
.s_addr
== INADDR_ANY
)
109 && (up
->sg
.grp
.s_addr
== INADDR_ANY
))
112 frr_each (rb_pim_upstream
, &pim
->upstream_head
, child
) {
113 if ((up
->sg
.grp
.s_addr
!= INADDR_ANY
)
114 && (child
->sg
.grp
.s_addr
== up
->sg
.grp
.s_addr
)
117 listnode_add_sort(up
->sources
, child
);
118 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
119 pim_upstream_mroute_iif_update(
127 * If we have a (*,*) || (S,*) there is no parent
128 * If we have a (S,G), find the (*,G)
129 * If we have a (*,G), find the (*,*)
131 static struct pim_upstream
*pim_upstream_find_parent(struct pim_instance
*pim
,
132 struct pim_upstream
*child
)
134 struct prefix_sg any
= child
->sg
;
135 struct pim_upstream
*up
= NULL
;
138 if ((child
->sg
.src
.s_addr
!= INADDR_ANY
)
139 && (child
->sg
.grp
.s_addr
!= INADDR_ANY
)) {
140 any
.src
.s_addr
= INADDR_ANY
;
141 up
= pim_upstream_find(pim
, &any
);
144 listnode_add(up
->sources
, child
);
147 * In case parent is MLAG entry copy the data to child
149 if (up
&& PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up
->flags
)) {
150 PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(child
->flags
);
151 if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up
->flags
))
152 PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(child
->flags
);
154 PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(
164 static void upstream_channel_oil_detach(struct pim_upstream
*up
)
166 struct channel_oil
*channel_oil
= up
->channel_oil
;
169 /* Detaching from channel_oil, channel_oil may exist post del,
170 but upstream would not keep reference of it
172 channel_oil
->up
= NULL
;
173 up
->channel_oil
= NULL
;
175 /* attempt to delete channel_oil; if channel_oil is being held
176 * because of other references cleanup info such as "Mute"
177 * inferred from the parent upstream
179 pim_channel_oil_upstream_deref(channel_oil
);
184 struct pim_upstream
*pim_upstream_del(struct pim_instance
*pim
,
185 struct pim_upstream
*up
, const char *name
)
187 struct listnode
*node
, *nnode
;
188 struct pim_ifchannel
*ch
;
189 bool notify_msdp
= false;
192 if (PIM_DEBUG_PIM_TRACE
)
194 "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
195 __func__
, name
, up
->sg_str
, pim
->vrf
->name
,
196 up
->ref_count
, up
->flags
,
197 up
->channel_oil
->oil_ref_count
);
199 assert(up
->ref_count
> 0);
203 if (up
->ref_count
>= 1)
207 zlog_debug("pim_upstream free vrf:%s %s flags 0x%x",
208 pim
->vrf
->name
, up
->sg_str
, up
->flags
);
210 if (pim_up_mlag_is_local(up
))
211 pim_mlag_up_local_del(pim
, up
);
213 THREAD_OFF(up
->t_ka_timer
);
214 THREAD_OFF(up
->t_rs_timer
);
215 THREAD_OFF(up
->t_msdp_reg_timer
);
217 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
218 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 0);
220 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
221 /* if a (*, G) entry in the joined state is being
223 * need to notify MSDP */
229 pim_jp_agg_upstream_verification(up
, false);
230 up
->rpf
.source_nexthop
.interface
= NULL
;
232 if (up
->sg
.src
.s_addr
!= INADDR_ANY
) {
233 if (pim
->upstream_sg_wheel
)
234 wheel_remove_item(pim
->upstream_sg_wheel
, up
);
238 pim_mroute_del(up
->channel_oil
, __func__
);
239 upstream_channel_oil_detach(up
);
241 for (ALL_LIST_ELEMENTS(up
->ifchannels
, node
, nnode
, ch
))
242 pim_ifchannel_delete(ch
);
243 list_delete(&up
->ifchannels
);
245 pim_upstream_remove_children(pim
, up
);
247 list_delete(&up
->sources
);
249 if (up
->parent
&& up
->parent
->sources
)
250 listnode_delete(up
->parent
->sources
, up
);
253 rb_pim_upstream_del(&pim
->upstream_head
, up
);
256 pim_msdp_up_del(pim
, &up
->sg
);
259 /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT
260 * and assign up->upstream_addr as INADDR_ANY.
261 * So before de-registering the upstream address, check if is not equal
262 * to INADDR_ANY. This is done in order to avoid de-registering for
263 * 255.255.255.255 which is maintained for some reason..
265 if (up
->upstream_addr
.s_addr
!= INADDR_ANY
) {
266 /* Deregister addr with Zebra NHT */
267 nht_p
.family
= AF_INET
;
268 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
269 nht_p
.u
.prefix4
= up
->upstream_addr
;
270 if (PIM_DEBUG_PIM_TRACE
)
272 "%s: Deregister upstream %s addr %pFX with Zebra NHT",
273 __func__
, up
->sg_str
, &nht_p
);
274 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
, false);
277 XFREE(MTYPE_PIM_UPSTREAM
, up
);
282 void pim_upstream_send_join(struct pim_upstream
*up
)
284 if (!up
->rpf
.source_nexthop
.interface
) {
285 if (PIM_DEBUG_PIM_TRACE
)
286 zlog_debug("%s: up %s RPF is not present", __func__
,
291 if (PIM_DEBUG_PIM_TRACE
) {
292 char rpf_str
[PREFIX_STRLEN
];
293 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_str
,
295 zlog_debug("%s: RPF'%s=%s(%s) for Interface %s", __func__
,
297 pim_upstream_state2str(up
->join_state
),
298 up
->rpf
.source_nexthop
.interface
->name
);
299 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
300 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
301 __func__
, up
->sg_str
, rpf_str
);
306 /* send Join(S,G) to the current upstream neighbor */
307 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 1 /* join */);
310 static int on_join_timer(struct thread
*t
)
312 struct pim_upstream
*up
;
316 if (!up
->rpf
.source_nexthop
.interface
) {
317 if (PIM_DEBUG_PIM_TRACE
)
318 zlog_debug("%s: up %s RPF is not present", __func__
,
324 * In the case of a HFR we will not ahve anyone to send this to.
326 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
330 * Don't send the join if the outgoing interface is a loopback
331 * But since this might change leave the join timer running
333 if (up
->rpf
.source_nexthop
334 .interface
&& !if_is_loopback(up
->rpf
.source_nexthop
.interface
))
335 pim_upstream_send_join(up
);
337 join_timer_start(up
);
342 static void join_timer_stop(struct pim_upstream
*up
)
344 struct pim_neighbor
*nbr
= NULL
;
346 THREAD_OFF(up
->t_join_timer
);
348 if (up
->rpf
.source_nexthop
.interface
)
349 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
350 up
->rpf
.rpf_addr
.u
.prefix4
);
353 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
, nbr
);
355 pim_jp_agg_upstream_verification(up
, false);
358 void join_timer_start(struct pim_upstream
*up
)
360 struct pim_neighbor
*nbr
= NULL
;
362 if (up
->rpf
.source_nexthop
.interface
) {
363 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
364 up
->rpf
.rpf_addr
.u
.prefix4
);
366 if (PIM_DEBUG_PIM_EVENTS
) {
368 "%s: starting %d sec timer for upstream (S,G)=%s",
369 __func__
, router
->t_periodic
, up
->sg_str
);
374 pim_jp_agg_add_group(nbr
->upstream_jp_agg
, up
, 1, nbr
);
376 THREAD_OFF(up
->t_join_timer
);
377 thread_add_timer(router
->master
, on_join_timer
, up
,
378 router
->t_periodic
, &up
->t_join_timer
);
380 pim_jp_agg_upstream_verification(up
, true);
384 * This is only called when we are switching the upstream
385 * J/P from one neighbor to another
387 * As such we need to remove from the old list and
388 * add to the new list.
390 void pim_upstream_join_timer_restart(struct pim_upstream
*up
,
393 // THREAD_OFF(up->t_join_timer);
394 join_timer_start(up
);
397 static void pim_upstream_join_timer_restart_msec(struct pim_upstream
*up
,
400 if (PIM_DEBUG_PIM_EVENTS
) {
401 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
402 __func__
, interval_msec
, up
->sg_str
);
405 THREAD_OFF(up
->t_join_timer
);
406 thread_add_timer_msec(router
->master
, on_join_timer
, up
, interval_msec
,
410 void pim_upstream_join_suppress(struct pim_upstream
*up
,
411 struct in_addr rpf_addr
, int holdtime
)
413 long t_joinsuppress_msec
;
414 long join_timer_remain_msec
= 0;
415 struct pim_neighbor
*nbr
= NULL
;
417 if (!up
->rpf
.source_nexthop
.interface
) {
418 if (PIM_DEBUG_PIM_TRACE
)
419 zlog_debug("%s: up %s RPF is not present", __func__
,
424 t_joinsuppress_msec
=
425 MIN(pim_if_t_suppressed_msec(up
->rpf
.source_nexthop
.interface
),
428 if (up
->t_join_timer
)
429 join_timer_remain_msec
=
430 pim_time_timer_remain_msec(up
->t_join_timer
);
432 /* Remove it from jp agg from the nbr for suppression */
433 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
434 up
->rpf
.rpf_addr
.u
.prefix4
);
436 join_timer_remain_msec
=
437 pim_time_timer_remain_msec(nbr
->jp_timer
);
441 if (PIM_DEBUG_PIM_TRACE
) {
442 char rpf_str
[INET_ADDRSTRLEN
];
443 pim_inet4_dump("<rpf?>", rpf_addr
, rpf_str
, sizeof(rpf_str
));
445 "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
446 __FILE__
, __func__
, up
->sg_str
, rpf_str
,
447 join_timer_remain_msec
, t_joinsuppress_msec
);
450 if (join_timer_remain_msec
< t_joinsuppress_msec
) {
451 if (PIM_DEBUG_PIM_TRACE
) {
453 "%s %s: suppressing Join(S,G)=%s for %ld msec",
454 __FILE__
, __func__
, up
->sg_str
,
455 t_joinsuppress_msec
);
459 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
, nbr
);
461 pim_upstream_join_timer_restart_msec(up
, t_joinsuppress_msec
);
465 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label
,
466 struct pim_upstream
*up
)
468 long join_timer_remain_msec
;
471 if (!up
->rpf
.source_nexthop
.interface
) {
472 if (PIM_DEBUG_PIM_TRACE
)
473 zlog_debug("%s: up %s RPF is not present", __func__
,
479 pim_if_t_override_msec(up
->rpf
.source_nexthop
.interface
);
481 if (up
->t_join_timer
) {
482 join_timer_remain_msec
=
483 pim_time_timer_remain_msec(up
->t_join_timer
);
485 /* upstream join tracked with neighbor jp timer */
486 struct pim_neighbor
*nbr
;
488 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
489 up
->rpf
.rpf_addr
.u
.prefix4
);
491 join_timer_remain_msec
=
492 pim_time_timer_remain_msec(nbr
->jp_timer
);
494 /* Manipulate such that override takes place */
495 join_timer_remain_msec
= t_override_msec
+ 1;
498 if (PIM_DEBUG_PIM_TRACE
) {
499 char rpf_str
[INET_ADDRSTRLEN
];
500 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
.u
.prefix4
, rpf_str
,
503 "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
504 debug_label
, up
->sg_str
, rpf_str
,
505 join_timer_remain_msec
, t_override_msec
);
508 if (join_timer_remain_msec
> t_override_msec
) {
509 if (PIM_DEBUG_PIM_TRACE
) {
511 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
512 debug_label
, up
->sg_str
, t_override_msec
);
515 pim_upstream_join_timer_restart_msec(up
, t_override_msec
);
519 static void forward_on(struct pim_upstream
*up
)
521 struct listnode
*chnode
;
522 struct listnode
*chnextnode
;
523 struct pim_ifchannel
*ch
= NULL
;
525 /* scan (S,G) state */
526 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
527 if (pim_macro_chisin_oiflist(ch
))
528 pim_forward_start(ch
);
530 } /* scan iface channel list */
533 static void forward_off(struct pim_upstream
*up
)
535 struct listnode
*chnode
;
536 struct listnode
*chnextnode
;
537 struct pim_ifchannel
*ch
;
539 /* scan per-interface (S,G) state */
540 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
542 pim_forward_stop(ch
, false);
544 } /* scan iface channel list */
547 int pim_upstream_could_register(struct pim_upstream
*up
)
549 struct pim_interface
*pim_ifp
= NULL
;
551 /* FORCE_PIMREG is a generic flag to let an app like VxLAN-AA register
552 * a source on an upstream entry even if the source is not directly
553 * connected on the IIF.
555 if (PIM_UPSTREAM_FLAG_TEST_FORCE_PIMREG(up
->flags
))
558 if (up
->rpf
.source_nexthop
.interface
)
559 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
561 if (PIM_DEBUG_PIM_TRACE
)
562 zlog_debug("%s: up %s RPF is not present", __func__
,
566 if (pim_ifp
&& PIM_I_am_DR(pim_ifp
)
567 && pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
574 /* Source registration is suppressed for SSM groups. When the SSM range changes
575 * we re-revaluate register setup for existing upstream entries */
576 void pim_upstream_register_reevaluate(struct pim_instance
*pim
)
578 struct pim_upstream
*up
;
580 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
581 /* If FHR is set CouldRegister is True. Also check if the flow
582 * is actually active; if it is not kat setup will trigger
584 * registration whenever the flow becomes active. */
585 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) ||
586 !pim_upstream_is_kat_running(up
))
589 if (pim_is_grp_ssm(pim
, up
->sg
.grp
)) {
590 /* clear the register state for SSM groups */
591 if (up
->reg_state
!= PIM_REG_NOINFO
) {
592 if (PIM_DEBUG_PIM_EVENTS
)
594 "Clear register for %s as G is now SSM",
596 /* remove regiface from the OIL if it is there*/
597 pim_channel_del_oif(up
->channel_oil
,
599 PIM_OIF_FLAG_PROTO_PIM
,
601 up
->reg_state
= PIM_REG_NOINFO
;
604 /* register ASM sources with the RP */
605 if (up
->reg_state
== PIM_REG_NOINFO
) {
606 if (PIM_DEBUG_PIM_EVENTS
)
608 "Register %s as G is now ASM",
610 pim_channel_add_oif(up
->channel_oil
,
612 PIM_OIF_FLAG_PROTO_PIM
,
614 up
->reg_state
= PIM_REG_JOIN
;
620 /* RFC7761, Section 4.2 “Data Packet Forwarding Rules” says we should
622 * 1. along the SPT if SPTbit is set
623 * 2. and along the RPT if SPTbit is not set
624 * If forwarding is hw accelerated i.e. control and dataplane components
625 * are separate you may not be able to reliably set SPT bit on intermediate
626 * routers while still fowarding on the (S,G,rpt).
628 * This macro is a slight deviation on the RFC and uses "traffic-agnostic"
629 * criteria to decide between using the RPT vs. SPT for forwarding.
631 void pim_upstream_update_use_rpt(struct pim_upstream
*up
,
637 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
640 old_use_rpt
= !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
642 /* We will use the SPT (IIF=RPF_interface(S) if -
643 * 1. We have decided to join the SPT
645 * 3. Source is directly connected
646 * 4. We are RP (parent's IIF is lo or vrf-device)
647 * In all other cases the source will stay along the RPT and
648 * IIF=RPF_interface(RP).
650 if (up
->join_state
== PIM_UPSTREAM_JOINED
||
651 PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) ||
652 pim_if_connected_to_source(
653 up
->rpf
.source_nexthop
.interface
,
655 /* XXX - need to switch this to a more efficient
658 I_am_RP(up
->pim
, up
->sg
.grp
))
660 PIM_UPSTREAM_FLAG_UNSET_USE_RPT(up
->flags
);
663 PIM_UPSTREAM_FLAG_SET_USE_RPT(up
->flags
);
665 new_use_rpt
= !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
666 if (old_use_rpt
!= new_use_rpt
) {
667 if (PIM_DEBUG_PIM_EVENTS
)
668 zlog_debug("%s switched from %s to %s",
670 old_use_rpt
?"RPT":"SPT",
671 new_use_rpt
?"RPT":"SPT");
673 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
677 /* some events like RP change require re-evaluation of SGrpt across
680 void pim_upstream_reeval_use_rpt(struct pim_instance
*pim
)
682 struct pim_upstream
*up
;
684 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
685 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
688 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
692 void pim_upstream_switch(struct pim_instance
*pim
, struct pim_upstream
*up
,
693 enum pim_upstream_state new_state
)
695 enum pim_upstream_state old_state
= up
->join_state
;
697 if (up
->upstream_addr
.s_addr
== INADDR_ANY
) {
698 if (PIM_DEBUG_PIM_EVENTS
)
699 zlog_debug("%s: RPF not configured for %s", __func__
,
704 if (!up
->rpf
.source_nexthop
.interface
) {
705 if (PIM_DEBUG_PIM_EVENTS
)
706 zlog_debug("%s: RP not reachable for %s", __func__
,
711 if (PIM_DEBUG_PIM_EVENTS
) {
712 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
713 __func__
, up
->sg_str
,
714 pim_upstream_state2str(up
->join_state
),
715 pim_upstream_state2str(new_state
));
718 up
->join_state
= new_state
;
719 if (old_state
!= new_state
)
720 up
->state_transition
= pim_time_monotonic_sec();
722 pim_upstream_update_assert_tracking_desired(up
);
724 if (new_state
== PIM_UPSTREAM_JOINED
) {
725 pim_upstream_inherited_olist_decide(pim
, up
);
726 if (old_state
!= PIM_UPSTREAM_JOINED
) {
727 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
729 pim_msdp_up_join_state_changed(pim
, up
);
730 if (pim_upstream_could_register(up
)) {
731 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
733 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
735 pim_upstream_keep_alive_timer_start(
736 up
, pim
->keep_alive_time
);
737 pim_register_join(up
);
740 pim_upstream_send_join(up
);
741 join_timer_start(up
);
744 if (old_state
!= new_state
)
745 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
749 bool send_xg_jp
= false;
752 if (old_state
== PIM_UPSTREAM_JOINED
)
753 pim_msdp_up_join_state_changed(pim
, up
);
755 if (old_state
!= new_state
) {
757 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
758 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
760 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
762 (new_use_rpt
!= old_use_rpt
) &&
764 /* we have decided to switch from the SPT back
765 * to the RPT which means we need to cancel
766 * any previously sent SGrpt prunes immediately
771 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
773 If I am RP for G then send S,G prune to its IIF. */
774 if (pim_upstream_is_sg_rpt(up
) && up
->parent
&&
775 !I_am_RP(pim
, up
->sg
.grp
))
778 pim_jp_agg_single_upstream_send(&up
->rpf
, up
,
782 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
784 "re-join RPT; *,G IIF %s S,G IIF %s ",
785 up
->parent
->rpf
.source_nexthop
.interface
?
786 up
->parent
->rpf
.source_nexthop
.interface
->name
788 up
->rpf
.source_nexthop
.interface
?
789 up
->rpf
.source_nexthop
.interface
->name
:
791 pim_jp_agg_single_upstream_send(&up
->parent
->rpf
,
799 int pim_upstream_compare(const struct pim_upstream
*up1
,
800 const struct pim_upstream
*up2
)
802 if (ntohl(up1
->sg
.grp
.s_addr
) < ntohl(up2
->sg
.grp
.s_addr
))
805 if (ntohl(up1
->sg
.grp
.s_addr
) > ntohl(up2
->sg
.grp
.s_addr
))
808 if (ntohl(up1
->sg
.src
.s_addr
) < ntohl(up2
->sg
.src
.s_addr
))
811 if (ntohl(up1
->sg
.src
.s_addr
) > ntohl(up2
->sg
.src
.s_addr
))
817 void pim_upstream_fill_static_iif(struct pim_upstream
*up
,
818 struct interface
*incoming
)
820 up
->rpf
.source_nexthop
.interface
= incoming
;
822 /* reset other parameters to matched a connected incoming interface */
823 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
824 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
826 up
->rpf
.source_nexthop
.mrib_metric_preference
=
827 ZEBRA_CONNECT_DISTANCE_DEFAULT
;
828 up
->rpf
.source_nexthop
.mrib_route_metric
= 0;
829 up
->rpf
.rpf_addr
.family
= AF_INET
;
830 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
834 static struct pim_upstream
*pim_upstream_new(struct pim_instance
*pim
,
835 struct prefix_sg
*sg
,
836 struct interface
*incoming
,
838 struct pim_ifchannel
*ch
)
840 enum pim_rpf_result rpf_result
;
841 struct pim_interface
*pim_ifp
;
842 struct pim_upstream
*up
;
844 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
848 pim_str_sg_set(sg
, up
->sg_str
);
852 rb_pim_upstream_add(&pim
->upstream_head
, up
);
853 /* Set up->upstream_addr as INADDR_ANY, if RP is not
854 * configured and retain the upstream data structure
856 if (!pim_rp_set_upstream_addr(pim
, &up
->upstream_addr
, sg
->src
,
858 if (PIM_DEBUG_PIM_TRACE
)
859 zlog_debug("%s: Received a (*,G) with no RP configured",
863 up
->parent
= pim_upstream_find_parent(pim
, up
);
864 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
865 up
->sources
= list_new();
867 (int (*)(void *, void *))pim_upstream_compare
;
871 pim_upstream_find_new_children(pim
, up
);
874 up
->t_join_timer
= NULL
;
875 up
->t_ka_timer
= NULL
;
876 up
->t_rs_timer
= NULL
;
877 up
->t_msdp_reg_timer
= NULL
;
878 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
879 up
->reg_state
= PIM_REG_NOINFO
;
880 up
->state_transition
= pim_time_monotonic_sec();
881 up
->channel_oil
= pim_channel_oil_add(pim
, &up
->sg
, __func__
);
882 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
884 up
->rpf
.source_nexthop
.interface
= NULL
;
885 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
886 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
888 up
->rpf
.source_nexthop
.mrib_metric_preference
=
889 router
->infinite_assert_metric
.metric_preference
;
890 up
->rpf
.source_nexthop
.mrib_route_metric
=
891 router
->infinite_assert_metric
.route_metric
;
892 up
->rpf
.rpf_addr
.family
= AF_INET
;
893 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
895 up
->ifchannels
= list_new();
896 up
->ifchannels
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
898 if (up
->sg
.src
.s_addr
!= INADDR_ANY
) {
899 wheel_add_item(pim
->upstream_sg_wheel
, up
);
901 /* Inherit the DF role from the parent (*, G) entry for
905 && PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up
->parent
->flags
)
906 && PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up
->parent
->flags
)) {
907 PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(up
->flags
);
910 "upstream %s inherited mlag non-df flag from parent",
915 if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up
->flags
)
916 || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
)) {
917 pim_upstream_fill_static_iif(up
, incoming
);
918 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
920 pim_upstream_update_use_rpt(up
,
921 false /*update_mroute*/);
922 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
924 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
))
925 pim_upstream_keep_alive_timer_start(
926 up
, pim
->keep_alive_time
);
927 } else if (up
->upstream_addr
.s_addr
!= INADDR_ANY
) {
928 pim_upstream_update_use_rpt(up
,
929 false /*update_mroute*/);
930 rpf_result
= pim_rpf_update(pim
, up
, NULL
, __func__
);
931 if (rpf_result
== PIM_RPF_FAILURE
) {
932 if (PIM_DEBUG_PIM_TRACE
)
934 "%s: Attempting to create upstream(%s), Unable to RPF for source",
935 __func__
, up
->sg_str
);
938 if (up
->rpf
.source_nexthop
.interface
) {
939 pim_upstream_mroute_iif_update(up
->channel_oil
,
944 /* send the entry to the MLAG peer */
945 /* XXX - duplicate send is possible here if pim_rpf_update
946 * successfully resolved the nexthop
948 if (pim_up_mlag_is_local(up
)
949 || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up
->flags
))
950 pim_mlag_up_local_add(pim
, up
);
952 if (PIM_DEBUG_PIM_TRACE
) {
954 "%s: Created Upstream %s upstream_addr %pI4 ref count %d increment",
955 __func__
, up
->sg_str
, &up
->upstream_addr
,
962 uint32_t pim_up_mlag_local_cost(struct pim_upstream
*up
)
964 if (!(pim_up_mlag_is_local(up
))
965 && !(up
->flags
& PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE
))
966 return router
->infinite_assert_metric
.route_metric
;
968 if ((up
->rpf
.source_nexthop
.interface
==
969 up
->pim
->vxlan
.peerlink_rif
) &&
970 (up
->rpf
.source_nexthop
.mrib_route_metric
<
971 (router
->infinite_assert_metric
.route_metric
-
972 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC
)))
973 return up
->rpf
.source_nexthop
.mrib_route_metric
+
974 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC
;
976 return up
->rpf
.source_nexthop
.mrib_route_metric
;
979 uint32_t pim_up_mlag_peer_cost(struct pim_upstream
*up
)
981 if (!(up
->flags
& PIM_UPSTREAM_FLAG_MASK_MLAG_PEER
))
982 return router
->infinite_assert_metric
.route_metric
;
984 return up
->mlag
.peer_mrib_metric
;
987 struct pim_upstream
*pim_upstream_find(struct pim_instance
*pim
,
988 struct prefix_sg
*sg
)
990 struct pim_upstream lookup
;
991 struct pim_upstream
*up
= NULL
;
994 up
= rb_pim_upstream_find(&pim
->upstream_head
, &lookup
);
998 struct pim_upstream
*pim_upstream_find_or_add(struct prefix_sg
*sg
,
999 struct interface
*incoming
,
1000 int flags
, const char *name
)
1002 struct pim_interface
*pim_ifp
= incoming
->info
;
1004 return (pim_upstream_add(pim_ifp
->pim
, sg
, incoming
, flags
, name
,
1008 void pim_upstream_ref(struct pim_upstream
*up
, int flags
, const char *name
)
1010 /* if a local MLAG reference is being created we need to send the mroute
1013 if (!PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up
->flags
) &&
1014 PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags
)) {
1015 PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(up
->flags
);
1016 pim_mlag_up_local_add(up
->pim
, up
);
1019 /* when we go from non-FHR to FHR we need to re-eval traffic
1022 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) &&
1023 PIM_UPSTREAM_FLAG_TEST_FHR(flags
)) {
1024 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1025 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
1028 /* re-eval joinDesired; clearing peer-msdp-sa flag can
1029 * cause JD to change
1031 if (!PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up
->flags
) &&
1032 PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags
)) {
1033 PIM_UPSTREAM_FLAG_SET_SRC_MSDP(up
->flags
);
1034 pim_upstream_update_join_desired(up
->pim
, up
);
1039 if (PIM_DEBUG_PIM_TRACE
)
1040 zlog_debug("%s(%s): upstream %s ref count %d increment",
1041 __func__
, name
, up
->sg_str
, up
->ref_count
);
1044 struct pim_upstream
*pim_upstream_add(struct pim_instance
*pim
,
1045 struct prefix_sg
*sg
,
1046 struct interface
*incoming
, int flags
,
1048 struct pim_ifchannel
*ch
)
1050 struct pim_upstream
*up
= NULL
;
1053 up
= pim_upstream_find(pim
, sg
);
1055 pim_upstream_ref(up
, flags
, name
);
1058 up
= pim_upstream_new(pim
, sg
, incoming
, flags
, ch
);
1061 if (PIM_DEBUG_PIM_TRACE
) {
1063 zlog_debug("%s(%s): %s, iif %pFX (%s) found: %d: ref_count: %d",
1065 up
->sg_str
, &up
->rpf
.rpf_addr
, up
->rpf
.source_nexthop
.interface
?
1066 up
->rpf
.source_nexthop
.interface
->name
: "Unknown" ,
1067 found
, up
->ref_count
);
1069 zlog_debug("%s(%s): (%s) failure to create", __func__
,
1070 name
, pim_str_sg_dump(sg
));
1077 * Passed in up must be the upstream for ch. starch is NULL if no
1079 * This function is copied over from
1080 * pim_upstream_evaluate_join_desired_interface but limited to
1081 * parent (*,G)'s includes/joins.
1083 int pim_upstream_eval_inherit_if(struct pim_upstream
*up
,
1084 struct pim_ifchannel
*ch
,
1085 struct pim_ifchannel
*starch
)
1087 /* if there is an explicit prune for this interface we cannot
1091 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1095 /* Check if the OIF can be inherited fron the (*,G) entry
1098 if (!pim_macro_ch_lost_assert(starch
)
1099 && pim_macro_chisin_joins_or_include(starch
))
1107 * Passed in up must be the upstream for ch. starch is NULL if no
1110 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream
*up
,
1111 struct pim_ifchannel
*ch
,
1112 struct pim_ifchannel
*starch
)
1115 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1118 if (!pim_macro_ch_lost_assert(ch
)
1119 && pim_macro_chisin_joins_or_include(ch
))
1127 /* XXX: check on this with donald
1128 * we are looking for PIM_IF_FLAG_MASK_S_G_RPT in
1132 if (PIM_IF_FLAG_TEST_S_G_RPT(starch
->upstream
->flags
))
1136 if (!pim_macro_ch_lost_assert(starch
)
1137 && pim_macro_chisin_joins_or_include(starch
))
1144 /* Returns true if immediate OIL is empty and is used to evaluate
1145 * JoinDesired. See pim_upstream_evaluate_join_desired.
1147 static bool pim_upstream_empty_immediate_olist(struct pim_instance
*pim
,
1148 struct pim_upstream
*up
)
1150 struct interface
*ifp
;
1151 struct pim_ifchannel
*ch
;
1153 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1157 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1161 /* If we have even one immediate OIF we can return with
1164 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1167 } /* scan iface channel list */
1169 /* immediate_oil is empty */
1174 static inline bool pim_upstream_is_msdp_peer_sa(struct pim_upstream
*up
)
1176 return PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up
->flags
);
1180 * bool JoinDesired(*,G) {
1181 * if (immediate_olist(*,G) != NULL)
1187 * bool JoinDesired(S,G) {
1188 * return( immediate_olist(S,G) != NULL
1189 * OR ( KeepaliveTimer(S,G) is running
1190 * AND inherited_olist(S,G) != NULL ) )
1193 bool pim_upstream_evaluate_join_desired(struct pim_instance
*pim
,
1194 struct pim_upstream
*up
)
1199 empty_imm_oil
= pim_upstream_empty_immediate_olist(pim
, up
);
1202 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
1203 return !empty_imm_oil
;
1208 empty_inh_oil
= pim_upstream_empty_inherited_olist(up
);
1209 if (!empty_inh_oil
&&
1210 (pim_upstream_is_kat_running(up
) ||
1211 pim_upstream_is_msdp_peer_sa(up
)))
1218 See also pim_upstream_evaluate_join_desired() above.
1220 void pim_upstream_update_join_desired(struct pim_instance
*pim
,
1221 struct pim_upstream
*up
)
1223 int was_join_desired
; /* boolean */
1224 int is_join_desired
; /* boolean */
1226 was_join_desired
= PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up
->flags
);
1228 is_join_desired
= pim_upstream_evaluate_join_desired(pim
, up
);
1229 if (is_join_desired
)
1230 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up
->flags
);
1232 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up
->flags
);
1234 /* switched from false to true */
1235 if (is_join_desired
&& (up
->join_state
== PIM_UPSTREAM_NOTJOINED
)) {
1236 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
1240 /* switched from true to false */
1241 if (!is_join_desired
&& was_join_desired
) {
1242 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_NOTJOINED
);
1248 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
1249 Transitions from Joined State
1250 RPF'(S,G) GenID changes
1252 The upstream (S,G) state machine remains in Joined state. If the
1253 Join Timer is set to expire in more than t_override seconds, reset
1254 it so that it expires after t_override seconds.
1256 void pim_upstream_rpf_genid_changed(struct pim_instance
*pim
,
1257 struct in_addr neigh_addr
)
1259 struct pim_upstream
*up
;
1262 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1264 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
1265 if (PIM_DEBUG_PIM_TRACE
) {
1266 char neigh_str
[INET_ADDRSTRLEN
];
1267 char rpf_addr_str
[PREFIX_STRLEN
];
1268 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
,
1270 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_addr_str
,
1271 sizeof(rpf_addr_str
));
1273 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
1274 __func__
, neigh_str
, up
->sg_str
, pim
->vrf
->name
,
1275 up
->join_state
== PIM_UPSTREAM_JOINED
,
1279 /* consider only (S,G) upstream in Joined state */
1280 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
1283 /* match RPF'(S,G)=neigh_addr */
1284 if (up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
!= neigh_addr
.s_addr
)
1287 pim_upstream_join_timer_decrease_to_t_override(
1288 "RPF'(S,G) GenID change", up
);
1293 void pim_upstream_rpf_interface_changed(struct pim_upstream
*up
,
1294 struct interface
*old_rpf_ifp
)
1296 struct listnode
*chnode
;
1297 struct listnode
*chnextnode
;
1298 struct pim_ifchannel
*ch
;
1300 /* search all ifchannels */
1301 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1302 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
1304 /* RPF_interface(S) was NOT I */
1305 (old_rpf_ifp
== ch
->interface
) &&
1306 /* RPF_interface(S) stopped being I */
1307 (ch
->upstream
->rpf
.source_nexthop
1309 (ch
->upstream
->rpf
.source_nexthop
1310 .interface
!= ch
->interface
)) {
1311 assert_action_a5(ch
);
1313 } /* PIM_IFASSERT_I_AM_LOSER */
1315 pim_ifchannel_update_assert_tracking_desired(ch
);
1319 void pim_upstream_update_could_assert(struct pim_upstream
*up
)
1321 struct listnode
*chnode
;
1322 struct listnode
*chnextnode
;
1323 struct pim_ifchannel
*ch
;
1325 /* scan per-interface (S,G) state */
1326 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1327 pim_ifchannel_update_could_assert(ch
);
1328 } /* scan iface channel list */
1331 void pim_upstream_update_my_assert_metric(struct pim_upstream
*up
)
1333 struct listnode
*chnode
;
1334 struct listnode
*chnextnode
;
1335 struct pim_ifchannel
*ch
;
1337 /* scan per-interface (S,G) state */
1338 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1339 pim_ifchannel_update_my_assert_metric(ch
);
1341 } /* scan iface channel list */
1344 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
)
1346 struct listnode
*chnode
;
1347 struct listnode
*chnextnode
;
1348 struct pim_interface
*pim_ifp
;
1349 struct pim_ifchannel
*ch
;
1351 /* scan per-interface (S,G) state */
1352 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1355 pim_ifp
= ch
->interface
->info
;
1359 pim_ifchannel_update_assert_tracking_desired(ch
);
1361 } /* scan iface channel list */
1364 /* When kat is stopped CouldRegister goes to false so we need to
1365 * transition the (S, G) on FHR to NI state and remove reg tunnel
1367 static void pim_upstream_fhr_kat_expiry(struct pim_instance
*pim
,
1368 struct pim_upstream
*up
)
1370 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
1373 if (PIM_DEBUG_PIM_TRACE
)
1374 zlog_debug("kat expired on %s; clear fhr reg state",
1377 /* stop reg-stop timer */
1378 THREAD_OFF(up
->t_rs_timer
);
1379 /* remove regiface from the OIL if it is there*/
1380 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1381 PIM_OIF_FLAG_PROTO_PIM
, __func__
);
1382 /* clear the register state */
1383 up
->reg_state
= PIM_REG_NOINFO
;
1384 PIM_UPSTREAM_FLAG_UNSET_FHR(up
->flags
);
1387 /* When kat is started CouldRegister can go to true. And if it does we
1388 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1390 static void pim_upstream_fhr_kat_start(struct pim_upstream
*up
)
1392 if (pim_upstream_could_register(up
)) {
1393 if (PIM_DEBUG_PIM_TRACE
)
1395 "kat started on %s; set fhr reg state to joined",
1398 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1399 if (up
->reg_state
== PIM_REG_NOINFO
)
1400 pim_register_join(up
);
1401 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
1406 * On an RP, the PMBR value must be cleared when the
1407 * Keepalive Timer expires
1408 * KAT expiry indicates that flow is inactive. If the flow was created or
1409 * maintained by activity now is the time to deref it.
1411 struct pim_upstream
*pim_upstream_keep_alive_timer_proc(
1412 struct pim_upstream
*up
)
1414 struct pim_instance
*pim
;
1416 pim
= up
->channel_oil
->pim
;
1418 if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up
->flags
)) {
1419 /* if the router is a PIM vxlan encapsulator we prevent expiry
1420 * of KAT as the mroute is pre-setup without any traffic
1422 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1426 if (I_am_RP(pim
, up
->sg
.grp
)) {
1427 pim_br_clear_pmbr(&up
->sg
);
1429 * We need to do more here :)
1430 * But this is the start.
1434 /* source is no longer active - pull the SA from MSDP's cache */
1435 pim_msdp_sa_local_del(pim
, &up
->sg
);
1437 /* JoinDesired can change when KAT is started or stopped */
1438 pim_upstream_update_join_desired(pim
, up
);
1440 /* if entry was created because of activity we need to deref it */
1441 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1442 pim_upstream_fhr_kat_expiry(pim
, up
);
1443 if (PIM_DEBUG_PIM_TRACE
)
1445 "kat expired on %s[%s]; remove stream reference",
1446 up
->sg_str
, pim
->vrf
->name
);
1447 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up
->flags
);
1449 /* Return if upstream entry got deleted.*/
1450 if (!pim_upstream_del(pim
, up
, __func__
))
1453 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
)) {
1454 PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up
->flags
);
1456 if (!pim_upstream_del(pim
, up
, __func__
))
1460 /* upstream reference would have been added to track the local
1461 * membership if it is LHR. We have to clear it when KAT expires.
1462 * Otherwise would result in stale entry with uncleared ref count.
1464 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
1465 struct pim_upstream
*parent
= up
->parent
;
1467 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1468 up
= pim_upstream_del(pim
, up
, __func__
);
1471 pim_jp_agg_single_upstream_send(&parent
->rpf
, parent
,
1478 static int pim_upstream_keep_alive_timer(struct thread
*t
)
1480 struct pim_upstream
*up
;
1484 /* pull the stats and re-check */
1485 if (pim_upstream_sg_running_proc(up
))
1486 /* kat was restarted because of new activity */
1489 pim_upstream_keep_alive_timer_proc(up
);
1493 void pim_upstream_keep_alive_timer_start(struct pim_upstream
*up
, uint32_t time
)
1495 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1496 if (PIM_DEBUG_PIM_TRACE
)
1497 zlog_debug("kat start on %s with no stream reference",
1500 THREAD_OFF(up
->t_ka_timer
);
1501 thread_add_timer(router
->master
, pim_upstream_keep_alive_timer
, up
,
1502 time
, &up
->t_ka_timer
);
1504 /* any time keepalive is started against a SG we will have to
1505 * re-evaluate our active source database */
1506 pim_msdp_sa_local_update(up
);
1507 /* JoinDesired can change when KAT is started or stopped */
1508 pim_upstream_update_join_desired(up
->pim
, up
);
1511 /* MSDP on RP needs to know if a source is registerable to this RP */
1512 static int pim_upstream_msdp_reg_timer(struct thread
*t
)
1514 struct pim_upstream
*up
= THREAD_ARG(t
);
1515 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1517 /* source is no longer active - pull the SA from MSDP's cache */
1518 pim_msdp_sa_local_del(pim
, &up
->sg
);
1521 void pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1523 THREAD_OFF(up
->t_msdp_reg_timer
);
1524 thread_add_timer(router
->master
, pim_upstream_msdp_reg_timer
, up
,
1525 PIM_MSDP_REG_RXED_PERIOD
, &up
->t_msdp_reg_timer
);
1527 pim_msdp_sa_local_update(up
);
1531 * 4.2.1 Last-Hop Switchover to the SPT
1533 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1534 * RP. Once traffic from sources to joined groups arrives at a last-hop
1535 * router, it has the option of switching to receive the traffic on a
1536 * shortest path tree (SPT).
1538 * The decision for a router to switch to the SPT is controlled as
1542 * CheckSwitchToSpt(S,G) {
1543 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1544 * (+) pim_include(S,G) != NULL )
1545 * AND SwitchToSptDesired(S,G) ) {
1546 * # Note: Restarting the KAT will result in the SPT switch
1547 * set KeepaliveTimer(S,G) to Keepalive_Period
1551 * SwitchToSptDesired(S,G) is a policy function that is implementation
1552 * defined. An "infinite threshold" policy can be implemented by making
1553 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1554 * first packet" policy can be implemented by making
1555 * SwitchToSptDesired(S,G) return true once a single packet has been
1556 * received for the source and group.
1558 int pim_upstream_switch_to_spt_desired_on_rp(struct pim_instance
*pim
,
1559 struct prefix_sg
*sg
)
1561 if (I_am_RP(pim
, sg
->grp
))
1567 int pim_upstream_is_sg_rpt(struct pim_upstream
*up
)
1569 struct listnode
*chnode
;
1570 struct pim_ifchannel
*ch
;
1572 for (ALL_LIST_ELEMENTS_RO(up
->ifchannels
, chnode
, ch
)) {
1573 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1580 * After receiving a packet set SPTbit:
1582 * Update_SPTbit(S,G,iif) {
1583 * if ( iif == RPF_interface(S)
1584 * AND JoinDesired(S,G) == true
1585 * AND ( DirectlyConnected(S) == true
1586 * OR RPF_interface(S) != RPF_interface(RP(G))
1587 * OR inherited_olist(S,G,rpt) == NULL
1588 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1589 * ( RPF'(S,G) != NULL ) )
1590 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1591 * Set SPTbit(S,G) to true
1595 void pim_upstream_set_sptbit(struct pim_upstream
*up
,
1596 struct interface
*incoming
)
1598 struct pim_upstream
*starup
= up
->parent
;
1600 // iif == RPF_interfvace(S)
1601 if (up
->rpf
.source_nexthop
.interface
!= incoming
) {
1602 if (PIM_DEBUG_PIM_TRACE
)
1604 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1605 __func__
, incoming
->name
,
1606 up
->rpf
.source_nexthop
.interface
->name
);
1610 // AND JoinDesired(S,G) == true
1611 if (!pim_upstream_evaluate_join_desired(up
->channel_oil
->pim
, up
)) {
1612 if (PIM_DEBUG_PIM_TRACE
)
1613 zlog_debug("%s: %s Join is not Desired", __func__
,
1618 // DirectlyConnected(S) == true
1619 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1621 if (PIM_DEBUG_PIM_TRACE
)
1622 zlog_debug("%s: %s is directly connected to the source",
1623 __func__
, up
->sg_str
);
1624 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1628 // OR RPF_interface(S) != RPF_interface(RP(G))
1630 || up
->rpf
.source_nexthop
1631 .interface
!= starup
->rpf
.source_nexthop
.interface
) {
1632 struct pim_upstream
*starup
= up
->parent
;
1634 if (PIM_DEBUG_PIM_TRACE
)
1636 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1637 __func__
, up
->sg_str
);
1638 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1640 pim_jp_agg_single_upstream_send(&starup
->rpf
, starup
, true);
1644 // OR inherited_olist(S,G,rpt) == NULL
1645 if (pim_upstream_is_sg_rpt(up
)
1646 && pim_upstream_empty_inherited_olist(up
)) {
1647 if (PIM_DEBUG_PIM_TRACE
)
1648 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1649 __func__
, up
->sg_str
);
1650 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1654 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1655 // ( RPF'(S,G) != NULL ) )
1656 if (up
->parent
&& pim_rpf_is_same(&up
->rpf
, &up
->parent
->rpf
)) {
1657 if (PIM_DEBUG_PIM_TRACE
)
1658 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1659 __func__
, up
->sg_str
);
1660 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1667 const char *pim_upstream_state2str(enum pim_upstream_state join_state
)
1669 switch (join_state
) {
1670 case PIM_UPSTREAM_NOTJOINED
:
1672 case PIM_UPSTREAM_JOINED
:
1678 const char *pim_reg_state2str(enum pim_reg_state reg_state
, char *state_str
,
1679 size_t state_str_len
)
1681 switch (reg_state
) {
1682 case PIM_REG_NOINFO
:
1683 strlcpy(state_str
, "RegNoInfo", state_str_len
);
1686 strlcpy(state_str
, "RegJoined", state_str_len
);
1688 case PIM_REG_JOIN_PENDING
:
1689 strlcpy(state_str
, "RegJoinPend", state_str_len
);
1692 strlcpy(state_str
, "RegPrune", state_str_len
);
1695 strlcpy(state_str
, "RegUnknown", state_str_len
);
1700 static int pim_upstream_register_stop_timer(struct thread
*t
)
1702 struct pim_interface
*pim_ifp
;
1703 struct pim_instance
*pim
;
1704 struct pim_upstream
*up
;
1706 pim
= up
->channel_oil
->pim
;
1708 if (PIM_DEBUG_PIM_TRACE
) {
1709 char state_str
[PIM_REG_STATE_STR_LEN
];
1710 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1711 __func__
, up
->sg_str
, pim
->vrf
->name
,
1712 pim_reg_state2str(up
->reg_state
, state_str
,
1713 sizeof(state_str
)));
1716 switch (up
->reg_state
) {
1717 case PIM_REG_JOIN_PENDING
:
1718 up
->reg_state
= PIM_REG_JOIN
;
1719 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1720 PIM_OIF_FLAG_PROTO_PIM
,
1722 pim_vxlan_update_sg_reg_state(pim
, up
, true /*reg_join*/);
1727 /* This is equalent to Couldreg -> False */
1728 if (!up
->rpf
.source_nexthop
.interface
) {
1729 if (PIM_DEBUG_PIM_TRACE
)
1730 zlog_debug("%s: up %s RPF is not present",
1731 __func__
, up
->sg_str
);
1732 up
->reg_state
= PIM_REG_NOINFO
;
1736 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1738 if (PIM_DEBUG_PIM_TRACE
)
1740 "%s: Interface: %s is not configured for pim",
1742 up
->rpf
.source_nexthop
.interface
->name
);
1745 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1746 pim_upstream_start_register_stop_timer(up
, 1);
1748 if (((up
->channel_oil
->cc
.lastused
/ 100)
1749 > pim
->keep_alive_time
)
1750 && (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
))) {
1751 if (PIM_DEBUG_PIM_TRACE
)
1753 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1757 pim_null_register_send(up
);
1766 void pim_upstream_start_register_stop_timer(struct pim_upstream
*up
,
1771 THREAD_OFF(up
->t_rs_timer
);
1773 if (!null_register
) {
1774 uint32_t lower
= (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1775 uint32_t upper
= (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1776 time
= lower
+ (frr_weak_random() % (upper
- lower
+ 1))
1777 - PIM_REGISTER_PROBE_PERIOD
;
1779 time
= PIM_REGISTER_PROBE_PERIOD
;
1781 if (PIM_DEBUG_PIM_TRACE
) {
1783 "%s: (S,G)=%s Starting upstream register stop timer %d",
1784 __func__
, up
->sg_str
, time
);
1786 thread_add_timer(router
->master
, pim_upstream_register_stop_timer
, up
,
1787 time
, &up
->t_rs_timer
);
1790 int pim_upstream_inherited_olist_decide(struct pim_instance
*pim
,
1791 struct pim_upstream
*up
)
1793 struct interface
*ifp
;
1794 struct pim_ifchannel
*ch
, *starch
;
1795 struct pim_upstream
*starup
= up
->parent
;
1796 int output_intf
= 0;
1798 if (!up
->rpf
.source_nexthop
.interface
)
1799 if (PIM_DEBUG_PIM_TRACE
)
1800 zlog_debug("%s: up %s RPF is not present", __func__
,
1803 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1804 struct pim_interface
*pim_ifp
;
1808 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1811 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
1818 pim_ifp
= ifp
->info
;
1819 if (PIM_I_am_DualActive(pim_ifp
)
1820 && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up
->flags
)
1821 && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up
->flags
)
1822 || !PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up
->flags
)))
1824 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1829 flag
= PIM_OIF_FLAG_PROTO_STAR
;
1831 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch
->flags
))
1832 flag
= PIM_OIF_FLAG_PROTO_IGMP
;
1833 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch
->flags
))
1834 flag
|= PIM_OIF_FLAG_PROTO_PIM
;
1837 pim_channel_add_oif(up
->channel_oil
, ifp
, flag
,
1847 * For a given upstream, determine the inherited_olist
1850 * inherited_olist(S,G,rpt) =
1851 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1852 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1853 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1855 * inherited_olist(S,G) =
1856 * inherited_olist(S,G,rpt) (+)
1857 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1859 * return 1 if there are any output interfaces
1860 * return 0 if there are not any output interfaces
1862 int pim_upstream_inherited_olist(struct pim_instance
*pim
,
1863 struct pim_upstream
*up
)
1865 int output_intf
= pim_upstream_inherited_olist_decide(pim
, up
);
1868 * If we have output_intf switch state to Join and work like normal
1869 * If we don't have an output_intf that means we are probably a
1870 * switch on a stick so turn on forwarding to just accept the
1871 * incoming packets so we don't bother the other stuff!
1873 pim_upstream_update_join_desired(pim
, up
);
1881 int pim_upstream_empty_inherited_olist(struct pim_upstream
*up
)
1883 return pim_channel_oil_empty(up
->channel_oil
);
1887 * When we have a new neighbor,
1888 * find upstreams that don't have their rpf_addr
1889 * set and see if the new neighbor allows
1890 * the join to be sent
1892 void pim_upstream_find_new_rpf(struct pim_instance
*pim
)
1894 struct pim_upstream
*up
;
1896 enum pim_rpf_result rpf_result
;
1899 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1901 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
1902 if (up
->upstream_addr
.s_addr
== INADDR_ANY
) {
1903 if (PIM_DEBUG_PIM_TRACE
)
1905 "%s: RP not configured for Upstream %s",
1906 __func__
, up
->sg_str
);
1910 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
1911 if (PIM_DEBUG_PIM_TRACE
)
1913 "%s: Upstream %s without a path to send join, checking",
1914 __func__
, up
->sg_str
);
1915 old
.source_nexthop
.interface
=
1916 up
->rpf
.source_nexthop
.interface
;
1917 rpf_result
= pim_rpf_update(pim
, up
, &old
, __func__
);
1918 if (rpf_result
== PIM_RPF_CHANGED
||
1919 (rpf_result
== PIM_RPF_FAILURE
&&
1920 old
.source_nexthop
.interface
))
1921 pim_zebra_upstream_rpf_changed(pim
, up
, &old
);
1922 /* update kernel multicast forwarding cache (MFC) */
1923 pim_upstream_mroute_iif_update(up
->channel_oil
,
1927 pim_zebra_update_all_interfaces(pim
);
1930 unsigned int pim_upstream_hash_key(const void *arg
)
1932 const struct pim_upstream
*up
= arg
;
1934 return jhash_2words(up
->sg
.src
.s_addr
, up
->sg
.grp
.s_addr
, 0);
1937 void pim_upstream_terminate(struct pim_instance
*pim
)
1939 struct pim_upstream
*up
;
1941 while ((up
= rb_pim_upstream_first(&pim
->upstream_head
))) {
1942 pim_upstream_del(pim
, up
, __func__
);
1945 rb_pim_upstream_fini(&pim
->upstream_head
);
1947 if (pim
->upstream_sg_wheel
)
1948 wheel_delete(pim
->upstream_sg_wheel
);
1949 pim
->upstream_sg_wheel
= NULL
;
1952 bool pim_upstream_equal(const void *arg1
, const void *arg2
)
1954 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1955 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1957 if ((up1
->sg
.grp
.s_addr
== up2
->sg
.grp
.s_addr
)
1958 && (up1
->sg
.src
.s_addr
== up2
->sg
.src
.s_addr
))
1964 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1965 * the cases where kat has to be restarted on rxing traffic -
1967 * if( DirectlyConnected(S) == true AND iif == RPF_interface(S) ) {
1968 * set KeepaliveTimer(S,G) to Keepalive_Period
1969 * # Note: a register state transition or UpstreamJPState(S,G)
1970 * # transition may happen as a result of restarting
1971 * # KeepaliveTimer, and must be dealt with here.
1973 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1974 * inherited_olist(S,G) != NULL ) {
1975 * set KeepaliveTimer(S,G) to Keepalive_Period
1978 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1980 struct channel_oil
*c_oil
= up
->channel_oil
;
1981 struct interface
*ifp
= up
->rpf
.source_nexthop
.interface
;
1982 struct pim_interface
*pim_ifp
;
1984 /* "iif == RPF_interface(S)" check is not easy to do as the info
1985 * we get from the kernel/ASIC is really a "lookup/key hit".
1986 * So we will do an approximate check here to avoid starting KAT
1987 * because of (S,G,rpt) forwarding on a non-LHR.
1992 pim_ifp
= ifp
->info
;
1993 if (pim_ifp
->mroute_vif_index
!= c_oil
->oil
.mfcc_parent
)
1996 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
2001 if ((up
->join_state
== PIM_UPSTREAM_JOINED
)
2002 && !pim_upstream_empty_inherited_olist(up
)) {
2009 static bool pim_upstream_sg_running_proc(struct pim_upstream
*up
)
2012 struct pim_instance
*pim
= up
->pim
;
2014 if (!up
->channel_oil
->installed
)
2017 pim_mroute_update_counters(up
->channel_oil
);
2019 // Have we seen packets?
2020 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
)
2021 && (up
->channel_oil
->cc
.lastused
/ 100 > 30)) {
2022 if (PIM_DEBUG_PIM_TRACE
) {
2024 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
2025 __func__
, up
->sg_str
, pim
->vrf
->name
,
2026 up
->channel_oil
->cc
.oldpktcnt
,
2027 up
->channel_oil
->cc
.pktcnt
,
2028 up
->channel_oil
->cc
.lastused
/ 100);
2033 if (pim_upstream_kat_start_ok(up
)) {
2034 /* Add a source reference to the stream if
2035 * one doesn't already exist */
2036 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
2037 if (PIM_DEBUG_PIM_TRACE
)
2039 "source reference created on kat restart %s[%s]",
2040 up
->sg_str
, pim
->vrf
->name
);
2042 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
,
2044 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
2045 pim_upstream_fhr_kat_start(up
);
2047 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
2049 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
2050 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
2054 if ((up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
) &&
2055 (up
->rpf
.source_nexthop
.interface
)) {
2056 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
2063 * Code to check and see if we've received packets on a S,G mroute
2064 * and if so to set the SPT bit appropriately
2066 static void pim_upstream_sg_running(void *arg
)
2068 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
2069 struct pim_instance
*pim
= up
->channel_oil
->pim
;
2071 // No packet can have arrived here if this is the case
2072 if (!up
->channel_oil
->installed
) {
2073 if (PIM_DEBUG_TRACE
)
2074 zlog_debug("%s: %s%s is not installed in mroute",
2075 __func__
, up
->sg_str
, pim
->vrf
->name
);
2080 * This is a bit of a hack
2081 * We've noted that we should rescan but
2082 * we've missed the window for doing so in
2083 * pim_zebra.c for some reason. I am
2084 * only doing this at this point in time
2085 * to get us up and working for the moment
2087 if (up
->channel_oil
->oil_inherited_rescan
) {
2088 if (PIM_DEBUG_TRACE
)
2090 "%s: Handling unscanned inherited_olist for %s[%s]",
2091 __func__
, up
->sg_str
, pim
->vrf
->name
);
2092 pim_upstream_inherited_olist_decide(pim
, up
);
2093 up
->channel_oil
->oil_inherited_rescan
= 0;
2096 pim_upstream_sg_running_proc(up
);
2099 void pim_upstream_add_lhr_star_pimreg(struct pim_instance
*pim
)
2101 struct pim_upstream
*up
;
2103 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
2104 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
2107 if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
))
2110 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
2111 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
2115 void pim_upstream_spt_prefix_list_update(struct pim_instance
*pim
,
2116 struct prefix_list
*pl
)
2118 const char *pname
= prefix_list_name(pl
);
2120 if (pim
->spt
.plist
&& strcmp(pim
->spt
.plist
, pname
) == 0) {
2121 pim_upstream_remove_lhr_star_pimreg(pim
, pname
);
2126 * nlist -> The new prefix list
2128 * Per Group Application of pimreg to the OIL
2129 * If the prefix list tells us DENY then
2130 * we need to Switchover to SPT immediate
2131 * so add the pimreg.
2132 * If the prefix list tells us to ACCEPT than
2133 * we need to Never do the SPT so remove
2137 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance
*pim
,
2140 struct pim_upstream
*up
;
2141 struct prefix_list
*np
;
2143 enum prefix_list_type apply_new
;
2145 np
= prefix_list_lookup(AFI_IP
, nlist
);
2148 g
.prefixlen
= IPV4_MAX_PREFIXLEN
;
2150 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
2151 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
2154 if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
))
2158 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
2159 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
2162 g
.u
.prefix4
= up
->sg
.grp
;
2163 apply_new
= prefix_list_apply(np
, &g
);
2164 if (apply_new
== PREFIX_DENY
)
2165 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
2166 PIM_OIF_FLAG_PROTO_IGMP
,
2169 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
2170 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
2174 void pim_upstream_init(struct pim_instance
*pim
)
2178 snprintf(name
, sizeof(name
), "PIM %s Timer Wheel", pim
->vrf
->name
);
2179 pim
->upstream_sg_wheel
=
2180 wheel_init(router
->master
, 31000, 100, pim_upstream_hash_key
,
2181 pim_upstream_sg_running
, name
);
2183 rb_pim_upstream_init(&pim
->upstream_head
);