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
22 #include "zebra/rib.h"
39 #include "pim_iface.h"
41 #include "pim_zlookup.h"
42 #include "pim_upstream.h"
43 #include "pim_ifchannel.h"
44 #include "pim_neighbor.h"
46 #include "pim_zebra.h"
48 #include "pim_macro.h"
51 #include "pim_register.h"
53 #include "pim_jp_agg.h"
57 static void join_timer_stop(struct pim_upstream
*up
);
59 pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
);
62 * A (*,G) or a (*,*) is going away
63 * remove the parent pointer from
64 * those pointing at us
66 static void pim_upstream_remove_children(struct pim_instance
*pim
,
67 struct pim_upstream
*up
)
69 struct pim_upstream
*child
;
74 while (!list_isempty(up
->sources
)) {
75 child
= listnode_head(up
->sources
);
76 listnode_delete(up
->sources
, child
);
77 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child
->flags
)) {
78 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child
->flags
);
79 child
= pim_upstream_del(pim
, child
,
85 list_delete_and_null(&up
->sources
);
89 * A (*,G) or a (*,*) is being created
90 * Find the children that would point
93 static void pim_upstream_find_new_children(struct pim_instance
*pim
,
94 struct pim_upstream
*up
)
96 struct pim_upstream
*child
;
97 struct listnode
*ch_node
;
99 if ((up
->sg
.src
.s_addr
!= INADDR_ANY
)
100 && (up
->sg
.grp
.s_addr
!= INADDR_ANY
))
103 if ((up
->sg
.src
.s_addr
== INADDR_ANY
)
104 && (up
->sg
.grp
.s_addr
== INADDR_ANY
))
107 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, ch_node
, child
)) {
108 if ((up
->sg
.grp
.s_addr
!= INADDR_ANY
)
109 && (child
->sg
.grp
.s_addr
== up
->sg
.grp
.s_addr
)
112 listnode_add_sort(up
->sources
, child
);
118 * If we have a (*,*) || (S,*) there is no parent
119 * If we have a (S,G), find the (*,G)
120 * If we have a (*,G), find the (*,*)
122 static struct pim_upstream
*pim_upstream_find_parent(struct pim_instance
*pim
,
123 struct pim_upstream
*child
)
125 struct prefix_sg any
= child
->sg
;
126 struct pim_upstream
*up
= NULL
;
129 if ((child
->sg
.src
.s_addr
!= INADDR_ANY
)
130 && (child
->sg
.grp
.s_addr
!= INADDR_ANY
)) {
131 any
.src
.s_addr
= INADDR_ANY
;
132 up
= pim_upstream_find(pim
, &any
);
135 listnode_add(up
->sources
, child
);
143 void pim_upstream_free(struct pim_upstream
*up
)
145 XFREE(MTYPE_PIM_UPSTREAM
, up
);
149 static void upstream_channel_oil_detach(struct pim_upstream
*up
)
151 if (up
->channel_oil
) {
152 /* Detaching from channel_oil, channel_oil may exist post del,
153 but upstream would not keep reference of it
155 up
->channel_oil
->up
= NULL
;
156 pim_channel_oil_del(up
->channel_oil
);
157 up
->channel_oil
= NULL
;
161 struct pim_upstream
*pim_upstream_del(struct pim_instance
*pim
,
162 struct pim_upstream
*up
, const char *name
)
164 bool notify_msdp
= false;
169 "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
170 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
171 pim
->vrf
->name
, up
->ref_count
,
172 up
->flags
, up
->channel_oil
->oil_ref_count
);
176 if (up
->ref_count
>= 1)
179 THREAD_OFF(up
->t_ka_timer
);
180 THREAD_OFF(up
->t_rs_timer
);
181 THREAD_OFF(up
->t_msdp_reg_timer
);
183 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
184 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 0);
186 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
187 /* if a (*, G) entry in the joined state is being
189 * need to notify MSDP */
195 pim_jp_agg_upstream_verification(up
, false);
196 up
->rpf
.source_nexthop
.interface
= NULL
;
198 if (up
->sg
.src
.s_addr
!= INADDR_ANY
) {
199 wheel_remove_item(pim
->upstream_sg_wheel
, up
);
203 pim_upstream_remove_children(pim
, up
);
205 list_delete_and_null(&up
->sources
);
207 pim_mroute_del(up
->channel_oil
, __PRETTY_FUNCTION__
);
208 upstream_channel_oil_detach(up
);
210 list_delete_and_null(&up
->ifchannels
);
213 notice that listnode_delete() can't be moved
214 into pim_upstream_free() because the later is
215 called by list_delete_all_node()
217 if (up
->parent
&& up
->parent
->sources
)
218 listnode_delete(up
->parent
->sources
, up
);
221 listnode_delete(pim
->upstream_list
, up
);
222 hash_release(pim
->upstream_hash
, up
);
225 pim_msdp_up_del(pim
, &up
->sg
);
228 /* Deregister addr with Zebra NHT */
229 nht_p
.family
= AF_INET
;
230 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
231 nht_p
.u
.prefix4
= up
->upstream_addr
;
232 if (PIM_DEBUG_TRACE
) {
233 char buf
[PREFIX2STR_BUFFER
];
234 prefix2str(&nht_p
, buf
, sizeof(buf
));
235 zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
236 __PRETTY_FUNCTION__
, up
->sg_str
, buf
);
238 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
);
240 pim_upstream_free(up
);
245 void pim_upstream_send_join(struct pim_upstream
*up
)
247 if (PIM_DEBUG_TRACE
) {
248 char rpf_str
[PREFIX_STRLEN
];
249 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_str
,
251 zlog_debug("%s: RPF'%s=%s(%s) for Interface %s",
252 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
253 pim_upstream_state2str(up
->join_state
),
254 up
->rpf
.source_nexthop
.interface
->name
);
255 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
256 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
257 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
);
262 /* send Join(S,G) to the current upstream neighbor */
263 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 1 /* join */);
266 static int on_join_timer(struct thread
*t
)
268 struct pim_upstream
*up
;
273 * In the case of a HFR we will not ahve anyone to send this to.
275 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
279 * Don't send the join if the outgoing interface is a loopback
280 * But since this might change leave the join timer running
282 if (up
->rpf
.source_nexthop
283 .interface
&& !if_is_loopback(up
->rpf
.source_nexthop
.interface
))
284 pim_upstream_send_join(up
);
286 join_timer_start(up
);
291 static void join_timer_stop(struct pim_upstream
*up
)
293 struct pim_neighbor
*nbr
;
295 THREAD_OFF(up
->t_join_timer
);
297 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
298 up
->rpf
.rpf_addr
.u
.prefix4
);
301 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
);
303 pim_jp_agg_upstream_verification(up
, false);
306 void join_timer_start(struct pim_upstream
*up
)
308 struct pim_neighbor
*nbr
= NULL
;
310 if (up
->rpf
.source_nexthop
.interface
) {
311 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
312 up
->rpf
.rpf_addr
.u
.prefix4
);
314 if (PIM_DEBUG_PIM_EVENTS
) {
316 "%s: starting %d sec timer for upstream (S,G)=%s",
317 __PRETTY_FUNCTION__
, qpim_t_periodic
,
323 pim_jp_agg_add_group(nbr
->upstream_jp_agg
, up
, 1);
325 THREAD_OFF(up
->t_join_timer
);
326 thread_add_timer(master
, on_join_timer
, up
, qpim_t_periodic
,
329 pim_jp_agg_upstream_verification(up
, true);
333 * This is only called when we are switching the upstream
334 * J/P from one neighbor to another
336 * As such we need to remove from the old list and
337 * add to the new list.
339 void pim_upstream_join_timer_restart(struct pim_upstream
*up
,
342 // THREAD_OFF(up->t_join_timer);
343 join_timer_start(up
);
346 static void pim_upstream_join_timer_restart_msec(struct pim_upstream
*up
,
349 if (PIM_DEBUG_PIM_EVENTS
) {
350 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
351 __PRETTY_FUNCTION__
, interval_msec
, up
->sg_str
);
354 THREAD_OFF(up
->t_join_timer
);
355 thread_add_timer_msec(master
, on_join_timer
, up
, interval_msec
,
359 void pim_upstream_join_suppress(struct pim_upstream
*up
,
360 struct in_addr rpf_addr
, int holdtime
)
362 long t_joinsuppress_msec
;
363 long join_timer_remain_msec
;
365 t_joinsuppress_msec
=
366 MIN(pim_if_t_suppressed_msec(up
->rpf
.source_nexthop
.interface
),
369 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
371 if (PIM_DEBUG_TRACE
) {
372 char rpf_str
[INET_ADDRSTRLEN
];
373 pim_inet4_dump("<rpf?>", rpf_addr
, rpf_str
, sizeof(rpf_str
));
375 "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
376 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
377 join_timer_remain_msec
, t_joinsuppress_msec
);
380 if (join_timer_remain_msec
< t_joinsuppress_msec
) {
381 if (PIM_DEBUG_TRACE
) {
383 "%s %s: suppressing Join(S,G)=%s for %ld msec",
384 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
,
385 t_joinsuppress_msec
);
388 pim_upstream_join_timer_restart_msec(up
, t_joinsuppress_msec
);
392 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label
,
393 struct pim_upstream
*up
)
395 long join_timer_remain_msec
;
398 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
400 pim_if_t_override_msec(up
->rpf
.source_nexthop
.interface
);
402 if (PIM_DEBUG_TRACE
) {
403 char rpf_str
[INET_ADDRSTRLEN
];
404 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
.u
.prefix4
, rpf_str
,
407 "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
408 debug_label
, up
->sg_str
, rpf_str
,
409 join_timer_remain_msec
, t_override_msec
);
412 if (join_timer_remain_msec
> t_override_msec
) {
413 if (PIM_DEBUG_TRACE
) {
415 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
416 debug_label
, up
->sg_str
, t_override_msec
);
419 pim_upstream_join_timer_restart_msec(up
, t_override_msec
);
423 static void forward_on(struct pim_upstream
*up
)
425 struct listnode
*chnode
;
426 struct listnode
*chnextnode
;
427 struct pim_ifchannel
*ch
= NULL
;
429 /* scan (S,G) state */
430 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
431 if (pim_macro_chisin_oiflist(ch
))
432 pim_forward_start(ch
);
434 } /* scan iface channel list */
437 static void forward_off(struct pim_upstream
*up
)
439 struct listnode
*chnode
;
440 struct listnode
*chnextnode
;
441 struct pim_ifchannel
*ch
;
443 /* scan per-interface (S,G) state */
444 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
446 pim_forward_stop(ch
, false);
448 } /* scan iface channel list */
451 static int pim_upstream_could_register(struct pim_upstream
*up
)
453 struct pim_interface
*pim_ifp
= NULL
;
455 if (up
->rpf
.source_nexthop
.interface
)
456 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
459 zlog_debug("%s: up %s RPF is not present",
460 __PRETTY_FUNCTION__
, up
->sg_str
);
463 if (pim_ifp
&& PIM_I_am_DR(pim_ifp
)
464 && pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
471 /* Source registration is supressed for SSM groups. When the SSM range changes
472 * we re-revaluate register setup for existing upstream entries */
473 void pim_upstream_register_reevaluate(struct pim_instance
*pim
)
475 struct listnode
*upnode
;
476 struct pim_upstream
*up
;
478 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
479 /* If FHR is set CouldRegister is True. Also check if the flow
480 * is actually active; if it is not kat setup will trigger
482 * registration whenever the flow becomes active. */
483 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) || !up
->t_ka_timer
)
486 if (pim_is_grp_ssm(pim
, up
->sg
.grp
)) {
487 /* clear the register state for SSM groups */
488 if (up
->reg_state
!= PIM_REG_NOINFO
) {
489 if (PIM_DEBUG_PIM_EVENTS
)
491 "Clear register for %s as G is now SSM",
493 /* remove regiface from the OIL if it is there*/
494 pim_channel_del_oif(up
->channel_oil
,
496 PIM_OIF_FLAG_PROTO_PIM
);
497 up
->reg_state
= PIM_REG_NOINFO
;
500 /* register ASM sources with the RP */
501 if (up
->reg_state
== PIM_REG_NOINFO
) {
502 if (PIM_DEBUG_PIM_EVENTS
)
504 "Register %s as G is now ASM",
506 pim_channel_add_oif(up
->channel_oil
,
508 PIM_OIF_FLAG_PROTO_PIM
);
509 up
->reg_state
= PIM_REG_JOIN
;
515 void pim_upstream_switch(struct pim_instance
*pim
, struct pim_upstream
*up
,
516 enum pim_upstream_state new_state
)
518 enum pim_upstream_state old_state
= up
->join_state
;
520 if (PIM_DEBUG_PIM_EVENTS
) {
521 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
522 __PRETTY_FUNCTION__
, up
->sg_str
,
523 pim_upstream_state2str(up
->join_state
),
524 pim_upstream_state2str(new_state
));
527 up
->join_state
= new_state
;
528 if (old_state
!= new_state
)
529 up
->state_transition
= pim_time_monotonic_sec();
531 pim_upstream_update_assert_tracking_desired(up
);
533 if (new_state
== PIM_UPSTREAM_JOINED
) {
534 if (old_state
!= PIM_UPSTREAM_JOINED
) {
535 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
537 pim_msdp_up_join_state_changed(pim
, up
);
538 if (pim_upstream_could_register(up
)) {
539 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
541 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
543 pim_upstream_keep_alive_timer_start(
544 up
, pim
->keep_alive_time
);
545 pim_register_join(up
);
548 pim_upstream_send_join(up
);
549 join_timer_start(up
);
557 if (old_state
== PIM_UPSTREAM_JOINED
)
558 pim_msdp_up_join_state_changed(pim
, up
);
560 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
562 If I am RP for G then send S,G prune to its IIF. */
563 if (pim_upstream_is_sg_rpt(up
) && up
->parent
564 && !I_am_RP(pim
, up
->sg
.grp
)) {
565 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
567 "%s: *,G IIF %s S,G IIF %s ",
569 up
->parent
->rpf
.source_nexthop
571 up
->rpf
.source_nexthop
.interface
->name
);
572 pim_jp_agg_single_upstream_send(&up
->parent
->rpf
,
576 pim_jp_agg_single_upstream_send(&up
->rpf
, up
,
582 int pim_upstream_compare(void *arg1
, void *arg2
)
584 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
585 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
587 if (ntohl(up1
->sg
.grp
.s_addr
) < ntohl(up2
->sg
.grp
.s_addr
))
590 if (ntohl(up1
->sg
.grp
.s_addr
) > ntohl(up2
->sg
.grp
.s_addr
))
593 if (ntohl(up1
->sg
.src
.s_addr
) < ntohl(up2
->sg
.src
.s_addr
))
596 if (ntohl(up1
->sg
.src
.s_addr
) > ntohl(up2
->sg
.src
.s_addr
))
602 static struct pim_upstream
*pim_upstream_new(struct pim_instance
*pim
,
603 struct prefix_sg
*sg
,
604 struct interface
*incoming
,
606 struct pim_ifchannel
*ch
)
608 enum pim_rpf_result rpf_result
;
609 struct pim_interface
*pim_ifp
;
610 struct pim_upstream
*up
;
612 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
614 zlog_err("%s: PIM XCALLOC(%zu) failure", __PRETTY_FUNCTION__
,
620 pim_str_sg_set(sg
, up
->sg_str
);
624 up
= hash_get(pim
->upstream_hash
, up
, hash_alloc_intern
);
625 if (!pim_rp_set_upstream_addr(pim
, &up
->upstream_addr
, sg
->src
,
628 zlog_debug("%s: Received a (*,G) with no RP configured",
629 __PRETTY_FUNCTION__
);
631 hash_release(pim
->upstream_hash
, up
);
632 XFREE(MTYPE_PIM_UPSTREAM
, up
);
636 up
->parent
= pim_upstream_find_parent(pim
, up
);
637 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
638 up
->sources
= list_new();
639 up
->sources
->cmp
= pim_upstream_compare
;
643 pim_upstream_find_new_children(pim
, up
);
646 up
->t_join_timer
= NULL
;
647 up
->t_ka_timer
= NULL
;
648 up
->t_rs_timer
= NULL
;
649 up
->t_msdp_reg_timer
= NULL
;
650 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
651 up
->reg_state
= PIM_REG_NOINFO
;
652 up
->state_transition
= pim_time_monotonic_sec();
653 up
->channel_oil
= NULL
;
654 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
656 up
->rpf
.source_nexthop
.interface
= NULL
;
657 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
658 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
660 up
->rpf
.source_nexthop
.mrib_metric_preference
=
661 qpim_infinite_assert_metric
.metric_preference
;
662 up
->rpf
.source_nexthop
.mrib_route_metric
=
663 qpim_infinite_assert_metric
.route_metric
;
664 up
->rpf
.rpf_addr
.family
= AF_INET
;
665 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
667 up
->ifchannels
= list_new();
668 up
->ifchannels
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
670 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
671 wheel_add_item(pim
->upstream_sg_wheel
, up
);
673 rpf_result
= pim_rpf_update(pim
, up
, NULL
, 1);
674 if (rpf_result
== PIM_RPF_FAILURE
) {
679 "%s: Attempting to create upstream(%s), Unable to RPF for source",
680 __PRETTY_FUNCTION__
, up
->sg_str
);
682 nht_p
.family
= AF_INET
;
683 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
684 nht_p
.u
.prefix4
= up
->upstream_addr
;
685 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
);
688 listnode_delete(up
->parent
->sources
, up
);
692 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
693 wheel_remove_item(pim
->upstream_sg_wheel
, up
);
695 pim_upstream_remove_children(pim
, up
);
697 list_delete_and_null(&up
->sources
);
699 list_delete_and_null(&up
->ifchannels
);
701 hash_release(pim
->upstream_hash
, up
);
702 XFREE(MTYPE_PIM_UPSTREAM
, up
);
706 if (up
->rpf
.source_nexthop
.interface
) {
707 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
709 up
->channel_oil
= pim_channel_oil_add(
710 pim
, &up
->sg
, pim_ifp
->mroute_vif_index
);
712 listnode_add_sort(pim
->upstream_list
, up
);
714 if (PIM_DEBUG_TRACE
) {
716 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
717 __PRETTY_FUNCTION__
, up
->sg_str
,
718 inet_ntoa(up
->upstream_addr
), up
->ref_count
);
724 struct pim_upstream
*pim_upstream_find(struct pim_instance
*pim
,
725 struct prefix_sg
*sg
)
727 struct pim_upstream lookup
;
728 struct pim_upstream
*up
= NULL
;
731 up
= hash_lookup(pim
->upstream_hash
, &lookup
);
735 struct pim_upstream
*pim_upstream_find_or_add(struct prefix_sg
*sg
,
736 struct interface
*incoming
,
737 int flags
, const char *name
)
739 struct pim_upstream
*up
;
740 struct pim_interface
*pim_ifp
;
742 pim_ifp
= incoming
->info
;
744 up
= pim_upstream_find(pim_ifp
->pim
, sg
);
747 if (!(up
->flags
& flags
)) {
752 "%s(%s): upstream %s ref count %d increment",
753 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
757 up
= pim_upstream_add(pim_ifp
->pim
, sg
, incoming
, flags
, name
,
763 void pim_upstream_ref(struct pim_upstream
*up
, int flags
, const char *name
)
768 zlog_debug("%s(%s): upstream %s ref count %d increment",
769 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
773 struct pim_upstream
*pim_upstream_add(struct pim_instance
*pim
,
774 struct prefix_sg
*sg
,
775 struct interface
*incoming
, int flags
,
777 struct pim_ifchannel
*ch
)
779 struct pim_upstream
*up
= NULL
;
782 up
= pim_upstream_find(pim
, sg
);
784 pim_upstream_ref(up
, flags
, name
);
787 up
= pim_upstream_new(pim
, sg
, incoming
, flags
, ch
);
790 if (PIM_DEBUG_TRACE
) {
792 char buf
[PREFIX2STR_BUFFER
];
793 prefix2str(&up
->rpf
.rpf_addr
, buf
, sizeof(buf
));
794 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
795 __PRETTY_FUNCTION__
, name
,
796 up
->sg_str
, buf
, up
->rpf
.source_nexthop
.interface
?
797 up
->rpf
.source_nexthop
.interface
->name
: "NIL" ,
798 found
, up
->ref_count
);
800 zlog_debug("%s(%s): (%s) failure to create",
801 __PRETTY_FUNCTION__
, name
,
802 pim_str_sg_dump(sg
));
809 * Passed in up must be the upstream for ch. starch is NULL if no
812 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream
*up
,
813 struct pim_ifchannel
*ch
,
814 struct pim_ifchannel
*starch
)
817 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
820 if (!pim_macro_ch_lost_assert(ch
)
821 && pim_macro_chisin_joins_or_include(ch
))
829 if (PIM_IF_FLAG_TEST_S_G_RPT(starch
->upstream
->flags
))
832 if (!pim_macro_ch_lost_assert(starch
)
833 && pim_macro_chisin_joins_or_include(starch
))
841 Evaluate JoinDesired(S,G):
843 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
846 inherited_olist(S,G) =
847 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
849 JoinDesired(S,G) may be affected by changes in the following:
851 pim_ifp->primary_address
853 ch->ifassert_winner_metric
855 ch->local_ifmembership
857 ch->upstream->rpf.source_nexthop.mrib_metric_preference
858 ch->upstream->rpf.source_nexthop.mrib_route_metric
859 ch->upstream->rpf.source_nexthop.interface
861 See also pim_upstream_update_join_desired() below.
863 int pim_upstream_evaluate_join_desired(struct pim_instance
*pim
,
864 struct pim_upstream
*up
)
866 struct interface
*ifp
;
867 struct pim_ifchannel
*ch
, *starch
;
868 struct pim_upstream
*starup
= up
->parent
;
871 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
875 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
878 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
885 ret
+= pim_upstream_evaluate_join_desired_interface(up
, ch
,
887 } /* scan iface channel list */
889 return ret
; /* false */
893 See also pim_upstream_evaluate_join_desired() above.
895 void pim_upstream_update_join_desired(struct pim_instance
*pim
,
896 struct pim_upstream
*up
)
898 int was_join_desired
; /* boolean */
899 int is_join_desired
; /* boolean */
901 was_join_desired
= PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up
->flags
);
903 is_join_desired
= pim_upstream_evaluate_join_desired(pim
, up
);
905 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up
->flags
);
907 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up
->flags
);
909 /* switched from false to true */
910 if (is_join_desired
&& !was_join_desired
) {
911 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
915 /* switched from true to false */
916 if (!is_join_desired
&& was_join_desired
) {
917 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_NOTJOINED
);
923 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
924 Transitions from Joined State
925 RPF'(S,G) GenID changes
927 The upstream (S,G) state machine remains in Joined state. If the
928 Join Timer is set to expire in more than t_override seconds, reset
929 it so that it expires after t_override seconds.
931 void pim_upstream_rpf_genid_changed(struct pim_instance
*pim
,
932 struct in_addr neigh_addr
)
934 struct listnode
*up_node
;
935 struct listnode
*up_nextnode
;
936 struct pim_upstream
*up
;
939 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
941 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
943 if (PIM_DEBUG_TRACE
) {
944 char neigh_str
[INET_ADDRSTRLEN
];
945 char rpf_addr_str
[PREFIX_STRLEN
];
946 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
,
948 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_addr_str
,
949 sizeof(rpf_addr_str
));
951 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
952 __PRETTY_FUNCTION__
, neigh_str
, up
->sg_str
, pim
->vrf
->name
,
953 up
->join_state
== PIM_UPSTREAM_JOINED
,
957 /* consider only (S,G) upstream in Joined state */
958 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
961 /* match RPF'(S,G)=neigh_addr */
962 if (up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
!= neigh_addr
.s_addr
)
965 pim_upstream_join_timer_decrease_to_t_override(
966 "RPF'(S,G) GenID change", up
);
971 void pim_upstream_rpf_interface_changed(struct pim_upstream
*up
,
972 struct interface
*old_rpf_ifp
)
974 struct listnode
*chnode
;
975 struct listnode
*chnextnode
;
976 struct pim_ifchannel
*ch
;
978 /* search all ifchannels */
979 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
980 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
982 /* RPF_interface(S) was NOT I */
983 (old_rpf_ifp
== ch
->interface
) &&
984 /* RPF_interface(S) stopped being I */
985 (ch
->upstream
->rpf
.source_nexthop
986 .interface
!= ch
->interface
)) {
987 assert_action_a5(ch
);
989 } /* PIM_IFASSERT_I_AM_LOSER */
991 pim_ifchannel_update_assert_tracking_desired(ch
);
995 void pim_upstream_update_could_assert(struct pim_upstream
*up
)
997 struct listnode
*chnode
;
998 struct listnode
*chnextnode
;
999 struct pim_ifchannel
*ch
;
1001 /* scan per-interface (S,G) state */
1002 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1003 pim_ifchannel_update_could_assert(ch
);
1004 } /* scan iface channel list */
1007 void pim_upstream_update_my_assert_metric(struct pim_upstream
*up
)
1009 struct listnode
*chnode
;
1010 struct listnode
*chnextnode
;
1011 struct pim_ifchannel
*ch
;
1013 /* scan per-interface (S,G) state */
1014 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1015 pim_ifchannel_update_my_assert_metric(ch
);
1017 } /* scan iface channel list */
1020 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
)
1022 struct listnode
*chnode
;
1023 struct listnode
*chnextnode
;
1024 struct pim_interface
*pim_ifp
;
1025 struct pim_ifchannel
*ch
;
1027 /* scan per-interface (S,G) state */
1028 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1031 pim_ifp
= ch
->interface
->info
;
1035 pim_ifchannel_update_assert_tracking_desired(ch
);
1037 } /* scan iface channel list */
1040 /* When kat is stopped CouldRegister goes to false so we need to
1041 * transition the (S, G) on FHR to NI state and remove reg tunnel
1043 static void pim_upstream_fhr_kat_expiry(struct pim_instance
*pim
,
1044 struct pim_upstream
*up
)
1046 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
1049 if (PIM_DEBUG_TRACE
)
1050 zlog_debug("kat expired on %s; clear fhr reg state",
1053 /* stop reg-stop timer */
1054 THREAD_OFF(up
->t_rs_timer
);
1055 /* remove regiface from the OIL if it is there*/
1056 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1057 PIM_OIF_FLAG_PROTO_PIM
);
1058 /* clear the register state */
1059 up
->reg_state
= PIM_REG_NOINFO
;
1060 PIM_UPSTREAM_FLAG_UNSET_FHR(up
->flags
);
1063 /* When kat is started CouldRegister can go to true. And if it does we
1064 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1066 static void pim_upstream_fhr_kat_start(struct pim_upstream
*up
)
1068 if (pim_upstream_could_register(up
)) {
1069 if (PIM_DEBUG_TRACE
)
1071 "kat started on %s; set fhr reg state to joined",
1074 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1075 if (up
->reg_state
== PIM_REG_NOINFO
)
1076 pim_register_join(up
);
1081 * On an RP, the PMBR value must be cleared when the
1082 * Keepalive Timer expires
1083 * KAT expiry indicates that flow is inactive. If the flow was created or
1084 * maintained by activity now is the time to deref it.
1086 static int pim_upstream_keep_alive_timer(struct thread
*t
)
1088 struct pim_upstream
*up
;
1089 struct pim_instance
*pim
;
1092 pim
= up
->channel_oil
->pim
;
1094 if (I_am_RP(pim
, up
->sg
.grp
)) {
1095 pim_br_clear_pmbr(&up
->sg
);
1097 * We need to do more here :)
1098 * But this is the start.
1102 /* source is no longer active - pull the SA from MSDP's cache */
1103 pim_msdp_sa_local_del(pim
, &up
->sg
);
1105 /* if entry was created because of activity we need to deref it */
1106 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1107 pim_upstream_fhr_kat_expiry(pim
, up
);
1108 if (PIM_DEBUG_TRACE
)
1109 zlog_debug("kat expired on %s[%s]; remove stream reference",
1110 up
->sg_str
, pim
->vrf
->name
);
1111 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up
->flags
);
1112 pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1113 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
1114 struct pim_upstream
*parent
= up
->parent
;
1116 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1117 pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1120 pim_jp_agg_single_upstream_send(&parent
->rpf
,
1128 void pim_upstream_keep_alive_timer_start(struct pim_upstream
*up
, uint32_t time
)
1130 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1131 if (PIM_DEBUG_TRACE
)
1132 zlog_debug("kat start on %s with no stream reference",
1135 THREAD_OFF(up
->t_ka_timer
);
1136 thread_add_timer(master
, pim_upstream_keep_alive_timer
, up
, time
,
1139 /* any time keepalive is started against a SG we will have to
1140 * re-evaluate our active source database */
1141 pim_msdp_sa_local_update(up
);
1144 /* MSDP on RP needs to know if a source is registerable to this RP */
1145 static int pim_upstream_msdp_reg_timer(struct thread
*t
)
1147 struct pim_upstream
*up
= THREAD_ARG(t
);
1148 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1150 /* source is no longer active - pull the SA from MSDP's cache */
1151 pim_msdp_sa_local_del(pim
, &up
->sg
);
1154 void pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1156 THREAD_OFF(up
->t_msdp_reg_timer
);
1157 thread_add_timer(master
, pim_upstream_msdp_reg_timer
, up
,
1158 PIM_MSDP_REG_RXED_PERIOD
, &up
->t_msdp_reg_timer
);
1160 pim_msdp_sa_local_update(up
);
1164 * 4.2.1 Last-Hop Switchover to the SPT
1166 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1167 * RP. Once traffic from sources to joined groups arrives at a last-hop
1168 * router, it has the option of switching to receive the traffic on a
1169 * shortest path tree (SPT).
1171 * The decision for a router to switch to the SPT is controlled as
1175 * CheckSwitchToSpt(S,G) {
1176 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1177 * (+) pim_include(S,G) != NULL )
1178 * AND SwitchToSptDesired(S,G) ) {
1179 * # Note: Restarting the KAT will result in the SPT switch
1180 * set KeepaliveTimer(S,G) to Keepalive_Period
1184 * SwitchToSptDesired(S,G) is a policy function that is implementation
1185 * defined. An "infinite threshold" policy can be implemented by making
1186 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1187 * first packet" policy can be implemented by making
1188 * SwitchToSptDesired(S,G) return true once a single packet has been
1189 * received for the source and group.
1191 int pim_upstream_switch_to_spt_desired(struct pim_instance
*pim
,
1192 struct prefix_sg
*sg
)
1194 if (I_am_RP(pim
, sg
->grp
))
1200 int pim_upstream_is_sg_rpt(struct pim_upstream
*up
)
1202 struct listnode
*chnode
;
1203 struct pim_ifchannel
*ch
;
1205 for (ALL_LIST_ELEMENTS_RO(up
->ifchannels
, chnode
, ch
)) {
1206 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1213 * After receiving a packet set SPTbit:
1215 * Update_SPTbit(S,G,iif) {
1216 * if ( iif == RPF_interface(S)
1217 * AND JoinDesired(S,G) == TRUE
1218 * AND ( DirectlyConnected(S) == TRUE
1219 * OR RPF_interface(S) != RPF_interface(RP(G))
1220 * OR inherited_olist(S,G,rpt) == NULL
1221 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1222 * ( RPF'(S,G) != NULL ) )
1223 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1224 * Set SPTbit(S,G) to TRUE
1228 void pim_upstream_set_sptbit(struct pim_upstream
*up
,
1229 struct interface
*incoming
)
1231 struct pim_upstream
*starup
= up
->parent
;
1233 // iif == RPF_interfvace(S)
1234 if (up
->rpf
.source_nexthop
.interface
!= incoming
) {
1235 if (PIM_DEBUG_TRACE
)
1237 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1238 __PRETTY_FUNCTION__
, incoming
->name
,
1239 up
->rpf
.source_nexthop
.interface
->name
);
1243 // AND JoinDesired(S,G) == TRUE
1246 // DirectlyConnected(S) == TRUE
1247 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1249 if (PIM_DEBUG_TRACE
)
1250 zlog_debug("%s: %s is directly connected to the source",
1251 __PRETTY_FUNCTION__
, up
->sg_str
);
1252 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1256 // OR RPF_interface(S) != RPF_interface(RP(G))
1258 || up
->rpf
.source_nexthop
1259 .interface
!= starup
->rpf
.source_nexthop
.interface
) {
1260 if (PIM_DEBUG_TRACE
)
1262 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1263 __PRETTY_FUNCTION__
, up
->sg_str
);
1264 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1268 // OR inherited_olist(S,G,rpt) == NULL
1269 if (pim_upstream_is_sg_rpt(up
)
1270 && pim_upstream_empty_inherited_olist(up
)) {
1271 if (PIM_DEBUG_TRACE
)
1272 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1273 __PRETTY_FUNCTION__
, up
->sg_str
);
1274 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1278 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1279 // ( RPF'(S,G) != NULL ) )
1280 if (up
->parent
&& pim_rpf_is_same(&up
->rpf
, &up
->parent
->rpf
)) {
1281 if (PIM_DEBUG_TRACE
)
1282 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1283 __PRETTY_FUNCTION__
, up
->sg_str
);
1284 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1291 const char *pim_upstream_state2str(enum pim_upstream_state join_state
)
1293 switch (join_state
) {
1294 case PIM_UPSTREAM_NOTJOINED
:
1297 case PIM_UPSTREAM_JOINED
:
1304 const char *pim_reg_state2str(enum pim_reg_state reg_state
, char *state_str
)
1306 switch (reg_state
) {
1307 case PIM_REG_NOINFO
:
1308 strcpy(state_str
, "RegNoInfo");
1311 strcpy(state_str
, "RegJoined");
1313 case PIM_REG_JOIN_PENDING
:
1314 strcpy(state_str
, "RegJoinPend");
1317 strcpy(state_str
, "RegPrune");
1320 strcpy(state_str
, "RegUnknown");
1325 static int pim_upstream_register_stop_timer(struct thread
*t
)
1327 struct pim_interface
*pim_ifp
;
1328 struct pim_instance
*pim
;
1329 struct pim_upstream
*up
;
1330 struct pim_rpf
*rpg
;
1333 pim
= up
->channel_oil
->pim
;
1335 if (PIM_DEBUG_TRACE
) {
1336 char state_str
[PIM_REG_STATE_STR_LEN
];
1337 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1338 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
1339 pim_reg_state2str(up
->reg_state
, state_str
));
1342 switch (up
->reg_state
) {
1343 case PIM_REG_JOIN_PENDING
:
1344 up
->reg_state
= PIM_REG_JOIN
;
1345 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1346 PIM_OIF_FLAG_PROTO_PIM
);
1351 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1353 if (PIM_DEBUG_TRACE
)
1355 "%s: Interface: %s is not configured for pim",
1356 __PRETTY_FUNCTION__
,
1357 up
->rpf
.source_nexthop
.interface
->name
);
1360 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1361 pim_upstream_start_register_stop_timer(up
, 1);
1363 if (((up
->channel_oil
->cc
.lastused
/ 100)
1364 > pim
->keep_alive_time
)
1365 && (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
))) {
1366 if (PIM_DEBUG_TRACE
)
1368 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1369 __PRETTY_FUNCTION__
);
1372 rpg
= RP(pim_ifp
->pim
, up
->sg
.grp
);
1374 if (PIM_DEBUG_TRACE
)
1376 "%s: Cannot send register for %s no RPF to the RP",
1377 __PRETTY_FUNCTION__
, up
->sg_str
);
1380 memset(&ip_hdr
, 0, sizeof(struct ip
));
1381 ip_hdr
.ip_p
= PIM_IP_PROTO_PIM
;
1384 ip_hdr
.ip_src
= up
->sg
.src
;
1385 ip_hdr
.ip_dst
= up
->sg
.grp
;
1386 ip_hdr
.ip_len
= htons(20);
1387 // checksum is broken
1388 pim_register_send((uint8_t *)&ip_hdr
, sizeof(struct ip
),
1389 pim_ifp
->primary_address
, rpg
, 1, up
);
1398 void pim_upstream_start_register_stop_timer(struct pim_upstream
*up
,
1403 THREAD_TIMER_OFF(up
->t_rs_timer
);
1405 if (!null_register
) {
1406 uint32_t lower
= (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1407 uint32_t upper
= (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1408 time
= lower
+ (random() % (upper
- lower
+ 1))
1409 - PIM_REGISTER_PROBE_PERIOD
;
1411 time
= PIM_REGISTER_PROBE_PERIOD
;
1413 if (PIM_DEBUG_TRACE
) {
1415 "%s: (S,G)=%s Starting upstream register stop timer %d",
1416 __PRETTY_FUNCTION__
, up
->sg_str
, time
);
1418 thread_add_timer(master
, pim_upstream_register_stop_timer
, up
, time
,
1422 int pim_upstream_inherited_olist_decide(struct pim_instance
*pim
,
1423 struct pim_upstream
*up
)
1425 struct interface
*ifp
;
1426 struct pim_interface
*pim_ifp
= NULL
;
1427 struct pim_ifchannel
*ch
, *starch
;
1428 struct pim_upstream
*starup
= up
->parent
;
1429 int output_intf
= 0;
1431 if (up
->rpf
.source_nexthop
.interface
)
1432 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1434 if (PIM_DEBUG_TRACE
)
1435 zlog_debug("%s: up %s RPF is not present",
1436 __PRETTY_FUNCTION__
, up
->sg_str
);
1438 if (pim_ifp
&& !up
->channel_oil
)
1439 up
->channel_oil
= pim_channel_oil_add(
1440 pim
, &up
->sg
, pim_ifp
->mroute_vif_index
);
1442 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1446 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1449 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
1456 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1458 int flag
= PIM_OIF_FLAG_PROTO_PIM
;
1461 flag
= PIM_OIF_FLAG_PROTO_STAR
;
1463 pim_channel_add_oif(up
->channel_oil
, ifp
, flag
);
1472 * For a given upstream, determine the inherited_olist
1475 * inherited_olist(S,G,rpt) =
1476 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1477 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1478 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1480 * inherited_olist(S,G) =
1481 * inherited_olist(S,G,rpt) (+)
1482 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1484 * return 1 if there are any output interfaces
1485 * return 0 if there are not any output interfaces
1487 int pim_upstream_inherited_olist(struct pim_instance
*pim
,
1488 struct pim_upstream
*up
)
1490 int output_intf
= pim_upstream_inherited_olist_decide(pim
, up
);
1493 * If we have output_intf switch state to Join and work like normal
1494 * If we don't have an output_intf that means we are probably a
1495 * switch on a stick so turn on forwarding to just accept the
1496 * incoming packets so we don't bother the other stuff!
1499 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
1506 int pim_upstream_empty_inherited_olist(struct pim_upstream
*up
)
1508 return pim_channel_oil_empty(up
->channel_oil
);
1512 * When we have a new neighbor,
1513 * find upstreams that don't have their rpf_addr
1514 * set and see if the new neighbor allows
1515 * the join to be sent
1517 void pim_upstream_find_new_rpf(struct pim_instance
*pim
)
1519 struct listnode
*up_node
;
1520 struct listnode
*up_nextnode
;
1521 struct pim_upstream
*up
;
1524 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1526 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
1527 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
1528 if (PIM_DEBUG_TRACE
)
1530 "Upstream %s without a path to send join, checking",
1532 pim_rpf_update(pim
, up
, NULL
, 1);
1537 unsigned int pim_upstream_hash_key(void *arg
)
1539 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1541 return jhash_2words(up
->sg
.src
.s_addr
, up
->sg
.grp
.s_addr
, 0);
1544 void pim_upstream_terminate(struct pim_instance
*pim
)
1546 if (pim
->upstream_list
)
1547 list_delete_and_null(&pim
->upstream_list
);
1549 if (pim
->upstream_hash
)
1550 hash_free(pim
->upstream_hash
);
1551 pim
->upstream_hash
= NULL
;
1554 int pim_upstream_equal(const void *arg1
, const void *arg2
)
1556 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1557 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1559 if ((up1
->sg
.grp
.s_addr
== up2
->sg
.grp
.s_addr
)
1560 && (up1
->sg
.src
.s_addr
== up2
->sg
.src
.s_addr
))
1566 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1567 * the cases where kat has to be restarted on rxing traffic -
1569 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1570 * set KeepaliveTimer(S,G) to Keepalive_Period
1571 * # Note: a register state transition or UpstreamJPState(S,G)
1572 * # transition may happen as a result of restarting
1573 * # KeepaliveTimer, and must be dealt with here.
1575 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1576 * inherited_olist(S,G) != NULL ) {
1577 * set KeepaliveTimer(S,G) to Keepalive_Period
1580 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1582 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1584 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1585 * so we will skip that here */
1586 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1591 if ((up
->join_state
== PIM_UPSTREAM_JOINED
)
1592 && !pim_upstream_empty_inherited_olist(up
)) {
1593 /* XXX: I have added this RP check just for 3.2 and it's a
1595 * what rfc-4601 says. Till now we were only running KAT on FHR
1597 * there is some angst around making the change to run it all
1599 * maintain the (S, G) state. This is tracked via CM-13601 and
1601 * removed to handle spt turn-arounds correctly in a 3-tier clos
1603 if (I_am_RP(pim
, up
->sg
.grp
))
1611 * Code to check and see if we've received packets on a S,G mroute
1612 * and if so to set the SPT bit appropriately
1614 static void pim_upstream_sg_running(void *arg
)
1616 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1617 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1619 // No packet can have arrived here if this is the case
1620 if (!up
->channel_oil
->installed
) {
1621 if (PIM_DEBUG_TRACE
)
1622 zlog_debug("%s: %s[%s] is not installed in mroute",
1623 __PRETTY_FUNCTION__
,
1624 up
->sg_str
, pim
->vrf
->name
);
1629 * This is a bit of a hack
1630 * We've noted that we should rescan but
1631 * we've missed the window for doing so in
1632 * pim_zebra.c for some reason. I am
1633 * only doing this at this point in time
1634 * to get us up and working for the moment
1636 if (up
->channel_oil
->oil_inherited_rescan
) {
1637 if (PIM_DEBUG_TRACE
)
1639 "%s: Handling unscanned inherited_olist for %s[%s]",
1640 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
);
1641 pim_upstream_inherited_olist_decide(pim
, up
);
1642 up
->channel_oil
->oil_inherited_rescan
= 0;
1644 pim_mroute_update_counters(up
->channel_oil
);
1646 // Have we seen packets?
1647 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
)
1648 && (up
->channel_oil
->cc
.lastused
/ 100 > 30)) {
1649 if (PIM_DEBUG_TRACE
) {
1651 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1652 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
1653 up
->channel_oil
->cc
.oldpktcnt
,
1654 up
->channel_oil
->cc
.pktcnt
,
1655 up
->channel_oil
->cc
.lastused
/ 100);
1660 if (pim_upstream_kat_start_ok(up
)) {
1661 /* Add a source reference to the stream if
1662 * one doesn't already exist */
1663 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1664 if (PIM_DEBUG_TRACE
)
1666 "source reference created on kat restart %s[%s]",
1667 up
->sg_str
, pim
->vrf
->name
);
1669 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
,
1670 __PRETTY_FUNCTION__
);
1671 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
1672 pim_upstream_fhr_kat_start(up
);
1674 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1675 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
))
1676 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1678 if (up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
) {
1679 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
1684 void pim_upstream_add_lhr_star_pimreg(struct pim_instance
*pim
)
1686 struct pim_upstream
*up
;
1687 struct listnode
*node
;
1689 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1690 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1693 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1696 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1697 PIM_OIF_FLAG_PROTO_IGMP
);
1701 void pim_upstream_spt_prefix_list_update(struct pim_instance
*pim
,
1702 struct prefix_list
*pl
)
1704 const char *pname
= prefix_list_name(pl
);
1706 if (pim
->spt
.plist
&& strcmp(pim
->spt
.plist
, pname
) == 0) {
1707 pim_upstream_remove_lhr_star_pimreg(pim
, pname
);
1712 * nlist -> The new prefix list
1714 * Per Group Application of pimreg to the OIL
1715 * If the prefix list tells us DENY then
1716 * we need to Switchover to SPT immediate
1717 * so add the pimreg.
1718 * If the prefix list tells us to ACCEPT than
1719 * we need to Never do the SPT so remove
1723 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance
*pim
,
1726 struct pim_upstream
*up
;
1727 struct listnode
*node
;
1728 struct prefix_list
*np
;
1730 enum prefix_list_type apply_new
;
1732 np
= prefix_list_lookup(AFI_IP
, nlist
);
1735 g
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1737 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1738 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1741 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1745 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1746 PIM_OIF_FLAG_PROTO_IGMP
);
1749 g
.u
.prefix4
= up
->sg
.grp
;
1750 apply_new
= prefix_list_apply(np
, &g
);
1751 if (apply_new
== PREFIX_DENY
)
1752 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1753 PIM_OIF_FLAG_PROTO_IGMP
);
1755 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1756 PIM_OIF_FLAG_PROTO_IGMP
);
1760 void pim_upstream_init(struct pim_instance
*pim
)
1764 pim
->upstream_sg_wheel
=
1765 wheel_init(master
, 31000, 100, pim_upstream_hash_key
,
1766 pim_upstream_sg_running
);
1768 snprintf(hash_name
, 64, "PIM %s Upstream Hash",
1770 pim
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
1771 pim_upstream_equal
, hash_name
);
1773 pim
->upstream_list
= list_new();
1774 pim
->upstream_list
->del
= (void (*)(void *))pim_upstream_free
;
1775 pim
->upstream_list
->cmp
= pim_upstream_compare
;