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 pim_channel_oil_del(up
->channel_oil
);
157 up
->channel_oil
= NULL
;
161 struct pim_upstream
*pim_upstream_del(struct pim_instance
*pim
,
162 struct pim_upstream
*up
, const char *name
)
164 bool notify_msdp
= false;
169 "%s(%s): Delete %s ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
170 __PRETTY_FUNCTION__
, name
, up
->sg_str
, up
->ref_count
,
171 up
->flags
, up
->channel_oil
->oil_ref_count
);
175 if (up
->ref_count
>= 1)
178 THREAD_OFF(up
->t_ka_timer
);
179 THREAD_OFF(up
->t_rs_timer
);
180 THREAD_OFF(up
->t_msdp_reg_timer
);
182 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
183 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 0);
185 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
186 /* if a (*, G) entry in the joined state is being
188 * need to notify MSDP */
194 pim_jp_agg_upstream_verification(up
, false);
195 up
->rpf
.source_nexthop
.interface
= NULL
;
197 if (up
->sg
.src
.s_addr
!= INADDR_ANY
) {
198 wheel_remove_item(pim
->upstream_sg_wheel
, up
);
202 pim_upstream_remove_children(pim
, up
);
204 list_delete(up
->sources
);
206 pim_mroute_del(up
->channel_oil
, __PRETTY_FUNCTION__
);
207 upstream_channel_oil_detach(up
);
209 list_delete(up
->ifchannels
);
210 up
->ifchannels
= NULL
;
213 notice that listnode_delete() can't be moved
214 into pim_upstream_free() because the later is
215 called by list_delete_all_node()
217 if (up
->parent
&& up
->parent
->sources
)
218 listnode_delete(up
->parent
->sources
, up
);
221 listnode_delete(pim
->upstream_list
, up
);
222 hash_release(pim
->upstream_hash
, up
);
225 pim_msdp_up_del(pim
, &up
->sg
);
228 /* Deregister addr with Zebra NHT */
229 nht_p
.family
= AF_INET
;
230 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
231 nht_p
.u
.prefix4
= up
->upstream_addr
;
232 if (PIM_DEBUG_TRACE
) {
233 char buf
[PREFIX2STR_BUFFER
];
234 prefix2str(&nht_p
, buf
, sizeof(buf
));
235 zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
236 __PRETTY_FUNCTION__
, up
->sg_str
, buf
);
238 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
);
240 pim_upstream_free(up
);
245 void pim_upstream_send_join(struct pim_upstream
*up
)
247 if (PIM_DEBUG_TRACE
) {
248 char rpf_str
[PREFIX_STRLEN
];
249 pim_addr_dump("<rpf?>", &up
->rpf
.rpf_addr
, rpf_str
,
251 zlog_debug("%s: RPF'%s=%s(%s) for Interface %s",
252 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
253 pim_upstream_state2str(up
->join_state
),
254 up
->rpf
.source_nexthop
.interface
->name
);
255 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
256 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
257 __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
);
262 /* send Join(S,G) to the current upstream neighbor */
263 pim_jp_agg_single_upstream_send(&up
->rpf
, up
, 1 /* join */);
266 static int on_join_timer(struct thread
*t
)
268 struct pim_upstream
*up
;
273 * In the case of a HFR we will not ahve anyone to send this to.
275 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
279 * Don't send the join if the outgoing interface is a loopback
280 * But since this might change leave the join timer running
282 if (up
->rpf
.source_nexthop
283 .interface
&& !if_is_loopback(up
->rpf
.source_nexthop
.interface
))
284 pim_upstream_send_join(up
);
286 join_timer_start(up
);
291 static void join_timer_stop(struct pim_upstream
*up
)
293 struct pim_neighbor
*nbr
;
295 THREAD_OFF(up
->t_join_timer
);
297 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
298 up
->rpf
.rpf_addr
.u
.prefix4
);
301 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
);
303 pim_jp_agg_upstream_verification(up
, false);
306 void join_timer_start(struct pim_upstream
*up
)
308 struct pim_neighbor
*nbr
= NULL
;
310 if (up
->rpf
.source_nexthop
.interface
) {
311 nbr
= pim_neighbor_find(up
->rpf
.source_nexthop
.interface
,
312 up
->rpf
.rpf_addr
.u
.prefix4
);
314 if (PIM_DEBUG_PIM_EVENTS
) {
316 "%s: starting %d sec timer for upstream (S,G)=%s",
317 __PRETTY_FUNCTION__
, qpim_t_periodic
,
323 pim_jp_agg_add_group(nbr
->upstream_jp_agg
, up
, 1);
325 THREAD_OFF(up
->t_join_timer
);
326 thread_add_timer(master
, on_join_timer
, up
, qpim_t_periodic
,
329 pim_jp_agg_upstream_verification(up
, true);
333 * This is only called when we are switching the upstream
334 * J/P from one neighbor to another
336 * As such we need to remove from the old list and
337 * add to the new list.
339 void pim_upstream_join_timer_restart(struct pim_upstream
*up
,
342 // THREAD_OFF(up->t_join_timer);
343 join_timer_start(up
);
346 static void pim_upstream_join_timer_restart_msec(struct pim_upstream
*up
,
349 if (PIM_DEBUG_PIM_EVENTS
) {
350 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
351 __PRETTY_FUNCTION__
, interval_msec
, up
->sg_str
);
354 THREAD_OFF(up
->t_join_timer
);
355 thread_add_timer_msec(master
, on_join_timer
, up
, interval_msec
,
359 void pim_upstream_join_suppress(struct pim_upstream
*up
,
360 struct in_addr rpf_addr
, int holdtime
)
362 long t_joinsuppress_msec
;
363 long join_timer_remain_msec
;
365 t_joinsuppress_msec
=
366 MIN(pim_if_t_suppressed_msec(up
->rpf
.source_nexthop
.interface
),
369 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
371 if (PIM_DEBUG_TRACE
) {
372 char rpf_str
[INET_ADDRSTRLEN
];
373 pim_inet4_dump("<rpf?>", rpf_addr
, rpf_str
, sizeof(rpf_str
));
375 "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
376 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
, rpf_str
,
377 join_timer_remain_msec
, t_joinsuppress_msec
);
380 if (join_timer_remain_msec
< t_joinsuppress_msec
) {
381 if (PIM_DEBUG_TRACE
) {
383 "%s %s: suppressing Join(S,G)=%s for %ld msec",
384 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
,
385 t_joinsuppress_msec
);
388 pim_upstream_join_timer_restart_msec(up
, t_joinsuppress_msec
);
392 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label
,
393 struct pim_upstream
*up
)
395 long join_timer_remain_msec
;
398 join_timer_remain_msec
= pim_time_timer_remain_msec(up
->t_join_timer
);
400 pim_if_t_override_msec(up
->rpf
.source_nexthop
.interface
);
402 if (PIM_DEBUG_TRACE
) {
403 char rpf_str
[INET_ADDRSTRLEN
];
404 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
.u
.prefix4
, rpf_str
,
407 "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
408 debug_label
, up
->sg_str
, rpf_str
,
409 join_timer_remain_msec
, t_override_msec
);
412 if (join_timer_remain_msec
> t_override_msec
) {
413 if (PIM_DEBUG_TRACE
) {
415 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
416 debug_label
, up
->sg_str
, t_override_msec
);
419 pim_upstream_join_timer_restart_msec(up
, t_override_msec
);
423 static void forward_on(struct pim_upstream
*up
)
425 struct listnode
*chnode
;
426 struct listnode
*chnextnode
;
427 struct pim_ifchannel
*ch
= NULL
;
429 /* scan (S,G) state */
430 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
431 if (pim_macro_chisin_oiflist(ch
))
432 pim_forward_start(ch
);
434 } /* scan iface channel list */
437 static void forward_off(struct pim_upstream
*up
)
439 struct listnode
*chnode
;
440 struct listnode
*chnextnode
;
441 struct pim_ifchannel
*ch
;
443 /* scan per-interface (S,G) state */
444 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
446 pim_forward_stop(ch
);
448 } /* scan iface channel list */
451 static int pim_upstream_could_register(struct pim_upstream
*up
)
453 struct pim_interface
*pim_ifp
= NULL
;
455 if (up
->rpf
.source_nexthop
.interface
)
456 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
459 zlog_debug("%s: up %s RPF is not present",
460 __PRETTY_FUNCTION__
, up
->sg_str
);
463 if (pim_ifp
&& PIM_I_am_DR(pim_ifp
)
464 && pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
471 /* Source registration is supressed for SSM groups. When the SSM range changes
472 * we re-revaluate register setup for existing upstream entries */
473 void pim_upstream_register_reevaluate(struct pim_instance
*pim
)
475 struct listnode
*upnode
;
476 struct pim_upstream
*up
;
478 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
479 /* If FHR is set CouldRegister is True. Also check if the flow
480 * is actually active; if it is not kat setup will trigger
482 * registration whenever the flow becomes active. */
483 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) || !up
->t_ka_timer
)
486 if (pim_is_grp_ssm(pim
, up
->sg
.grp
)) {
487 /* clear the register state for SSM groups */
488 if (up
->reg_state
!= PIM_REG_NOINFO
) {
489 if (PIM_DEBUG_PIM_EVENTS
)
491 "Clear register for %s as G is now SSM",
493 /* remove regiface from the OIL if it is there*/
494 pim_channel_del_oif(up
->channel_oil
,
496 PIM_OIF_FLAG_PROTO_PIM
);
497 up
->reg_state
= PIM_REG_NOINFO
;
500 /* register ASM sources with the RP */
501 if (up
->reg_state
== PIM_REG_NOINFO
) {
502 if (PIM_DEBUG_PIM_EVENTS
)
504 "Register %s as G is now ASM",
506 pim_channel_add_oif(up
->channel_oil
,
508 PIM_OIF_FLAG_PROTO_PIM
);
509 up
->reg_state
= PIM_REG_JOIN
;
515 void pim_upstream_switch(struct pim_upstream
*up
,
516 enum pim_upstream_state new_state
)
518 enum pim_upstream_state old_state
= up
->join_state
;
520 if (PIM_DEBUG_PIM_EVENTS
) {
521 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
522 __PRETTY_FUNCTION__
, up
->sg_str
,
523 pim_upstream_state2str(up
->join_state
),
524 pim_upstream_state2str(new_state
));
527 up
->join_state
= new_state
;
528 if (old_state
!= new_state
)
529 up
->state_transition
= pim_time_monotonic_sec();
531 pim_upstream_update_assert_tracking_desired(up
);
533 if (new_state
== PIM_UPSTREAM_JOINED
) {
534 if (old_state
!= PIM_UPSTREAM_JOINED
) {
535 int old_fhr
= PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
);
537 pim_msdp_up_join_state_changed(up
);
538 if (pim_upstream_could_register(up
)) {
539 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
541 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
543 pim_upstream_keep_alive_timer_start(
544 up
, qpim_keep_alive_time
);
545 pim_register_join(up
);
548 pim_upstream_send_join(up
);
549 join_timer_start(up
);
557 if (old_state
== PIM_UPSTREAM_JOINED
)
558 pim_msdp_up_join_state_changed(up
);
560 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
562 If I am RP for G then send S,G prune to its IIF. */
563 if (pim_upstream_is_sg_rpt(up
) && up
->parent
564 && !I_am_RP(up
->channel_oil
->pim
, up
->sg
.grp
)) {
565 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
567 "%s: *,G IIF %s S,G IIF %s ",
569 up
->parent
->rpf
.source_nexthop
571 up
->rpf
.source_nexthop
.interface
->name
);
572 pim_jp_agg_single_upstream_send(&up
->parent
->rpf
,
576 pim_jp_agg_single_upstream_send(&up
->rpf
, up
,
582 int pim_upstream_compare(void *arg1
, void *arg2
)
584 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
585 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
587 if (ntohl(up1
->sg
.grp
.s_addr
) < ntohl(up2
->sg
.grp
.s_addr
))
590 if (ntohl(up1
->sg
.grp
.s_addr
) > ntohl(up2
->sg
.grp
.s_addr
))
593 if (ntohl(up1
->sg
.src
.s_addr
) < ntohl(up2
->sg
.src
.s_addr
))
596 if (ntohl(up1
->sg
.src
.s_addr
) > ntohl(up2
->sg
.src
.s_addr
))
602 static struct pim_upstream
*pim_upstream_new(struct pim_instance
*pim
,
603 struct prefix_sg
*sg
,
604 struct interface
*incoming
,
607 enum pim_rpf_result rpf_result
;
608 struct pim_interface
*pim_ifp
;
609 struct pim_upstream
*up
;
611 up
= XCALLOC(MTYPE_PIM_UPSTREAM
, sizeof(*up
));
613 zlog_err("%s: PIM XCALLOC(%zu) failure", __PRETTY_FUNCTION__
,
619 pim_str_sg_set(sg
, up
->sg_str
);
620 up
= hash_get(pim
->upstream_hash
, up
, hash_alloc_intern
);
621 if (!pim_rp_set_upstream_addr(pim
, &up
->upstream_addr
, sg
->src
,
624 zlog_debug("%s: Received a (*,G) with no RP configured",
625 __PRETTY_FUNCTION__
);
627 hash_release(pim
->upstream_hash
, up
);
628 XFREE(MTYPE_PIM_UPSTREAM
, up
);
632 up
->parent
= pim_upstream_find_parent(pim
, up
);
633 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
634 up
->sources
= list_new();
635 up
->sources
->cmp
= pim_upstream_compare
;
639 pim_upstream_find_new_children(pim
, up
);
642 up
->t_join_timer
= NULL
;
643 up
->t_ka_timer
= NULL
;
644 up
->t_rs_timer
= NULL
;
645 up
->t_msdp_reg_timer
= NULL
;
646 up
->join_state
= PIM_UPSTREAM_NOTJOINED
;
647 up
->reg_state
= PIM_REG_NOINFO
;
648 up
->state_transition
= pim_time_monotonic_sec();
649 up
->channel_oil
= NULL
;
650 up
->sptbit
= PIM_UPSTREAM_SPTBIT_FALSE
;
652 up
->rpf
.source_nexthop
.interface
= NULL
;
653 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.family
= AF_INET
;
654 up
->rpf
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
656 up
->rpf
.source_nexthop
.mrib_metric_preference
=
657 qpim_infinite_assert_metric
.metric_preference
;
658 up
->rpf
.source_nexthop
.mrib_route_metric
=
659 qpim_infinite_assert_metric
.route_metric
;
660 up
->rpf
.rpf_addr
.family
= AF_INET
;
661 up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
= PIM_NET_INADDR_ANY
;
663 up
->ifchannels
= list_new();
664 up
->ifchannels
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
666 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
667 wheel_add_item(pim
->upstream_sg_wheel
, up
);
669 rpf_result
= pim_rpf_update(pim
, up
, NULL
, 1);
670 if (rpf_result
== PIM_RPF_FAILURE
) {
675 "%s: Attempting to create upstream(%s), Unable to RPF for source",
676 __PRETTY_FUNCTION__
, up
->sg_str
);
678 nht_p
.family
= AF_INET
;
679 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
680 nht_p
.u
.prefix4
= up
->upstream_addr
;
681 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
);
684 listnode_delete(up
->parent
->sources
, up
);
688 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
689 wheel_remove_item(pim
->upstream_sg_wheel
, up
);
691 pim_upstream_remove_children(pim
, up
);
693 list_delete(up
->sources
);
695 hash_release(pim
->upstream_hash
, up
);
696 XFREE(MTYPE_PIM_UPSTREAM
, up
);
700 if (up
->rpf
.source_nexthop
.interface
) {
701 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
703 up
->channel_oil
= pim_channel_oil_add(
704 pim
, &up
->sg
, pim_ifp
->mroute_vif_index
);
706 listnode_add_sort(pim
->upstream_list
, up
);
708 if (PIM_DEBUG_TRACE
) {
710 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
711 __PRETTY_FUNCTION__
, up
->sg_str
,
712 inet_ntoa(up
->upstream_addr
), up
->ref_count
);
718 struct pim_upstream
*pim_upstream_find(struct pim_instance
*pim
,
719 struct prefix_sg
*sg
)
721 struct pim_upstream lookup
;
722 struct pim_upstream
*up
= NULL
;
725 up
= hash_lookup(pim
->upstream_hash
, &lookup
);
729 struct pim_upstream
*pim_upstream_find_or_add(struct prefix_sg
*sg
,
730 struct interface
*incoming
,
731 int flags
, const char *name
)
733 struct pim_upstream
*up
;
734 struct pim_interface
*pim_ifp
;
736 pim_ifp
= incoming
->info
;
738 up
= pim_upstream_find(pim_ifp
->pim
, sg
);
741 if (!(up
->flags
& flags
)) {
746 "%s(%s): upstream %s ref count %d increment",
747 __PRETTY_FUNCTION__
, name
, up
->sg_str
,
751 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
,
771 struct pim_upstream
*up
= NULL
;
774 up
= pim_upstream_find(pim
, sg
);
776 pim_upstream_ref(up
, flags
, name
);
779 up
= pim_upstream_new(pim
, sg
, incoming
, flags
);
782 if (PIM_DEBUG_TRACE
) {
784 char buf
[PREFIX2STR_BUFFER
];
785 prefix2str(&up
->rpf
.rpf_addr
, buf
, sizeof(buf
));
786 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
787 __PRETTY_FUNCTION__
, name
,
788 up
->sg_str
, buf
, up
->rpf
.source_nexthop
.interface
?
789 up
->rpf
.source_nexthop
.interface
->name
: "NIL" ,
790 found
, up
->ref_count
);
792 zlog_debug("%s(%s): (%s) failure to create",
793 __PRETTY_FUNCTION__
, name
,
794 pim_str_sg_dump(sg
));
801 * Passed in up must be the upstream for ch. starch is NULL if no
804 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream
*up
,
805 struct pim_ifchannel
*ch
,
806 struct pim_ifchannel
*starch
)
809 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
812 if (!pim_macro_ch_lost_assert(ch
)
813 && pim_macro_chisin_joins_or_include(ch
))
821 if (PIM_IF_FLAG_TEST_S_G_RPT(starch
->upstream
->flags
))
824 if (!pim_macro_ch_lost_assert(starch
)
825 && pim_macro_chisin_joins_or_include(starch
))
833 Evaluate JoinDesired(S,G):
835 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
838 inherited_olist(S,G) =
839 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
841 JoinDesired(S,G) may be affected by changes in the following:
843 pim_ifp->primary_address
845 ch->ifassert_winner_metric
847 ch->local_ifmembership
849 ch->upstream->rpf.source_nexthop.mrib_metric_preference
850 ch->upstream->rpf.source_nexthop.mrib_route_metric
851 ch->upstream->rpf.source_nexthop.interface
853 See also pim_upstream_update_join_desired() below.
855 int pim_upstream_evaluate_join_desired(struct pim_instance
*pim
,
856 struct pim_upstream
*up
)
858 struct interface
*ifp
;
859 struct listnode
*node
;
860 struct pim_ifchannel
*ch
, *starch
;
861 struct pim_upstream
*starup
= up
->parent
;
864 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim
->vrf_id
), node
, 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(up
, PIM_UPSTREAM_JOINED
);
908 /* switched from true to false */
909 if (!is_join_desired
&& was_join_desired
) {
910 pim_upstream_switch(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 joined=%d rpf_addr=%s",
945 __PRETTY_FUNCTION__
, neigh_str
, up
->sg_str
,
946 up
->join_state
== PIM_UPSTREAM_JOINED
,
950 /* consider only (S,G) upstream in Joined state */
951 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
954 /* match RPF'(S,G)=neigh_addr */
955 if (up
->rpf
.rpf_addr
.u
.prefix4
.s_addr
!= neigh_addr
.s_addr
)
958 pim_upstream_join_timer_decrease_to_t_override(
959 "RPF'(S,G) GenID change", up
);
964 void pim_upstream_rpf_interface_changed(struct pim_upstream
*up
,
965 struct interface
*old_rpf_ifp
)
967 struct listnode
*chnode
;
968 struct listnode
*chnextnode
;
969 struct pim_ifchannel
*ch
;
971 /* search all ifchannels */
972 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
973 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
975 /* RPF_interface(S) was NOT I */
976 (old_rpf_ifp
== ch
->interface
) &&
977 /* RPF_interface(S) stopped being I */
978 (ch
->upstream
->rpf
.source_nexthop
979 .interface
!= ch
->interface
)) {
980 assert_action_a5(ch
);
982 } /* PIM_IFASSERT_I_AM_LOSER */
984 pim_ifchannel_update_assert_tracking_desired(ch
);
988 void pim_upstream_update_could_assert(struct pim_upstream
*up
)
990 struct listnode
*chnode
;
991 struct listnode
*chnextnode
;
992 struct pim_ifchannel
*ch
;
994 /* scan per-interface (S,G) state */
995 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
996 pim_ifchannel_update_could_assert(ch
);
997 } /* scan iface channel list */
1000 void pim_upstream_update_my_assert_metric(struct pim_upstream
*up
)
1002 struct listnode
*chnode
;
1003 struct listnode
*chnextnode
;
1004 struct pim_ifchannel
*ch
;
1006 /* scan per-interface (S,G) state */
1007 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1008 pim_ifchannel_update_my_assert_metric(ch
);
1010 } /* scan iface channel list */
1013 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream
*up
)
1015 struct listnode
*chnode
;
1016 struct listnode
*chnextnode
;
1017 struct pim_interface
*pim_ifp
;
1018 struct pim_ifchannel
*ch
;
1020 /* scan per-interface (S,G) state */
1021 for (ALL_LIST_ELEMENTS(up
->ifchannels
, chnode
, chnextnode
, ch
)) {
1024 pim_ifp
= ch
->interface
->info
;
1028 pim_ifchannel_update_assert_tracking_desired(ch
);
1030 } /* scan iface channel list */
1033 /* When kat is stopped CouldRegister goes to false so we need to
1034 * transition the (S, G) on FHR to NI state and remove reg tunnel
1036 static void pim_upstream_fhr_kat_expiry(struct pim_instance
*pim
,
1037 struct pim_upstream
*up
)
1039 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
1042 if (PIM_DEBUG_TRACE
)
1043 zlog_debug("kat expired on %s; clear fhr reg state",
1046 /* stop reg-stop timer */
1047 THREAD_OFF(up
->t_rs_timer
);
1048 /* remove regiface from the OIL if it is there*/
1049 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1050 PIM_OIF_FLAG_PROTO_PIM
);
1051 /* clear the register state */
1052 up
->reg_state
= PIM_REG_NOINFO
;
1053 PIM_UPSTREAM_FLAG_UNSET_FHR(up
->flags
);
1056 /* When kat is started CouldRegister can go to true. And if it does we
1057 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1059 static void pim_upstream_fhr_kat_start(struct pim_upstream
*up
)
1061 if (pim_upstream_could_register(up
)) {
1062 if (PIM_DEBUG_TRACE
)
1064 "kat started on %s; set fhr reg state to joined",
1067 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
1068 if (up
->reg_state
== PIM_REG_NOINFO
)
1069 pim_register_join(up
);
1074 * On an RP, the PMBR value must be cleared when the
1075 * Keepalive Timer expires
1076 * KAT expiry indicates that flow is inactive. If the flow was created or
1077 * maintained by activity now is the time to deref it.
1079 static int pim_upstream_keep_alive_timer(struct thread
*t
)
1081 struct pim_upstream
*up
;
1082 struct pim_instance
*pim
;
1085 pim
= up
->channel_oil
->pim
;
1087 if (I_am_RP(pim
, up
->sg
.grp
)) {
1088 pim_br_clear_pmbr(&up
->sg
);
1090 * We need to do more here :)
1091 * But this is the start.
1095 /* source is no longer active - pull the SA from MSDP's cache */
1096 pim_msdp_sa_local_del(pim
, &up
->sg
);
1098 /* if entry was created because of activity we need to deref it */
1099 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1100 pim_upstream_fhr_kat_expiry(pim
, up
);
1101 if (PIM_DEBUG_TRACE
)
1102 zlog_debug("kat expired on %s; remove stream reference",
1104 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up
->flags
);
1105 pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1106 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
)) {
1107 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up
->flags
);
1108 pim_upstream_del(pim
, up
, __PRETTY_FUNCTION__
);
1114 void pim_upstream_keep_alive_timer_start(struct pim_upstream
*up
, uint32_t time
)
1116 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1117 if (PIM_DEBUG_TRACE
)
1118 zlog_debug("kat start on %s with no stream reference",
1121 THREAD_OFF(up
->t_ka_timer
);
1122 thread_add_timer(master
, pim_upstream_keep_alive_timer
, up
, time
,
1125 /* any time keepalive is started against a SG we will have to
1126 * re-evaluate our active source database */
1127 pim_msdp_sa_local_update(up
);
1130 /* MSDP on RP needs to know if a source is registerable to this RP */
1131 static int pim_upstream_msdp_reg_timer(struct thread
*t
)
1133 struct pim_upstream
*up
= THREAD_ARG(t
);
1134 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1136 /* source is no longer active - pull the SA from MSDP's cache */
1137 pim_msdp_sa_local_del(pim
, &up
->sg
);
1140 void pim_upstream_msdp_reg_timer_start(struct pim_upstream
*up
)
1142 THREAD_OFF(up
->t_msdp_reg_timer
);
1143 thread_add_timer(master
, pim_upstream_msdp_reg_timer
, up
,
1144 PIM_MSDP_REG_RXED_PERIOD
, &up
->t_msdp_reg_timer
);
1146 pim_msdp_sa_local_update(up
);
1150 * 4.2.1 Last-Hop Switchover to the SPT
1152 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1153 * RP. Once traffic from sources to joined groups arrives at a last-hop
1154 * router, it has the option of switching to receive the traffic on a
1155 * shortest path tree (SPT).
1157 * The decision for a router to switch to the SPT is controlled as
1161 * CheckSwitchToSpt(S,G) {
1162 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1163 * (+) pim_include(S,G) != NULL )
1164 * AND SwitchToSptDesired(S,G) ) {
1165 * # Note: Restarting the KAT will result in the SPT switch
1166 * set KeepaliveTimer(S,G) to Keepalive_Period
1170 * SwitchToSptDesired(S,G) is a policy function that is implementation
1171 * defined. An "infinite threshold" policy can be implemented by making
1172 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1173 * first packet" policy can be implemented by making
1174 * SwitchToSptDesired(S,G) return true once a single packet has been
1175 * received for the source and group.
1177 int pim_upstream_switch_to_spt_desired(struct pim_instance
*pim
,
1178 struct prefix_sg
*sg
)
1180 if (I_am_RP(pim
, sg
->grp
))
1186 int pim_upstream_is_sg_rpt(struct pim_upstream
*up
)
1188 struct listnode
*chnode
;
1189 struct pim_ifchannel
*ch
;
1191 for (ALL_LIST_ELEMENTS_RO(up
->ifchannels
, chnode
, ch
)) {
1192 if (PIM_IF_FLAG_TEST_S_G_RPT(ch
->flags
))
1199 * After receiving a packet set SPTbit:
1201 * Update_SPTbit(S,G,iif) {
1202 * if ( iif == RPF_interface(S)
1203 * AND JoinDesired(S,G) == TRUE
1204 * AND ( DirectlyConnected(S) == TRUE
1205 * OR RPF_interface(S) != RPF_interface(RP(G))
1206 * OR inherited_olist(S,G,rpt) == NULL
1207 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1208 * ( RPF'(S,G) != NULL ) )
1209 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1210 * Set SPTbit(S,G) to TRUE
1214 void pim_upstream_set_sptbit(struct pim_upstream
*up
,
1215 struct interface
*incoming
)
1217 struct pim_upstream
*starup
= up
->parent
;
1219 // iif == RPF_interfvace(S)
1220 if (up
->rpf
.source_nexthop
.interface
!= incoming
) {
1221 if (PIM_DEBUG_TRACE
)
1223 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1224 __PRETTY_FUNCTION__
, incoming
->name
,
1225 up
->rpf
.source_nexthop
.interface
->name
);
1229 // AND JoinDesired(S,G) == TRUE
1232 // DirectlyConnected(S) == TRUE
1233 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1235 if (PIM_DEBUG_TRACE
)
1236 zlog_debug("%s: %s is directly connected to the source",
1237 __PRETTY_FUNCTION__
, up
->sg_str
);
1238 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1242 // OR RPF_interface(S) != RPF_interface(RP(G))
1244 || up
->rpf
.source_nexthop
1245 .interface
!= starup
->rpf
.source_nexthop
.interface
) {
1246 if (PIM_DEBUG_TRACE
)
1248 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1249 __PRETTY_FUNCTION__
, up
->sg_str
);
1250 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1254 // OR inherited_olist(S,G,rpt) == NULL
1255 if (pim_upstream_is_sg_rpt(up
)
1256 && pim_upstream_empty_inherited_olist(up
)) {
1257 if (PIM_DEBUG_TRACE
)
1258 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1259 __PRETTY_FUNCTION__
, up
->sg_str
);
1260 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1264 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1265 // ( RPF'(S,G) != NULL ) )
1266 if (up
->parent
&& pim_rpf_is_same(&up
->rpf
, &up
->parent
->rpf
)) {
1267 if (PIM_DEBUG_TRACE
)
1268 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1269 __PRETTY_FUNCTION__
, up
->sg_str
);
1270 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
1277 const char *pim_upstream_state2str(enum pim_upstream_state join_state
)
1279 switch (join_state
) {
1280 case PIM_UPSTREAM_NOTJOINED
:
1283 case PIM_UPSTREAM_JOINED
:
1290 const char *pim_reg_state2str(enum pim_reg_state reg_state
, char *state_str
)
1292 switch (reg_state
) {
1293 case PIM_REG_NOINFO
:
1294 strcpy(state_str
, "RegNoInfo");
1297 strcpy(state_str
, "RegJoined");
1299 case PIM_REG_JOIN_PENDING
:
1300 strcpy(state_str
, "RegJoinPend");
1303 strcpy(state_str
, "RegPrune");
1306 strcpy(state_str
, "RegUnknown");
1311 static int pim_upstream_register_stop_timer(struct thread
*t
)
1313 struct pim_interface
*pim_ifp
;
1314 struct pim_instance
*pim
;
1315 struct pim_upstream
*up
;
1316 struct pim_rpf
*rpg
;
1319 pim
= up
->channel_oil
->pim
;
1321 if (PIM_DEBUG_TRACE
) {
1322 char state_str
[PIM_REG_STATE_STR_LEN
];
1323 zlog_debug("%s: (S,G)=%s upstream register stop timer %s",
1324 __PRETTY_FUNCTION__
, up
->sg_str
,
1325 pim_reg_state2str(up
->reg_state
, state_str
));
1328 switch (up
->reg_state
) {
1329 case PIM_REG_JOIN_PENDING
:
1330 up
->reg_state
= PIM_REG_JOIN
;
1331 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1332 PIM_OIF_FLAG_PROTO_PIM
);
1337 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1339 if (PIM_DEBUG_TRACE
)
1341 "%s: Interface: %s is not configured for pim",
1342 __PRETTY_FUNCTION__
,
1343 up
->rpf
.source_nexthop
.interface
->name
);
1346 up
->reg_state
= PIM_REG_JOIN_PENDING
;
1347 pim_upstream_start_register_stop_timer(up
, 1);
1349 if (((up
->channel_oil
->cc
.lastused
/ 100)
1350 > PIM_KEEPALIVE_PERIOD
)
1351 && (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
))) {
1352 if (PIM_DEBUG_TRACE
)
1354 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1355 __PRETTY_FUNCTION__
);
1358 rpg
= RP(pim_ifp
->pim
, up
->sg
.grp
);
1359 memset(&ip_hdr
, 0, sizeof(struct ip
));
1360 ip_hdr
.ip_p
= PIM_IP_PROTO_PIM
;
1363 ip_hdr
.ip_src
= up
->sg
.src
;
1364 ip_hdr
.ip_dst
= up
->sg
.grp
;
1365 ip_hdr
.ip_len
= htons(20);
1366 // checksum is broken
1367 pim_register_send((uint8_t *)&ip_hdr
, sizeof(struct ip
),
1368 pim_ifp
->primary_address
, rpg
, 1, up
);
1377 void pim_upstream_start_register_stop_timer(struct pim_upstream
*up
,
1382 THREAD_TIMER_OFF(up
->t_rs_timer
);
1384 if (!null_register
) {
1385 uint32_t lower
= (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1386 uint32_t upper
= (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD
);
1387 time
= lower
+ (random() % (upper
- lower
+ 1))
1388 - PIM_REGISTER_PROBE_PERIOD
;
1390 time
= PIM_REGISTER_PROBE_PERIOD
;
1392 if (PIM_DEBUG_TRACE
) {
1394 "%s: (S,G)=%s Starting upstream register stop timer %d",
1395 __PRETTY_FUNCTION__
, up
->sg_str
, time
);
1397 thread_add_timer(master
, pim_upstream_register_stop_timer
, up
, time
,
1401 int pim_upstream_inherited_olist_decide(struct pim_instance
*pim
,
1402 struct pim_upstream
*up
)
1404 struct interface
*ifp
;
1405 struct pim_interface
*pim_ifp
= NULL
;
1406 struct pim_ifchannel
*ch
, *starch
;
1407 struct listnode
*node
;
1408 struct pim_upstream
*starup
= up
->parent
;
1409 int output_intf
= 0;
1411 if (up
->rpf
.source_nexthop
.interface
)
1412 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
1414 if (PIM_DEBUG_TRACE
)
1415 zlog_debug("%s: up %s RPF is not present",
1416 __PRETTY_FUNCTION__
, up
->sg_str
);
1418 if (pim_ifp
&& !up
->channel_oil
)
1419 up
->channel_oil
= pim_channel_oil_add(
1420 pim
, &up
->sg
, pim_ifp
->mroute_vif_index
);
1422 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim
->vrf_id
), node
, ifp
)) {
1426 ch
= pim_ifchannel_find(ifp
, &up
->sg
);
1429 starch
= pim_ifchannel_find(ifp
, &starup
->sg
);
1436 if (pim_upstream_evaluate_join_desired_interface(up
, ch
,
1438 int flag
= PIM_OIF_FLAG_PROTO_PIM
;
1441 flag
= PIM_OIF_FLAG_PROTO_STAR
;
1443 pim_channel_add_oif(up
->channel_oil
, ifp
, flag
);
1452 * For a given upstream, determine the inherited_olist
1455 * inherited_olist(S,G,rpt) =
1456 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1457 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1458 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1460 * inherited_olist(S,G) =
1461 * inherited_olist(S,G,rpt) (+)
1462 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1464 * return 1 if there are any output interfaces
1465 * return 0 if there are not any output interfaces
1467 int pim_upstream_inherited_olist(struct pim_instance
*pim
,
1468 struct pim_upstream
*up
)
1470 int output_intf
= pim_upstream_inherited_olist_decide(pim
, up
);
1473 * If we have output_intf switch state to Join and work like normal
1474 * If we don't have an output_intf that means we are probably a
1475 * switch on a stick so turn on forwarding to just accept the
1476 * incoming packets so we don't bother the other stuff!
1479 pim_upstream_switch(up
, PIM_UPSTREAM_JOINED
);
1486 int pim_upstream_empty_inherited_olist(struct pim_upstream
*up
)
1488 return pim_channel_oil_empty(up
->channel_oil
);
1492 * When we have a new neighbor,
1493 * find upstreams that don't have their rpf_addr
1494 * set and see if the new neighbor allows
1495 * the join to be sent
1497 void pim_upstream_find_new_rpf(struct pim_instance
*pim
)
1499 struct listnode
*up_node
;
1500 struct listnode
*up_nextnode
;
1501 struct pim_upstream
*up
;
1504 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1506 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
1507 if (pim_rpf_addr_is_inaddr_any(&up
->rpf
)) {
1508 if (PIM_DEBUG_TRACE
)
1510 "Upstream %s without a path to send join, checking",
1512 pim_rpf_update(pim
, up
, NULL
, 1);
1517 static unsigned int pim_upstream_hash_key(void *arg
)
1519 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1521 return jhash_2words(up
->sg
.src
.s_addr
, up
->sg
.grp
.s_addr
, 0);
1524 void pim_upstream_terminate(struct pim_instance
*pim
)
1526 if (pim
->upstream_list
)
1527 list_delete(pim
->upstream_list
);
1528 pim
->upstream_list
= NULL
;
1530 if (pim
->upstream_hash
)
1531 hash_free(pim
->upstream_hash
);
1532 pim
->upstream_hash
= NULL
;
1535 static int pim_upstream_equal(const void *arg1
, const void *arg2
)
1537 const struct pim_upstream
*up1
= (const struct pim_upstream
*)arg1
;
1538 const struct pim_upstream
*up2
= (const struct pim_upstream
*)arg2
;
1540 if ((up1
->sg
.grp
.s_addr
== up2
->sg
.grp
.s_addr
)
1541 && (up1
->sg
.src
.s_addr
== up2
->sg
.src
.s_addr
))
1547 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1548 * the cases where kat has to be restarted on rxing traffic -
1550 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1551 * set KeepaliveTimer(S,G) to Keepalive_Period
1552 * # Note: a register state transition or UpstreamJPState(S,G)
1553 * # transition may happen as a result of restarting
1554 * # KeepaliveTimer, and must be dealt with here.
1556 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1557 * inherited_olist(S,G) != NULL ) {
1558 * set KeepaliveTimer(S,G) to Keepalive_Period
1561 static bool pim_upstream_kat_start_ok(struct pim_upstream
*up
)
1563 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1565 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1566 * so we will skip that here */
1567 if (pim_if_connected_to_source(up
->rpf
.source_nexthop
.interface
,
1572 if ((up
->join_state
== PIM_UPSTREAM_JOINED
)
1573 && !pim_upstream_empty_inherited_olist(up
)) {
1574 /* XXX: I have added this RP check just for 3.2 and it's a
1576 * what rfc-4601 says. Till now we were only running KAT on FHR
1578 * there is some angst around making the change to run it all
1580 * maintain the (S, G) state. This is tracked via CM-13601 and
1582 * removed to handle spt turn-arounds correctly in a 3-tier clos
1584 if (I_am_RP(pim
, up
->sg
.grp
))
1592 * Code to check and see if we've received packets on a S,G mroute
1593 * and if so to set the SPT bit appropriately
1595 static void pim_upstream_sg_running(void *arg
)
1597 struct pim_upstream
*up
= (struct pim_upstream
*)arg
;
1598 struct pim_instance
*pim
= up
->channel_oil
->pim
;
1600 // No packet can have arrived here if this is the case
1601 if (!up
->channel_oil
->installed
) {
1602 if (PIM_DEBUG_TRACE
)
1603 zlog_debug("%s: %s is not installed in mroute",
1604 __PRETTY_FUNCTION__
, up
->sg_str
);
1609 * This is a bit of a hack
1610 * We've noted that we should rescan but
1611 * we've missed the window for doing so in
1612 * pim_zebra.c for some reason. I am
1613 * only doing this at this point in time
1614 * to get us up and working for the moment
1616 if (up
->channel_oil
->oil_inherited_rescan
) {
1617 if (PIM_DEBUG_TRACE
)
1619 "%s: Handling unscanned inherited_olist for %s",
1620 __PRETTY_FUNCTION__
, up
->sg_str
);
1621 pim_upstream_inherited_olist_decide(pim
, up
);
1622 up
->channel_oil
->oil_inherited_rescan
= 0;
1624 pim_mroute_update_counters(up
->channel_oil
);
1626 // Have we seen packets?
1627 if ((up
->channel_oil
->cc
.oldpktcnt
>= up
->channel_oil
->cc
.pktcnt
)
1628 && (up
->channel_oil
->cc
.lastused
/ 100 > 30)) {
1629 if (PIM_DEBUG_TRACE
) {
1631 "%s: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1632 __PRETTY_FUNCTION__
, up
->sg_str
,
1633 up
->channel_oil
->cc
.oldpktcnt
,
1634 up
->channel_oil
->cc
.pktcnt
,
1635 up
->channel_oil
->cc
.lastused
/ 100);
1640 if (pim_upstream_kat_start_ok(up
)) {
1641 /* Add a source reference to the stream if
1642 * one doesn't already exist */
1643 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
1644 if (PIM_DEBUG_TRACE
)
1646 "source reference created on kat restart %s",
1649 pim_upstream_ref(up
, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
,
1650 __PRETTY_FUNCTION__
);
1651 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
1652 pim_upstream_fhr_kat_start(up
);
1654 pim_upstream_keep_alive_timer_start(up
, qpim_keep_alive_time
);
1655 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up
->flags
))
1656 pim_upstream_keep_alive_timer_start(up
, qpim_keep_alive_time
);
1658 if (up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
) {
1659 pim_upstream_set_sptbit(up
, up
->rpf
.source_nexthop
.interface
);
1664 void pim_upstream_add_lhr_star_pimreg(struct pim_instance
*pim
)
1666 struct pim_upstream
*up
;
1667 struct listnode
*node
;
1669 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1670 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1673 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1676 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1677 PIM_OIF_FLAG_PROTO_IGMP
);
1681 void pim_upstream_spt_prefix_list_update(struct pim_instance
*pim
,
1682 struct prefix_list
*pl
)
1684 const char *pname
= prefix_list_name(pl
);
1686 if (pim
->spt
.plist
&& strcmp(pim
->spt
.plist
, pname
) == 0) {
1687 pim_upstream_remove_lhr_star_pimreg(pim
, pname
);
1692 * nlist -> The new prefix list
1694 * Per Group Application of pimreg to the OIL
1695 * If the prefix list tells us DENY then
1696 * we need to Switchover to SPT immediate
1697 * so add the pimreg.
1698 * If the prefix list tells us to ACCEPT than
1699 * we need to Never do the SPT so remove
1703 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance
*pim
,
1706 struct pim_upstream
*up
;
1707 struct listnode
*node
;
1708 struct prefix_list
*np
;
1710 enum prefix_list_type apply_new
;
1712 np
= prefix_list_lookup(AFI_IP
, nlist
);
1715 g
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1717 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, node
, up
)) {
1718 if (up
->sg
.src
.s_addr
!= INADDR_ANY
)
1721 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
1725 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1726 PIM_OIF_FLAG_PROTO_IGMP
);
1729 g
.u
.prefix4
= up
->sg
.grp
;
1730 apply_new
= prefix_list_apply(np
, &g
);
1731 if (apply_new
== PREFIX_DENY
)
1732 pim_channel_add_oif(up
->channel_oil
, pim
->regiface
,
1733 PIM_OIF_FLAG_PROTO_IGMP
);
1735 pim_channel_del_oif(up
->channel_oil
, pim
->regiface
,
1736 PIM_OIF_FLAG_PROTO_IGMP
);
1740 void pim_upstream_init(struct pim_instance
*pim
)
1742 pim
->upstream_sg_wheel
=
1743 wheel_init(master
, 31000, 100, pim_upstream_hash_key
,
1744 pim_upstream_sg_running
);
1745 pim
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
1746 pim_upstream_equal
, NULL
);
1748 pim
->upstream_list
= list_new();
1749 pim
->upstream_list
->del
= (void (*)(void *))pim_upstream_free
;
1750 pim
->upstream_list
->cmp
= pim_upstream_compare
;