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
,
84 list_delete(&up
->sources
);
88 * A (*,G) or a (*,*) is being created
89 * Find the children that would point
92 static void pim_upstream_find_new_children(struct pim_instance
*pim
,
93 struct pim_upstream
*up
)
95 struct pim_upstream
*child
;
96 struct listnode
*ch_node
;
98 if ((up
->sg
.src
.s_addr
!= INADDR_ANY
)
99 && (up
->sg
.grp
.s_addr
!= INADDR_ANY
))
102 if ((up
->sg
.src
.s_addr
== INADDR_ANY
)
103 && (up
->sg
.grp
.s_addr
== INADDR_ANY
))
106 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, ch_node
, child
)) {
107 if ((up
->sg
.grp
.s_addr
!= INADDR_ANY
)
108 && (child
->sg
.grp
.s_addr
== up
->sg
.grp
.s_addr
)
111 listnode_add_sort(up
->sources
, child
);
117 * If we have a (*,*) || (S,*) there is no parent
118 * If we have a (S,G), find the (*,G)
119 * If we have a (*,G), find the (*,*)
121 static struct pim_upstream
*pim_upstream_find_parent(struct pim_instance
*pim
,
122 struct pim_upstream
*child
)
124 struct prefix_sg any
= child
->sg
;
125 struct pim_upstream
*up
= NULL
;
128 if ((child
->sg
.src
.s_addr
!= INADDR_ANY
)
129 && (child
->sg
.grp
.s_addr
!= INADDR_ANY
)) {
130 any
.src
.s_addr
= INADDR_ANY
;
131 up
= pim_upstream_find(pim
, &any
);
134 listnode_add(up
->sources
, child
);
142 static void upstream_channel_oil_detach(struct pim_upstream
*up
)
144 if (up
->channel_oil
) {
145 /* Detaching from channel_oil, channel_oil may exist post del,
146 but upstream would not keep reference of it
148 up
->channel_oil
->up
= NULL
;
149 pim_channel_oil_del(up
->channel_oil
, __PRETTY_FUNCTION__
);
150 up
->channel_oil
= NULL
;
154 struct pim_upstream
*pim_upstream_del(struct pim_instance
*pim
,
155 struct pim_upstream
*up
, const char *name
)
157 struct listnode
*node
, *nnode
;
158 struct pim_ifchannel
*ch
;
159 bool notify_msdp
= false;
164 "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
165 __PRETTY_FUNCTION__
, name
, up
->sg_str
, pim
->vrf
->name
,
166 up
->ref_count
, up
->flags
,
167 up
->channel_oil
->oil_ref_count
);
169 assert(up
->ref_count
> 0);
173 if (up
->ref_count
>= 1)
176 THREAD_OFF(up
->t_ka_timer
);
177 THREAD_OFF(up
->t_rs_timer
);
178 THREAD_OFF(up
->t_msdp_reg_timer
);
180 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
181 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 0);
183 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
184 /* if a (*, G) entry in the joined state is being
186 * need to notify MSDP */
192 pim_jp_agg_upstream_verification(up
, false);
193 up
->rpf
.source_nexthop
.interface
= NULL
;
195 if (up
->sg
.src
.s_addr
!= INADDR_ANY
) {
196 if (pim
->upstream_sg_wheel
)
197 wheel_remove_item(pim
->upstream_sg_wheel
, up
);
201 pim_mroute_del(up
->channel_oil
, __PRETTY_FUNCTION__
);
202 upstream_channel_oil_detach(up
);
204 for (ALL_LIST_ELEMENTS(up
->ifchannels
, node
, nnode
, ch
))
205 pim_ifchannel_delete(ch
);
206 list_delete(&up
->ifchannels
);
208 pim_upstream_remove_children(pim
, up
);
210 list_delete(&up
->sources
);
212 if (up
->parent
&& up
->parent
->sources
)
213 listnode_delete(up
->parent
->sources
, up
);
216 listnode_delete(pim
->upstream_list
, up
);
217 hash_release(pim
->upstream_hash
, up
);
220 pim_msdp_up_del(pim
, &up
->sg
);
223 /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT
224 * and assign up->upstream_addr as INADDR_ANY.
225 * So before de-registering the upstream address, check if is not equal
226 * to INADDR_ANY. This is done in order to avoid de-registering for
227 * 255.255.255.255 which is maintained for some reason..
229 if (up
->upstream_addr
.s_addr
!= INADDR_ANY
) {
230 /* Deregister addr with Zebra NHT */
231 nht_p
.family
= AF_INET
;
232 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
233 nht_p
.u
.prefix4
= up
->upstream_addr
;
234 if (PIM_DEBUG_TRACE
) {
235 char buf
[PREFIX2STR_BUFFER
];
236 prefix2str(&nht_p
, buf
, sizeof(buf
));
237 zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
238 __PRETTY_FUNCTION__
, up
->sg_str
, buf
);
240 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
, false);
243 XFREE(MTYPE_PIM_UPSTREAM
, up
);
248 void pim_upstream_send_join(struct pim_upstream
*up
)
250 if (!up
->rpf
.source_nexthop
.interface
) {
252 zlog_debug("%s: up %s RPF is not present",
253 __PRETTY_FUNCTION__
, up
->sg_str
);
257 if (PIM_DEBUG_TRACE
) {
258 char rpf_str
[PREFIX_STRLEN
];
259 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_str
,
261 zlog_debug("%s: RPF'%s=%s(%s) for Interface %s",
262 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
263 pim_upstream_state2str(up
->join_state
),
264 up
->rpf
.source_nexthop
.interface
->name
);
265 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
266 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
267 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
);
272 /* send Join(S,G) to the current upstream neighbor */
273 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 1 /* join */);
276 static int on_join_timer(struct thread
*t
)
278 struct pim_upstream
*up
;
282 if (!up
->rpf
.source_nexthop
.interface
) {
284 zlog_debug("%s: up %s RPF is not present",
285 __PRETTY_FUNCTION__
, up
->sg_str
);
290 * In the case of a HFR we will not ahve anyone to send this to.
292 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
296 * Don't send the join if the outgoing interface is a loopback
297 * But since this might change leave the join timer running
299 if (up
->rpf
.source_nexthop
300 .interface
&& !if_is_loopback(up
->rpf
.source_nexthop
.interface
))
301 pim_upstream_send_join(up
);
303 join_timer_start(up
);
308 static void join_timer_stop(struct pim_upstream
*up
)
310 struct pim_neighbor
*nbr
= NULL
;
312 THREAD_OFF(up
->t_join_timer
);
314 if (up
->rpf
.source_nexthop
.interface
)
315 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
316 up
->rpf
.rpf_addr
.u
.prefix4
);
319 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
);
321 pim_jp_agg_upstream_verification(up
, false);
324 void join_timer_start(struct pim_upstream
*up
)
326 struct pim_neighbor
*nbr
= NULL
;
328 if (up
->rpf
.source_nexthop
.interface
) {
329 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
330 up
->rpf
.rpf_addr
.u
.prefix4
);
332 if (PIM_DEBUG_PIM_EVENTS
) {
334 "%s: starting %d sec timer for upstream (S,G)=%s",
335 __PRETTY_FUNCTION__
, router
->t_periodic
,
341 pim_jp_agg_add_group(nbr
->upstream_jp_agg
, up
, 1);
343 THREAD_OFF(up
->t_join_timer
);
344 thread_add_timer(router
->master
, on_join_timer
, up
,
345 router
->t_periodic
, &up
->t_join_timer
);
347 pim_jp_agg_upstream_verification(up
, true);
351 * This is only called when we are switching the upstream
352 * J/P from one neighbor to another
354 * As such we need to remove from the old list and
355 * add to the new list.
357 void pim_upstream_join_timer_restart(struct pim_upstream
*up
,
360 // THREAD_OFF(up->t_join_timer);
361 join_timer_start(up
);
364 static void pim_upstream_join_timer_restart_msec(struct pim_upstream
*up
,
367 if (PIM_DEBUG_PIM_EVENTS
) {
368 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
369 __PRETTY_FUNCTION__
, interval_msec
, up
->sg_str
);
372 THREAD_OFF(up
->t_join_timer
);
373 thread_add_timer_msec(router
->master
, on_join_timer
, up
, interval_msec
,
377 void pim_upstream_join_suppress(struct pim_upstream
*up
,
378 struct in_addr rpf_addr
, int holdtime
)
380 long t_joinsuppress_msec
;
381 long join_timer_remain_msec
;
383 if (!up
->rpf
.source_nexthop
.interface
) {
385 zlog_debug("%s: up %s RPF is not present",
386 __PRETTY_FUNCTION__
, up
->sg_str
);
390 t_joinsuppress_msec
=
391 MIN(pim_if_t_suppressed_msec(up
->rpf
.source_nexthop
.interface
),
394 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
396 if (PIM_DEBUG_TRACE
) {
397 char rpf_str
[INET_ADDRSTRLEN
];
398 pim_inet4_dump("<rpf?>", rpf_addr
, rpf_str
, sizeof(rpf_str
));
400 "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
401 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
402 join_timer_remain_msec
, t_joinsuppress_msec
);
405 if (join_timer_remain_msec
< t_joinsuppress_msec
) {
406 if (PIM_DEBUG_TRACE
) {
408 "%s %s: suppressing Join(S,G)=%s for %ld msec",
409 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
,
410 t_joinsuppress_msec
);
413 pim_upstream_join_timer_restart_msec(up
, t_joinsuppress_msec
);
417 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label
,
418 struct pim_upstream
*up
)
420 long join_timer_remain_msec
;
423 if (!up
->rpf
.source_nexthop
.interface
) {
425 zlog_debug("%s: up %s RPF is not present",
426 __PRETTY_FUNCTION__
, up
->sg_str
);
430 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
432 pim_if_t_override_msec(up
->rpf
.source_nexthop
.interface
);
434 if (PIM_DEBUG_TRACE
) {
435 char rpf_str
[INET_ADDRSTRLEN
];
436 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
.u
.prefix4
, rpf_str
,
439 "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
440 debug_label
, up
->sg_str
, rpf_str
,
441 join_timer_remain_msec
, t_override_msec
);
444 if (join_timer_remain_msec
> t_override_msec
) {
445 if (PIM_DEBUG_TRACE
) {
447 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
448 debug_label
, up
->sg_str
, t_override_msec
);
451 pim_upstream_join_timer_restart_msec(up
, t_override_msec
);
455 static void forward_on(struct pim_upstream
*up
)
457 struct listnode
*chnode
;
458 struct listnode
*chnextnode
;
459 struct pim_ifchannel
*ch
= NULL
;
461 /* scan (S,G) state */
462 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
463 if (pim_macro_chisin_oiflist(ch
))
464 pim_forward_start(ch
);
466 } /* scan iface channel list */
469 static void forward_off(struct pim_upstream
*up
)
471 struct listnode
*chnode
;
472 struct listnode
*chnextnode
;
473 struct pim_ifchannel
*ch
;
475 /* scan per-interface (S,G) state */
476 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
478 pim_forward_stop(ch
, false);
480 } /* scan iface channel list */
483 static int pim_upstream_could_register(struct pim_upstream
*up
)
485 struct pim_interface
*pim_ifp
= NULL
;
487 /* FORCE_PIMREG is a generic flag to let an app like VxLAN-AA register
488 * a source on an upstream entry even if the source is not directly
489 * connected on the IIF.
491 if (PIM_UPSTREAM_FLAG_TEST_FORCE_PIMREG(up
->flags
))
494 if (up
->rpf
.source_nexthop
.interface
)
495 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
498 zlog_debug("%s: up %s RPF is not present",
499 __PRETTY_FUNCTION__
, up
->sg_str
);
502 if (pim_ifp
&& PIM_I_am_DR(pim_ifp
)
503 && pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
510 /* Source registration is suppressed for SSM groups. When the SSM range changes
511 * we re-revaluate register setup for existing upstream entries */
512 void pim_upstream_register_reevaluate(struct pim_instance
*pim
)
514 struct listnode
*upnode
;
515 struct pim_upstream
*up
;
517 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
518 /* If FHR is set CouldRegister is True. Also check if the flow
519 * is actually active; if it is not kat setup will trigger
521 * registration whenever the flow becomes active. */
522 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) || !up
->t_ka_timer
)
525 if (pim_is_grp_ssm(pim
, up
->sg
.grp
)) {
526 /* clear the register state for SSM groups */
527 if (up
->reg_state
!= PIM_REG_NOINFO
) {
528 if (PIM_DEBUG_PIM_EVENTS
)
530 "Clear register for %s as G is now SSM",
532 /* remove regiface from the OIL if it is there*/
533 pim_channel_del_oif(up
->channel_oil
,
535 PIM_OIF_FLAG_PROTO_PIM
);
536 up
->reg_state
= PIM_REG_NOINFO
;
539 /* register ASM sources with the RP */
540 if (up
->reg_state
== PIM_REG_NOINFO
) {
541 if (PIM_DEBUG_PIM_EVENTS
)
543 "Register %s as G is now ASM",
545 pim_channel_add_oif(up
->channel_oil
,
547 PIM_OIF_FLAG_PROTO_PIM
);
548 up
->reg_state
= PIM_REG_JOIN
;
554 void pim_upstream_switch(struct pim_instance
*pim
, struct pim_upstream
*up
,
555 enum pim_upstream_state new_state
)
557 enum pim_upstream_state old_state
= up
->join_state
;
559 if (up
->upstream_addr
.s_addr
== INADDR_ANY
) {
560 if (PIM_DEBUG_PIM_EVENTS
)
561 zlog_debug("%s: RPF not configured for %s",
562 __PRETTY_FUNCTION__
, up
->sg_str
);
566 if (!up
->rpf
.source_nexthop
.interface
) {
567 if (PIM_DEBUG_PIM_EVENTS
)
568 zlog_debug("%s: RP not reachable for %s",
569 __PRETTY_FUNCTION__
, up
->sg_str
);
573 if (PIM_DEBUG_PIM_EVENTS
) {
574 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
575 __PRETTY_FUNCTION__
, up
->sg_str
,
576 pim_upstream_state2str(up
->join_state
),
577 pim_upstream_state2str(new_state
));
580 up
->join_state
= new_state
;
581 if (old_state
!= new_state
)
582 up
->state_transition
= pim_time_monotonic_sec();
584 pim_upstream_update_assert_tracking_desired(up
);
586 if (new_state
== PIM_UPSTREAM_JOINED
) {
587 pim_upstream_inherited_olist_decide(pim
, up
);
588 if (old_state
!= PIM_UPSTREAM_JOINED
) {
589 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
591 pim_msdp_up_join_state_changed(pim
, up
);
592 if (pim_upstream_could_register(up
)) {
593 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
595 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
597 pim_upstream_keep_alive_timer_start(
598 up
, pim
->keep_alive_time
);
599 pim_register_join(up
);
602 pim_upstream_send_join(up
);
603 join_timer_start(up
);
609 if (old_state
== PIM_UPSTREAM_JOINED
)
610 pim_msdp_up_join_state_changed(pim
, up
);
612 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
614 If I am RP for G then send S,G prune to its IIF. */
615 if (pim_upstream_is_sg_rpt(up
) && up
->parent
616 && !I_am_RP(pim
, up
->sg
.grp
)) {
617 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
619 "%s: *,G IIF %s S,G IIF %s ",
621 up
->parent
->rpf
.source_nexthop
.interface
?
622 up
->parent
->rpf
.source_nexthop
.interface
->name
624 up
->rpf
.source_nexthop
.interface
?
625 up
->rpf
.source_nexthop
.interface
->name
:
627 pim_jp_agg_single_upstream_send(&up
->parent
->rpf
,
631 pim_jp_agg_single_upstream_send(&up
->rpf
, up
,
637 int pim_upstream_compare(void *arg1
, void *arg2
)
639 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
640 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
642 if (ntohl(up1
->sg
.grp
.s_addr
) < ntohl(up2
->sg
.grp
.s_addr
))
645 if (ntohl(up1
->sg
.grp
.s_addr
) > ntohl(up2
->sg
.grp
.s_addr
))
648 if (ntohl(up1
->sg
.src
.s_addr
) < ntohl(up2
->sg
.src
.s_addr
))
651 if (ntohl(up1
->sg
.src
.s_addr
) > ntohl(up2
->sg
.src
.s_addr
))
657 void pim_upstream_fill_static_iif(struct pim_upstream
*up
,
658 struct interface
*incoming
)
660 up
->rpf
.source_nexthop
.interface
= incoming
;
662 /* reset other parameters to matched a connected incoming interface */
663 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
664 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
666 up
->rpf
.source_nexthop
.mrib_metric_preference
=
667 ZEBRA_CONNECT_DISTANCE_DEFAULT
;
668 up
->rpf
.source_nexthop
.mrib_route_metric
= 0;
669 up
->rpf
.rpf_addr
.family
= AF_INET
;
670 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
674 static struct pim_upstream
*pim_upstream_new(struct pim_instance
*pim
,
675 struct prefix_sg
*sg
,
676 struct interface
*incoming
,
678 struct pim_ifchannel
*ch
)
680 enum pim_rpf_result rpf_result
;
681 struct pim_interface
*pim_ifp
;
682 struct pim_upstream
*up
;
684 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
687 pim_str_sg_set(sg
, up
->sg_str
);
691 up
= hash_get(pim
->upstream_hash
, up
, hash_alloc_intern
);
692 /* Set up->upstream_addr as INADDR_ANY, if RP is not
693 * configured and retain the upstream data structure
695 if (!pim_rp_set_upstream_addr(pim
, &up
->upstream_addr
, sg
->src
,
698 zlog_debug("%s: Received a (*,G) with no RP configured",
699 __PRETTY_FUNCTION__
);
702 up
->parent
= pim_upstream_find_parent(pim
, up
);
703 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
704 up
->sources
= list_new();
705 up
->sources
->cmp
= pim_upstream_compare
;
709 pim_upstream_find_new_children(pim
, up
);
712 up
->t_join_timer
= NULL
;
713 up
->t_ka_timer
= NULL
;
714 up
->t_rs_timer
= NULL
;
715 up
->t_msdp_reg_timer
= NULL
;
716 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
717 up
->reg_state
= PIM_REG_NOINFO
;
718 up
->state_transition
= pim_time_monotonic_sec();
719 up
->channel_oil
= NULL
;
720 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
722 up
->rpf
.source_nexthop
.interface
= NULL
;
723 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
724 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
726 up
->rpf
.source_nexthop
.mrib_metric_preference
=
727 router
->infinite_assert_metric
.metric_preference
;
728 up
->rpf
.source_nexthop
.mrib_route_metric
=
729 router
->infinite_assert_metric
.route_metric
;
730 up
->rpf
.rpf_addr
.family
= AF_INET
;
731 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
733 up
->ifchannels
= list_new();
734 up
->ifchannels
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
736 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
737 wheel_add_item(pim
->upstream_sg_wheel
, up
);
739 if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up
->flags
)) {
740 pim_upstream_fill_static_iif(up
, incoming
);
741 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
743 up
->channel_oil
= pim_channel_oil_add(pim
, &up
->sg
,
744 pim_ifp
->mroute_vif_index
,
745 __PRETTY_FUNCTION__
);
746 } else if (up
->upstream_addr
.s_addr
== INADDR_ANY
) {
747 /* Create a dummmy channel oil with incoming ineterface MAXVIFS,
748 * since RP is not configured
750 up
->channel_oil
= pim_channel_oil_add(pim
, &up
->sg
, MAXVIFS
,
751 __PRETTY_FUNCTION__
);
754 rpf_result
= pim_rpf_update(pim
, up
, NULL
);
755 if (rpf_result
== PIM_RPF_FAILURE
) {
758 "%s: Attempting to create upstream(%s), Unable to RPF for source",
759 __PRETTY_FUNCTION__
, up
->sg_str
);
760 /* Create a dummmy channel oil with incoming ineterface
761 * MAXVIFS, since RP is not reachable
763 up
->channel_oil
= pim_channel_oil_add(
764 pim
, &up
->sg
, MAXVIFS
, __PRETTY_FUNCTION__
);
767 if (up
->rpf
.source_nexthop
.interface
) {
768 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
770 up
->channel_oil
= pim_channel_oil_add(
771 pim
, &up
->sg
, pim_ifp
->mroute_vif_index
,
772 __PRETTY_FUNCTION__
);
776 listnode_add_sort(pim
->upstream_list
, up
);
778 if (PIM_DEBUG_TRACE
) {
780 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
781 __PRETTY_FUNCTION__
, up
->sg_str
,
782 inet_ntoa(up
->upstream_addr
), up
->ref_count
);
788 struct pim_upstream
*pim_upstream_find(struct pim_instance
*pim
,
789 struct prefix_sg
*sg
)
791 struct pim_upstream lookup
;
792 struct pim_upstream
*up
= NULL
;
795 up
= hash_lookup(pim
->upstream_hash
, &lookup
);
799 struct pim_upstream
*pim_upstream_find_or_add(struct prefix_sg
*sg
,
800 struct interface
*incoming
,
801 int flags
, const char *name
)
803 struct pim_upstream
*up
;
804 struct pim_interface
*pim_ifp
;
806 pim_ifp
= incoming
->info
;
808 up
= pim_upstream_find(pim_ifp
->pim
, sg
);
811 if (!(up
->flags
& flags
)) {
816 "%s(%s): upstream %s ref count %d increment",
817 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
821 up
= pim_upstream_add(pim_ifp
->pim
, sg
, incoming
, flags
, name
,
827 void pim_upstream_ref(struct pim_upstream
*up
, int flags
, const char *name
)
832 zlog_debug("%s(%s): upstream %s ref count %d increment",
833 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
837 struct pim_upstream
*pim_upstream_add(struct pim_instance
*pim
,
838 struct prefix_sg
*sg
,
839 struct interface
*incoming
, int flags
,
841 struct pim_ifchannel
*ch
)
843 struct pim_upstream
*up
= NULL
;
846 up
= pim_upstream_find(pim
, sg
);
848 pim_upstream_ref(up
, flags
, name
);
851 up
= pim_upstream_new(pim
, sg
, incoming
, flags
, ch
);
854 if (PIM_DEBUG_TRACE
) {
856 char buf
[PREFIX2STR_BUFFER
];
857 prefix2str(&up
->rpf
.rpf_addr
, buf
, sizeof(buf
));
858 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
859 __PRETTY_FUNCTION__
, name
,
860 up
->sg_str
, buf
, up
->rpf
.source_nexthop
.interface
?
861 up
->rpf
.source_nexthop
.interface
->name
: "Unknown" ,
862 found
, up
->ref_count
);
864 zlog_debug("%s(%s): (%s) failure to create",
865 __PRETTY_FUNCTION__
, name
,
866 pim_str_sg_dump(sg
));
873 * Passed in up must be the upstream for ch. starch is NULL if no
876 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream
*up
,
877 struct pim_ifchannel
*ch
,
878 struct pim_ifchannel
*starch
)
881 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
884 if (!pim_macro_ch_lost_assert(ch
)
885 && pim_macro_chisin_joins_or_include(ch
))
893 if (PIM_IF_FLAG_TEST_S_G_RPT(starch
->upstream
->flags
))
896 if (!pim_macro_ch_lost_assert(starch
)
897 && pim_macro_chisin_joins_or_include(starch
))
905 Evaluate JoinDesired(S,G):
907 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
910 inherited_olist(S,G) =
911 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
913 JoinDesired(S,G) may be affected by changes in the following:
915 pim_ifp->primary_address
917 ch->ifassert_winner_metric
919 ch->local_ifmembership
921 ch->upstream->rpf.source_nexthop.mrib_metric_preference
922 ch->upstream->rpf.source_nexthop.mrib_route_metric
923 ch->upstream->rpf.source_nexthop.interface
925 See also pim_upstream_update_join_desired() below.
927 int pim_upstream_evaluate_join_desired(struct pim_instance
*pim
,
928 struct pim_upstream
*up
)
930 struct interface
*ifp
;
931 struct pim_ifchannel
*ch
, *starch
;
932 struct pim_upstream
*starup
= up
->parent
;
935 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
939 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
942 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
949 ret
+= pim_upstream_evaluate_join_desired_interface(up
, ch
,
951 } /* scan iface channel list */
953 return ret
; /* false */
957 See also pim_upstream_evaluate_join_desired() above.
959 void pim_upstream_update_join_desired(struct pim_instance
*pim
,
960 struct pim_upstream
*up
)
962 int was_join_desired
; /* boolean */
963 int is_join_desired
; /* boolean */
965 was_join_desired
= PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up
->flags
);
967 is_join_desired
= pim_upstream_evaluate_join_desired(pim
, up
);
969 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up
->flags
);
971 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up
->flags
);
973 /* switched from false to true */
974 if (is_join_desired
&& (up
->join_state
== PIM_UPSTREAM_NOTJOINED
)) {
975 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
979 /* switched from true to false */
980 if (!is_join_desired
&& was_join_desired
) {
981 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_NOTJOINED
);
987 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
988 Transitions from Joined State
989 RPF'(S,G) GenID changes
991 The upstream (S,G) state machine remains in Joined state. If the
992 Join Timer is set to expire in more than t_override seconds, reset
993 it so that it expires after t_override seconds.
995 void pim_upstream_rpf_genid_changed(struct pim_instance
*pim
,
996 struct in_addr neigh_addr
)
998 struct listnode
*up_node
;
999 struct listnode
*up_nextnode
;
1000 struct pim_upstream
*up
;
1003 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1005 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
1007 if (PIM_DEBUG_TRACE
) {
1008 char neigh_str
[INET_ADDRSTRLEN
];
1009 char rpf_addr_str
[PREFIX_STRLEN
];
1010 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
,
1012 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_addr_str
,
1013 sizeof(rpf_addr_str
));
1015 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
1016 __PRETTY_FUNCTION__
, neigh_str
, up
->sg_str
,
1018 up
->join_state
== PIM_UPSTREAM_JOINED
,
1022 /* consider only (S,G) upstream in Joined state */
1023 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
1026 /* match RPF'(S,G)=neigh_addr */
1027 if (up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
!= neigh_addr
.s_addr
)
1030 pim_upstream_join_timer_decrease_to_t_override(
1031 "RPF'(S,G) GenID change", up
);
1036 void pim_upstream_rpf_interface_changed(struct pim_upstream
*up
,
1037 struct interface
*old_rpf_ifp
)
1039 struct listnode
*chnode
;
1040 struct listnode
*chnextnode
;
1041 struct pim_ifchannel
*ch
;
1043 /* search all ifchannels */
1044 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1045 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
1047 /* RPF_interface(S) was NOT I */
1048 (old_rpf_ifp
== ch
->interface
) &&
1049 /* RPF_interface(S) stopped being I */
1050 (ch
->upstream
->rpf
.source_nexthop
1052 (ch
->upstream
->rpf
.source_nexthop
1053 .interface
!= ch
->interface
)) {
1054 assert_action_a5(ch
);
1056 } /* PIM_IFASSERT_I_AM_LOSER */
1058 pim_ifchannel_update_assert_tracking_desired(ch
);
1062 void pim_upstream_update_could_assert(struct pim_upstream
*up
)
1064 struct listnode
*chnode
;
1065 struct listnode
*chnextnode
;
1066 struct pim_ifchannel
*ch
;
1068 /* scan per-interface (S,G) state */
1069 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1070 pim_ifchannel_update_could_assert(ch
);
1071 } /* scan iface channel list */
1074 void pim_upstream_update_my_assert_metric(struct pim_upstream
*up
)
1076 struct listnode
*chnode
;
1077 struct listnode
*chnextnode
;
1078 struct pim_ifchannel
*ch
;
1080 /* scan per-interface (S,G) state */
1081 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1082 pim_ifchannel_update_my_assert_metric(ch
);
1084 } /* scan iface channel list */
1087 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
)
1089 struct listnode
*chnode
;
1090 struct listnode
*chnextnode
;
1091 struct pim_interface
*pim_ifp
;
1092 struct pim_ifchannel
*ch
;
1094 /* scan per-interface (S,G) state */
1095 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1098 pim_ifp
= ch
->interface
->info
;
1102 pim_ifchannel_update_assert_tracking_desired(ch
);
1104 } /* scan iface channel list */
1107 /* When kat is stopped CouldRegister goes to false so we need to
1108 * transition the (S, G) on FHR to NI state and remove reg tunnel
1110 static void pim_upstream_fhr_kat_expiry(struct pim_instance
*pim
,
1111 struct pim_upstream
*up
)
1113 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
1116 if (PIM_DEBUG_TRACE
)
1117 zlog_debug("kat expired on %s; clear fhr reg state",
1120 /* stop reg-stop timer */
1121 THREAD_OFF(up
->t_rs_timer
);
1122 /* remove regiface from the OIL if it is there*/
1123 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1124 PIM_OIF_FLAG_PROTO_PIM
);
1125 /* clear the register state */
1126 up
->reg_state
= PIM_REG_NOINFO
;
1127 PIM_UPSTREAM_FLAG_UNSET_FHR(up
->flags
);
1130 /* When kat is started CouldRegister can go to true. And if it does we
1131 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1133 static void pim_upstream_fhr_kat_start(struct pim_upstream
*up
)
1135 if (pim_upstream_could_register(up
)) {
1136 if (PIM_DEBUG_TRACE
)
1138 "kat started on %s; set fhr reg state to joined",
1141 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1142 if (up
->reg_state
== PIM_REG_NOINFO
)
1143 pim_register_join(up
);
1148 * On an RP, the PMBR value must be cleared when the
1149 * Keepalive Timer expires
1150 * KAT expiry indicates that flow is inactive. If the flow was created or
1151 * maintained by activity now is the time to deref it.
1153 struct pim_upstream
*pim_upstream_keep_alive_timer_proc(
1154 struct pim_upstream
*up
)
1156 struct pim_instance
*pim
;
1158 pim
= up
->channel_oil
->pim
;
1160 if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up
->flags
)) {
1161 /* if the router is a PIM vxlan encapsulator we prevent expiry
1162 * of KAT as the mroute is pre-setup without any traffic
1164 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1168 if (I_am_RP(pim
, up
->sg
.grp
)) {
1169 pim_br_clear_pmbr(&up
->sg
);
1171 * We need to do more here :)
1172 * But this is the start.
1176 /* source is no longer active - pull the SA from MSDP's cache */
1177 pim_msdp_sa_local_del(pim
, &up
->sg
);
1179 /* if entry was created because of activity we need to deref it */
1180 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1181 pim_upstream_fhr_kat_expiry(pim
, up
);
1182 if (PIM_DEBUG_TRACE
)
1184 "kat expired on %s[%s]; remove stream reference",
1185 up
->sg_str
, pim
->vrf
->name
);
1186 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up
->flags
);
1188 /* Return if upstream entry got deleted.*/
1189 if (!pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
))
1192 /* upstream reference would have been added to track the local
1193 * membership if it is LHR. We have to clear it when KAT expires.
1194 * Otherwise would result in stale entry with uncleared ref count.
1196 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
1197 struct pim_upstream
*parent
= up
->parent
;
1199 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1200 up
= pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1203 pim_jp_agg_single_upstream_send(&parent
->rpf
, parent
,
1210 static int pim_upstream_keep_alive_timer(struct thread
*t
)
1212 struct pim_upstream
*up
;
1216 pim_upstream_keep_alive_timer_proc(up
);
1220 void pim_upstream_keep_alive_timer_start(struct pim_upstream
*up
, uint32_t time
)
1222 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1223 if (PIM_DEBUG_TRACE
)
1224 zlog_debug("kat start on %s with no stream reference",
1227 THREAD_OFF(up
->t_ka_timer
);
1228 thread_add_timer(router
->master
, pim_upstream_keep_alive_timer
, up
,
1229 time
, &up
->t_ka_timer
);
1231 /* any time keepalive is started against a SG we will have to
1232 * re-evaluate our active source database */
1233 pim_msdp_sa_local_update(up
);
1236 /* MSDP on RP needs to know if a source is registerable to this RP */
1237 static int pim_upstream_msdp_reg_timer(struct thread
*t
)
1239 struct pim_upstream
*up
= THREAD_ARG(t
);
1240 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1242 /* source is no longer active - pull the SA from MSDP's cache */
1243 pim_msdp_sa_local_del(pim
, &up
->sg
);
1246 void pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1248 THREAD_OFF(up
->t_msdp_reg_timer
);
1249 thread_add_timer(router
->master
, pim_upstream_msdp_reg_timer
, up
,
1250 PIM_MSDP_REG_RXED_PERIOD
, &up
->t_msdp_reg_timer
);
1252 pim_msdp_sa_local_update(up
);
1256 * 4.2.1 Last-Hop Switchover to the SPT
1258 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1259 * RP. Once traffic from sources to joined groups arrives at a last-hop
1260 * router, it has the option of switching to receive the traffic on a
1261 * shortest path tree (SPT).
1263 * The decision for a router to switch to the SPT is controlled as
1267 * CheckSwitchToSpt(S,G) {
1268 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1269 * (+) pim_include(S,G) != NULL )
1270 * AND SwitchToSptDesired(S,G) ) {
1271 * # Note: Restarting the KAT will result in the SPT switch
1272 * set KeepaliveTimer(S,G) to Keepalive_Period
1276 * SwitchToSptDesired(S,G) is a policy function that is implementation
1277 * defined. An "infinite threshold" policy can be implemented by making
1278 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1279 * first packet" policy can be implemented by making
1280 * SwitchToSptDesired(S,G) return true once a single packet has been
1281 * received for the source and group.
1283 int pim_upstream_switch_to_spt_desired(struct pim_instance
*pim
,
1284 struct prefix_sg
*sg
)
1286 if (I_am_RP(pim
, sg
->grp
))
1292 int pim_upstream_is_sg_rpt(struct pim_upstream
*up
)
1294 struct listnode
*chnode
;
1295 struct pim_ifchannel
*ch
;
1297 for (ALL_LIST_ELEMENTS_RO(up
->ifchannels
, chnode
, ch
)) {
1298 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1305 * After receiving a packet set SPTbit:
1307 * Update_SPTbit(S,G,iif) {
1308 * if ( iif == RPF_interface(S)
1309 * AND JoinDesired(S,G) == TRUE
1310 * AND ( DirectlyConnected(S) == TRUE
1311 * OR RPF_interface(S) != RPF_interface(RP(G))
1312 * OR inherited_olist(S,G,rpt) == NULL
1313 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1314 * ( RPF'(S,G) != NULL ) )
1315 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1316 * Set SPTbit(S,G) to TRUE
1320 void pim_upstream_set_sptbit(struct pim_upstream
*up
,
1321 struct interface
*incoming
)
1323 struct pim_upstream
*starup
= up
->parent
;
1325 // iif == RPF_interfvace(S)
1326 if (up
->rpf
.source_nexthop
.interface
!= incoming
) {
1327 if (PIM_DEBUG_TRACE
)
1329 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1330 __PRETTY_FUNCTION__
, incoming
->name
,
1331 up
->rpf
.source_nexthop
.interface
->name
);
1335 // AND JoinDesired(S,G) == TRUE
1336 if (!pim_upstream_evaluate_join_desired(up
->channel_oil
->pim
, up
)) {
1337 if (PIM_DEBUG_TRACE
)
1338 zlog_debug("%s: %s Join is not Desired",
1339 __PRETTY_FUNCTION__
, up
->sg_str
);
1343 // DirectlyConnected(S) == TRUE
1344 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1346 if (PIM_DEBUG_TRACE
)
1347 zlog_debug("%s: %s is directly connected to the source",
1348 __PRETTY_FUNCTION__
, up
->sg_str
);
1349 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1353 // OR RPF_interface(S) != RPF_interface(RP(G))
1355 || up
->rpf
.source_nexthop
1356 .interface
!= starup
->rpf
.source_nexthop
.interface
) {
1357 struct pim_upstream
*starup
= up
->parent
;
1359 if (PIM_DEBUG_TRACE
)
1361 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1362 __PRETTY_FUNCTION__
, up
->sg_str
);
1363 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1365 pim_jp_agg_single_upstream_send(&starup
->rpf
, starup
, true);
1369 // OR inherited_olist(S,G,rpt) == NULL
1370 if (pim_upstream_is_sg_rpt(up
)
1371 && pim_upstream_empty_inherited_olist(up
)) {
1372 if (PIM_DEBUG_TRACE
)
1373 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1374 __PRETTY_FUNCTION__
, up
->sg_str
);
1375 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1379 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1380 // ( RPF'(S,G) != NULL ) )
1381 if (up
->parent
&& pim_rpf_is_same(&up
->rpf
, &up
->parent
->rpf
)) {
1382 if (PIM_DEBUG_TRACE
)
1383 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1384 __PRETTY_FUNCTION__
, up
->sg_str
);
1385 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1392 const char *pim_upstream_state2str(enum pim_upstream_state join_state
)
1394 switch (join_state
) {
1395 case PIM_UPSTREAM_NOTJOINED
:
1398 case PIM_UPSTREAM_JOINED
:
1405 const char *pim_reg_state2str(enum pim_reg_state reg_state
, char *state_str
,
1406 size_t state_str_len
)
1408 switch (reg_state
) {
1409 case PIM_REG_NOINFO
:
1410 strlcpy(state_str
, "RegNoInfo", state_str_len
);
1413 strlcpy(state_str
, "RegJoined", state_str_len
);
1415 case PIM_REG_JOIN_PENDING
:
1416 strlcpy(state_str
, "RegJoinPend", state_str_len
);
1419 strlcpy(state_str
, "RegPrune", state_str_len
);
1422 strlcpy(state_str
, "RegUnknown", state_str_len
);
1427 static int pim_upstream_register_stop_timer(struct thread
*t
)
1429 struct pim_interface
*pim_ifp
;
1430 struct pim_instance
*pim
;
1431 struct pim_upstream
*up
;
1433 pim
= up
->channel_oil
->pim
;
1435 if (PIM_DEBUG_TRACE
) {
1436 char state_str
[PIM_REG_STATE_STR_LEN
];
1437 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1438 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
1439 pim_reg_state2str(up
->reg_state
, state_str
, sizeof(state_str
)));
1442 switch (up
->reg_state
) {
1443 case PIM_REG_JOIN_PENDING
:
1444 up
->reg_state
= PIM_REG_JOIN
;
1445 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1446 PIM_OIF_FLAG_PROTO_PIM
);
1447 pim_vxlan_update_sg_reg_state(pim
, up
, TRUE
/*reg_join*/);
1452 if (!up
->rpf
.source_nexthop
.interface
) {
1453 if (PIM_DEBUG_TRACE
)
1454 zlog_debug("%s: up %s RPF is not present",
1455 __PRETTY_FUNCTION__
, up
->sg_str
);
1459 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1461 if (PIM_DEBUG_TRACE
)
1463 "%s: Interface: %s is not configured for pim",
1464 __PRETTY_FUNCTION__
,
1465 up
->rpf
.source_nexthop
.interface
->name
);
1468 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1469 pim_upstream_start_register_stop_timer(up
, 1);
1471 if (((up
->channel_oil
->cc
.lastused
/ 100)
1472 > pim
->keep_alive_time
)
1473 && (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
))) {
1474 if (PIM_DEBUG_TRACE
)
1476 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1477 __PRETTY_FUNCTION__
);
1480 pim_null_register_send(up
);
1489 void pim_upstream_start_register_stop_timer(struct pim_upstream
*up
,
1494 THREAD_TIMER_OFF(up
->t_rs_timer
);
1496 if (!null_register
) {
1497 uint32_t lower
= (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1498 uint32_t upper
= (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1499 time
= lower
+ (random() % (upper
- lower
+ 1))
1500 - PIM_REGISTER_PROBE_PERIOD
;
1502 time
= PIM_REGISTER_PROBE_PERIOD
;
1504 if (PIM_DEBUG_TRACE
) {
1506 "%s: (S,G)=%s Starting upstream register stop timer %d",
1507 __PRETTY_FUNCTION__
, up
->sg_str
, time
);
1509 thread_add_timer(router
->master
, pim_upstream_register_stop_timer
, up
,
1510 time
, &up
->t_rs_timer
);
1513 int pim_upstream_inherited_olist_decide(struct pim_instance
*pim
,
1514 struct pim_upstream
*up
)
1516 struct interface
*ifp
;
1517 struct pim_interface
*pim_ifp
= NULL
;
1518 struct pim_ifchannel
*ch
, *starch
;
1519 struct pim_upstream
*starup
= up
->parent
;
1520 int output_intf
= 0;
1522 if (up
->rpf
.source_nexthop
.interface
)
1523 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1525 if (PIM_DEBUG_TRACE
)
1526 zlog_debug("%s: up %s RPF is not present",
1527 __PRETTY_FUNCTION__
, up
->sg_str
);
1529 if (pim_ifp
&& !up
->channel_oil
)
1530 up
->channel_oil
= pim_channel_oil_add(pim
, &up
->sg
,
1531 pim_ifp
->mroute_vif_index
,
1532 __PRETTY_FUNCTION__
);
1534 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1538 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1541 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
1548 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1550 int flag
= PIM_OIF_FLAG_PROTO_PIM
;
1553 flag
= PIM_OIF_FLAG_PROTO_STAR
;
1555 pim_channel_add_oif(up
->channel_oil
, ifp
, flag
);
1564 * For a given upstream, determine the inherited_olist
1567 * inherited_olist(S,G,rpt) =
1568 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1569 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1570 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1572 * inherited_olist(S,G) =
1573 * inherited_olist(S,G,rpt) (+)
1574 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1576 * return 1 if there are any output interfaces
1577 * return 0 if there are not any output interfaces
1579 int pim_upstream_inherited_olist(struct pim_instance
*pim
,
1580 struct pim_upstream
*up
)
1582 int output_intf
= pim_upstream_inherited_olist_decide(pim
, up
);
1585 * If we have output_intf switch state to Join and work like normal
1586 * If we don't have an output_intf that means we are probably a
1587 * switch on a stick so turn on forwarding to just accept the
1588 * incoming packets so we don't bother the other stuff!
1591 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
1598 int pim_upstream_empty_inherited_olist(struct pim_upstream
*up
)
1600 return pim_channel_oil_empty(up
->channel_oil
);
1604 * When we have a new neighbor,
1605 * find upstreams that don't have their rpf_addr
1606 * set and see if the new neighbor allows
1607 * the join to be sent
1609 void pim_upstream_find_new_rpf(struct pim_instance
*pim
)
1611 struct listnode
*up_node
;
1612 struct listnode
*up_nextnode
;
1613 struct pim_upstream
*up
;
1616 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1618 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
1619 if (up
->upstream_addr
.s_addr
== INADDR_ANY
) {
1620 if (PIM_DEBUG_TRACE
)
1622 "%s: RP not configured for Upstream %s",
1623 __PRETTY_FUNCTION__
, up
->sg_str
);
1627 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
1628 if (PIM_DEBUG_TRACE
)
1630 "%s: Upstream %s without a path to send join, checking",
1631 __PRETTY_FUNCTION__
, up
->sg_str
);
1632 pim_rpf_update(pim
, up
, NULL
);
1637 unsigned int pim_upstream_hash_key(const void *arg
)
1639 const struct pim_upstream
*up
= arg
;
1641 return jhash_2words(up
->sg
.src
.s_addr
, up
->sg
.grp
.s_addr
, 0);
1644 void pim_upstream_terminate(struct pim_instance
*pim
)
1646 struct pim_upstream
*up
;
1648 if (pim
->upstream_list
) {
1649 while (pim
->upstream_list
->count
) {
1650 up
= listnode_head(pim
->upstream_list
);
1651 pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1654 list_delete(&pim
->upstream_list
);
1657 if (pim
->upstream_hash
)
1658 hash_free(pim
->upstream_hash
);
1659 pim
->upstream_hash
= NULL
;
1661 if (pim
->upstream_sg_wheel
)
1662 wheel_delete(pim
->upstream_sg_wheel
);
1663 pim
->upstream_sg_wheel
= NULL
;
1666 bool pim_upstream_equal(const void *arg1
, const void *arg2
)
1668 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1669 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1671 if ((up1
->sg
.grp
.s_addr
== up2
->sg
.grp
.s_addr
)
1672 && (up1
->sg
.src
.s_addr
== up2
->sg
.src
.s_addr
))
1678 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1679 * the cases where kat has to be restarted on rxing traffic -
1681 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1682 * set KeepaliveTimer(S,G) to Keepalive_Period
1683 * # Note: a register state transition or UpstreamJPState(S,G)
1684 * # transition may happen as a result of restarting
1685 * # KeepaliveTimer, and must be dealt with here.
1687 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1688 * inherited_olist(S,G) != NULL ) {
1689 * set KeepaliveTimer(S,G) to Keepalive_Period
1692 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1694 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1696 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1697 * so we will skip that here */
1698 if (up
->rpf
.source_nexthop
.interface
&&
1699 pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1704 if ((up
->join_state
== PIM_UPSTREAM_JOINED
)
1705 && !pim_upstream_empty_inherited_olist(up
)) {
1706 /* XXX: I have added this RP check just for 3.2 and it's a
1708 * what rfc-4601 says. Till now we were only running KAT on FHR
1710 * there is some angst around making the change to run it all
1712 * maintain the (S, G) state. This is tracked via CM-13601 and
1714 * removed to handle spt turn-arounds correctly in a 3-tier clos
1716 if (I_am_RP(pim
, up
->sg
.grp
))
1724 * Code to check and see if we've received packets on a S,G mroute
1725 * and if so to set the SPT bit appropriately
1727 static void pim_upstream_sg_running(void *arg
)
1729 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1730 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1732 // No packet can have arrived here if this is the case
1733 if (!up
->channel_oil
->installed
) {
1734 if (PIM_DEBUG_TRACE
)
1735 zlog_debug("%s: %s%s is not installed in mroute",
1736 __PRETTY_FUNCTION__
, up
->sg_str
,
1742 * This is a bit of a hack
1743 * We've noted that we should rescan but
1744 * we've missed the window for doing so in
1745 * pim_zebra.c for some reason. I am
1746 * only doing this at this point in time
1747 * to get us up and working for the moment
1749 if (up
->channel_oil
->oil_inherited_rescan
) {
1750 if (PIM_DEBUG_TRACE
)
1752 "%s: Handling unscanned inherited_olist for %s[%s]",
1753 __PRETTY_FUNCTION__
, up
->sg_str
,
1755 pim_upstream_inherited_olist_decide(pim
, up
);
1756 up
->channel_oil
->oil_inherited_rescan
= 0;
1758 pim_mroute_update_counters(up
->channel_oil
);
1760 // Have we seen packets?
1761 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
)
1762 && (up
->channel_oil
->cc
.lastused
/ 100 > 30)) {
1763 if (PIM_DEBUG_TRACE
) {
1765 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1766 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
1767 up
->channel_oil
->cc
.oldpktcnt
,
1768 up
->channel_oil
->cc
.pktcnt
,
1769 up
->channel_oil
->cc
.lastused
/ 100);
1774 if (pim_upstream_kat_start_ok(up
)) {
1775 /* Add a source reference to the stream if
1776 * one doesn't already exist */
1777 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1778 if (PIM_DEBUG_TRACE
)
1780 "source reference created on kat restart %s[%s]",
1781 up
->sg_str
, pim
->vrf
->name
);
1783 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
,
1784 __PRETTY_FUNCTION__
);
1785 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
1786 pim_upstream_fhr_kat_start(up
);
1788 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1789 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
))
1790 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1792 if ((up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
) &&
1793 (up
->rpf
.source_nexthop
.interface
)) {
1794 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
1799 void pim_upstream_add_lhr_star_pimreg(struct pim_instance
*pim
)
1801 struct pim_upstream
*up
;
1802 struct listnode
*node
;
1804 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1805 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1808 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1811 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1812 PIM_OIF_FLAG_PROTO_IGMP
);
1816 void pim_upstream_spt_prefix_list_update(struct pim_instance
*pim
,
1817 struct prefix_list
*pl
)
1819 const char *pname
= prefix_list_name(pl
);
1821 if (pim
->spt
.plist
&& strcmp(pim
->spt
.plist
, pname
) == 0) {
1822 pim_upstream_remove_lhr_star_pimreg(pim
, pname
);
1827 * nlist -> The new prefix list
1829 * Per Group Application of pimreg to the OIL
1830 * If the prefix list tells us DENY then
1831 * we need to Switchover to SPT immediate
1832 * so add the pimreg.
1833 * If the prefix list tells us to ACCEPT than
1834 * we need to Never do the SPT so remove
1838 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance
*pim
,
1841 struct pim_upstream
*up
;
1842 struct listnode
*node
;
1843 struct prefix_list
*np
;
1845 enum prefix_list_type apply_new
;
1847 np
= prefix_list_lookup(AFI_IP
, nlist
);
1850 g
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1852 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1853 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1856 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1860 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1861 PIM_OIF_FLAG_PROTO_IGMP
);
1864 g
.u
.prefix4
= up
->sg
.grp
;
1865 apply_new
= prefix_list_apply(np
, &g
);
1866 if (apply_new
== PREFIX_DENY
)
1867 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1868 PIM_OIF_FLAG_PROTO_IGMP
);
1870 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1871 PIM_OIF_FLAG_PROTO_IGMP
);
1875 void pim_upstream_init(struct pim_instance
*pim
)
1879 snprintf(name
, 64, "PIM %s Timer Wheel",
1881 pim
->upstream_sg_wheel
=
1882 wheel_init(router
->master
, 31000, 100, pim_upstream_hash_key
,
1883 pim_upstream_sg_running
, name
);
1885 snprintf(name
, 64, "PIM %s Upstream Hash",
1887 pim
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
1888 pim_upstream_equal
, name
);
1890 pim
->upstream_list
= list_new();
1891 pim
->upstream_list
->cmp
= pim_upstream_compare
;