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
37 #include "pim_iface.h"
39 #include "pim_zlookup.h"
40 #include "pim_upstream.h"
41 #include "pim_ifchannel.h"
42 #include "pim_neighbor.h"
44 #include "pim_zebra.h"
46 #include "pim_macro.h"
49 #include "pim_register.h"
51 #include "pim_jp_agg.h"
54 #include "pim_vxlan.h"
56 static void join_timer_stop(struct pim_upstream
*up
);
58 pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
);
61 * A (*,G) or a (*,*) is going away
62 * remove the parent pointer from
63 * those pointing at us
65 static void pim_upstream_remove_children(struct pim_instance
*pim
,
66 struct pim_upstream
*up
)
68 struct pim_upstream
*child
;
73 while (!list_isempty(up
->sources
)) {
74 child
= listnode_head(up
->sources
);
75 listnode_delete(up
->sources
, child
);
76 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child
->flags
)) {
77 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child
->flags
);
78 child
= pim_upstream_del(pim
, child
,
83 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
84 pim_upstream_mroute_iif_update(
89 list_delete(&up
->sources
);
93 * A (*,G) or a (*,*) is being created
94 * Find the children that would point
97 static void pim_upstream_find_new_children(struct pim_instance
*pim
,
98 struct pim_upstream
*up
)
100 struct pim_upstream
*child
;
101 struct listnode
*ch_node
;
103 if ((up
->sg
.src
.s_addr
!= INADDR_ANY
)
104 && (up
->sg
.grp
.s_addr
!= INADDR_ANY
))
107 if ((up
->sg
.src
.s_addr
== INADDR_ANY
)
108 && (up
->sg
.grp
.s_addr
== INADDR_ANY
))
111 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, ch_node
, child
)) {
112 if ((up
->sg
.grp
.s_addr
!= INADDR_ANY
)
113 && (child
->sg
.grp
.s_addr
== up
->sg
.grp
.s_addr
)
116 listnode_add_sort(up
->sources
, child
);
117 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
118 pim_upstream_mroute_iif_update(
126 * If we have a (*,*) || (S,*) there is no parent
127 * If we have a (S,G), find the (*,G)
128 * If we have a (*,G), find the (*,*)
130 static struct pim_upstream
*pim_upstream_find_parent(struct pim_instance
*pim
,
131 struct pim_upstream
*child
)
133 struct prefix_sg any
= child
->sg
;
134 struct pim_upstream
*up
= NULL
;
137 if ((child
->sg
.src
.s_addr
!= INADDR_ANY
)
138 && (child
->sg
.grp
.s_addr
!= INADDR_ANY
)) {
139 any
.src
.s_addr
= INADDR_ANY
;
140 up
= pim_upstream_find(pim
, &any
);
143 listnode_add(up
->sources
, child
);
151 static void upstream_channel_oil_detach(struct pim_upstream
*up
)
153 struct channel_oil
*channel_oil
= up
->channel_oil
;
156 /* Detaching from channel_oil, channel_oil may exist post del,
157 but upstream would not keep reference of it
159 channel_oil
->up
= NULL
;
160 up
->channel_oil
= NULL
;
162 /* attempt to delete channel_oil; if channel_oil is being held
163 * because of other references cleanup info such as "Mute"
164 * inferred from the parent upstream
166 pim_channel_oil_upstream_deref(channel_oil
);
171 struct pim_upstream
*pim_upstream_del(struct pim_instance
*pim
,
172 struct pim_upstream
*up
, const char *name
)
174 struct listnode
*node
, *nnode
;
175 struct pim_ifchannel
*ch
;
176 bool notify_msdp
= false;
179 if (PIM_DEBUG_PIM_TRACE
)
181 "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
182 __PRETTY_FUNCTION__
, name
, up
->sg_str
, pim
->vrf
->name
,
183 up
->ref_count
, up
->flags
,
184 up
->channel_oil
->oil_ref_count
);
186 assert(up
->ref_count
> 0);
190 if (up
->ref_count
>= 1)
193 THREAD_OFF(up
->t_ka_timer
);
194 THREAD_OFF(up
->t_rs_timer
);
195 THREAD_OFF(up
->t_msdp_reg_timer
);
197 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
198 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 0);
200 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
201 /* if a (*, G) entry in the joined state is being
203 * need to notify MSDP */
209 pim_jp_agg_upstream_verification(up
, false);
210 up
->rpf
.source_nexthop
.interface
= NULL
;
212 if (up
->sg
.src
.s_addr
!= INADDR_ANY
) {
213 if (pim
->upstream_sg_wheel
)
214 wheel_remove_item(pim
->upstream_sg_wheel
, up
);
218 pim_mroute_del(up
->channel_oil
, __PRETTY_FUNCTION__
);
219 upstream_channel_oil_detach(up
);
221 for (ALL_LIST_ELEMENTS(up
->ifchannels
, node
, nnode
, ch
))
222 pim_ifchannel_delete(ch
);
223 list_delete(&up
->ifchannels
);
225 pim_upstream_remove_children(pim
, up
);
227 list_delete(&up
->sources
);
229 if (up
->parent
&& up
->parent
->sources
)
230 listnode_delete(up
->parent
->sources
, up
);
233 listnode_delete(pim
->upstream_list
, up
);
234 hash_release(pim
->upstream_hash
, up
);
237 pim_msdp_up_del(pim
, &up
->sg
);
240 /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT
241 * and assign up->upstream_addr as INADDR_ANY.
242 * So before de-registering the upstream address, check if is not equal
243 * to INADDR_ANY. This is done in order to avoid de-registering for
244 * 255.255.255.255 which is maintained for some reason..
246 if (up
->upstream_addr
.s_addr
!= INADDR_ANY
) {
247 /* Deregister addr with Zebra NHT */
248 nht_p
.family
= AF_INET
;
249 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
250 nht_p
.u
.prefix4
= up
->upstream_addr
;
251 if (PIM_DEBUG_PIM_TRACE
) {
252 char buf
[PREFIX2STR_BUFFER
];
253 prefix2str(&nht_p
, buf
, sizeof(buf
));
254 zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
255 __PRETTY_FUNCTION__
, up
->sg_str
, buf
);
257 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
, false);
260 XFREE(MTYPE_PIM_UPSTREAM
, up
);
265 void pim_upstream_send_join(struct pim_upstream
*up
)
267 if (!up
->rpf
.source_nexthop
.interface
) {
268 if (PIM_DEBUG_PIM_TRACE
)
269 zlog_debug("%s: up %s RPF is not present",
270 __PRETTY_FUNCTION__
, up
->sg_str
);
274 if (PIM_DEBUG_PIM_TRACE
) {
275 char rpf_str
[PREFIX_STRLEN
];
276 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_str
,
278 zlog_debug("%s: RPF'%s=%s(%s) for Interface %s",
279 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
280 pim_upstream_state2str(up
->join_state
),
281 up
->rpf
.source_nexthop
.interface
->name
);
282 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
283 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
284 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
);
289 /* send Join(S,G) to the current upstream neighbor */
290 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 1 /* join */);
293 static int on_join_timer(struct thread
*t
)
295 struct pim_upstream
*up
;
299 if (!up
->rpf
.source_nexthop
.interface
) {
300 if (PIM_DEBUG_PIM_TRACE
)
301 zlog_debug("%s: up %s RPF is not present",
302 __PRETTY_FUNCTION__
, up
->sg_str
);
307 * In the case of a HFR we will not ahve anyone to send this to.
309 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
313 * Don't send the join if the outgoing interface is a loopback
314 * But since this might change leave the join timer running
316 if (up
->rpf
.source_nexthop
317 .interface
&& !if_is_loopback(up
->rpf
.source_nexthop
.interface
))
318 pim_upstream_send_join(up
);
320 join_timer_start(up
);
325 static void join_timer_stop(struct pim_upstream
*up
)
327 struct pim_neighbor
*nbr
= NULL
;
329 THREAD_OFF(up
->t_join_timer
);
331 if (up
->rpf
.source_nexthop
.interface
)
332 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
333 up
->rpf
.rpf_addr
.u
.prefix4
);
336 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
);
338 pim_jp_agg_upstream_verification(up
, false);
341 void join_timer_start(struct pim_upstream
*up
)
343 struct pim_neighbor
*nbr
= NULL
;
345 if (up
->rpf
.source_nexthop
.interface
) {
346 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
347 up
->rpf
.rpf_addr
.u
.prefix4
);
349 if (PIM_DEBUG_PIM_EVENTS
) {
351 "%s: starting %d sec timer for upstream (S,G)=%s",
352 __PRETTY_FUNCTION__
, router
->t_periodic
,
358 pim_jp_agg_add_group(nbr
->upstream_jp_agg
, up
, 1);
360 THREAD_OFF(up
->t_join_timer
);
361 thread_add_timer(router
->master
, on_join_timer
, up
,
362 router
->t_periodic
, &up
->t_join_timer
);
364 pim_jp_agg_upstream_verification(up
, true);
368 * This is only called when we are switching the upstream
369 * J/P from one neighbor to another
371 * As such we need to remove from the old list and
372 * add to the new list.
374 void pim_upstream_join_timer_restart(struct pim_upstream
*up
,
377 // THREAD_OFF(up->t_join_timer);
378 join_timer_start(up
);
381 static void pim_upstream_join_timer_restart_msec(struct pim_upstream
*up
,
384 if (PIM_DEBUG_PIM_EVENTS
) {
385 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
386 __PRETTY_FUNCTION__
, interval_msec
, up
->sg_str
);
389 THREAD_OFF(up
->t_join_timer
);
390 thread_add_timer_msec(router
->master
, on_join_timer
, up
, interval_msec
,
394 void pim_upstream_join_suppress(struct pim_upstream
*up
,
395 struct in_addr rpf_addr
, int holdtime
)
397 long t_joinsuppress_msec
;
398 long join_timer_remain_msec
;
400 if (!up
->rpf
.source_nexthop
.interface
) {
401 if (PIM_DEBUG_PIM_TRACE
)
402 zlog_debug("%s: up %s RPF is not present",
403 __PRETTY_FUNCTION__
, up
->sg_str
);
407 t_joinsuppress_msec
=
408 MIN(pim_if_t_suppressed_msec(up
->rpf
.source_nexthop
.interface
),
411 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
413 if (PIM_DEBUG_PIM_TRACE
) {
414 char rpf_str
[INET_ADDRSTRLEN
];
415 pim_inet4_dump("<rpf?>", rpf_addr
, rpf_str
, sizeof(rpf_str
));
417 "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
418 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
419 join_timer_remain_msec
, t_joinsuppress_msec
);
422 if (join_timer_remain_msec
< t_joinsuppress_msec
) {
423 if (PIM_DEBUG_PIM_TRACE
) {
425 "%s %s: suppressing Join(S,G)=%s for %ld msec",
426 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
,
427 t_joinsuppress_msec
);
430 pim_upstream_join_timer_restart_msec(up
, t_joinsuppress_msec
);
434 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label
,
435 struct pim_upstream
*up
)
437 long join_timer_remain_msec
;
440 if (!up
->rpf
.source_nexthop
.interface
) {
441 if (PIM_DEBUG_PIM_TRACE
)
442 zlog_debug("%s: up %s RPF is not present",
443 __PRETTY_FUNCTION__
, up
->sg_str
);
447 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
449 pim_if_t_override_msec(up
->rpf
.source_nexthop
.interface
);
451 if (PIM_DEBUG_PIM_TRACE
) {
452 char rpf_str
[INET_ADDRSTRLEN
];
453 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
.u
.prefix4
, rpf_str
,
456 "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
457 debug_label
, up
->sg_str
, rpf_str
,
458 join_timer_remain_msec
, t_override_msec
);
461 if (join_timer_remain_msec
> t_override_msec
) {
462 if (PIM_DEBUG_PIM_TRACE
) {
464 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
465 debug_label
, up
->sg_str
, t_override_msec
);
468 pim_upstream_join_timer_restart_msec(up
, t_override_msec
);
472 static void forward_on(struct pim_upstream
*up
)
474 struct listnode
*chnode
;
475 struct listnode
*chnextnode
;
476 struct pim_ifchannel
*ch
= NULL
;
478 /* scan (S,G) state */
479 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
480 if (pim_macro_chisin_oiflist(ch
))
481 pim_forward_start(ch
);
483 } /* scan iface channel list */
486 static void forward_off(struct pim_upstream
*up
)
488 struct listnode
*chnode
;
489 struct listnode
*chnextnode
;
490 struct pim_ifchannel
*ch
;
492 /* scan per-interface (S,G) state */
493 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
495 pim_forward_stop(ch
, false);
497 } /* scan iface channel list */
500 static int pim_upstream_could_register(struct pim_upstream
*up
)
502 struct pim_interface
*pim_ifp
= NULL
;
504 /* FORCE_PIMREG is a generic flag to let an app like VxLAN-AA register
505 * a source on an upstream entry even if the source is not directly
506 * connected on the IIF.
508 if (PIM_UPSTREAM_FLAG_TEST_FORCE_PIMREG(up
->flags
))
511 if (up
->rpf
.source_nexthop
.interface
)
512 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
514 if (PIM_DEBUG_PIM_TRACE
)
515 zlog_debug("%s: up %s RPF is not present",
516 __PRETTY_FUNCTION__
, up
->sg_str
);
519 if (pim_ifp
&& PIM_I_am_DR(pim_ifp
)
520 && pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
527 /* Source registration is suppressed for SSM groups. When the SSM range changes
528 * we re-revaluate register setup for existing upstream entries */
529 void pim_upstream_register_reevaluate(struct pim_instance
*pim
)
531 struct listnode
*upnode
;
532 struct pim_upstream
*up
;
534 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
535 /* If FHR is set CouldRegister is True. Also check if the flow
536 * is actually active; if it is not kat setup will trigger
538 * registration whenever the flow becomes active. */
539 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) || !up
->t_ka_timer
)
542 if (pim_is_grp_ssm(pim
, up
->sg
.grp
)) {
543 /* clear the register state for SSM groups */
544 if (up
->reg_state
!= PIM_REG_NOINFO
) {
545 if (PIM_DEBUG_PIM_EVENTS
)
547 "Clear register for %s as G is now SSM",
549 /* remove regiface from the OIL if it is there*/
550 pim_channel_del_oif(up
->channel_oil
,
552 PIM_OIF_FLAG_PROTO_PIM
,
554 up
->reg_state
= PIM_REG_NOINFO
;
557 /* register ASM sources with the RP */
558 if (up
->reg_state
== PIM_REG_NOINFO
) {
559 if (PIM_DEBUG_PIM_EVENTS
)
561 "Register %s as G is now ASM",
563 pim_channel_add_oif(up
->channel_oil
,
565 PIM_OIF_FLAG_PROTO_PIM
,
567 up
->reg_state
= PIM_REG_JOIN
;
573 /* RFC7761, Section 4.2 “Data Packet Forwarding Rules” says we should
575 * 1. along the SPT if SPTbit is set
576 * 2. and along the RPT if SPTbit is not set
577 * If forwarding is hw accelerated i.e. control and dataplane components
578 * are separate you may not be able to reliably set SPT bit on intermediate
579 * routers while still fowarding on the (S,G,rpt).
581 * This macro is a slight deviation on the RFC and uses "traffic-agnostic"
582 * criteria to decide between using the RPT vs. SPT for forwarding.
584 void pim_upstream_update_use_rpt(struct pim_upstream
*up
,
590 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
593 old_use_rpt
= !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
595 /* We will use the SPT (IIF=RPF_interface(S) if -
596 * 1. We have decided to join the SPT
598 * 3. Source is directly connected
599 * 4. We are RP (parent's IIF is lo or vrf-device)
600 * In all other cases the source will stay along the RPT and
601 * IIF=RPF_interface(RP).
603 if (up
->join_state
== PIM_UPSTREAM_JOINED
||
604 PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) ||
605 pim_if_connected_to_source(
606 up
->rpf
.source_nexthop
.interface
,
608 /* XXX - need to switch this to a more efficient
611 I_am_RP(up
->pim
, up
->sg
.grp
))
613 PIM_UPSTREAM_FLAG_UNSET_USE_RPT(up
->flags
);
616 PIM_UPSTREAM_FLAG_SET_USE_RPT(up
->flags
);
618 new_use_rpt
= !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
619 if (old_use_rpt
!= new_use_rpt
) {
620 if (PIM_DEBUG_PIM_EVENTS
)
621 zlog_debug("%s switched from %s to %s",
623 old_use_rpt
?"RPT":"SPT",
624 new_use_rpt
?"RPT":"SPT");
626 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
630 void pim_upstream_switch(struct pim_instance
*pim
, struct pim_upstream
*up
,
631 enum pim_upstream_state new_state
)
633 enum pim_upstream_state old_state
= up
->join_state
;
635 if (up
->upstream_addr
.s_addr
== INADDR_ANY
) {
636 if (PIM_DEBUG_PIM_EVENTS
)
637 zlog_debug("%s: RPF not configured for %s",
638 __PRETTY_FUNCTION__
, up
->sg_str
);
642 if (!up
->rpf
.source_nexthop
.interface
) {
643 if (PIM_DEBUG_PIM_EVENTS
)
644 zlog_debug("%s: RP not reachable for %s",
645 __PRETTY_FUNCTION__
, up
->sg_str
);
649 if (PIM_DEBUG_PIM_EVENTS
) {
650 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
651 __PRETTY_FUNCTION__
, up
->sg_str
,
652 pim_upstream_state2str(up
->join_state
),
653 pim_upstream_state2str(new_state
));
656 up
->join_state
= new_state
;
657 if (old_state
!= new_state
)
658 up
->state_transition
= pim_time_monotonic_sec();
660 pim_upstream_update_assert_tracking_desired(up
);
662 if (new_state
== PIM_UPSTREAM_JOINED
) {
663 pim_upstream_inherited_olist_decide(pim
, up
);
664 if (old_state
!= PIM_UPSTREAM_JOINED
) {
665 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
667 pim_msdp_up_join_state_changed(pim
, up
);
668 if (pim_upstream_could_register(up
)) {
669 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
671 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
673 pim_upstream_keep_alive_timer_start(
674 up
, pim
->keep_alive_time
);
675 pim_register_join(up
);
678 pim_upstream_send_join(up
);
679 join_timer_start(up
);
685 if (old_state
== PIM_UPSTREAM_JOINED
)
686 pim_msdp_up_join_state_changed(pim
, up
);
688 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
690 If I am RP for G then send S,G prune to its IIF. */
691 if (pim_upstream_is_sg_rpt(up
) && up
->parent
692 && !I_am_RP(pim
, up
->sg
.grp
)) {
693 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
695 "%s: *,G IIF %s S,G IIF %s ",
697 up
->parent
->rpf
.source_nexthop
.interface
?
698 up
->parent
->rpf
.source_nexthop
.interface
->name
700 up
->rpf
.source_nexthop
.interface
?
701 up
->rpf
.source_nexthop
.interface
->name
:
703 pim_jp_agg_single_upstream_send(&up
->parent
->rpf
,
707 pim_jp_agg_single_upstream_send(&up
->rpf
, up
,
712 if (old_state
!= new_state
)
713 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
716 int pim_upstream_compare(void *arg1
, void *arg2
)
718 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
719 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
721 if (ntohl(up1
->sg
.grp
.s_addr
) < ntohl(up2
->sg
.grp
.s_addr
))
724 if (ntohl(up1
->sg
.grp
.s_addr
) > ntohl(up2
->sg
.grp
.s_addr
))
727 if (ntohl(up1
->sg
.src
.s_addr
) < ntohl(up2
->sg
.src
.s_addr
))
730 if (ntohl(up1
->sg
.src
.s_addr
) > ntohl(up2
->sg
.src
.s_addr
))
736 void pim_upstream_fill_static_iif(struct pim_upstream
*up
,
737 struct interface
*incoming
)
739 up
->rpf
.source_nexthop
.interface
= incoming
;
741 /* reset other parameters to matched a connected incoming interface */
742 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
743 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
745 up
->rpf
.source_nexthop
.mrib_metric_preference
=
746 ZEBRA_CONNECT_DISTANCE_DEFAULT
;
747 up
->rpf
.source_nexthop
.mrib_route_metric
= 0;
748 up
->rpf
.rpf_addr
.family
= AF_INET
;
749 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
753 static struct pim_upstream
*pim_upstream_new(struct pim_instance
*pim
,
754 struct prefix_sg
*sg
,
755 struct interface
*incoming
,
757 struct pim_ifchannel
*ch
)
759 enum pim_rpf_result rpf_result
;
760 struct pim_interface
*pim_ifp
;
761 struct pim_upstream
*up
;
763 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
767 pim_str_sg_set(sg
, up
->sg_str
);
771 up
= hash_get(pim
->upstream_hash
, up
, hash_alloc_intern
);
772 /* Set up->upstream_addr as INADDR_ANY, if RP is not
773 * configured and retain the upstream data structure
775 if (!pim_rp_set_upstream_addr(pim
, &up
->upstream_addr
, sg
->src
,
777 if (PIM_DEBUG_PIM_TRACE
)
778 zlog_debug("%s: Received a (*,G) with no RP configured",
779 __PRETTY_FUNCTION__
);
782 up
->parent
= pim_upstream_find_parent(pim
, up
);
783 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
784 up
->sources
= list_new();
785 up
->sources
->cmp
= pim_upstream_compare
;
789 pim_upstream_find_new_children(pim
, up
);
792 up
->t_join_timer
= NULL
;
793 up
->t_ka_timer
= NULL
;
794 up
->t_rs_timer
= NULL
;
795 up
->t_msdp_reg_timer
= NULL
;
796 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
797 up
->reg_state
= PIM_REG_NOINFO
;
798 up
->state_transition
= pim_time_monotonic_sec();
800 pim_channel_oil_add(pim
, &up
->sg
, __PRETTY_FUNCTION__
);
801 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
803 up
->rpf
.source_nexthop
.interface
= NULL
;
804 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
805 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
807 up
->rpf
.source_nexthop
.mrib_metric_preference
=
808 router
->infinite_assert_metric
.metric_preference
;
809 up
->rpf
.source_nexthop
.mrib_route_metric
=
810 router
->infinite_assert_metric
.route_metric
;
811 up
->rpf
.rpf_addr
.family
= AF_INET
;
812 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
814 up
->ifchannels
= list_new();
815 up
->ifchannels
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
817 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
818 wheel_add_item(pim
->upstream_sg_wheel
, up
);
820 if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up
->flags
)
821 || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
)) {
822 pim_upstream_fill_static_iif(up
, incoming
);
823 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
825 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
827 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
))
828 pim_upstream_keep_alive_timer_start(
829 up
, pim
->keep_alive_time
);
830 } else if (up
->upstream_addr
.s_addr
!= INADDR_ANY
) {
831 rpf_result
= pim_rpf_update(pim
, up
, NULL
);
832 if (rpf_result
== PIM_RPF_FAILURE
) {
833 if (PIM_DEBUG_PIM_TRACE
)
835 "%s: Attempting to create upstream(%s), Unable to RPF for source",
836 __PRETTY_FUNCTION__
, up
->sg_str
);
839 if (up
->rpf
.source_nexthop
.interface
) {
840 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
842 pim_upstream_mroute_iif_update(up
->channel_oil
,
845 pim_upstream_update_use_rpt(up
,
846 false /*update_mroute*/);
849 listnode_add_sort(pim
->upstream_list
, up
);
851 if (PIM_DEBUG_PIM_TRACE
) {
853 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
854 __PRETTY_FUNCTION__
, up
->sg_str
,
855 inet_ntoa(up
->upstream_addr
), up
->ref_count
);
861 struct pim_upstream
*pim_upstream_find(struct pim_instance
*pim
,
862 struct prefix_sg
*sg
)
864 struct pim_upstream lookup
;
865 struct pim_upstream
*up
= NULL
;
868 up
= hash_lookup(pim
->upstream_hash
, &lookup
);
872 struct pim_upstream
*pim_upstream_find_or_add(struct prefix_sg
*sg
,
873 struct interface
*incoming
,
874 int flags
, const char *name
)
876 struct pim_interface
*pim_ifp
= incoming
->info
;
878 return (pim_upstream_add(pim_ifp
->pim
, sg
, incoming
, flags
, name
,
882 void pim_upstream_ref(struct pim_upstream
*up
, int flags
, const char *name
)
884 /* when we go from non-FHR to FHR we need to re-eval traffic
887 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) &&
888 PIM_UPSTREAM_FLAG_TEST_FHR(flags
)) {
889 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
890 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
895 if (PIM_DEBUG_PIM_TRACE
)
896 zlog_debug("%s(%s): upstream %s ref count %d increment",
897 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
901 struct pim_upstream
*pim_upstream_add(struct pim_instance
*pim
,
902 struct prefix_sg
*sg
,
903 struct interface
*incoming
, int flags
,
905 struct pim_ifchannel
*ch
)
907 struct pim_upstream
*up
= NULL
;
910 up
= pim_upstream_find(pim
, sg
);
912 pim_upstream_ref(up
, flags
, name
);
915 up
= pim_upstream_new(pim
, sg
, incoming
, flags
, ch
);
918 if (PIM_DEBUG_PIM_TRACE
) {
920 char buf
[PREFIX2STR_BUFFER
];
921 prefix2str(&up
->rpf
.rpf_addr
, buf
, sizeof(buf
));
922 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
923 __PRETTY_FUNCTION__
, name
,
924 up
->sg_str
, buf
, up
->rpf
.source_nexthop
.interface
?
925 up
->rpf
.source_nexthop
.interface
->name
: "Unknown" ,
926 found
, up
->ref_count
);
928 zlog_debug("%s(%s): (%s) failure to create",
929 __PRETTY_FUNCTION__
, name
,
930 pim_str_sg_dump(sg
));
937 * Passed in up must be the upstream for ch. starch is NULL if no
940 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream
*up
,
941 struct pim_ifchannel
*ch
,
942 struct pim_ifchannel
*starch
)
945 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
948 if (!pim_macro_ch_lost_assert(ch
)
949 && pim_macro_chisin_joins_or_include(ch
))
957 if (PIM_IF_FLAG_TEST_S_G_RPT(starch
->upstream
->flags
))
960 if (!pim_macro_ch_lost_assert(starch
)
961 && pim_macro_chisin_joins_or_include(starch
))
969 Evaluate JoinDesired(S,G):
971 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
974 inherited_olist(S,G) =
975 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
977 JoinDesired(S,G) may be affected by changes in the following:
979 pim_ifp->primary_address
981 ch->ifassert_winner_metric
983 ch->local_ifmembership
985 ch->upstream->rpf.source_nexthop.mrib_metric_preference
986 ch->upstream->rpf.source_nexthop.mrib_route_metric
987 ch->upstream->rpf.source_nexthop.interface
989 See also pim_upstream_update_join_desired() below.
991 int pim_upstream_evaluate_join_desired(struct pim_instance
*pim
,
992 struct pim_upstream
*up
)
994 struct interface
*ifp
;
995 struct pim_ifchannel
*ch
, *starch
;
996 struct pim_upstream
*starup
= up
->parent
;
999 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1003 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1006 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
1013 ret
+= pim_upstream_evaluate_join_desired_interface(up
, ch
,
1015 } /* scan iface channel list */
1017 return ret
; /* false */
1021 See also pim_upstream_evaluate_join_desired() above.
1023 void pim_upstream_update_join_desired(struct pim_instance
*pim
,
1024 struct pim_upstream
*up
)
1026 int was_join_desired
; /* boolean */
1027 int is_join_desired
; /* boolean */
1029 was_join_desired
= PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up
->flags
);
1031 is_join_desired
= pim_upstream_evaluate_join_desired(pim
, up
);
1032 if (is_join_desired
)
1033 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up
->flags
);
1035 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up
->flags
);
1037 /* switched from false to true */
1038 if (is_join_desired
&& (up
->join_state
== PIM_UPSTREAM_NOTJOINED
)) {
1039 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
1043 /* switched from true to false */
1044 if (!is_join_desired
&& was_join_desired
) {
1045 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_NOTJOINED
);
1051 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
1052 Transitions from Joined State
1053 RPF'(S,G) GenID changes
1055 The upstream (S,G) state machine remains in Joined state. If the
1056 Join Timer is set to expire in more than t_override seconds, reset
1057 it so that it expires after t_override seconds.
1059 void pim_upstream_rpf_genid_changed(struct pim_instance
*pim
,
1060 struct in_addr neigh_addr
)
1062 struct listnode
*up_node
;
1063 struct listnode
*up_nextnode
;
1064 struct pim_upstream
*up
;
1067 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1069 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
1071 if (PIM_DEBUG_PIM_TRACE
) {
1072 char neigh_str
[INET_ADDRSTRLEN
];
1073 char rpf_addr_str
[PREFIX_STRLEN
];
1074 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
,
1076 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_addr_str
,
1077 sizeof(rpf_addr_str
));
1079 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
1080 __PRETTY_FUNCTION__
, neigh_str
, up
->sg_str
,
1082 up
->join_state
== PIM_UPSTREAM_JOINED
,
1086 /* consider only (S,G) upstream in Joined state */
1087 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
1090 /* match RPF'(S,G)=neigh_addr */
1091 if (up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
!= neigh_addr
.s_addr
)
1094 pim_upstream_join_timer_decrease_to_t_override(
1095 "RPF'(S,G) GenID change", up
);
1100 void pim_upstream_rpf_interface_changed(struct pim_upstream
*up
,
1101 struct interface
*old_rpf_ifp
)
1103 struct listnode
*chnode
;
1104 struct listnode
*chnextnode
;
1105 struct pim_ifchannel
*ch
;
1107 /* search all ifchannels */
1108 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1109 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
1111 /* RPF_interface(S) was NOT I */
1112 (old_rpf_ifp
== ch
->interface
) &&
1113 /* RPF_interface(S) stopped being I */
1114 (ch
->upstream
->rpf
.source_nexthop
1116 (ch
->upstream
->rpf
.source_nexthop
1117 .interface
!= ch
->interface
)) {
1118 assert_action_a5(ch
);
1120 } /* PIM_IFASSERT_I_AM_LOSER */
1122 pim_ifchannel_update_assert_tracking_desired(ch
);
1126 void pim_upstream_update_could_assert(struct pim_upstream
*up
)
1128 struct listnode
*chnode
;
1129 struct listnode
*chnextnode
;
1130 struct pim_ifchannel
*ch
;
1132 /* scan per-interface (S,G) state */
1133 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1134 pim_ifchannel_update_could_assert(ch
);
1135 } /* scan iface channel list */
1138 void pim_upstream_update_my_assert_metric(struct pim_upstream
*up
)
1140 struct listnode
*chnode
;
1141 struct listnode
*chnextnode
;
1142 struct pim_ifchannel
*ch
;
1144 /* scan per-interface (S,G) state */
1145 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1146 pim_ifchannel_update_my_assert_metric(ch
);
1148 } /* scan iface channel list */
1151 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
)
1153 struct listnode
*chnode
;
1154 struct listnode
*chnextnode
;
1155 struct pim_interface
*pim_ifp
;
1156 struct pim_ifchannel
*ch
;
1158 /* scan per-interface (S,G) state */
1159 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1162 pim_ifp
= ch
->interface
->info
;
1166 pim_ifchannel_update_assert_tracking_desired(ch
);
1168 } /* scan iface channel list */
1171 /* When kat is stopped CouldRegister goes to false so we need to
1172 * transition the (S, G) on FHR to NI state and remove reg tunnel
1174 static void pim_upstream_fhr_kat_expiry(struct pim_instance
*pim
,
1175 struct pim_upstream
*up
)
1177 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
1180 if (PIM_DEBUG_PIM_TRACE
)
1181 zlog_debug("kat expired on %s; clear fhr reg state",
1184 /* stop reg-stop timer */
1185 THREAD_OFF(up
->t_rs_timer
);
1186 /* remove regiface from the OIL if it is there*/
1187 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1188 PIM_OIF_FLAG_PROTO_PIM
, __func__
);
1189 /* clear the register state */
1190 up
->reg_state
= PIM_REG_NOINFO
;
1191 PIM_UPSTREAM_FLAG_UNSET_FHR(up
->flags
);
1194 /* When kat is started CouldRegister can go to true. And if it does we
1195 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1197 static void pim_upstream_fhr_kat_start(struct pim_upstream
*up
)
1199 if (pim_upstream_could_register(up
)) {
1200 if (PIM_DEBUG_PIM_TRACE
)
1202 "kat started on %s; set fhr reg state to joined",
1205 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1206 if (up
->reg_state
== PIM_REG_NOINFO
)
1207 pim_register_join(up
);
1208 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
1213 * On an RP, the PMBR value must be cleared when the
1214 * Keepalive Timer expires
1215 * KAT expiry indicates that flow is inactive. If the flow was created or
1216 * maintained by activity now is the time to deref it.
1218 struct pim_upstream
*pim_upstream_keep_alive_timer_proc(
1219 struct pim_upstream
*up
)
1221 struct pim_instance
*pim
;
1223 pim
= up
->channel_oil
->pim
;
1225 if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up
->flags
)) {
1226 /* if the router is a PIM vxlan encapsulator we prevent expiry
1227 * of KAT as the mroute is pre-setup without any traffic
1229 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1233 if (I_am_RP(pim
, up
->sg
.grp
)) {
1234 pim_br_clear_pmbr(&up
->sg
);
1236 * We need to do more here :)
1237 * But this is the start.
1241 /* source is no longer active - pull the SA from MSDP's cache */
1242 pim_msdp_sa_local_del(pim
, &up
->sg
);
1244 /* if entry was created because of activity we need to deref it */
1245 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1246 pim_upstream_fhr_kat_expiry(pim
, up
);
1247 if (PIM_DEBUG_PIM_TRACE
)
1249 "kat expired on %s[%s]; remove stream reference",
1250 up
->sg_str
, pim
->vrf
->name
);
1251 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up
->flags
);
1253 /* Return if upstream entry got deleted.*/
1254 if (!pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
))
1257 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
)) {
1258 PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up
->flags
);
1260 if (!pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
))
1264 /* upstream reference would have been added to track the local
1265 * membership if it is LHR. We have to clear it when KAT expires.
1266 * Otherwise would result in stale entry with uncleared ref count.
1268 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
1269 struct pim_upstream
*parent
= up
->parent
;
1271 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1272 up
= pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1275 pim_jp_agg_single_upstream_send(&parent
->rpf
, parent
,
1282 static int pim_upstream_keep_alive_timer(struct thread
*t
)
1284 struct pim_upstream
*up
;
1288 pim_upstream_keep_alive_timer_proc(up
);
1292 void pim_upstream_keep_alive_timer_start(struct pim_upstream
*up
, uint32_t time
)
1294 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1295 if (PIM_DEBUG_PIM_TRACE
)
1296 zlog_debug("kat start on %s with no stream reference",
1299 THREAD_OFF(up
->t_ka_timer
);
1300 thread_add_timer(router
->master
, pim_upstream_keep_alive_timer
, up
,
1301 time
, &up
->t_ka_timer
);
1303 /* any time keepalive is started against a SG we will have to
1304 * re-evaluate our active source database */
1305 pim_msdp_sa_local_update(up
);
1308 /* MSDP on RP needs to know if a source is registerable to this RP */
1309 static int pim_upstream_msdp_reg_timer(struct thread
*t
)
1311 struct pim_upstream
*up
= THREAD_ARG(t
);
1312 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1314 /* source is no longer active - pull the SA from MSDP's cache */
1315 pim_msdp_sa_local_del(pim
, &up
->sg
);
1318 void pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1320 THREAD_OFF(up
->t_msdp_reg_timer
);
1321 thread_add_timer(router
->master
, pim_upstream_msdp_reg_timer
, up
,
1322 PIM_MSDP_REG_RXED_PERIOD
, &up
->t_msdp_reg_timer
);
1324 pim_msdp_sa_local_update(up
);
1328 * 4.2.1 Last-Hop Switchover to the SPT
1330 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1331 * RP. Once traffic from sources to joined groups arrives at a last-hop
1332 * router, it has the option of switching to receive the traffic on a
1333 * shortest path tree (SPT).
1335 * The decision for a router to switch to the SPT is controlled as
1339 * CheckSwitchToSpt(S,G) {
1340 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1341 * (+) pim_include(S,G) != NULL )
1342 * AND SwitchToSptDesired(S,G) ) {
1343 * # Note: Restarting the KAT will result in the SPT switch
1344 * set KeepaliveTimer(S,G) to Keepalive_Period
1348 * SwitchToSptDesired(S,G) is a policy function that is implementation
1349 * defined. An "infinite threshold" policy can be implemented by making
1350 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1351 * first packet" policy can be implemented by making
1352 * SwitchToSptDesired(S,G) return true once a single packet has been
1353 * received for the source and group.
1355 int pim_upstream_switch_to_spt_desired(struct pim_instance
*pim
,
1356 struct prefix_sg
*sg
)
1358 if (I_am_RP(pim
, sg
->grp
))
1364 int pim_upstream_is_sg_rpt(struct pim_upstream
*up
)
1366 struct listnode
*chnode
;
1367 struct pim_ifchannel
*ch
;
1369 for (ALL_LIST_ELEMENTS_RO(up
->ifchannels
, chnode
, ch
)) {
1370 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1377 * After receiving a packet set SPTbit:
1379 * Update_SPTbit(S,G,iif) {
1380 * if ( iif == RPF_interface(S)
1381 * AND JoinDesired(S,G) == true
1382 * AND ( DirectlyConnected(S) == true
1383 * OR RPF_interface(S) != RPF_interface(RP(G))
1384 * OR inherited_olist(S,G,rpt) == NULL
1385 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1386 * ( RPF'(S,G) != NULL ) )
1387 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1388 * Set SPTbit(S,G) to true
1392 void pim_upstream_set_sptbit(struct pim_upstream
*up
,
1393 struct interface
*incoming
)
1395 struct pim_upstream
*starup
= up
->parent
;
1397 // iif == RPF_interfvace(S)
1398 if (up
->rpf
.source_nexthop
.interface
!= incoming
) {
1399 if (PIM_DEBUG_PIM_TRACE
)
1401 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1402 __PRETTY_FUNCTION__
, incoming
->name
,
1403 up
->rpf
.source_nexthop
.interface
->name
);
1407 // AND JoinDesired(S,G) == true
1408 if (!pim_upstream_evaluate_join_desired(up
->channel_oil
->pim
, up
)) {
1409 if (PIM_DEBUG_PIM_TRACE
)
1410 zlog_debug("%s: %s Join is not Desired",
1411 __PRETTY_FUNCTION__
, up
->sg_str
);
1415 // DirectlyConnected(S) == true
1416 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1418 if (PIM_DEBUG_PIM_TRACE
)
1419 zlog_debug("%s: %s is directly connected to the source",
1420 __PRETTY_FUNCTION__
, up
->sg_str
);
1421 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1425 // OR RPF_interface(S) != RPF_interface(RP(G))
1427 || up
->rpf
.source_nexthop
1428 .interface
!= starup
->rpf
.source_nexthop
.interface
) {
1429 struct pim_upstream
*starup
= up
->parent
;
1431 if (PIM_DEBUG_PIM_TRACE
)
1433 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1434 __PRETTY_FUNCTION__
, up
->sg_str
);
1435 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1437 pim_jp_agg_single_upstream_send(&starup
->rpf
, starup
, true);
1441 // OR inherited_olist(S,G,rpt) == NULL
1442 if (pim_upstream_is_sg_rpt(up
)
1443 && pim_upstream_empty_inherited_olist(up
)) {
1444 if (PIM_DEBUG_PIM_TRACE
)
1445 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1446 __PRETTY_FUNCTION__
, up
->sg_str
);
1447 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1451 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1452 // ( RPF'(S,G) != NULL ) )
1453 if (up
->parent
&& pim_rpf_is_same(&up
->rpf
, &up
->parent
->rpf
)) {
1454 if (PIM_DEBUG_PIM_TRACE
)
1455 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1456 __PRETTY_FUNCTION__
, up
->sg_str
);
1457 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1464 const char *pim_upstream_state2str(enum pim_upstream_state join_state
)
1466 switch (join_state
) {
1467 case PIM_UPSTREAM_NOTJOINED
:
1470 case PIM_UPSTREAM_JOINED
:
1477 const char *pim_reg_state2str(enum pim_reg_state reg_state
, char *state_str
,
1478 size_t state_str_len
)
1480 switch (reg_state
) {
1481 case PIM_REG_NOINFO
:
1482 strlcpy(state_str
, "RegNoInfo", state_str_len
);
1485 strlcpy(state_str
, "RegJoined", state_str_len
);
1487 case PIM_REG_JOIN_PENDING
:
1488 strlcpy(state_str
, "RegJoinPend", state_str_len
);
1491 strlcpy(state_str
, "RegPrune", state_str_len
);
1494 strlcpy(state_str
, "RegUnknown", state_str_len
);
1499 static int pim_upstream_register_stop_timer(struct thread
*t
)
1501 struct pim_interface
*pim_ifp
;
1502 struct pim_instance
*pim
;
1503 struct pim_upstream
*up
;
1505 pim
= up
->channel_oil
->pim
;
1507 if (PIM_DEBUG_PIM_TRACE
) {
1508 char state_str
[PIM_REG_STATE_STR_LEN
];
1509 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1510 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
1511 pim_reg_state2str(up
->reg_state
, state_str
, sizeof(state_str
)));
1514 switch (up
->reg_state
) {
1515 case PIM_REG_JOIN_PENDING
:
1516 up
->reg_state
= PIM_REG_JOIN
;
1517 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1518 PIM_OIF_FLAG_PROTO_PIM
,
1520 pim_vxlan_update_sg_reg_state(pim
, up
, true /*reg_join*/);
1525 if (!up
->rpf
.source_nexthop
.interface
) {
1526 if (PIM_DEBUG_PIM_TRACE
)
1527 zlog_debug("%s: up %s RPF is not present",
1528 __PRETTY_FUNCTION__
, up
->sg_str
);
1532 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1534 if (PIM_DEBUG_PIM_TRACE
)
1536 "%s: Interface: %s is not configured for pim",
1537 __PRETTY_FUNCTION__
,
1538 up
->rpf
.source_nexthop
.interface
->name
);
1541 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1542 pim_upstream_start_register_stop_timer(up
, 1);
1544 if (((up
->channel_oil
->cc
.lastused
/ 100)
1545 > pim
->keep_alive_time
)
1546 && (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
))) {
1547 if (PIM_DEBUG_PIM_TRACE
)
1549 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1550 __PRETTY_FUNCTION__
);
1553 pim_null_register_send(up
);
1562 void pim_upstream_start_register_stop_timer(struct pim_upstream
*up
,
1567 THREAD_TIMER_OFF(up
->t_rs_timer
);
1569 if (!null_register
) {
1570 uint32_t lower
= (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1571 uint32_t upper
= (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1572 time
= lower
+ (random() % (upper
- lower
+ 1))
1573 - PIM_REGISTER_PROBE_PERIOD
;
1575 time
= PIM_REGISTER_PROBE_PERIOD
;
1577 if (PIM_DEBUG_PIM_TRACE
) {
1579 "%s: (S,G)=%s Starting upstream register stop timer %d",
1580 __PRETTY_FUNCTION__
, up
->sg_str
, time
);
1582 thread_add_timer(router
->master
, pim_upstream_register_stop_timer
, up
,
1583 time
, &up
->t_rs_timer
);
1586 int pim_upstream_inherited_olist_decide(struct pim_instance
*pim
,
1587 struct pim_upstream
*up
)
1589 struct interface
*ifp
;
1590 struct pim_ifchannel
*ch
, *starch
;
1591 struct pim_upstream
*starup
= up
->parent
;
1592 int output_intf
= 0;
1594 if (!up
->rpf
.source_nexthop
.interface
)
1595 if (PIM_DEBUG_PIM_TRACE
)
1596 zlog_debug("%s: up %s RPF is not present",
1597 __PRETTY_FUNCTION__
, up
->sg_str
);
1599 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1603 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1606 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
1613 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1615 int flag
= PIM_OIF_FLAG_PROTO_PIM
;
1618 flag
= PIM_OIF_FLAG_PROTO_STAR
;
1620 pim_channel_add_oif(up
->channel_oil
, ifp
, flag
,
1630 * For a given upstream, determine the inherited_olist
1633 * inherited_olist(S,G,rpt) =
1634 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1635 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1636 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1638 * inherited_olist(S,G) =
1639 * inherited_olist(S,G,rpt) (+)
1640 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1642 * return 1 if there are any output interfaces
1643 * return 0 if there are not any output interfaces
1645 int pim_upstream_inherited_olist(struct pim_instance
*pim
,
1646 struct pim_upstream
*up
)
1648 int output_intf
= pim_upstream_inherited_olist_decide(pim
, up
);
1651 * If we have output_intf switch state to Join and work like normal
1652 * If we don't have an output_intf that means we are probably a
1653 * switch on a stick so turn on forwarding to just accept the
1654 * incoming packets so we don't bother the other stuff!
1657 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
1664 int pim_upstream_empty_inherited_olist(struct pim_upstream
*up
)
1666 return pim_channel_oil_empty(up
->channel_oil
);
1670 * When we have a new neighbor,
1671 * find upstreams that don't have their rpf_addr
1672 * set and see if the new neighbor allows
1673 * the join to be sent
1675 void pim_upstream_find_new_rpf(struct pim_instance
*pim
)
1677 struct listnode
*up_node
;
1678 struct listnode
*up_nextnode
;
1679 struct pim_upstream
*up
;
1682 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1684 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
1685 if (up
->upstream_addr
.s_addr
== INADDR_ANY
) {
1686 if (PIM_DEBUG_PIM_TRACE
)
1688 "%s: RP not configured for Upstream %s",
1689 __PRETTY_FUNCTION__
, up
->sg_str
);
1693 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
1694 if (PIM_DEBUG_PIM_TRACE
)
1696 "%s: Upstream %s without a path to send join, checking",
1697 __PRETTY_FUNCTION__
, up
->sg_str
);
1698 pim_rpf_update(pim
, up
, NULL
);
1703 unsigned int pim_upstream_hash_key(const void *arg
)
1705 const struct pim_upstream
*up
= arg
;
1707 return jhash_2words(up
->sg
.src
.s_addr
, up
->sg
.grp
.s_addr
, 0);
1710 void pim_upstream_terminate(struct pim_instance
*pim
)
1712 struct pim_upstream
*up
;
1714 if (pim
->upstream_list
) {
1715 while (pim
->upstream_list
->count
) {
1716 up
= listnode_head(pim
->upstream_list
);
1717 pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1720 list_delete(&pim
->upstream_list
);
1723 if (pim
->upstream_hash
)
1724 hash_free(pim
->upstream_hash
);
1725 pim
->upstream_hash
= NULL
;
1727 if (pim
->upstream_sg_wheel
)
1728 wheel_delete(pim
->upstream_sg_wheel
);
1729 pim
->upstream_sg_wheel
= NULL
;
1732 bool pim_upstream_equal(const void *arg1
, const void *arg2
)
1734 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1735 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1737 if ((up1
->sg
.grp
.s_addr
== up2
->sg
.grp
.s_addr
)
1738 && (up1
->sg
.src
.s_addr
== up2
->sg
.src
.s_addr
))
1744 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1745 * the cases where kat has to be restarted on rxing traffic -
1747 * if( DirectlyConnected(S) == true AND iif == RPF_interface(S) ) {
1748 * set KeepaliveTimer(S,G) to Keepalive_Period
1749 * # Note: a register state transition or UpstreamJPState(S,G)
1750 * # transition may happen as a result of restarting
1751 * # KeepaliveTimer, and must be dealt with here.
1753 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1754 * inherited_olist(S,G) != NULL ) {
1755 * set KeepaliveTimer(S,G) to Keepalive_Period
1758 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1760 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1762 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1763 * so we will skip that here */
1764 if (up
->rpf
.source_nexthop
.interface
&&
1765 pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1770 if ((up
->join_state
== PIM_UPSTREAM_JOINED
)
1771 && !pim_upstream_empty_inherited_olist(up
)) {
1772 /* XXX: I have added this RP check just for 3.2 and it's a
1774 * what rfc-4601 says. Till now we were only running KAT on FHR
1776 * there is some angst around making the change to run it all
1778 * maintain the (S, G) state. This is tracked via CM-13601 and
1780 * removed to handle spt turn-arounds correctly in a 3-tier clos
1782 if (I_am_RP(pim
, up
->sg
.grp
))
1790 * Code to check and see if we've received packets on a S,G mroute
1791 * and if so to set the SPT bit appropriately
1793 static void pim_upstream_sg_running(void *arg
)
1795 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1796 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1798 // No packet can have arrived here if this is the case
1799 if (!up
->channel_oil
->installed
) {
1800 if (PIM_DEBUG_PIM_TRACE
)
1801 zlog_debug("%s: %s%s is not installed in mroute",
1802 __PRETTY_FUNCTION__
, up
->sg_str
,
1808 * This is a bit of a hack
1809 * We've noted that we should rescan but
1810 * we've missed the window for doing so in
1811 * pim_zebra.c for some reason. I am
1812 * only doing this at this point in time
1813 * to get us up and working for the moment
1815 if (up
->channel_oil
->oil_inherited_rescan
) {
1816 if (PIM_DEBUG_PIM_TRACE
)
1818 "%s: Handling unscanned inherited_olist for %s[%s]",
1819 __PRETTY_FUNCTION__
, up
->sg_str
,
1821 pim_upstream_inherited_olist_decide(pim
, up
);
1822 up
->channel_oil
->oil_inherited_rescan
= 0;
1824 pim_mroute_update_counters(up
->channel_oil
);
1826 // Have we seen packets?
1827 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
)
1828 && (up
->channel_oil
->cc
.lastused
/ 100 > 30)) {
1829 if (PIM_DEBUG_PIM_TRACE
) {
1831 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1832 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
1833 up
->channel_oil
->cc
.oldpktcnt
,
1834 up
->channel_oil
->cc
.pktcnt
,
1835 up
->channel_oil
->cc
.lastused
/ 100);
1840 if (pim_upstream_kat_start_ok(up
)) {
1841 /* Add a source reference to the stream if
1842 * one doesn't already exist */
1843 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1844 if (PIM_DEBUG_PIM_TRACE
)
1846 "source reference created on kat restart %s[%s]",
1847 up
->sg_str
, pim
->vrf
->name
);
1849 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
,
1850 __PRETTY_FUNCTION__
);
1851 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
1852 pim_upstream_fhr_kat_start(up
);
1854 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1855 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
))
1856 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1858 if ((up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
) &&
1859 (up
->rpf
.source_nexthop
.interface
)) {
1860 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
1865 void pim_upstream_add_lhr_star_pimreg(struct pim_instance
*pim
)
1867 struct pim_upstream
*up
;
1868 struct listnode
*node
;
1870 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1871 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1874 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1877 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1878 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
1882 void pim_upstream_spt_prefix_list_update(struct pim_instance
*pim
,
1883 struct prefix_list
*pl
)
1885 const char *pname
= prefix_list_name(pl
);
1887 if (pim
->spt
.plist
&& strcmp(pim
->spt
.plist
, pname
) == 0) {
1888 pim_upstream_remove_lhr_star_pimreg(pim
, pname
);
1893 * nlist -> The new prefix list
1895 * Per Group Application of pimreg to the OIL
1896 * If the prefix list tells us DENY then
1897 * we need to Switchover to SPT immediate
1898 * so add the pimreg.
1899 * If the prefix list tells us to ACCEPT than
1900 * we need to Never do the SPT so remove
1904 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance
*pim
,
1907 struct pim_upstream
*up
;
1908 struct listnode
*node
;
1909 struct prefix_list
*np
;
1911 enum prefix_list_type apply_new
;
1913 np
= prefix_list_lookup(AFI_IP
, nlist
);
1916 g
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1918 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1919 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1922 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1926 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1927 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
1930 g
.u
.prefix4
= up
->sg
.grp
;
1931 apply_new
= prefix_list_apply(np
, &g
);
1932 if (apply_new
== PREFIX_DENY
)
1933 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1934 PIM_OIF_FLAG_PROTO_IGMP
,
1937 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1938 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
1942 void pim_upstream_init(struct pim_instance
*pim
)
1946 snprintf(name
, 64, "PIM %s Timer Wheel",
1948 pim
->upstream_sg_wheel
=
1949 wheel_init(router
->master
, 31000, 100, pim_upstream_hash_key
,
1950 pim_upstream_sg_running
, name
);
1952 snprintf(name
, 64, "PIM %s Upstream Hash",
1954 pim
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
1955 pim_upstream_equal
, name
);
1957 pim
->upstream_list
= list_new();
1958 pim
->upstream_list
->cmp
= pim_upstream_compare
;