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
) ||
540 !pim_upstream_is_kat_running(up
))
543 if (pim_is_grp_ssm(pim
, up
->sg
.grp
)) {
544 /* clear the register state for SSM groups */
545 if (up
->reg_state
!= PIM_REG_NOINFO
) {
546 if (PIM_DEBUG_PIM_EVENTS
)
548 "Clear register for %s as G is now SSM",
550 /* remove regiface from the OIL if it is there*/
551 pim_channel_del_oif(up
->channel_oil
,
553 PIM_OIF_FLAG_PROTO_PIM
,
555 up
->reg_state
= PIM_REG_NOINFO
;
558 /* register ASM sources with the RP */
559 if (up
->reg_state
== PIM_REG_NOINFO
) {
560 if (PIM_DEBUG_PIM_EVENTS
)
562 "Register %s as G is now ASM",
564 pim_channel_add_oif(up
->channel_oil
,
566 PIM_OIF_FLAG_PROTO_PIM
,
568 up
->reg_state
= PIM_REG_JOIN
;
574 /* RFC7761, Section 4.2 “Data Packet Forwarding Rules” says we should
576 * 1. along the SPT if SPTbit is set
577 * 2. and along the RPT if SPTbit is not set
578 * If forwarding is hw accelerated i.e. control and dataplane components
579 * are separate you may not be able to reliably set SPT bit on intermediate
580 * routers while still fowarding on the (S,G,rpt).
582 * This macro is a slight deviation on the RFC and uses "traffic-agnostic"
583 * criteria to decide between using the RPT vs. SPT for forwarding.
585 void pim_upstream_update_use_rpt(struct pim_upstream
*up
,
591 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
594 old_use_rpt
= !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
596 /* We will use the SPT (IIF=RPF_interface(S) if -
597 * 1. We have decided to join the SPT
599 * 3. Source is directly connected
600 * 4. We are RP (parent's IIF is lo or vrf-device)
601 * In all other cases the source will stay along the RPT and
602 * IIF=RPF_interface(RP).
604 if (up
->join_state
== PIM_UPSTREAM_JOINED
||
605 PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) ||
606 pim_if_connected_to_source(
607 up
->rpf
.source_nexthop
.interface
,
609 /* XXX - need to switch this to a more efficient
612 I_am_RP(up
->pim
, up
->sg
.grp
))
614 PIM_UPSTREAM_FLAG_UNSET_USE_RPT(up
->flags
);
617 PIM_UPSTREAM_FLAG_SET_USE_RPT(up
->flags
);
619 new_use_rpt
= !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
);
620 if (old_use_rpt
!= new_use_rpt
) {
621 if (PIM_DEBUG_PIM_EVENTS
)
622 zlog_debug("%s switched from %s to %s",
624 old_use_rpt
?"RPT":"SPT",
625 new_use_rpt
?"RPT":"SPT");
627 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
631 /* some events like RP change require re-evaluation of SGrpt across
634 void pim_upstream_reeval_use_rpt(struct pim_instance
*pim
)
636 struct pim_upstream
*up
;
637 struct listnode
*node
;
639 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
640 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
643 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
647 void pim_upstream_switch(struct pim_instance
*pim
, struct pim_upstream
*up
,
648 enum pim_upstream_state new_state
)
650 enum pim_upstream_state old_state
= up
->join_state
;
652 if (up
->upstream_addr
.s_addr
== INADDR_ANY
) {
653 if (PIM_DEBUG_PIM_EVENTS
)
654 zlog_debug("%s: RPF not configured for %s",
655 __PRETTY_FUNCTION__
, up
->sg_str
);
659 if (!up
->rpf
.source_nexthop
.interface
) {
660 if (PIM_DEBUG_PIM_EVENTS
)
661 zlog_debug("%s: RP not reachable for %s",
662 __PRETTY_FUNCTION__
, up
->sg_str
);
666 if (PIM_DEBUG_PIM_EVENTS
) {
667 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
668 __PRETTY_FUNCTION__
, up
->sg_str
,
669 pim_upstream_state2str(up
->join_state
),
670 pim_upstream_state2str(new_state
));
673 up
->join_state
= new_state
;
674 if (old_state
!= new_state
)
675 up
->state_transition
= pim_time_monotonic_sec();
677 pim_upstream_update_assert_tracking_desired(up
);
679 if (new_state
== PIM_UPSTREAM_JOINED
) {
680 pim_upstream_inherited_olist_decide(pim
, up
);
681 if (old_state
!= PIM_UPSTREAM_JOINED
) {
682 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
684 pim_msdp_up_join_state_changed(pim
, up
);
685 if (pim_upstream_could_register(up
)) {
686 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
688 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
690 pim_upstream_keep_alive_timer_start(
691 up
, pim
->keep_alive_time
);
692 pim_register_join(up
);
695 pim_upstream_send_join(up
);
696 join_timer_start(up
);
702 if (old_state
== PIM_UPSTREAM_JOINED
)
703 pim_msdp_up_join_state_changed(pim
, up
);
705 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
707 If I am RP for G then send S,G prune to its IIF. */
708 if (pim_upstream_is_sg_rpt(up
) && up
->parent
709 && !I_am_RP(pim
, up
->sg
.grp
)) {
710 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
712 "%s: *,G IIF %s S,G IIF %s ",
714 up
->parent
->rpf
.source_nexthop
.interface
?
715 up
->parent
->rpf
.source_nexthop
.interface
->name
717 up
->rpf
.source_nexthop
.interface
?
718 up
->rpf
.source_nexthop
.interface
->name
:
720 pim_jp_agg_single_upstream_send(&up
->parent
->rpf
,
724 pim_jp_agg_single_upstream_send(&up
->rpf
, up
,
729 if (old_state
!= new_state
)
730 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
733 int pim_upstream_compare(void *arg1
, void *arg2
)
735 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
736 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
738 if (ntohl(up1
->sg
.grp
.s_addr
) < ntohl(up2
->sg
.grp
.s_addr
))
741 if (ntohl(up1
->sg
.grp
.s_addr
) > ntohl(up2
->sg
.grp
.s_addr
))
744 if (ntohl(up1
->sg
.src
.s_addr
) < ntohl(up2
->sg
.src
.s_addr
))
747 if (ntohl(up1
->sg
.src
.s_addr
) > ntohl(up2
->sg
.src
.s_addr
))
753 void pim_upstream_fill_static_iif(struct pim_upstream
*up
,
754 struct interface
*incoming
)
756 up
->rpf
.source_nexthop
.interface
= incoming
;
758 /* reset other parameters to matched a connected incoming interface */
759 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
760 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
762 up
->rpf
.source_nexthop
.mrib_metric_preference
=
763 ZEBRA_CONNECT_DISTANCE_DEFAULT
;
764 up
->rpf
.source_nexthop
.mrib_route_metric
= 0;
765 up
->rpf
.rpf_addr
.family
= AF_INET
;
766 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
770 static struct pim_upstream
*pim_upstream_new(struct pim_instance
*pim
,
771 struct prefix_sg
*sg
,
772 struct interface
*incoming
,
774 struct pim_ifchannel
*ch
)
776 enum pim_rpf_result rpf_result
;
777 struct pim_interface
*pim_ifp
;
778 struct pim_upstream
*up
;
780 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
784 pim_str_sg_set(sg
, up
->sg_str
);
788 up
= hash_get(pim
->upstream_hash
, up
, hash_alloc_intern
);
789 /* Set up->upstream_addr as INADDR_ANY, if RP is not
790 * configured and retain the upstream data structure
792 if (!pim_rp_set_upstream_addr(pim
, &up
->upstream_addr
, sg
->src
,
794 if (PIM_DEBUG_PIM_TRACE
)
795 zlog_debug("%s: Received a (*,G) with no RP configured",
796 __PRETTY_FUNCTION__
);
799 up
->parent
= pim_upstream_find_parent(pim
, up
);
800 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
801 up
->sources
= list_new();
802 up
->sources
->cmp
= pim_upstream_compare
;
806 pim_upstream_find_new_children(pim
, up
);
809 up
->t_join_timer
= NULL
;
810 up
->t_ka_timer
= NULL
;
811 up
->t_rs_timer
= NULL
;
812 up
->t_msdp_reg_timer
= NULL
;
813 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
814 up
->reg_state
= PIM_REG_NOINFO
;
815 up
->state_transition
= pim_time_monotonic_sec();
817 pim_channel_oil_add(pim
, &up
->sg
, __PRETTY_FUNCTION__
);
818 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
820 up
->rpf
.source_nexthop
.interface
= NULL
;
821 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
822 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
824 up
->rpf
.source_nexthop
.mrib_metric_preference
=
825 router
->infinite_assert_metric
.metric_preference
;
826 up
->rpf
.source_nexthop
.mrib_route_metric
=
827 router
->infinite_assert_metric
.route_metric
;
828 up
->rpf
.rpf_addr
.family
= AF_INET
;
829 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
831 up
->ifchannels
= list_new();
832 up
->ifchannels
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
834 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
835 wheel_add_item(pim
->upstream_sg_wheel
, up
);
837 if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up
->flags
)
838 || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
)) {
839 pim_upstream_fill_static_iif(up
, incoming
);
840 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
842 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
844 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
))
845 pim_upstream_keep_alive_timer_start(
846 up
, pim
->keep_alive_time
);
847 } else if (up
->upstream_addr
.s_addr
!= INADDR_ANY
) {
848 rpf_result
= pim_rpf_update(pim
, up
, NULL
);
849 if (rpf_result
== PIM_RPF_FAILURE
) {
850 if (PIM_DEBUG_PIM_TRACE
)
852 "%s: Attempting to create upstream(%s), Unable to RPF for source",
853 __PRETTY_FUNCTION__
, up
->sg_str
);
856 if (up
->rpf
.source_nexthop
.interface
) {
857 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
859 pim_upstream_mroute_iif_update(up
->channel_oil
,
862 pim_upstream_update_use_rpt(up
,
863 false /*update_mroute*/);
866 listnode_add_sort(pim
->upstream_list
, up
);
868 if (PIM_DEBUG_PIM_TRACE
) {
870 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
871 __PRETTY_FUNCTION__
, up
->sg_str
,
872 inet_ntoa(up
->upstream_addr
), up
->ref_count
);
878 struct pim_upstream
*pim_upstream_find(struct pim_instance
*pim
,
879 struct prefix_sg
*sg
)
881 struct pim_upstream lookup
;
882 struct pim_upstream
*up
= NULL
;
885 up
= hash_lookup(pim
->upstream_hash
, &lookup
);
889 struct pim_upstream
*pim_upstream_find_or_add(struct prefix_sg
*sg
,
890 struct interface
*incoming
,
891 int flags
, const char *name
)
893 struct pim_interface
*pim_ifp
= incoming
->info
;
895 return (pim_upstream_add(pim_ifp
->pim
, sg
, incoming
, flags
, name
,
899 void pim_upstream_ref(struct pim_upstream
*up
, int flags
, const char *name
)
901 /* when we go from non-FHR to FHR we need to re-eval traffic
904 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) &&
905 PIM_UPSTREAM_FLAG_TEST_FHR(flags
)) {
906 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
907 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
912 if (PIM_DEBUG_PIM_TRACE
)
913 zlog_debug("%s(%s): upstream %s ref count %d increment",
914 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
918 struct pim_upstream
*pim_upstream_add(struct pim_instance
*pim
,
919 struct prefix_sg
*sg
,
920 struct interface
*incoming
, int flags
,
922 struct pim_ifchannel
*ch
)
924 struct pim_upstream
*up
= NULL
;
927 up
= pim_upstream_find(pim
, sg
);
929 pim_upstream_ref(up
, flags
, name
);
932 up
= pim_upstream_new(pim
, sg
, incoming
, flags
, ch
);
935 if (PIM_DEBUG_PIM_TRACE
) {
937 char buf
[PREFIX2STR_BUFFER
];
938 prefix2str(&up
->rpf
.rpf_addr
, buf
, sizeof(buf
));
939 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
940 __PRETTY_FUNCTION__
, name
,
941 up
->sg_str
, buf
, up
->rpf
.source_nexthop
.interface
?
942 up
->rpf
.source_nexthop
.interface
->name
: "Unknown" ,
943 found
, up
->ref_count
);
945 zlog_debug("%s(%s): (%s) failure to create",
946 __PRETTY_FUNCTION__
, name
,
947 pim_str_sg_dump(sg
));
954 * Passed in up must be the upstream for ch. starch is NULL if no
956 * This function is copied over from
957 * pim_upstream_evaluate_join_desired_interface but limited to
958 * parent (*,G)'s includes/joins.
960 int pim_upstream_eval_inherit_if(struct pim_upstream
*up
,
961 struct pim_ifchannel
*ch
,
962 struct pim_ifchannel
*starch
)
964 /* if there is an explicit prune for this interface we cannot
968 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
972 /* Check if the OIF can be inherited fron the (*,G) entry
975 if (!pim_macro_ch_lost_assert(starch
)
976 && pim_macro_chisin_joins_or_include(starch
))
984 * Passed in up must be the upstream for ch. starch is NULL if no
987 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream
*up
,
988 struct pim_ifchannel
*ch
,
989 struct pim_ifchannel
*starch
)
992 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
995 if (!pim_macro_ch_lost_assert(ch
)
996 && pim_macro_chisin_joins_or_include(ch
))
1004 /* XXX: check on this with donald
1005 * we are looking for PIM_IF_FLAG_MASK_S_G_RPT in
1009 if (PIM_IF_FLAG_TEST_S_G_RPT(starch
->upstream
->flags
))
1013 if (!pim_macro_ch_lost_assert(starch
)
1014 && pim_macro_chisin_joins_or_include(starch
))
1021 /* Returns true if immediate OIL is empty and is used to evaluate
1022 * JoinDesired. See pim_upstream_evaluate_join_desired.
1024 static bool pim_upstream_empty_immediate_olist(struct pim_instance
*pim
,
1025 struct pim_upstream
*up
)
1027 struct interface
*ifp
;
1028 struct pim_ifchannel
*ch
;
1030 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1034 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1038 /* If we have even one immediate OIF we can return with
1041 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1044 } /* scan iface channel list */
1046 /* immediate_oil is empty */
1051 * bool JoinDesired(*,G) {
1052 * if (immediate_olist(*,G) != NULL)
1058 * bool JoinDesired(S,G) {
1059 * return( immediate_olist(S,G) != NULL
1060 * OR ( KeepaliveTimer(S,G) is running
1061 * AND inherited_olist(S,G) != NULL ) )
1064 int pim_upstream_evaluate_join_desired(struct pim_instance
*pim
,
1065 struct pim_upstream
*up
)
1070 empty_imm_oil
= pim_upstream_empty_immediate_olist(pim
, up
);
1073 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
1074 return !empty_imm_oil
;
1079 empty_inh_oil
= pim_upstream_empty_inherited_olist(up
);
1080 if (!empty_inh_oil
&&
1081 (pim_upstream_is_kat_running(up
) ||
1082 I_am_RP(pim
, up
->sg
.grp
)))
1089 See also pim_upstream_evaluate_join_desired() above.
1091 void pim_upstream_update_join_desired(struct pim_instance
*pim
,
1092 struct pim_upstream
*up
)
1094 int was_join_desired
; /* boolean */
1095 int is_join_desired
; /* boolean */
1097 was_join_desired
= PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up
->flags
);
1099 is_join_desired
= pim_upstream_evaluate_join_desired(pim
, up
);
1100 if (is_join_desired
)
1101 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up
->flags
);
1103 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up
->flags
);
1105 /* switched from false to true */
1106 if (is_join_desired
&& (up
->join_state
== PIM_UPSTREAM_NOTJOINED
)) {
1107 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
1111 /* switched from true to false */
1112 if (!is_join_desired
&& was_join_desired
) {
1113 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_NOTJOINED
);
1119 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
1120 Transitions from Joined State
1121 RPF'(S,G) GenID changes
1123 The upstream (S,G) state machine remains in Joined state. If the
1124 Join Timer is set to expire in more than t_override seconds, reset
1125 it so that it expires after t_override seconds.
1127 void pim_upstream_rpf_genid_changed(struct pim_instance
*pim
,
1128 struct in_addr neigh_addr
)
1130 struct listnode
*up_node
;
1131 struct listnode
*up_nextnode
;
1132 struct pim_upstream
*up
;
1135 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1137 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
1139 if (PIM_DEBUG_PIM_TRACE
) {
1140 char neigh_str
[INET_ADDRSTRLEN
];
1141 char rpf_addr_str
[PREFIX_STRLEN
];
1142 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
,
1144 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_addr_str
,
1145 sizeof(rpf_addr_str
));
1147 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
1148 __PRETTY_FUNCTION__
, neigh_str
, up
->sg_str
,
1150 up
->join_state
== PIM_UPSTREAM_JOINED
,
1154 /* consider only (S,G) upstream in Joined state */
1155 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
1158 /* match RPF'(S,G)=neigh_addr */
1159 if (up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
!= neigh_addr
.s_addr
)
1162 pim_upstream_join_timer_decrease_to_t_override(
1163 "RPF'(S,G) GenID change", up
);
1168 void pim_upstream_rpf_interface_changed(struct pim_upstream
*up
,
1169 struct interface
*old_rpf_ifp
)
1171 struct listnode
*chnode
;
1172 struct listnode
*chnextnode
;
1173 struct pim_ifchannel
*ch
;
1175 /* search all ifchannels */
1176 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1177 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
1179 /* RPF_interface(S) was NOT I */
1180 (old_rpf_ifp
== ch
->interface
) &&
1181 /* RPF_interface(S) stopped being I */
1182 (ch
->upstream
->rpf
.source_nexthop
1184 (ch
->upstream
->rpf
.source_nexthop
1185 .interface
!= ch
->interface
)) {
1186 assert_action_a5(ch
);
1188 } /* PIM_IFASSERT_I_AM_LOSER */
1190 pim_ifchannel_update_assert_tracking_desired(ch
);
1194 void pim_upstream_update_could_assert(struct pim_upstream
*up
)
1196 struct listnode
*chnode
;
1197 struct listnode
*chnextnode
;
1198 struct pim_ifchannel
*ch
;
1200 /* scan per-interface (S,G) state */
1201 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1202 pim_ifchannel_update_could_assert(ch
);
1203 } /* scan iface channel list */
1206 void pim_upstream_update_my_assert_metric(struct pim_upstream
*up
)
1208 struct listnode
*chnode
;
1209 struct listnode
*chnextnode
;
1210 struct pim_ifchannel
*ch
;
1212 /* scan per-interface (S,G) state */
1213 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1214 pim_ifchannel_update_my_assert_metric(ch
);
1216 } /* scan iface channel list */
1219 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
)
1221 struct listnode
*chnode
;
1222 struct listnode
*chnextnode
;
1223 struct pim_interface
*pim_ifp
;
1224 struct pim_ifchannel
*ch
;
1226 /* scan per-interface (S,G) state */
1227 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1230 pim_ifp
= ch
->interface
->info
;
1234 pim_ifchannel_update_assert_tracking_desired(ch
);
1236 } /* scan iface channel list */
1239 /* When kat is stopped CouldRegister goes to false so we need to
1240 * transition the (S, G) on FHR to NI state and remove reg tunnel
1242 static void pim_upstream_fhr_kat_expiry(struct pim_instance
*pim
,
1243 struct pim_upstream
*up
)
1245 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
1248 if (PIM_DEBUG_PIM_TRACE
)
1249 zlog_debug("kat expired on %s; clear fhr reg state",
1252 /* stop reg-stop timer */
1253 THREAD_OFF(up
->t_rs_timer
);
1254 /* remove regiface from the OIL if it is there*/
1255 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1256 PIM_OIF_FLAG_PROTO_PIM
, __func__
);
1257 /* clear the register state */
1258 up
->reg_state
= PIM_REG_NOINFO
;
1259 PIM_UPSTREAM_FLAG_UNSET_FHR(up
->flags
);
1262 /* When kat is started CouldRegister can go to true. And if it does we
1263 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1265 static void pim_upstream_fhr_kat_start(struct pim_upstream
*up
)
1267 if (pim_upstream_could_register(up
)) {
1268 if (PIM_DEBUG_PIM_TRACE
)
1270 "kat started on %s; set fhr reg state to joined",
1273 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1274 if (up
->reg_state
== PIM_REG_NOINFO
)
1275 pim_register_join(up
);
1276 pim_upstream_update_use_rpt(up
, true /*update_mroute*/);
1281 * On an RP, the PMBR value must be cleared when the
1282 * Keepalive Timer expires
1283 * KAT expiry indicates that flow is inactive. If the flow was created or
1284 * maintained by activity now is the time to deref it.
1286 struct pim_upstream
*pim_upstream_keep_alive_timer_proc(
1287 struct pim_upstream
*up
)
1289 struct pim_instance
*pim
;
1291 pim
= up
->channel_oil
->pim
;
1293 if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up
->flags
)) {
1294 /* if the router is a PIM vxlan encapsulator we prevent expiry
1295 * of KAT as the mroute is pre-setup without any traffic
1297 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1301 if (I_am_RP(pim
, up
->sg
.grp
)) {
1302 pim_br_clear_pmbr(&up
->sg
);
1304 * We need to do more here :)
1305 * But this is the start.
1309 /* source is no longer active - pull the SA from MSDP's cache */
1310 pim_msdp_sa_local_del(pim
, &up
->sg
);
1312 /* JoinDesired can change when KAT is started or stopped */
1313 pim_upstream_update_join_desired(pim
, up
);
1315 /* if entry was created because of activity we need to deref it */
1316 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1317 pim_upstream_fhr_kat_expiry(pim
, up
);
1318 if (PIM_DEBUG_PIM_TRACE
)
1320 "kat expired on %s[%s]; remove stream reference",
1321 up
->sg_str
, pim
->vrf
->name
);
1322 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up
->flags
);
1324 /* Return if upstream entry got deleted.*/
1325 if (!pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
))
1328 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up
->flags
)) {
1329 PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up
->flags
);
1331 if (!pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
))
1335 /* upstream reference would have been added to track the local
1336 * membership if it is LHR. We have to clear it when KAT expires.
1337 * Otherwise would result in stale entry with uncleared ref count.
1339 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
1340 struct pim_upstream
*parent
= up
->parent
;
1342 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1343 up
= pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1346 pim_jp_agg_single_upstream_send(&parent
->rpf
, parent
,
1353 static int pim_upstream_keep_alive_timer(struct thread
*t
)
1355 struct pim_upstream
*up
;
1359 pim_upstream_keep_alive_timer_proc(up
);
1363 void pim_upstream_keep_alive_timer_start(struct pim_upstream
*up
, uint32_t time
)
1365 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1366 if (PIM_DEBUG_PIM_TRACE
)
1367 zlog_debug("kat start on %s with no stream reference",
1370 THREAD_OFF(up
->t_ka_timer
);
1371 thread_add_timer(router
->master
, pim_upstream_keep_alive_timer
, up
,
1372 time
, &up
->t_ka_timer
);
1374 /* any time keepalive is started against a SG we will have to
1375 * re-evaluate our active source database */
1376 pim_msdp_sa_local_update(up
);
1377 /* JoinDesired can change when KAT is started or stopped */
1378 pim_upstream_update_join_desired(up
->pim
, up
);
1381 /* MSDP on RP needs to know if a source is registerable to this RP */
1382 static int pim_upstream_msdp_reg_timer(struct thread
*t
)
1384 struct pim_upstream
*up
= THREAD_ARG(t
);
1385 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1387 /* source is no longer active - pull the SA from MSDP's cache */
1388 pim_msdp_sa_local_del(pim
, &up
->sg
);
1391 void pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1393 THREAD_OFF(up
->t_msdp_reg_timer
);
1394 thread_add_timer(router
->master
, pim_upstream_msdp_reg_timer
, up
,
1395 PIM_MSDP_REG_RXED_PERIOD
, &up
->t_msdp_reg_timer
);
1397 pim_msdp_sa_local_update(up
);
1401 * 4.2.1 Last-Hop Switchover to the SPT
1403 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1404 * RP. Once traffic from sources to joined groups arrives at a last-hop
1405 * router, it has the option of switching to receive the traffic on a
1406 * shortest path tree (SPT).
1408 * The decision for a router to switch to the SPT is controlled as
1412 * CheckSwitchToSpt(S,G) {
1413 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1414 * (+) pim_include(S,G) != NULL )
1415 * AND SwitchToSptDesired(S,G) ) {
1416 * # Note: Restarting the KAT will result in the SPT switch
1417 * set KeepaliveTimer(S,G) to Keepalive_Period
1421 * SwitchToSptDesired(S,G) is a policy function that is implementation
1422 * defined. An "infinite threshold" policy can be implemented by making
1423 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1424 * first packet" policy can be implemented by making
1425 * SwitchToSptDesired(S,G) return true once a single packet has been
1426 * received for the source and group.
1428 int pim_upstream_switch_to_spt_desired_on_rp(struct pim_instance
*pim
,
1429 struct prefix_sg
*sg
)
1431 if (I_am_RP(pim
, sg
->grp
))
1437 int pim_upstream_is_sg_rpt(struct pim_upstream
*up
)
1439 struct listnode
*chnode
;
1440 struct pim_ifchannel
*ch
;
1442 for (ALL_LIST_ELEMENTS_RO(up
->ifchannels
, chnode
, ch
)) {
1443 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1450 * After receiving a packet set SPTbit:
1452 * Update_SPTbit(S,G,iif) {
1453 * if ( iif == RPF_interface(S)
1454 * AND JoinDesired(S,G) == true
1455 * AND ( DirectlyConnected(S) == true
1456 * OR RPF_interface(S) != RPF_interface(RP(G))
1457 * OR inherited_olist(S,G,rpt) == NULL
1458 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1459 * ( RPF'(S,G) != NULL ) )
1460 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1461 * Set SPTbit(S,G) to true
1465 void pim_upstream_set_sptbit(struct pim_upstream
*up
,
1466 struct interface
*incoming
)
1468 struct pim_upstream
*starup
= up
->parent
;
1470 // iif == RPF_interfvace(S)
1471 if (up
->rpf
.source_nexthop
.interface
!= incoming
) {
1472 if (PIM_DEBUG_PIM_TRACE
)
1474 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1475 __PRETTY_FUNCTION__
, incoming
->name
,
1476 up
->rpf
.source_nexthop
.interface
->name
);
1480 // AND JoinDesired(S,G) == true
1481 if (!pim_upstream_evaluate_join_desired(up
->channel_oil
->pim
, up
)) {
1482 if (PIM_DEBUG_PIM_TRACE
)
1483 zlog_debug("%s: %s Join is not Desired",
1484 __PRETTY_FUNCTION__
, up
->sg_str
);
1488 // DirectlyConnected(S) == true
1489 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1491 if (PIM_DEBUG_PIM_TRACE
)
1492 zlog_debug("%s: %s is directly connected to the source",
1493 __PRETTY_FUNCTION__
, up
->sg_str
);
1494 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1498 // OR RPF_interface(S) != RPF_interface(RP(G))
1500 || up
->rpf
.source_nexthop
1501 .interface
!= starup
->rpf
.source_nexthop
.interface
) {
1502 struct pim_upstream
*starup
= up
->parent
;
1504 if (PIM_DEBUG_PIM_TRACE
)
1506 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1507 __PRETTY_FUNCTION__
, up
->sg_str
);
1508 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1510 pim_jp_agg_single_upstream_send(&starup
->rpf
, starup
, true);
1514 // OR inherited_olist(S,G,rpt) == NULL
1515 if (pim_upstream_is_sg_rpt(up
)
1516 && pim_upstream_empty_inherited_olist(up
)) {
1517 if (PIM_DEBUG_PIM_TRACE
)
1518 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1519 __PRETTY_FUNCTION__
, up
->sg_str
);
1520 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1524 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1525 // ( RPF'(S,G) != NULL ) )
1526 if (up
->parent
&& pim_rpf_is_same(&up
->rpf
, &up
->parent
->rpf
)) {
1527 if (PIM_DEBUG_PIM_TRACE
)
1528 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1529 __PRETTY_FUNCTION__
, up
->sg_str
);
1530 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1537 const char *pim_upstream_state2str(enum pim_upstream_state join_state
)
1539 switch (join_state
) {
1540 case PIM_UPSTREAM_NOTJOINED
:
1543 case PIM_UPSTREAM_JOINED
:
1550 const char *pim_reg_state2str(enum pim_reg_state reg_state
, char *state_str
,
1551 size_t state_str_len
)
1553 switch (reg_state
) {
1554 case PIM_REG_NOINFO
:
1555 strlcpy(state_str
, "RegNoInfo", state_str_len
);
1558 strlcpy(state_str
, "RegJoined", state_str_len
);
1560 case PIM_REG_JOIN_PENDING
:
1561 strlcpy(state_str
, "RegJoinPend", state_str_len
);
1564 strlcpy(state_str
, "RegPrune", state_str_len
);
1567 strlcpy(state_str
, "RegUnknown", state_str_len
);
1572 static int pim_upstream_register_stop_timer(struct thread
*t
)
1574 struct pim_interface
*pim_ifp
;
1575 struct pim_instance
*pim
;
1576 struct pim_upstream
*up
;
1578 pim
= up
->channel_oil
->pim
;
1580 if (PIM_DEBUG_PIM_TRACE
) {
1581 char state_str
[PIM_REG_STATE_STR_LEN
];
1582 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1583 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
1584 pim_reg_state2str(up
->reg_state
, state_str
, sizeof(state_str
)));
1587 switch (up
->reg_state
) {
1588 case PIM_REG_JOIN_PENDING
:
1589 up
->reg_state
= PIM_REG_JOIN
;
1590 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1591 PIM_OIF_FLAG_PROTO_PIM
,
1593 pim_vxlan_update_sg_reg_state(pim
, up
, true /*reg_join*/);
1598 if (!up
->rpf
.source_nexthop
.interface
) {
1599 if (PIM_DEBUG_PIM_TRACE
)
1600 zlog_debug("%s: up %s RPF is not present",
1601 __PRETTY_FUNCTION__
, up
->sg_str
);
1605 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1607 if (PIM_DEBUG_PIM_TRACE
)
1609 "%s: Interface: %s is not configured for pim",
1610 __PRETTY_FUNCTION__
,
1611 up
->rpf
.source_nexthop
.interface
->name
);
1614 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1615 pim_upstream_start_register_stop_timer(up
, 1);
1617 if (((up
->channel_oil
->cc
.lastused
/ 100)
1618 > pim
->keep_alive_time
)
1619 && (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
))) {
1620 if (PIM_DEBUG_PIM_TRACE
)
1622 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1623 __PRETTY_FUNCTION__
);
1626 pim_null_register_send(up
);
1635 void pim_upstream_start_register_stop_timer(struct pim_upstream
*up
,
1640 THREAD_TIMER_OFF(up
->t_rs_timer
);
1642 if (!null_register
) {
1643 uint32_t lower
= (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1644 uint32_t upper
= (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1645 time
= lower
+ (random() % (upper
- lower
+ 1))
1646 - PIM_REGISTER_PROBE_PERIOD
;
1648 time
= PIM_REGISTER_PROBE_PERIOD
;
1650 if (PIM_DEBUG_PIM_TRACE
) {
1652 "%s: (S,G)=%s Starting upstream register stop timer %d",
1653 __PRETTY_FUNCTION__
, up
->sg_str
, time
);
1655 thread_add_timer(router
->master
, pim_upstream_register_stop_timer
, up
,
1656 time
, &up
->t_rs_timer
);
1659 int pim_upstream_inherited_olist_decide(struct pim_instance
*pim
,
1660 struct pim_upstream
*up
)
1662 struct interface
*ifp
;
1663 struct pim_ifchannel
*ch
, *starch
;
1664 struct pim_upstream
*starup
= up
->parent
;
1665 int output_intf
= 0;
1667 if (!up
->rpf
.source_nexthop
.interface
)
1668 if (PIM_DEBUG_PIM_TRACE
)
1669 zlog_debug("%s: up %s RPF is not present",
1670 __PRETTY_FUNCTION__
, up
->sg_str
);
1672 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1676 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1679 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
1686 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1688 int flag
= PIM_OIF_FLAG_PROTO_PIM
;
1691 flag
= PIM_OIF_FLAG_PROTO_STAR
;
1693 pim_channel_add_oif(up
->channel_oil
, ifp
, flag
,
1703 * For a given upstream, determine the inherited_olist
1706 * inherited_olist(S,G,rpt) =
1707 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1708 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1709 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1711 * inherited_olist(S,G) =
1712 * inherited_olist(S,G,rpt) (+)
1713 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1715 * return 1 if there are any output interfaces
1716 * return 0 if there are not any output interfaces
1718 int pim_upstream_inherited_olist(struct pim_instance
*pim
,
1719 struct pim_upstream
*up
)
1721 int output_intf
= pim_upstream_inherited_olist_decide(pim
, up
);
1724 * If we have output_intf switch state to Join and work like normal
1725 * If we don't have an output_intf that means we are probably a
1726 * switch on a stick so turn on forwarding to just accept the
1727 * incoming packets so we don't bother the other stuff!
1729 pim_upstream_update_join_desired(pim
, up
);
1737 int pim_upstream_empty_inherited_olist(struct pim_upstream
*up
)
1739 return pim_channel_oil_empty(up
->channel_oil
);
1743 * When we have a new neighbor,
1744 * find upstreams that don't have their rpf_addr
1745 * set and see if the new neighbor allows
1746 * the join to be sent
1748 void pim_upstream_find_new_rpf(struct pim_instance
*pim
)
1750 struct listnode
*up_node
;
1751 struct listnode
*up_nextnode
;
1752 struct pim_upstream
*up
;
1755 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1757 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
1758 if (up
->upstream_addr
.s_addr
== INADDR_ANY
) {
1759 if (PIM_DEBUG_PIM_TRACE
)
1761 "%s: RP not configured for Upstream %s",
1762 __PRETTY_FUNCTION__
, up
->sg_str
);
1766 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
1767 if (PIM_DEBUG_PIM_TRACE
)
1769 "%s: Upstream %s without a path to send join, checking",
1770 __PRETTY_FUNCTION__
, up
->sg_str
);
1771 pim_rpf_update(pim
, up
, NULL
);
1776 unsigned int pim_upstream_hash_key(const void *arg
)
1778 const struct pim_upstream
*up
= arg
;
1780 return jhash_2words(up
->sg
.src
.s_addr
, up
->sg
.grp
.s_addr
, 0);
1783 void pim_upstream_terminate(struct pim_instance
*pim
)
1785 struct pim_upstream
*up
;
1787 if (pim
->upstream_list
) {
1788 while (pim
->upstream_list
->count
) {
1789 up
= listnode_head(pim
->upstream_list
);
1790 pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1793 list_delete(&pim
->upstream_list
);
1796 if (pim
->upstream_hash
)
1797 hash_free(pim
->upstream_hash
);
1798 pim
->upstream_hash
= NULL
;
1800 if (pim
->upstream_sg_wheel
)
1801 wheel_delete(pim
->upstream_sg_wheel
);
1802 pim
->upstream_sg_wheel
= NULL
;
1805 bool pim_upstream_equal(const void *arg1
, const void *arg2
)
1807 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1808 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1810 if ((up1
->sg
.grp
.s_addr
== up2
->sg
.grp
.s_addr
)
1811 && (up1
->sg
.src
.s_addr
== up2
->sg
.src
.s_addr
))
1817 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1818 * the cases where kat has to be restarted on rxing traffic -
1820 * if( DirectlyConnected(S) == true AND iif == RPF_interface(S) ) {
1821 * set KeepaliveTimer(S,G) to Keepalive_Period
1822 * # Note: a register state transition or UpstreamJPState(S,G)
1823 * # transition may happen as a result of restarting
1824 * # KeepaliveTimer, and must be dealt with here.
1826 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1827 * inherited_olist(S,G) != NULL ) {
1828 * set KeepaliveTimer(S,G) to Keepalive_Period
1831 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1833 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1835 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1836 * so we will skip that here */
1837 if (up
->rpf
.source_nexthop
.interface
&&
1838 pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1843 if ((up
->join_state
== PIM_UPSTREAM_JOINED
)
1844 && !pim_upstream_empty_inherited_olist(up
)) {
1845 /* XXX: I have added this RP check just for 3.2 and it's a
1847 * what rfc-4601 says. Till now we were only running KAT on FHR
1849 * there is some angst around making the change to run it all
1851 * maintain the (S, G) state. This is tracked via CM-13601 and
1853 * removed to handle spt turn-arounds correctly in a 3-tier clos
1855 if (I_am_RP(pim
, up
->sg
.grp
))
1863 * Code to check and see if we've received packets on a S,G mroute
1864 * and if so to set the SPT bit appropriately
1866 static void pim_upstream_sg_running(void *arg
)
1868 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1869 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1871 // No packet can have arrived here if this is the case
1872 if (!up
->channel_oil
->installed
) {
1873 if (PIM_DEBUG_PIM_TRACE
)
1874 zlog_debug("%s: %s%s is not installed in mroute",
1875 __PRETTY_FUNCTION__
, up
->sg_str
,
1881 * This is a bit of a hack
1882 * We've noted that we should rescan but
1883 * we've missed the window for doing so in
1884 * pim_zebra.c for some reason. I am
1885 * only doing this at this point in time
1886 * to get us up and working for the moment
1888 if (up
->channel_oil
->oil_inherited_rescan
) {
1889 if (PIM_DEBUG_PIM_TRACE
)
1891 "%s: Handling unscanned inherited_olist for %s[%s]",
1892 __PRETTY_FUNCTION__
, up
->sg_str
,
1894 pim_upstream_inherited_olist_decide(pim
, up
);
1895 up
->channel_oil
->oil_inherited_rescan
= 0;
1897 pim_mroute_update_counters(up
->channel_oil
);
1899 // Have we seen packets?
1900 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
)
1901 && (up
->channel_oil
->cc
.lastused
/ 100 > 30)) {
1902 if (PIM_DEBUG_PIM_TRACE
) {
1904 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1905 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
1906 up
->channel_oil
->cc
.oldpktcnt
,
1907 up
->channel_oil
->cc
.pktcnt
,
1908 up
->channel_oil
->cc
.lastused
/ 100);
1913 if (pim_upstream_kat_start_ok(up
)) {
1914 /* Add a source reference to the stream if
1915 * one doesn't already exist */
1916 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1917 if (PIM_DEBUG_PIM_TRACE
)
1919 "source reference created on kat restart %s[%s]",
1920 up
->sg_str
, pim
->vrf
->name
);
1922 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
,
1923 __PRETTY_FUNCTION__
);
1924 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
1925 pim_upstream_fhr_kat_start(up
);
1927 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1928 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
))
1929 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1931 if ((up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
) &&
1932 (up
->rpf
.source_nexthop
.interface
)) {
1933 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
1938 void pim_upstream_add_lhr_star_pimreg(struct pim_instance
*pim
)
1940 struct pim_upstream
*up
;
1941 struct listnode
*node
;
1943 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1944 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1947 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1950 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1951 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
1955 void pim_upstream_spt_prefix_list_update(struct pim_instance
*pim
,
1956 struct prefix_list
*pl
)
1958 const char *pname
= prefix_list_name(pl
);
1960 if (pim
->spt
.plist
&& strcmp(pim
->spt
.plist
, pname
) == 0) {
1961 pim_upstream_remove_lhr_star_pimreg(pim
, pname
);
1966 * nlist -> The new prefix list
1968 * Per Group Application of pimreg to the OIL
1969 * If the prefix list tells us DENY then
1970 * we need to Switchover to SPT immediate
1971 * so add the pimreg.
1972 * If the prefix list tells us to ACCEPT than
1973 * we need to Never do the SPT so remove
1977 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance
*pim
,
1980 struct pim_upstream
*up
;
1981 struct listnode
*node
;
1982 struct prefix_list
*np
;
1984 enum prefix_list_type apply_new
;
1986 np
= prefix_list_lookup(AFI_IP
, nlist
);
1989 g
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1991 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1992 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1995 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1999 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
2000 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
2003 g
.u
.prefix4
= up
->sg
.grp
;
2004 apply_new
= prefix_list_apply(np
, &g
);
2005 if (apply_new
== PREFIX_DENY
)
2006 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
2007 PIM_OIF_FLAG_PROTO_IGMP
,
2010 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
2011 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
2015 void pim_upstream_init(struct pim_instance
*pim
)
2019 snprintf(name
, 64, "PIM %s Timer Wheel",
2021 pim
->upstream_sg_wheel
=
2022 wheel_init(router
->master
, 31000, 100, pim_upstream_hash_key
,
2023 pim_upstream_sg_running
, name
);
2025 snprintf(name
, 64, "PIM %s Upstream Hash",
2027 pim
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
2028 pim_upstream_equal
, name
);
2030 pim
->upstream_list
= list_new();
2031 pim
->upstream_list
->cmp
= pim_upstream_compare
;