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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
23 #include "zebra/rib.h"
40 #include "pim_iface.h"
42 #include "pim_zlookup.h"
43 #include "pim_upstream.h"
44 #include "pim_ifchannel.h"
45 #include "pim_neighbor.h"
47 #include "pim_zebra.h"
49 #include "pim_macro.h"
52 #include "pim_register.h"
54 #include "pim_jp_agg.h"
58 struct hash
*pim_upstream_hash
= NULL
;
59 struct list
*pim_upstream_list
= NULL
;
60 struct timer_wheel
*pim_upstream_sg_wheel
= NULL
;
62 static void join_timer_stop(struct pim_upstream
*up
);
63 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
);
66 * A (*,G) or a (*,*) is going away
67 * remove the parent pointer from
68 * those pointing at us
71 pim_upstream_remove_children (struct pim_upstream
*up
)
73 struct pim_upstream
*child
;
78 while (!list_isempty (up
->sources
))
80 child
= listnode_head (up
->sources
);
82 listnode_delete (up
->sources
, child
);
87 * A (*,G) or a (*,*) is being created
88 * Find the children that would point
92 pim_upstream_find_new_children (struct pim_upstream
*up
)
94 struct pim_upstream
*child
;
95 struct listnode
*ch_node
;
97 if ((up
->sg
.src
.s_addr
!= INADDR_ANY
) &&
98 (up
->sg
.grp
.s_addr
!= INADDR_ANY
))
101 if ((up
->sg
.src
.s_addr
== INADDR_ANY
) &&
102 (up
->sg
.grp
.s_addr
== INADDR_ANY
))
105 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
) &&
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
*
123 pim_upstream_find_parent (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
))
132 any
.src
.s_addr
= INADDR_ANY
;
133 up
= pim_upstream_find (&any
);
136 listnode_add (up
->sources
, child
);
144 void pim_upstream_free(struct pim_upstream
*up
)
146 XFREE(MTYPE_PIM_UPSTREAM
, up
);
150 static void upstream_channel_oil_detach(struct pim_upstream
*up
)
152 if (up
->channel_oil
) {
153 pim_channel_oil_del(up
->channel_oil
);
154 up
->channel_oil
= NULL
;
158 struct pim_upstream
*
159 pim_upstream_del(struct pim_upstream
*up
, const char *name
)
161 bool notify_msdp
= false;
165 zlog_debug ("%s(%s): Delete %s ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
166 __PRETTY_FUNCTION__
, name
, up
->sg_str
, up
->ref_count
, up
->flags
,
167 up
->channel_oil
->oil_ref_count
);
171 if (up
->ref_count
>= 1)
174 THREAD_OFF(up
->t_ka_timer
);
175 THREAD_OFF(up
->t_rs_timer
);
176 THREAD_OFF(up
->t_msdp_reg_timer
);
178 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
179 pim_jp_agg_single_upstream_send (&up
->rpf
, up
, 0);
181 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
182 /* if a (*, G) entry in the joined state is being deleted we
183 * need to notify MSDP */
189 pim_jp_agg_upstream_verification (up
, false);
190 up
->rpf
.source_nexthop
.interface
= NULL
;
192 if (up
->sg
.src
.s_addr
!= INADDR_ANY
) {
193 wheel_remove_item (pim_upstream_sg_wheel
, up
);
197 pim_upstream_remove_children (up
);
198 pim_mroute_del (up
->channel_oil
, __PRETTY_FUNCTION__
);
199 upstream_channel_oil_detach(up
);
203 struct listnode
*node
, *nnode
;
204 struct pim_upstream
*child
;
205 for (ALL_LIST_ELEMENTS (up
->sources
, node
, nnode
, child
))
207 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child
->flags
))
209 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child
->flags
);
210 pim_upstream_del(child
, __PRETTY_FUNCTION__
);
214 list_delete (up
->sources
);
218 list_delete (up
->ifchannels
);
219 up
->ifchannels
= NULL
;
222 notice that listnode_delete() can't be moved
223 into pim_upstream_free() because the later is
224 called by list_delete_all_node()
228 listnode_delete (up
->parent
->sources
, up
);
231 listnode_delete (pim_upstream_list
, up
);
232 hash_release (pim_upstream_hash
, up
);
236 pim_msdp_up_del (&up
->sg
);
239 /* Deregister addr with Zebra NHT */
240 nht_p
.family
= AF_INET
;
241 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
242 nht_p
.u
.prefix4
= up
->upstream_addr
;
245 char buf
[PREFIX2STR_BUFFER
];
246 prefix2str (&nht_p
, buf
, sizeof (buf
));
247 zlog_debug ("%s: Deregister upstream %s addr %s with Zebra NHT",
248 __PRETTY_FUNCTION__
, up
->sg_str
, buf
);
250 pim_delete_tracked_nexthop (&nht_p
, up
, NULL
);
252 pim_upstream_free (up
);
258 pim_upstream_send_join (struct pim_upstream
*up
)
260 if (PIM_DEBUG_TRACE
) {
261 char rpf_str
[PREFIX_STRLEN
];
262 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_str
, sizeof(rpf_str
));
263 zlog_debug ("%s: RPF'%s=%s(%s) for Interface %s", __PRETTY_FUNCTION__
,
264 up
->sg_str
, rpf_str
, pim_upstream_state2str (up
->join_state
),
265 up
->rpf
.source_nexthop
.interface
->name
);
266 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
267 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
269 up
->sg_str
, rpf_str
);
274 /* send Join(S,G) to the current upstream neighbor */
275 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 1 /* join */);
278 static int on_join_timer(struct thread
*t
)
280 struct pim_upstream
*up
;
284 up
->t_join_timer
= NULL
;
287 * In the case of a HFR we will not ahve anyone to send this to.
289 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
293 * Don't send the join if the outgoing interface is a loopback
294 * But since this might change leave the join timer running
296 if (up
->rpf
.source_nexthop
.interface
&&
297 !if_is_loopback (up
->rpf
.source_nexthop
.interface
))
298 pim_upstream_send_join (up
);
300 join_timer_start(up
);
305 static void join_timer_stop(struct pim_upstream
*up
)
307 struct pim_neighbor
*nbr
;
309 THREAD_OFF (up
->t_join_timer
);
311 nbr
= pim_neighbor_find (up
->rpf
.source_nexthop
.interface
,
312 up
->rpf
.rpf_addr
.u
.prefix4
);
315 pim_jp_agg_remove_group (nbr
->upstream_jp_agg
, up
);
317 pim_jp_agg_upstream_verification (up
, false);
321 join_timer_start(struct pim_upstream
*up
)
323 struct pim_neighbor
*nbr
= NULL
;
325 if (up
->rpf
.source_nexthop
.interface
)
327 nbr
= pim_neighbor_find (up
->rpf
.source_nexthop
.interface
,
328 up
->rpf
.rpf_addr
.u
.prefix4
);
330 if (PIM_DEBUG_PIM_EVENTS
) {
331 zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s",
339 pim_jp_agg_add_group (nbr
->upstream_jp_agg
, up
, 1);
342 THREAD_OFF (up
->t_join_timer
);
343 THREAD_TIMER_ON(master
, up
->t_join_timer
,
345 up
, qpim_t_periodic
);
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
, struct pim_rpf
*old
)
359 //THREAD_OFF(up->t_join_timer);
360 join_timer_start(up
);
363 static void pim_upstream_join_timer_restart_msec(struct pim_upstream
*up
,
366 if (PIM_DEBUG_PIM_EVENTS
) {
367 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
373 THREAD_OFF(up
->t_join_timer
);
374 THREAD_TIMER_MSEC_ON(master
, up
->t_join_timer
,
379 void pim_upstream_join_suppress(struct pim_upstream
*up
,
380 struct in_addr rpf_addr
,
383 long t_joinsuppress_msec
;
384 long join_timer_remain_msec
;
386 t_joinsuppress_msec
= MIN(pim_if_t_suppressed_msec(up
->rpf
.source_nexthop
.interface
),
389 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
391 if (PIM_DEBUG_TRACE
) {
392 char rpf_str
[INET_ADDRSTRLEN
];
393 pim_inet4_dump("<rpf?>", rpf_addr
, rpf_str
, sizeof(rpf_str
));
394 zlog_debug("%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
395 __FILE__
, __PRETTY_FUNCTION__
,
398 join_timer_remain_msec
, t_joinsuppress_msec
);
401 if (join_timer_remain_msec
< t_joinsuppress_msec
) {
402 if (PIM_DEBUG_TRACE
) {
403 zlog_debug("%s %s: suppressing Join(S,G)=%s for %ld msec",
404 __FILE__
, __PRETTY_FUNCTION__
,
405 up
->sg_str
, t_joinsuppress_msec
);
408 pim_upstream_join_timer_restart_msec(up
, t_joinsuppress_msec
);
412 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label
,
413 struct pim_upstream
*up
)
415 long join_timer_remain_msec
;
418 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
419 t_override_msec
= pim_if_t_override_msec(up
->rpf
.source_nexthop
.interface
);
421 if (PIM_DEBUG_TRACE
) {
422 char rpf_str
[INET_ADDRSTRLEN
];
423 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
.u
.prefix4
, rpf_str
, sizeof(rpf_str
));
424 zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
427 join_timer_remain_msec
, t_override_msec
);
430 if (join_timer_remain_msec
> t_override_msec
) {
431 if (PIM_DEBUG_TRACE
) {
432 zlog_debug("%s: decreasing (S,G)=%s join timer to t_override=%d msec",
438 pim_upstream_join_timer_restart_msec(up
, t_override_msec
);
442 static void forward_on(struct pim_upstream
*up
)
444 struct listnode
*chnode
;
445 struct listnode
*chnextnode
;
446 struct pim_ifchannel
*ch
= NULL
;
448 /* scan (S,G) state */
449 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
450 if (pim_macro_chisin_oiflist(ch
))
451 pim_forward_start(ch
);
453 } /* scan iface channel list */
456 static void forward_off(struct pim_upstream
*up
)
458 struct listnode
*chnode
;
459 struct listnode
*chnextnode
;
460 struct pim_ifchannel
*ch
;
462 /* scan per-interface (S,G) state */
463 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
465 pim_forward_stop(ch
);
467 } /* scan iface channel list */
471 pim_upstream_could_register (struct pim_upstream
*up
)
473 struct pim_interface
*pim_ifp
= NULL
;
475 if (up
->rpf
.source_nexthop
.interface
)
476 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
480 zlog_debug ("%s: up %s RPF is not present", __PRETTY_FUNCTION__
, up
->sg_str
);
483 if (pim_ifp
&& PIM_I_am_DR (pim_ifp
) &&
484 pim_if_connected_to_source (up
->rpf
.source_nexthop
.interface
, up
->sg
.src
))
490 /* Source registration is supressed for SSM groups. When the SSM range changes
491 * we re-revaluate register setup for existing upstream entries */
493 pim_upstream_register_reevaluate (void)
495 struct listnode
*upnode
;
496 struct pim_upstream
*up
;
498 for (ALL_LIST_ELEMENTS_RO (pim_upstream_list
, upnode
, up
))
500 /* If FHR is set CouldRegister is True. Also check if the flow
501 * is actually active; if it is not kat setup will trigger source
502 * registration whenever the flow becomes active. */
503 if (!PIM_UPSTREAM_FLAG_TEST_FHR (up
->flags
) || !up
->t_ka_timer
)
506 if (pim_is_grp_ssm (up
->sg
.grp
))
508 /* clear the register state for SSM groups */
509 if (up
->reg_state
!= PIM_REG_NOINFO
)
511 if (PIM_DEBUG_PIM_EVENTS
)
512 zlog_debug ("Clear register for %s as G is now SSM",
514 /* remove regiface from the OIL if it is there*/
515 pim_channel_del_oif (up
->channel_oil
, pim_regiface
,
516 PIM_OIF_FLAG_PROTO_PIM
);
517 up
->reg_state
= PIM_REG_NOINFO
;
522 /* register ASM sources with the RP */
523 if (up
->reg_state
== PIM_REG_NOINFO
)
525 if (PIM_DEBUG_PIM_EVENTS
)
526 zlog_debug ("Register %s as G is now ASM", up
->sg_str
);
527 pim_channel_add_oif (up
->channel_oil
, pim_regiface
,
528 PIM_OIF_FLAG_PROTO_PIM
);
529 up
->reg_state
= PIM_REG_JOIN
;
536 pim_upstream_switch(struct pim_upstream
*up
,
537 enum pim_upstream_state new_state
)
539 enum pim_upstream_state old_state
= up
->join_state
;
541 if (PIM_DEBUG_PIM_EVENTS
) {
542 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
545 pim_upstream_state2str (up
->join_state
),
546 pim_upstream_state2str (new_state
));
549 up
->join_state
= new_state
;
550 if (old_state
!= new_state
)
551 up
->state_transition
= pim_time_monotonic_sec();
553 pim_upstream_update_assert_tracking_desired(up
);
555 if (new_state
== PIM_UPSTREAM_JOINED
) {
556 if (old_state
!= PIM_UPSTREAM_JOINED
)
558 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
560 pim_msdp_up_join_state_changed(up
);
561 if (pim_upstream_could_register (up
))
563 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
564 if (!old_fhr
&& PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
))
566 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
567 pim_register_join (up
);
572 pim_upstream_send_join (up
);
573 join_timer_start (up
);
584 if (old_state
== PIM_UPSTREAM_JOINED
)
585 pim_msdp_up_join_state_changed(up
);
587 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 0 /* prune */);
593 pim_upstream_compare (void *arg1
, void *arg2
)
595 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
596 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
598 if (ntohl(up1
->sg
.grp
.s_addr
) < ntohl(up2
->sg
.grp
.s_addr
))
601 if (ntohl(up1
->sg
.grp
.s_addr
) > ntohl(up2
->sg
.grp
.s_addr
))
604 if (ntohl(up1
->sg
.src
.s_addr
) < ntohl(up2
->sg
.src
.s_addr
))
607 if (ntohl(up1
->sg
.src
.s_addr
) > ntohl(up2
->sg
.src
.s_addr
))
613 static struct pim_upstream
*
614 pim_upstream_new (struct prefix_sg
*sg
,
615 struct interface
*incoming
,
618 enum pim_rpf_result rpf_result
;
619 struct pim_interface
*pim_ifp
;
620 struct pim_upstream
*up
;
622 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
625 zlog_err("%s: PIM XCALLOC(%zu) failure",
626 __PRETTY_FUNCTION__
, sizeof(*up
));
631 pim_str_sg_set (sg
, up
->sg_str
);
632 up
= hash_get (pim_upstream_hash
, up
, hash_alloc_intern
);
633 if (!pim_rp_set_upstream_addr (&up
->upstream_addr
, sg
->src
, sg
->grp
))
636 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__
);
638 hash_release (pim_upstream_hash
, up
);
639 XFREE (MTYPE_PIM_UPSTREAM
, up
);
643 up
->parent
= pim_upstream_find_parent (up
);
644 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
646 up
->sources
= list_new ();
647 up
->sources
->cmp
= pim_upstream_compare
;
652 pim_upstream_find_new_children (up
);
655 up
->t_join_timer
= NULL
;
656 up
->t_ka_timer
= NULL
;
657 up
->t_rs_timer
= NULL
;
658 up
->t_msdp_reg_timer
= NULL
;
659 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
660 up
->reg_state
= PIM_REG_NOINFO
;
661 up
->state_transition
= pim_time_monotonic_sec();
662 up
->channel_oil
= NULL
;
663 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
665 up
->rpf
.source_nexthop
.interface
= NULL
;
666 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
667 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
668 up
->rpf
.source_nexthop
.mrib_metric_preference
= qpim_infinite_assert_metric
.metric_preference
;
669 up
->rpf
.source_nexthop
.mrib_route_metric
= qpim_infinite_assert_metric
.route_metric
;
670 up
->rpf
.rpf_addr
.family
= AF_INET
;
671 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
673 up
->ifchannels
= list_new();
674 up
->ifchannels
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
676 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
677 wheel_add_item (pim_upstream_sg_wheel
, up
);
679 rpf_result
= pim_rpf_update(up
, NULL
, 1);
680 if (rpf_result
== PIM_RPF_FAILURE
) {
684 zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__
,
687 nht_p
.family
= AF_INET
;
688 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
689 nht_p
.u
.prefix4
= up
->upstream_addr
;
690 pim_delete_tracked_nexthop (&nht_p
, up
, NULL
);
694 listnode_delete (up
->parent
->sources
, up
);
698 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
699 wheel_remove_item (pim_upstream_sg_wheel
, up
);
701 pim_upstream_remove_children (up
);
703 list_delete (up
->sources
);
705 hash_release (pim_upstream_hash
, up
);
706 XFREE(MTYPE_PIM_UPSTREAM
, up
);
710 if (up
->rpf
.source_nexthop
.interface
)
712 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
714 up
->channel_oil
= pim_channel_oil_add(&up
->sg
, pim_ifp
->mroute_vif_index
);
716 listnode_add_sort(pim_upstream_list
, up
);
720 zlog_debug ("%s: Created Upstream %s upstream_addr %s",
721 __PRETTY_FUNCTION__
, up
->sg_str
,
722 inet_ntoa (up
->upstream_addr
));
728 struct pim_upstream
*pim_upstream_find(struct prefix_sg
*sg
)
730 struct pim_upstream lookup
;
731 struct pim_upstream
*up
= NULL
;
734 up
= hash_lookup (pim_upstream_hash
, &lookup
);
738 struct pim_upstream
*
739 pim_upstream_find_or_add(struct prefix_sg
*sg
,
740 struct interface
*incoming
,
741 int flags
, const char *name
)
743 struct pim_upstream
*up
;
745 up
= pim_upstream_find(sg
);
749 if (!(up
->flags
& flags
))
756 up
= pim_upstream_add (sg
, incoming
, flags
, name
);
762 pim_upstream_ref(struct pim_upstream
*up
, int flags
)
768 struct pim_upstream
*pim_upstream_add(struct prefix_sg
*sg
,
769 struct interface
*incoming
,
770 int flags
, const char *name
)
772 struct pim_upstream
*up
= NULL
;
774 up
= pim_upstream_find(sg
);
776 pim_upstream_ref(up
, flags
);
780 up
= pim_upstream_new(sg
, incoming
, flags
);
787 char buf
[PREFIX2STR_BUFFER
];
788 prefix2str (&up
->rpf
.rpf_addr
, buf
, sizeof (buf
));
789 zlog_debug("%s(%s): %s, iif %s found: %d: ref_count: %d",
790 __PRETTY_FUNCTION__
, name
,
791 up
->sg_str
, buf
, found
,
795 zlog_debug("%s(%s): (%s) failure to create",
796 __PRETTY_FUNCTION__
, name
,
797 pim_str_sg_dump (sg
));
804 * Passed in up must be the upstream for ch. starch is NULL if no
808 pim_upstream_evaluate_join_desired_interface (struct pim_upstream
*up
,
809 struct pim_ifchannel
*ch
,
810 struct pim_ifchannel
*starch
)
814 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
817 if (!pim_macro_ch_lost_assert(ch
) && pim_macro_chisin_joins_or_include(ch
))
826 if (PIM_IF_FLAG_TEST_S_G_RPT (starch
->upstream
->flags
))
829 if (!pim_macro_ch_lost_assert (starch
) && pim_macro_chisin_joins_or_include (starch
))
837 Evaluate JoinDesired(S,G):
839 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
842 inherited_olist(S,G) =
843 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
845 JoinDesired(S,G) may be affected by changes in the following:
847 pim_ifp->primary_address
849 ch->ifassert_winner_metric
851 ch->local_ifmembership
853 ch->upstream->rpf.source_nexthop.mrib_metric_preference
854 ch->upstream->rpf.source_nexthop.mrib_route_metric
855 ch->upstream->rpf.source_nexthop.interface
857 See also pim_upstream_update_join_desired() below.
859 int pim_upstream_evaluate_join_desired(struct pim_upstream
*up
)
861 struct interface
*ifp
;
862 struct listnode
*node
;
863 struct pim_ifchannel
*ch
, *starch
;
864 struct pim_upstream
*starup
= up
->parent
;
867 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), node
, ifp
))
872 ch
= pim_ifchannel_find (ifp
, &up
->sg
);
875 starch
= pim_ifchannel_find (ifp
, &starup
->sg
);
882 ret
+= pim_upstream_evaluate_join_desired_interface (up
, ch
, starch
);
883 } /* scan iface channel list */
885 return ret
; /* false */
889 See also pim_upstream_evaluate_join_desired() above.
891 void pim_upstream_update_join_desired(struct pim_upstream
*up
)
893 int was_join_desired
; /* boolean */
894 int is_join_desired
; /* boolean */
896 was_join_desired
= PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up
->flags
);
898 is_join_desired
= pim_upstream_evaluate_join_desired(up
);
900 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up
->flags
);
902 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up
->flags
);
904 /* switched from false to true */
905 if (is_join_desired
&& !was_join_desired
) {
906 pim_upstream_switch(up
, PIM_UPSTREAM_JOINED
);
910 /* switched from true to false */
911 if (!is_join_desired
&& was_join_desired
) {
912 pim_upstream_switch(up
, PIM_UPSTREAM_NOTJOINED
);
918 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
919 Transitions from Joined State
920 RPF'(S,G) GenID changes
922 The upstream (S,G) state machine remains in Joined state. If the
923 Join Timer is set to expire in more than t_override seconds, reset
924 it so that it expires after t_override seconds.
926 void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr
)
928 struct listnode
*up_node
;
929 struct listnode
*up_nextnode
;
930 struct pim_upstream
*up
;
933 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
935 for (ALL_LIST_ELEMENTS(pim_upstream_list
, up_node
, up_nextnode
, up
)) {
937 if (PIM_DEBUG_TRACE
) {
938 char neigh_str
[INET_ADDRSTRLEN
];
939 char rpf_addr_str
[PREFIX_STRLEN
];
940 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
, sizeof(neigh_str
));
941 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_addr_str
, sizeof(rpf_addr_str
));
942 zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
944 neigh_str
, up
->sg_str
,
945 up
->join_state
== PIM_UPSTREAM_JOINED
,
949 /* consider only (S,G) upstream in Joined state */
950 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
953 /* match RPF'(S,G)=neigh_addr */
954 if (up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
!= neigh_addr
.s_addr
)
957 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
963 void pim_upstream_rpf_interface_changed(struct pim_upstream
*up
,
964 struct interface
*old_rpf_ifp
)
966 struct listnode
*chnode
;
967 struct listnode
*chnextnode
;
968 struct pim_ifchannel
*ch
;
970 /* search all ifchannels */
971 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
972 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
974 /* RPF_interface(S) was NOT I */
975 (old_rpf_ifp
== ch
->interface
)
977 /* RPF_interface(S) stopped being I */
978 (ch
->upstream
->rpf
.source_nexthop
.interface
!= ch
->interface
)
980 assert_action_a5(ch
);
982 } /* PIM_IFASSERT_I_AM_LOSER */
984 pim_ifchannel_update_assert_tracking_desired(ch
);
988 void pim_upstream_update_could_assert(struct pim_upstream
*up
)
990 struct listnode
*chnode
;
991 struct listnode
*chnextnode
;
992 struct pim_ifchannel
*ch
;
994 /* scan per-interface (S,G) state */
995 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
996 pim_ifchannel_update_could_assert(ch
);
997 } /* scan iface channel list */
1000 void pim_upstream_update_my_assert_metric(struct pim_upstream
*up
)
1002 struct listnode
*chnode
;
1003 struct listnode
*chnextnode
;
1004 struct pim_ifchannel
*ch
;
1006 /* scan per-interface (S,G) state */
1007 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1008 pim_ifchannel_update_my_assert_metric(ch
);
1010 } /* scan iface channel list */
1013 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
)
1015 struct listnode
*chnode
;
1016 struct listnode
*chnextnode
;
1017 struct pim_interface
*pim_ifp
;
1018 struct pim_ifchannel
*ch
;
1020 /* scan per-interface (S,G) state */
1021 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
))
1025 pim_ifp
= ch
->interface
->info
;
1029 pim_ifchannel_update_assert_tracking_desired(ch
);
1031 } /* scan iface channel list */
1034 /* When kat is stopped CouldRegister goes to false so we need to
1035 * transition the (S, G) on FHR to NI state and remove reg tunnel
1037 static void pim_upstream_fhr_kat_expiry(struct pim_upstream
*up
)
1039 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
1042 if (PIM_DEBUG_TRACE
)
1043 zlog_debug ("kat expired on %s; clear fhr reg state", up
->sg_str
);
1045 /* stop reg-stop timer */
1046 THREAD_OFF(up
->t_rs_timer
);
1047 /* remove regiface from the OIL if it is there*/
1048 pim_channel_del_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_PIM
);
1049 /* clear the register state */
1050 up
->reg_state
= PIM_REG_NOINFO
;
1051 PIM_UPSTREAM_FLAG_UNSET_FHR(up
->flags
);
1054 /* When kat is started CouldRegister can go to true. And if it does we
1055 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1057 static void pim_upstream_fhr_kat_start(struct pim_upstream
*up
)
1059 if (pim_upstream_could_register(up
)) {
1060 if (PIM_DEBUG_TRACE
)
1061 zlog_debug ("kat started on %s; set fhr reg state to joined", up
->sg_str
);
1063 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1064 if (up
->reg_state
== PIM_REG_NOINFO
)
1065 pim_register_join (up
);
1070 * On an RP, the PMBR value must be cleared when the
1071 * Keepalive Timer expires
1072 * KAT expiry indicates that flow is inactive. If the flow was created or
1073 * maintained by activity now is the time to deref it.
1076 pim_upstream_keep_alive_timer (struct thread
*t
)
1078 struct pim_upstream
*up
;
1081 up
->t_ka_timer
= NULL
;
1083 if (I_am_RP (up
->sg
.grp
))
1085 pim_br_clear_pmbr (&up
->sg
);
1087 * We need to do more here :)
1088 * But this is the start.
1092 /* source is no longer active - pull the SA from MSDP's cache */
1093 pim_msdp_sa_local_del(&up
->sg
);
1095 /* if entry was created because of activity we need to deref it */
1096 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
))
1098 pim_upstream_fhr_kat_expiry(up
);
1099 if (PIM_DEBUG_TRACE
)
1100 zlog_debug ("kat expired on %s; remove stream reference", up
->sg_str
);
1101 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up
->flags
);
1102 pim_upstream_del(up
, __PRETTY_FUNCTION__
);
1104 else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
))
1106 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1107 pim_upstream_del(up
, __PRETTY_FUNCTION__
);
1114 pim_upstream_keep_alive_timer_start (struct pim_upstream
*up
,
1117 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1118 if (PIM_DEBUG_TRACE
)
1119 zlog_debug ("kat start on %s with no stream reference", up
->sg_str
);
1121 THREAD_OFF (up
->t_ka_timer
);
1122 THREAD_TIMER_ON (master
,
1124 pim_upstream_keep_alive_timer
,
1127 /* any time keepalive is started against a SG we will have to
1128 * re-evaluate our active source database */
1129 pim_msdp_sa_local_update(up
);
1132 /* MSDP on RP needs to know if a source is registerable to this RP */
1134 pim_upstream_msdp_reg_timer(struct thread
*t
)
1136 struct pim_upstream
*up
;
1139 up
->t_msdp_reg_timer
= NULL
;
1141 /* source is no longer active - pull the SA from MSDP's cache */
1142 pim_msdp_sa_local_del(&up
->sg
);
1146 pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1148 THREAD_OFF(up
->t_msdp_reg_timer
);
1149 THREAD_TIMER_ON(master
, up
->t_msdp_reg_timer
,
1150 pim_upstream_msdp_reg_timer
, up
, PIM_MSDP_REG_RXED_PERIOD
);
1152 pim_msdp_sa_local_update(up
);
1156 * 4.2.1 Last-Hop Switchover to the SPT
1158 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1159 * RP. Once traffic from sources to joined groups arrives at a last-hop
1160 * router, it has the option of switching to receive the traffic on a
1161 * shortest path tree (SPT).
1163 * The decision for a router to switch to the SPT is controlled as
1167 * CheckSwitchToSpt(S,G) {
1168 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1169 * (+) pim_include(S,G) != NULL )
1170 * AND SwitchToSptDesired(S,G) ) {
1171 * # Note: Restarting the KAT will result in the SPT switch
1172 * set KeepaliveTimer(S,G) to Keepalive_Period
1176 * SwitchToSptDesired(S,G) is a policy function that is implementation
1177 * defined. An "infinite threshold" policy can be implemented by making
1178 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1179 * first packet" policy can be implemented by making
1180 * SwitchToSptDesired(S,G) return true once a single packet has been
1181 * received for the source and group.
1184 pim_upstream_switch_to_spt_desired (struct prefix_sg
*sg
)
1186 if (I_am_RP (sg
->grp
))
1193 pim_upstream_is_sg_rpt (struct pim_upstream
*up
)
1195 struct listnode
*chnode
;
1196 struct pim_ifchannel
*ch
;
1198 for (ALL_LIST_ELEMENTS_RO(up
->ifchannels
, chnode
, ch
))
1200 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1207 * After receiving a packet set SPTbit:
1209 * Update_SPTbit(S,G,iif) {
1210 * if ( iif == RPF_interface(S)
1211 * AND JoinDesired(S,G) == TRUE
1212 * AND ( DirectlyConnected(S) == TRUE
1213 * OR RPF_interface(S) != RPF_interface(RP(G))
1214 * OR inherited_olist(S,G,rpt) == NULL
1215 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1216 * ( RPF'(S,G) != NULL ) )
1217 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1218 * Set SPTbit(S,G) to TRUE
1223 pim_upstream_set_sptbit (struct pim_upstream
*up
, struct interface
*incoming
)
1225 struct pim_upstream
*starup
= up
->parent
;
1227 // iif == RPF_interfvace(S)
1228 if (up
->rpf
.source_nexthop
.interface
!= incoming
)
1230 if (PIM_DEBUG_TRACE
)
1231 zlog_debug ("%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1232 __PRETTY_FUNCTION__
, incoming
->name
, up
->rpf
.source_nexthop
.interface
->name
);
1236 // AND JoinDesired(S,G) == TRUE
1239 // DirectlyConnected(S) == TRUE
1240 if (pim_if_connected_to_source (up
->rpf
.source_nexthop
.interface
, up
->sg
.src
))
1242 if (PIM_DEBUG_TRACE
)
1243 zlog_debug ("%s: %s is directly connected to the source", __PRETTY_FUNCTION__
,
1245 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1249 // OR RPF_interface(S) != RPF_interface(RP(G))
1250 if (!starup
|| up
->rpf
.source_nexthop
.interface
!= starup
->rpf
.source_nexthop
.interface
)
1252 if (PIM_DEBUG_TRACE
)
1253 zlog_debug ("%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1254 __PRETTY_FUNCTION__
, up
->sg_str
);
1255 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1259 // OR inherited_olist(S,G,rpt) == NULL
1260 if (pim_upstream_is_sg_rpt(up
) && pim_upstream_empty_inherited_olist(up
))
1262 if (PIM_DEBUG_TRACE
)
1263 zlog_debug ("%s: %s OR inherited_olist(S,G,rpt) == NULL", __PRETTY_FUNCTION__
,
1265 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1269 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1270 // ( RPF'(S,G) != NULL ) )
1271 if (up
->parent
&& pim_rpf_is_same (&up
->rpf
, &up
->parent
->rpf
))
1273 if (PIM_DEBUG_TRACE
)
1274 zlog_debug ("%s: %s RPF'(S,G) is the same as RPF'(*,G)", __PRETTY_FUNCTION__
,
1276 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1284 pim_upstream_state2str (enum pim_upstream_state join_state
)
1288 case PIM_UPSTREAM_NOTJOINED
:
1291 case PIM_UPSTREAM_JOINED
:
1299 pim_reg_state2str (enum pim_reg_state reg_state
, char *state_str
)
1303 case PIM_REG_NOINFO
:
1304 strcpy (state_str
, "RegNoInfo");
1307 strcpy (state_str
, "RegJoined");
1309 case PIM_REG_JOIN_PENDING
:
1310 strcpy (state_str
, "RegJoinPend");
1313 strcpy (state_str
, "RegPrune");
1316 strcpy (state_str
, "RegUnknown");
1322 pim_upstream_register_stop_timer (struct thread
*t
)
1324 struct pim_interface
*pim_ifp
;
1325 struct pim_upstream
*up
;
1326 struct pim_rpf
*rpg
;
1328 up
= THREAD_ARG (t
);
1330 up
->t_rs_timer
= NULL
;
1332 if (PIM_DEBUG_TRACE
)
1334 char state_str
[PIM_REG_STATE_STR_LEN
];
1335 zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
1336 __PRETTY_FUNCTION__
, up
->sg_str
,
1337 pim_reg_state2str(up
->reg_state
, state_str
));
1340 switch (up
->reg_state
)
1342 case PIM_REG_JOIN_PENDING
:
1343 up
->reg_state
= PIM_REG_JOIN
;
1344 pim_channel_add_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_PIM
);
1349 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1352 if (PIM_DEBUG_TRACE
)
1353 zlog_debug ("%s: Interface: %s is not configured for pim",
1354 __PRETTY_FUNCTION__
, up
->rpf
.source_nexthop
.interface
->name
);
1357 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1358 pim_upstream_start_register_stop_timer (up
, 1);
1360 if (((up
->channel_oil
->cc
.lastused
/100) > PIM_KEEPALIVE_PERIOD
) &&
1361 (I_am_RP (up
->sg
.grp
)))
1363 if (PIM_DEBUG_TRACE
)
1364 zlog_debug ("%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while", __PRETTY_FUNCTION__
);
1367 rpg
= RP (up
->sg
.grp
);
1368 memset (&ip_hdr
, 0, sizeof (struct ip
));
1369 ip_hdr
.ip_p
= PIM_IP_PROTO_PIM
;
1372 ip_hdr
.ip_src
= up
->sg
.src
;
1373 ip_hdr
.ip_dst
= up
->sg
.grp
;
1374 ip_hdr
.ip_len
= htons (20);
1375 // checksum is broken
1376 pim_register_send ((uint8_t *)&ip_hdr
, sizeof (struct ip
),
1377 pim_ifp
->primary_address
, rpg
, 1, up
);
1387 pim_upstream_start_register_stop_timer (struct pim_upstream
*up
, int null_register
)
1393 THREAD_TIMER_OFF (up
->t_rs_timer
);
1394 up
->t_rs_timer
= NULL
;
1399 uint32_t lower
= (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1400 uint32_t upper
= (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1401 time
= lower
+ (random () % (upper
- lower
+ 1)) - PIM_REGISTER_PROBE_PERIOD
;
1404 time
= PIM_REGISTER_PROBE_PERIOD
;
1406 if (PIM_DEBUG_TRACE
)
1408 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
1409 __PRETTY_FUNCTION__
, up
->sg_str
, time
);
1411 THREAD_TIMER_ON (master
, up
->t_rs_timer
,
1412 pim_upstream_register_stop_timer
,
1417 pim_upstream_inherited_olist_decide (struct pim_upstream
*up
)
1419 struct interface
*ifp
;
1420 struct pim_interface
*pim_ifp
= NULL
;
1421 struct pim_ifchannel
*ch
, *starch
;
1422 struct listnode
*node
;
1423 struct pim_upstream
*starup
= up
->parent
;
1424 int output_intf
= 0;
1426 if (up
->rpf
.source_nexthop
.interface
)
1427 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1430 if (PIM_DEBUG_TRACE
)
1431 zlog_debug ("%s: up %s RPF is not present", __PRETTY_FUNCTION__
, up
->sg_str
);
1433 if (pim_ifp
&& !up
->channel_oil
)
1434 up
->channel_oil
= pim_channel_oil_add (&up
->sg
, pim_ifp
->mroute_vif_index
);
1436 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), node
, ifp
))
1441 ch
= pim_ifchannel_find (ifp
, &up
->sg
);
1444 starch
= pim_ifchannel_find (ifp
, &starup
->sg
);
1451 if (pim_upstream_evaluate_join_desired_interface (up
, ch
, starch
))
1453 int flag
= PIM_OIF_FLAG_PROTO_PIM
;
1456 flag
= PIM_OIF_FLAG_PROTO_STAR
;
1458 pim_channel_add_oif (up
->channel_oil
, ifp
, flag
);
1467 * For a given upstream, determine the inherited_olist
1470 * inherited_olist(S,G,rpt) =
1471 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1472 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1473 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1475 * inherited_olist(S,G) =
1476 * inherited_olist(S,G,rpt) (+)
1477 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1479 * return 1 if there are any output interfaces
1480 * return 0 if there are not any output interfaces
1483 pim_upstream_inherited_olist (struct pim_upstream
*up
)
1485 int output_intf
= pim_upstream_inherited_olist_decide (up
);
1488 * If we have output_intf switch state to Join and work like normal
1489 * If we don't have an output_intf that means we are probably a
1490 * switch on a stick so turn on forwarding to just accept the
1491 * incoming packets so we don't bother the other stuff!
1494 pim_upstream_switch (up
, PIM_UPSTREAM_JOINED
);
1502 pim_upstream_empty_inherited_olist (struct pim_upstream
*up
)
1504 return pim_channel_oil_empty (up
->channel_oil
);
1508 * When we have a new neighbor,
1509 * find upstreams that don't have their rpf_addr
1510 * set and see if the new neighbor allows
1511 * the join to be sent
1514 pim_upstream_find_new_rpf (void)
1516 struct listnode
*up_node
;
1517 struct listnode
*up_nextnode
;
1518 struct pim_upstream
*up
;
1521 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1523 for (ALL_LIST_ELEMENTS(pim_upstream_list
, up_node
, up_nextnode
, up
))
1525 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
))
1527 if (PIM_DEBUG_TRACE
)
1528 zlog_debug ("Upstream %s without a path to send join, checking",
1530 pim_rpf_update (up
, NULL
, 1);
1536 pim_upstream_hash_key (void *arg
)
1538 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1540 return jhash_2words (up
->sg
.src
.s_addr
, up
->sg
.grp
.s_addr
, 0);
1543 void pim_upstream_terminate (void)
1545 if (pim_upstream_list
)
1546 list_delete (pim_upstream_list
);
1547 pim_upstream_list
= NULL
;
1549 if (pim_upstream_hash
)
1550 hash_free (pim_upstream_hash
);
1551 pim_upstream_hash
= NULL
;
1555 pim_upstream_equal (const void *arg1
, const void *arg2
)
1557 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1558 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1560 if ((up1
->sg
.grp
.s_addr
== up2
->sg
.grp
.s_addr
) &&
1561 (up1
->sg
.src
.s_addr
== up2
->sg
.src
.s_addr
))
1567 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1568 * the cases where kat has to be restarted on rxing traffic -
1570 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1571 * set KeepaliveTimer(S,G) to Keepalive_Period
1572 * # Note: a register state transition or UpstreamJPState(S,G)
1573 * # transition may happen as a result of restarting
1574 * # KeepaliveTimer, and must be dealt with here.
1576 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1577 * inherited_olist(S,G) != NULL ) {
1578 * set KeepaliveTimer(S,G) to Keepalive_Period
1581 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1583 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1584 * so we will skip that here */
1585 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1590 if ((up
->join_state
== PIM_UPSTREAM_JOINED
) &&
1591 !pim_upstream_empty_inherited_olist(up
)) {
1592 /* XXX: I have added this RP check just for 3.2 and it's a digression from
1593 * what rfc-4601 says. Till now we were only running KAT on FHR and RP and
1594 * there is some angst around making the change to run it all routers that
1595 * maintain the (S, G) state. This is tracked via CM-13601 and MUST be
1596 * removed to handle spt turn-arounds correctly in a 3-tier clos */
1597 if (I_am_RP (up
->sg
.grp
))
1605 * Code to check and see if we've received packets on a S,G mroute
1606 * and if so to set the SPT bit appropriately
1609 pim_upstream_sg_running (void *arg
)
1611 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1613 // No packet can have arrived here if this is the case
1614 if (!up
->channel_oil
|| !up
->channel_oil
->installed
)
1616 if (PIM_DEBUG_TRACE
)
1617 zlog_debug ("%s: %s is not installed in mroute",
1618 __PRETTY_FUNCTION__
, up
->sg_str
);
1623 * This is a bit of a hack
1624 * We've noted that we should rescan but
1625 * we've missed the window for doing so in
1626 * pim_zebra.c for some reason. I am
1627 * only doing this at this point in time
1628 * to get us up and working for the moment
1630 if (up
->channel_oil
->oil_inherited_rescan
)
1632 if (PIM_DEBUG_TRACE
)
1633 zlog_debug ("%s: Handling unscanned inherited_olist for %s", __PRETTY_FUNCTION__
, up
->sg_str
);
1634 pim_upstream_inherited_olist_decide (up
);
1635 up
->channel_oil
->oil_inherited_rescan
= 0;
1637 pim_mroute_update_counters (up
->channel_oil
);
1639 // Have we seen packets?
1640 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
) &&
1641 (up
->channel_oil
->cc
.lastused
/100 > 30))
1643 if (PIM_DEBUG_TRACE
)
1645 zlog_debug ("%s: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1646 __PRETTY_FUNCTION__
, up
->sg_str
,
1647 up
->channel_oil
->cc
.oldpktcnt
,
1648 up
->channel_oil
->cc
.pktcnt
,
1649 up
->channel_oil
->cc
.lastused
/100);
1654 if (pim_upstream_kat_start_ok(up
))
1656 /* Add a source reference to the stream if
1657 * one doesn't already exist */
1658 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
))
1660 if (PIM_DEBUG_TRACE
)
1661 zlog_debug ("source reference created on kat restart %s", up
->sg_str
);
1663 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
);
1664 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
1665 pim_upstream_fhr_kat_start(up
);
1667 pim_upstream_keep_alive_timer_start(up
, qpim_keep_alive_time
);
1669 else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
))
1670 pim_upstream_keep_alive_timer_start(up
, qpim_keep_alive_time
);
1672 if (up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
)
1674 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
1680 pim_upstream_add_lhr_star_pimreg (void)
1682 struct pim_upstream
*up
;
1683 struct listnode
*node
;
1685 for (ALL_LIST_ELEMENTS_RO (pim_upstream_list
, node
, up
))
1687 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1690 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up
->flags
))
1693 pim_channel_add_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_IGMP
);
1698 pim_upstream_spt_prefix_list_update (struct prefix_list
*pl
)
1700 const char *pname
= prefix_list_name (pl
);
1702 if (pimg
->spt
.plist
&& strcmp (pimg
->spt
.plist
, pname
) == 0)
1704 pim_upstream_remove_lhr_star_pimreg (pname
);
1709 * nlist -> The new prefix list
1711 * Per Group Application of pimreg to the OIL
1712 * If the prefix list tells us DENY then
1713 * we need to Switchover to SPT immediate
1714 * so add the pimreg.
1715 * If the prefix list tells us to ACCEPT than
1716 * we need to Never do the SPT so remove
1721 pim_upstream_remove_lhr_star_pimreg (const char *nlist
)
1723 struct pim_upstream
*up
;
1724 struct listnode
*node
;
1725 struct prefix_list
*np
;
1727 enum prefix_list_type apply_new
;
1729 np
= prefix_list_lookup (AFI_IP
, nlist
);
1732 g
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1734 for (ALL_LIST_ELEMENTS_RO (pim_upstream_list
, node
, up
))
1736 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1739 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up
->flags
))
1744 pim_channel_del_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_IGMP
);
1747 g
.u
.prefix4
= up
->sg
.grp
;
1748 apply_new
= prefix_list_apply (np
, &g
);
1749 if (apply_new
== PREFIX_DENY
)
1750 pim_channel_add_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_IGMP
);
1752 pim_channel_del_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_IGMP
);
1757 pim_upstream_init (void)
1759 pim_upstream_sg_wheel
= wheel_init (master
, 31000, 100,
1760 pim_upstream_hash_key
,
1761 pim_upstream_sg_running
);
1762 pim_upstream_hash
= hash_create_size (8192, pim_upstream_hash_key
,
1763 pim_upstream_equal
);
1765 pim_upstream_list
= list_new ();
1766 pim_upstream_list
->del
= (void (*)(void *)) pim_upstream_free
;
1767 pim_upstream_list
->cmp
= pim_upstream_compare
;