3 Copyright (C) 2008 Everton da Silva Marques
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
30 #include "pim_iface.h"
31 #include "pim_ifchannel.h"
32 #include "pim_zebra.h"
38 #include "pim_macro.h"
40 void pim_ifchannel_free(struct pim_ifchannel
*ch
)
42 zassert(!ch
->t_ifjoin_expiry_timer
);
43 zassert(!ch
->t_ifjoin_prune_pending_timer
);
44 zassert(!ch
->t_ifassert_timer
);
46 XFREE(MTYPE_PIM_IFCHANNEL
, ch
);
49 void pim_ifchannel_delete(struct pim_ifchannel
*ch
)
51 struct pim_interface
*pim_ifp
;
53 pim_ifp
= ch
->interface
->info
;
56 if (ch
->ifjoin_state
!= PIM_IFJOIN_NOINFO
) {
57 pim_upstream_update_join_desired(ch
->upstream
);
60 pim_upstream_del(ch
->upstream
);
62 THREAD_OFF(ch
->t_ifjoin_expiry_timer
);
63 THREAD_OFF(ch
->t_ifjoin_prune_pending_timer
);
64 THREAD_OFF(ch
->t_ifassert_timer
);
67 notice that listnode_delete() can't be moved
68 into pim_ifchannel_free() because the later is
69 called by list_delete_all_node()
71 listnode_delete(pim_ifp
->pim_ifchannel_list
, ch
);
73 pim_ifchannel_free(ch
);
76 #define IFCHANNEL_NOINFO(ch) \
78 ((ch)->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO) \
80 ((ch)->ifjoin_state == PIM_IFJOIN_NOINFO) \
82 ((ch)->ifassert_state == PIM_IFASSERT_NOINFO) \
85 static void delete_on_noinfo(struct pim_ifchannel
*ch
)
87 if (IFCHANNEL_NOINFO(ch
)) {
89 /* In NOINFO state, timers should have been cleared */
90 zassert(!ch
->t_ifjoin_expiry_timer
);
91 zassert(!ch
->t_ifjoin_prune_pending_timer
);
92 zassert(!ch
->t_ifassert_timer
);
94 pim_ifchannel_delete(ch
);
98 void pim_ifchannel_ifjoin_switch(const char *caller
,
99 struct pim_ifchannel
*ch
,
100 enum pim_ifjoin_state new_state
)
102 enum pim_ifjoin_state old_state
= ch
->ifjoin_state
;
104 if (old_state
== new_state
) {
105 if (PIM_DEBUG_PIM_EVENTS
) {
106 zlog_debug("%s calledby %s: non-transition on state %d (%s)",
107 __PRETTY_FUNCTION__
, caller
, new_state
,
108 pim_ifchannel_ifjoin_name(new_state
));
113 zassert(old_state
!= new_state
);
115 ch
->ifjoin_state
= new_state
;
117 /* Transition to/from NOINFO ? */
119 (old_state
== PIM_IFJOIN_NOINFO
)
121 (new_state
== PIM_IFJOIN_NOINFO
)
124 if (PIM_DEBUG_PIM_EVENTS
) {
127 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
128 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
129 zlog_debug("PIM_IFCHANNEL_%s: (S,G)=(%s,%s) on interface %s",
130 ((new_state
== PIM_IFJOIN_NOINFO
) ? "DOWN" : "UP"),
131 src_str
, grp_str
, ch
->interface
->name
);
135 Record uptime of state transition to/from NOINFO
137 ch
->ifjoin_creation
= pim_time_monotonic_sec();
139 pim_upstream_update_join_desired(ch
->upstream
);
140 pim_ifchannel_update_could_assert(ch
);
141 pim_ifchannel_update_assert_tracking_desired(ch
);
145 const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state
)
147 switch (ifjoin_state
) {
148 case PIM_IFJOIN_NOINFO
: return "NOINFO";
149 case PIM_IFJOIN_JOIN
: return "JOIN";
150 case PIM_IFJOIN_PRUNE_PENDING
: return "PRUNEP";
153 return "ifjoin_bad_state";
156 const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state
)
158 switch (ifassert_state
) {
159 case PIM_IFASSERT_NOINFO
: return "NOINFO";
160 case PIM_IFASSERT_I_AM_WINNER
: return "WINNER";
161 case PIM_IFASSERT_I_AM_LOSER
: return "LOSER";
164 return "ifassert_bad_state";
168 RFC 4601: 4.6.5. Assert State Macros
170 AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I)
171 defaults to Infinity when in the NoInfo state.
173 void reset_ifassert_state(struct pim_ifchannel
*ch
)
175 THREAD_OFF(ch
->t_ifassert_timer
);
177 pim_ifassert_winner_set(ch
,
180 qpim_infinite_assert_metric
);
183 static struct pim_ifchannel
*pim_ifchannel_new(struct interface
*ifp
,
184 struct in_addr source_addr
,
185 struct in_addr group_addr
)
187 struct pim_ifchannel
*ch
;
188 struct pim_interface
*pim_ifp
;
189 struct pim_upstream
*up
;
194 up
= pim_upstream_add(source_addr
, group_addr
, NULL
);
198 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
199 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
200 zlog_err("%s: could not attach upstream (S,G)=(%s,%s) on interface %s",
202 src_str
, grp_str
, ifp
->name
);
206 ch
= XMALLOC(MTYPE_PIM_IFCHANNEL
, sizeof(*ch
));
208 zlog_err("%s: PIM XMALLOC(%zu) failure",
209 __PRETTY_FUNCTION__
, sizeof(*ch
));
216 ch
->source_addr
= source_addr
;
217 ch
->group_addr
= group_addr
;
218 ch
->local_ifmembership
= PIM_IFMEMBERSHIP_NOINFO
;
220 ch
->ifjoin_state
= PIM_IFJOIN_NOINFO
;
221 ch
->t_ifjoin_expiry_timer
= 0;
222 ch
->t_ifjoin_prune_pending_timer
= 0;
223 ch
->ifjoin_creation
= 0;
225 ch
->ifassert_my_metric
= pim_macro_ch_my_assert_metric_eval(ch
);
226 ch
->ifassert_winner_metric
= pim_macro_ch_my_assert_metric_eval (ch
);
228 ch
->ifassert_winner
.s_addr
= 0;
231 ch
->t_ifassert_timer
= 0;
232 reset_ifassert_state(ch
);
233 if (pim_macro_ch_could_assert_eval(ch
))
234 PIM_IF_FLAG_SET_COULD_ASSERT(ch
->flags
);
236 PIM_IF_FLAG_UNSET_COULD_ASSERT(ch
->flags
);
238 if (pim_macro_assert_tracking_desired_eval(ch
))
239 PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch
->flags
);
241 PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch
->flags
);
244 listnode_add(pim_ifp
->pim_ifchannel_list
, ch
);
246 zassert(IFCHANNEL_NOINFO(ch
));
251 struct pim_ifchannel
*pim_ifchannel_find(struct interface
*ifp
,
252 struct in_addr source_addr
,
253 struct in_addr group_addr
)
255 struct pim_interface
*pim_ifp
;
256 struct listnode
*ch_node
;
257 struct pim_ifchannel
*ch
;
266 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
267 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
268 zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
275 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
277 (source_addr
.s_addr
== ch
->source_addr
.s_addr
) &&
278 (group_addr
.s_addr
== ch
->group_addr
.s_addr
)
287 static void ifmembership_set(struct pim_ifchannel
*ch
,
288 enum pim_ifmembership membership
)
290 if (ch
->local_ifmembership
== membership
)
293 if (PIM_DEBUG_PIM_EVENTS
) {
296 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
297 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
298 zlog_debug("%s: (S,G)=(%s,%s) membership now is %s on interface %s",
301 membership
== PIM_IFMEMBERSHIP_INCLUDE
? "INCLUDE" : "NOINFO",
302 ch
->interface
->name
);
305 ch
->local_ifmembership
= membership
;
307 pim_upstream_update_join_desired(ch
->upstream
);
308 pim_ifchannel_update_could_assert(ch
);
309 pim_ifchannel_update_assert_tracking_desired(ch
);
313 void pim_ifchannel_membership_clear(struct interface
*ifp
)
315 struct pim_interface
*pim_ifp
;
316 struct listnode
*ch_node
;
317 struct pim_ifchannel
*ch
;
322 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
323 ifmembership_set(ch
, PIM_IFMEMBERSHIP_NOINFO
);
327 void pim_ifchannel_delete_on_noinfo(struct interface
*ifp
)
329 struct pim_interface
*pim_ifp
;
330 struct listnode
*node
;
331 struct listnode
*next_node
;
332 struct pim_ifchannel
*ch
;
337 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
338 delete_on_noinfo(ch
);
342 struct pim_ifchannel
*pim_ifchannel_add(struct interface
*ifp
,
343 struct in_addr source_addr
,
344 struct in_addr group_addr
)
346 struct pim_ifchannel
*ch
;
350 ch
= pim_ifchannel_find(ifp
, source_addr
, group_addr
);
354 ch
= pim_ifchannel_new(ifp
, source_addr
, group_addr
);
358 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
359 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
360 zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=(%s,%s) on interface %s",
362 src_str
, grp_str
, ifp
->name
);
367 static void ifjoin_to_noinfo(struct pim_ifchannel
*ch
)
369 pim_forward_stop(ch
);
370 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_NOINFO
);
371 delete_on_noinfo(ch
);
374 static int on_ifjoin_expiry_timer(struct thread
*t
)
376 struct pim_ifchannel
*ch
;
382 ch
->t_ifjoin_expiry_timer
= 0;
384 zassert(ch
->ifjoin_state
== PIM_IFJOIN_JOIN
);
386 ifjoin_to_noinfo(ch
);
387 /* ch may have been deleted */
392 static void prune_echo(struct interface
*ifp
,
393 struct in_addr source_addr
,
394 struct in_addr group_addr
)
396 struct pim_interface
*pim_ifp
;
397 struct in_addr neigh_dst_addr
;
402 neigh_dst_addr
= pim_ifp
->primary_address
;
404 if (PIM_DEBUG_PIM_EVENTS
) {
405 char source_str
[100];
407 char neigh_dst_str
[100];
408 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
409 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
410 pim_inet4_dump("<neigh?>", neigh_dst_addr
, neigh_dst_str
, sizeof(neigh_dst_str
));
411 zlog_debug("%s: sending PruneEcho(S,G)=(%s,%s) to upstream=%s on interface %s",
412 __PRETTY_FUNCTION__
, source_str
, group_str
, neigh_dst_str
, ifp
->name
);
415 pim_joinprune_send(ifp
, neigh_dst_addr
, source_addr
, group_addr
,
416 0 /* boolean: send_join=false (prune) */);
419 static int on_ifjoin_prune_pending_timer(struct thread
*t
)
421 struct pim_ifchannel
*ch
;
422 int send_prune_echo
; /* boolean */
423 struct interface
*ifp
;
424 struct pim_interface
*pim_ifp
;
425 struct in_addr ch_source
;
426 struct in_addr ch_group
;
432 ch
->t_ifjoin_prune_pending_timer
= 0;
434 zassert(ch
->ifjoin_state
== PIM_IFJOIN_PRUNE_PENDING
);
436 /* Send PruneEcho(S,G) ? */
439 send_prune_echo
= (listcount(pim_ifp
->pim_neighbor_list
) > 1);
442 ch_source
= ch
->source_addr
;
443 ch_group
= ch
->group_addr
;
445 ifjoin_to_noinfo(ch
);
446 /* from here ch may have been deleted */
449 prune_echo(ifp
, ch_source
, ch_group
);
454 static void check_recv_upstream(int is_join
,
455 struct interface
*recv_ifp
,
456 struct in_addr upstream
,
457 struct in_addr source_addr
,
458 struct in_addr group_addr
,
459 uint8_t source_flags
,
462 struct pim_upstream
*up
;
464 /* Upstream (S,G) in Joined state ? */
465 up
= pim_upstream_find(source_addr
, group_addr
);
468 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
471 /* Upstream (S,G) in Joined state */
473 if (PIM_INADDR_IS_ANY(up
->rpf
.rpf_addr
)) {
474 /* RPF'(S,G) not found */
477 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
478 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
479 zlog_warn("%s %s: RPF'(%s,%s) not found",
480 __FILE__
, __PRETTY_FUNCTION__
,
485 /* upstream directed to RPF'(S,G) ? */
486 if (upstream
.s_addr
!= up
->rpf
.rpf_addr
.s_addr
) {
491 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
492 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
493 pim_inet4_dump("<up?>", upstream
, up_str
, sizeof(up_str
));
494 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
, rpf_str
, sizeof(rpf_str
));
495 zlog_warn("%s %s: (S,G)=(%s,%s) upstream=%s not directed to RPF'(S,G)=%s on interface %s",
496 __FILE__
, __PRETTY_FUNCTION__
,
498 up_str
, rpf_str
, recv_ifp
->name
);
501 /* upstream directed to RPF'(S,G) */
504 /* Join(S,G) to RPF'(S,G) */
505 pim_upstream_join_suppress(up
, up
->rpf
.rpf_addr
, holdtime
);
509 /* Prune to RPF'(S,G) */
511 if (source_flags
& PIM_RPT_BIT_MASK
) {
512 if (source_flags
& PIM_WILDCARD_BIT_MASK
) {
513 /* Prune(*,G) to RPF'(S,G) */
514 pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)",
515 up
, up
->rpf
.rpf_addr
);
519 /* Prune(S,G,rpt) to RPF'(S,G) */
520 pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)",
521 up
, up
->rpf
.rpf_addr
);
525 /* Prune(S,G) to RPF'(S,G) */
526 pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up
,
530 static int nonlocal_upstream(int is_join
,
531 struct interface
*recv_ifp
,
532 struct in_addr upstream
,
533 struct in_addr source_addr
,
534 struct in_addr group_addr
,
535 uint8_t source_flags
,
538 struct pim_interface
*recv_pim_ifp
;
539 int is_local
; /* boolean */
541 recv_pim_ifp
= recv_ifp
->info
;
542 zassert(recv_pim_ifp
);
544 is_local
= (upstream
.s_addr
== recv_pim_ifp
->primary_address
.s_addr
);
546 if (PIM_DEBUG_PIM_TRACE
) {
550 pim_inet4_dump("<upstream?>", upstream
, up_str
, sizeof(up_str
));
551 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
552 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
553 zlog_warn("%s: recv %s (S,G)=(%s,%s) to %s upstream=%s on %s",
555 is_join
? "join" : "prune",
557 is_local
? "local" : "non-local",
558 up_str
, recv_ifp
->name
);
565 Since recv upstream addr was not directed to our primary
566 address, check if we should react to it in any way.
568 check_recv_upstream(is_join
, recv_ifp
, upstream
, source_addr
, group_addr
,
569 source_flags
, holdtime
);
571 return 1; /* non-local */
574 void pim_ifchannel_join_add(struct interface
*ifp
,
575 struct in_addr neigh_addr
,
576 struct in_addr upstream
,
577 struct in_addr source_addr
,
578 struct in_addr group_addr
,
579 uint8_t source_flags
,
582 struct pim_interface
*pim_ifp
;
583 struct pim_ifchannel
*ch
;
585 if (nonlocal_upstream(1 /* join */, ifp
, upstream
,
586 source_addr
, group_addr
, source_flags
, holdtime
)) {
590 ch
= pim_ifchannel_add(ifp
, source_addr
, group_addr
);
595 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
597 Transitions from "I am Assert Loser" State
599 Receive Join(S,G) on Interface I
601 We receive a Join(S,G) that has the Upstream Neighbor Address
602 field set to my primary IP address on interface I. The action is
603 to transition to NoInfo state, delete this (S,G) assert state
604 (Actions A5 below), and allow the normal PIM Join/Prune mechanisms
607 Notice: The nonlocal_upstream() test above ensures the upstream
608 address of the join message is our primary address.
610 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
614 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
615 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
616 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
, sizeof(neigh_str
));
617 zlog_warn("%s: Assert Loser recv Join(%s,%s) from %s on %s",
619 src_str
, grp_str
, neigh_str
, ifp
->name
);
621 assert_action_a5(ch
);
627 switch (ch
->ifjoin_state
) {
628 case PIM_IFJOIN_NOINFO
:
629 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_JOIN
);
630 if (pim_macro_chisin_oiflist(ch
)) {
631 pim_forward_start(ch
);
634 case PIM_IFJOIN_JOIN
:
635 zassert(!ch
->t_ifjoin_prune_pending_timer
);
638 In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to a
639 previously received join message with holdtime=0xFFFF.
641 if (ch
->t_ifjoin_expiry_timer
) {
642 unsigned long remain
=
643 thread_timer_remain_second(ch
->t_ifjoin_expiry_timer
);
644 if (remain
> holdtime
) {
646 RFC 4601: 4.5.3. Receiving (S,G) Join/Prune Messages
648 Transitions from Join State
650 The (S,G) downstream state machine on interface I remains in
651 Join state, and the Expiry Timer (ET) is restarted, set to
652 maximum of its current value and the HoldTime from the
653 triggering Join/Prune message.
655 Conclusion: Do not change the ET if the current value is
656 higher than the received join holdtime.
661 THREAD_OFF(ch
->t_ifjoin_expiry_timer
);
663 case PIM_IFJOIN_PRUNE_PENDING
:
664 zassert(!ch
->t_ifjoin_expiry_timer
);
665 zassert(ch
->t_ifjoin_prune_pending_timer
);
666 THREAD_OFF(ch
->t_ifjoin_prune_pending_timer
);
667 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_JOIN
);
671 zassert(!IFCHANNEL_NOINFO(ch
));
673 if (holdtime
!= 0xFFFF) {
674 THREAD_TIMER_ON(master
, ch
->t_ifjoin_expiry_timer
,
675 on_ifjoin_expiry_timer
,
680 void pim_ifchannel_prune(struct interface
*ifp
,
681 struct in_addr upstream
,
682 struct in_addr source_addr
,
683 struct in_addr group_addr
,
684 uint8_t source_flags
,
687 struct pim_ifchannel
*ch
;
688 int jp_override_interval_msec
;
690 if (nonlocal_upstream(0 /* prune */, ifp
, upstream
,
691 source_addr
, group_addr
, source_flags
, holdtime
)) {
695 ch
= pim_ifchannel_add(ifp
, source_addr
, group_addr
);
699 switch (ch
->ifjoin_state
) {
700 case PIM_IFJOIN_NOINFO
:
701 case PIM_IFJOIN_PRUNE_PENDING
:
704 case PIM_IFJOIN_JOIN
:
706 struct pim_interface
*pim_ifp
;
710 zassert(ch
->t_ifjoin_expiry_timer
);
711 zassert(!ch
->t_ifjoin_prune_pending_timer
);
713 THREAD_OFF(ch
->t_ifjoin_expiry_timer
);
715 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_PRUNE_PENDING
);
717 if (listcount(pim_ifp
->pim_neighbor_list
) > 1) {
718 jp_override_interval_msec
= pim_if_jp_override_interval_msec(ifp
);
721 jp_override_interval_msec
= 0; /* schedule to expire immediately */
722 /* If we called ifjoin_prune() directly instead, care should
723 be taken not to use "ch" afterwards since it would be
727 THREAD_TIMER_MSEC_ON(master
, ch
->t_ifjoin_prune_pending_timer
,
728 on_ifjoin_prune_pending_timer
,
729 ch
, jp_override_interval_msec
);
731 zassert(!ch
->t_ifjoin_expiry_timer
);
732 zassert(ch
->t_ifjoin_prune_pending_timer
);
739 void pim_ifchannel_local_membership_add(struct interface
*ifp
,
740 struct in_addr source_addr
,
741 struct in_addr group_addr
)
743 struct pim_ifchannel
*ch
;
744 struct pim_interface
*pim_ifp
;
746 /* PIM enabled on interface? */
750 if (!PIM_IF_TEST_PIM(pim_ifp
->options
))
753 ch
= pim_ifchannel_add(ifp
, source_addr
, group_addr
);
758 ifmembership_set(ch
, PIM_IFMEMBERSHIP_INCLUDE
);
760 zassert(!IFCHANNEL_NOINFO(ch
));
763 void pim_ifchannel_local_membership_del(struct interface
*ifp
,
764 struct in_addr source_addr
,
765 struct in_addr group_addr
)
767 struct pim_ifchannel
*ch
;
768 struct pim_interface
*pim_ifp
;
770 /* PIM enabled on interface? */
774 if (!PIM_IF_TEST_PIM(pim_ifp
->options
))
777 ch
= pim_ifchannel_find(ifp
, source_addr
, group_addr
);
781 ifmembership_set(ch
, PIM_IFMEMBERSHIP_NOINFO
);
783 delete_on_noinfo(ch
);
786 void pim_ifchannel_update_could_assert(struct pim_ifchannel
*ch
)
788 int old_couldassert
= PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
));
789 int new_couldassert
= PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch
));
791 if (new_couldassert
== old_couldassert
)
794 if (PIM_DEBUG_PIM_EVENTS
) {
797 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
798 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
799 zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d",
801 src_str
, grp_str
, ch
->interface
->name
,
802 old_couldassert
, new_couldassert
);
805 if (new_couldassert
) {
806 /* CouldAssert(S,G,I) switched from FALSE to TRUE */
807 PIM_IF_FLAG_SET_COULD_ASSERT(ch
->flags
);
810 /* CouldAssert(S,G,I) switched from TRUE to FALSE */
811 PIM_IF_FLAG_UNSET_COULD_ASSERT(ch
->flags
);
813 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
) {
814 assert_action_a4(ch
);
818 pim_ifchannel_update_my_assert_metric(ch
);
822 my_assert_metric may be affected by:
825 pim_ifp->primary_address
826 rpf->source_nexthop.mrib_metric_preference;
827 rpf->source_nexthop.mrib_route_metric;
829 void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel
*ch
)
831 struct pim_assert_metric my_metric_new
= pim_macro_ch_my_assert_metric_eval(ch
);
833 if (pim_assert_metric_match(&my_metric_new
, &ch
->ifassert_my_metric
))
836 if (PIM_DEBUG_PIM_EVENTS
) {
839 char old_addr_str
[100];
840 char new_addr_str
[100];
841 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
842 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
843 pim_inet4_dump("<old_addr?>", ch
->ifassert_my_metric
.ip_address
, old_addr_str
, sizeof(old_addr_str
));
844 pim_inet4_dump("<new_addr?>", my_metric_new
.ip_address
, new_addr_str
, sizeof(new_addr_str
));
845 zlog_debug("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s",
847 src_str
, grp_str
, ch
->interface
->name
,
848 ch
->ifassert_my_metric
.rpt_bit_flag
,
849 ch
->ifassert_my_metric
.metric_preference
,
850 ch
->ifassert_my_metric
.route_metric
,
852 my_metric_new
.rpt_bit_flag
,
853 my_metric_new
.metric_preference
,
854 my_metric_new
.route_metric
,
858 ch
->ifassert_my_metric
= my_metric_new
;
860 if (pim_assert_metric_better(&ch
->ifassert_my_metric
,
861 &ch
->ifassert_winner_metric
)) {
862 assert_action_a5(ch
);
866 void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel
*ch
)
868 int old_atd
= PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch
->flags
));
869 int new_atd
= PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch
));
871 if (new_atd
== old_atd
)
874 if (PIM_DEBUG_PIM_EVENTS
) {
877 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
878 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
879 zlog_debug("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d",
881 src_str
, grp_str
, ch
->interface
->name
,
886 /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */
887 PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch
->flags
);
890 /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */
891 PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch
->flags
);
893 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
894 assert_action_a5(ch
);