3 * Copyright (C) 2008 Everton da Silva Marques
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "zebra/rib.h"
39 #include "pim_iface.h"
41 #include "pim_zlookup.h"
42 #include "pim_upstream.h"
43 #include "pim_ifchannel.h"
44 #include "pim_neighbor.h"
46 #include "pim_zebra.h"
48 #include "pim_macro.h"
51 #include "pim_register.h"
53 #include "pim_jp_agg.h"
57 static void join_timer_stop(struct pim_upstream
*up
);
59 pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
);
62 * A (*,G) or a (*,*) is going away
63 * remove the parent pointer from
64 * those pointing at us
66 static void pim_upstream_remove_children(struct pim_instance
*pim
,
67 struct pim_upstream
*up
)
69 struct pim_upstream
*child
;
74 while (!list_isempty(up
->sources
)) {
75 child
= listnode_head(up
->sources
);
76 listnode_delete(up
->sources
, child
);
77 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child
->flags
)) {
78 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child
->flags
);
79 child
= pim_upstream_del(pim
, child
,
85 list_delete_and_null(&up
->sources
);
89 * A (*,G) or a (*,*) is being created
90 * Find the children that would point
93 static void pim_upstream_find_new_children(struct pim_instance
*pim
,
94 struct pim_upstream
*up
)
96 struct pim_upstream
*child
;
97 struct listnode
*ch_node
;
99 if ((up
->sg
.src
.s_addr
!= INADDR_ANY
)
100 && (up
->sg
.grp
.s_addr
!= INADDR_ANY
))
103 if ((up
->sg
.src
.s_addr
== INADDR_ANY
)
104 && (up
->sg
.grp
.s_addr
== INADDR_ANY
))
107 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, ch_node
, child
)) {
108 if ((up
->sg
.grp
.s_addr
!= INADDR_ANY
)
109 && (child
->sg
.grp
.s_addr
== up
->sg
.grp
.s_addr
)
112 listnode_add_sort(up
->sources
, child
);
118 * If we have a (*,*) || (S,*) there is no parent
119 * If we have a (S,G), find the (*,G)
120 * If we have a (*,G), find the (*,*)
122 static struct pim_upstream
*pim_upstream_find_parent(struct pim_instance
*pim
,
123 struct pim_upstream
*child
)
125 struct prefix_sg any
= child
->sg
;
126 struct pim_upstream
*up
= NULL
;
129 if ((child
->sg
.src
.s_addr
!= INADDR_ANY
)
130 && (child
->sg
.grp
.s_addr
!= INADDR_ANY
)) {
131 any
.src
.s_addr
= INADDR_ANY
;
132 up
= pim_upstream_find(pim
, &any
);
135 listnode_add(up
->sources
, child
);
143 static void upstream_channel_oil_detach(struct pim_upstream
*up
)
145 if (up
->channel_oil
) {
146 /* Detaching from channel_oil, channel_oil may exist post del,
147 but upstream would not keep reference of it
149 up
->channel_oil
->up
= NULL
;
150 pim_channel_oil_del(up
->channel_oil
);
151 up
->channel_oil
= NULL
;
155 struct pim_upstream
*pim_upstream_del(struct pim_instance
*pim
,
156 struct pim_upstream
*up
, const char *name
)
158 struct listnode
*node
, *nnode
;
159 struct pim_ifchannel
*ch
;
160 bool notify_msdp
= false;
165 "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
166 __PRETTY_FUNCTION__
, name
, up
->sg_str
, pim
->vrf
->name
,
167 up
->ref_count
, up
->flags
,
168 up
->channel_oil
->oil_ref_count
);
172 if (up
->ref_count
>= 1)
175 THREAD_OFF(up
->t_ka_timer
);
176 THREAD_OFF(up
->t_rs_timer
);
177 THREAD_OFF(up
->t_msdp_reg_timer
);
179 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
180 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 0);
182 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
183 /* if a (*, G) entry in the joined state is being
185 * need to notify MSDP */
191 pim_jp_agg_upstream_verification(up
, false);
192 up
->rpf
.source_nexthop
.interface
= NULL
;
194 if (up
->sg
.src
.s_addr
!= INADDR_ANY
) {
195 wheel_remove_item(pim
->upstream_sg_wheel
, up
);
199 pim_mroute_del(up
->channel_oil
, __PRETTY_FUNCTION__
);
200 upstream_channel_oil_detach(up
);
202 for (ALL_LIST_ELEMENTS(up
->ifchannels
, node
, nnode
, ch
))
203 pim_ifchannel_delete(ch
);
204 list_delete_and_null(&up
->ifchannels
);
206 pim_upstream_remove_children(pim
, up
);
208 list_delete_and_null(&up
->sources
);
210 if (up
->parent
&& up
->parent
->sources
)
211 listnode_delete(up
->parent
->sources
, up
);
214 listnode_delete(pim
->upstream_list
, up
);
215 hash_release(pim
->upstream_hash
, up
);
218 pim_msdp_up_del(pim
, &up
->sg
);
221 /* Deregister addr with Zebra NHT */
222 nht_p
.family
= AF_INET
;
223 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
224 nht_p
.u
.prefix4
= up
->upstream_addr
;
225 if (PIM_DEBUG_TRACE
) {
226 char buf
[PREFIX2STR_BUFFER
];
227 prefix2str(&nht_p
, buf
, sizeof(buf
));
228 zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
229 __PRETTY_FUNCTION__
, up
->sg_str
, buf
);
231 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
);
233 XFREE(MTYPE_PIM_UPSTREAM
, up
);
238 void pim_upstream_send_join(struct pim_upstream
*up
)
240 if (PIM_DEBUG_TRACE
) {
241 char rpf_str
[PREFIX_STRLEN
];
242 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_str
,
244 zlog_debug("%s: RPF'%s=%s(%s) for Interface %s",
245 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
246 pim_upstream_state2str(up
->join_state
),
247 up
->rpf
.source_nexthop
.interface
->name
);
248 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
249 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
250 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
);
255 /* send Join(S,G) to the current upstream neighbor */
256 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 1 /* join */);
259 static int on_join_timer(struct thread
*t
)
261 struct pim_upstream
*up
;
266 * In the case of a HFR we will not ahve anyone to send this to.
268 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
272 * Don't send the join if the outgoing interface is a loopback
273 * But since this might change leave the join timer running
275 if (up
->rpf
.source_nexthop
276 .interface
&& !if_is_loopback(up
->rpf
.source_nexthop
.interface
))
277 pim_upstream_send_join(up
);
279 join_timer_start(up
);
284 static void join_timer_stop(struct pim_upstream
*up
)
286 struct pim_neighbor
*nbr
;
288 THREAD_OFF(up
->t_join_timer
);
290 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
291 up
->rpf
.rpf_addr
.u
.prefix4
);
294 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
);
296 pim_jp_agg_upstream_verification(up
, false);
299 void join_timer_start(struct pim_upstream
*up
)
301 struct pim_neighbor
*nbr
= NULL
;
303 if (up
->rpf
.source_nexthop
.interface
) {
304 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
305 up
->rpf
.rpf_addr
.u
.prefix4
);
307 if (PIM_DEBUG_PIM_EVENTS
) {
309 "%s: starting %d sec timer for upstream (S,G)=%s",
310 __PRETTY_FUNCTION__
, qpim_t_periodic
,
316 pim_jp_agg_add_group(nbr
->upstream_jp_agg
, up
, 1);
318 THREAD_OFF(up
->t_join_timer
);
319 thread_add_timer(master
, on_join_timer
, up
, qpim_t_periodic
,
322 pim_jp_agg_upstream_verification(up
, true);
326 * This is only called when we are switching the upstream
327 * J/P from one neighbor to another
329 * As such we need to remove from the old list and
330 * add to the new list.
332 void pim_upstream_join_timer_restart(struct pim_upstream
*up
,
335 // THREAD_OFF(up->t_join_timer);
336 join_timer_start(up
);
339 static void pim_upstream_join_timer_restart_msec(struct pim_upstream
*up
,
342 if (PIM_DEBUG_PIM_EVENTS
) {
343 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
344 __PRETTY_FUNCTION__
, interval_msec
, up
->sg_str
);
347 THREAD_OFF(up
->t_join_timer
);
348 thread_add_timer_msec(master
, on_join_timer
, up
, interval_msec
,
352 void pim_upstream_join_suppress(struct pim_upstream
*up
,
353 struct in_addr rpf_addr
, int holdtime
)
355 long t_joinsuppress_msec
;
356 long join_timer_remain_msec
;
358 t_joinsuppress_msec
=
359 MIN(pim_if_t_suppressed_msec(up
->rpf
.source_nexthop
.interface
),
362 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
364 if (PIM_DEBUG_TRACE
) {
365 char rpf_str
[INET_ADDRSTRLEN
];
366 pim_inet4_dump("<rpf?>", rpf_addr
, rpf_str
, sizeof(rpf_str
));
368 "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
369 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
370 join_timer_remain_msec
, t_joinsuppress_msec
);
373 if (join_timer_remain_msec
< t_joinsuppress_msec
) {
374 if (PIM_DEBUG_TRACE
) {
376 "%s %s: suppressing Join(S,G)=%s for %ld msec",
377 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
,
378 t_joinsuppress_msec
);
381 pim_upstream_join_timer_restart_msec(up
, t_joinsuppress_msec
);
385 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label
,
386 struct pim_upstream
*up
)
388 long join_timer_remain_msec
;
391 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
393 pim_if_t_override_msec(up
->rpf
.source_nexthop
.interface
);
395 if (PIM_DEBUG_TRACE
) {
396 char rpf_str
[INET_ADDRSTRLEN
];
397 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
.u
.prefix4
, rpf_str
,
400 "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
401 debug_label
, up
->sg_str
, rpf_str
,
402 join_timer_remain_msec
, t_override_msec
);
405 if (join_timer_remain_msec
> t_override_msec
) {
406 if (PIM_DEBUG_TRACE
) {
408 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
409 debug_label
, up
->sg_str
, t_override_msec
);
412 pim_upstream_join_timer_restart_msec(up
, t_override_msec
);
416 static void forward_on(struct pim_upstream
*up
)
418 struct listnode
*chnode
;
419 struct listnode
*chnextnode
;
420 struct pim_ifchannel
*ch
= NULL
;
422 /* scan (S,G) state */
423 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
424 if (pim_macro_chisin_oiflist(ch
))
425 pim_forward_start(ch
);
427 } /* scan iface channel list */
430 static void forward_off(struct pim_upstream
*up
)
432 struct listnode
*chnode
;
433 struct listnode
*chnextnode
;
434 struct pim_ifchannel
*ch
;
436 /* scan per-interface (S,G) state */
437 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
439 pim_forward_stop(ch
, false);
441 } /* scan iface channel list */
444 static int pim_upstream_could_register(struct pim_upstream
*up
)
446 struct pim_interface
*pim_ifp
= NULL
;
448 if (up
->rpf
.source_nexthop
.interface
)
449 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
452 zlog_debug("%s: up %s RPF is not present",
453 __PRETTY_FUNCTION__
, up
->sg_str
);
456 if (pim_ifp
&& PIM_I_am_DR(pim_ifp
)
457 && pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
464 /* Source registration is supressed for SSM groups. When the SSM range changes
465 * we re-revaluate register setup for existing upstream entries */
466 void pim_upstream_register_reevaluate(struct pim_instance
*pim
)
468 struct listnode
*upnode
;
469 struct pim_upstream
*up
;
471 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
472 /* If FHR is set CouldRegister is True. Also check if the flow
473 * is actually active; if it is not kat setup will trigger
475 * registration whenever the flow becomes active. */
476 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) || !up
->t_ka_timer
)
479 if (pim_is_grp_ssm(pim
, up
->sg
.grp
)) {
480 /* clear the register state for SSM groups */
481 if (up
->reg_state
!= PIM_REG_NOINFO
) {
482 if (PIM_DEBUG_PIM_EVENTS
)
484 "Clear register for %s as G is now SSM",
486 /* remove regiface from the OIL if it is there*/
487 pim_channel_del_oif(up
->channel_oil
,
489 PIM_OIF_FLAG_PROTO_PIM
);
490 up
->reg_state
= PIM_REG_NOINFO
;
493 /* register ASM sources with the RP */
494 if (up
->reg_state
== PIM_REG_NOINFO
) {
495 if (PIM_DEBUG_PIM_EVENTS
)
497 "Register %s as G is now ASM",
499 pim_channel_add_oif(up
->channel_oil
,
501 PIM_OIF_FLAG_PROTO_PIM
);
502 up
->reg_state
= PIM_REG_JOIN
;
508 void pim_upstream_switch(struct pim_instance
*pim
, struct pim_upstream
*up
,
509 enum pim_upstream_state new_state
)
511 enum pim_upstream_state old_state
= up
->join_state
;
513 if (PIM_DEBUG_PIM_EVENTS
) {
514 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
515 __PRETTY_FUNCTION__
, up
->sg_str
,
516 pim_upstream_state2str(up
->join_state
),
517 pim_upstream_state2str(new_state
));
520 up
->join_state
= new_state
;
521 if (old_state
!= new_state
)
522 up
->state_transition
= pim_time_monotonic_sec();
524 pim_upstream_update_assert_tracking_desired(up
);
526 if (new_state
== PIM_UPSTREAM_JOINED
) {
527 if (old_state
!= PIM_UPSTREAM_JOINED
) {
528 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
530 pim_msdp_up_join_state_changed(pim
, up
);
531 if (pim_upstream_could_register(up
)) {
532 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
534 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
536 pim_upstream_keep_alive_timer_start(
537 up
, pim
->keep_alive_time
);
538 pim_register_join(up
);
541 pim_upstream_send_join(up
);
542 join_timer_start(up
);
550 if (old_state
== PIM_UPSTREAM_JOINED
)
551 pim_msdp_up_join_state_changed(pim
, up
);
553 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
555 If I am RP for G then send S,G prune to its IIF. */
556 if (pim_upstream_is_sg_rpt(up
) && up
->parent
557 && !I_am_RP(pim
, up
->sg
.grp
)) {
558 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
560 "%s: *,G IIF %s S,G IIF %s ",
562 up
->parent
->rpf
.source_nexthop
564 up
->rpf
.source_nexthop
.interface
->name
);
565 pim_jp_agg_single_upstream_send(&up
->parent
->rpf
,
569 pim_jp_agg_single_upstream_send(&up
->rpf
, up
,
575 int pim_upstream_compare(void *arg1
, void *arg2
)
577 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
578 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
580 if (ntohl(up1
->sg
.grp
.s_addr
) < ntohl(up2
->sg
.grp
.s_addr
))
583 if (ntohl(up1
->sg
.grp
.s_addr
) > ntohl(up2
->sg
.grp
.s_addr
))
586 if (ntohl(up1
->sg
.src
.s_addr
) < ntohl(up2
->sg
.src
.s_addr
))
589 if (ntohl(up1
->sg
.src
.s_addr
) > ntohl(up2
->sg
.src
.s_addr
))
595 static struct pim_upstream
*pim_upstream_new(struct pim_instance
*pim
,
596 struct prefix_sg
*sg
,
597 struct interface
*incoming
,
599 struct pim_ifchannel
*ch
)
601 enum pim_rpf_result rpf_result
;
602 struct pim_interface
*pim_ifp
;
603 struct pim_upstream
*up
;
605 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
607 zlog_err("%s: PIM XCALLOC(%zu) failure", __PRETTY_FUNCTION__
,
613 pim_str_sg_set(sg
, up
->sg_str
);
617 up
= hash_get(pim
->upstream_hash
, up
, hash_alloc_intern
);
618 if (!pim_rp_set_upstream_addr(pim
, &up
->upstream_addr
, sg
->src
,
621 zlog_debug("%s: Received a (*,G) with no RP configured",
622 __PRETTY_FUNCTION__
);
624 hash_release(pim
->upstream_hash
, up
);
625 XFREE(MTYPE_PIM_UPSTREAM
, up
);
629 up
->parent
= pim_upstream_find_parent(pim
, up
);
630 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
631 up
->sources
= list_new();
632 up
->sources
->cmp
= pim_upstream_compare
;
636 pim_upstream_find_new_children(pim
, up
);
639 up
->t_join_timer
= NULL
;
640 up
->t_ka_timer
= NULL
;
641 up
->t_rs_timer
= NULL
;
642 up
->t_msdp_reg_timer
= NULL
;
643 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
644 up
->reg_state
= PIM_REG_NOINFO
;
645 up
->state_transition
= pim_time_monotonic_sec();
646 up
->channel_oil
= NULL
;
647 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
649 up
->rpf
.source_nexthop
.interface
= NULL
;
650 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
651 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
653 up
->rpf
.source_nexthop
.mrib_metric_preference
=
654 qpim_infinite_assert_metric
.metric_preference
;
655 up
->rpf
.source_nexthop
.mrib_route_metric
=
656 qpim_infinite_assert_metric
.route_metric
;
657 up
->rpf
.rpf_addr
.family
= AF_INET
;
658 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
660 up
->ifchannels
= list_new();
661 up
->ifchannels
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
663 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
664 wheel_add_item(pim
->upstream_sg_wheel
, up
);
666 rpf_result
= pim_rpf_update(pim
, up
, NULL
, 1);
667 if (rpf_result
== PIM_RPF_FAILURE
) {
672 "%s: Attempting to create upstream(%s), Unable to RPF for source",
673 __PRETTY_FUNCTION__
, up
->sg_str
);
675 nht_p
.family
= AF_INET
;
676 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
677 nht_p
.u
.prefix4
= up
->upstream_addr
;
678 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
);
681 listnode_delete(up
->parent
->sources
, up
);
685 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
686 wheel_remove_item(pim
->upstream_sg_wheel
, up
);
688 pim_upstream_remove_children(pim
, up
);
690 list_delete_and_null(&up
->sources
);
692 list_delete_and_null(&up
->ifchannels
);
694 hash_release(pim
->upstream_hash
, up
);
695 XFREE(MTYPE_PIM_UPSTREAM
, up
);
699 if (up
->rpf
.source_nexthop
.interface
) {
700 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
702 up
->channel_oil
= pim_channel_oil_add(
703 pim
, &up
->sg
, pim_ifp
->mroute_vif_index
);
705 listnode_add_sort(pim
->upstream_list
, up
);
707 if (PIM_DEBUG_TRACE
) {
709 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
710 __PRETTY_FUNCTION__
, up
->sg_str
,
711 inet_ntoa(up
->upstream_addr
), up
->ref_count
);
717 struct pim_upstream
*pim_upstream_find(struct pim_instance
*pim
,
718 struct prefix_sg
*sg
)
720 struct pim_upstream lookup
;
721 struct pim_upstream
*up
= NULL
;
724 up
= hash_lookup(pim
->upstream_hash
, &lookup
);
728 struct pim_upstream
*pim_upstream_find_or_add(struct prefix_sg
*sg
,
729 struct interface
*incoming
,
730 int flags
, const char *name
)
732 struct pim_upstream
*up
;
733 struct pim_interface
*pim_ifp
;
735 pim_ifp
= incoming
->info
;
737 up
= pim_upstream_find(pim_ifp
->pim
, sg
);
740 if (!(up
->flags
& flags
)) {
745 "%s(%s): upstream %s ref count %d increment",
746 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
750 up
= pim_upstream_add(pim_ifp
->pim
, sg
, incoming
, flags
, name
,
756 void pim_upstream_ref(struct pim_upstream
*up
, int flags
, const char *name
)
761 zlog_debug("%s(%s): upstream %s ref count %d increment",
762 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
766 struct pim_upstream
*pim_upstream_add(struct pim_instance
*pim
,
767 struct prefix_sg
*sg
,
768 struct interface
*incoming
, int flags
,
770 struct pim_ifchannel
*ch
)
772 struct pim_upstream
*up
= NULL
;
775 up
= pim_upstream_find(pim
, sg
);
777 pim_upstream_ref(up
, flags
, name
);
780 up
= pim_upstream_new(pim
, sg
, incoming
, flags
, ch
);
783 if (PIM_DEBUG_TRACE
) {
785 char buf
[PREFIX2STR_BUFFER
];
786 prefix2str(&up
->rpf
.rpf_addr
, buf
, sizeof(buf
));
787 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
788 __PRETTY_FUNCTION__
, name
,
789 up
->sg_str
, buf
, up
->rpf
.source_nexthop
.interface
?
790 up
->rpf
.source_nexthop
.interface
->name
: "NIL" ,
791 found
, up
->ref_count
);
793 zlog_debug("%s(%s): (%s) failure to create",
794 __PRETTY_FUNCTION__
, name
,
795 pim_str_sg_dump(sg
));
802 * Passed in up must be the upstream for ch. starch is NULL if no
805 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream
*up
,
806 struct pim_ifchannel
*ch
,
807 struct pim_ifchannel
*starch
)
810 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
813 if (!pim_macro_ch_lost_assert(ch
)
814 && pim_macro_chisin_joins_or_include(ch
))
822 if (PIM_IF_FLAG_TEST_S_G_RPT(starch
->upstream
->flags
))
825 if (!pim_macro_ch_lost_assert(starch
)
826 && pim_macro_chisin_joins_or_include(starch
))
834 Evaluate JoinDesired(S,G):
836 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
839 inherited_olist(S,G) =
840 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
842 JoinDesired(S,G) may be affected by changes in the following:
844 pim_ifp->primary_address
846 ch->ifassert_winner_metric
848 ch->local_ifmembership
850 ch->upstream->rpf.source_nexthop.mrib_metric_preference
851 ch->upstream->rpf.source_nexthop.mrib_route_metric
852 ch->upstream->rpf.source_nexthop.interface
854 See also pim_upstream_update_join_desired() below.
856 int pim_upstream_evaluate_join_desired(struct pim_instance
*pim
,
857 struct pim_upstream
*up
)
859 struct interface
*ifp
;
860 struct pim_ifchannel
*ch
, *starch
;
861 struct pim_upstream
*starup
= up
->parent
;
864 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
868 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
871 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
878 ret
+= pim_upstream_evaluate_join_desired_interface(up
, ch
,
880 } /* scan iface channel list */
882 return ret
; /* false */
886 See also pim_upstream_evaluate_join_desired() above.
888 void pim_upstream_update_join_desired(struct pim_instance
*pim
,
889 struct pim_upstream
*up
)
891 int was_join_desired
; /* boolean */
892 int is_join_desired
; /* boolean */
894 was_join_desired
= PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up
->flags
);
896 is_join_desired
= pim_upstream_evaluate_join_desired(pim
, up
);
898 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up
->flags
);
900 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up
->flags
);
902 /* switched from false to true */
903 if (is_join_desired
&& !was_join_desired
) {
904 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_JOINED
);
908 /* switched from true to false */
909 if (!is_join_desired
&& was_join_desired
) {
910 pim_upstream_switch(pim
, up
, PIM_UPSTREAM_NOTJOINED
);
916 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
917 Transitions from Joined State
918 RPF'(S,G) GenID changes
920 The upstream (S,G) state machine remains in Joined state. If the
921 Join Timer is set to expire in more than t_override seconds, reset
922 it so that it expires after t_override seconds.
924 void pim_upstream_rpf_genid_changed(struct pim_instance
*pim
,
925 struct in_addr neigh_addr
)
927 struct listnode
*up_node
;
928 struct listnode
*up_nextnode
;
929 struct pim_upstream
*up
;
932 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
934 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
936 if (PIM_DEBUG_TRACE
) {
937 char neigh_str
[INET_ADDRSTRLEN
];
938 char rpf_addr_str
[PREFIX_STRLEN
];
939 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
,
941 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_addr_str
,
942 sizeof(rpf_addr_str
));
944 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
945 __PRETTY_FUNCTION__
, neigh_str
, up
->sg_str
,
947 up
->join_state
== PIM_UPSTREAM_JOINED
,
951 /* consider only (S,G) upstream in Joined state */
952 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
955 /* match RPF'(S,G)=neigh_addr */
956 if (up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
!= neigh_addr
.s_addr
)
959 pim_upstream_join_timer_decrease_to_t_override(
960 "RPF'(S,G) GenID change", up
);
965 void pim_upstream_rpf_interface_changed(struct pim_upstream
*up
,
966 struct interface
*old_rpf_ifp
)
968 struct listnode
*chnode
;
969 struct listnode
*chnextnode
;
970 struct pim_ifchannel
*ch
;
972 /* search all ifchannels */
973 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
974 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
976 /* RPF_interface(S) was NOT I */
977 (old_rpf_ifp
== ch
->interface
) &&
978 /* RPF_interface(S) stopped being I */
979 (ch
->upstream
->rpf
.source_nexthop
980 .interface
!= ch
->interface
)) {
981 assert_action_a5(ch
);
983 } /* PIM_IFASSERT_I_AM_LOSER */
985 pim_ifchannel_update_assert_tracking_desired(ch
);
989 void pim_upstream_update_could_assert(struct pim_upstream
*up
)
991 struct listnode
*chnode
;
992 struct listnode
*chnextnode
;
993 struct pim_ifchannel
*ch
;
995 /* scan per-interface (S,G) state */
996 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
997 pim_ifchannel_update_could_assert(ch
);
998 } /* scan iface channel list */
1001 void pim_upstream_update_my_assert_metric(struct pim_upstream
*up
)
1003 struct listnode
*chnode
;
1004 struct listnode
*chnextnode
;
1005 struct pim_ifchannel
*ch
;
1007 /* scan per-interface (S,G) state */
1008 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1009 pim_ifchannel_update_my_assert_metric(ch
);
1011 } /* scan iface channel list */
1014 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
)
1016 struct listnode
*chnode
;
1017 struct listnode
*chnextnode
;
1018 struct pim_interface
*pim_ifp
;
1019 struct pim_ifchannel
*ch
;
1021 /* scan per-interface (S,G) state */
1022 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_instance
*pim
,
1038 struct pim_upstream
*up
)
1040 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
1043 if (PIM_DEBUG_TRACE
)
1044 zlog_debug("kat expired on %s; clear fhr reg state",
1047 /* stop reg-stop timer */
1048 THREAD_OFF(up
->t_rs_timer
);
1049 /* remove regiface from the OIL if it is there*/
1050 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1051 PIM_OIF_FLAG_PROTO_PIM
);
1052 /* clear the register state */
1053 up
->reg_state
= PIM_REG_NOINFO
;
1054 PIM_UPSTREAM_FLAG_UNSET_FHR(up
->flags
);
1057 /* When kat is started CouldRegister can go to true. And if it does we
1058 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1060 static void pim_upstream_fhr_kat_start(struct pim_upstream
*up
)
1062 if (pim_upstream_could_register(up
)) {
1063 if (PIM_DEBUG_TRACE
)
1065 "kat started on %s; set fhr reg state to joined",
1068 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1069 if (up
->reg_state
== PIM_REG_NOINFO
)
1070 pim_register_join(up
);
1075 * On an RP, the PMBR value must be cleared when the
1076 * Keepalive Timer expires
1077 * KAT expiry indicates that flow is inactive. If the flow was created or
1078 * maintained by activity now is the time to deref it.
1080 static int pim_upstream_keep_alive_timer(struct thread
*t
)
1082 struct pim_upstream
*up
;
1083 struct pim_instance
*pim
;
1086 pim
= up
->channel_oil
->pim
;
1088 if (I_am_RP(pim
, up
->sg
.grp
)) {
1089 pim_br_clear_pmbr(&up
->sg
);
1091 * We need to do more here :)
1092 * But this is the start.
1096 /* source is no longer active - pull the SA from MSDP's cache */
1097 pim_msdp_sa_local_del(pim
, &up
->sg
);
1099 /* if entry was created because of activity we need to deref it */
1100 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1101 pim_upstream_fhr_kat_expiry(pim
, up
);
1102 if (PIM_DEBUG_TRACE
)
1104 "kat expired on %s[%s]; remove stream reference",
1105 up
->sg_str
, pim
->vrf
->name
);
1106 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up
->flags
);
1107 pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1108 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
1109 struct pim_upstream
*parent
= up
->parent
;
1111 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1112 pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1115 pim_jp_agg_single_upstream_send(&parent
->rpf
, parent
,
1123 void pim_upstream_keep_alive_timer_start(struct pim_upstream
*up
, uint32_t time
)
1125 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1126 if (PIM_DEBUG_TRACE
)
1127 zlog_debug("kat start on %s with no stream reference",
1130 THREAD_OFF(up
->t_ka_timer
);
1131 thread_add_timer(master
, pim_upstream_keep_alive_timer
, up
, time
,
1134 /* any time keepalive is started against a SG we will have to
1135 * re-evaluate our active source database */
1136 pim_msdp_sa_local_update(up
);
1139 /* MSDP on RP needs to know if a source is registerable to this RP */
1140 static int pim_upstream_msdp_reg_timer(struct thread
*t
)
1142 struct pim_upstream
*up
= THREAD_ARG(t
);
1143 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1145 /* source is no longer active - pull the SA from MSDP's cache */
1146 pim_msdp_sa_local_del(pim
, &up
->sg
);
1149 void pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1151 THREAD_OFF(up
->t_msdp_reg_timer
);
1152 thread_add_timer(master
, pim_upstream_msdp_reg_timer
, up
,
1153 PIM_MSDP_REG_RXED_PERIOD
, &up
->t_msdp_reg_timer
);
1155 pim_msdp_sa_local_update(up
);
1159 * 4.2.1 Last-Hop Switchover to the SPT
1161 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1162 * RP. Once traffic from sources to joined groups arrives at a last-hop
1163 * router, it has the option of switching to receive the traffic on a
1164 * shortest path tree (SPT).
1166 * The decision for a router to switch to the SPT is controlled as
1170 * CheckSwitchToSpt(S,G) {
1171 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1172 * (+) pim_include(S,G) != NULL )
1173 * AND SwitchToSptDesired(S,G) ) {
1174 * # Note: Restarting the KAT will result in the SPT switch
1175 * set KeepaliveTimer(S,G) to Keepalive_Period
1179 * SwitchToSptDesired(S,G) is a policy function that is implementation
1180 * defined. An "infinite threshold" policy can be implemented by making
1181 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1182 * first packet" policy can be implemented by making
1183 * SwitchToSptDesired(S,G) return true once a single packet has been
1184 * received for the source and group.
1186 int pim_upstream_switch_to_spt_desired(struct pim_instance
*pim
,
1187 struct prefix_sg
*sg
)
1189 if (I_am_RP(pim
, sg
->grp
))
1195 int pim_upstream_is_sg_rpt(struct pim_upstream
*up
)
1197 struct listnode
*chnode
;
1198 struct pim_ifchannel
*ch
;
1200 for (ALL_LIST_ELEMENTS_RO(up
->ifchannels
, chnode
, ch
)) {
1201 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1208 * After receiving a packet set SPTbit:
1210 * Update_SPTbit(S,G,iif) {
1211 * if ( iif == RPF_interface(S)
1212 * AND JoinDesired(S,G) == TRUE
1213 * AND ( DirectlyConnected(S) == TRUE
1214 * OR RPF_interface(S) != RPF_interface(RP(G))
1215 * OR inherited_olist(S,G,rpt) == NULL
1216 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1217 * ( RPF'(S,G) != NULL ) )
1218 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1219 * Set SPTbit(S,G) to TRUE
1223 void pim_upstream_set_sptbit(struct pim_upstream
*up
,
1224 struct interface
*incoming
)
1226 struct pim_upstream
*starup
= up
->parent
;
1228 // iif == RPF_interfvace(S)
1229 if (up
->rpf
.source_nexthop
.interface
!= incoming
) {
1230 if (PIM_DEBUG_TRACE
)
1232 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1233 __PRETTY_FUNCTION__
, incoming
->name
,
1234 up
->rpf
.source_nexthop
.interface
->name
);
1238 // AND JoinDesired(S,G) == TRUE
1241 // DirectlyConnected(S) == TRUE
1242 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1244 if (PIM_DEBUG_TRACE
)
1245 zlog_debug("%s: %s is directly connected to the source",
1246 __PRETTY_FUNCTION__
, up
->sg_str
);
1247 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1251 // OR RPF_interface(S) != RPF_interface(RP(G))
1253 || up
->rpf
.source_nexthop
1254 .interface
!= starup
->rpf
.source_nexthop
.interface
) {
1255 if (PIM_DEBUG_TRACE
)
1257 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1258 __PRETTY_FUNCTION__
, up
->sg_str
);
1259 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1263 // OR inherited_olist(S,G,rpt) == NULL
1264 if (pim_upstream_is_sg_rpt(up
)
1265 && pim_upstream_empty_inherited_olist(up
)) {
1266 if (PIM_DEBUG_TRACE
)
1267 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1268 __PRETTY_FUNCTION__
, up
->sg_str
);
1269 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1273 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1274 // ( RPF'(S,G) != NULL ) )
1275 if (up
->parent
&& pim_rpf_is_same(&up
->rpf
, &up
->parent
->rpf
)) {
1276 if (PIM_DEBUG_TRACE
)
1277 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1278 __PRETTY_FUNCTION__
, up
->sg_str
);
1279 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1286 const char *pim_upstream_state2str(enum pim_upstream_state join_state
)
1288 switch (join_state
) {
1289 case PIM_UPSTREAM_NOTJOINED
:
1292 case PIM_UPSTREAM_JOINED
:
1299 const char *pim_reg_state2str(enum pim_reg_state reg_state
, char *state_str
)
1301 switch (reg_state
) {
1302 case PIM_REG_NOINFO
:
1303 strcpy(state_str
, "RegNoInfo");
1306 strcpy(state_str
, "RegJoined");
1308 case PIM_REG_JOIN_PENDING
:
1309 strcpy(state_str
, "RegJoinPend");
1312 strcpy(state_str
, "RegPrune");
1315 strcpy(state_str
, "RegUnknown");
1320 static int pim_upstream_register_stop_timer(struct thread
*t
)
1322 struct pim_interface
*pim_ifp
;
1323 struct pim_instance
*pim
;
1324 struct pim_upstream
*up
;
1325 struct pim_rpf
*rpg
;
1328 pim
= up
->channel_oil
->pim
;
1330 if (PIM_DEBUG_TRACE
) {
1331 char state_str
[PIM_REG_STATE_STR_LEN
];
1332 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1333 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
1334 pim_reg_state2str(up
->reg_state
, state_str
));
1337 switch (up
->reg_state
) {
1338 case PIM_REG_JOIN_PENDING
:
1339 up
->reg_state
= PIM_REG_JOIN
;
1340 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1341 PIM_OIF_FLAG_PROTO_PIM
);
1346 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1348 if (PIM_DEBUG_TRACE
)
1350 "%s: Interface: %s is not configured for pim",
1351 __PRETTY_FUNCTION__
,
1352 up
->rpf
.source_nexthop
.interface
->name
);
1355 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1356 pim_upstream_start_register_stop_timer(up
, 1);
1358 if (((up
->channel_oil
->cc
.lastused
/ 100)
1359 > pim
->keep_alive_time
)
1360 && (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
))) {
1361 if (PIM_DEBUG_TRACE
)
1363 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1364 __PRETTY_FUNCTION__
);
1367 rpg
= RP(pim_ifp
->pim
, up
->sg
.grp
);
1369 if (PIM_DEBUG_TRACE
)
1371 "%s: Cannot send register for %s no RPF to the RP",
1372 __PRETTY_FUNCTION__
, up
->sg_str
);
1375 memset(&ip_hdr
, 0, sizeof(struct ip
));
1376 ip_hdr
.ip_p
= PIM_IP_PROTO_PIM
;
1379 ip_hdr
.ip_src
= up
->sg
.src
;
1380 ip_hdr
.ip_dst
= up
->sg
.grp
;
1381 ip_hdr
.ip_len
= htons(20);
1382 // checksum is broken
1383 pim_register_send((uint8_t *)&ip_hdr
, sizeof(struct ip
),
1384 pim_ifp
->primary_address
, rpg
, 1, up
);
1393 void pim_upstream_start_register_stop_timer(struct pim_upstream
*up
,
1398 THREAD_TIMER_OFF(up
->t_rs_timer
);
1400 if (!null_register
) {
1401 uint32_t lower
= (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1402 uint32_t upper
= (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1403 time
= lower
+ (random() % (upper
- lower
+ 1))
1404 - PIM_REGISTER_PROBE_PERIOD
;
1406 time
= PIM_REGISTER_PROBE_PERIOD
;
1408 if (PIM_DEBUG_TRACE
) {
1410 "%s: (S,G)=%s Starting upstream register stop timer %d",
1411 __PRETTY_FUNCTION__
, up
->sg_str
, time
);
1413 thread_add_timer(master
, pim_upstream_register_stop_timer
, up
, time
,
1417 int pim_upstream_inherited_olist_decide(struct pim_instance
*pim
,
1418 struct pim_upstream
*up
)
1420 struct interface
*ifp
;
1421 struct pim_interface
*pim_ifp
= NULL
;
1422 struct pim_ifchannel
*ch
, *starch
;
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
;
1429 if (PIM_DEBUG_TRACE
)
1430 zlog_debug("%s: up %s RPF is not present",
1431 __PRETTY_FUNCTION__
, up
->sg_str
);
1433 if (pim_ifp
&& !up
->channel_oil
)
1434 up
->channel_oil
= pim_channel_oil_add(
1435 pim
, &up
->sg
, pim_ifp
->mroute_vif_index
);
1437 FOR_ALL_INTERFACES (pim
->vrf
, 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
,
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
1482 int pim_upstream_inherited_olist(struct pim_instance
*pim
,
1483 struct pim_upstream
*up
)
1485 int output_intf
= pim_upstream_inherited_olist_decide(pim
, 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(pim
, up
, PIM_UPSTREAM_JOINED
);
1501 int pim_upstream_empty_inherited_olist(struct pim_upstream
*up
)
1503 return pim_channel_oil_empty(up
->channel_oil
);
1507 * When we have a new neighbor,
1508 * find upstreams that don't have their rpf_addr
1509 * set and see if the new neighbor allows
1510 * the join to be sent
1512 void pim_upstream_find_new_rpf(struct pim_instance
*pim
)
1514 struct listnode
*up_node
;
1515 struct listnode
*up_nextnode
;
1516 struct pim_upstream
*up
;
1519 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1521 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
1522 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
1523 if (PIM_DEBUG_TRACE
)
1525 "Upstream %s without a path to send join, checking",
1527 pim_rpf_update(pim
, up
, NULL
, 1);
1532 unsigned int pim_upstream_hash_key(void *arg
)
1534 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1536 return jhash_2words(up
->sg
.src
.s_addr
, up
->sg
.grp
.s_addr
, 0);
1539 void pim_upstream_terminate(struct pim_instance
*pim
)
1541 struct listnode
*node
, *nnode
;
1542 struct pim_upstream
*up
;
1544 if (pim
->upstream_list
) {
1545 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, node
, nnode
, up
))
1546 pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1548 list_delete_and_null(&pim
->upstream_list
);
1551 if (pim
->upstream_hash
)
1552 hash_free(pim
->upstream_hash
);
1553 pim
->upstream_hash
= NULL
;
1556 int pim_upstream_equal(const void *arg1
, const void *arg2
)
1558 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1559 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1561 if ((up1
->sg
.grp
.s_addr
== up2
->sg
.grp
.s_addr
)
1562 && (up1
->sg
.src
.s_addr
== up2
->sg
.src
.s_addr
))
1568 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1569 * the cases where kat has to be restarted on rxing traffic -
1571 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1572 * set KeepaliveTimer(S,G) to Keepalive_Period
1573 * # Note: a register state transition or UpstreamJPState(S,G)
1574 * # transition may happen as a result of restarting
1575 * # KeepaliveTimer, and must be dealt with here.
1577 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1578 * inherited_olist(S,G) != NULL ) {
1579 * set KeepaliveTimer(S,G) to Keepalive_Period
1582 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1584 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1586 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1587 * so we will skip that here */
1588 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1593 if ((up
->join_state
== PIM_UPSTREAM_JOINED
)
1594 && !pim_upstream_empty_inherited_olist(up
)) {
1595 /* XXX: I have added this RP check just for 3.2 and it's a
1597 * what rfc-4601 says. Till now we were only running KAT on FHR
1599 * there is some angst around making the change to run it all
1601 * maintain the (S, G) state. This is tracked via CM-13601 and
1603 * removed to handle spt turn-arounds correctly in a 3-tier clos
1605 if (I_am_RP(pim
, up
->sg
.grp
))
1613 * Code to check and see if we've received packets on a S,G mroute
1614 * and if so to set the SPT bit appropriately
1616 static void pim_upstream_sg_running(void *arg
)
1618 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1619 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1621 // No packet can have arrived here if this is the case
1622 if (!up
->channel_oil
->installed
) {
1623 if (PIM_DEBUG_TRACE
)
1624 zlog_debug("%s: %s[%s] is not installed in mroute",
1625 __PRETTY_FUNCTION__
, up
->sg_str
,
1631 * This is a bit of a hack
1632 * We've noted that we should rescan but
1633 * we've missed the window for doing so in
1634 * pim_zebra.c for some reason. I am
1635 * only doing this at this point in time
1636 * to get us up and working for the moment
1638 if (up
->channel_oil
->oil_inherited_rescan
) {
1639 if (PIM_DEBUG_TRACE
)
1641 "%s: Handling unscanned inherited_olist for %s[%s]",
1642 __PRETTY_FUNCTION__
, up
->sg_str
,
1644 pim_upstream_inherited_olist_decide(pim
, up
);
1645 up
->channel_oil
->oil_inherited_rescan
= 0;
1647 pim_mroute_update_counters(up
->channel_oil
);
1649 // Have we seen packets?
1650 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
)
1651 && (up
->channel_oil
->cc
.lastused
/ 100 > 30)) {
1652 if (PIM_DEBUG_TRACE
) {
1654 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1655 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
1656 up
->channel_oil
->cc
.oldpktcnt
,
1657 up
->channel_oil
->cc
.pktcnt
,
1658 up
->channel_oil
->cc
.lastused
/ 100);
1663 if (pim_upstream_kat_start_ok(up
)) {
1664 /* Add a source reference to the stream if
1665 * one doesn't already exist */
1666 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1667 if (PIM_DEBUG_TRACE
)
1669 "source reference created on kat restart %s[%s]",
1670 up
->sg_str
, pim
->vrf
->name
);
1672 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
,
1673 __PRETTY_FUNCTION__
);
1674 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
1675 pim_upstream_fhr_kat_start(up
);
1677 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1678 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
))
1679 pim_upstream_keep_alive_timer_start(up
, pim
->keep_alive_time
);
1681 if (up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
) {
1682 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
1687 void pim_upstream_add_lhr_star_pimreg(struct pim_instance
*pim
)
1689 struct pim_upstream
*up
;
1690 struct listnode
*node
;
1692 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
,
1700 PIM_OIF_FLAG_PROTO_IGMP
);
1704 void pim_upstream_spt_prefix_list_update(struct pim_instance
*pim
,
1705 struct prefix_list
*pl
)
1707 const char *pname
= prefix_list_name(pl
);
1709 if (pim
->spt
.plist
&& strcmp(pim
->spt
.plist
, pname
) == 0) {
1710 pim_upstream_remove_lhr_star_pimreg(pim
, pname
);
1715 * nlist -> The new prefix list
1717 * Per Group Application of pimreg to the OIL
1718 * If the prefix list tells us DENY then
1719 * we need to Switchover to SPT immediate
1720 * so add the pimreg.
1721 * If the prefix list tells us to ACCEPT than
1722 * we need to Never do the SPT so remove
1726 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance
*pim
,
1729 struct pim_upstream
*up
;
1730 struct listnode
*node
;
1731 struct prefix_list
*np
;
1733 enum prefix_list_type apply_new
;
1735 np
= prefix_list_lookup(AFI_IP
, nlist
);
1738 g
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1740 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1741 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1744 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1748 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1749 PIM_OIF_FLAG_PROTO_IGMP
);
1752 g
.u
.prefix4
= up
->sg
.grp
;
1753 apply_new
= prefix_list_apply(np
, &g
);
1754 if (apply_new
== PREFIX_DENY
)
1755 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1756 PIM_OIF_FLAG_PROTO_IGMP
);
1758 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1759 PIM_OIF_FLAG_PROTO_IGMP
);
1763 void pim_upstream_init(struct pim_instance
*pim
)
1767 pim
->upstream_sg_wheel
=
1768 wheel_init(master
, 31000, 100, pim_upstream_hash_key
,
1769 pim_upstream_sg_running
);
1771 snprintf(hash_name
, 64, "PIM %s Upstream Hash", pim
->vrf
->name
);
1772 pim
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
1773 pim_upstream_equal
, hash_name
);
1775 pim
->upstream_list
= list_new();
1776 pim
->upstream_list
->cmp
= pim_upstream_compare
;