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(up
->sources
);
90 * A (*,G) or a (*,*) is being created
91 * Find the children that would point
94 static void pim_upstream_find_new_children(struct pim_instance
*pim
,
95 struct pim_upstream
*up
)
97 struct pim_upstream
*child
;
98 struct listnode
*ch_node
;
100 if ((up
->sg
.src
.s_addr
!= INADDR_ANY
)
101 && (up
->sg
.grp
.s_addr
!= INADDR_ANY
))
104 if ((up
->sg
.src
.s_addr
== INADDR_ANY
)
105 && (up
->sg
.grp
.s_addr
== INADDR_ANY
))
108 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, ch_node
, child
)) {
109 if ((up
->sg
.grp
.s_addr
!= INADDR_ANY
)
110 && (child
->sg
.grp
.s_addr
== up
->sg
.grp
.s_addr
)
113 listnode_add_sort(up
->sources
, child
);
119 * If we have a (*,*) || (S,*) there is no parent
120 * If we have a (S,G), find the (*,G)
121 * If we have a (*,G), find the (*,*)
123 static struct pim_upstream
*pim_upstream_find_parent(struct pim_instance
*pim
,
124 struct pim_upstream
*child
)
126 struct prefix_sg any
= child
->sg
;
127 struct pim_upstream
*up
= NULL
;
130 if ((child
->sg
.src
.s_addr
!= INADDR_ANY
)
131 && (child
->sg
.grp
.s_addr
!= INADDR_ANY
)) {
132 any
.src
.s_addr
= INADDR_ANY
;
133 up
= pim_upstream_find(pim
, &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 /* Detaching from channel_oil, channel_oil may exist post del,
154 but upstream would not keep reference of it
156 up
->channel_oil
->up
= NULL
;
157 pim_channel_oil_del(up
->channel_oil
);
158 up
->channel_oil
= NULL
;
162 struct pim_upstream
*pim_upstream_del(struct pim_instance
*pim
,
163 struct pim_upstream
*up
, const char *name
)
165 bool notify_msdp
= false;
170 "%s(%s): Delete %s ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
171 __PRETTY_FUNCTION__
, name
, up
->sg_str
, 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(up
->sources
);
207 pim_mroute_del(up
->channel_oil
, __PRETTY_FUNCTION__
);
208 upstream_channel_oil_detach(up
);
210 list_delete(up
->ifchannels
);
211 up
->ifchannels
= NULL
;
214 notice that listnode_delete() can't be moved
215 into pim_upstream_free() because the later is
216 called by list_delete_all_node()
218 if (up
->parent
&& up
->parent
->sources
)
219 listnode_delete(up
->parent
->sources
, up
);
222 listnode_delete(pim
->upstream_list
, up
);
223 hash_release(pim
->upstream_hash
, up
);
226 pim_msdp_up_del(pim
, &up
->sg
);
229 /* Deregister addr with Zebra NHT */
230 nht_p
.family
= AF_INET
;
231 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
232 nht_p
.u
.prefix4
= up
->upstream_addr
;
233 if (PIM_DEBUG_TRACE
) {
234 char buf
[PREFIX2STR_BUFFER
];
235 prefix2str(&nht_p
, buf
, sizeof(buf
));
236 zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
237 __PRETTY_FUNCTION__
, up
->sg_str
, buf
);
239 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
);
241 pim_upstream_free(up
);
246 void pim_upstream_send_join(struct pim_upstream
*up
)
248 if (PIM_DEBUG_TRACE
) {
249 char rpf_str
[PREFIX_STRLEN
];
250 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_str
,
252 zlog_debug("%s: RPF'%s=%s(%s) for Interface %s",
253 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
254 pim_upstream_state2str(up
->join_state
),
255 up
->rpf
.source_nexthop
.interface
->name
);
256 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
257 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
258 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
);
263 /* send Join(S,G) to the current upstream neighbor */
264 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 1 /* join */);
267 static int on_join_timer(struct thread
*t
)
269 struct pim_upstream
*up
;
274 * In the case of a HFR we will not ahve anyone to send this to.
276 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
280 * Don't send the join if the outgoing interface is a loopback
281 * But since this might change leave the join timer running
283 if (up
->rpf
.source_nexthop
284 .interface
&& !if_is_loopback(up
->rpf
.source_nexthop
.interface
))
285 pim_upstream_send_join(up
);
287 join_timer_start(up
);
292 static void join_timer_stop(struct pim_upstream
*up
)
294 struct pim_neighbor
*nbr
;
296 THREAD_OFF(up
->t_join_timer
);
298 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
299 up
->rpf
.rpf_addr
.u
.prefix4
);
302 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
);
304 pim_jp_agg_upstream_verification(up
, false);
307 void join_timer_start(struct pim_upstream
*up
)
309 struct pim_neighbor
*nbr
= NULL
;
311 if (up
->rpf
.source_nexthop
.interface
) {
312 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
313 up
->rpf
.rpf_addr
.u
.prefix4
);
315 if (PIM_DEBUG_PIM_EVENTS
) {
317 "%s: starting %d sec timer for upstream (S,G)=%s",
318 __PRETTY_FUNCTION__
, qpim_t_periodic
,
324 pim_jp_agg_add_group(nbr
->upstream_jp_agg
, up
, 1);
326 THREAD_OFF(up
->t_join_timer
);
327 thread_add_timer(master
, on_join_timer
, up
, qpim_t_periodic
,
330 pim_jp_agg_upstream_verification(up
, true);
334 * This is only called when we are switching the upstream
335 * J/P from one neighbor to another
337 * As such we need to remove from the old list and
338 * add to the new list.
340 void pim_upstream_join_timer_restart(struct pim_upstream
*up
,
343 // THREAD_OFF(up->t_join_timer);
344 join_timer_start(up
);
347 static void pim_upstream_join_timer_restart_msec(struct pim_upstream
*up
,
350 if (PIM_DEBUG_PIM_EVENTS
) {
351 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
352 __PRETTY_FUNCTION__
, interval_msec
, up
->sg_str
);
355 THREAD_OFF(up
->t_join_timer
);
356 thread_add_timer_msec(master
, on_join_timer
, up
, interval_msec
,
360 void pim_upstream_join_suppress(struct pim_upstream
*up
,
361 struct in_addr rpf_addr
, int holdtime
)
363 long t_joinsuppress_msec
;
364 long join_timer_remain_msec
;
366 t_joinsuppress_msec
=
367 MIN(pim_if_t_suppressed_msec(up
->rpf
.source_nexthop
.interface
),
370 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
372 if (PIM_DEBUG_TRACE
) {
373 char rpf_str
[INET_ADDRSTRLEN
];
374 pim_inet4_dump("<rpf?>", rpf_addr
, rpf_str
, sizeof(rpf_str
));
376 "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
377 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
378 join_timer_remain_msec
, t_joinsuppress_msec
);
381 if (join_timer_remain_msec
< t_joinsuppress_msec
) {
382 if (PIM_DEBUG_TRACE
) {
384 "%s %s: suppressing Join(S,G)=%s for %ld msec",
385 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
,
386 t_joinsuppress_msec
);
389 pim_upstream_join_timer_restart_msec(up
, t_joinsuppress_msec
);
393 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label
,
394 struct pim_upstream
*up
)
396 long join_timer_remain_msec
;
399 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
401 pim_if_t_override_msec(up
->rpf
.source_nexthop
.interface
);
403 if (PIM_DEBUG_TRACE
) {
404 char rpf_str
[INET_ADDRSTRLEN
];
405 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
.u
.prefix4
, rpf_str
,
408 "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
409 debug_label
, up
->sg_str
, rpf_str
,
410 join_timer_remain_msec
, t_override_msec
);
413 if (join_timer_remain_msec
> t_override_msec
) {
414 if (PIM_DEBUG_TRACE
) {
416 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
417 debug_label
, up
->sg_str
, t_override_msec
);
420 pim_upstream_join_timer_restart_msec(up
, t_override_msec
);
424 static void forward_on(struct pim_upstream
*up
)
426 struct listnode
*chnode
;
427 struct listnode
*chnextnode
;
428 struct pim_ifchannel
*ch
= NULL
;
430 /* scan (S,G) state */
431 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
432 if (pim_macro_chisin_oiflist(ch
))
433 pim_forward_start(ch
);
435 } /* scan iface channel list */
438 static void forward_off(struct pim_upstream
*up
)
440 struct listnode
*chnode
;
441 struct listnode
*chnextnode
;
442 struct pim_ifchannel
*ch
;
444 /* scan per-interface (S,G) state */
445 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
447 pim_forward_stop(ch
, false);
449 } /* scan iface channel list */
452 static int pim_upstream_could_register(struct pim_upstream
*up
)
454 struct pim_interface
*pim_ifp
= NULL
;
456 if (up
->rpf
.source_nexthop
.interface
)
457 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
460 zlog_debug("%s: up %s RPF is not present",
461 __PRETTY_FUNCTION__
, up
->sg_str
);
464 if (pim_ifp
&& PIM_I_am_DR(pim_ifp
)
465 && pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
472 /* Source registration is supressed for SSM groups. When the SSM range changes
473 * we re-revaluate register setup for existing upstream entries */
474 void pim_upstream_register_reevaluate(struct pim_instance
*pim
)
476 struct listnode
*upnode
;
477 struct pim_upstream
*up
;
479 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
480 /* If FHR is set CouldRegister is True. Also check if the flow
481 * is actually active; if it is not kat setup will trigger
483 * registration whenever the flow becomes active. */
484 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) || !up
->t_ka_timer
)
487 if (pim_is_grp_ssm(pim
, up
->sg
.grp
)) {
488 /* clear the register state for SSM groups */
489 if (up
->reg_state
!= PIM_REG_NOINFO
) {
490 if (PIM_DEBUG_PIM_EVENTS
)
492 "Clear register for %s as G is now SSM",
494 /* remove regiface from the OIL if it is there*/
495 pim_channel_del_oif(up
->channel_oil
,
497 PIM_OIF_FLAG_PROTO_PIM
);
498 up
->reg_state
= PIM_REG_NOINFO
;
501 /* register ASM sources with the RP */
502 if (up
->reg_state
== PIM_REG_NOINFO
) {
503 if (PIM_DEBUG_PIM_EVENTS
)
505 "Register %s as G is now ASM",
507 pim_channel_add_oif(up
->channel_oil
,
509 PIM_OIF_FLAG_PROTO_PIM
);
510 up
->reg_state
= PIM_REG_JOIN
;
516 void pim_upstream_switch(struct pim_instance
*pim
, struct pim_upstream
*up
,
517 enum pim_upstream_state new_state
)
519 enum pim_upstream_state old_state
= up
->join_state
;
521 if (PIM_DEBUG_PIM_EVENTS
) {
522 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
523 __PRETTY_FUNCTION__
, up
->sg_str
,
524 pim_upstream_state2str(up
->join_state
),
525 pim_upstream_state2str(new_state
));
528 up
->join_state
= new_state
;
529 if (old_state
!= new_state
)
530 up
->state_transition
= pim_time_monotonic_sec();
532 pim_upstream_update_assert_tracking_desired(up
);
534 if (new_state
== PIM_UPSTREAM_JOINED
) {
535 if (old_state
!= PIM_UPSTREAM_JOINED
) {
536 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
538 pim_msdp_up_join_state_changed(pim
, up
);
539 if (pim_upstream_could_register(up
)) {
540 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
542 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
544 pim_upstream_keep_alive_timer_start(
545 up
, pim
->keep_alive_time
);
546 pim_register_join(up
);
549 pim_upstream_send_join(up
);
550 join_timer_start(up
);
558 if (old_state
== PIM_UPSTREAM_JOINED
)
559 pim_msdp_up_join_state_changed(pim
, up
);
561 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
563 If I am RP for G then send S,G prune to its IIF. */
564 if (pim_upstream_is_sg_rpt(up
) && up
->parent
565 && !I_am_RP(pim
, up
->sg
.grp
)) {
566 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
568 "%s: *,G IIF %s S,G IIF %s ",
570 up
->parent
->rpf
.source_nexthop
572 up
->rpf
.source_nexthop
.interface
->name
);
573 pim_jp_agg_single_upstream_send(&up
->parent
->rpf
,
577 pim_jp_agg_single_upstream_send(&up
->rpf
, up
,
583 int pim_upstream_compare(void *arg1
, void *arg2
)
585 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
586 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
588 if (ntohl(up1
->sg
.grp
.s_addr
) < ntohl(up2
->sg
.grp
.s_addr
))
591 if (ntohl(up1
->sg
.grp
.s_addr
) > ntohl(up2
->sg
.grp
.s_addr
))
594 if (ntohl(up1
->sg
.src
.s_addr
) < ntohl(up2
->sg
.src
.s_addr
))
597 if (ntohl(up1
->sg
.src
.s_addr
) > ntohl(up2
->sg
.src
.s_addr
))
603 static struct pim_upstream
*pim_upstream_new(struct pim_instance
*pim
,
604 struct prefix_sg
*sg
,
605 struct interface
*incoming
,
607 struct pim_ifchannel
*ch
)
609 enum pim_rpf_result rpf_result
;
610 struct pim_interface
*pim_ifp
;
611 struct pim_upstream
*up
;
613 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
615 zlog_err("%s: PIM XCALLOC(%zu) failure", __PRETTY_FUNCTION__
,
621 pim_str_sg_set(sg
, up
->sg_str
);
625 up
= hash_get(pim
->upstream_hash
, up
, hash_alloc_intern
);
626 if (!pim_rp_set_upstream_addr(pim
, &up
->upstream_addr
, sg
->src
,
629 zlog_debug("%s: Received a (*,G) with no RP configured",
630 __PRETTY_FUNCTION__
);
632 hash_release(pim
->upstream_hash
, up
);
633 XFREE(MTYPE_PIM_UPSTREAM
, up
);
637 up
->parent
= pim_upstream_find_parent(pim
, up
);
638 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
639 up
->sources
= list_new();
640 up
->sources
->cmp
= pim_upstream_compare
;
644 pim_upstream_find_new_children(pim
, up
);
647 up
->t_join_timer
= NULL
;
648 up
->t_ka_timer
= NULL
;
649 up
->t_rs_timer
= NULL
;
650 up
->t_msdp_reg_timer
= NULL
;
651 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
652 up
->reg_state
= PIM_REG_NOINFO
;
653 up
->state_transition
= pim_time_monotonic_sec();
654 up
->channel_oil
= NULL
;
655 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
657 up
->rpf
.source_nexthop
.interface
= NULL
;
658 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
659 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
661 up
->rpf
.source_nexthop
.mrib_metric_preference
=
662 qpim_infinite_assert_metric
.metric_preference
;
663 up
->rpf
.source_nexthop
.mrib_route_metric
=
664 qpim_infinite_assert_metric
.route_metric
;
665 up
->rpf
.rpf_addr
.family
= AF_INET
;
666 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
668 up
->ifchannels
= list_new();
669 up
->ifchannels
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
671 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
672 wheel_add_item(pim
->upstream_sg_wheel
, up
);
674 rpf_result
= pim_rpf_update(pim
, up
, NULL
, 1);
675 if (rpf_result
== PIM_RPF_FAILURE
) {
680 "%s: Attempting to create upstream(%s), Unable to RPF for source",
681 __PRETTY_FUNCTION__
, up
->sg_str
);
683 nht_p
.family
= AF_INET
;
684 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
685 nht_p
.u
.prefix4
= up
->upstream_addr
;
686 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
);
689 listnode_delete(up
->parent
->sources
, up
);
693 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
694 wheel_remove_item(pim
->upstream_sg_wheel
, up
);
696 pim_upstream_remove_children(pim
, up
);
698 list_delete(up
->sources
);
700 hash_release(pim
->upstream_hash
, up
);
701 XFREE(MTYPE_PIM_UPSTREAM
, up
);
705 if (up
->rpf
.source_nexthop
.interface
) {
706 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
708 up
->channel_oil
= pim_channel_oil_add(
709 pim
, &up
->sg
, pim_ifp
->mroute_vif_index
);
711 listnode_add_sort(pim
->upstream_list
, up
);
713 if (PIM_DEBUG_TRACE
) {
715 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
716 __PRETTY_FUNCTION__
, up
->sg_str
,
717 inet_ntoa(up
->upstream_addr
), up
->ref_count
);
723 struct pim_upstream
*pim_upstream_find(struct pim_instance
*pim
,
724 struct prefix_sg
*sg
)
726 struct pim_upstream lookup
;
727 struct pim_upstream
*up
= NULL
;
730 up
= hash_lookup(pim
->upstream_hash
, &lookup
);
734 struct pim_upstream
*pim_upstream_find_or_add(struct prefix_sg
*sg
,
735 struct interface
*incoming
,
736 int flags
, const char *name
)
738 struct pim_upstream
*up
;
739 struct pim_interface
*pim_ifp
;
741 pim_ifp
= incoming
->info
;
743 up
= pim_upstream_find(pim_ifp
->pim
, sg
);
746 if (!(up
->flags
& flags
)) {
751 "%s(%s): upstream %s ref count %d increment",
752 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
756 up
= pim_upstream_add(pim_ifp
->pim
, sg
, incoming
, flags
, name
,
762 void pim_upstream_ref(struct pim_upstream
*up
, int flags
, const char *name
)
767 zlog_debug("%s(%s): upstream %s ref count %d increment",
768 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
772 struct pim_upstream
*pim_upstream_add(struct pim_instance
*pim
,
773 struct prefix_sg
*sg
,
774 struct interface
*incoming
, int flags
,
776 struct pim_ifchannel
*ch
)
778 struct pim_upstream
*up
= NULL
;
781 up
= pim_upstream_find(pim
, sg
);
783 pim_upstream_ref(up
, flags
, name
);
786 up
= pim_upstream_new(pim
, sg
, incoming
, flags
, ch
);
789 if (PIM_DEBUG_TRACE
) {
791 char buf
[PREFIX2STR_BUFFER
];
792 prefix2str(&up
->rpf
.rpf_addr
, buf
, sizeof(buf
));
793 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
794 __PRETTY_FUNCTION__
, name
,
795 up
->sg_str
, buf
, up
->rpf
.source_nexthop
.interface
?
796 up
->rpf
.source_nexthop
.interface
->name
: "NIL" ,
797 found
, up
->ref_count
);
799 zlog_debug("%s(%s): (%s) failure to create",
800 __PRETTY_FUNCTION__
, name
,
801 pim_str_sg_dump(sg
));
808 * Passed in up must be the upstream for ch. starch is NULL if no
811 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream
*up
,
812 struct pim_ifchannel
*ch
,
813 struct pim_ifchannel
*starch
)
816 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
819 if (!pim_macro_ch_lost_assert(ch
)
820 && pim_macro_chisin_joins_or_include(ch
))
828 if (PIM_IF_FLAG_TEST_S_G_RPT(starch
->upstream
->flags
))
831 if (!pim_macro_ch_lost_assert(starch
)
832 && pim_macro_chisin_joins_or_include(starch
))
840 Evaluate JoinDesired(S,G):
842 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
845 inherited_olist(S,G) =
846 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
848 JoinDesired(S,G) may be affected by changes in the following:
850 pim_ifp->primary_address
852 ch->ifassert_winner_metric
854 ch->local_ifmembership
856 ch->upstream->rpf.source_nexthop.mrib_metric_preference
857 ch->upstream->rpf.source_nexthop.mrib_route_metric
858 ch->upstream->rpf.source_nexthop.interface
860 See also pim_upstream_update_join_desired() below.
862 int pim_upstream_evaluate_join_desired(struct pim_instance
*pim
,
863 struct pim_upstream
*up
)
865 struct interface
*ifp
;
866 struct listnode
*node
;
867 struct pim_ifchannel
*ch
, *starch
;
868 struct pim_upstream
*starup
= up
->parent
;
871 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim
->vrf_id
), node
, 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 joined=%d rpf_addr=%s",
952 __PRETTY_FUNCTION__
, neigh_str
, up
->sg_str
,
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; remove stream reference",
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 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1115 pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1121 void pim_upstream_keep_alive_timer_start(struct pim_upstream
*up
, uint32_t time
)
1123 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1124 if (PIM_DEBUG_TRACE
)
1125 zlog_debug("kat start on %s with no stream reference",
1128 THREAD_OFF(up
->t_ka_timer
);
1129 thread_add_timer(master
, pim_upstream_keep_alive_timer
, up
, time
,
1132 /* any time keepalive is started against a SG we will have to
1133 * re-evaluate our active source database */
1134 pim_msdp_sa_local_update(up
);
1137 /* MSDP on RP needs to know if a source is registerable to this RP */
1138 static int pim_upstream_msdp_reg_timer(struct thread
*t
)
1140 struct pim_upstream
*up
= THREAD_ARG(t
);
1141 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1143 /* source is no longer active - pull the SA from MSDP's cache */
1144 pim_msdp_sa_local_del(pim
, &up
->sg
);
1147 void pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1149 THREAD_OFF(up
->t_msdp_reg_timer
);
1150 thread_add_timer(master
, pim_upstream_msdp_reg_timer
, up
,
1151 PIM_MSDP_REG_RXED_PERIOD
, &up
->t_msdp_reg_timer
);
1153 pim_msdp_sa_local_update(up
);
1157 * 4.2.1 Last-Hop Switchover to the SPT
1159 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1160 * RP. Once traffic from sources to joined groups arrives at a last-hop
1161 * router, it has the option of switching to receive the traffic on a
1162 * shortest path tree (SPT).
1164 * The decision for a router to switch to the SPT is controlled as
1168 * CheckSwitchToSpt(S,G) {
1169 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1170 * (+) pim_include(S,G) != NULL )
1171 * AND SwitchToSptDesired(S,G) ) {
1172 * # Note: Restarting the KAT will result in the SPT switch
1173 * set KeepaliveTimer(S,G) to Keepalive_Period
1177 * SwitchToSptDesired(S,G) is a policy function that is implementation
1178 * defined. An "infinite threshold" policy can be implemented by making
1179 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1180 * first packet" policy can be implemented by making
1181 * SwitchToSptDesired(S,G) return true once a single packet has been
1182 * received for the source and group.
1184 int pim_upstream_switch_to_spt_desired(struct pim_instance
*pim
,
1185 struct prefix_sg
*sg
)
1187 if (I_am_RP(pim
, sg
->grp
))
1193 int 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
)) {
1199 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1206 * After receiving a packet set SPTbit:
1208 * Update_SPTbit(S,G,iif) {
1209 * if ( iif == RPF_interface(S)
1210 * AND JoinDesired(S,G) == TRUE
1211 * AND ( DirectlyConnected(S) == TRUE
1212 * OR RPF_interface(S) != RPF_interface(RP(G))
1213 * OR inherited_olist(S,G,rpt) == NULL
1214 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1215 * ( RPF'(S,G) != NULL ) )
1216 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1217 * Set SPTbit(S,G) to TRUE
1221 void pim_upstream_set_sptbit(struct pim_upstream
*up
,
1222 struct interface
*incoming
)
1224 struct pim_upstream
*starup
= up
->parent
;
1226 // iif == RPF_interfvace(S)
1227 if (up
->rpf
.source_nexthop
.interface
!= incoming
) {
1228 if (PIM_DEBUG_TRACE
)
1230 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1231 __PRETTY_FUNCTION__
, incoming
->name
,
1232 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
,
1242 if (PIM_DEBUG_TRACE
)
1243 zlog_debug("%s: %s is directly connected to the source",
1244 __PRETTY_FUNCTION__
, up
->sg_str
);
1245 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1249 // OR RPF_interface(S) != RPF_interface(RP(G))
1251 || up
->rpf
.source_nexthop
1252 .interface
!= starup
->rpf
.source_nexthop
.interface
) {
1253 if (PIM_DEBUG_TRACE
)
1255 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1256 __PRETTY_FUNCTION__
, up
->sg_str
);
1257 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1261 // OR inherited_olist(S,G,rpt) == NULL
1262 if (pim_upstream_is_sg_rpt(up
)
1263 && pim_upstream_empty_inherited_olist(up
)) {
1264 if (PIM_DEBUG_TRACE
)
1265 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1266 __PRETTY_FUNCTION__
, up
->sg_str
);
1267 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1271 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1272 // ( RPF'(S,G) != NULL ) )
1273 if (up
->parent
&& pim_rpf_is_same(&up
->rpf
, &up
->parent
->rpf
)) {
1274 if (PIM_DEBUG_TRACE
)
1275 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1276 __PRETTY_FUNCTION__
, up
->sg_str
);
1277 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1284 const char *pim_upstream_state2str(enum pim_upstream_state join_state
)
1286 switch (join_state
) {
1287 case PIM_UPSTREAM_NOTJOINED
:
1290 case PIM_UPSTREAM_JOINED
:
1297 const char *pim_reg_state2str(enum pim_reg_state reg_state
, char *state_str
)
1299 switch (reg_state
) {
1300 case PIM_REG_NOINFO
:
1301 strcpy(state_str
, "RegNoInfo");
1304 strcpy(state_str
, "RegJoined");
1306 case PIM_REG_JOIN_PENDING
:
1307 strcpy(state_str
, "RegJoinPend");
1310 strcpy(state_str
, "RegPrune");
1313 strcpy(state_str
, "RegUnknown");
1318 static int pim_upstream_register_stop_timer(struct thread
*t
)
1320 struct pim_interface
*pim_ifp
;
1321 struct pim_instance
*pim
;
1322 struct pim_upstream
*up
;
1323 struct pim_rpf
*rpg
;
1326 pim
= up
->channel_oil
->pim
;
1328 if (PIM_DEBUG_TRACE
) {
1329 char state_str
[PIM_REG_STATE_STR_LEN
];
1330 zlog_debug("%s: (S,G)=%s upstream register stop timer %s",
1331 __PRETTY_FUNCTION__
, up
->sg_str
,
1332 pim_reg_state2str(up
->reg_state
, state_str
));
1335 switch (up
->reg_state
) {
1336 case PIM_REG_JOIN_PENDING
:
1337 up
->reg_state
= PIM_REG_JOIN
;
1338 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1339 PIM_OIF_FLAG_PROTO_PIM
);
1344 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1346 if (PIM_DEBUG_TRACE
)
1348 "%s: Interface: %s is not configured for pim",
1349 __PRETTY_FUNCTION__
,
1350 up
->rpf
.source_nexthop
.interface
->name
);
1353 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1354 pim_upstream_start_register_stop_timer(up
, 1);
1356 if (((up
->channel_oil
->cc
.lastused
/ 100)
1357 > PIM_KEEPALIVE_PERIOD
)
1358 && (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
))) {
1359 if (PIM_DEBUG_TRACE
)
1361 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1362 __PRETTY_FUNCTION__
);
1365 rpg
= RP(pim_ifp
->pim
, up
->sg
.grp
);
1367 if (PIM_DEBUG_TRACE
)
1369 "%s: Cannot send register for %s no RPF to the RP",
1370 __PRETTY_FUNCTION__
, up
->sg_str
);
1373 memset(&ip_hdr
, 0, sizeof(struct ip
));
1374 ip_hdr
.ip_p
= PIM_IP_PROTO_PIM
;
1377 ip_hdr
.ip_src
= up
->sg
.src
;
1378 ip_hdr
.ip_dst
= up
->sg
.grp
;
1379 ip_hdr
.ip_len
= htons(20);
1380 // checksum is broken
1381 pim_register_send((uint8_t *)&ip_hdr
, sizeof(struct ip
),
1382 pim_ifp
->primary_address
, rpg
, 1, up
);
1391 void pim_upstream_start_register_stop_timer(struct pim_upstream
*up
,
1396 THREAD_TIMER_OFF(up
->t_rs_timer
);
1398 if (!null_register
) {
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))
1402 - PIM_REGISTER_PROBE_PERIOD
;
1404 time
= PIM_REGISTER_PROBE_PERIOD
;
1406 if (PIM_DEBUG_TRACE
) {
1408 "%s: (S,G)=%s Starting upstream register stop timer %d",
1409 __PRETTY_FUNCTION__
, up
->sg_str
, time
);
1411 thread_add_timer(master
, pim_upstream_register_stop_timer
, up
, time
,
1415 int pim_upstream_inherited_olist_decide(struct pim_instance
*pim
,
1416 struct pim_upstream
*up
)
1418 struct interface
*ifp
;
1419 struct pim_interface
*pim_ifp
= NULL
;
1420 struct pim_ifchannel
*ch
, *starch
;
1421 struct listnode
*node
;
1422 struct pim_upstream
*starup
= up
->parent
;
1423 int output_intf
= 0;
1425 if (up
->rpf
.source_nexthop
.interface
)
1426 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1428 if (PIM_DEBUG_TRACE
)
1429 zlog_debug("%s: up %s RPF is not present",
1430 __PRETTY_FUNCTION__
, up
->sg_str
);
1432 if (pim_ifp
&& !up
->channel_oil
)
1433 up
->channel_oil
= pim_channel_oil_add(
1434 pim
, &up
->sg
, pim_ifp
->mroute_vif_index
);
1436 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim
->vrf_id
), node
, ifp
)) {
1440 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1443 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
1450 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1452 int flag
= PIM_OIF_FLAG_PROTO_PIM
;
1455 flag
= PIM_OIF_FLAG_PROTO_STAR
;
1457 pim_channel_add_oif(up
->channel_oil
, ifp
, flag
);
1466 * For a given upstream, determine the inherited_olist
1469 * inherited_olist(S,G,rpt) =
1470 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1471 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1472 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1474 * inherited_olist(S,G) =
1475 * inherited_olist(S,G,rpt) (+)
1476 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1478 * return 1 if there are any output interfaces
1479 * return 0 if there are not any output interfaces
1481 int pim_upstream_inherited_olist(struct pim_instance
*pim
,
1482 struct pim_upstream
*up
)
1484 int output_intf
= pim_upstream_inherited_olist_decide(pim
, up
);
1487 * If we have output_intf switch state to Join and work like normal
1488 * If we don't have an output_intf that means we are probably a
1489 * switch on a stick so turn on forwarding to just accept the
1490 * incoming packets so we don't bother the other stuff!
1493 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
1500 int pim_upstream_empty_inherited_olist(struct pim_upstream
*up
)
1502 return pim_channel_oil_empty(up
->channel_oil
);
1506 * When we have a new neighbor,
1507 * find upstreams that don't have their rpf_addr
1508 * set and see if the new neighbor allows
1509 * the join to be sent
1511 void pim_upstream_find_new_rpf(struct pim_instance
*pim
)
1513 struct listnode
*up_node
;
1514 struct listnode
*up_nextnode
;
1515 struct pim_upstream
*up
;
1518 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1520 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
1521 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
1522 if (PIM_DEBUG_TRACE
)
1524 "Upstream %s without a path to send join, checking",
1526 pim_rpf_update(pim
, up
, NULL
, 1);
1531 unsigned int pim_upstream_hash_key(void *arg
)
1533 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1535 return jhash_2words(up
->sg
.src
.s_addr
, up
->sg
.grp
.s_addr
, 0);
1538 void pim_upstream_terminate(struct pim_instance
*pim
)
1540 if (pim
->upstream_list
)
1541 list_delete(pim
->upstream_list
);
1542 pim
->upstream_list
= NULL
;
1544 if (pim
->upstream_hash
)
1545 hash_free(pim
->upstream_hash
);
1546 pim
->upstream_hash
= NULL
;
1549 int pim_upstream_equal(const void *arg1
, const void *arg2
)
1551 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1552 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1554 if ((up1
->sg
.grp
.s_addr
== up2
->sg
.grp
.s_addr
)
1555 && (up1
->sg
.src
.s_addr
== up2
->sg
.src
.s_addr
))
1561 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1562 * the cases where kat has to be restarted on rxing traffic -
1564 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1565 * set KeepaliveTimer(S,G) to Keepalive_Period
1566 * # Note: a register state transition or UpstreamJPState(S,G)
1567 * # transition may happen as a result of restarting
1568 * # KeepaliveTimer, and must be dealt with here.
1570 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1571 * inherited_olist(S,G) != NULL ) {
1572 * set KeepaliveTimer(S,G) to Keepalive_Period
1575 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1577 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1579 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1580 * so we will skip that here */
1581 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1586 if ((up
->join_state
== PIM_UPSTREAM_JOINED
)
1587 && !pim_upstream_empty_inherited_olist(up
)) {
1588 /* XXX: I have added this RP check just for 3.2 and it's a
1590 * what rfc-4601 says. Till now we were only running KAT on FHR
1592 * there is some angst around making the change to run it all
1594 * maintain the (S, G) state. This is tracked via CM-13601 and
1596 * removed to handle spt turn-arounds correctly in a 3-tier clos
1598 if (I_am_RP(pim
, up
->sg
.grp
))
1606 * Code to check and see if we've received packets on a S,G mroute
1607 * and if so to set the SPT bit appropriately
1609 static void pim_upstream_sg_running(void *arg
)
1611 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1612 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1614 // No packet can have arrived here if this is the case
1615 if (!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
) {
1631 if (PIM_DEBUG_TRACE
)
1633 "%s: Handling unscanned inherited_olist for %s",
1634 __PRETTY_FUNCTION__
, up
->sg_str
);
1635 pim_upstream_inherited_olist_decide(pim
, up
);
1636 up
->channel_oil
->oil_inherited_rescan
= 0;
1638 pim_mroute_update_counters(up
->channel_oil
);
1640 // Have we seen packets?
1641 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
)
1642 && (up
->channel_oil
->cc
.lastused
/ 100 > 30)) {
1643 if (PIM_DEBUG_TRACE
) {
1645 "%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
)) {
1655 /* Add a source reference to the stream if
1656 * one doesn't already exist */
1657 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1658 if (PIM_DEBUG_TRACE
)
1660 "source reference created on kat restart %s",
1663 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
,
1664 __PRETTY_FUNCTION__
);
1665 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
1666 pim_upstream_fhr_kat_start(up
);
1668 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1669 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
))
1670 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1672 if (up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
) {
1673 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
1678 void pim_upstream_add_lhr_star_pimreg(struct pim_instance
*pim
)
1680 struct pim_upstream
*up
;
1681 struct listnode
*node
;
1683 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1684 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1687 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1690 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1691 PIM_OIF_FLAG_PROTO_IGMP
);
1695 void pim_upstream_spt_prefix_list_update(struct pim_instance
*pim
,
1696 struct prefix_list
*pl
)
1698 const char *pname
= prefix_list_name(pl
);
1700 if (pim
->spt
.plist
&& strcmp(pim
->spt
.plist
, pname
) == 0) {
1701 pim_upstream_remove_lhr_star_pimreg(pim
, pname
);
1706 * nlist -> The new prefix list
1708 * Per Group Application of pimreg to the OIL
1709 * If the prefix list tells us DENY then
1710 * we need to Switchover to SPT immediate
1711 * so add the pimreg.
1712 * If the prefix list tells us to ACCEPT than
1713 * we need to Never do the SPT so remove
1717 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance
*pim
,
1720 struct pim_upstream
*up
;
1721 struct listnode
*node
;
1722 struct prefix_list
*np
;
1724 enum prefix_list_type apply_new
;
1726 np
= prefix_list_lookup(AFI_IP
, nlist
);
1729 g
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1731 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1732 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1735 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1739 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1740 PIM_OIF_FLAG_PROTO_IGMP
);
1743 g
.u
.prefix4
= up
->sg
.grp
;
1744 apply_new
= prefix_list_apply(np
, &g
);
1745 if (apply_new
== PREFIX_DENY
)
1746 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1747 PIM_OIF_FLAG_PROTO_IGMP
);
1749 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1750 PIM_OIF_FLAG_PROTO_IGMP
);
1754 void pim_upstream_init(struct pim_instance
*pim
)
1758 pim
->upstream_sg_wheel
=
1759 wheel_init(master
, 31000, 100, pim_upstream_hash_key
,
1760 pim_upstream_sg_running
);
1762 snprintf(hash_name
, 64, "PIM %s Upstream Hash",
1764 pim
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
1765 pim_upstream_equal
, hash_name
);
1767 pim
->upstream_list
= list_new();
1768 pim
->upstream_list
->del
= (void (*)(void *))pim_upstream_free
;
1769 pim
->upstream_list
->cmp
= pim_upstream_compare
;