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
) {
127 zlog_debug("PIM_IFCHANNEL_%s: (S,G)=%s on interface %s",
128 ((new_state
== PIM_IFJOIN_NOINFO
) ? "DOWN" : "UP"),
129 pim_str_sg_dump (&ch
->sg
), ch
->interface
->name
);
133 Record uptime of state transition to/from NOINFO
135 ch
->ifjoin_creation
= pim_time_monotonic_sec();
137 pim_upstream_update_join_desired(ch
->upstream
);
138 pim_ifchannel_update_could_assert(ch
);
139 pim_ifchannel_update_assert_tracking_desired(ch
);
143 const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state
)
145 switch (ifjoin_state
) {
146 case PIM_IFJOIN_NOINFO
: return "NOINFO";
147 case PIM_IFJOIN_JOIN_PIMREG
: return "REGT";
148 case PIM_IFJOIN_JOIN
: return "JOIN";
149 case PIM_IFJOIN_PRUNE_PENDING
: return "PRUNEP";
152 return "ifjoin_bad_state";
155 const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state
)
157 switch (ifassert_state
) {
158 case PIM_IFASSERT_NOINFO
: return "NOINFO";
159 case PIM_IFASSERT_I_AM_WINNER
: return "WINNER";
160 case PIM_IFASSERT_I_AM_LOSER
: return "LOSER";
163 return "ifassert_bad_state";
167 RFC 4601: 4.6.5. Assert State Macros
169 AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I)
170 defaults to Infinity when in the NoInfo state.
172 void reset_ifassert_state(struct pim_ifchannel
*ch
)
174 THREAD_OFF(ch
->t_ifassert_timer
);
176 pim_ifassert_winner_set(ch
,
179 qpim_infinite_assert_metric
);
182 struct pim_ifchannel
*pim_ifchannel_find(struct interface
*ifp
,
185 struct pim_interface
*pim_ifp
;
186 struct listnode
*ch_node
;
187 struct pim_ifchannel
*ch
;
194 zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
196 pim_str_sg_dump (sg
),
201 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
203 (sg
->u
.sg
.src
.s_addr
== ch
->sg
.u
.sg
.src
.s_addr
) &&
204 (sg
->u
.sg
.grp
.s_addr
== ch
->sg
.u
.sg
.grp
.s_addr
)
213 static void ifmembership_set(struct pim_ifchannel
*ch
,
214 enum pim_ifmembership membership
)
216 if (ch
->local_ifmembership
== membership
)
219 if (PIM_DEBUG_PIM_EVENTS
) {
220 zlog_debug("%s: (S,G)=%s membership now is %s on interface %s",
222 pim_str_sg_dump (&ch
->sg
),
223 membership
== PIM_IFMEMBERSHIP_INCLUDE
? "INCLUDE" : "NOINFO",
224 ch
->interface
->name
);
227 ch
->local_ifmembership
= membership
;
229 pim_upstream_update_join_desired(ch
->upstream
);
230 pim_ifchannel_update_could_assert(ch
);
231 pim_ifchannel_update_assert_tracking_desired(ch
);
235 void pim_ifchannel_membership_clear(struct interface
*ifp
)
237 struct pim_interface
*pim_ifp
;
238 struct listnode
*ch_node
;
239 struct pim_ifchannel
*ch
;
244 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
245 ifmembership_set(ch
, PIM_IFMEMBERSHIP_NOINFO
);
249 void pim_ifchannel_delete_on_noinfo(struct interface
*ifp
)
251 struct pim_interface
*pim_ifp
;
252 struct listnode
*node
;
253 struct listnode
*next_node
;
254 struct pim_ifchannel
*ch
;
259 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
260 delete_on_noinfo(ch
);
264 struct pim_ifchannel
*pim_ifchannel_add(struct interface
*ifp
,
267 struct pim_interface
*pim_ifp
;
268 struct pim_ifchannel
*ch
;
269 struct pim_upstream
*up
;
271 ch
= pim_ifchannel_find(ifp
, sg
);
278 up
= pim_upstream_add(sg
, NULL
);
280 zlog_err("%s: could not attach upstream (S,G)=%s on interface %s",
282 pim_str_sg_dump (sg
), ifp
->name
);
286 ch
= XMALLOC(MTYPE_PIM_IFCHANNEL
, sizeof(*ch
));
288 zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=%s on interface %s",
290 pim_str_sg_dump (sg
), ifp
->name
);
299 ch
->local_ifmembership
= PIM_IFMEMBERSHIP_NOINFO
;
301 ch
->ifjoin_state
= PIM_IFJOIN_NOINFO
;
302 ch
->t_ifjoin_expiry_timer
= NULL
;
303 ch
->t_ifjoin_prune_pending_timer
= NULL
;
304 ch
->ifjoin_creation
= 0;
306 ch
->ifassert_my_metric
= pim_macro_ch_my_assert_metric_eval(ch
);
307 ch
->ifassert_winner_metric
= pim_macro_ch_my_assert_metric_eval (ch
);
309 ch
->ifassert_winner
.s_addr
= 0;
312 ch
->t_ifassert_timer
= NULL
;
313 reset_ifassert_state(ch
);
314 if (pim_macro_ch_could_assert_eval(ch
))
315 PIM_IF_FLAG_SET_COULD_ASSERT(ch
->flags
);
317 PIM_IF_FLAG_UNSET_COULD_ASSERT(ch
->flags
);
319 if (pim_macro_assert_tracking_desired_eval(ch
))
320 PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch
->flags
);
322 PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch
->flags
);
325 listnode_add(pim_ifp
->pim_ifchannel_list
, ch
);
327 zassert(IFCHANNEL_NOINFO(ch
));
332 static void ifjoin_to_noinfo(struct pim_ifchannel
*ch
)
334 pim_forward_stop(ch
);
335 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_NOINFO
);
336 delete_on_noinfo(ch
);
339 static int on_ifjoin_expiry_timer(struct thread
*t
)
341 struct pim_ifchannel
*ch
;
347 ch
->t_ifjoin_expiry_timer
= NULL
;
349 zassert(ch
->ifjoin_state
== PIM_IFJOIN_JOIN
);
351 ifjoin_to_noinfo(ch
);
352 /* ch may have been deleted */
357 static int on_ifjoin_prune_pending_timer(struct thread
*t
)
359 struct pim_ifchannel
*ch
;
360 int send_prune_echo
; /* boolean */
361 struct interface
*ifp
;
362 struct pim_interface
*pim_ifp
;
369 ch
->t_ifjoin_prune_pending_timer
= NULL
;
371 zassert(ch
->ifjoin_state
== PIM_IFJOIN_PRUNE_PENDING
);
373 /* Send PruneEcho(S,G) ? */
376 send_prune_echo
= (listcount(pim_ifp
->pim_neighbor_list
) > 1);
381 ifjoin_to_noinfo(ch
);
382 /* from here ch may have been deleted */
385 pim_joinprune_send (ifp
, pim_ifp
->primary_address
,
391 static void check_recv_upstream(int is_join
,
392 struct interface
*recv_ifp
,
393 struct in_addr upstream
,
394 struct in_addr source_addr
,
395 struct in_addr group_addr
,
396 uint8_t source_flags
,
399 struct pim_upstream
*up
;
402 memset (&sg
, 0, sizeof (struct prefix
));
403 sg
.u
.sg
.src
= source_addr
;
404 sg
.u
.sg
.grp
= group_addr
;
405 /* Upstream (S,G) in Joined state ? */
406 up
= pim_upstream_find(&sg
);
409 if (up
->join_state
!= PIM_UPSTREAM_JOINED
)
412 /* Upstream (S,G) in Joined state */
414 if (PIM_INADDR_IS_ANY(up
->rpf
.rpf_addr
)) {
415 /* RPF'(S,G) not found */
418 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
419 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
420 zlog_warn("%s %s: RPF'(%s,%s) not found",
421 __FILE__
, __PRETTY_FUNCTION__
,
426 /* upstream directed to RPF'(S,G) ? */
427 if (upstream
.s_addr
!= up
->rpf
.rpf_addr
.s_addr
) {
432 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
433 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
434 pim_inet4_dump("<up?>", upstream
, up_str
, sizeof(up_str
));
435 pim_inet4_dump("<rpf?>", up
->rpf
.rpf_addr
, rpf_str
, sizeof(rpf_str
));
436 zlog_warn("%s %s: (S,G)=(%s,%s) upstream=%s not directed to RPF'(S,G)=%s on interface %s",
437 __FILE__
, __PRETTY_FUNCTION__
,
439 up_str
, rpf_str
, recv_ifp
->name
);
442 /* upstream directed to RPF'(S,G) */
445 /* Join(S,G) to RPF'(S,G) */
446 pim_upstream_join_suppress(up
, up
->rpf
.rpf_addr
, holdtime
);
450 /* Prune to RPF'(S,G) */
452 if (source_flags
& PIM_RPT_BIT_MASK
) {
453 if (source_flags
& PIM_WILDCARD_BIT_MASK
) {
454 /* Prune(*,G) to RPF'(S,G) */
455 pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)",
456 up
, up
->rpf
.rpf_addr
);
460 /* Prune(S,G,rpt) to RPF'(S,G) */
461 pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)",
462 up
, up
->rpf
.rpf_addr
);
466 /* Prune(S,G) to RPF'(S,G) */
467 pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up
,
471 static int nonlocal_upstream(int is_join
,
472 struct interface
*recv_ifp
,
473 struct in_addr upstream
,
474 struct in_addr source_addr
,
475 struct in_addr group_addr
,
476 uint8_t source_flags
,
479 struct pim_interface
*recv_pim_ifp
;
480 int is_local
; /* boolean */
482 recv_pim_ifp
= recv_ifp
->info
;
483 zassert(recv_pim_ifp
);
485 is_local
= (upstream
.s_addr
== recv_pim_ifp
->primary_address
.s_addr
);
487 if (PIM_DEBUG_PIM_TRACE
) {
491 pim_inet4_dump("<upstream?>", upstream
, up_str
, sizeof(up_str
));
492 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
493 pim_inet4_dump("<grp?>", group_addr
, grp_str
, sizeof(grp_str
));
494 zlog_warn("%s: recv %s (S,G)=(%s,%s) to %s upstream=%s on %s",
496 is_join
? "join" : "prune",
498 is_local
? "local" : "non-local",
499 up_str
, recv_ifp
->name
);
506 Since recv upstream addr was not directed to our primary
507 address, check if we should react to it in any way.
509 check_recv_upstream(is_join
, recv_ifp
, upstream
, source_addr
, group_addr
,
510 source_flags
, holdtime
);
512 return 1; /* non-local */
515 void pim_ifchannel_join_add(struct interface
*ifp
,
516 struct in_addr neigh_addr
,
517 struct in_addr upstream
,
519 uint8_t source_flags
,
522 struct pim_interface
*pim_ifp
;
523 struct pim_ifchannel
*ch
;
525 if (nonlocal_upstream(1 /* join */, ifp
, upstream
,
526 sg
->u
.sg
.src
, sg
->u
.sg
.grp
, source_flags
, holdtime
)) {
530 ch
= pim_ifchannel_add(ifp
, sg
);
535 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
537 Transitions from "I am Assert Loser" State
539 Receive Join(S,G) on Interface I
541 We receive a Join(S,G) that has the Upstream Neighbor Address
542 field set to my primary IP address on interface I. The action is
543 to transition to NoInfo state, delete this (S,G) assert state
544 (Actions A5 below), and allow the normal PIM Join/Prune mechanisms
547 Notice: The nonlocal_upstream() test above ensures the upstream
548 address of the join message is our primary address.
550 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
552 pim_inet4_dump("<neigh?>", neigh_addr
, neigh_str
, sizeof(neigh_str
));
553 zlog_warn("%s: Assert Loser recv Join%s from %s on %s",
555 pim_str_sg_dump (sg
), neigh_str
, ifp
->name
);
557 assert_action_a5(ch
);
563 switch (ch
->ifjoin_state
) {
564 case PIM_IFJOIN_NOINFO
:
565 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_JOIN
);
566 if (pim_macro_chisin_oiflist(ch
)) {
567 pim_forward_start(ch
);
570 case PIM_IFJOIN_JOIN
:
571 zassert(!ch
->t_ifjoin_prune_pending_timer
);
574 In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to a
575 previously received join message with holdtime=0xFFFF.
577 if (ch
->t_ifjoin_expiry_timer
) {
578 unsigned long remain
=
579 thread_timer_remain_second(ch
->t_ifjoin_expiry_timer
);
580 if (remain
> holdtime
) {
582 RFC 4601: 4.5.3. Receiving (S,G) Join/Prune Messages
584 Transitions from Join State
586 The (S,G) downstream state machine on interface I remains in
587 Join state, and the Expiry Timer (ET) is restarted, set to
588 maximum of its current value and the HoldTime from the
589 triggering Join/Prune message.
591 Conclusion: Do not change the ET if the current value is
592 higher than the received join holdtime.
597 THREAD_OFF(ch
->t_ifjoin_expiry_timer
);
599 case PIM_IFJOIN_PRUNE_PENDING
:
600 zassert(!ch
->t_ifjoin_expiry_timer
);
601 zassert(ch
->t_ifjoin_prune_pending_timer
);
602 THREAD_OFF(ch
->t_ifjoin_prune_pending_timer
);
603 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_JOIN
);
605 case PIM_IFJOIN_JOIN_PIMREG
:
606 zlog_warn("Received Incorrect new state");
609 zassert(!IFCHANNEL_NOINFO(ch
));
611 if (holdtime
!= 0xFFFF) {
612 THREAD_TIMER_ON(master
, ch
->t_ifjoin_expiry_timer
,
613 on_ifjoin_expiry_timer
,
618 void pim_ifchannel_prune(struct interface
*ifp
,
619 struct in_addr upstream
,
620 struct in_addr source_addr
,
621 struct in_addr group_addr
,
622 uint8_t source_flags
,
625 struct pim_ifchannel
*ch
;
626 int jp_override_interval_msec
;
629 memset (&sg
, 0, sizeof (struct prefix
));
630 sg
.u
.sg
.src
= source_addr
;
631 sg
.u
.sg
.grp
= group_addr
;
633 if (nonlocal_upstream(0 /* prune */, ifp
, upstream
,
634 source_addr
, group_addr
, source_flags
, holdtime
)) {
638 ch
= pim_ifchannel_add(ifp
, &sg
);
642 switch (ch
->ifjoin_state
) {
643 case PIM_IFJOIN_NOINFO
:
644 case PIM_IFJOIN_PRUNE_PENDING
:
645 case PIM_IFJOIN_JOIN_PIMREG
:
648 case PIM_IFJOIN_JOIN
:
650 struct pim_interface
*pim_ifp
;
654 zassert(ch
->t_ifjoin_expiry_timer
);
655 zassert(!ch
->t_ifjoin_prune_pending_timer
);
657 THREAD_OFF(ch
->t_ifjoin_expiry_timer
);
659 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__
, ch
, PIM_IFJOIN_PRUNE_PENDING
);
661 if (listcount(pim_ifp
->pim_neighbor_list
) > 1) {
662 jp_override_interval_msec
= pim_if_jp_override_interval_msec(ifp
);
665 jp_override_interval_msec
= 0; /* schedule to expire immediately */
666 /* If we called ifjoin_prune() directly instead, care should
667 be taken not to use "ch" afterwards since it would be
671 THREAD_TIMER_MSEC_ON(master
, ch
->t_ifjoin_prune_pending_timer
,
672 on_ifjoin_prune_pending_timer
,
673 ch
, jp_override_interval_msec
);
675 zassert(!ch
->t_ifjoin_expiry_timer
);
676 zassert(ch
->t_ifjoin_prune_pending_timer
);
683 void pim_ifchannel_local_membership_add(struct interface
*ifp
,
684 struct in_addr source_addr
,
685 struct in_addr group_addr
)
687 struct pim_ifchannel
*ch
;
688 struct pim_interface
*pim_ifp
;
691 memset (&sg
, 0, sizeof (struct prefix
));
692 sg
.u
.sg
.src
= source_addr
;
693 sg
.u
.sg
.grp
= group_addr
;
695 /* PIM enabled on interface? */
699 if (!PIM_IF_TEST_PIM(pim_ifp
->options
))
702 ch
= pim_ifchannel_add(ifp
, &sg
);
707 ifmembership_set(ch
, PIM_IFMEMBERSHIP_INCLUDE
);
709 zassert(!IFCHANNEL_NOINFO(ch
));
712 void pim_ifchannel_local_membership_del(struct interface
*ifp
,
713 struct in_addr source_addr
,
714 struct in_addr group_addr
)
716 struct pim_ifchannel
*ch
;
717 struct pim_interface
*pim_ifp
;
720 memset (&sg
, 0, sizeof (struct prefix
));
721 sg
.u
.sg
.src
= source_addr
;
722 sg
.u
.sg
.grp
= group_addr
;
724 /* PIM enabled on interface? */
728 if (!PIM_IF_TEST_PIM(pim_ifp
->options
))
731 ch
= pim_ifchannel_find(ifp
, &sg
);
735 ifmembership_set(ch
, PIM_IFMEMBERSHIP_NOINFO
);
737 delete_on_noinfo(ch
);
740 void pim_ifchannel_update_could_assert(struct pim_ifchannel
*ch
)
742 int old_couldassert
= PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
));
743 int new_couldassert
= PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch
));
745 if (new_couldassert
== old_couldassert
)
748 if (PIM_DEBUG_PIM_EVENTS
) {
751 pim_inet4_dump("<src?>", ch
->sg
.u
.sg
.src
, src_str
, sizeof(src_str
));
752 pim_inet4_dump("<grp?>", ch
->sg
.u
.sg
.grp
, grp_str
, sizeof(grp_str
));
753 zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d",
755 src_str
, grp_str
, ch
->interface
->name
,
756 old_couldassert
, new_couldassert
);
759 if (new_couldassert
) {
760 /* CouldAssert(S,G,I) switched from FALSE to TRUE */
761 PIM_IF_FLAG_SET_COULD_ASSERT(ch
->flags
);
764 /* CouldAssert(S,G,I) switched from TRUE to FALSE */
765 PIM_IF_FLAG_UNSET_COULD_ASSERT(ch
->flags
);
767 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
) {
768 assert_action_a4(ch
);
772 pim_ifchannel_update_my_assert_metric(ch
);
776 my_assert_metric may be affected by:
779 pim_ifp->primary_address
780 rpf->source_nexthop.mrib_metric_preference;
781 rpf->source_nexthop.mrib_route_metric;
783 void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel
*ch
)
785 struct pim_assert_metric my_metric_new
= pim_macro_ch_my_assert_metric_eval(ch
);
787 if (pim_assert_metric_match(&my_metric_new
, &ch
->ifassert_my_metric
))
790 if (PIM_DEBUG_PIM_EVENTS
) {
793 char old_addr_str
[100];
794 char new_addr_str
[100];
795 pim_inet4_dump("<src?>", ch
->sg
.u
.sg
.src
, src_str
, sizeof(src_str
));
796 pim_inet4_dump("<grp?>", ch
->sg
.u
.sg
.grp
, grp_str
, sizeof(grp_str
));
797 pim_inet4_dump("<old_addr?>", ch
->ifassert_my_metric
.ip_address
, old_addr_str
, sizeof(old_addr_str
));
798 pim_inet4_dump("<new_addr?>", my_metric_new
.ip_address
, new_addr_str
, sizeof(new_addr_str
));
799 zlog_debug("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s",
801 src_str
, grp_str
, ch
->interface
->name
,
802 ch
->ifassert_my_metric
.rpt_bit_flag
,
803 ch
->ifassert_my_metric
.metric_preference
,
804 ch
->ifassert_my_metric
.route_metric
,
806 my_metric_new
.rpt_bit_flag
,
807 my_metric_new
.metric_preference
,
808 my_metric_new
.route_metric
,
812 ch
->ifassert_my_metric
= my_metric_new
;
814 if (pim_assert_metric_better(&ch
->ifassert_my_metric
,
815 &ch
->ifassert_winner_metric
)) {
816 assert_action_a5(ch
);
820 void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel
*ch
)
822 int old_atd
= PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch
->flags
));
823 int new_atd
= PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch
));
825 if (new_atd
== old_atd
)
828 if (PIM_DEBUG_PIM_EVENTS
) {
831 pim_inet4_dump("<src?>", ch
->sg
.u
.sg
.src
, src_str
, sizeof(src_str
));
832 pim_inet4_dump("<grp?>", ch
->sg
.u
.sg
.grp
, grp_str
, sizeof(grp_str
));
833 zlog_debug("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d",
835 src_str
, grp_str
, ch
->interface
->name
,
840 /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */
841 PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch
->flags
);
844 /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */
845 PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch
->flags
);
847 if (ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
848 assert_action_a5(ch
);