1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2008 Everton da Silva Marques
25 #include "pim_iface.h"
27 #include "pim_zlookup.h"
28 #include "pim_upstream.h"
29 #include "pim_ifchannel.h"
30 #include "pim_neighbor.h"
32 #include "pim_zebra.h"
34 #include "pim_macro.h"
36 #include "pim_register.h"
38 #include "pim_jp_agg.h"
41 #include "pim_vxlan.h"
44 static void join_timer_stop(struct pim_upstream
*up
);
46 pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
);
47 static bool pim_upstream_sg_running_proc(struct pim_upstream
*up
);
50 * A (*,G) or a (*,*) is going away
51 * remove the parent pointer from
52 * those pointing at us
54 static void pim_upstream_remove_children(struct pim_instance
*pim
,
55 struct pim_upstream
*up
)
57 struct pim_upstream
*child
;
62 while (!list_isempty(up
->sources
)) {
63 child
= listnode_head(up
->sources
);
64 listnode_delete(up
->sources
, child
);
65 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child
->flags
)) {
66 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child
->flags
);
67 child
= pim_upstream_del(pim
, child
, __func__
);
71 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
72 pim_upstream_mroute_iif_update(
77 list_delete(&up
->sources
);
81 * A (*,G) or a (*,*) is being created
82 * Find the children that would point
85 static void pim_upstream_find_new_children(struct pim_instance
*pim
,
86 struct pim_upstream
*up
)
88 struct pim_upstream
*child
;
90 if (!pim_addr_is_any(up
->sg
.src
) && !pim_addr_is_any(up
->sg
.grp
))
93 if (pim_addr_is_any(up
->sg
.src
) && pim_addr_is_any(up
->sg
.grp
))
96 frr_each (rb_pim_upstream
, &pim
->upstream_head
, child
) {
97 if (!pim_addr_is_any(up
->sg
.grp
) &&
98 !pim_addr_cmp(child
->sg
.grp
, up
->sg
.grp
) && (child
!= up
)) {
100 listnode_add_sort(up
->sources
, child
);
101 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
102 pim_upstream_mroute_iif_update(
110 * If we have a (*,*) || (S,*) there is no parent
111 * If we have a (S,G), find the (*,G)
112 * If we have a (*,G), find the (*,*)
114 static struct pim_upstream
*pim_upstream_find_parent(struct pim_instance
*pim
,
115 struct pim_upstream
*child
)
117 pim_sgaddr any
= child
->sg
;
118 struct pim_upstream
*up
= NULL
;
121 if (!pim_addr_is_any(child
->sg
.src
) &&
122 !pim_addr_is_any(child
->sg
.grp
)) {
123 any
.src
= PIMADDR_ANY
;
124 up
= pim_upstream_find(pim
, &any
);
127 listnode_add(up
->sources
, child
);
130 * In case parent is MLAG entry copy the data to child
132 if (up
&& PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up
->flags
)) {
133 PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(child
->flags
);
134 if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up
->flags
))
135 PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(child
->flags
);
137 PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(
147 static void upstream_channel_oil_detach(struct pim_upstream
*up
)
149 struct channel_oil
*channel_oil
= up
->channel_oil
;
152 /* Detaching from channel_oil, channel_oil may exist post del,
153 but upstream would not keep reference of it
155 channel_oil
->up
= NULL
;
156 up
->channel_oil
= NULL
;
158 /* attempt to delete channel_oil; if channel_oil is being held
159 * because of other references cleanup info such as "Mute"
160 * inferred from the parent upstream
162 pim_channel_oil_upstream_deref(channel_oil
);
167 static void pim_upstream_timers_stop(struct pim_upstream
*up
)
169 EVENT_OFF(up
->t_ka_timer
);
170 EVENT_OFF(up
->t_rs_timer
);
171 EVENT_OFF(up
->t_msdp_reg_timer
);
172 EVENT_OFF(up
->t_join_timer
);
175 struct pim_upstream
*pim_upstream_del(struct pim_instance
*pim
,
176 struct pim_upstream
*up
, const char *name
)
178 struct listnode
*node
, *nnode
;
179 struct pim_ifchannel
*ch
;
180 bool notify_msdp
= false;
182 if (PIM_DEBUG_PIM_TRACE
)
184 "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
185 __func__
, name
, up
->sg_str
, pim
->vrf
->name
,
186 up
->ref_count
, up
->flags
,
187 up
->channel_oil
->oil_ref_count
);
189 assert(up
->ref_count
> 0);
193 if (up
->ref_count
>= 1)
197 zlog_debug("pim_upstream free vrf:%s %s flags 0x%x",
198 pim
->vrf
->name
, up
->sg_str
, up
->flags
);
200 if (pim_up_mlag_is_local(up
))
201 pim_mlag_up_local_del(pim
, up
);
203 pim_upstream_timers_stop(up
);
205 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
206 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 0);
208 if (pim_addr_is_any(up
->sg
.src
)) {
209 /* if a (*, G) entry in the joined state is being
211 * need to notify MSDP */
217 pim_jp_agg_upstream_verification(up
, false);
218 up
->rpf
.source_nexthop
.interface
= NULL
;
220 if (!pim_addr_is_any(up
->sg
.src
)) {
221 if (pim
->upstream_sg_wheel
)
222 wheel_remove_item(pim
->upstream_sg_wheel
, up
);
226 pim_mroute_del(up
->channel_oil
, __func__
);
227 upstream_channel_oil_detach(up
);
229 for (ALL_LIST_ELEMENTS(up
->ifchannels
, node
, nnode
, ch
))
230 pim_ifchannel_delete(ch
);
231 list_delete(&up
->ifchannels
);
233 pim_upstream_remove_children(pim
, up
);
235 list_delete(&up
->sources
);
237 if (up
->parent
&& up
->parent
->sources
)
238 listnode_delete(up
->parent
->sources
, up
);
241 rb_pim_upstream_del(&pim
->upstream_head
, up
);
244 pim_msdp_up_del(pim
, &up
->sg
);
247 /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT
248 * and assign up->upstream_addr as INADDR_ANY.
249 * So before de-registering the upstream address, check if is not equal
250 * to INADDR_ANY. This is done in order to avoid de-registering for
251 * 255.255.255.255 which is maintained for some reason..
253 if (!pim_addr_is_any(up
->upstream_addr
)) {
254 /* Deregister addr with Zebra NHT */
255 if (PIM_DEBUG_PIM_TRACE
)
257 "%s: Deregister upstream %s addr %pPA with Zebra NHT",
258 __func__
, up
->sg_str
, &up
->upstream_addr
);
259 pim_delete_tracked_nexthop(pim
, up
->upstream_addr
, up
, NULL
);
262 XFREE(MTYPE_PIM_UPSTREAM
, up
);
267 void pim_upstream_send_join(struct pim_upstream
*up
)
269 if (!up
->rpf
.source_nexthop
.interface
) {
270 if (PIM_DEBUG_PIM_TRACE
)
271 zlog_debug("%s: up %s RPF is not present", __func__
,
276 if (PIM_DEBUG_PIM_TRACE
) {
277 zlog_debug("%s: RPF'%s=%pPA(%s) for Interface %s", __func__
,
278 up
->sg_str
, &up
->rpf
.rpf_addr
,
279 pim_upstream_state2str(up
->join_state
),
280 up
->rpf
.source_nexthop
.interface
->name
);
281 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
282 zlog_debug("%s: can't send join upstream: RPF'%s=%pPA",
283 __func__
, up
->sg_str
, &up
->rpf
.rpf_addr
);
288 /* send Join(S,G) to the current upstream neighbor */
289 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 1 /* join */);
292 static void on_join_timer(struct event
*t
)
294 struct pim_upstream
*up
;
298 if (!up
->rpf
.source_nexthop
.interface
) {
299 if (PIM_DEBUG_PIM_TRACE
)
300 zlog_debug("%s: up %s RPF is not present", __func__
,
306 * In the case of a HFR we will not ahve anyone to send this to.
308 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
312 * Don't send the join if the outgoing interface is a loopback
313 * But since this might change leave the join timer running
315 if (up
->rpf
.source_nexthop
316 .interface
&& !if_is_loopback(up
->rpf
.source_nexthop
.interface
))
317 pim_upstream_send_join(up
);
319 join_timer_start(up
);
322 static void join_timer_stop(struct pim_upstream
*up
)
324 struct pim_neighbor
*nbr
= NULL
;
326 EVENT_OFF(up
->t_join_timer
);
328 if (up
->rpf
.source_nexthop
.interface
)
329 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
330 up
->rpf
.rpf_addr
, true);
333 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
, nbr
);
335 pim_jp_agg_upstream_verification(up
, false);
338 void join_timer_start(struct pim_upstream
*up
)
340 struct pim_neighbor
*nbr
= NULL
;
342 if (up
->rpf
.source_nexthop
.interface
) {
343 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
344 up
->rpf
.rpf_addr
, true);
346 if (PIM_DEBUG_PIM_EVENTS
) {
348 "%s: starting %d sec timer for upstream (S,G)=%s",
349 __func__
, router
->t_periodic
, up
->sg_str
);
354 pim_jp_agg_add_group(nbr
->upstream_jp_agg
, up
, 1, nbr
);
356 EVENT_OFF(up
->t_join_timer
);
357 event_add_timer(router
->master
, on_join_timer
, up
,
358 router
->t_periodic
, &up
->t_join_timer
);
360 pim_jp_agg_upstream_verification(up
, true);
364 * This is only called when we are switching the upstream
365 * J/P from one neighbor to another
367 * As such we need to remove from the old list and
368 * add to the new list.
370 void pim_upstream_join_timer_restart(struct pim_upstream
*up
,
373 // EVENT_OFF(up->t_join_timer);
374 join_timer_start(up
);
377 static void pim_upstream_join_timer_restart_msec(struct pim_upstream
*up
,
380 if (PIM_DEBUG_PIM_EVENTS
) {
381 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
382 __func__
, interval_msec
, up
->sg_str
);
385 EVENT_OFF(up
->t_join_timer
);
386 event_add_timer_msec(router
->master
, on_join_timer
, up
, interval_msec
,
390 void pim_update_suppress_timers(uint32_t suppress_time
)
392 struct pim_instance
*pim
;
394 unsigned int old_rp_ka_time
;
396 /* stash the old one so we know which values were manually configured */
397 old_rp_ka_time
= (3 * router
->register_suppress_time
398 + router
->register_probe_time
);
399 router
->register_suppress_time
= suppress_time
;
401 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
406 /* Only adjust if not manually configured */
407 if (pim
->rp_keep_alive_time
== old_rp_ka_time
)
408 pim
->rp_keep_alive_time
= PIM_RP_KEEPALIVE_PERIOD
;
412 void pim_upstream_join_suppress(struct pim_upstream
*up
, pim_addr rpf
,
415 long t_joinsuppress_msec
;
416 long join_timer_remain_msec
= 0;
417 struct pim_neighbor
*nbr
= NULL
;
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 if (up
->t_join_timer
)
431 join_timer_remain_msec
=
432 pim_time_timer_remain_msec(up
->t_join_timer
);
434 /* Remove it from jp agg from the nbr for suppression */
435 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
436 up
->rpf
.rpf_addr
, true);
439 join_timer_remain_msec
=
440 pim_time_timer_remain_msec(nbr
->jp_timer
);
444 if (PIM_DEBUG_PIM_TRACE
)
446 "%s %s: detected Join%s to RPF'(S,G)=%pPA: join_timer=%ld msec t_joinsuppress=%ld msec",
447 __FILE__
, __func__
, up
->sg_str
, &rpf
,
448 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
, true);
492 join_timer_remain_msec
=
493 pim_time_timer_remain_msec(nbr
->jp_timer
);
495 /* Manipulate such that override takes place */
496 join_timer_remain_msec
= t_override_msec
+ 1;
499 if (PIM_DEBUG_PIM_TRACE
)
501 "%s: to RPF'%s=%pPA: join_timer=%ld msec t_override=%d msec",
502 debug_label
, up
->sg_str
, &up
->rpf
.rpf_addr
,
503 join_timer_remain_msec
, t_override_msec
);
505 if (join_timer_remain_msec
> t_override_msec
) {
506 if (PIM_DEBUG_PIM_TRACE
) {
508 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
509 debug_label
, up
->sg_str
, t_override_msec
);
512 pim_upstream_join_timer_restart_msec(up
, t_override_msec
);
516 static void forward_on(struct pim_upstream
*up
)
518 struct listnode
*chnode
;
519 struct listnode
*chnextnode
;
520 struct pim_ifchannel
*ch
= NULL
;
522 /* scan (S,G) state */
523 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
524 if (pim_macro_chisin_oiflist(ch
))
525 pim_forward_start(ch
);
527 } /* scan iface channel list */
530 static void forward_off(struct pim_upstream
*up
)
532 struct listnode
*chnode
;
533 struct listnode
*chnextnode
;
534 struct pim_ifchannel
*ch
;
536 /* scan per-interface (S,G) state */
537 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
539 pim_forward_stop(ch
);
541 } /* scan iface channel list */
544 int pim_upstream_could_register(struct pim_upstream
*up
)
546 struct pim_interface
*pim_ifp
= NULL
;
548 /* FORCE_PIMREG is a generic flag to let an app like VxLAN-AA register
549 * a source on an upstream entry even if the source is not directly
550 * connected on the IIF.
552 if (PIM_UPSTREAM_FLAG_TEST_FORCE_PIMREG(up
->flags
))
555 if (up
->rpf
.source_nexthop
.interface
)
556 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
558 if (PIM_DEBUG_PIM_TRACE
)
559 zlog_debug("%s: up %s RPF is not present", __func__
,
563 if (pim_ifp
&& PIM_I_am_DR(pim_ifp
)
564 && pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
571 /* Source registration is suppressed for SSM groups. When the SSM range changes
572 * we re-revaluate register setup for existing upstream entries */
573 void pim_upstream_register_reevaluate(struct pim_instance
*pim
)
575 struct pim_upstream
*up
;
577 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
578 /* If FHR is set CouldRegister is True. Also check if the flow
579 * is actually active; if it is not kat setup will trigger
581 * registration whenever the flow becomes active. */
582 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) ||
583 !pim_upstream_is_kat_running(up
))
586 if (pim_is_grp_ssm(pim
, up
->sg
.grp
)) {
587 /* clear the register state for SSM groups */
588 if (up
->reg_state
!= PIM_REG_NOINFO
) {
589 if (PIM_DEBUG_PIM_EVENTS
)
591 "Clear register for %s as G is now SSM",
593 /* remove regiface from the OIL if it is there*/
594 pim_channel_del_oif(up
->channel_oil
,
596 PIM_OIF_FLAG_PROTO_PIM
,
598 up
->reg_state
= PIM_REG_NOINFO
;
601 /* register ASM sources with the RP */
602 if (up
->reg_state
== PIM_REG_NOINFO
) {
603 if (PIM_DEBUG_PIM_EVENTS
)
605 "Register %s as G is now ASM",
607 pim_channel_add_oif(up
->channel_oil
,
609 PIM_OIF_FLAG_PROTO_PIM
,
611 up
->reg_state
= PIM_REG_JOIN
;
617 /* RFC7761, Section 4.2 “Data Packet Forwarding Rules” says we should
619 * 1. along the SPT if SPTbit is set
620 * 2. and along the RPT if SPTbit is not set
621 * If forwarding is hw accelerated i.e. control and dataplane components
622 * are separate you may not be able to reliably set SPT bit on intermediate
623 * routers while still forwarding on the (S,G,rpt).
625 * This macro is a slight deviation on the RFC and uses "traffic-agnostic"
626 * criteria to decide between using the RPT vs. SPT for forwarding.
628 void pim_upstream_update_use_rpt(struct pim_upstream
*up
,
634 if (pim_addr_is_any(up
->sg
.src
))
637 old_use_rpt
= !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
639 /* We will use the SPT (IIF=RPF_interface(S) if -
640 * 1. We have decided to join the SPT
642 * 3. Source is directly connected
643 * 4. We are RP (parent's IIF is lo or vrf-device)
644 * In all other cases the source will stay along the RPT and
645 * IIF=RPF_interface(RP).
647 if (up
->join_state
== PIM_UPSTREAM_JOINED
||
648 PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) ||
649 pim_if_connected_to_source(
650 up
->rpf
.source_nexthop
.interface
,
652 /* XXX - need to switch this to a more efficient
655 I_am_RP(up
->pim
, up
->sg
.grp
))
657 PIM_UPSTREAM_FLAG_UNSET_USE_RPT(up
->flags
);
660 PIM_UPSTREAM_FLAG_SET_USE_RPT(up
->flags
);
662 new_use_rpt
= !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
663 if (old_use_rpt
!= new_use_rpt
) {
664 if (PIM_DEBUG_PIM_EVENTS
)
665 zlog_debug("%s switched from %s to %s",
667 old_use_rpt
?"RPT":"SPT",
668 new_use_rpt
?"RPT":"SPT");
670 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
674 /* some events like RP change require re-evaluation of SGrpt across
677 void pim_upstream_reeval_use_rpt(struct pim_instance
*pim
)
679 struct pim_upstream
*up
;
681 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
682 if (pim_addr_is_any(up
->sg
.src
))
685 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
689 void pim_upstream_switch(struct pim_instance
*pim
, struct pim_upstream
*up
,
690 enum pim_upstream_state new_state
)
692 enum pim_upstream_state old_state
= up
->join_state
;
694 if (pim_addr_is_any(up
->upstream_addr
)) {
695 if (PIM_DEBUG_PIM_EVENTS
)
696 zlog_debug("%s: RPF not configured for %s", __func__
,
701 if (!up
->rpf
.source_nexthop
.interface
) {
702 if (PIM_DEBUG_PIM_EVENTS
)
703 zlog_debug("%s: RP not reachable for %s", __func__
,
708 if (PIM_DEBUG_PIM_EVENTS
) {
709 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
710 __func__
, up
->sg_str
,
711 pim_upstream_state2str(up
->join_state
),
712 pim_upstream_state2str(new_state
));
715 up
->join_state
= new_state
;
716 if (old_state
!= new_state
)
717 up
->state_transition
= pim_time_monotonic_sec();
719 pim_upstream_update_assert_tracking_desired(up
);
721 if (new_state
== PIM_UPSTREAM_JOINED
) {
722 pim_upstream_inherited_olist_decide(pim
, up
);
723 if (old_state
!= PIM_UPSTREAM_JOINED
) {
724 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
726 pim_msdp_up_join_state_changed(pim
, up
);
727 if (pim_upstream_could_register(up
)) {
728 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
730 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
732 pim_upstream_keep_alive_timer_start(
733 up
, pim
->keep_alive_time
);
734 pim_register_join(up
);
737 pim_upstream_send_join(up
);
738 join_timer_start(up
);
741 if (old_state
!= new_state
)
742 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
746 bool send_xg_jp
= false;
750 * RFC 4601 Sec 4.5.7:
751 * JoinDesired(S,G) -> False, set SPTbit to false.
753 if (!pim_addr_is_any(up
->sg
.src
))
754 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
756 if (old_state
== PIM_UPSTREAM_JOINED
)
757 pim_msdp_up_join_state_changed(pim
, up
);
759 if (old_state
!= new_state
) {
761 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
762 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
764 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
766 (new_use_rpt
!= old_use_rpt
) &&
768 /* we have decided to switch from the SPT back
769 * to the RPT which means we need to cancel
770 * any previously sent SGrpt prunes immediately
775 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
777 If I am RP for G then send S,G prune to its IIF. */
778 if (pim_upstream_is_sg_rpt(up
) && up
->parent
&&
779 !I_am_RP(pim
, up
->sg
.grp
))
782 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 0 /* prune */);
785 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
787 "re-join RPT; *,G IIF %s S,G IIF %s ",
788 up
->parent
->rpf
.source_nexthop
.interface
?
789 up
->parent
->rpf
.source_nexthop
.interface
->name
791 up
->rpf
.source_nexthop
.interface
?
792 up
->rpf
.source_nexthop
.interface
->name
:
794 pim_jp_agg_single_upstream_send(&up
->parent
->rpf
,
802 int pim_upstream_compare(const struct pim_upstream
*up1
,
803 const struct pim_upstream
*up2
)
805 return pim_sgaddr_cmp(up1
->sg
, up2
->sg
);
808 void pim_upstream_fill_static_iif(struct pim_upstream
*up
,
809 struct interface
*incoming
)
811 up
->rpf
.source_nexthop
.interface
= incoming
;
813 /* reset other parameters to matched a connected incoming interface */
814 up
->rpf
.source_nexthop
.mrib_nexthop_addr
= PIMADDR_ANY
;
815 up
->rpf
.source_nexthop
.mrib_metric_preference
=
816 ZEBRA_CONNECT_DISTANCE_DEFAULT
;
817 up
->rpf
.source_nexthop
.mrib_route_metric
= 0;
818 up
->rpf
.rpf_addr
= PIMADDR_ANY
;
821 static struct pim_upstream
*pim_upstream_new(struct pim_instance
*pim
,
823 struct interface
*incoming
,
825 struct pim_ifchannel
*ch
)
827 enum pim_rpf_result rpf_result
;
828 struct pim_interface
*pim_ifp
;
829 struct pim_upstream
*up
;
831 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
835 snprintfrr(up
->sg_str
, sizeof(up
->sg_str
), "%pSG", sg
);
839 rb_pim_upstream_add(&pim
->upstream_head
, up
);
840 /* Set up->upstream_addr as INADDR_ANY, if RP is not
841 * configured and retain the upstream data structure
843 if (!pim_rp_set_upstream_addr(pim
, &up
->upstream_addr
, sg
->src
,
845 if (PIM_DEBUG_PIM_TRACE
)
846 zlog_debug("%s: Received a (*,G) with no RP configured",
850 up
->parent
= pim_upstream_find_parent(pim
, up
);
851 if (pim_addr_is_any(up
->sg
.src
)) {
852 up
->sources
= list_new();
854 (int (*)(void *, void *))pim_upstream_compare
;
858 pim_upstream_find_new_children(pim
, up
);
861 up
->t_join_timer
= NULL
;
862 up
->t_ka_timer
= NULL
;
863 up
->t_rs_timer
= NULL
;
864 up
->t_msdp_reg_timer
= NULL
;
865 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
866 up
->reg_state
= PIM_REG_NOINFO
;
867 up
->state_transition
= pim_time_monotonic_sec();
868 up
->channel_oil
= pim_channel_oil_add(pim
, &up
->sg
, __func__
);
869 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
871 up
->rpf
.source_nexthop
.interface
= NULL
;
872 up
->rpf
.source_nexthop
.mrib_nexthop_addr
= PIMADDR_ANY
;
873 up
->rpf
.source_nexthop
.mrib_metric_preference
=
874 router
->infinite_assert_metric
.metric_preference
;
875 up
->rpf
.source_nexthop
.mrib_route_metric
=
876 router
->infinite_assert_metric
.route_metric
;
877 up
->rpf
.rpf_addr
= PIMADDR_ANY
;
878 up
->ifchannels
= list_new();
879 up
->ifchannels
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
881 if (!pim_addr_is_any(up
->sg
.src
)) {
882 wheel_add_item(pim
->upstream_sg_wheel
, up
);
884 /* Inherit the DF role from the parent (*, G) entry for
888 && PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up
->parent
->flags
)
889 && PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up
->parent
->flags
)) {
890 PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(up
->flags
);
893 "upstream %s inherited mlag non-df flag from parent",
898 if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up
->flags
)
899 || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
)) {
900 pim_upstream_fill_static_iif(up
, incoming
);
901 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
903 pim_upstream_update_use_rpt(up
,
904 false /*update_mroute*/);
905 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
907 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
))
908 pim_upstream_keep_alive_timer_start(
909 up
, pim
->keep_alive_time
);
910 } else if (!pim_addr_is_any(up
->upstream_addr
)) {
911 pim_upstream_update_use_rpt(up
,
912 false /*update_mroute*/);
913 rpf_result
= pim_rpf_update(pim
, up
, NULL
, __func__
);
914 if (rpf_result
== PIM_RPF_FAILURE
) {
915 if (PIM_DEBUG_PIM_TRACE
)
917 "%s: Attempting to create upstream(%s), Unable to RPF for source",
918 __func__
, up
->sg_str
);
921 /* Consider a case where (S,G,rpt) prune is received and this
922 * upstream is getting created due to that, then as per RFC
923 * until prune pending time we need to behave same as NOINFO
924 * state, therefore do not install if OIF is NULL until then
925 * This is for PIM Conformance PIM-SM 16.3 fix
926 * When the prune pending timer pop, this mroute will get
927 * installed with none as OIF */
928 if (up
->rpf
.source_nexthop
.interface
&&
929 !(pim_upstream_empty_inherited_olist(up
) && (ch
!= NULL
) &&
930 PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))) {
931 pim_upstream_mroute_iif_update(up
->channel_oil
,
936 /* send the entry to the MLAG peer */
937 /* XXX - duplicate send is possible here if pim_rpf_update
938 * successfully resolved the nexthop
940 if (pim_up_mlag_is_local(up
)
941 || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up
->flags
))
942 pim_mlag_up_local_add(pim
, up
);
944 if (PIM_DEBUG_PIM_TRACE
) {
946 "%s: Created Upstream %s upstream_addr %pPAs ref count %d increment",
947 __func__
, up
->sg_str
, &up
->upstream_addr
,
954 uint32_t pim_up_mlag_local_cost(struct pim_upstream
*up
)
956 if (!(pim_up_mlag_is_local(up
))
957 && !(up
->flags
& PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE
))
958 return router
->infinite_assert_metric
.route_metric
;
960 if ((up
->rpf
.source_nexthop
.interface
==
961 up
->pim
->vxlan
.peerlink_rif
) &&
962 (up
->rpf
.source_nexthop
.mrib_route_metric
<
963 (router
->infinite_assert_metric
.route_metric
-
964 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC
)))
965 return up
->rpf
.source_nexthop
.mrib_route_metric
+
966 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC
;
968 return up
->rpf
.source_nexthop
.mrib_route_metric
;
971 uint32_t pim_up_mlag_peer_cost(struct pim_upstream
*up
)
973 if (!(up
->flags
& PIM_UPSTREAM_FLAG_MASK_MLAG_PEER
))
974 return router
->infinite_assert_metric
.route_metric
;
976 return up
->mlag
.peer_mrib_metric
;
979 struct pim_upstream
*pim_upstream_find(struct pim_instance
*pim
, pim_sgaddr
*sg
)
981 struct pim_upstream lookup
;
982 struct pim_upstream
*up
= NULL
;
985 up
= rb_pim_upstream_find(&pim
->upstream_head
, &lookup
);
989 struct pim_upstream
*pim_upstream_find_or_add(pim_sgaddr
*sg
,
990 struct interface
*incoming
,
991 int flags
, const char *name
)
993 struct pim_interface
*pim_ifp
= incoming
->info
;
995 return (pim_upstream_add(pim_ifp
->pim
, sg
, incoming
, flags
, name
,
999 void pim_upstream_ref(struct pim_upstream
*up
, int flags
, const char *name
)
1001 /* if a local MLAG reference is being created we need to send the mroute
1004 if (!PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up
->flags
) &&
1005 PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags
)) {
1006 PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(up
->flags
);
1007 pim_mlag_up_local_add(up
->pim
, up
);
1010 /* when we go from non-FHR to FHR we need to re-eval traffic
1013 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) &&
1014 PIM_UPSTREAM_FLAG_TEST_FHR(flags
)) {
1015 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1016 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
1019 /* re-eval joinDesired; clearing peer-msdp-sa flag can
1020 * cause JD to change
1022 if (!PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up
->flags
) &&
1023 PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags
)) {
1024 PIM_UPSTREAM_FLAG_SET_SRC_MSDP(up
->flags
);
1025 pim_upstream_update_join_desired(up
->pim
, up
);
1030 if (PIM_DEBUG_PIM_TRACE
)
1031 zlog_debug("%s(%s): upstream %s ref count %d increment",
1032 __func__
, name
, up
->sg_str
, up
->ref_count
);
1035 struct pim_upstream
*pim_upstream_add(struct pim_instance
*pim
, pim_sgaddr
*sg
,
1036 struct interface
*incoming
, int flags
,
1038 struct pim_ifchannel
*ch
)
1040 struct pim_upstream
*up
= NULL
;
1043 up
= pim_upstream_find(pim
, sg
);
1045 pim_upstream_ref(up
, flags
, name
);
1048 up
= pim_upstream_new(pim
, sg
, incoming
, flags
, ch
);
1051 if (PIM_DEBUG_PIM_TRACE
) {
1053 "%s(%s): %s, iif %pPA (%s) found: %d: ref_count: %d",
1054 __func__
, name
, up
->sg_str
, &up
->rpf
.rpf_addr
,
1055 up
->rpf
.source_nexthop
.interface
? up
->rpf
.source_nexthop
1058 found
, up
->ref_count
);
1065 * Passed in up must be the upstream for ch. starch is NULL if no
1067 * This function is copied over from
1068 * pim_upstream_evaluate_join_desired_interface but limited to
1069 * parent (*,G)'s includes/joins.
1071 int pim_upstream_eval_inherit_if(struct pim_upstream
*up
,
1072 struct pim_ifchannel
*ch
,
1073 struct pim_ifchannel
*starch
)
1075 /* if there is an explicit prune for this interface we cannot
1079 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1083 /* Check if the OIF can be inherited fron the (*,G) entry
1086 if (!pim_macro_ch_lost_assert(starch
)
1087 && pim_macro_chisin_joins_or_include(starch
))
1095 * Passed in up must be the upstream for ch. starch is NULL if no
1098 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream
*up
,
1099 struct pim_ifchannel
*ch
,
1100 struct pim_ifchannel
*starch
)
1103 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1106 if (!pim_macro_ch_lost_assert(ch
)
1107 && pim_macro_chisin_joins_or_include(ch
))
1115 /* XXX: check on this with donald
1116 * we are looking for PIM_IF_FLAG_MASK_S_G_RPT in
1120 if (PIM_IF_FLAG_TEST_S_G_RPT(starch
->upstream
->flags
))
1124 if (!pim_macro_ch_lost_assert(starch
)
1125 && pim_macro_chisin_joins_or_include(starch
))
1132 /* Returns true if immediate OIL is empty and is used to evaluate
1133 * JoinDesired. See pim_upstream_evaluate_join_desired.
1135 static bool pim_upstream_empty_immediate_olist(struct pim_instance
*pim
,
1136 struct pim_upstream
*up
)
1138 struct interface
*ifp
;
1139 struct pim_ifchannel
*ch
;
1141 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1145 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1149 /* If we have even one immediate OIF we can return with
1152 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1155 } /* scan iface channel list */
1157 /* immediate_oil is empty */
1162 static inline bool pim_upstream_is_msdp_peer_sa(struct pim_upstream
*up
)
1164 return PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up
->flags
);
1168 * bool JoinDesired(*,G) {
1169 * if (immediate_olist(*,G) != NULL)
1175 * bool JoinDesired(S,G) {
1176 * return( immediate_olist(S,G) != NULL
1177 * OR ( KeepaliveTimer(S,G) is running
1178 * AND inherited_olist(S,G) != NULL ) )
1181 bool pim_upstream_evaluate_join_desired(struct pim_instance
*pim
,
1182 struct pim_upstream
*up
)
1187 empty_imm_oil
= pim_upstream_empty_immediate_olist(pim
, up
);
1190 if (pim_addr_is_any(up
->sg
.src
))
1191 return !empty_imm_oil
;
1196 empty_inh_oil
= pim_upstream_empty_inherited_olist(up
);
1197 if (!empty_inh_oil
&&
1198 (pim_upstream_is_kat_running(up
) ||
1199 pim_upstream_is_msdp_peer_sa(up
)))
1206 See also pim_upstream_evaluate_join_desired() above.
1208 void pim_upstream_update_join_desired(struct pim_instance
*pim
,
1209 struct pim_upstream
*up
)
1211 int was_join_desired
; /* boolean */
1212 int is_join_desired
; /* boolean */
1214 was_join_desired
= PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up
->flags
);
1216 is_join_desired
= pim_upstream_evaluate_join_desired(pim
, up
);
1217 if (is_join_desired
)
1218 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up
->flags
);
1220 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up
->flags
);
1222 /* switched from false to true */
1223 if (is_join_desired
&& (up
->join_state
== PIM_UPSTREAM_NOTJOINED
)) {
1224 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
1228 /* switched from true to false */
1229 if (!is_join_desired
&& was_join_desired
) {
1230 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_NOTJOINED
);
1236 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
1237 Transitions from Joined State
1238 RPF'(S,G) GenID changes
1240 The upstream (S,G) state machine remains in Joined state. If the
1241 Join Timer is set to expire in more than t_override seconds, reset
1242 it so that it expires after t_override seconds.
1244 void pim_upstream_rpf_genid_changed(struct pim_instance
*pim
,
1245 pim_addr neigh_addr
)
1247 struct pim_upstream
*up
;
1250 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1252 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
1255 rpf_addr
= up
->rpf
.rpf_addr
;
1257 if (PIM_DEBUG_PIM_TRACE
)
1259 "%s: matching neigh=%pPA against upstream (S,G)=%s[%s] joined=%d rpf_addr=%pPA",
1260 __func__
, &neigh_addr
, up
->sg_str
,
1262 up
->join_state
== PIM_UPSTREAM_JOINED
,
1265 /* consider only (S,G) upstream in Joined state */
1266 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
1269 /* match RPF'(S,G)=neigh_addr */
1270 if (pim_addr_cmp(rpf_addr
, neigh_addr
))
1273 pim_upstream_join_timer_decrease_to_t_override(
1274 "RPF'(S,G) GenID change", up
);
1279 void pim_upstream_rpf_interface_changed(struct pim_upstream
*up
,
1280 struct interface
*old_rpf_ifp
)
1282 struct listnode
*chnode
;
1283 struct listnode
*chnextnode
;
1284 struct pim_ifchannel
*ch
;
1286 /* search all ifchannels */
1287 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1288 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
1290 /* RPF_interface(S) was NOT I */
1291 (old_rpf_ifp
== ch
->interface
) &&
1292 /* RPF_interface(S) stopped being I */
1293 (ch
->upstream
->rpf
.source_nexthop
1295 (ch
->upstream
->rpf
.source_nexthop
1296 .interface
!= ch
->interface
)) {
1297 assert_action_a5(ch
);
1299 } /* PIM_IFASSERT_I_AM_LOSER */
1301 pim_ifchannel_update_assert_tracking_desired(ch
);
1305 void pim_upstream_update_could_assert(struct pim_upstream
*up
)
1307 struct listnode
*chnode
;
1308 struct listnode
*chnextnode
;
1309 struct pim_ifchannel
*ch
;
1311 /* scan per-interface (S,G) state */
1312 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1313 pim_ifchannel_update_could_assert(ch
);
1314 } /* scan iface channel list */
1317 void pim_upstream_update_my_assert_metric(struct pim_upstream
*up
)
1319 struct listnode
*chnode
;
1320 struct listnode
*chnextnode
;
1321 struct pim_ifchannel
*ch
;
1323 /* scan per-interface (S,G) state */
1324 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1325 pim_ifchannel_update_my_assert_metric(ch
);
1327 } /* scan iface channel list */
1330 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
)
1332 struct listnode
*chnode
;
1333 struct listnode
*chnextnode
;
1334 struct pim_interface
*pim_ifp
;
1335 struct pim_ifchannel
*ch
;
1337 /* scan per-interface (S,G) state */
1338 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1341 pim_ifp
= ch
->interface
->info
;
1345 pim_ifchannel_update_assert_tracking_desired(ch
);
1347 } /* scan iface channel list */
1350 /* When kat is stopped CouldRegister goes to false so we need to
1351 * transition the (S, G) on FHR to NI state and remove reg tunnel
1353 static void pim_upstream_fhr_kat_expiry(struct pim_instance
*pim
,
1354 struct pim_upstream
*up
)
1356 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
1359 if (PIM_DEBUG_PIM_TRACE
)
1360 zlog_debug("kat expired on %s; clear fhr reg state",
1363 /* stop reg-stop timer */
1364 EVENT_OFF(up
->t_rs_timer
);
1365 /* remove regiface from the OIL if it is there*/
1366 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1367 PIM_OIF_FLAG_PROTO_PIM
, __func__
);
1368 /* clear the register state */
1369 up
->reg_state
= PIM_REG_NOINFO
;
1370 PIM_UPSTREAM_FLAG_UNSET_FHR(up
->flags
);
1373 /* When kat is started CouldRegister can go to true. And if it does we
1374 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1376 static void pim_upstream_fhr_kat_start(struct pim_upstream
*up
)
1378 if (pim_upstream_could_register(up
)) {
1379 if (PIM_DEBUG_PIM_TRACE
)
1381 "kat started on %s; set fhr reg state to joined",
1384 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1385 if (up
->reg_state
== PIM_REG_NOINFO
)
1386 pim_register_join(up
);
1387 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
1392 * On an RP, the PMBR value must be cleared when the
1393 * Keepalive Timer expires
1394 * KAT expiry indicates that flow is inactive. If the flow was created or
1395 * maintained by activity now is the time to deref it.
1397 struct pim_upstream
*pim_upstream_keep_alive_timer_proc(
1398 struct pim_upstream
*up
)
1400 struct pim_instance
*pim
;
1402 pim
= up
->channel_oil
->pim
;
1404 if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up
->flags
)) {
1405 /* if the router is a PIM vxlan encapsulator we prevent expiry
1406 * of KAT as the mroute is pre-setup without any traffic
1408 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1412 if (I_am_RP(pim
, up
->sg
.grp
)) {
1414 * Handle Border Router
1415 * We need to do more here :)
1416 * But this is the start.
1420 /* source is no longer active - pull the SA from MSDP's cache */
1421 pim_msdp_sa_local_del(pim
, &up
->sg
);
1423 /* JoinDesired can change when KAT is started or stopped */
1424 pim_upstream_update_join_desired(pim
, up
);
1426 /* if entry was created because of activity we need to deref it */
1427 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1428 pim_upstream_fhr_kat_expiry(pim
, up
);
1429 if (PIM_DEBUG_PIM_TRACE
)
1431 "kat expired on %s[%s]; remove stream reference",
1432 up
->sg_str
, pim
->vrf
->name
);
1433 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up
->flags
);
1435 /* Return if upstream entry got deleted.*/
1436 if (!pim_upstream_del(pim
, up
, __func__
))
1439 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
)) {
1440 PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up
->flags
);
1442 if (!pim_upstream_del(pim
, up
, __func__
))
1446 /* upstream reference would have been added to track the local
1447 * membership if it is LHR. We have to clear it when KAT expires.
1448 * Otherwise would result in stale entry with uncleared ref count.
1450 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
1451 struct pim_upstream
*parent
= up
->parent
;
1453 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1454 up
= pim_upstream_del(pim
, up
, __func__
);
1457 pim_jp_agg_single_upstream_send(&parent
->rpf
, parent
,
1464 static void pim_upstream_keep_alive_timer(struct event
*t
)
1466 struct pim_upstream
*up
;
1470 /* pull the stats and re-check */
1471 if (pim_upstream_sg_running_proc(up
))
1472 /* kat was restarted because of new activity */
1475 pim_upstream_keep_alive_timer_proc(up
);
1478 void pim_upstream_keep_alive_timer_start(struct pim_upstream
*up
, uint32_t time
)
1480 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1481 if (PIM_DEBUG_PIM_TRACE
)
1482 zlog_debug("kat start on %s with no stream reference",
1485 EVENT_OFF(up
->t_ka_timer
);
1486 event_add_timer(router
->master
, pim_upstream_keep_alive_timer
, up
, time
,
1489 /* any time keepalive is started against a SG we will have to
1490 * re-evaluate our active source database */
1491 pim_msdp_sa_local_update(up
);
1492 /* JoinDesired can change when KAT is started or stopped */
1493 pim_upstream_update_join_desired(up
->pim
, up
);
1496 /* MSDP on RP needs to know if a source is registerable to this RP */
1497 static void pim_upstream_msdp_reg_timer(struct event
*t
)
1499 struct pim_upstream
*up
= EVENT_ARG(t
);
1500 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1502 /* source is no longer active - pull the SA from MSDP's cache */
1503 pim_msdp_sa_local_del(pim
, &up
->sg
);
1506 void pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1508 EVENT_OFF(up
->t_msdp_reg_timer
);
1509 event_add_timer(router
->master
, pim_upstream_msdp_reg_timer
, up
,
1510 PIM_MSDP_REG_RXED_PERIOD
, &up
->t_msdp_reg_timer
);
1512 pim_msdp_sa_local_update(up
);
1516 * 4.2.1 Last-Hop Switchover to the SPT
1518 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1519 * RP. Once traffic from sources to joined groups arrives at a last-hop
1520 * router, it has the option of switching to receive the traffic on a
1521 * shortest path tree (SPT).
1523 * The decision for a router to switch to the SPT is controlled as
1527 * CheckSwitchToSpt(S,G) {
1528 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1529 * (+) pim_include(S,G) != NULL )
1530 * AND SwitchToSptDesired(S,G) ) {
1531 * # Note: Restarting the KAT will result in the SPT switch
1532 * set KeepaliveTimer(S,G) to Keepalive_Period
1536 * SwitchToSptDesired(S,G) is a policy function that is implementation
1537 * defined. An "infinite threshold" policy can be implemented by making
1538 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1539 * first packet" policy can be implemented by making
1540 * SwitchToSptDesired(S,G) return true once a single packet has been
1541 * received for the source and group.
1543 int pim_upstream_switch_to_spt_desired_on_rp(struct pim_instance
*pim
,
1546 if (I_am_RP(pim
, sg
->grp
))
1552 int pim_upstream_is_sg_rpt(struct pim_upstream
*up
)
1554 struct listnode
*chnode
;
1555 struct pim_ifchannel
*ch
;
1557 for (ALL_LIST_ELEMENTS_RO(up
->ifchannels
, chnode
, ch
)) {
1558 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1565 * After receiving a packet set SPTbit:
1567 * Update_SPTbit(S,G,iif) {
1568 * if ( iif == RPF_interface(S)
1569 * AND JoinDesired(S,G) == true
1570 * AND ( DirectlyConnected(S) == true
1571 * OR RPF_interface(S) != RPF_interface(RP(G))
1572 * OR inherited_olist(S,G,rpt) == NULL
1573 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1574 * ( RPF'(S,G) != NULL ) )
1575 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1576 * Set SPTbit(S,G) to true
1580 void pim_upstream_set_sptbit(struct pim_upstream
*up
,
1581 struct interface
*incoming
)
1583 struct pim_upstream
*starup
= up
->parent
;
1585 // iif == RPF_interfvace(S)
1586 if (up
->rpf
.source_nexthop
.interface
!= incoming
) {
1587 if (PIM_DEBUG_PIM_TRACE
)
1589 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1590 __func__
, incoming
->name
,
1591 up
->rpf
.source_nexthop
.interface
->name
);
1595 // AND JoinDesired(S,G) == true
1596 if (!pim_upstream_evaluate_join_desired(up
->channel_oil
->pim
, up
)) {
1597 if (PIM_DEBUG_PIM_TRACE
)
1598 zlog_debug("%s: %s Join is not Desired", __func__
,
1603 // DirectlyConnected(S) == true
1604 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1606 if (PIM_DEBUG_PIM_TRACE
)
1607 zlog_debug("%s: %s is directly connected to the source",
1608 __func__
, up
->sg_str
);
1609 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1613 // OR RPF_interface(S) != RPF_interface(RP(G))
1615 || up
->rpf
.source_nexthop
1616 .interface
!= starup
->rpf
.source_nexthop
.interface
) {
1617 struct pim_upstream
*starup
= up
->parent
;
1619 if (PIM_DEBUG_PIM_TRACE
)
1621 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1622 __func__
, up
->sg_str
);
1623 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1625 pim_jp_agg_single_upstream_send(&starup
->rpf
, starup
, true);
1629 // OR inherited_olist(S,G,rpt) == NULL
1630 if (pim_upstream_is_sg_rpt(up
)
1631 && pim_upstream_empty_inherited_olist(up
)) {
1632 if (PIM_DEBUG_PIM_TRACE
)
1633 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1634 __func__
, up
->sg_str
);
1635 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1639 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1640 // ( RPF'(S,G) != NULL ) )
1641 if (up
->parent
&& pim_rpf_is_same(&up
->rpf
, &up
->parent
->rpf
)) {
1642 if (PIM_DEBUG_PIM_TRACE
)
1643 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1644 __func__
, up
->sg_str
);
1645 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1652 const char *pim_upstream_state2str(enum pim_upstream_state join_state
)
1654 switch (join_state
) {
1655 case PIM_UPSTREAM_NOTJOINED
:
1657 case PIM_UPSTREAM_JOINED
:
1663 const char *pim_reg_state2str(enum pim_reg_state reg_state
, char *state_str
,
1664 size_t state_str_len
)
1666 switch (reg_state
) {
1667 case PIM_REG_NOINFO
:
1668 strlcpy(state_str
, "RegNoInfo", state_str_len
);
1671 strlcpy(state_str
, "RegJoined", state_str_len
);
1673 case PIM_REG_JOIN_PENDING
:
1674 strlcpy(state_str
, "RegJoinPend", state_str_len
);
1677 strlcpy(state_str
, "RegPrune", state_str_len
);
1683 static void pim_upstream_register_stop_timer(struct event
*t
)
1685 struct pim_interface
*pim_ifp
;
1686 struct pim_instance
*pim
;
1687 struct pim_upstream
*up
;
1689 pim
= up
->channel_oil
->pim
;
1691 if (PIM_DEBUG_PIM_TRACE
) {
1692 char state_str
[PIM_REG_STATE_STR_LEN
];
1693 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1694 __func__
, up
->sg_str
, pim
->vrf
->name
,
1695 pim_reg_state2str(up
->reg_state
, state_str
,
1696 sizeof(state_str
)));
1699 switch (up
->reg_state
) {
1700 case PIM_REG_JOIN_PENDING
:
1701 up
->reg_state
= PIM_REG_JOIN
;
1702 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1703 PIM_OIF_FLAG_PROTO_PIM
,
1705 pim_vxlan_update_sg_reg_state(pim
, up
, true /*reg_join*/);
1710 /* This is equalent to Couldreg -> False */
1711 if (!up
->rpf
.source_nexthop
.interface
) {
1712 if (PIM_DEBUG_PIM_TRACE
)
1713 zlog_debug("%s: up %s RPF is not present",
1714 __func__
, up
->sg_str
);
1715 up
->reg_state
= PIM_REG_NOINFO
;
1719 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1721 if (PIM_DEBUG_PIM_TRACE
)
1723 "%s: Interface: %s is not configured for pim",
1725 up
->rpf
.source_nexthop
.interface
->name
);
1728 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1729 pim_upstream_start_register_stop_timer(up
, 1);
1731 if (((up
->channel_oil
->cc
.lastused
/ 100)
1732 > pim
->keep_alive_time
)
1733 && (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
))) {
1734 if (PIM_DEBUG_PIM_TRACE
)
1736 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1740 pim_null_register_send(up
);
1742 case PIM_REG_NOINFO
:
1747 void pim_upstream_start_register_stop_timer(struct pim_upstream
*up
,
1752 EVENT_OFF(up
->t_rs_timer
);
1754 if (!null_register
) {
1755 uint32_t lower
= (0.5 * router
->register_suppress_time
);
1756 uint32_t upper
= (1.5 * router
->register_suppress_time
);
1757 time
= lower
+ (frr_weak_random() % (upper
- lower
+ 1));
1758 /* Make sure we don't wrap around */
1759 if (time
>= router
->register_probe_time
)
1760 time
-= router
->register_probe_time
;
1764 time
= router
->register_probe_time
;
1766 if (PIM_DEBUG_PIM_TRACE
) {
1768 "%s: (S,G)=%s Starting upstream register stop timer %d",
1769 __func__
, up
->sg_str
, time
);
1771 event_add_timer(router
->master
, pim_upstream_register_stop_timer
, up
,
1772 time
, &up
->t_rs_timer
);
1775 int pim_upstream_inherited_olist_decide(struct pim_instance
*pim
,
1776 struct pim_upstream
*up
)
1778 struct interface
*ifp
;
1779 struct pim_ifchannel
*ch
, *starch
;
1780 struct pim_upstream
*starup
= up
->parent
;
1781 int output_intf
= 0;
1783 if (!up
->rpf
.source_nexthop
.interface
)
1784 if (PIM_DEBUG_PIM_TRACE
)
1785 zlog_debug("%s: up %s RPF is not present", __func__
,
1788 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1789 struct pim_interface
*pim_ifp
;
1793 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1796 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
1803 pim_ifp
= ifp
->info
;
1804 if (PIM_I_am_DualActive(pim_ifp
)
1805 && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up
->flags
)
1806 && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up
->flags
)
1807 || !PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up
->flags
)))
1809 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1814 flag
= PIM_OIF_FLAG_PROTO_STAR
;
1816 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch
->flags
))
1817 flag
= PIM_OIF_FLAG_PROTO_GM
;
1818 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch
->flags
))
1819 flag
|= PIM_OIF_FLAG_PROTO_PIM
;
1821 flag
|= PIM_OIF_FLAG_PROTO_STAR
;
1824 pim_channel_add_oif(up
->channel_oil
, ifp
, flag
,
1834 * For a given upstream, determine the inherited_olist
1837 * inherited_olist(S,G,rpt) =
1838 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1839 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1840 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1842 * inherited_olist(S,G) =
1843 * inherited_olist(S,G,rpt) (+)
1844 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1846 * return 1 if there are any output interfaces
1847 * return 0 if there are not any output interfaces
1849 int pim_upstream_inherited_olist(struct pim_instance
*pim
,
1850 struct pim_upstream
*up
)
1852 int output_intf
= pim_upstream_inherited_olist_decide(pim
, up
);
1855 * If we have output_intf switch state to Join and work like normal
1856 * If we don't have an output_intf that means we are probably a
1857 * switch on a stick so turn on forwarding to just accept the
1858 * incoming packets so we don't bother the other stuff!
1860 pim_upstream_update_join_desired(pim
, up
);
1868 int pim_upstream_empty_inherited_olist(struct pim_upstream
*up
)
1870 return pim_channel_oil_empty(up
->channel_oil
);
1874 * When we have a new neighbor,
1875 * find upstreams that don't have their rpf_addr
1876 * set and see if the new neighbor allows
1877 * the join to be sent
1879 void pim_upstream_find_new_rpf(struct pim_instance
*pim
)
1881 struct pim_upstream
*up
;
1883 enum pim_rpf_result rpf_result
;
1886 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1888 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
1889 if (pim_addr_is_any(up
->upstream_addr
)) {
1890 if (PIM_DEBUG_PIM_TRACE
)
1892 "%s: RP not configured for Upstream %s",
1893 __func__
, up
->sg_str
);
1897 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
1898 if (PIM_DEBUG_PIM_TRACE
)
1900 "%s: Upstream %s without a path to send join, checking",
1901 __func__
, up
->sg_str
);
1902 old
.source_nexthop
.interface
=
1903 up
->rpf
.source_nexthop
.interface
;
1904 rpf_result
= pim_rpf_update(pim
, up
, &old
, __func__
);
1905 if (rpf_result
== PIM_RPF_CHANGED
||
1906 (rpf_result
== PIM_RPF_FAILURE
&&
1907 old
.source_nexthop
.interface
))
1908 pim_zebra_upstream_rpf_changed(pim
, up
, &old
);
1909 /* update kernel multicast forwarding cache (MFC) */
1910 pim_upstream_mroute_iif_update(up
->channel_oil
,
1914 pim_zebra_update_all_interfaces(pim
);
1917 unsigned int pim_upstream_hash_key(const void *arg
)
1919 const struct pim_upstream
*up
= arg
;
1921 return pim_sgaddr_hash(up
->sg
, 0);
1924 void pim_upstream_terminate(struct pim_instance
*pim
)
1926 struct pim_upstream
*up
;
1928 while ((up
= rb_pim_upstream_first(&pim
->upstream_head
))) {
1929 if (pim_upstream_del(pim
, up
, __func__
))
1930 pim_upstream_timers_stop(up
);
1933 rb_pim_upstream_fini(&pim
->upstream_head
);
1935 if (pim
->upstream_sg_wheel
)
1936 wheel_delete(pim
->upstream_sg_wheel
);
1937 pim
->upstream_sg_wheel
= NULL
;
1940 bool pim_upstream_equal(const void *arg1
, const void *arg2
)
1942 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1943 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1945 return !pim_sgaddr_cmp(up1
->sg
, up2
->sg
);
1948 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1949 * the cases where kat has to be restarted on rxing traffic -
1951 * if( DirectlyConnected(S) == true AND iif == RPF_interface(S) ) {
1952 * set KeepaliveTimer(S,G) to Keepalive_Period
1953 * # Note: a register state transition or UpstreamJPState(S,G)
1954 * # transition may happen as a result of restarting
1955 * # KeepaliveTimer, and must be dealt with here.
1957 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1958 * inherited_olist(S,G) != NULL ) {
1959 * set KeepaliveTimer(S,G) to Keepalive_Period
1962 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1964 struct channel_oil
*c_oil
= up
->channel_oil
;
1965 struct interface
*ifp
= up
->rpf
.source_nexthop
.interface
;
1966 struct pim_interface
*pim_ifp
;
1968 /* "iif == RPF_interface(S)" check is not easy to do as the info
1969 * we get from the kernel/ASIC is really a "lookup/key hit".
1970 * So we will do an approximate check here to avoid starting KAT
1971 * because of (S,G,rpt) forwarding on a non-LHR.
1976 pim_ifp
= ifp
->info
;
1977 if (pim_ifp
->mroute_vif_index
!= *oil_parent(c_oil
))
1980 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1985 if ((up
->join_state
== PIM_UPSTREAM_JOINED
)
1986 && !pim_upstream_empty_inherited_olist(up
)) {
1993 static bool pim_upstream_sg_running_proc(struct pim_upstream
*up
)
1996 struct pim_instance
*pim
= up
->pim
;
1998 if (!up
->channel_oil
->installed
)
2001 pim_mroute_update_counters(up
->channel_oil
);
2003 // Have we seen packets?
2004 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
)
2005 && (up
->channel_oil
->cc
.lastused
/ 100 > 30)) {
2006 if (PIM_DEBUG_PIM_TRACE
) {
2008 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
2009 __func__
, up
->sg_str
, pim
->vrf
->name
,
2010 up
->channel_oil
->cc
.oldpktcnt
,
2011 up
->channel_oil
->cc
.pktcnt
,
2012 up
->channel_oil
->cc
.lastused
/ 100);
2017 if (pim_upstream_kat_start_ok(up
)) {
2018 /* Add a source reference to the stream if
2019 * one doesn't already exist */
2020 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
2021 if (PIM_DEBUG_PIM_TRACE
)
2023 "source reference created on kat restart %s[%s]",
2024 up
->sg_str
, pim
->vrf
->name
);
2026 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
,
2028 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
2029 pim_upstream_fhr_kat_start(up
);
2031 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
2033 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
2034 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
2038 if ((up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
) &&
2039 (up
->rpf
.source_nexthop
.interface
)) {
2040 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
2041 pim_upstream_update_could_assert(up
);
2048 * Code to check and see if we've received packets on a S,G mroute
2049 * and if so to set the SPT bit appropriately
2051 static void pim_upstream_sg_running(void *arg
)
2053 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
2054 struct pim_instance
*pim
= up
->channel_oil
->pim
;
2056 // No packet can have arrived here if this is the case
2057 if (!up
->channel_oil
->installed
) {
2058 if (PIM_DEBUG_TRACE
)
2059 zlog_debug("%s: %s%s is not installed in mroute",
2060 __func__
, up
->sg_str
, pim
->vrf
->name
);
2065 * This is a bit of a hack
2066 * We've noted that we should rescan but
2067 * we've missed the window for doing so in
2068 * pim_zebra.c for some reason. I am
2069 * only doing this at this point in time
2070 * to get us up and working for the moment
2072 if (up
->channel_oil
->oil_inherited_rescan
) {
2073 if (PIM_DEBUG_TRACE
)
2075 "%s: Handling unscanned inherited_olist for %s[%s]",
2076 __func__
, up
->sg_str
, pim
->vrf
->name
);
2077 pim_upstream_inherited_olist_decide(pim
, up
);
2078 up
->channel_oil
->oil_inherited_rescan
= 0;
2081 pim_upstream_sg_running_proc(up
);
2084 void pim_upstream_add_lhr_star_pimreg(struct pim_instance
*pim
)
2086 struct pim_upstream
*up
;
2088 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
2089 if (!pim_addr_is_any(up
->sg
.src
))
2092 if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
))
2095 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
2096 PIM_OIF_FLAG_PROTO_GM
, __func__
);
2100 void pim_upstream_spt_prefix_list_update(struct pim_instance
*pim
,
2101 struct prefix_list
*pl
)
2103 const char *pname
= prefix_list_name(pl
);
2105 if (pim
->spt
.plist
&& strcmp(pim
->spt
.plist
, pname
) == 0) {
2106 pim_upstream_remove_lhr_star_pimreg(pim
, pname
);
2111 * nlist -> The new prefix list
2113 * Per Group Application of pimreg to the OIL
2114 * If the prefix list tells us DENY then
2115 * we need to Switchover to SPT immediate
2116 * so add the pimreg.
2117 * If the prefix list tells us to ACCEPT than
2118 * we need to Never do the SPT so remove
2122 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance
*pim
,
2125 struct pim_upstream
*up
;
2126 struct prefix_list
*np
;
2128 enum prefix_list_type apply_new
;
2130 np
= prefix_list_lookup(PIM_AFI
, nlist
);
2132 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
2133 if (!pim_addr_is_any(up
->sg
.src
))
2136 if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
))
2140 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
2141 PIM_OIF_FLAG_PROTO_GM
, __func__
);
2144 pim_addr_to_prefix(&g
, up
->sg
.grp
);
2145 apply_new
= prefix_list_apply_ext(np
, NULL
, &g
, true);
2146 if (apply_new
== PREFIX_DENY
)
2147 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
2148 PIM_OIF_FLAG_PROTO_GM
, __func__
);
2150 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
2151 PIM_OIF_FLAG_PROTO_GM
, __func__
);
2155 void pim_upstream_init(struct pim_instance
*pim
)
2159 snprintf(name
, sizeof(name
), "PIM %s Timer Wheel", pim
->vrf
->name
);
2160 pim
->upstream_sg_wheel
=
2161 wheel_init(router
->master
, 31000, 100, pim_upstream_hash_key
,
2162 pim_upstream_sg_running
, name
);
2164 rb_pim_upstream_init(&pim
->upstream_head
);