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,
20 $QuaggaId: $Format:%an, %ai, %h$ $
32 #include "pim_iface.h"
33 #include "pim_ifchannel.h"
34 #include "pim_zebra.h"
40 #include "pim_macro.h"
42 void pim_ifchannel_free(struct pim_ifchannel
*ch
)
44 zassert(!ch
->t_ifjoin_expiry_timer
);
45 zassert(!ch
->t_ifjoin_prune_pending_timer
);
46 zassert(!ch
->t_ifassert_timer
);
48 XFREE(MTYPE_PIM_IFCHANNEL
, ch
);
51 void pim_ifchannel_delete(struct pim_ifchannel
*ch
)
53 struct pim_interface
*pim_ifp
;
55 pim_ifp
= ch
->interface
->info
;
58 if (ch
->ifjoin_state
!= PIM_IFJOIN_NOINFO
) {
59 pim_upstream_update_join_desired(ch
->upstream
);
62 pim_upstream_del(ch
->upstream
);
64 THREAD_OFF(ch
->t_ifjoin_expiry_timer
);
65 THREAD_OFF(ch
->t_ifjoin_prune_pending_timer
);
66 THREAD_OFF(ch
->t_ifassert_timer
);
69 notice that listnode_delete() can't be moved
70 into pim_ifchannel_free() because the later is
71 called by list_delete_all_node()
73 listnode_delete(pim_ifp
->pim_ifchannel_list
, ch
);
75 pim_ifchannel_free(ch
);
78 #define IFCHANNEL_NOINFO(ch) \
80 ((ch)->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO) \
82 ((ch)->ifjoin_state == PIM_IFJOIN_NOINFO) \
84 ((ch)->ifassert_state == PIM_IFASSERT_NOINFO) \
87 static void delete_on_noinfo(struct pim_ifchannel
*ch
)
89 if (IFCHANNEL_NOINFO(ch
)) {
91 /* In NOINFO state, timers should have been cleared */
92 zassert(!ch
->t_ifjoin_expiry_timer
);
93 zassert(!ch
->t_ifjoin_prune_pending_timer
);
94 zassert(!ch
->t_ifassert_timer
);
96 pim_ifchannel_delete(ch
);
100 void pim_ifchannel_ifjoin_switch(const char *caller
,
101 struct pim_ifchannel
*ch
,
102 enum pim_ifjoin_state new_state
)
104 enum pim_ifjoin_state old_state
= ch
->ifjoin_state
;
106 if (old_state
== new_state
) {
107 if (PIM_DEBUG_PIM_EVENTS
) {
108 zlog_debug("%s calledby %s: non-transition on state %d (%s)",
109 __PRETTY_FUNCTION__
, caller
, new_state
,
110 pim_ifchannel_ifjoin_name(new_state
));
115 zassert(old_state
!= new_state
);
117 ch
->ifjoin_state
= new_state
;
119 /* Transition to/from NOINFO ? */
121 (old_state
== PIM_IFJOIN_NOINFO
)
123 (new_state
== PIM_IFJOIN_NOINFO
)
126 if (PIM_DEBUG_PIM_EVENTS
) {
129 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
130 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
131 zlog_debug("PIM_IFCHANNEL_%s: (S,G)=(%s,%s) on interface %s",
132 ((new_state
== PIM_IFJOIN_NOINFO
) ? "DOWN" : "UP"),
133 src_str
, grp_str
, ch
->interface
->name
);
137 Record uptime of state transition to/from NOINFO
139 ch
->ifjoin_creation
= pim_time_monotonic_sec();
141 pim_upstream_update_join_desired(ch
->upstream
);
142 pim_ifchannel_update_could_assert(ch
);
143 pim_ifchannel_update_assert_tracking_desired(ch
);
147 const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state
)
149 switch (ifjoin_state
) {
150 case PIM_IFJOIN_NOINFO
: return "NOINFO";
151 case PIM_IFJOIN_JOIN
: return "JOIN";
152 case PIM_IFJOIN_PRUNE_PENDING
: return "PRUNEP";
155 return "ifjoin_bad_state";
158 const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state
)
160 switch (ifassert_state
) {
161 case PIM_IFASSERT_NOINFO
: return "NOINFO";
162 case PIM_IFASSERT_I_AM_WINNER
: return "WINNER";
163 case PIM_IFASSERT_I_AM_LOSER
: return "LOSER";
166 return "ifassert_bad_state";
170 RFC 4601: 4.6.5. Assert State Macros
172 AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I)
173 defaults to Infinity when in the NoInfo state.
175 void reset_ifassert_state(struct pim_ifchannel
*ch
)
177 THREAD_OFF(ch
->t_ifassert_timer
);
179 pim_ifassert_winner_set(ch
,
182 qpim_infinite_assert_metric
);
185 static struct pim_ifchannel
*pim_ifchannel_new(struct interface
*ifp
,
186 struct in_addr source_addr
,
187 struct in_addr group_addr
)
189 struct pim_ifchannel
*ch
;
190 struct pim_interface
*pim_ifp
;
191 struct pim_upstream
*up
;
196 up
= pim_upstream_add(source_addr
, group_addr
, NULL
);
200 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
201 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
202 zlog_err("%s: could not attach upstream (S,G)=(%s,%s) on interface %s",
204 src_str
, grp_str
, ifp
->name
);
208 ch
= XMALLOC(MTYPE_PIM_IFCHANNEL
, sizeof(*ch
));
210 zlog_err("%s: PIM XMALLOC(%zu) failure",
211 __PRETTY_FUNCTION__
, sizeof(*ch
));
218 ch
->source_addr
= source_addr
;
219 ch
->group_addr
= group_addr
;
220 ch
->local_ifmembership
= PIM_IFMEMBERSHIP_NOINFO
;
222 ch
->ifjoin_state
= PIM_IFJOIN_NOINFO
;
223 ch
->t_ifjoin_expiry_timer
= 0;
224 ch
->t_ifjoin_prune_pending_timer
= 0;
225 ch
->ifjoin_creation
= 0;
227 ch
->ifassert_my_metric
= pim_macro_ch_my_assert_metric_eval(ch
);
228 ch
->ifassert_winner_metric
= pim_macro_ch_my_assert_metric_eval (ch
);
230 ch
->ifassert_winner
.s_addr
= 0;
233 ch
->t_ifassert_timer
= 0;
234 reset_ifassert_state(ch
);
235 if (pim_macro_ch_could_assert_eval(ch
))
236 PIM_IF_FLAG_SET_COULD_ASSERT(ch
->flags
);
238 PIM_IF_FLAG_UNSET_COULD_ASSERT(ch
->flags
);
240 if (pim_macro_assert_tracking_desired_eval(ch
))
241 PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch
->flags
);
243 PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch
->flags
);
246 listnode_add(pim_ifp
->pim_ifchannel_list
, ch
);
248 zassert(IFCHANNEL_NOINFO(ch
));
253 struct pim_ifchannel
*pim_ifchannel_find(struct interface
*ifp
,
254 struct in_addr source_addr
,
255 struct in_addr group_addr
)
257 struct pim_interface
*pim_ifp
;
258 struct listnode
*ch_node
;
259 struct pim_ifchannel
*ch
;
268 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
269 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
270 zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
277 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
279 (source_addr
.s_addr
== ch
->source_addr
.s_addr
) &&
280 (group_addr
.s_addr
== ch
->group_addr
.s_addr
)
289 static void ifmembership_set(struct pim_ifchannel
*ch
,
290 enum pim_ifmembership membership
)
292 if (ch
->local_ifmembership
== membership
)
295 if (PIM_DEBUG_PIM_EVENTS
) {
298 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
299 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
300 zlog_debug("%s: (S,G)=(%s,%s) membership now is %s on interface %s",
303 membership
== PIM_IFMEMBERSHIP_INCLUDE
? "INCLUDE" : "NOINFO",
304 ch
->interface
->name
);
307 ch
->local_ifmembership
= membership
;
309 pim_upstream_update_join_desired(ch
->upstream
);
310 pim_ifchannel_update_could_assert(ch
);
311 pim_ifchannel_update_assert_tracking_desired(ch
);
315 void pim_ifchannel_membership_clear(struct interface
*ifp
)
317 struct pim_interface
*pim_ifp
;
318 struct listnode
*ch_node
;
319 struct pim_ifchannel
*ch
;
324 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
325 ifmembership_set(ch
, PIM_IFMEMBERSHIP_NOINFO
);
329 void pim_ifchannel_delete_on_noinfo(struct interface
*ifp
)
331 struct pim_interface
*pim_ifp
;
332 struct listnode
*node
;
333 struct listnode
*next_node
;
334 struct pim_ifchannel
*ch
;
339 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
340 delete_on_noinfo(ch
);
344 struct pim_ifchannel
*pim_ifchannel_add(struct interface
*ifp
,
345 struct in_addr source_addr
,
346 struct in_addr group_addr
)
348 struct pim_ifchannel
*ch
;
352 ch
= pim_ifchannel_find(ifp
, source_addr
, group_addr
);
356 ch
= pim_ifchannel_new(ifp
, source_addr
, group_addr
);
360 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
361 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
362 zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=(%s,%s) on interface %s",
364 src_str
, grp_str
, ifp
->name
);
369 static void ifjoin_to_noinfo(struct pim_ifchannel
*ch
)
371 pim_forward_stop(ch
);
372 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_NOINFO
);
373 delete_on_noinfo(ch
);
376 static int on_ifjoin_expiry_timer(struct thread
*t
)
378 struct pim_ifchannel
*ch
;
384 ch
->t_ifjoin_expiry_timer
= 0;
386 zassert(ch
->ifjoin_state
== PIM_IFJOIN_JOIN
);
388 ifjoin_to_noinfo(ch
);
389 /* ch may have been deleted */
394 static void prune_echo(struct interface
*ifp
,
395 struct in_addr source_addr
,
396 struct in_addr group_addr
)
398 struct pim_interface
*pim_ifp
;
399 struct in_addr neigh_dst_addr
;
404 neigh_dst_addr
= pim_ifp
->primary_address
;
406 if (PIM_DEBUG_PIM_EVENTS
) {
407 char source_str
[100];
409 char neigh_dst_str
[100];
410 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
411 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
412 pim_inet4_dump("<neigh?>", neigh_dst_addr
, neigh_dst_str
, sizeof(neigh_dst_str
));
413 zlog_debug("%s: sending PruneEcho(S,G)=(%s,%s) to upstream=%s on interface %s",
414 __PRETTY_FUNCTION__
, source_str
, group_str
, neigh_dst_str
, ifp
->name
);
417 pim_joinprune_send(ifp
, neigh_dst_addr
, source_addr
, group_addr
,
418 0 /* boolean: send_join=false (prune) */);
421 static int on_ifjoin_prune_pending_timer(struct thread
*t
)
423 struct pim_ifchannel
*ch
;
424 int send_prune_echo
; /* boolean */
425 struct interface
*ifp
;
426 struct pim_interface
*pim_ifp
;
427 struct in_addr ch_source
;
428 struct in_addr ch_group
;
434 ch
->t_ifjoin_prune_pending_timer
= 0;
436 zassert(ch
->ifjoin_state
== PIM_IFJOIN_PRUNE_PENDING
);
438 /* Send PruneEcho(S,G) ? */
441 send_prune_echo
= (listcount(pim_ifp
->pim_neighbor_list
) > 1);
444 ch_source
= ch
->source_addr
;
445 ch_group
= ch
->group_addr
;
447 ifjoin_to_noinfo(ch
);
448 /* from here ch may have been deleted */
451 prune_echo(ifp
, ch_source
, ch_group
);
456 static void check_recv_upstream(int is_join
,
457 struct interface
*recv_ifp
,
458 struct in_addr upstream
,
459 struct in_addr source_addr
,
460 struct in_addr group_addr
,
461 uint8_t source_flags
,
464 struct pim_upstream
*up
;
466 /* Upstream (S,G) in Joined state ? */
467 up
= pim_upstream_find(source_addr
, group_addr
);
470 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
473 /* Upstream (S,G) in Joined state */
475 if (PIM_INADDR_IS_ANY(up
->rpf
.rpf_addr
)) {
476 /* RPF'(S,G) not found */
479 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
480 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
481 zlog_warn("%s %s: RPF'(%s,%s) not found",
482 __FILE__
, __PRETTY_FUNCTION__
,
487 /* upstream directed to RPF'(S,G) ? */
488 if (upstream
.s_addr
!= up
->rpf
.rpf_addr
.s_addr
) {
493 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
494 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
495 pim_inet4_dump("<up?>", upstream
, up_str
, sizeof(up_str
));
496 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
, rpf_str
, sizeof(rpf_str
));
497 zlog_warn("%s %s: (S,G)=(%s,%s) upstream=%s not directed to RPF'(S,G)=%s on interface %s",
498 __FILE__
, __PRETTY_FUNCTION__
,
500 up_str
, rpf_str
, recv_ifp
->name
);
503 /* upstream directed to RPF'(S,G) */
506 /* Join(S,G) to RPF'(S,G) */
507 pim_upstream_join_suppress(up
, up
->rpf
.rpf_addr
, holdtime
);
511 /* Prune to RPF'(S,G) */
513 if (source_flags
& PIM_RPT_BIT_MASK
) {
514 if (source_flags
& PIM_WILDCARD_BIT_MASK
) {
515 /* Prune(*,G) to RPF'(S,G) */
516 pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)",
517 up
, up
->rpf
.rpf_addr
);
521 /* Prune(S,G,rpt) to RPF'(S,G) */
522 pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)",
523 up
, up
->rpf
.rpf_addr
);
527 /* Prune(S,G) to RPF'(S,G) */
528 pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up
,
532 static int nonlocal_upstream(int is_join
,
533 struct interface
*recv_ifp
,
534 struct in_addr upstream
,
535 struct in_addr source_addr
,
536 struct in_addr group_addr
,
537 uint8_t source_flags
,
540 struct pim_interface
*recv_pim_ifp
;
541 int is_local
; /* boolean */
543 recv_pim_ifp
= recv_ifp
->info
;
544 zassert(recv_pim_ifp
);
546 is_local
= (upstream
.s_addr
== recv_pim_ifp
->primary_address
.s_addr
);
548 if (PIM_DEBUG_PIM_TRACE
) {
552 pim_inet4_dump("<upstream?>", upstream
, up_str
, sizeof(up_str
));
553 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
554 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
555 zlog_warn("%s: recv %s (S,G)=(%s,%s) to %s upstream=%s on %s",
557 is_join
? "join" : "prune",
559 is_local
? "local" : "non-local",
560 up_str
, recv_ifp
->name
);
567 Since recv upstream addr was not directed to our primary
568 address, check if we should react to it in any way.
570 check_recv_upstream(is_join
, recv_ifp
, upstream
, source_addr
, group_addr
,
571 source_flags
, holdtime
);
573 return 1; /* non-local */
576 void pim_ifchannel_join_add(struct interface
*ifp
,
577 struct in_addr neigh_addr
,
578 struct in_addr upstream
,
579 struct in_addr source_addr
,
580 struct in_addr group_addr
,
581 uint8_t source_flags
,
584 struct pim_interface
*pim_ifp
;
585 struct pim_ifchannel
*ch
;
587 if (nonlocal_upstream(1 /* join */, ifp
, upstream
,
588 source_addr
, group_addr
, source_flags
, holdtime
)) {
592 ch
= pim_ifchannel_add(ifp
, source_addr
, group_addr
);
597 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
599 Transitions from "I am Assert Loser" State
601 Receive Join(S,G) on Interface I
603 We receive a Join(S,G) that has the Upstream Neighbor Address
604 field set to my primary IP address on interface I. The action is
605 to transition to NoInfo state, delete this (S,G) assert state
606 (Actions A5 below), and allow the normal PIM Join/Prune mechanisms
609 Notice: The nonlocal_upstream() test above ensures the upstream
610 address of the join message is our primary address.
612 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
616 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
617 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
618 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
, sizeof(neigh_str
));
619 zlog_warn("%s: Assert Loser recv Join(%s,%s) from %s on %s",
621 src_str
, grp_str
, neigh_str
, ifp
->name
);
623 assert_action_a5(ch
);
629 switch (ch
->ifjoin_state
) {
630 case PIM_IFJOIN_NOINFO
:
631 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_JOIN
);
632 if (pim_macro_chisin_oiflist(ch
)) {
633 pim_forward_start(ch
);
636 case PIM_IFJOIN_JOIN
:
637 zassert(!ch
->t_ifjoin_prune_pending_timer
);
640 In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to a
641 previously received join message with holdtime=0xFFFF.
643 if (ch
->t_ifjoin_expiry_timer
) {
644 unsigned long remain
=
645 thread_timer_remain_second(ch
->t_ifjoin_expiry_timer
);
646 if (remain
> holdtime
) {
648 RFC 4601: 4.5.3. Receiving (S,G) Join/Prune Messages
650 Transitions from Join State
652 The (S,G) downstream state machine on interface I remains in
653 Join state, and the Expiry Timer (ET) is restarted, set to
654 maximum of its current value and the HoldTime from the
655 triggering Join/Prune message.
657 Conclusion: Do not change the ET if the current value is
658 higher than the received join holdtime.
663 THREAD_OFF(ch
->t_ifjoin_expiry_timer
);
665 case PIM_IFJOIN_PRUNE_PENDING
:
666 zassert(!ch
->t_ifjoin_expiry_timer
);
667 zassert(ch
->t_ifjoin_prune_pending_timer
);
668 THREAD_OFF(ch
->t_ifjoin_prune_pending_timer
);
669 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_JOIN
);
673 zassert(!IFCHANNEL_NOINFO(ch
));
675 if (holdtime
!= 0xFFFF) {
676 THREAD_TIMER_ON(master
, ch
->t_ifjoin_expiry_timer
,
677 on_ifjoin_expiry_timer
,
682 void pim_ifchannel_prune(struct interface
*ifp
,
683 struct in_addr upstream
,
684 struct in_addr source_addr
,
685 struct in_addr group_addr
,
686 uint8_t source_flags
,
689 struct pim_ifchannel
*ch
;
690 int jp_override_interval_msec
;
692 if (nonlocal_upstream(0 /* prune */, ifp
, upstream
,
693 source_addr
, group_addr
, source_flags
, holdtime
)) {
697 ch
= pim_ifchannel_add(ifp
, source_addr
, group_addr
);
701 switch (ch
->ifjoin_state
) {
702 case PIM_IFJOIN_NOINFO
:
703 case PIM_IFJOIN_PRUNE_PENDING
:
706 case PIM_IFJOIN_JOIN
:
708 struct pim_interface
*pim_ifp
;
712 zassert(ch
->t_ifjoin_expiry_timer
);
713 zassert(!ch
->t_ifjoin_prune_pending_timer
);
715 THREAD_OFF(ch
->t_ifjoin_expiry_timer
);
717 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_PRUNE_PENDING
);
719 if (listcount(pim_ifp
->pim_neighbor_list
) > 1) {
720 jp_override_interval_msec
= pim_if_jp_override_interval_msec(ifp
);
723 jp_override_interval_msec
= 0; /* schedule to expire immediately */
724 /* If we called ifjoin_prune() directly instead, care should
725 be taken not to use "ch" afterwards since it would be
729 THREAD_TIMER_MSEC_ON(master
, ch
->t_ifjoin_prune_pending_timer
,
730 on_ifjoin_prune_pending_timer
,
731 ch
, jp_override_interval_msec
);
733 zassert(!ch
->t_ifjoin_expiry_timer
);
734 zassert(ch
->t_ifjoin_prune_pending_timer
);
741 void pim_ifchannel_local_membership_add(struct interface
*ifp
,
742 struct in_addr source_addr
,
743 struct in_addr group_addr
)
745 struct pim_ifchannel
*ch
;
746 struct pim_interface
*pim_ifp
;
748 /* PIM enabled on interface? */
752 if (!PIM_IF_TEST_PIM(pim_ifp
->options
))
755 ch
= pim_ifchannel_add(ifp
, source_addr
, group_addr
);
760 ifmembership_set(ch
, PIM_IFMEMBERSHIP_INCLUDE
);
762 zassert(!IFCHANNEL_NOINFO(ch
));
765 void pim_ifchannel_local_membership_del(struct interface
*ifp
,
766 struct in_addr source_addr
,
767 struct in_addr group_addr
)
769 struct pim_ifchannel
*ch
;
770 struct pim_interface
*pim_ifp
;
772 /* PIM enabled on interface? */
776 if (!PIM_IF_TEST_PIM(pim_ifp
->options
))
779 ch
= pim_ifchannel_find(ifp
, source_addr
, group_addr
);
783 ifmembership_set(ch
, PIM_IFMEMBERSHIP_NOINFO
);
785 delete_on_noinfo(ch
);
788 void pim_ifchannel_update_could_assert(struct pim_ifchannel
*ch
)
790 int old_couldassert
= PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
));
791 int new_couldassert
= PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch
));
793 if (new_couldassert
== old_couldassert
)
796 if (PIM_DEBUG_PIM_EVENTS
) {
799 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
800 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
801 zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d",
803 src_str
, grp_str
, ch
->interface
->name
,
804 old_couldassert
, new_couldassert
);
807 if (new_couldassert
) {
808 /* CouldAssert(S,G,I) switched from FALSE to TRUE */
809 PIM_IF_FLAG_SET_COULD_ASSERT(ch
->flags
);
812 /* CouldAssert(S,G,I) switched from TRUE to FALSE */
813 PIM_IF_FLAG_UNSET_COULD_ASSERT(ch
->flags
);
815 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
) {
816 assert_action_a4(ch
);
820 pim_ifchannel_update_my_assert_metric(ch
);
824 my_assert_metric may be affected by:
827 pim_ifp->primary_address
828 rpf->source_nexthop.mrib_metric_preference;
829 rpf->source_nexthop.mrib_route_metric;
831 void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel
*ch
)
833 struct pim_assert_metric my_metric_new
= pim_macro_ch_my_assert_metric_eval(ch
);
835 if (pim_assert_metric_match(&my_metric_new
, &ch
->ifassert_my_metric
))
838 if (PIM_DEBUG_PIM_EVENTS
) {
841 char old_addr_str
[100];
842 char new_addr_str
[100];
843 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
844 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
845 pim_inet4_dump("<old_addr?>", ch
->ifassert_my_metric
.ip_address
, old_addr_str
, sizeof(old_addr_str
));
846 pim_inet4_dump("<new_addr?>", my_metric_new
.ip_address
, new_addr_str
, sizeof(new_addr_str
));
847 zlog_debug("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s",
849 src_str
, grp_str
, ch
->interface
->name
,
850 ch
->ifassert_my_metric
.rpt_bit_flag
,
851 ch
->ifassert_my_metric
.metric_preference
,
852 ch
->ifassert_my_metric
.route_metric
,
854 my_metric_new
.rpt_bit_flag
,
855 my_metric_new
.metric_preference
,
856 my_metric_new
.route_metric
,
860 ch
->ifassert_my_metric
= my_metric_new
;
862 if (pim_assert_metric_better(&ch
->ifassert_my_metric
,
863 &ch
->ifassert_winner_metric
)) {
864 assert_action_a5(ch
);
868 void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel
*ch
)
870 int old_atd
= PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch
->flags
));
871 int new_atd
= PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch
));
873 if (new_atd
== old_atd
)
876 if (PIM_DEBUG_PIM_EVENTS
) {
879 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
880 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
881 zlog_debug("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d",
883 src_str
, grp_str
, ch
->interface
->name
,
888 /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */
889 PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch
->flags
);
892 /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */
893 PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch
->flags
);
895 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
896 assert_action_a5(ch
);