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
33 #include "pim_iface.h"
34 #include "pim_hello.h"
35 #include "pim_macro.h"
36 #include "pim_assert.h"
37 #include "pim_ifchannel.h"
39 static int assert_action_a3(struct pim_ifchannel
*ch
);
40 static void assert_action_a2(struct pim_ifchannel
*ch
,
41 struct pim_assert_metric winner_metric
);
42 static void assert_action_a6(struct pim_ifchannel
*ch
,
43 struct pim_assert_metric winner_metric
);
45 void pim_ifassert_winner_set(struct pim_ifchannel
*ch
,
46 enum pim_ifassert_state new_state
,
47 struct in_addr winner
,
48 struct pim_assert_metric winner_metric
)
50 int winner_changed
= (ch
->ifassert_winner
.s_addr
!= winner
.s_addr
);
51 int metric_changed
= !pim_assert_metric_match(
52 &ch
->ifassert_winner_metric
, &winner_metric
);
54 if (PIM_DEBUG_PIM_EVENTS
) {
55 if (ch
->ifassert_state
!= new_state
) {
57 "%s: (S,G)=%s assert state changed from %s to %s on interface %s",
58 __PRETTY_FUNCTION__
, ch
->sg_str
,
59 pim_ifchannel_ifassert_name(ch
->ifassert_state
),
60 pim_ifchannel_ifassert_name(new_state
),
65 char was_str
[INET_ADDRSTRLEN
];
66 char winner_str
[INET_ADDRSTRLEN
];
67 pim_inet4_dump("<was?>", ch
->ifassert_winner
, was_str
,
69 pim_inet4_dump("<winner?>", winner
, winner_str
,
72 "%s: (S,G)=%s assert winner changed from %s to %s on interface %s",
73 __PRETTY_FUNCTION__
, ch
->sg_str
, was_str
,
74 winner_str
, ch
->interface
->name
);
76 } /* PIM_DEBUG_PIM_EVENTS */
78 ch
->ifassert_state
= new_state
;
79 ch
->ifassert_winner
= winner
;
80 ch
->ifassert_winner_metric
= winner_metric
;
81 ch
->ifassert_creation
= pim_time_monotonic_sec();
83 if (winner_changed
|| metric_changed
) {
84 pim_upstream_update_join_desired(ch
->upstream
);
85 pim_ifchannel_update_could_assert(ch
);
86 pim_ifchannel_update_assert_tracking_desired(ch
);
90 static void on_trace(const char *label
, struct interface
*ifp
,
93 if (PIM_DEBUG_PIM_TRACE
) {
94 char src_str
[INET_ADDRSTRLEN
];
95 pim_inet4_dump("<src?>", src
, src_str
, sizeof(src_str
));
96 zlog_debug("%s: from %s on %s", label
, src_str
, ifp
->name
);
100 static int preferred_assert(const struct pim_ifchannel
*ch
,
101 const struct pim_assert_metric
*recv_metric
)
103 return pim_assert_metric_better(recv_metric
,
104 &ch
->ifassert_winner_metric
);
107 static int acceptable_assert(const struct pim_assert_metric
*my_metric
,
108 const struct pim_assert_metric
*recv_metric
)
110 return pim_assert_metric_better(recv_metric
, my_metric
);
113 static int inferior_assert(const struct pim_assert_metric
*my_metric
,
114 const struct pim_assert_metric
*recv_metric
)
116 return pim_assert_metric_better(my_metric
, recv_metric
);
119 static int cancel_assert(const struct pim_assert_metric
*recv_metric
)
121 return (recv_metric
->metric_preference
122 == PIM_ASSERT_METRIC_PREFERENCE_MAX
)
123 && (recv_metric
->route_metric
== PIM_ASSERT_ROUTE_METRIC_MAX
);
126 static void if_could_assert_do_a1(const char *caller
, struct pim_ifchannel
*ch
)
128 if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
129 if (assert_action_a1(ch
)) {
131 "%s: %s: (S,G)=%s assert_action_a1 failure on interface %s",
132 __PRETTY_FUNCTION__
, caller
, ch
->sg_str
,
133 ch
->interface
->name
);
134 /* log warning only */
139 static int dispatch_assert(struct interface
*ifp
, struct in_addr source_addr
,
140 struct in_addr group_addr
,
141 struct pim_assert_metric recv_metric
)
143 struct pim_ifchannel
*ch
;
146 memset(&sg
, 0, sizeof(struct prefix_sg
));
147 sg
.src
= source_addr
;
149 ch
= pim_ifchannel_add(ifp
, &sg
, 0);
152 "%s: (S,G)=%s failure creating channel on interface %s",
153 __PRETTY_FUNCTION__
, pim_str_sg_dump(&sg
), ifp
->name
);
157 switch (ch
->ifassert_state
) {
158 case PIM_IFASSERT_NOINFO
:
159 if (recv_metric
.rpt_bit_flag
) {
161 if_could_assert_do_a1(__PRETTY_FUNCTION__
, ch
);
164 if (inferior_assert(&ch
->ifassert_my_metric
,
166 if_could_assert_do_a1(__PRETTY_FUNCTION__
, ch
);
167 } else if (acceptable_assert(&ch
->ifassert_my_metric
,
169 if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(
171 assert_action_a6(ch
, recv_metric
);
176 case PIM_IFASSERT_I_AM_WINNER
:
177 if (preferred_assert(ch
, &recv_metric
)) {
178 assert_action_a2(ch
, recv_metric
);
180 if (inferior_assert(&ch
->ifassert_my_metric
,
182 assert_action_a3(ch
);
186 case PIM_IFASSERT_I_AM_LOSER
:
187 if (recv_metric
.ip_address
.s_addr
188 == ch
->ifassert_winner
.s_addr
) {
189 /* Assert from current winner */
191 if (cancel_assert(&recv_metric
)) {
192 assert_action_a5(ch
);
194 if (inferior_assert(&ch
->ifassert_my_metric
,
196 assert_action_a5(ch
);
197 } else if (acceptable_assert(
198 &ch
->ifassert_my_metric
,
200 if (!recv_metric
.rpt_bit_flag
) {
206 } else if (preferred_assert(ch
, &recv_metric
)) {
207 assert_action_a2(ch
, recv_metric
);
212 "%s: (S,G)=%s invalid assert state %d on interface %s",
213 __PRETTY_FUNCTION__
, ch
->sg_str
, ch
->ifassert_state
,
222 int pim_assert_recv(struct interface
*ifp
, struct pim_neighbor
*neigh
,
223 struct in_addr src_addr
, uint8_t *buf
, int buf_size
)
226 struct prefix msg_source_addr
;
227 struct pim_assert_metric msg_metric
;
231 struct pim_interface
*pim_ifp
= NULL
;
233 on_trace(__PRETTY_FUNCTION__
, ifp
, src_addr
);
236 curr_size
= buf_size
;
239 Parse assert group addr
241 memset(&sg
, 0, sizeof(struct prefix_sg
));
242 offset
= pim_parse_addr_group(&sg
, curr
, curr_size
);
244 char src_str
[INET_ADDRSTRLEN
];
245 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
246 zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
247 __PRETTY_FUNCTION__
, src_str
, ifp
->name
);
254 Parse assert source addr
256 offset
= pim_parse_addr_ucast(&msg_source_addr
, curr
, curr_size
);
258 char src_str
[INET_ADDRSTRLEN
];
259 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
260 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
261 __PRETTY_FUNCTION__
, src_str
, ifp
->name
);
267 if (curr_size
!= 8) {
268 char src_str
[INET_ADDRSTRLEN
];
269 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
271 "%s: preference/metric size is not 8: size=%d from %s on interface %s",
272 __PRETTY_FUNCTION__
, curr_size
, src_str
, ifp
->name
);
277 Parse assert metric preference
280 msg_metric
.metric_preference
= pim_read_uint32_host(curr
);
282 msg_metric
.rpt_bit_flag
= msg_metric
.metric_preference
283 & 0x80000000; /* save highest bit */
284 msg_metric
.metric_preference
&= ~0x80000000; /* clear highest bit */
289 Parse assert route metric
292 msg_metric
.route_metric
= pim_read_uint32_host(curr
);
294 if (PIM_DEBUG_PIM_TRACE
) {
295 char neigh_str
[INET_ADDRSTRLEN
];
296 char source_str
[INET_ADDRSTRLEN
];
297 char group_str
[INET_ADDRSTRLEN
];
298 pim_inet4_dump("<neigh?>", src_addr
, neigh_str
,
300 pim_inet4_dump("<src?>", msg_source_addr
.u
.prefix4
, source_str
,
302 pim_inet4_dump("<grp?>", sg
.grp
, group_str
, sizeof(group_str
));
304 "%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
305 __PRETTY_FUNCTION__
, neigh_str
, ifp
->name
, source_str
,
306 group_str
, msg_metric
.metric_preference
,
307 msg_metric
.route_metric
,
308 PIM_FORCE_BOOLEAN(msg_metric
.rpt_bit_flag
));
311 msg_metric
.ip_address
= src_addr
;
315 ++pim_ifp
->pim_ifstat_assert_recv
;
317 return dispatch_assert(ifp
, msg_source_addr
.u
.prefix4
, sg
.grp
,
322 RFC 4601: 4.6.3. Assert Metrics
324 Assert metrics are defined as:
326 When comparing assert_metrics, the rpt_bit_flag, metric_preference,
327 and route_metric field are compared in order, where the first lower
328 value wins. If all fields are equal, the primary IP address of the
329 router that sourced the Assert message is used as a tie-breaker,
330 with the highest IP address winning.
332 int pim_assert_metric_better(const struct pim_assert_metric
*m1
,
333 const struct pim_assert_metric
*m2
)
335 if (m1
->rpt_bit_flag
< m2
->rpt_bit_flag
)
337 if (m1
->rpt_bit_flag
> m2
->rpt_bit_flag
)
340 if (m1
->metric_preference
< m2
->metric_preference
)
342 if (m1
->metric_preference
> m2
->metric_preference
)
345 if (m1
->route_metric
< m2
->route_metric
)
347 if (m1
->route_metric
> m2
->route_metric
)
350 return ntohl(m1
->ip_address
.s_addr
) > ntohl(m2
->ip_address
.s_addr
);
353 int pim_assert_metric_match(const struct pim_assert_metric
*m1
,
354 const struct pim_assert_metric
*m2
)
356 if (m1
->rpt_bit_flag
!= m2
->rpt_bit_flag
)
358 if (m1
->metric_preference
!= m2
->metric_preference
)
360 if (m1
->route_metric
!= m2
->route_metric
)
363 return m1
->ip_address
.s_addr
== m2
->ip_address
.s_addr
;
366 int pim_assert_build_msg(uint8_t *pim_msg
, int buf_size
, struct interface
*ifp
,
367 struct in_addr group_addr
, struct in_addr source_addr
,
368 uint32_t metric_preference
, uint32_t route_metric
,
369 uint32_t rpt_bit_flag
)
371 uint8_t *buf_pastend
= pim_msg
+ buf_size
;
372 uint8_t *pim_msg_curr
;
377 pim_msg
+ PIM_MSG_HEADER_LEN
; /* skip room for pim header */
380 remain
= buf_pastend
- pim_msg_curr
;
381 pim_msg_curr
= pim_msg_addr_encode_ipv4_group(pim_msg_curr
, group_addr
);
383 char group_str
[INET_ADDRSTRLEN
];
384 pim_inet4_dump("<grp?>", group_addr
, group_str
,
387 "%s: failure encoding group address %s: space left=%d",
388 __PRETTY_FUNCTION__
, group_str
, remain
);
393 remain
= buf_pastend
- pim_msg_curr
;
395 pim_msg_addr_encode_ipv4_ucast(pim_msg_curr
, source_addr
);
397 char source_str
[INET_ADDRSTRLEN
];
398 pim_inet4_dump("<src?>", source_addr
, source_str
,
401 "%s: failure encoding source address %s: space left=%d",
402 __PRETTY_FUNCTION__
, source_str
, remain
);
406 /* Metric preference */
407 pim_write_uint32(pim_msg_curr
,
408 rpt_bit_flag
? metric_preference
| 0x80000000
409 : metric_preference
);
413 pim_write_uint32(pim_msg_curr
, route_metric
);
419 pim_msg_size
= pim_msg_curr
- pim_msg
;
420 pim_msg_build_header(pim_msg
, pim_msg_size
, PIM_MSG_TYPE_ASSERT
);
425 static int pim_assert_do(struct pim_ifchannel
*ch
,
426 struct pim_assert_metric metric
)
428 struct interface
*ifp
;
429 struct pim_interface
*pim_ifp
;
430 uint8_t pim_msg
[1000];
435 if (PIM_DEBUG_PIM_TRACE
)
436 zlog_debug("%s: channel%s has no associated interface!",
437 __PRETTY_FUNCTION__
, ch
->sg_str
);
442 if (PIM_DEBUG_PIM_TRACE
)
444 "%s: channel %s pim not enabled on interface: %s",
445 __PRETTY_FUNCTION__
, ch
->sg_str
, ifp
->name
);
450 pim_assert_build_msg(pim_msg
, sizeof(pim_msg
), ifp
, ch
->sg
.grp
,
451 ch
->sg
.src
, metric
.metric_preference
,
452 metric
.route_metric
, metric
.rpt_bit_flag
);
453 if (pim_msg_size
< 1) {
455 "%s: failure building PIM assert message: msg_size=%d",
456 __PRETTY_FUNCTION__
, pim_msg_size
);
461 RFC 4601: 4.3.1. Sending Hello Messages
463 Thus, if a router needs to send a Join/Prune or Assert message on
464 an interface on which it has not yet sent a Hello message with the
465 currently configured IP address, then it MUST immediately send the
466 relevant Hello message without waiting for the Hello Timer to
467 expire, followed by the Join/Prune or Assert message.
469 pim_hello_require(ifp
);
471 if (PIM_DEBUG_PIM_TRACE
) {
472 zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
473 __PRETTY_FUNCTION__
, ifp
->name
, ch
->sg_str
,
474 metric
.metric_preference
, metric
.route_metric
,
475 PIM_FORCE_BOOLEAN(metric
.rpt_bit_flag
));
477 ++pim_ifp
->pim_ifstat_assert_send
;
479 if (pim_msg_send(pim_ifp
->pim_sock_fd
, pim_ifp
->primary_address
,
480 qpim_all_pim_routers_addr
, pim_msg
, pim_msg_size
,
482 zlog_warn("%s: could not send PIM message on interface %s",
483 __PRETTY_FUNCTION__
, ifp
->name
);
490 int pim_assert_send(struct pim_ifchannel
*ch
)
492 return pim_assert_do(ch
, ch
->ifassert_my_metric
);
496 RFC 4601: 4.6.4. AssertCancel Messages
498 An AssertCancel(S,G) is an infinite metric assert with the RPT bit
499 set that names S as the source.
501 static int pim_assert_cancel(struct pim_ifchannel
*ch
)
503 struct pim_assert_metric metric
;
505 metric
.rpt_bit_flag
= 0;
506 metric
.metric_preference
= PIM_ASSERT_METRIC_PREFERENCE_MAX
;
507 metric
.route_metric
= PIM_ASSERT_ROUTE_METRIC_MAX
;
508 metric
.ip_address
= ch
->sg
.src
;
510 return pim_assert_do(ch
, metric
);
513 static int on_assert_timer(struct thread
*t
)
515 struct pim_ifchannel
*ch
;
516 struct interface
*ifp
;
522 if (PIM_DEBUG_PIM_TRACE
) {
523 zlog_debug("%s: (S,G)=%s timer expired on interface %s",
524 __PRETTY_FUNCTION__
, ch
->sg_str
, ifp
->name
);
527 ch
->t_ifassert_timer
= NULL
;
529 switch (ch
->ifassert_state
) {
530 case PIM_IFASSERT_I_AM_WINNER
:
531 assert_action_a3(ch
);
533 case PIM_IFASSERT_I_AM_LOSER
:
534 assert_action_a5(ch
);
537 if (PIM_DEBUG_PIM_EVENTS
)
539 "%s: (S,G)=%s invalid assert state %d on interface %s",
540 __PRETTY_FUNCTION__
, ch
->sg_str
,
541 ch
->ifassert_state
, ifp
->name
);
548 static void assert_timer_off(struct pim_ifchannel
*ch
)
550 if (PIM_DEBUG_PIM_TRACE
) {
551 if (ch
->t_ifassert_timer
) {
553 "%s: (S,G)=%s cancelling timer on interface %s",
554 __PRETTY_FUNCTION__
, ch
->sg_str
,
555 ch
->interface
->name
);
558 THREAD_OFF(ch
->t_ifassert_timer
);
561 static void pim_assert_timer_set(struct pim_ifchannel
*ch
, int interval
)
563 assert_timer_off(ch
);
565 if (PIM_DEBUG_PIM_TRACE
) {
566 zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
567 __PRETTY_FUNCTION__
, ch
->sg_str
, interval
,
568 ch
->interface
->name
);
571 thread_add_timer(master
, on_assert_timer
, ch
, interval
,
572 &ch
->t_ifassert_timer
);
575 static void pim_assert_timer_reset(struct pim_ifchannel
*ch
)
577 pim_assert_timer_set(ch
,
578 PIM_ASSERT_TIME
- PIM_ASSERT_OVERRIDE_INTERVAL
);
582 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
584 (S,G) Assert State machine Actions
586 A1: Send Assert(S,G).
587 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
588 Store self as AssertWinner(S,G,I).
589 Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
591 int assert_action_a1(struct pim_ifchannel
*ch
)
593 struct interface
*ifp
= ch
->interface
;
594 struct pim_interface
*pim_ifp
;
598 zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
599 __PRETTY_FUNCTION__
, ch
->sg_str
, ifp
->name
);
600 return -1; /* must return since pim_ifp is used below */
603 /* Switch to I_AM_WINNER before performing action_a3 below */
604 pim_ifassert_winner_set(
605 ch
, PIM_IFASSERT_I_AM_WINNER
, pim_ifp
->primary_address
,
606 pim_macro_spt_assert_metric(&ch
->upstream
->rpf
,
607 pim_ifp
->primary_address
));
609 if (assert_action_a3(ch
)) {
611 "%s: (S,G)=%s assert_action_a3 failure on interface %s",
612 __PRETTY_FUNCTION__
, ch
->sg_str
, ifp
->name
);
616 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_WINNER
) {
617 if (PIM_DEBUG_PIM_EVENTS
)
619 "%s: channel%s not in expected PIM_IFASSERT_I_AM_WINNER state",
620 __PRETTY_FUNCTION__
, ch
->sg_str
);
627 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
629 (S,G) Assert State machine Actions
631 A2: Store new assert winner as AssertWinner(S,G,I) and assert
632 winner metric as AssertWinnerMetric(S,G,I).
633 Set Assert Timer to Assert_Time.
635 static void assert_action_a2(struct pim_ifchannel
*ch
,
636 struct pim_assert_metric winner_metric
)
638 pim_ifassert_winner_set(ch
, PIM_IFASSERT_I_AM_LOSER
,
639 winner_metric
.ip_address
, winner_metric
);
641 pim_assert_timer_set(ch
, PIM_ASSERT_TIME
);
643 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
) {
644 if (PIM_DEBUG_PIM_EVENTS
)
646 "%s: channel%s not in expected PIM_IFASSERT_I_AM_LOSER state",
647 __PRETTY_FUNCTION__
, ch
->sg_str
);
652 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
654 (S,G) Assert State machine Actions
656 A3: Send Assert(S,G).
657 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
659 static int assert_action_a3(struct pim_ifchannel
*ch
)
661 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_WINNER
) {
662 if (PIM_DEBUG_PIM_EVENTS
)
664 "%s: channel%s expected to be in PIM_IFASSERT_I_AM_WINNER state",
665 __PRETTY_FUNCTION__
, ch
->sg_str
);
669 pim_assert_timer_reset(ch
);
671 if (pim_assert_send(ch
)) {
672 zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
673 __PRETTY_FUNCTION__
, ch
->sg_str
, ch
->interface
->name
);
681 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
683 (S,G) Assert State machine Actions
685 A4: Send AssertCancel(S,G).
686 Delete assert info (AssertWinner(S,G,I) and
687 AssertWinnerMetric(S,G,I) will then return their default
690 void assert_action_a4(struct pim_ifchannel
*ch
)
692 if (pim_assert_cancel(ch
)) {
693 zlog_warn("%s: failure sending AssertCancel%s on interface %s",
694 __PRETTY_FUNCTION__
, ch
->sg_str
, ch
->interface
->name
);
695 /* log warning only */
698 assert_action_a5(ch
);
700 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
701 if (PIM_DEBUG_PIM_EVENTS
)
703 "%s: channel%s not in PIM_IFASSERT_NOINFO state as expected",
704 __PRETTY_FUNCTION__
, ch
->sg_str
);
709 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
711 (S,G) Assert State machine Actions
713 A5: Delete assert info (AssertWinner(S,G,I) and
714 AssertWinnerMetric(S,G,I) will then return their default values).
716 void assert_action_a5(struct pim_ifchannel
*ch
)
718 reset_ifassert_state(ch
);
719 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
720 if (PIM_DEBUG_PIM_EVENTS
)
722 "%s: channel%s not in PIM_IFSSERT_NOINFO state as expected",
723 __PRETTY_FUNCTION__
, ch
->sg_str
);
728 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
730 (S,G) Assert State machine Actions
732 A6: Store new assert winner as AssertWinner(S,G,I) and assert
733 winner metric as AssertWinnerMetric(S,G,I).
734 Set Assert Timer to Assert_Time.
735 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
736 set SPTbit(S,G) to TRUE.
738 static void assert_action_a6(struct pim_ifchannel
*ch
,
739 struct pim_assert_metric winner_metric
)
741 assert_action_a2(ch
, winner_metric
);
744 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
747 if (ch
->upstream
->rpf
.source_nexthop
.interface
== ch
->interface
)
748 if (ch
->upstream
->join_state
== PIM_UPSTREAM_JOINED
)
749 ch
->upstream
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
751 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
) {
752 if (PIM_DEBUG_PIM_EVENTS
)
754 "%s: channel%s not in PIM_IFASSERT_I_AM_LOSER state as expected",
755 __PRETTY_FUNCTION__
, ch
->sg_str
);