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 (Pre decrement)",
166 __PRETTY_FUNCTION__
, name
, up
->sg_str
, up
->ref_count
, up
->flags
);
170 if (up
->ref_count
>= 1)
173 THREAD_OFF(up
->t_ka_timer
);
174 THREAD_OFF(up
->t_rs_timer
);
175 THREAD_OFF(up
->t_msdp_reg_timer
);
177 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
178 pim_jp_agg_single_upstream_send (&up
->rpf
, up
, 0);
180 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
181 /* if a (*, G) entry in the joined state is being deleted we
182 * need to notify MSDP */
188 pim_jp_agg_upstream_verification (up
, false);
189 up
->rpf
.source_nexthop
.interface
= NULL
;
191 if (up
->sg
.src
.s_addr
!= INADDR_ANY
) {
192 wheel_remove_item (pim_upstream_sg_wheel
, up
);
196 pim_upstream_remove_children (up
);
197 pim_mroute_del (up
->channel_oil
, __PRETTY_FUNCTION__
);
198 upstream_channel_oil_detach(up
);
202 struct listnode
*node
, *nnode
;
203 struct pim_upstream
*child
;
204 for (ALL_LIST_ELEMENTS (up
->sources
, node
, nnode
, child
))
206 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child
->flags
))
208 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child
->flags
);
209 pim_upstream_del(child
, __PRETTY_FUNCTION__
);
213 list_delete (up
->sources
);
218 notice that listnode_delete() can't be moved
219 into pim_upstream_free() because the later is
220 called by list_delete_all_node()
224 listnode_delete (up
->parent
->sources
, up
);
227 listnode_delete (pim_upstream_list
, up
);
228 hash_release (pim_upstream_hash
, up
);
232 pim_msdp_up_del (&up
->sg
);
235 /* Deregister addr with Zebra NHT */
236 nht_p
.family
= AF_INET
;
237 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
238 nht_p
.u
.prefix4
= up
->upstream_addr
;
241 char buf
[PREFIX2STR_BUFFER
];
242 prefix2str (&nht_p
, buf
, sizeof (buf
));
243 zlog_debug ("%s: Deregister upstream %s addr %s with Zebra",
244 __PRETTY_FUNCTION__
, up
->sg_str
, buf
);
246 pim_delete_tracked_nexthop (&nht_p
, up
, NULL
);
248 pim_upstream_free (up
);
254 pim_upstream_send_join (struct pim_upstream
*up
)
256 if (PIM_DEBUG_TRACE
) {
257 char rpf_str
[PREFIX_STRLEN
];
258 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_str
, sizeof(rpf_str
));
259 zlog_debug ("%s: RPF'%s=%s(%s) for Interface %s", __PRETTY_FUNCTION__
,
260 up
->sg_str
, rpf_str
, pim_upstream_state2str (up
->join_state
),
261 up
->rpf
.source_nexthop
.interface
->name
);
262 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
263 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
265 up
->sg_str
, rpf_str
);
270 /* send Join(S,G) to the current upstream neighbor */
271 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 1 /* join */);
274 static int on_join_timer(struct thread
*t
)
276 struct pim_upstream
*up
;
280 up
->t_join_timer
= NULL
;
283 * In the case of a HFR we will not ahve anyone to send this to.
285 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
289 * Don't send the join if the outgoing interface is a loopback
290 * But since this might change leave the join timer running
292 if (up
->rpf
.source_nexthop
.interface
&&
293 !if_is_loopback (up
->rpf
.source_nexthop
.interface
))
294 pim_upstream_send_join (up
);
296 join_timer_start(up
);
301 static void join_timer_stop(struct pim_upstream
*up
)
303 struct pim_neighbor
*nbr
;
305 THREAD_OFF (up
->t_join_timer
);
307 nbr
= pim_neighbor_find (up
->rpf
.source_nexthop
.interface
,
308 up
->rpf
.rpf_addr
.u
.prefix4
);
311 pim_jp_agg_remove_group (nbr
->upstream_jp_agg
, up
);
313 pim_jp_agg_upstream_verification (up
, false);
317 join_timer_start(struct pim_upstream
*up
)
319 struct pim_neighbor
*nbr
= NULL
;
321 if (up
->rpf
.source_nexthop
.interface
)
323 nbr
= pim_neighbor_find (up
->rpf
.source_nexthop
.interface
,
324 up
->rpf
.rpf_addr
.u
.prefix4
);
326 if (PIM_DEBUG_PIM_EVENTS
) {
327 zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s",
335 pim_jp_agg_add_group (nbr
->upstream_jp_agg
, up
, 1);
338 THREAD_OFF (up
->t_join_timer
);
339 THREAD_TIMER_ON(master
, up
->t_join_timer
,
341 up
, qpim_t_periodic
);
343 pim_jp_agg_upstream_verification (up
, true);
347 * This is only called when we are switching the upstream
348 * J/P from one neighbor to another
350 * As such we need to remove from the old list and
351 * add to the new list.
353 void pim_upstream_join_timer_restart(struct pim_upstream
*up
, struct pim_rpf
*old
)
355 //THREAD_OFF(up->t_join_timer);
356 join_timer_start(up
);
359 static void pim_upstream_join_timer_restart_msec(struct pim_upstream
*up
,
362 if (PIM_DEBUG_PIM_EVENTS
) {
363 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
369 THREAD_OFF(up
->t_join_timer
);
370 THREAD_TIMER_MSEC_ON(master
, up
->t_join_timer
,
375 void pim_upstream_join_suppress(struct pim_upstream
*up
,
376 struct in_addr rpf_addr
,
379 long t_joinsuppress_msec
;
380 long join_timer_remain_msec
;
382 t_joinsuppress_msec
= MIN(pim_if_t_suppressed_msec(up
->rpf
.source_nexthop
.interface
),
385 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
387 if (PIM_DEBUG_TRACE
) {
388 char rpf_str
[INET_ADDRSTRLEN
];
389 pim_inet4_dump("<rpf?>", rpf_addr
, rpf_str
, sizeof(rpf_str
));
390 zlog_debug("%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
391 __FILE__
, __PRETTY_FUNCTION__
,
394 join_timer_remain_msec
, t_joinsuppress_msec
);
397 if (join_timer_remain_msec
< t_joinsuppress_msec
) {
398 if (PIM_DEBUG_TRACE
) {
399 zlog_debug("%s %s: suppressing Join(S,G)=%s for %ld msec",
400 __FILE__
, __PRETTY_FUNCTION__
,
401 up
->sg_str
, t_joinsuppress_msec
);
404 pim_upstream_join_timer_restart_msec(up
, t_joinsuppress_msec
);
408 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label
,
409 struct pim_upstream
*up
)
411 long join_timer_remain_msec
;
414 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
415 t_override_msec
= pim_if_t_override_msec(up
->rpf
.source_nexthop
.interface
);
417 if (PIM_DEBUG_TRACE
) {
418 char rpf_str
[INET_ADDRSTRLEN
];
419 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
.u
.prefix4
, rpf_str
, sizeof(rpf_str
));
420 zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
423 join_timer_remain_msec
, t_override_msec
);
426 if (join_timer_remain_msec
> t_override_msec
) {
427 if (PIM_DEBUG_TRACE
) {
428 zlog_debug("%s: decreasing (S,G)=%s join timer to t_override=%d msec",
434 pim_upstream_join_timer_restart_msec(up
, t_override_msec
);
438 static void forward_on(struct pim_upstream
*up
)
440 struct listnode
*chnode
;
441 struct listnode
*chnextnode
;
442 struct pim_interface
*pim_ifp
;
443 struct pim_ifchannel
*ch
;
445 /* scan (S,G) state */
446 for (ALL_LIST_ELEMENTS(pim_ifchannel_list
, chnode
, chnextnode
, ch
)) {
447 pim_ifp
= ch
->interface
->info
;
451 if (ch
->upstream
!= up
)
454 if (pim_macro_chisin_oiflist(ch
))
455 pim_forward_start(ch
);
457 } /* scan iface channel list */
460 static void forward_off(struct pim_upstream
*up
)
462 struct listnode
*chnode
;
463 struct listnode
*chnextnode
;
464 struct pim_interface
*pim_ifp
;
465 struct pim_ifchannel
*ch
;
467 /* scan per-interface (S,G) state */
468 for (ALL_LIST_ELEMENTS(pim_ifchannel_list
, chnode
, chnextnode
, ch
)) {
469 pim_ifp
= ch
->interface
->info
;
473 if (ch
->upstream
!= up
)
476 pim_forward_stop(ch
);
478 } /* scan iface channel list */
482 pim_upstream_could_register (struct pim_upstream
*up
)
484 struct pim_interface
*pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
486 if (pim_ifp
&& PIM_I_am_DR (pim_ifp
) &&
487 pim_if_connected_to_source (up
->rpf
.source_nexthop
.interface
, up
->sg
.src
))
493 /* Source registration is supressed for SSM groups. When the SSM range changes
494 * we re-revaluate register setup for existing upstream entries */
496 pim_upstream_register_reevaluate (void)
498 struct listnode
*upnode
;
499 struct pim_upstream
*up
;
501 for (ALL_LIST_ELEMENTS_RO (pim_upstream_list
, upnode
, up
))
503 /* If FHR is set CouldRegister is True. Also check if the flow
504 * is actually active; if it is not kat setup will trigger source
505 * registration whenever the flow becomes active. */
506 if (!PIM_UPSTREAM_FLAG_TEST_FHR (up
->flags
) || !up
->t_ka_timer
)
509 if (pim_is_grp_ssm (up
->sg
.grp
))
511 /* clear the register state for SSM groups */
512 if (up
->reg_state
!= PIM_REG_NOINFO
)
514 if (PIM_DEBUG_PIM_EVENTS
)
515 zlog_debug ("Clear register for %s as G is now SSM",
517 /* remove regiface from the OIL if it is there*/
518 pim_channel_del_oif (up
->channel_oil
, pim_regiface
,
519 PIM_OIF_FLAG_PROTO_PIM
);
520 up
->reg_state
= PIM_REG_NOINFO
;
525 /* register ASM sources with the RP */
526 if (up
->reg_state
== PIM_REG_NOINFO
)
528 if (PIM_DEBUG_PIM_EVENTS
)
529 zlog_debug ("Register %s as G is now ASM", up
->sg_str
);
530 pim_channel_add_oif (up
->channel_oil
, pim_regiface
,
531 PIM_OIF_FLAG_PROTO_PIM
);
532 up
->reg_state
= PIM_REG_JOIN
;
539 pim_upstream_switch(struct pim_upstream
*up
,
540 enum pim_upstream_state new_state
)
542 enum pim_upstream_state old_state
= up
->join_state
;
544 if (PIM_DEBUG_PIM_EVENTS
) {
545 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
548 pim_upstream_state2str (up
->join_state
),
549 pim_upstream_state2str (new_state
));
552 up
->join_state
= new_state
;
553 if (old_state
!= new_state
)
554 up
->state_transition
= pim_time_monotonic_sec();
556 pim_upstream_update_assert_tracking_desired(up
);
558 if (new_state
== PIM_UPSTREAM_JOINED
) {
559 if (old_state
!= PIM_UPSTREAM_JOINED
)
561 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
563 pim_msdp_up_join_state_changed(up
);
564 if (pim_upstream_could_register (up
))
566 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
567 if (!old_fhr
&& PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
))
569 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
570 pim_register_join (up
);
575 pim_upstream_send_join (up
);
576 join_timer_start (up
);
587 if (old_state
== PIM_UPSTREAM_JOINED
)
588 pim_msdp_up_join_state_changed(up
);
590 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 0 /* prune */);
596 pim_upstream_compare (void *arg1
, void *arg2
)
598 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
599 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
601 if (ntohl(up1
->sg
.grp
.s_addr
) < ntohl(up2
->sg
.grp
.s_addr
))
604 if (ntohl(up1
->sg
.grp
.s_addr
) > ntohl(up2
->sg
.grp
.s_addr
))
607 if (ntohl(up1
->sg
.src
.s_addr
) < ntohl(up2
->sg
.src
.s_addr
))
610 if (ntohl(up1
->sg
.src
.s_addr
) > ntohl(up2
->sg
.src
.s_addr
))
616 static struct pim_upstream
*
617 pim_upstream_new (struct prefix_sg
*sg
,
618 struct interface
*incoming
,
621 enum pim_rpf_result rpf_result
;
622 struct pim_interface
*pim_ifp
;
623 struct pim_upstream
*up
;
625 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
628 zlog_err("%s: PIM XCALLOC(%zu) failure",
629 __PRETTY_FUNCTION__
, sizeof(*up
));
634 pim_str_sg_set (sg
, up
->sg_str
);
635 up
= hash_get (pim_upstream_hash
, up
, hash_alloc_intern
);
636 if (!pim_rp_set_upstream_addr (&up
->upstream_addr
, sg
->src
, sg
->grp
))
639 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__
);
641 hash_release (pim_upstream_hash
, up
);
642 XFREE (MTYPE_PIM_UPSTREAM
, up
);
646 up
->parent
= pim_upstream_find_parent (up
);
647 if (up
->sg
.src
.s_addr
== INADDR_ANY
)
649 up
->sources
= list_new ();
650 up
->sources
->cmp
= pim_upstream_compare
;
655 pim_upstream_find_new_children (up
);
658 up
->t_join_timer
= NULL
;
659 up
->t_ka_timer
= NULL
;
660 up
->t_rs_timer
= NULL
;
661 up
->t_msdp_reg_timer
= NULL
;
662 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
663 up
->reg_state
= PIM_REG_NOINFO
;
664 up
->state_transition
= pim_time_monotonic_sec();
665 up
->channel_oil
= NULL
;
666 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
668 up
->rpf
.source_nexthop
.interface
= NULL
;
669 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
670 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
671 up
->rpf
.source_nexthop
.mrib_metric_preference
= qpim_infinite_assert_metric
.metric_preference
;
672 up
->rpf
.source_nexthop
.mrib_route_metric
= qpim_infinite_assert_metric
.route_metric
;
673 up
->rpf
.rpf_addr
.family
= AF_INET
;
674 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
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 pim_upstream_evaluate_join_desired_interface (struct pim_upstream
*up
,
805 struct pim_ifchannel
*ch
)
807 struct pim_upstream
*parent
= up
->parent
;
809 if (ch
->upstream
== up
)
811 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
814 if (!pim_macro_ch_lost_assert(ch
) && pim_macro_chisin_joins_or_include(ch
))
821 if (parent
&& ch
->upstream
== parent
)
823 struct listnode
*ch_node
;
824 struct pim_ifchannel
*child
;
825 for (ALL_LIST_ELEMENTS_RO (ch
->sources
, ch_node
, child
))
827 if (child
->upstream
== up
)
829 if (PIM_IF_FLAG_TEST_S_G_RPT(child
->flags
))
833 if (!pim_macro_ch_lost_assert (ch
) && pim_macro_chisin_joins_or_include (ch
))
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_upstream
*up
)
865 struct listnode
*chnode
;
866 struct listnode
*chnextnode
;
867 struct pim_interface
*pim_ifp
;
868 struct pim_ifchannel
*ch
;
871 /* scan per-interface (S,G) state */
872 for (ALL_LIST_ELEMENTS(pim_ifchannel_list
, chnode
, chnextnode
, ch
))
874 pim_ifp
= ch
->interface
->info
;
878 ret
+= pim_upstream_evaluate_join_desired_interface (up
, ch
);
879 } /* scan iface channel list */
881 return ret
; /* false */
885 See also pim_upstream_evaluate_join_desired() above.
887 void pim_upstream_update_join_desired(struct pim_upstream
*up
)
889 int was_join_desired
; /* boolean */
890 int is_join_desired
; /* boolean */
892 was_join_desired
= PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up
->flags
);
894 is_join_desired
= pim_upstream_evaluate_join_desired(up
);
896 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up
->flags
);
898 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up
->flags
);
900 /* switched from false to true */
901 if (is_join_desired
&& !was_join_desired
) {
902 pim_upstream_switch(up
, PIM_UPSTREAM_JOINED
);
906 /* switched from true to false */
907 if (!is_join_desired
&& was_join_desired
) {
908 pim_upstream_switch(up
, PIM_UPSTREAM_NOTJOINED
);
914 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
915 Transitions from Joined State
916 RPF'(S,G) GenID changes
918 The upstream (S,G) state machine remains in Joined state. If the
919 Join Timer is set to expire in more than t_override seconds, reset
920 it so that it expires after t_override seconds.
922 void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr
)
924 struct listnode
*up_node
;
925 struct listnode
*up_nextnode
;
926 struct pim_upstream
*up
;
929 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
931 for (ALL_LIST_ELEMENTS(pim_upstream_list
, up_node
, up_nextnode
, up
)) {
933 if (PIM_DEBUG_TRACE
) {
934 char neigh_str
[INET_ADDRSTRLEN
];
935 char rpf_addr_str
[PREFIX_STRLEN
];
936 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
, sizeof(neigh_str
));
937 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_addr_str
, sizeof(rpf_addr_str
));
938 zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
940 neigh_str
, up
->sg_str
,
941 up
->join_state
== PIM_UPSTREAM_JOINED
,
945 /* consider only (S,G) upstream in Joined state */
946 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
949 /* match RPF'(S,G)=neigh_addr */
950 if (up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
!= neigh_addr
.s_addr
)
953 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
959 void pim_upstream_rpf_interface_changed(struct pim_upstream
*up
,
960 struct interface
*old_rpf_ifp
)
962 struct listnode
*chnode
;
963 struct listnode
*chnextnode
;
964 struct pim_ifchannel
*ch
;
965 struct pim_interface
*pim_ifp
;
967 /* search all ifchannels */
968 for (ALL_LIST_ELEMENTS(pim_ifchannel_list
, chnode
, chnextnode
, ch
)) {
970 pim_ifp
= ch
->interface
->info
;
974 if (ch
->upstream
!= up
)
977 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
979 /* RPF_interface(S) was NOT I */
980 (old_rpf_ifp
== ch
->interface
)
982 /* RPF_interface(S) stopped being I */
983 (ch
->upstream
->rpf
.source_nexthop
.interface
!= ch
->interface
)
985 assert_action_a5(ch
);
987 } /* PIM_IFASSERT_I_AM_LOSER */
989 pim_ifchannel_update_assert_tracking_desired(ch
);
993 void pim_upstream_update_could_assert(struct pim_upstream
*up
)
995 struct listnode
*chnode
;
996 struct listnode
*chnextnode
;
997 struct pim_interface
*pim_ifp
;
998 struct pim_ifchannel
*ch
;
1000 /* scan per-interface (S,G) state */
1001 for (ALL_LIST_ELEMENTS(pim_ifchannel_list
, chnode
, chnextnode
, ch
)) {
1002 pim_ifp
= ch
->interface
->info
;
1006 if (ch
->upstream
!= up
)
1009 pim_ifchannel_update_could_assert(ch
);
1010 } /* scan iface channel list */
1013 void pim_upstream_update_my_assert_metric(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(pim_ifchannel_list
, chnode
, chnextnode
, ch
)) {
1022 pim_ifp
= ch
->interface
->info
;
1026 if (ch
->upstream
!= up
)
1029 pim_ifchannel_update_my_assert_metric(ch
);
1031 } /* scan iface channel list */
1034 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
)
1036 struct listnode
*chnode
;
1037 struct listnode
*chnextnode
;
1038 struct pim_interface
*pim_ifp
;
1039 struct pim_ifchannel
*ch
;
1041 /* scan per-interface (S,G) state */
1042 for (ALL_LIST_ELEMENTS(pim_ifchannel_list
, chnode
, chnextnode
, ch
)) {
1043 pim_ifp
= ch
->interface
->info
;
1047 if (ch
->upstream
!= up
)
1050 pim_ifchannel_update_assert_tracking_desired(ch
);
1052 } /* scan iface channel list */
1055 /* When kat is stopped CouldRegister goes to false so we need to
1056 * transition the (S, G) on FHR to NI state and remove reg tunnel
1058 static void pim_upstream_fhr_kat_expiry(struct pim_upstream
*up
)
1060 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
1063 if (PIM_DEBUG_TRACE
)
1064 zlog_debug ("kat expired on %s; clear fhr reg state", up
->sg_str
);
1066 /* stop reg-stop timer */
1067 THREAD_OFF(up
->t_rs_timer
);
1068 /* remove regiface from the OIL if it is there*/
1069 pim_channel_del_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_PIM
);
1070 /* clear the register state */
1071 up
->reg_state
= PIM_REG_NOINFO
;
1072 PIM_UPSTREAM_FLAG_UNSET_FHR(up
->flags
);
1075 /* When kat is started CouldRegister can go to true. And if it does we
1076 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1078 static void pim_upstream_fhr_kat_start(struct pim_upstream
*up
)
1080 if (pim_upstream_could_register(up
)) {
1081 if (PIM_DEBUG_TRACE
)
1082 zlog_debug ("kat started on %s; set fhr reg state to joined", up
->sg_str
);
1084 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1085 if (up
->reg_state
== PIM_REG_NOINFO
)
1086 pim_register_join (up
);
1091 * On an RP, the PMBR value must be cleared when the
1092 * Keepalive Timer expires
1093 * KAT expiry indicates that flow is inactive. If the flow was created or
1094 * maintained by activity now is the time to deref it.
1097 pim_upstream_keep_alive_timer (struct thread
*t
)
1099 struct pim_upstream
*up
;
1102 up
->t_ka_timer
= NULL
;
1104 if (I_am_RP (up
->sg
.grp
))
1106 pim_br_clear_pmbr (&up
->sg
);
1108 * We need to do more here :)
1109 * But this is the start.
1113 /* source is no longer active - pull the SA from MSDP's cache */
1114 pim_msdp_sa_local_del(&up
->sg
);
1116 /* if entry was created because of activity we need to deref it */
1117 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
))
1119 pim_upstream_fhr_kat_expiry(up
);
1120 if (PIM_DEBUG_TRACE
)
1121 zlog_debug ("kat expired on %s; remove stream reference", up
->sg_str
);
1122 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up
->flags
);
1123 pim_upstream_del(up
, __PRETTY_FUNCTION__
);
1125 else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
))
1127 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1128 pim_upstream_del(up
, __PRETTY_FUNCTION__
);
1135 pim_upstream_keep_alive_timer_start (struct pim_upstream
*up
,
1138 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1139 if (PIM_DEBUG_TRACE
)
1140 zlog_debug ("kat start on %s with no stream reference", up
->sg_str
);
1142 THREAD_OFF (up
->t_ka_timer
);
1143 THREAD_TIMER_ON (master
,
1145 pim_upstream_keep_alive_timer
,
1148 /* any time keepalive is started against a SG we will have to
1149 * re-evaluate our active source database */
1150 pim_msdp_sa_local_update(up
);
1153 /* MSDP on RP needs to know if a source is registerable to this RP */
1155 pim_upstream_msdp_reg_timer(struct thread
*t
)
1157 struct pim_upstream
*up
;
1160 up
->t_msdp_reg_timer
= NULL
;
1162 /* source is no longer active - pull the SA from MSDP's cache */
1163 pim_msdp_sa_local_del(&up
->sg
);
1167 pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1169 THREAD_OFF(up
->t_msdp_reg_timer
);
1170 THREAD_TIMER_ON(master
, up
->t_msdp_reg_timer
,
1171 pim_upstream_msdp_reg_timer
, up
, PIM_MSDP_REG_RXED_PERIOD
);
1173 pim_msdp_sa_local_update(up
);
1177 * 4.2.1 Last-Hop Switchover to the SPT
1179 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1180 * RP. Once traffic from sources to joined groups arrives at a last-hop
1181 * router, it has the option of switching to receive the traffic on a
1182 * shortest path tree (SPT).
1184 * The decision for a router to switch to the SPT is controlled as
1188 * CheckSwitchToSpt(S,G) {
1189 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1190 * (+) pim_include(S,G) != NULL )
1191 * AND SwitchToSptDesired(S,G) ) {
1192 * # Note: Restarting the KAT will result in the SPT switch
1193 * set KeepaliveTimer(S,G) to Keepalive_Period
1197 * SwitchToSptDesired(S,G) is a policy function that is implementation
1198 * defined. An "infinite threshold" policy can be implemented by making
1199 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1200 * first packet" policy can be implemented by making
1201 * SwitchToSptDesired(S,G) return true once a single packet has been
1202 * received for the source and group.
1205 pim_upstream_switch_to_spt_desired (struct prefix_sg
*sg
)
1207 if (I_am_RP (sg
->grp
))
1214 pim_upstream_is_sg_rpt (struct pim_upstream
*up
)
1216 struct listnode
*chnode
;
1217 struct pim_ifchannel
*ch
;
1219 for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list
, chnode
, ch
))
1221 if ((ch
->upstream
== up
) &&
1222 (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
)))
1229 * After receiving a packet set SPTbit:
1231 * Update_SPTbit(S,G,iif) {
1232 * if ( iif == RPF_interface(S)
1233 * AND JoinDesired(S,G) == TRUE
1234 * AND ( DirectlyConnected(S) == TRUE
1235 * OR RPF_interface(S) != RPF_interface(RP(G))
1236 * OR inherited_olist(S,G,rpt) == NULL
1237 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1238 * ( RPF'(S,G) != NULL ) )
1239 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1240 * Set SPTbit(S,G) to TRUE
1245 pim_upstream_set_sptbit (struct pim_upstream
*up
, struct interface
*incoming
)
1247 struct pim_rpf
*grpf
= NULL
;
1249 // iif == RPF_interfvace(S)
1250 if (up
->rpf
.source_nexthop
.interface
!= incoming
)
1252 if (PIM_DEBUG_TRACE
)
1253 zlog_debug ("%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1254 __PRETTY_FUNCTION__
, incoming
->name
, up
->rpf
.source_nexthop
.interface
->name
);
1258 // AND JoinDesired(S,G) == TRUE
1261 // DirectlyConnected(S) == TRUE
1262 if (pim_if_connected_to_source (up
->rpf
.source_nexthop
.interface
, up
->sg
.src
))
1264 if (PIM_DEBUG_TRACE
)
1265 zlog_debug ("%s: %s is directly connected to the source", __PRETTY_FUNCTION__
,
1267 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1271 // OR RPF_interface(S) != RPF_interface(RP(G))
1272 grpf
= RP(up
->sg
.grp
);
1273 if (!grpf
|| up
->rpf
.source_nexthop
.interface
!= grpf
->source_nexthop
.interface
)
1275 if (PIM_DEBUG_TRACE
)
1276 zlog_debug ("%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1277 __PRETTY_FUNCTION__
, up
->sg_str
);
1278 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1282 // OR inherited_olist(S,G,rpt) == NULL
1283 if (pim_upstream_is_sg_rpt(up
) && pim_upstream_empty_inherited_olist(up
))
1285 if (PIM_DEBUG_TRACE
)
1286 zlog_debug ("%s: %s OR inherited_olist(S,G,rpt) == NULL", __PRETTY_FUNCTION__
,
1288 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1292 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1293 // ( RPF'(S,G) != NULL ) )
1294 if (up
->parent
&& pim_rpf_is_same (&up
->rpf
, &up
->parent
->rpf
))
1296 if (PIM_DEBUG_TRACE
)
1297 zlog_debug ("%s: %s RPF'(S,G) is the same as RPF'(*,G)", __PRETTY_FUNCTION__
,
1299 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1307 pim_upstream_state2str (enum pim_upstream_state join_state
)
1311 case PIM_UPSTREAM_NOTJOINED
:
1314 case PIM_UPSTREAM_JOINED
:
1322 pim_reg_state2str (enum pim_reg_state reg_state
, char *state_str
)
1326 case PIM_REG_NOINFO
:
1327 strcpy (state_str
, "RegNoInfo");
1330 strcpy (state_str
, "RegJoined");
1332 case PIM_REG_JOIN_PENDING
:
1333 strcpy (state_str
, "RegJoinPend");
1336 strcpy (state_str
, "RegPrune");
1339 strcpy (state_str
, "RegUnknown");
1345 pim_upstream_register_stop_timer (struct thread
*t
)
1347 struct pim_interface
*pim_ifp
;
1348 struct pim_upstream
*up
;
1349 struct pim_rpf
*rpg
;
1351 up
= THREAD_ARG (t
);
1353 up
->t_rs_timer
= NULL
;
1355 if (PIM_DEBUG_TRACE
)
1357 char state_str
[PIM_REG_STATE_STR_LEN
];
1358 zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
1359 __PRETTY_FUNCTION__
, up
->sg_str
,
1360 pim_reg_state2str(up
->reg_state
, state_str
));
1363 switch (up
->reg_state
)
1365 case PIM_REG_JOIN_PENDING
:
1366 up
->reg_state
= PIM_REG_JOIN
;
1367 pim_channel_add_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_PIM
);
1372 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1375 if (PIM_DEBUG_TRACE
)
1376 zlog_debug ("%s: Interface: %s is not configured for pim",
1377 __PRETTY_FUNCTION__
, up
->rpf
.source_nexthop
.interface
->name
);
1380 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1381 pim_upstream_start_register_stop_timer (up
, 1);
1383 if (((up
->channel_oil
->cc
.lastused
/100) > PIM_KEEPALIVE_PERIOD
) &&
1384 (I_am_RP (up
->sg
.grp
)))
1386 if (PIM_DEBUG_TRACE
)
1387 zlog_debug ("%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while", __PRETTY_FUNCTION__
);
1390 rpg
= RP (up
->sg
.grp
);
1391 memset (&ip_hdr
, 0, sizeof (struct ip
));
1392 ip_hdr
.ip_p
= PIM_IP_PROTO_PIM
;
1395 ip_hdr
.ip_src
= up
->sg
.src
;
1396 ip_hdr
.ip_dst
= up
->sg
.grp
;
1397 ip_hdr
.ip_len
= htons (20);
1398 // checksum is broken
1399 pim_register_send ((uint8_t *)&ip_hdr
, sizeof (struct ip
),
1400 pim_ifp
->primary_address
, rpg
, 1, up
);
1410 pim_upstream_start_register_stop_timer (struct pim_upstream
*up
, int null_register
)
1416 THREAD_TIMER_OFF (up
->t_rs_timer
);
1417 up
->t_rs_timer
= NULL
;
1422 uint32_t lower
= (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1423 uint32_t upper
= (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1424 time
= lower
+ (random () % (upper
- lower
+ 1)) - PIM_REGISTER_PROBE_PERIOD
;
1427 time
= PIM_REGISTER_PROBE_PERIOD
;
1429 if (PIM_DEBUG_TRACE
)
1431 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
1432 __PRETTY_FUNCTION__
, up
->sg_str
, time
);
1434 THREAD_TIMER_ON (master
, up
->t_rs_timer
,
1435 pim_upstream_register_stop_timer
,
1440 pim_upstream_inherited_olist_decide (struct pim_upstream
*up
)
1442 struct pim_interface
*pim_ifp
;
1443 struct listnode
*chnextnode
;
1444 struct pim_ifchannel
*ch
;
1445 struct listnode
*chnode
;
1446 int output_intf
= 0;
1448 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1449 if (pim_ifp
&& !up
->channel_oil
)
1450 up
->channel_oil
= pim_channel_oil_add (&up
->sg
, pim_ifp
->mroute_vif_index
);
1452 for (ALL_LIST_ELEMENTS (pim_ifchannel_list
, chnode
, chnextnode
, ch
))
1454 pim_ifp
= ch
->interface
->info
;
1458 if (pim_upstream_evaluate_join_desired_interface (up
, ch
))
1460 int flag
= PIM_OIF_FLAG_PROTO_PIM
;
1462 if (ch
->sg
.src
.s_addr
== INADDR_ANY
&& ch
->upstream
!= up
)
1463 flag
= PIM_OIF_FLAG_PROTO_STAR
;
1464 pim_channel_add_oif (up
->channel_oil
, ch
->interface
, flag
);
1473 * For a given upstream, determine the inherited_olist
1476 * inherited_olist(S,G,rpt) =
1477 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1478 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1479 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1481 * inherited_olist(S,G) =
1482 * inherited_olist(S,G,rpt) (+)
1483 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1485 * return 1 if there are any output interfaces
1486 * return 0 if there are not any output interfaces
1489 pim_upstream_inherited_olist (struct pim_upstream
*up
)
1491 int output_intf
= pim_upstream_inherited_olist_decide (up
);
1494 * If we have output_intf switch state to Join and work like normal
1495 * If we don't have an output_intf that means we are probably a
1496 * switch on a stick so turn on forwarding to just accept the
1497 * incoming packets so we don't bother the other stuff!
1500 pim_upstream_switch (up
, PIM_UPSTREAM_JOINED
);
1508 pim_upstream_empty_inherited_olist (struct pim_upstream
*up
)
1510 return pim_channel_oil_empty (up
->channel_oil
);
1514 * When we have a new neighbor,
1515 * find upstreams that don't have their rpf_addr
1516 * set and see if the new neighbor allows
1517 * the join to be sent
1520 pim_upstream_find_new_rpf (void)
1522 struct listnode
*up_node
;
1523 struct listnode
*up_nextnode
;
1524 struct pim_upstream
*up
;
1527 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1529 for (ALL_LIST_ELEMENTS(pim_upstream_list
, up_node
, up_nextnode
, up
))
1531 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
))
1533 if (PIM_DEBUG_TRACE
)
1534 zlog_debug ("Upstream %s without a path to send join, checking",
1536 pim_rpf_update (up
, NULL
, 1);
1542 pim_upstream_hash_key (void *arg
)
1544 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1546 return jhash_2words (up
->sg
.src
.s_addr
, up
->sg
.grp
.s_addr
, 0);
1549 void pim_upstream_terminate (void)
1551 if (pim_upstream_list
)
1552 list_delete (pim_upstream_list
);
1553 pim_upstream_list
= NULL
;
1555 if (pim_upstream_hash
)
1556 hash_free (pim_upstream_hash
);
1557 pim_upstream_hash
= NULL
;
1561 pim_upstream_equal (const void *arg1
, const void *arg2
)
1563 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1564 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1566 if ((up1
->sg
.grp
.s_addr
== up2
->sg
.grp
.s_addr
) &&
1567 (up1
->sg
.src
.s_addr
== up2
->sg
.src
.s_addr
))
1573 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1574 * the cases where kat has to be restarted on rxing traffic -
1576 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1577 * set KeepaliveTimer(S,G) to Keepalive_Period
1578 * # Note: a register state transition or UpstreamJPState(S,G)
1579 * # transition may happen as a result of restarting
1580 * # KeepaliveTimer, and must be dealt with here.
1582 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1583 * inherited_olist(S,G) != NULL ) {
1584 * set KeepaliveTimer(S,G) to Keepalive_Period
1587 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1589 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1590 * so we will skip that here */
1591 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1596 if ((up
->join_state
== PIM_UPSTREAM_JOINED
) &&
1597 !pim_upstream_empty_inherited_olist(up
)) {
1598 /* XXX: I have added this RP check just for 3.2 and it's a digression from
1599 * what rfc-4601 says. Till now we were only running KAT on FHR and RP and
1600 * there is some angst around making the change to run it all routers that
1601 * maintain the (S, G) state. This is tracked via CM-13601 and MUST be
1602 * removed to handle spt turn-arounds correctly in a 3-tier clos */
1603 if (I_am_RP (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
1615 pim_upstream_sg_running (void *arg
)
1617 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1619 // No packet can have arrived here if this is the case
1620 if (!up
->channel_oil
|| !up
->channel_oil
->installed
)
1622 if (PIM_DEBUG_TRACE
)
1623 zlog_debug ("%s: %s is not installed in mroute",
1624 __PRETTY_FUNCTION__
, up
->sg_str
);
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
)
1638 if (PIM_DEBUG_TRACE
)
1639 zlog_debug ("%s: Handling unscanned inherited_olist for %s", __PRETTY_FUNCTION__
, up
->sg_str
);
1640 pim_upstream_inherited_olist_decide (up
);
1641 up
->channel_oil
->oil_inherited_rescan
= 0;
1643 pim_mroute_update_counters (up
->channel_oil
);
1645 // Have we seen packets?
1646 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
) &&
1647 (up
->channel_oil
->cc
.lastused
/100 > 30))
1649 if (PIM_DEBUG_TRACE
)
1651 zlog_debug ("%s: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1652 __PRETTY_FUNCTION__
, up
->sg_str
,
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
))
1662 /* Add a source reference to the stream if
1663 * one doesn't already exist */
1664 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
))
1666 if (PIM_DEBUG_TRACE
)
1667 zlog_debug ("source reference created on kat restart %s", up
->sg_str
);
1669 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
);
1670 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
1671 pim_upstream_fhr_kat_start(up
);
1673 pim_upstream_keep_alive_timer_start(up
, qpim_keep_alive_time
);
1675 else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
))
1676 pim_upstream_keep_alive_timer_start(up
, qpim_keep_alive_time
);
1678 if (up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
)
1680 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
1686 pim_upstream_add_lhr_star_pimreg (void)
1688 struct pim_upstream
*up
;
1689 struct listnode
*node
;
1691 for (ALL_LIST_ELEMENTS_RO (pim_upstream_list
, node
, up
))
1693 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1696 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up
->flags
))
1699 pim_channel_add_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_IGMP
);
1704 pim_upstream_remove_lhr_star_pimreg (void)
1706 struct pim_upstream
*up
;
1707 struct listnode
*node
;
1709 for (ALL_LIST_ELEMENTS_RO (pim_upstream_list
, node
, up
))
1711 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1714 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up
->flags
))
1717 pim_channel_del_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_IGMP
);
1722 pim_upstream_init (void)
1724 pim_upstream_sg_wheel
= wheel_init (master
, 31000, 100,
1725 pim_upstream_hash_key
,
1726 pim_upstream_sg_running
);
1727 pim_upstream_hash
= hash_create_size (8192, pim_upstream_hash_key
,
1728 pim_upstream_equal
);
1730 pim_upstream_list
= list_new ();
1731 pim_upstream_list
->del
= (void (*)(void *)) pim_upstream_free
;
1732 pim_upstream_list
->cmp
= pim_upstream_compare
;