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
) {
271 char buf
[PREFIX2STR_BUFFER
];
272 prefix2str(&nht_p
, buf
, sizeof(buf
));
274 "%s: Deregister upstream %s addr %s with Zebra NHT",
275 __func__
, up
->sg_str
, buf
);
277 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
, false);
280 XFREE(MTYPE_PIM_UPSTREAM
, up
);
285 void pim_upstream_send_join(struct pim_upstream
*up
)
287 if (!up
->rpf
.source_nexthop
.interface
) {
288 if (PIM_DEBUG_PIM_TRACE
)
289 zlog_debug("%s: up %s RPF is not present", __func__
,
294 if (PIM_DEBUG_PIM_TRACE
) {
295 char rpf_str
[PREFIX_STRLEN
];
296 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_str
,
298 zlog_debug("%s: RPF'%s=%s(%s) for Interface %s", __func__
,
300 pim_upstream_state2str(up
->join_state
),
301 up
->rpf
.source_nexthop
.interface
->name
);
302 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
303 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
304 __func__
, up
->sg_str
, rpf_str
);
309 /* send Join(S,G) to the current upstream neighbor */
310 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 1 /* join */);
313 static int on_join_timer(struct thread
*t
)
315 struct pim_upstream
*up
;
319 if (!up
->rpf
.source_nexthop
.interface
) {
320 if (PIM_DEBUG_PIM_TRACE
)
321 zlog_debug("%s: up %s RPF is not present", __func__
,
327 * In the case of a HFR we will not ahve anyone to send this to.
329 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
333 * Don't send the join if the outgoing interface is a loopback
334 * But since this might change leave the join timer running
336 if (up
->rpf
.source_nexthop
337 .interface
&& !if_is_loopback(up
->rpf
.source_nexthop
.interface
))
338 pim_upstream_send_join(up
);
340 join_timer_start(up
);
345 static void join_timer_stop(struct pim_upstream
*up
)
347 struct pim_neighbor
*nbr
= NULL
;
349 THREAD_OFF(up
->t_join_timer
);
351 if (up
->rpf
.source_nexthop
.interface
)
352 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
353 up
->rpf
.rpf_addr
.u
.prefix4
);
356 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
, nbr
);
358 pim_jp_agg_upstream_verification(up
, false);
361 void join_timer_start(struct pim_upstream
*up
)
363 struct pim_neighbor
*nbr
= NULL
;
365 if (up
->rpf
.source_nexthop
.interface
) {
366 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
367 up
->rpf
.rpf_addr
.u
.prefix4
);
369 if (PIM_DEBUG_PIM_EVENTS
) {
371 "%s: starting %d sec timer for upstream (S,G)=%s",
372 __func__
, router
->t_periodic
, up
->sg_str
);
377 pim_jp_agg_add_group(nbr
->upstream_jp_agg
, up
, 1, nbr
);
379 THREAD_OFF(up
->t_join_timer
);
380 thread_add_timer(router
->master
, on_join_timer
, up
,
381 router
->t_periodic
, &up
->t_join_timer
);
383 pim_jp_agg_upstream_verification(up
, true);
387 * This is only called when we are switching the upstream
388 * J/P from one neighbor to another
390 * As such we need to remove from the old list and
391 * add to the new list.
393 void pim_upstream_join_timer_restart(struct pim_upstream
*up
,
396 // THREAD_OFF(up->t_join_timer);
397 join_timer_start(up
);
400 static void pim_upstream_join_timer_restart_msec(struct pim_upstream
*up
,
403 if (PIM_DEBUG_PIM_EVENTS
) {
404 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
405 __func__
, interval_msec
, up
->sg_str
);
408 THREAD_OFF(up
->t_join_timer
);
409 thread_add_timer_msec(router
->master
, on_join_timer
, up
, interval_msec
,
413 void pim_upstream_join_suppress(struct pim_upstream
*up
,
414 struct in_addr rpf_addr
, int holdtime
)
416 long t_joinsuppress_msec
;
417 long join_timer_remain_msec
;
419 if (!up
->rpf
.source_nexthop
.interface
) {
420 if (PIM_DEBUG_PIM_TRACE
)
421 zlog_debug("%s: up %s RPF is not present", __func__
,
426 t_joinsuppress_msec
=
427 MIN(pim_if_t_suppressed_msec(up
->rpf
.source_nexthop
.interface
),
430 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
432 if (PIM_DEBUG_PIM_TRACE
) {
433 char rpf_str
[INET_ADDRSTRLEN
];
434 pim_inet4_dump("<rpf?>", rpf_addr
, rpf_str
, sizeof(rpf_str
));
436 "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
437 __FILE__
, __func__
, up
->sg_str
, rpf_str
,
438 join_timer_remain_msec
, t_joinsuppress_msec
);
441 if (join_timer_remain_msec
< t_joinsuppress_msec
) {
442 if (PIM_DEBUG_PIM_TRACE
) {
444 "%s %s: suppressing Join(S,G)=%s for %ld msec",
445 __FILE__
, __func__
, up
->sg_str
,
446 t_joinsuppress_msec
);
449 pim_upstream_join_timer_restart_msec(up
, t_joinsuppress_msec
);
453 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label
,
454 struct pim_upstream
*up
)
456 long join_timer_remain_msec
;
459 if (!up
->rpf
.source_nexthop
.interface
) {
460 if (PIM_DEBUG_PIM_TRACE
)
461 zlog_debug("%s: up %s RPF is not present", __func__
,
467 pim_if_t_override_msec(up
->rpf
.source_nexthop
.interface
);
469 if (up
->t_join_timer
) {
470 join_timer_remain_msec
=
471 pim_time_timer_remain_msec(up
->t_join_timer
);
473 /* upstream join tracked with neighbor jp timer */
474 struct pim_neighbor
*nbr
;
476 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
477 up
->rpf
.rpf_addr
.u
.prefix4
);
479 join_timer_remain_msec
=
480 pim_time_timer_remain_msec(nbr
->jp_timer
);
482 /* Manipulate such that override takes place */
483 join_timer_remain_msec
= t_override_msec
+ 1;
486 if (PIM_DEBUG_PIM_TRACE
) {
487 char rpf_str
[INET_ADDRSTRLEN
];
488 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
.u
.prefix4
, rpf_str
,
491 "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
492 debug_label
, up
->sg_str
, rpf_str
,
493 join_timer_remain_msec
, t_override_msec
);
496 if (join_timer_remain_msec
> t_override_msec
) {
497 if (PIM_DEBUG_PIM_TRACE
) {
499 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
500 debug_label
, up
->sg_str
, t_override_msec
);
503 pim_upstream_join_timer_restart_msec(up
, t_override_msec
);
507 static void forward_on(struct pim_upstream
*up
)
509 struct listnode
*chnode
;
510 struct listnode
*chnextnode
;
511 struct pim_ifchannel
*ch
= NULL
;
513 /* scan (S,G) state */
514 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
515 if (pim_macro_chisin_oiflist(ch
))
516 pim_forward_start(ch
);
518 } /* scan iface channel list */
521 static void forward_off(struct pim_upstream
*up
)
523 struct listnode
*chnode
;
524 struct listnode
*chnextnode
;
525 struct pim_ifchannel
*ch
;
527 /* scan per-interface (S,G) state */
528 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
530 pim_forward_stop(ch
, false);
532 } /* scan iface channel list */
535 static int pim_upstream_could_register(struct pim_upstream
*up
)
537 struct pim_interface
*pim_ifp
= NULL
;
539 /* FORCE_PIMREG is a generic flag to let an app like VxLAN-AA register
540 * a source on an upstream entry even if the source is not directly
541 * connected on the IIF.
543 if (PIM_UPSTREAM_FLAG_TEST_FORCE_PIMREG(up
->flags
))
546 if (up
->rpf
.source_nexthop
.interface
)
547 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
549 if (PIM_DEBUG_PIM_TRACE
)
550 zlog_debug("%s: up %s RPF is not present", __func__
,
554 if (pim_ifp
&& PIM_I_am_DR(pim_ifp
)
555 && pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
562 /* Source registration is suppressed for SSM groups. When the SSM range changes
563 * we re-revaluate register setup for existing upstream entries */
564 void pim_upstream_register_reevaluate(struct pim_instance
*pim
)
566 struct pim_upstream
*up
;
568 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
569 /* If FHR is set CouldRegister is True. Also check if the flow
570 * is actually active; if it is not kat setup will trigger
572 * registration whenever the flow becomes active. */
573 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) ||
574 !pim_upstream_is_kat_running(up
))
577 if (pim_is_grp_ssm(pim
, up
->sg
.grp
)) {
578 /* clear the register state for SSM groups */
579 if (up
->reg_state
!= PIM_REG_NOINFO
) {
580 if (PIM_DEBUG_PIM_EVENTS
)
582 "Clear register for %s as G is now SSM",
584 /* remove regiface from the OIL if it is there*/
585 pim_channel_del_oif(up
->channel_oil
,
587 PIM_OIF_FLAG_PROTO_PIM
,
589 up
->reg_state
= PIM_REG_NOINFO
;
592 /* register ASM sources with the RP */
593 if (up
->reg_state
== PIM_REG_NOINFO
) {
594 if (PIM_DEBUG_PIM_EVENTS
)
596 "Register %s as G is now ASM",
598 pim_channel_add_oif(up
->channel_oil
,
600 PIM_OIF_FLAG_PROTO_PIM
,
602 up
->reg_state
= PIM_REG_JOIN
;
608 /* RFC7761, Section 4.2 “Data Packet Forwarding Rules” says we should
610 * 1. along the SPT if SPTbit is set
611 * 2. and along the RPT if SPTbit is not set
612 * If forwarding is hw accelerated i.e. control and dataplane components
613 * are separate you may not be able to reliably set SPT bit on intermediate
614 * routers while still fowarding on the (S,G,rpt).
616 * This macro is a slight deviation on the RFC and uses "traffic-agnostic"
617 * criteria to decide between using the RPT vs. SPT for forwarding.
619 void pim_upstream_update_use_rpt(struct pim_upstream
*up
,
625 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
628 old_use_rpt
= !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
630 /* We will use the SPT (IIF=RPF_interface(S) if -
631 * 1. We have decided to join the SPT
633 * 3. Source is directly connected
634 * 4. We are RP (parent's IIF is lo or vrf-device)
635 * In all other cases the source will stay along the RPT and
636 * IIF=RPF_interface(RP).
638 if (up
->join_state
== PIM_UPSTREAM_JOINED
||
639 PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) ||
640 pim_if_connected_to_source(
641 up
->rpf
.source_nexthop
.interface
,
643 /* XXX - need to switch this to a more efficient
646 I_am_RP(up
->pim
, up
->sg
.grp
))
648 PIM_UPSTREAM_FLAG_UNSET_USE_RPT(up
->flags
);
651 PIM_UPSTREAM_FLAG_SET_USE_RPT(up
->flags
);
653 new_use_rpt
= !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
654 if (old_use_rpt
!= new_use_rpt
) {
655 if (PIM_DEBUG_PIM_EVENTS
)
656 zlog_debug("%s switched from %s to %s",
658 old_use_rpt
?"RPT":"SPT",
659 new_use_rpt
?"RPT":"SPT");
661 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
665 /* some events like RP change require re-evaluation of SGrpt across
668 void pim_upstream_reeval_use_rpt(struct pim_instance
*pim
)
670 struct pim_upstream
*up
;
672 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
673 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
676 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
680 void pim_upstream_switch(struct pim_instance
*pim
, struct pim_upstream
*up
,
681 enum pim_upstream_state new_state
)
683 enum pim_upstream_state old_state
= up
->join_state
;
685 if (up
->upstream_addr
.s_addr
== INADDR_ANY
) {
686 if (PIM_DEBUG_PIM_EVENTS
)
687 zlog_debug("%s: RPF not configured for %s", __func__
,
692 if (!up
->rpf
.source_nexthop
.interface
) {
693 if (PIM_DEBUG_PIM_EVENTS
)
694 zlog_debug("%s: RP not reachable for %s", __func__
,
699 if (PIM_DEBUG_PIM_EVENTS
) {
700 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
701 __func__
, up
->sg_str
,
702 pim_upstream_state2str(up
->join_state
),
703 pim_upstream_state2str(new_state
));
706 up
->join_state
= new_state
;
707 if (old_state
!= new_state
)
708 up
->state_transition
= pim_time_monotonic_sec();
710 pim_upstream_update_assert_tracking_desired(up
);
712 if (new_state
== PIM_UPSTREAM_JOINED
) {
713 pim_upstream_inherited_olist_decide(pim
, up
);
714 if (old_state
!= PIM_UPSTREAM_JOINED
) {
715 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
717 pim_msdp_up_join_state_changed(pim
, up
);
718 if (pim_upstream_could_register(up
)) {
719 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
721 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
723 pim_upstream_keep_alive_timer_start(
724 up
, pim
->keep_alive_time
);
725 pim_register_join(up
);
728 pim_upstream_send_join(up
);
729 join_timer_start(up
);
732 if (old_state
!= new_state
)
733 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
737 bool send_xg_jp
= false;
740 if (old_state
== PIM_UPSTREAM_JOINED
)
741 pim_msdp_up_join_state_changed(pim
, up
);
743 if (old_state
!= new_state
) {
745 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
746 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
748 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
750 (new_use_rpt
!= old_use_rpt
) &&
752 /* we have decided to switch from the SPT back
753 * to the RPT which means we need to cancel
754 * any previously sent SGrpt prunes immediately
759 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
761 If I am RP for G then send S,G prune to its IIF. */
762 if (pim_upstream_is_sg_rpt(up
) && up
->parent
&&
763 !I_am_RP(pim
, up
->sg
.grp
))
766 pim_jp_agg_single_upstream_send(&up
->rpf
, up
,
770 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
772 "re-join RPT; *,G IIF %s S,G IIF %s ",
773 up
->parent
->rpf
.source_nexthop
.interface
?
774 up
->parent
->rpf
.source_nexthop
.interface
->name
776 up
->rpf
.source_nexthop
.interface
?
777 up
->rpf
.source_nexthop
.interface
->name
:
779 pim_jp_agg_single_upstream_send(&up
->parent
->rpf
,
787 int pim_upstream_compare(const struct pim_upstream
*up1
,
788 const struct pim_upstream
*up2
)
790 if (ntohl(up1
->sg
.grp
.s_addr
) < ntohl(up2
->sg
.grp
.s_addr
))
793 if (ntohl(up1
->sg
.grp
.s_addr
) > ntohl(up2
->sg
.grp
.s_addr
))
796 if (ntohl(up1
->sg
.src
.s_addr
) < ntohl(up2
->sg
.src
.s_addr
))
799 if (ntohl(up1
->sg
.src
.s_addr
) > ntohl(up2
->sg
.src
.s_addr
))
805 void pim_upstream_fill_static_iif(struct pim_upstream
*up
,
806 struct interface
*incoming
)
808 up
->rpf
.source_nexthop
.interface
= incoming
;
810 /* reset other parameters to matched a connected incoming interface */
811 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
812 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
814 up
->rpf
.source_nexthop
.mrib_metric_preference
=
815 ZEBRA_CONNECT_DISTANCE_DEFAULT
;
816 up
->rpf
.source_nexthop
.mrib_route_metric
= 0;
817 up
->rpf
.rpf_addr
.family
= AF_INET
;
818 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
822 static struct pim_upstream
*pim_upstream_new(struct pim_instance
*pim
,
823 struct prefix_sg
*sg
,
824 struct interface
*incoming
,
826 struct pim_ifchannel
*ch
)
828 enum pim_rpf_result rpf_result
;
829 struct pim_interface
*pim_ifp
;
830 struct pim_upstream
*up
;
832 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
836 pim_str_sg_set(sg
, up
->sg_str
);
840 rb_pim_upstream_add(&pim
->upstream_head
, up
);
841 /* Set up->upstream_addr as INADDR_ANY, if RP is not
842 * configured and retain the upstream data structure
844 if (!pim_rp_set_upstream_addr(pim
, &up
->upstream_addr
, sg
->src
,
846 if (PIM_DEBUG_PIM_TRACE
)
847 zlog_debug("%s: Received a (*,G) with no RP configured",
851 up
->parent
= pim_upstream_find_parent(pim
, up
);
852 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
853 up
->sources
= list_new();
855 (int (*)(void *, void *))pim_upstream_compare
;
859 pim_upstream_find_new_children(pim
, up
);
862 up
->t_join_timer
= NULL
;
863 up
->t_ka_timer
= NULL
;
864 up
->t_rs_timer
= NULL
;
865 up
->t_msdp_reg_timer
= NULL
;
866 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
867 up
->reg_state
= PIM_REG_NOINFO
;
868 up
->state_transition
= pim_time_monotonic_sec();
869 up
->channel_oil
= pim_channel_oil_add(pim
, &up
->sg
, __func__
);
870 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
872 up
->rpf
.source_nexthop
.interface
= NULL
;
873 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
874 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
876 up
->rpf
.source_nexthop
.mrib_metric_preference
=
877 router
->infinite_assert_metric
.metric_preference
;
878 up
->rpf
.source_nexthop
.mrib_route_metric
=
879 router
->infinite_assert_metric
.route_metric
;
880 up
->rpf
.rpf_addr
.family
= AF_INET
;
881 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
883 up
->ifchannels
= list_new();
884 up
->ifchannels
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
886 if (up
->sg
.src
.s_addr
!= INADDR_ANY
) {
887 wheel_add_item(pim
->upstream_sg_wheel
, up
);
889 /* Inherit the DF role from the parent (*, G) entry for
893 && PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up
->parent
->flags
)
894 && PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up
->parent
->flags
)) {
895 PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(up
->flags
);
898 "upstream %s inherited mlag non-df flag from parent",
903 if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up
->flags
)
904 || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
)) {
905 pim_upstream_fill_static_iif(up
, incoming
);
906 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
908 pim_upstream_update_use_rpt(up
,
909 false /*update_mroute*/);
910 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
912 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
))
913 pim_upstream_keep_alive_timer_start(
914 up
, pim
->keep_alive_time
);
915 } else if (up
->upstream_addr
.s_addr
!= INADDR_ANY
) {
916 pim_upstream_update_use_rpt(up
,
917 false /*update_mroute*/);
918 rpf_result
= pim_rpf_update(pim
, up
, NULL
, __func__
);
919 if (rpf_result
== PIM_RPF_FAILURE
) {
920 if (PIM_DEBUG_PIM_TRACE
)
922 "%s: Attempting to create upstream(%s), Unable to RPF for source",
923 __func__
, up
->sg_str
);
926 if (up
->rpf
.source_nexthop
.interface
) {
927 pim_upstream_mroute_iif_update(up
->channel_oil
,
932 /* send the entry to the MLAG peer */
933 /* XXX - duplicate send is possible here if pim_rpf_update
934 * successfully resolved the nexthop
936 if (pim_up_mlag_is_local(up
)
937 || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up
->flags
))
938 pim_mlag_up_local_add(pim
, up
);
940 if (PIM_DEBUG_PIM_TRACE
) {
942 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
943 __func__
, up
->sg_str
, inet_ntoa(up
->upstream_addr
),
950 uint32_t pim_up_mlag_local_cost(struct pim_upstream
*up
)
952 if (!(pim_up_mlag_is_local(up
))
953 && !(up
->flags
& PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE
))
954 return router
->infinite_assert_metric
.route_metric
;
956 if ((up
->rpf
.source_nexthop
.interface
==
957 up
->pim
->vxlan
.peerlink_rif
) &&
958 (up
->rpf
.source_nexthop
.mrib_route_metric
<
959 (router
->infinite_assert_metric
.route_metric
-
960 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC
)))
961 return up
->rpf
.source_nexthop
.mrib_route_metric
+
962 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC
;
964 return up
->rpf
.source_nexthop
.mrib_route_metric
;
967 uint32_t pim_up_mlag_peer_cost(struct pim_upstream
*up
)
969 if (!(up
->flags
& PIM_UPSTREAM_FLAG_MASK_MLAG_PEER
))
970 return router
->infinite_assert_metric
.route_metric
;
972 return up
->mlag
.peer_mrib_metric
;
975 struct pim_upstream
*pim_upstream_find(struct pim_instance
*pim
,
976 struct prefix_sg
*sg
)
978 struct pim_upstream lookup
;
979 struct pim_upstream
*up
= NULL
;
982 up
= rb_pim_upstream_find(&pim
->upstream_head
, &lookup
);
986 struct pim_upstream
*pim_upstream_find_or_add(struct prefix_sg
*sg
,
987 struct interface
*incoming
,
988 int flags
, const char *name
)
990 struct pim_interface
*pim_ifp
= incoming
->info
;
992 return (pim_upstream_add(pim_ifp
->pim
, sg
, incoming
, flags
, name
,
996 void pim_upstream_ref(struct pim_upstream
*up
, int flags
, const char *name
)
998 /* if a local MLAG reference is being created we need to send the mroute
1001 if (!PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up
->flags
) &&
1002 PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags
)) {
1003 PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(up
->flags
);
1004 pim_mlag_up_local_add(up
->pim
, up
);
1007 /* when we go from non-FHR to FHR we need to re-eval traffic
1010 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) &&
1011 PIM_UPSTREAM_FLAG_TEST_FHR(flags
)) {
1012 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1013 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
1016 /* re-eval joinDesired; clearing peer-msdp-sa flag can
1017 * cause JD to change
1019 if (!PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up
->flags
) &&
1020 PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags
)) {
1021 PIM_UPSTREAM_FLAG_SET_SRC_MSDP(up
->flags
);
1022 pim_upstream_update_join_desired(up
->pim
, up
);
1027 if (PIM_DEBUG_PIM_TRACE
)
1028 zlog_debug("%s(%s): upstream %s ref count %d increment",
1029 __func__
, name
, up
->sg_str
, up
->ref_count
);
1032 struct pim_upstream
*pim_upstream_add(struct pim_instance
*pim
,
1033 struct prefix_sg
*sg
,
1034 struct interface
*incoming
, int flags
,
1036 struct pim_ifchannel
*ch
)
1038 struct pim_upstream
*up
= NULL
;
1041 up
= pim_upstream_find(pim
, sg
);
1043 pim_upstream_ref(up
, flags
, name
);
1046 up
= pim_upstream_new(pim
, sg
, incoming
, flags
, ch
);
1049 if (PIM_DEBUG_PIM_TRACE
) {
1051 char buf
[PREFIX2STR_BUFFER
];
1052 prefix2str(&up
->rpf
.rpf_addr
, buf
, sizeof(buf
));
1053 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
1055 up
->sg_str
, buf
, up
->rpf
.source_nexthop
.interface
?
1056 up
->rpf
.source_nexthop
.interface
->name
: "Unknown" ,
1057 found
, up
->ref_count
);
1059 zlog_debug("%s(%s): (%s) failure to create", __func__
,
1060 name
, pim_str_sg_dump(sg
));
1067 * Passed in up must be the upstream for ch. starch is NULL if no
1069 * This function is copied over from
1070 * pim_upstream_evaluate_join_desired_interface but limited to
1071 * parent (*,G)'s includes/joins.
1073 int pim_upstream_eval_inherit_if(struct pim_upstream
*up
,
1074 struct pim_ifchannel
*ch
,
1075 struct pim_ifchannel
*starch
)
1077 /* if there is an explicit prune for this interface we cannot
1081 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1085 /* Check if the OIF can be inherited fron the (*,G) entry
1088 if (!pim_macro_ch_lost_assert(starch
)
1089 && pim_macro_chisin_joins_or_include(starch
))
1097 * Passed in up must be the upstream for ch. starch is NULL if no
1100 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream
*up
,
1101 struct pim_ifchannel
*ch
,
1102 struct pim_ifchannel
*starch
)
1105 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1108 if (!pim_macro_ch_lost_assert(ch
)
1109 && pim_macro_chisin_joins_or_include(ch
))
1117 /* XXX: check on this with donald
1118 * we are looking for PIM_IF_FLAG_MASK_S_G_RPT in
1122 if (PIM_IF_FLAG_TEST_S_G_RPT(starch
->upstream
->flags
))
1126 if (!pim_macro_ch_lost_assert(starch
)
1127 && pim_macro_chisin_joins_or_include(starch
))
1134 /* Returns true if immediate OIL is empty and is used to evaluate
1135 * JoinDesired. See pim_upstream_evaluate_join_desired.
1137 static bool pim_upstream_empty_immediate_olist(struct pim_instance
*pim
,
1138 struct pim_upstream
*up
)
1140 struct interface
*ifp
;
1141 struct pim_ifchannel
*ch
;
1143 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1147 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1151 /* If we have even one immediate OIF we can return with
1154 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1157 } /* scan iface channel list */
1159 /* immediate_oil is empty */
1164 static inline bool pim_upstream_is_msdp_peer_sa(struct pim_upstream
*up
)
1166 return PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up
->flags
);
1170 * bool JoinDesired(*,G) {
1171 * if (immediate_olist(*,G) != NULL)
1177 * bool JoinDesired(S,G) {
1178 * return( immediate_olist(S,G) != NULL
1179 * OR ( KeepaliveTimer(S,G) is running
1180 * AND inherited_olist(S,G) != NULL ) )
1183 bool pim_upstream_evaluate_join_desired(struct pim_instance
*pim
,
1184 struct pim_upstream
*up
)
1189 empty_imm_oil
= pim_upstream_empty_immediate_olist(pim
, up
);
1192 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
1193 return !empty_imm_oil
;
1198 empty_inh_oil
= pim_upstream_empty_inherited_olist(up
);
1199 if (!empty_inh_oil
&&
1200 (pim_upstream_is_kat_running(up
) ||
1201 pim_upstream_is_msdp_peer_sa(up
)))
1208 See also pim_upstream_evaluate_join_desired() above.
1210 void pim_upstream_update_join_desired(struct pim_instance
*pim
,
1211 struct pim_upstream
*up
)
1213 int was_join_desired
; /* boolean */
1214 int is_join_desired
; /* boolean */
1216 was_join_desired
= PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up
->flags
);
1218 is_join_desired
= pim_upstream_evaluate_join_desired(pim
, up
);
1219 if (is_join_desired
)
1220 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up
->flags
);
1222 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up
->flags
);
1224 /* switched from false to true */
1225 if (is_join_desired
&& (up
->join_state
== PIM_UPSTREAM_NOTJOINED
)) {
1226 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
1230 /* switched from true to false */
1231 if (!is_join_desired
&& was_join_desired
) {
1232 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_NOTJOINED
);
1238 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
1239 Transitions from Joined State
1240 RPF'(S,G) GenID changes
1242 The upstream (S,G) state machine remains in Joined state. If the
1243 Join Timer is set to expire in more than t_override seconds, reset
1244 it so that it expires after t_override seconds.
1246 void pim_upstream_rpf_genid_changed(struct pim_instance
*pim
,
1247 struct in_addr neigh_addr
)
1249 struct pim_upstream
*up
;
1252 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1254 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
1255 if (PIM_DEBUG_PIM_TRACE
) {
1256 char neigh_str
[INET_ADDRSTRLEN
];
1257 char rpf_addr_str
[PREFIX_STRLEN
];
1258 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
,
1260 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_addr_str
,
1261 sizeof(rpf_addr_str
));
1263 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
1264 __func__
, neigh_str
, up
->sg_str
, pim
->vrf
->name
,
1265 up
->join_state
== PIM_UPSTREAM_JOINED
,
1269 /* consider only (S,G) upstream in Joined state */
1270 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
1273 /* match RPF'(S,G)=neigh_addr */
1274 if (up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
!= neigh_addr
.s_addr
)
1277 pim_upstream_join_timer_decrease_to_t_override(
1278 "RPF'(S,G) GenID change", up
);
1283 void pim_upstream_rpf_interface_changed(struct pim_upstream
*up
,
1284 struct interface
*old_rpf_ifp
)
1286 struct listnode
*chnode
;
1287 struct listnode
*chnextnode
;
1288 struct pim_ifchannel
*ch
;
1290 /* search all ifchannels */
1291 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1292 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
1294 /* RPF_interface(S) was NOT I */
1295 (old_rpf_ifp
== ch
->interface
) &&
1296 /* RPF_interface(S) stopped being I */
1297 (ch
->upstream
->rpf
.source_nexthop
1299 (ch
->upstream
->rpf
.source_nexthop
1300 .interface
!= ch
->interface
)) {
1301 assert_action_a5(ch
);
1303 } /* PIM_IFASSERT_I_AM_LOSER */
1305 pim_ifchannel_update_assert_tracking_desired(ch
);
1309 void pim_upstream_update_could_assert(struct pim_upstream
*up
)
1311 struct listnode
*chnode
;
1312 struct listnode
*chnextnode
;
1313 struct pim_ifchannel
*ch
;
1315 /* scan per-interface (S,G) state */
1316 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1317 pim_ifchannel_update_could_assert(ch
);
1318 } /* scan iface channel list */
1321 void pim_upstream_update_my_assert_metric(struct pim_upstream
*up
)
1323 struct listnode
*chnode
;
1324 struct listnode
*chnextnode
;
1325 struct pim_ifchannel
*ch
;
1327 /* scan per-interface (S,G) state */
1328 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1329 pim_ifchannel_update_my_assert_metric(ch
);
1331 } /* scan iface channel list */
1334 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
)
1336 struct listnode
*chnode
;
1337 struct listnode
*chnextnode
;
1338 struct pim_interface
*pim_ifp
;
1339 struct pim_ifchannel
*ch
;
1341 /* scan per-interface (S,G) state */
1342 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1345 pim_ifp
= ch
->interface
->info
;
1349 pim_ifchannel_update_assert_tracking_desired(ch
);
1351 } /* scan iface channel list */
1354 /* When kat is stopped CouldRegister goes to false so we need to
1355 * transition the (S, G) on FHR to NI state and remove reg tunnel
1357 static void pim_upstream_fhr_kat_expiry(struct pim_instance
*pim
,
1358 struct pim_upstream
*up
)
1360 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
1363 if (PIM_DEBUG_PIM_TRACE
)
1364 zlog_debug("kat expired on %s; clear fhr reg state",
1367 /* stop reg-stop timer */
1368 THREAD_OFF(up
->t_rs_timer
);
1369 /* remove regiface from the OIL if it is there*/
1370 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1371 PIM_OIF_FLAG_PROTO_PIM
, __func__
);
1372 /* clear the register state */
1373 up
->reg_state
= PIM_REG_NOINFO
;
1374 PIM_UPSTREAM_FLAG_UNSET_FHR(up
->flags
);
1377 /* When kat is started CouldRegister can go to true. And if it does we
1378 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1380 static void pim_upstream_fhr_kat_start(struct pim_upstream
*up
)
1382 if (pim_upstream_could_register(up
)) {
1383 if (PIM_DEBUG_PIM_TRACE
)
1385 "kat started on %s; set fhr reg state to joined",
1388 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1389 if (up
->reg_state
== PIM_REG_NOINFO
)
1390 pim_register_join(up
);
1391 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
1396 * On an RP, the PMBR value must be cleared when the
1397 * Keepalive Timer expires
1398 * KAT expiry indicates that flow is inactive. If the flow was created or
1399 * maintained by activity now is the time to deref it.
1401 struct pim_upstream
*pim_upstream_keep_alive_timer_proc(
1402 struct pim_upstream
*up
)
1404 struct pim_instance
*pim
;
1406 pim
= up
->channel_oil
->pim
;
1408 if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up
->flags
)) {
1409 /* if the router is a PIM vxlan encapsulator we prevent expiry
1410 * of KAT as the mroute is pre-setup without any traffic
1412 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1416 if (I_am_RP(pim
, up
->sg
.grp
)) {
1417 pim_br_clear_pmbr(&up
->sg
);
1419 * We need to do more here :)
1420 * But this is the start.
1424 /* source is no longer active - pull the SA from MSDP's cache */
1425 pim_msdp_sa_local_del(pim
, &up
->sg
);
1427 /* JoinDesired can change when KAT is started or stopped */
1428 pim_upstream_update_join_desired(pim
, up
);
1430 /* if entry was created because of activity we need to deref it */
1431 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1432 pim_upstream_fhr_kat_expiry(pim
, up
);
1433 if (PIM_DEBUG_PIM_TRACE
)
1435 "kat expired on %s[%s]; remove stream reference",
1436 up
->sg_str
, pim
->vrf
->name
);
1437 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up
->flags
);
1439 /* Return if upstream entry got deleted.*/
1440 if (!pim_upstream_del(pim
, up
, __func__
))
1443 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
)) {
1444 PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up
->flags
);
1446 if (!pim_upstream_del(pim
, up
, __func__
))
1450 /* upstream reference would have been added to track the local
1451 * membership if it is LHR. We have to clear it when KAT expires.
1452 * Otherwise would result in stale entry with uncleared ref count.
1454 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
1455 struct pim_upstream
*parent
= up
->parent
;
1457 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1458 up
= pim_upstream_del(pim
, up
, __func__
);
1461 pim_jp_agg_single_upstream_send(&parent
->rpf
, parent
,
1468 static int pim_upstream_keep_alive_timer(struct thread
*t
)
1470 struct pim_upstream
*up
;
1474 /* pull the stats and re-check */
1475 if (pim_upstream_sg_running_proc(up
))
1476 /* kat was restarted because of new activity */
1479 pim_upstream_keep_alive_timer_proc(up
);
1483 void pim_upstream_keep_alive_timer_start(struct pim_upstream
*up
, uint32_t time
)
1485 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1486 if (PIM_DEBUG_PIM_TRACE
)
1487 zlog_debug("kat start on %s with no stream reference",
1490 THREAD_OFF(up
->t_ka_timer
);
1491 thread_add_timer(router
->master
, pim_upstream_keep_alive_timer
, up
,
1492 time
, &up
->t_ka_timer
);
1494 /* any time keepalive is started against a SG we will have to
1495 * re-evaluate our active source database */
1496 pim_msdp_sa_local_update(up
);
1497 /* JoinDesired can change when KAT is started or stopped */
1498 pim_upstream_update_join_desired(up
->pim
, up
);
1501 /* MSDP on RP needs to know if a source is registerable to this RP */
1502 static int pim_upstream_msdp_reg_timer(struct thread
*t
)
1504 struct pim_upstream
*up
= THREAD_ARG(t
);
1505 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1507 /* source is no longer active - pull the SA from MSDP's cache */
1508 pim_msdp_sa_local_del(pim
, &up
->sg
);
1511 void pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1513 THREAD_OFF(up
->t_msdp_reg_timer
);
1514 thread_add_timer(router
->master
, pim_upstream_msdp_reg_timer
, up
,
1515 PIM_MSDP_REG_RXED_PERIOD
, &up
->t_msdp_reg_timer
);
1517 pim_msdp_sa_local_update(up
);
1521 * 4.2.1 Last-Hop Switchover to the SPT
1523 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1524 * RP. Once traffic from sources to joined groups arrives at a last-hop
1525 * router, it has the option of switching to receive the traffic on a
1526 * shortest path tree (SPT).
1528 * The decision for a router to switch to the SPT is controlled as
1532 * CheckSwitchToSpt(S,G) {
1533 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1534 * (+) pim_include(S,G) != NULL )
1535 * AND SwitchToSptDesired(S,G) ) {
1536 * # Note: Restarting the KAT will result in the SPT switch
1537 * set KeepaliveTimer(S,G) to Keepalive_Period
1541 * SwitchToSptDesired(S,G) is a policy function that is implementation
1542 * defined. An "infinite threshold" policy can be implemented by making
1543 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1544 * first packet" policy can be implemented by making
1545 * SwitchToSptDesired(S,G) return true once a single packet has been
1546 * received for the source and group.
1548 int pim_upstream_switch_to_spt_desired_on_rp(struct pim_instance
*pim
,
1549 struct prefix_sg
*sg
)
1551 if (I_am_RP(pim
, sg
->grp
))
1557 int pim_upstream_is_sg_rpt(struct pim_upstream
*up
)
1559 struct listnode
*chnode
;
1560 struct pim_ifchannel
*ch
;
1562 for (ALL_LIST_ELEMENTS_RO(up
->ifchannels
, chnode
, ch
)) {
1563 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1570 * After receiving a packet set SPTbit:
1572 * Update_SPTbit(S,G,iif) {
1573 * if ( iif == RPF_interface(S)
1574 * AND JoinDesired(S,G) == true
1575 * AND ( DirectlyConnected(S) == true
1576 * OR RPF_interface(S) != RPF_interface(RP(G))
1577 * OR inherited_olist(S,G,rpt) == NULL
1578 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1579 * ( RPF'(S,G) != NULL ) )
1580 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1581 * Set SPTbit(S,G) to true
1585 void pim_upstream_set_sptbit(struct pim_upstream
*up
,
1586 struct interface
*incoming
)
1588 struct pim_upstream
*starup
= up
->parent
;
1590 // iif == RPF_interfvace(S)
1591 if (up
->rpf
.source_nexthop
.interface
!= incoming
) {
1592 if (PIM_DEBUG_PIM_TRACE
)
1594 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1595 __func__
, incoming
->name
,
1596 up
->rpf
.source_nexthop
.interface
->name
);
1600 // AND JoinDesired(S,G) == true
1601 if (!pim_upstream_evaluate_join_desired(up
->channel_oil
->pim
, up
)) {
1602 if (PIM_DEBUG_PIM_TRACE
)
1603 zlog_debug("%s: %s Join is not Desired", __func__
,
1608 // DirectlyConnected(S) == true
1609 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1611 if (PIM_DEBUG_PIM_TRACE
)
1612 zlog_debug("%s: %s is directly connected to the source",
1613 __func__
, up
->sg_str
);
1614 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1618 // OR RPF_interface(S) != RPF_interface(RP(G))
1620 || up
->rpf
.source_nexthop
1621 .interface
!= starup
->rpf
.source_nexthop
.interface
) {
1622 struct pim_upstream
*starup
= up
->parent
;
1624 if (PIM_DEBUG_PIM_TRACE
)
1626 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1627 __func__
, up
->sg_str
);
1628 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1630 pim_jp_agg_single_upstream_send(&starup
->rpf
, starup
, true);
1634 // OR inherited_olist(S,G,rpt) == NULL
1635 if (pim_upstream_is_sg_rpt(up
)
1636 && pim_upstream_empty_inherited_olist(up
)) {
1637 if (PIM_DEBUG_PIM_TRACE
)
1638 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1639 __func__
, up
->sg_str
);
1640 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1644 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1645 // ( RPF'(S,G) != NULL ) )
1646 if (up
->parent
&& pim_rpf_is_same(&up
->rpf
, &up
->parent
->rpf
)) {
1647 if (PIM_DEBUG_PIM_TRACE
)
1648 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1649 __func__
, up
->sg_str
);
1650 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1657 const char *pim_upstream_state2str(enum pim_upstream_state join_state
)
1659 switch (join_state
) {
1660 case PIM_UPSTREAM_NOTJOINED
:
1662 case PIM_UPSTREAM_JOINED
:
1668 const char *pim_reg_state2str(enum pim_reg_state reg_state
, char *state_str
,
1669 size_t state_str_len
)
1671 switch (reg_state
) {
1672 case PIM_REG_NOINFO
:
1673 strlcpy(state_str
, "RegNoInfo", state_str_len
);
1676 strlcpy(state_str
, "RegJoined", state_str_len
);
1678 case PIM_REG_JOIN_PENDING
:
1679 strlcpy(state_str
, "RegJoinPend", state_str_len
);
1682 strlcpy(state_str
, "RegPrune", state_str_len
);
1685 strlcpy(state_str
, "RegUnknown", state_str_len
);
1690 static int pim_upstream_register_stop_timer(struct thread
*t
)
1692 struct pim_interface
*pim_ifp
;
1693 struct pim_instance
*pim
;
1694 struct pim_upstream
*up
;
1696 pim
= up
->channel_oil
->pim
;
1698 if (PIM_DEBUG_PIM_TRACE
) {
1699 char state_str
[PIM_REG_STATE_STR_LEN
];
1700 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1701 __func__
, up
->sg_str
, pim
->vrf
->name
,
1702 pim_reg_state2str(up
->reg_state
, state_str
,
1703 sizeof(state_str
)));
1706 switch (up
->reg_state
) {
1707 case PIM_REG_JOIN_PENDING
:
1708 up
->reg_state
= PIM_REG_JOIN
;
1709 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1710 PIM_OIF_FLAG_PROTO_PIM
,
1712 pim_vxlan_update_sg_reg_state(pim
, up
, true /*reg_join*/);
1717 /* This is equalent to Couldreg -> False */
1718 if (!up
->rpf
.source_nexthop
.interface
) {
1719 if (PIM_DEBUG_PIM_TRACE
)
1720 zlog_debug("%s: up %s RPF is not present",
1721 __func__
, up
->sg_str
);
1722 up
->reg_state
= PIM_REG_NOINFO
;
1726 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1728 if (PIM_DEBUG_PIM_TRACE
)
1730 "%s: Interface: %s is not configured for pim",
1732 up
->rpf
.source_nexthop
.interface
->name
);
1735 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1736 pim_upstream_start_register_stop_timer(up
, 1);
1738 if (((up
->channel_oil
->cc
.lastused
/ 100)
1739 > pim
->keep_alive_time
)
1740 && (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
))) {
1741 if (PIM_DEBUG_PIM_TRACE
)
1743 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1747 pim_null_register_send(up
);
1756 void pim_upstream_start_register_stop_timer(struct pim_upstream
*up
,
1761 THREAD_TIMER_OFF(up
->t_rs_timer
);
1763 if (!null_register
) {
1764 uint32_t lower
= (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1765 uint32_t upper
= (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1766 time
= lower
+ (frr_weak_random() % (upper
- lower
+ 1))
1767 - PIM_REGISTER_PROBE_PERIOD
;
1769 time
= PIM_REGISTER_PROBE_PERIOD
;
1771 if (PIM_DEBUG_PIM_TRACE
) {
1773 "%s: (S,G)=%s Starting upstream register stop timer %d",
1774 __func__
, up
->sg_str
, time
);
1776 thread_add_timer(router
->master
, pim_upstream_register_stop_timer
, up
,
1777 time
, &up
->t_rs_timer
);
1780 int pim_upstream_inherited_olist_decide(struct pim_instance
*pim
,
1781 struct pim_upstream
*up
)
1783 struct interface
*ifp
;
1784 struct pim_ifchannel
*ch
, *starch
;
1785 struct pim_upstream
*starup
= up
->parent
;
1786 int output_intf
= 0;
1788 if (!up
->rpf
.source_nexthop
.interface
)
1789 if (PIM_DEBUG_PIM_TRACE
)
1790 zlog_debug("%s: up %s RPF is not present", __func__
,
1793 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1794 struct pim_interface
*pim_ifp
;
1798 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1801 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
1808 pim_ifp
= ifp
->info
;
1809 if (PIM_I_am_DualActive(pim_ifp
)
1810 && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up
->flags
)
1811 && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up
->flags
)
1812 || !PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up
->flags
)))
1814 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1819 flag
= PIM_OIF_FLAG_PROTO_STAR
;
1821 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch
->flags
))
1822 flag
= PIM_OIF_FLAG_PROTO_IGMP
;
1823 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch
->flags
))
1824 flag
|= PIM_OIF_FLAG_PROTO_PIM
;
1827 pim_channel_add_oif(up
->channel_oil
, ifp
, flag
,
1837 * For a given upstream, determine the inherited_olist
1840 * inherited_olist(S,G,rpt) =
1841 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1842 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1843 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1845 * inherited_olist(S,G) =
1846 * inherited_olist(S,G,rpt) (+)
1847 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1849 * return 1 if there are any output interfaces
1850 * return 0 if there are not any output interfaces
1852 int pim_upstream_inherited_olist(struct pim_instance
*pim
,
1853 struct pim_upstream
*up
)
1855 int output_intf
= pim_upstream_inherited_olist_decide(pim
, up
);
1858 * If we have output_intf switch state to Join and work like normal
1859 * If we don't have an output_intf that means we are probably a
1860 * switch on a stick so turn on forwarding to just accept the
1861 * incoming packets so we don't bother the other stuff!
1863 pim_upstream_update_join_desired(pim
, up
);
1871 int pim_upstream_empty_inherited_olist(struct pim_upstream
*up
)
1873 return pim_channel_oil_empty(up
->channel_oil
);
1877 * When we have a new neighbor,
1878 * find upstreams that don't have their rpf_addr
1879 * set and see if the new neighbor allows
1880 * the join to be sent
1882 void pim_upstream_find_new_rpf(struct pim_instance
*pim
)
1884 struct pim_upstream
*up
;
1886 enum pim_rpf_result rpf_result
;
1889 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1891 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
1892 if (up
->upstream_addr
.s_addr
== INADDR_ANY
) {
1893 if (PIM_DEBUG_PIM_TRACE
)
1895 "%s: RP not configured for Upstream %s",
1896 __func__
, up
->sg_str
);
1900 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
1901 if (PIM_DEBUG_PIM_TRACE
)
1903 "%s: Upstream %s without a path to send join, checking",
1904 __func__
, up
->sg_str
);
1905 old
.source_nexthop
.interface
=
1906 up
->rpf
.source_nexthop
.interface
;
1907 rpf_result
= pim_rpf_update(pim
, up
, &old
, __func__
);
1908 if (rpf_result
== PIM_RPF_CHANGED
||
1909 (rpf_result
== PIM_RPF_FAILURE
&&
1910 old
.source_nexthop
.interface
))
1911 pim_zebra_upstream_rpf_changed(pim
, up
, &old
);
1912 /* update kernel multicast forwarding cache (MFC) */
1913 pim_upstream_mroute_iif_update(up
->channel_oil
,
1917 pim_zebra_update_all_interfaces(pim
);
1920 unsigned int pim_upstream_hash_key(const void *arg
)
1922 const struct pim_upstream
*up
= arg
;
1924 return jhash_2words(up
->sg
.src
.s_addr
, up
->sg
.grp
.s_addr
, 0);
1927 void pim_upstream_terminate(struct pim_instance
*pim
)
1929 struct pim_upstream
*up
;
1931 while ((up
= rb_pim_upstream_first(&pim
->upstream_head
))) {
1932 pim_upstream_del(pim
, up
, __func__
);
1935 rb_pim_upstream_fini(&pim
->upstream_head
);
1937 if (pim
->upstream_sg_wheel
)
1938 wheel_delete(pim
->upstream_sg_wheel
);
1939 pim
->upstream_sg_wheel
= NULL
;
1942 bool pim_upstream_equal(const void *arg1
, const void *arg2
)
1944 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1945 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1947 if ((up1
->sg
.grp
.s_addr
== up2
->sg
.grp
.s_addr
)
1948 && (up1
->sg
.src
.s_addr
== up2
->sg
.src
.s_addr
))
1954 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1955 * the cases where kat has to be restarted on rxing traffic -
1957 * if( DirectlyConnected(S) == true AND iif == RPF_interface(S) ) {
1958 * set KeepaliveTimer(S,G) to Keepalive_Period
1959 * # Note: a register state transition or UpstreamJPState(S,G)
1960 * # transition may happen as a result of restarting
1961 * # KeepaliveTimer, and must be dealt with here.
1963 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1964 * inherited_olist(S,G) != NULL ) {
1965 * set KeepaliveTimer(S,G) to Keepalive_Period
1968 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1970 struct channel_oil
*c_oil
= up
->channel_oil
;
1971 struct interface
*ifp
= up
->rpf
.source_nexthop
.interface
;
1972 struct pim_interface
*pim_ifp
;
1974 /* "iif == RPF_interface(S)" check is not easy to do as the info
1975 * we get from the kernel/ASIC is really a "lookup/key hit".
1976 * So we will do an approximate check here to avoid starting KAT
1977 * because of (S,G,rpt) forwarding on a non-LHR.
1982 pim_ifp
= ifp
->info
;
1983 if (pim_ifp
->mroute_vif_index
!= c_oil
->oil
.mfcc_parent
)
1986 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1991 if ((up
->join_state
== PIM_UPSTREAM_JOINED
)
1992 && !pim_upstream_empty_inherited_olist(up
)) {
1999 static bool pim_upstream_sg_running_proc(struct pim_upstream
*up
)
2002 struct pim_instance
*pim
= up
->pim
;
2004 if (!up
->channel_oil
->installed
)
2007 pim_mroute_update_counters(up
->channel_oil
);
2009 // Have we seen packets?
2010 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
)
2011 && (up
->channel_oil
->cc
.lastused
/ 100 > 30)) {
2012 if (PIM_DEBUG_PIM_TRACE
) {
2014 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
2015 __func__
, up
->sg_str
, pim
->vrf
->name
,
2016 up
->channel_oil
->cc
.oldpktcnt
,
2017 up
->channel_oil
->cc
.pktcnt
,
2018 up
->channel_oil
->cc
.lastused
/ 100);
2023 if (pim_upstream_kat_start_ok(up
)) {
2024 /* Add a source reference to the stream if
2025 * one doesn't already exist */
2026 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
2027 if (PIM_DEBUG_PIM_TRACE
)
2029 "source reference created on kat restart %s[%s]",
2030 up
->sg_str
, pim
->vrf
->name
);
2032 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
,
2034 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
2035 pim_upstream_fhr_kat_start(up
);
2037 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
2039 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
2040 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
2044 if ((up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
) &&
2045 (up
->rpf
.source_nexthop
.interface
)) {
2046 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
2053 * Code to check and see if we've received packets on a S,G mroute
2054 * and if so to set the SPT bit appropriately
2056 static void pim_upstream_sg_running(void *arg
)
2058 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
2059 struct pim_instance
*pim
= up
->channel_oil
->pim
;
2061 // No packet can have arrived here if this is the case
2062 if (!up
->channel_oil
->installed
) {
2063 if (PIM_DEBUG_TRACE
)
2064 zlog_debug("%s: %s%s is not installed in mroute",
2065 __func__
, up
->sg_str
, pim
->vrf
->name
);
2070 * This is a bit of a hack
2071 * We've noted that we should rescan but
2072 * we've missed the window for doing so in
2073 * pim_zebra.c for some reason. I am
2074 * only doing this at this point in time
2075 * to get us up and working for the moment
2077 if (up
->channel_oil
->oil_inherited_rescan
) {
2078 if (PIM_DEBUG_TRACE
)
2080 "%s: Handling unscanned inherited_olist for %s[%s]",
2081 __func__
, up
->sg_str
, pim
->vrf
->name
);
2082 pim_upstream_inherited_olist_decide(pim
, up
);
2083 up
->channel_oil
->oil_inherited_rescan
= 0;
2086 pim_upstream_sg_running_proc(up
);
2089 void pim_upstream_add_lhr_star_pimreg(struct pim_instance
*pim
)
2091 struct pim_upstream
*up
;
2093 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
2094 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
2097 if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
))
2100 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
2101 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
2105 void pim_upstream_spt_prefix_list_update(struct pim_instance
*pim
,
2106 struct prefix_list
*pl
)
2108 const char *pname
= prefix_list_name(pl
);
2110 if (pim
->spt
.plist
&& strcmp(pim
->spt
.plist
, pname
) == 0) {
2111 pim_upstream_remove_lhr_star_pimreg(pim
, pname
);
2116 * nlist -> The new prefix list
2118 * Per Group Application of pimreg to the OIL
2119 * If the prefix list tells us DENY then
2120 * we need to Switchover to SPT immediate
2121 * so add the pimreg.
2122 * If the prefix list tells us to ACCEPT than
2123 * we need to Never do the SPT so remove
2127 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance
*pim
,
2130 struct pim_upstream
*up
;
2131 struct prefix_list
*np
;
2133 enum prefix_list_type apply_new
;
2135 np
= prefix_list_lookup(AFI_IP
, nlist
);
2138 g
.prefixlen
= IPV4_MAX_PREFIXLEN
;
2140 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
2141 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
2144 if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
))
2148 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
2149 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
2152 g
.u
.prefix4
= up
->sg
.grp
;
2153 apply_new
= prefix_list_apply(np
, &g
);
2154 if (apply_new
== PREFIX_DENY
)
2155 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
2156 PIM_OIF_FLAG_PROTO_IGMP
,
2159 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
2160 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
2164 void pim_upstream_init(struct pim_instance
*pim
)
2168 snprintf(name
, sizeof(name
), "PIM %s Timer Wheel", pim
->vrf
->name
);
2169 pim
->upstream_sg_wheel
=
2170 wheel_init(router
->master
, 31000, 100, pim_upstream_hash_key
,
2171 pim_upstream_sg_running
, name
);
2173 rb_pim_upstream_init(&pim
->upstream_head
);