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$ $
31 #include "pim_iface.h"
32 #include "pim_ifchannel.h"
33 #include "pim_zebra.h"
39 #include "pim_macro.h"
41 void pim_ifchannel_free(struct pim_ifchannel *ch)
43 zassert(!ch->t_ifjoin_expiry_timer);
44 zassert(!ch->t_ifjoin_prune_pending_timer);
45 zassert(!ch->t_ifassert_timer);
47 XFREE(MTYPE_PIM_IFCHANNEL, ch);
50 void pim_ifchannel_delete(struct pim_ifchannel *ch)
52 struct pim_interface *pim_ifp;
54 pim_ifp = ch->interface->info;
57 if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) {
58 pim_upstream_update_join_desired(ch->upstream);
61 pim_upstream_del(ch->upstream);
63 THREAD_OFF(ch->t_ifjoin_expiry_timer);
64 THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
65 THREAD_OFF(ch->t_ifassert_timer);
68 notice that listnode_delete() can't be moved
69 into pim_ifchannel_free() because the later is
70 called by list_delete_all_node()
72 listnode_delete(pim_ifp->pim_ifchannel_list, ch);
74 pim_ifchannel_free(ch);
77 #define IFCHANNEL_NOINFO(ch) \
79 ((ch)->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO) \
81 ((ch)->ifjoin_state == PIM_IFJOIN_NOINFO) \
83 ((ch)->ifassert_state == PIM_IFASSERT_NOINFO) \
86 static void delete_on_noinfo(struct pim_ifchannel *ch)
88 if (IFCHANNEL_NOINFO(ch)) {
90 /* In NOINFO state, timers should have been cleared */
91 zassert(!ch->t_ifjoin_expiry_timer);
92 zassert(!ch->t_ifjoin_prune_pending_timer);
93 zassert(!ch->t_ifassert_timer);
95 pim_ifchannel_delete(ch);
99 void pim_ifchannel_ifjoin_switch(const char *caller,
100 struct pim_ifchannel *ch,
101 enum pim_ifjoin_state new_state)
103 enum pim_ifjoin_state old_state = ch->ifjoin_state;
105 if (old_state == new_state) {
106 if (PIM_DEBUG_PIM_EVENTS) {
107 zlog_debug("%s calledby %s: non-transition on state %d (%s)",
108 __PRETTY_FUNCTION__, caller, new_state,
109 pim_ifchannel_ifjoin_name(new_state));
114 zassert(old_state != new_state);
116 ch->ifjoin_state = new_state;
118 /* Transition to/from NOINFO ? */
120 (old_state == PIM_IFJOIN_NOINFO)
122 (new_state == PIM_IFJOIN_NOINFO)
125 if (PIM_DEBUG_PIM_EVENTS) {
128 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
129 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
130 zlog_debug("PIM_IFCHANNEL_%s: (S,G)=(%s,%s) on interface %s",
131 ((new_state == PIM_IFJOIN_NOINFO) ? "DOWN" : "UP"),
132 src_str, grp_str, ch->interface->name);
136 Record uptime of state transition to/from NOINFO
138 ch->ifjoin_creation = pim_time_monotonic_sec();
140 pim_upstream_update_join_desired(ch->upstream);
141 pim_ifchannel_update_could_assert(ch);
142 pim_ifchannel_update_assert_tracking_desired(ch);
146 const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state)
148 switch (ifjoin_state) {
149 case PIM_IFJOIN_NOINFO: return "NOINFO";
150 case PIM_IFJOIN_JOIN: return "JOIN";
151 case PIM_IFJOIN_PRUNE_PENDING: return "PRUNEP";
154 return "ifjoin_bad_state";
157 const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state)
159 switch (ifassert_state) {
160 case PIM_IFASSERT_NOINFO: return "NOINFO";
161 case PIM_IFASSERT_I_AM_WINNER: return "WINNER";
162 case PIM_IFASSERT_I_AM_LOSER: return "LOSER";
165 return "ifassert_bad_state";
169 RFC 4601: 4.6.5. Assert State Macros
171 AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I)
172 defaults to Infinity when in the NoInfo state.
174 void reset_ifassert_state(struct pim_ifchannel *ch)
176 THREAD_OFF(ch->t_ifassert_timer);
178 pim_ifassert_winner_set(ch,
181 qpim_infinite_assert_metric);
184 static struct pim_ifchannel *pim_ifchannel_new(struct interface *ifp,
185 struct in_addr source_addr,
186 struct in_addr group_addr)
188 struct pim_ifchannel *ch;
189 struct pim_interface *pim_ifp;
190 struct pim_upstream *up;
195 up = pim_upstream_add(source_addr, group_addr);
199 pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
200 pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
201 zlog_err("%s: could not attach upstream (S,G)=(%s,%s) on interface %s",
203 src_str, grp_str, ifp->name);
207 ch = XMALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch));
209 zlog_err("%s: PIM XMALLOC(%zu) failure",
210 __PRETTY_FUNCTION__, sizeof(*ch));
217 ch->source_addr = source_addr;
218 ch->group_addr = group_addr;
219 ch->local_ifmembership = PIM_IFMEMBERSHIP_NOINFO;
221 ch->ifjoin_state = PIM_IFJOIN_NOINFO;
222 ch->t_ifjoin_expiry_timer = 0;
223 ch->t_ifjoin_prune_pending_timer = 0;
224 ch->ifjoin_creation = 0;
226 ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
227 ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval (ch);
229 ch->ifassert_winner.s_addr = 0;
232 ch->t_ifassert_timer = 0;
233 reset_ifassert_state(ch);
234 if (pim_macro_ch_could_assert_eval(ch))
235 PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
237 PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
239 if (pim_macro_assert_tracking_desired_eval(ch))
240 PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
242 PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
245 listnode_add(pim_ifp->pim_ifchannel_list, ch);
247 zassert(IFCHANNEL_NOINFO(ch));
252 struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
253 struct in_addr source_addr,
254 struct in_addr group_addr)
256 struct pim_interface *pim_ifp;
257 struct listnode *ch_node;
258 struct pim_ifchannel *ch;
267 pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
268 pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
269 zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
276 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
278 (source_addr.s_addr == ch->source_addr.s_addr) &&
279 (group_addr.s_addr == ch->group_addr.s_addr)
288 static void ifmembership_set(struct pim_ifchannel *ch,
289 enum pim_ifmembership membership)
291 if (ch->local_ifmembership == membership)
294 if (PIM_DEBUG_PIM_EVENTS) {
297 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
298 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
299 zlog_debug("%s: (S,G)=(%s,%s) membership now is %s on interface %s",
302 membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE" : "NOINFO",
303 ch->interface->name);
306 ch->local_ifmembership = membership;
308 pim_upstream_update_join_desired(ch->upstream);
309 pim_ifchannel_update_could_assert(ch);
310 pim_ifchannel_update_assert_tracking_desired(ch);
314 void pim_ifchannel_membership_clear(struct interface *ifp)
316 struct pim_interface *pim_ifp;
317 struct listnode *ch_node;
318 struct pim_ifchannel *ch;
323 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
324 ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
328 void pim_ifchannel_delete_on_noinfo(struct interface *ifp)
330 struct pim_interface *pim_ifp;
331 struct listnode *node;
332 struct listnode *next_node;
333 struct pim_ifchannel *ch;
338 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
339 delete_on_noinfo(ch);
343 struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
344 struct in_addr source_addr,
345 struct in_addr group_addr)
347 struct pim_ifchannel *ch;
351 ch = pim_ifchannel_find(ifp, source_addr, group_addr);
355 ch = pim_ifchannel_new(ifp, source_addr, group_addr);
359 pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
360 pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
361 zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=(%s,%s) on interface %s",
363 src_str, grp_str, ifp->name);
368 static void ifjoin_to_noinfo(struct pim_ifchannel *ch)
370 pim_forward_stop(ch);
371 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO);
372 delete_on_noinfo(ch);
375 static int on_ifjoin_expiry_timer(struct thread *t)
377 struct pim_ifchannel *ch;
383 ch->t_ifjoin_expiry_timer = 0;
385 zassert(ch->ifjoin_state == PIM_IFJOIN_JOIN);
387 ifjoin_to_noinfo(ch);
388 /* ch may have been deleted */
393 static void prune_echo(struct interface *ifp,
394 struct in_addr source_addr,
395 struct in_addr group_addr)
397 struct pim_interface *pim_ifp;
398 struct in_addr neigh_dst_addr;
403 neigh_dst_addr = pim_ifp->primary_address;
405 if (PIM_DEBUG_PIM_EVENTS) {
406 char source_str[100];
408 char neigh_dst_str[100];
409 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
410 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
411 pim_inet4_dump("<neigh?>", neigh_dst_addr, neigh_dst_str, sizeof(neigh_dst_str));
412 zlog_debug("%s: sending PruneEcho(S,G)=(%s,%s) to upstream=%s on interface %s",
413 __PRETTY_FUNCTION__, source_str, group_str, neigh_dst_str, ifp->name);
416 pim_joinprune_send(ifp, neigh_dst_addr, source_addr, group_addr,
417 0 /* boolean: send_join=false (prune) */);
420 static int on_ifjoin_prune_pending_timer(struct thread *t)
422 struct pim_ifchannel *ch;
423 int send_prune_echo; /* boolean */
424 struct interface *ifp;
425 struct pim_interface *pim_ifp;
426 struct in_addr ch_source;
427 struct in_addr ch_group;
433 ch->t_ifjoin_prune_pending_timer = 0;
435 zassert(ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING);
437 /* Send PruneEcho(S,G) ? */
440 send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1);
443 ch_source = ch->source_addr;
444 ch_group = ch->group_addr;
446 ifjoin_to_noinfo(ch);
447 /* from here ch may have been deleted */
450 prune_echo(ifp, ch_source, ch_group);
455 static void check_recv_upstream(int is_join,
456 struct interface *recv_ifp,
457 struct in_addr upstream,
458 struct in_addr source_addr,
459 struct in_addr group_addr,
460 uint8_t source_flags,
463 struct pim_upstream *up;
465 /* Upstream (S,G) in Joined state ? */
466 up = pim_upstream_find(source_addr, group_addr);
469 if (up->join_state != PIM_UPSTREAM_JOINED)
472 /* Upstream (S,G) in Joined state */
474 if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
475 /* RPF'(S,G) not found */
478 pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
479 pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
480 zlog_warn("%s %s: RPF'(%s,%s) not found",
481 __FILE__, __PRETTY_FUNCTION__,
486 /* upstream directed to RPF'(S,G) ? */
487 if (upstream.s_addr != up->rpf.rpf_addr.s_addr) {
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 pim_inet4_dump("<up?>", upstream, up_str, sizeof(up_str));
495 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
496 zlog_warn("%s %s: (S,G)=(%s,%s) upstream=%s not directed to RPF'(S,G)=%s on interface %s",
497 __FILE__, __PRETTY_FUNCTION__,
499 up_str, rpf_str, recv_ifp->name);
502 /* upstream directed to RPF'(S,G) */
505 /* Join(S,G) to RPF'(S,G) */
506 pim_upstream_join_suppress(up, up->rpf.rpf_addr, holdtime);
510 /* Prune to RPF'(S,G) */
512 if (source_flags & PIM_RPT_BIT_MASK) {
513 if (source_flags & PIM_WILDCARD_BIT_MASK) {
514 /* Prune(*,G) to RPF'(S,G) */
515 pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)",
516 up, up->rpf.rpf_addr);
520 /* Prune(S,G,rpt) to RPF'(S,G) */
521 pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)",
522 up, up->rpf.rpf_addr);
526 /* Prune(S,G) to RPF'(S,G) */
527 pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up,
531 static int nonlocal_upstream(int is_join,
532 struct interface *recv_ifp,
533 struct in_addr upstream,
534 struct in_addr source_addr,
535 struct in_addr group_addr,
536 uint8_t source_flags,
539 struct pim_interface *recv_pim_ifp;
540 int is_local; /* boolean */
542 recv_pim_ifp = recv_ifp->info;
543 zassert(recv_pim_ifp);
545 is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr);
547 if (PIM_DEBUG_PIM_TRACE) {
551 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
552 pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
553 pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
554 zlog_warn("%s: recv %s (S,G)=(%s,%s) to %s upstream=%s on %s",
556 is_join ? "join" : "prune",
558 is_local ? "local" : "non-local",
559 up_str, recv_ifp->name);
566 Since recv upstream addr was not directed to our primary
567 address, check if we should react to it in any way.
569 check_recv_upstream(is_join, recv_ifp, upstream, source_addr, group_addr,
570 source_flags, holdtime);
572 return 1; /* non-local */
575 void pim_ifchannel_join_add(struct interface *ifp,
576 struct in_addr neigh_addr,
577 struct in_addr upstream,
578 struct in_addr source_addr,
579 struct in_addr group_addr,
580 uint8_t source_flags,
583 struct pim_interface *pim_ifp;
584 struct pim_ifchannel *ch;
586 if (nonlocal_upstream(1 /* join */, ifp, upstream,
587 source_addr, group_addr, source_flags, holdtime)) {
591 ch = pim_ifchannel_add(ifp, source_addr, group_addr);
596 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
598 Transitions from "I am Assert Loser" State
600 Receive Join(S,G) on Interface I
602 We receive a Join(S,G) that has the Upstream Neighbor Address
603 field set to my primary IP address on interface I. The action is
604 to transition to NoInfo state, delete this (S,G) assert state
605 (Actions A5 below), and allow the normal PIM Join/Prune mechanisms
608 Notice: The nonlocal_upstream() test above ensures the upstream
609 address of the join message is our primary address.
611 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
615 pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
616 pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
617 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
618 zlog_warn("%s: Assert Loser recv Join(%s,%s) from %s on %s",
620 src_str, grp_str, neigh_str, ifp->name);
622 assert_action_a5(ch);
628 switch (ch->ifjoin_state) {
629 case PIM_IFJOIN_NOINFO:
630 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
631 if (pim_macro_chisin_oiflist(ch)) {
632 pim_forward_start(ch);
635 case PIM_IFJOIN_JOIN:
636 zassert(!ch->t_ifjoin_prune_pending_timer);
639 In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to a
640 previously received join message with holdtime=0xFFFF.
642 if (ch->t_ifjoin_expiry_timer) {
643 unsigned long remain =
644 thread_timer_remain_second(ch->t_ifjoin_expiry_timer);
645 if (remain > holdtime) {
647 RFC 4601: 4.5.3. Receiving (S,G) Join/Prune Messages
649 Transitions from Join State
651 The (S,G) downstream state machine on interface I remains in
652 Join state, and the Expiry Timer (ET) is restarted, set to
653 maximum of its current value and the HoldTime from the
654 triggering Join/Prune message.
656 Conclusion: Do not change the ET if the current value is
657 higher than the received join holdtime.
662 THREAD_OFF(ch->t_ifjoin_expiry_timer);
664 case PIM_IFJOIN_PRUNE_PENDING:
665 zassert(!ch->t_ifjoin_expiry_timer);
666 zassert(ch->t_ifjoin_prune_pending_timer);
667 THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
668 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
672 zassert(!IFCHANNEL_NOINFO(ch));
674 if (holdtime != 0xFFFF) {
675 THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
676 on_ifjoin_expiry_timer,
681 void pim_ifchannel_prune(struct interface *ifp,
682 struct in_addr upstream,
683 struct in_addr source_addr,
684 struct in_addr group_addr,
685 uint8_t source_flags,
688 struct pim_ifchannel *ch;
689 int jp_override_interval_msec;
691 if (nonlocal_upstream(0 /* prune */, ifp, upstream,
692 source_addr, group_addr, source_flags, holdtime)) {
696 ch = pim_ifchannel_add(ifp, source_addr, group_addr);
700 switch (ch->ifjoin_state) {
701 case PIM_IFJOIN_NOINFO:
702 case PIM_IFJOIN_PRUNE_PENDING:
705 case PIM_IFJOIN_JOIN:
707 struct pim_interface *pim_ifp;
711 zassert(ch->t_ifjoin_expiry_timer);
712 zassert(!ch->t_ifjoin_prune_pending_timer);
714 THREAD_OFF(ch->t_ifjoin_expiry_timer);
716 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_PRUNE_PENDING);
718 if (listcount(pim_ifp->pim_neighbor_list) > 1) {
719 jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp);
722 jp_override_interval_msec = 0; /* schedule to expire immediately */
723 /* If we called ifjoin_prune() directly instead, care should
724 be taken not to use "ch" afterwards since it would be
728 THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer,
729 on_ifjoin_prune_pending_timer,
730 ch, jp_override_interval_msec);
732 zassert(!ch->t_ifjoin_expiry_timer);
733 zassert(ch->t_ifjoin_prune_pending_timer);
740 void pim_ifchannel_local_membership_add(struct interface *ifp,
741 struct in_addr source_addr,
742 struct in_addr group_addr)
744 struct pim_ifchannel *ch;
745 struct pim_interface *pim_ifp;
747 /* PIM enabled on interface? */
751 if (!PIM_IF_TEST_PIM(pim_ifp->options))
754 ch = pim_ifchannel_add(ifp, source_addr, group_addr);
759 ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE);
761 zassert(!IFCHANNEL_NOINFO(ch));
764 void pim_ifchannel_local_membership_del(struct interface *ifp,
765 struct in_addr source_addr,
766 struct in_addr group_addr)
768 struct pim_ifchannel *ch;
769 struct pim_interface *pim_ifp;
771 /* PIM enabled on interface? */
775 if (!PIM_IF_TEST_PIM(pim_ifp->options))
778 ch = pim_ifchannel_find(ifp, source_addr, group_addr);
782 ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
784 delete_on_noinfo(ch);
787 void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch)
789 int old_couldassert = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags));
790 int new_couldassert = PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch));
792 if (new_couldassert == old_couldassert)
795 if (PIM_DEBUG_PIM_EVENTS) {
798 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
799 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
800 zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d",
802 src_str, grp_str, ch->interface->name,
803 old_couldassert, new_couldassert);
806 if (new_couldassert) {
807 /* CouldAssert(S,G,I) switched from FALSE to TRUE */
808 PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
811 /* CouldAssert(S,G,I) switched from TRUE to FALSE */
812 PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
814 if (ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER) {
815 assert_action_a4(ch);
819 pim_ifchannel_update_my_assert_metric(ch);
823 my_assert_metric may be affected by:
826 pim_ifp->primary_address
827 rpf->source_nexthop.mrib_metric_preference;
828 rpf->source_nexthop.mrib_route_metric;
830 void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch)
832 struct pim_assert_metric my_metric_new = pim_macro_ch_my_assert_metric_eval(ch);
834 if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric))
837 if (PIM_DEBUG_PIM_EVENTS) {
840 char old_addr_str[100];
841 char new_addr_str[100];
842 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
843 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
844 pim_inet4_dump("<old_addr?>", ch->ifassert_my_metric.ip_address, old_addr_str, sizeof(old_addr_str));
845 pim_inet4_dump("<new_addr?>", my_metric_new.ip_address, new_addr_str, sizeof(new_addr_str));
846 zlog_debug("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s",
848 src_str, grp_str, ch->interface->name,
849 ch->ifassert_my_metric.rpt_bit_flag,
850 ch->ifassert_my_metric.metric_preference,
851 ch->ifassert_my_metric.route_metric,
853 my_metric_new.rpt_bit_flag,
854 my_metric_new.metric_preference,
855 my_metric_new.route_metric,
859 ch->ifassert_my_metric = my_metric_new;
861 if (pim_assert_metric_better(&ch->ifassert_my_metric,
862 &ch->ifassert_winner_metric)) {
863 assert_action_a5(ch);
867 void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch)
869 int old_atd = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags));
870 int new_atd = PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch));
872 if (new_atd == old_atd)
875 if (PIM_DEBUG_PIM_EVENTS) {
878 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
879 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
880 zlog_debug("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d",
882 src_str, grp_str, ch->interface->name,
887 /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */
888 PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
891 /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */
892 PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
894 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
895 assert_action_a5(ch);