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 struct pim_interface
*pim_ifp
= ch
->interface
->info
;
51 int winner_changed
= (ch
->ifassert_winner
.s_addr
!= winner
.s_addr
);
52 int metric_changed
= !pim_assert_metric_match(
53 &ch
->ifassert_winner_metric
, &winner_metric
);
55 if (PIM_DEBUG_PIM_EVENTS
) {
56 if (ch
->ifassert_state
!= new_state
) {
58 "%s: (S,G)=%s assert state changed from %s to %s on interface %s",
59 __PRETTY_FUNCTION__
, ch
->sg_str
,
60 pim_ifchannel_ifassert_name(ch
->ifassert_state
),
61 pim_ifchannel_ifassert_name(new_state
),
66 char was_str
[INET_ADDRSTRLEN
];
67 char winner_str
[INET_ADDRSTRLEN
];
68 pim_inet4_dump("<was?>", ch
->ifassert_winner
, was_str
,
70 pim_inet4_dump("<winner?>", winner
, winner_str
,
73 "%s: (S,G)=%s assert winner changed from %s to %s on interface %s",
74 __PRETTY_FUNCTION__
, ch
->sg_str
, was_str
,
75 winner_str
, ch
->interface
->name
);
77 } /* PIM_DEBUG_PIM_EVENTS */
79 ch
->ifassert_state
= new_state
;
80 ch
->ifassert_winner
= winner
;
81 ch
->ifassert_winner_metric
= winner_metric
;
82 ch
->ifassert_creation
= pim_time_monotonic_sec();
84 if (winner_changed
|| metric_changed
) {
85 pim_upstream_update_join_desired(pim_ifp
->pim
, ch
->upstream
);
86 pim_ifchannel_update_could_assert(ch
);
87 pim_ifchannel_update_assert_tracking_desired(ch
);
91 static void on_trace(const char *label
, struct interface
*ifp
,
94 if (PIM_DEBUG_PIM_TRACE
) {
95 char src_str
[INET_ADDRSTRLEN
];
96 pim_inet4_dump("<src?>", src
, src_str
, sizeof(src_str
));
97 zlog_debug("%s: from %s on %s", label
, src_str
, ifp
->name
);
101 static int preferred_assert(const struct pim_ifchannel
*ch
,
102 const struct pim_assert_metric
*recv_metric
)
104 return pim_assert_metric_better(recv_metric
,
105 &ch
->ifassert_winner_metric
);
108 static int acceptable_assert(const struct pim_assert_metric
*my_metric
,
109 const struct pim_assert_metric
*recv_metric
)
111 return pim_assert_metric_better(recv_metric
, my_metric
);
114 static int inferior_assert(const struct pim_assert_metric
*my_metric
,
115 const struct pim_assert_metric
*recv_metric
)
117 return pim_assert_metric_better(my_metric
, recv_metric
);
120 static int cancel_assert(const struct pim_assert_metric
*recv_metric
)
122 return (recv_metric
->metric_preference
123 == PIM_ASSERT_METRIC_PREFERENCE_MAX
)
124 && (recv_metric
->route_metric
== PIM_ASSERT_ROUTE_METRIC_MAX
);
127 static void if_could_assert_do_a1(const char *caller
, struct pim_ifchannel
*ch
)
129 if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
130 if (assert_action_a1(ch
)) {
132 "%s: %s: (S,G)=%s assert_action_a1 failure on interface %s",
133 __PRETTY_FUNCTION__
, caller
, ch
->sg_str
,
134 ch
->interface
->name
);
135 /* log warning only */
140 static int dispatch_assert(struct interface
*ifp
, struct in_addr source_addr
,
141 struct in_addr group_addr
,
142 struct pim_assert_metric recv_metric
)
144 struct pim_ifchannel
*ch
;
147 memset(&sg
, 0, sizeof(struct prefix_sg
));
148 sg
.src
= source_addr
;
150 ch
= pim_ifchannel_add(ifp
, &sg
, 0, 0);
152 switch (ch
->ifassert_state
) {
153 case PIM_IFASSERT_NOINFO
:
154 if (recv_metric
.rpt_bit_flag
) {
156 if_could_assert_do_a1(__PRETTY_FUNCTION__
, ch
);
159 if (inferior_assert(&ch
->ifassert_my_metric
,
161 if_could_assert_do_a1(__PRETTY_FUNCTION__
, ch
);
162 } else if (acceptable_assert(&ch
->ifassert_my_metric
,
164 if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(
166 assert_action_a6(ch
, recv_metric
);
171 case PIM_IFASSERT_I_AM_WINNER
:
172 if (preferred_assert(ch
, &recv_metric
)) {
173 assert_action_a2(ch
, recv_metric
);
175 if (inferior_assert(&ch
->ifassert_my_metric
,
177 assert_action_a3(ch
);
181 case PIM_IFASSERT_I_AM_LOSER
:
182 if (recv_metric
.ip_address
.s_addr
183 == ch
->ifassert_winner
.s_addr
) {
184 /* Assert from current winner */
186 if (cancel_assert(&recv_metric
)) {
187 assert_action_a5(ch
);
189 if (inferior_assert(&ch
->ifassert_my_metric
,
191 assert_action_a5(ch
);
192 } else if (acceptable_assert(
193 &ch
->ifassert_my_metric
,
195 if (!recv_metric
.rpt_bit_flag
) {
201 } else if (preferred_assert(ch
, &recv_metric
)) {
202 assert_action_a2(ch
, recv_metric
);
207 "%s: (S,G)=%s invalid assert state %d on interface %s",
208 __PRETTY_FUNCTION__
, ch
->sg_str
, ch
->ifassert_state
,
217 int pim_assert_recv(struct interface
*ifp
, struct pim_neighbor
*neigh
,
218 struct in_addr src_addr
, uint8_t *buf
, int buf_size
)
221 struct prefix msg_source_addr
;
222 struct pim_assert_metric msg_metric
;
226 struct pim_interface
*pim_ifp
= NULL
;
228 on_trace(__PRETTY_FUNCTION__
, ifp
, src_addr
);
231 curr_size
= buf_size
;
234 Parse assert group addr
236 memset(&sg
, 0, sizeof(struct prefix_sg
));
237 offset
= pim_parse_addr_group(&sg
, curr
, curr_size
);
239 char src_str
[INET_ADDRSTRLEN
];
240 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
241 zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
242 __PRETTY_FUNCTION__
, src_str
, ifp
->name
);
249 Parse assert source addr
251 offset
= pim_parse_addr_ucast(&msg_source_addr
, curr
, curr_size
);
253 char src_str
[INET_ADDRSTRLEN
];
254 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
255 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
256 __PRETTY_FUNCTION__
, src_str
, ifp
->name
);
263 char src_str
[INET_ADDRSTRLEN
];
264 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
266 "%s: preference/metric size is less than 8 bytes: size=%d from %s on interface %s",
267 __PRETTY_FUNCTION__
, curr_size
, src_str
, ifp
->name
);
272 Parse assert metric preference
275 msg_metric
.metric_preference
= pim_read_uint32_host(curr
);
277 msg_metric
.rpt_bit_flag
= msg_metric
.metric_preference
278 & 0x80000000; /* save highest bit */
279 msg_metric
.metric_preference
&= ~0x80000000; /* clear highest bit */
284 Parse assert route metric
287 msg_metric
.route_metric
= pim_read_uint32_host(curr
);
289 if (PIM_DEBUG_PIM_TRACE
) {
290 char neigh_str
[INET_ADDRSTRLEN
];
291 char source_str
[INET_ADDRSTRLEN
];
292 char group_str
[INET_ADDRSTRLEN
];
293 pim_inet4_dump("<neigh?>", src_addr
, neigh_str
,
295 pim_inet4_dump("<src?>", msg_source_addr
.u
.prefix4
, source_str
,
297 pim_inet4_dump("<grp?>", sg
.grp
, group_str
, sizeof(group_str
));
299 "%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
300 __PRETTY_FUNCTION__
, neigh_str
, ifp
->name
, source_str
,
301 group_str
, msg_metric
.metric_preference
,
302 msg_metric
.route_metric
,
303 PIM_FORCE_BOOLEAN(msg_metric
.rpt_bit_flag
));
306 msg_metric
.ip_address
= src_addr
;
310 ++pim_ifp
->pim_ifstat_assert_recv
;
312 return dispatch_assert(ifp
, msg_source_addr
.u
.prefix4
, sg
.grp
,
317 RFC 4601: 4.6.3. Assert Metrics
319 Assert metrics are defined as:
321 When comparing assert_metrics, the rpt_bit_flag, metric_preference,
322 and route_metric field are compared in order, where the first lower
323 value wins. If all fields are equal, the primary IP address of the
324 router that sourced the Assert message is used as a tie-breaker,
325 with the highest IP address winning.
327 int pim_assert_metric_better(const struct pim_assert_metric
*m1
,
328 const struct pim_assert_metric
*m2
)
330 if (m1
->rpt_bit_flag
< m2
->rpt_bit_flag
)
332 if (m1
->rpt_bit_flag
> m2
->rpt_bit_flag
)
335 if (m1
->metric_preference
< m2
->metric_preference
)
337 if (m1
->metric_preference
> m2
->metric_preference
)
340 if (m1
->route_metric
< m2
->route_metric
)
342 if (m1
->route_metric
> m2
->route_metric
)
345 return ntohl(m1
->ip_address
.s_addr
) > ntohl(m2
->ip_address
.s_addr
);
348 int pim_assert_metric_match(const struct pim_assert_metric
*m1
,
349 const struct pim_assert_metric
*m2
)
351 if (m1
->rpt_bit_flag
!= m2
->rpt_bit_flag
)
353 if (m1
->metric_preference
!= m2
->metric_preference
)
355 if (m1
->route_metric
!= m2
->route_metric
)
358 return m1
->ip_address
.s_addr
== m2
->ip_address
.s_addr
;
361 int pim_assert_build_msg(uint8_t *pim_msg
, int buf_size
, struct interface
*ifp
,
362 struct in_addr group_addr
, struct in_addr source_addr
,
363 uint32_t metric_preference
, uint32_t route_metric
,
364 uint32_t rpt_bit_flag
)
366 uint8_t *buf_pastend
= pim_msg
+ buf_size
;
367 uint8_t *pim_msg_curr
;
372 pim_msg
+ PIM_MSG_HEADER_LEN
; /* skip room for pim header */
375 remain
= buf_pastend
- pim_msg_curr
;
376 pim_msg_curr
= pim_msg_addr_encode_ipv4_group(pim_msg_curr
, group_addr
);
378 char group_str
[INET_ADDRSTRLEN
];
379 pim_inet4_dump("<grp?>", group_addr
, group_str
,
382 "%s: failure encoding group address %s: space left=%d",
383 __PRETTY_FUNCTION__
, group_str
, remain
);
388 remain
= buf_pastend
- pim_msg_curr
;
390 pim_msg_addr_encode_ipv4_ucast(pim_msg_curr
, source_addr
);
392 char source_str
[INET_ADDRSTRLEN
];
393 pim_inet4_dump("<src?>", source_addr
, source_str
,
396 "%s: failure encoding source address %s: space left=%d",
397 __PRETTY_FUNCTION__
, source_str
, remain
);
401 /* Metric preference */
402 pim_write_uint32(pim_msg_curr
,
403 rpt_bit_flag
? metric_preference
| 0x80000000
404 : metric_preference
);
408 pim_write_uint32(pim_msg_curr
, route_metric
);
414 pim_msg_size
= pim_msg_curr
- pim_msg
;
415 pim_msg_build_header(pim_msg
, pim_msg_size
, PIM_MSG_TYPE_ASSERT
, false);
420 static int pim_assert_do(struct pim_ifchannel
*ch
,
421 struct pim_assert_metric metric
)
423 struct interface
*ifp
;
424 struct pim_interface
*pim_ifp
;
425 uint8_t pim_msg
[1000];
430 if (PIM_DEBUG_PIM_TRACE
)
431 zlog_debug("%s: channel%s has no associated interface!",
432 __PRETTY_FUNCTION__
, ch
->sg_str
);
437 if (PIM_DEBUG_PIM_TRACE
)
439 "%s: channel %s pim not enabled on interface: %s",
440 __PRETTY_FUNCTION__
, ch
->sg_str
, ifp
->name
);
445 pim_assert_build_msg(pim_msg
, sizeof(pim_msg
), ifp
, ch
->sg
.grp
,
446 ch
->sg
.src
, metric
.metric_preference
,
447 metric
.route_metric
, metric
.rpt_bit_flag
);
448 if (pim_msg_size
< 1) {
450 "%s: failure building PIM assert message: msg_size=%d",
451 __PRETTY_FUNCTION__
, pim_msg_size
);
456 RFC 4601: 4.3.1. Sending Hello Messages
458 Thus, if a router needs to send a Join/Prune or Assert message on
459 an interface on which it has not yet sent a Hello message with the
460 currently configured IP address, then it MUST immediately send the
461 relevant Hello message without waiting for the Hello Timer to
462 expire, followed by the Join/Prune or Assert message.
464 pim_hello_require(ifp
);
466 if (PIM_DEBUG_PIM_TRACE
) {
467 zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
468 __PRETTY_FUNCTION__
, ifp
->name
, ch
->sg_str
,
469 metric
.metric_preference
, metric
.route_metric
,
470 PIM_FORCE_BOOLEAN(metric
.rpt_bit_flag
));
472 ++pim_ifp
->pim_ifstat_assert_send
;
474 if (pim_msg_send(pim_ifp
->pim_sock_fd
, pim_ifp
->primary_address
,
475 qpim_all_pim_routers_addr
, pim_msg
, pim_msg_size
,
477 zlog_warn("%s: could not send PIM message on interface %s",
478 __PRETTY_FUNCTION__
, ifp
->name
);
485 int pim_assert_send(struct pim_ifchannel
*ch
)
487 return pim_assert_do(ch
, ch
->ifassert_my_metric
);
491 RFC 4601: 4.6.4. AssertCancel Messages
493 An AssertCancel(S,G) is an infinite metric assert with the RPT bit
494 set that names S as the source.
496 static int pim_assert_cancel(struct pim_ifchannel
*ch
)
498 struct pim_assert_metric metric
;
500 metric
.rpt_bit_flag
= 0;
501 metric
.metric_preference
= PIM_ASSERT_METRIC_PREFERENCE_MAX
;
502 metric
.route_metric
= PIM_ASSERT_ROUTE_METRIC_MAX
;
503 metric
.ip_address
= ch
->sg
.src
;
505 return pim_assert_do(ch
, metric
);
508 static int on_assert_timer(struct thread
*t
)
510 struct pim_ifchannel
*ch
;
511 struct interface
*ifp
;
517 if (PIM_DEBUG_PIM_TRACE
) {
518 zlog_debug("%s: (S,G)=%s timer expired on interface %s",
519 __PRETTY_FUNCTION__
, ch
->sg_str
, ifp
->name
);
522 ch
->t_ifassert_timer
= NULL
;
524 switch (ch
->ifassert_state
) {
525 case PIM_IFASSERT_I_AM_WINNER
:
526 assert_action_a3(ch
);
528 case PIM_IFASSERT_I_AM_LOSER
:
529 assert_action_a5(ch
);
532 if (PIM_DEBUG_PIM_EVENTS
)
534 "%s: (S,G)=%s invalid assert state %d on interface %s",
535 __PRETTY_FUNCTION__
, ch
->sg_str
,
536 ch
->ifassert_state
, ifp
->name
);
543 static void assert_timer_off(struct pim_ifchannel
*ch
)
545 if (PIM_DEBUG_PIM_TRACE
) {
546 if (ch
->t_ifassert_timer
) {
548 "%s: (S,G)=%s cancelling timer on interface %s",
549 __PRETTY_FUNCTION__
, ch
->sg_str
,
550 ch
->interface
->name
);
553 THREAD_OFF(ch
->t_ifassert_timer
);
556 static void pim_assert_timer_set(struct pim_ifchannel
*ch
, int interval
)
558 assert_timer_off(ch
);
560 if (PIM_DEBUG_PIM_TRACE
) {
561 zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
562 __PRETTY_FUNCTION__
, ch
->sg_str
, interval
,
563 ch
->interface
->name
);
566 thread_add_timer(router
->master
, on_assert_timer
, ch
, interval
,
567 &ch
->t_ifassert_timer
);
570 static void pim_assert_timer_reset(struct pim_ifchannel
*ch
)
572 pim_assert_timer_set(ch
,
573 PIM_ASSERT_TIME
- PIM_ASSERT_OVERRIDE_INTERVAL
);
577 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
579 (S,G) Assert State machine Actions
581 A1: Send Assert(S,G).
582 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
583 Store self as AssertWinner(S,G,I).
584 Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
586 int assert_action_a1(struct pim_ifchannel
*ch
)
588 struct interface
*ifp
= ch
->interface
;
589 struct pim_interface
*pim_ifp
;
593 zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
594 __PRETTY_FUNCTION__
, ch
->sg_str
, ifp
->name
);
595 return -1; /* must return since pim_ifp is used below */
598 /* Switch to I_AM_WINNER before performing action_a3 below */
599 pim_ifassert_winner_set(
600 ch
, PIM_IFASSERT_I_AM_WINNER
, pim_ifp
->primary_address
,
601 pim_macro_spt_assert_metric(&ch
->upstream
->rpf
,
602 pim_ifp
->primary_address
));
604 if (assert_action_a3(ch
)) {
606 "%s: (S,G)=%s assert_action_a3 failure on interface %s",
607 __PRETTY_FUNCTION__
, ch
->sg_str
, ifp
->name
);
611 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_WINNER
) {
612 if (PIM_DEBUG_PIM_EVENTS
)
614 "%s: channel%s not in expected PIM_IFASSERT_I_AM_WINNER state",
615 __PRETTY_FUNCTION__
, ch
->sg_str
);
622 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
624 (S,G) Assert State machine Actions
626 A2: Store new assert winner as AssertWinner(S,G,I) and assert
627 winner metric as AssertWinnerMetric(S,G,I).
628 Set Assert Timer to Assert_Time.
630 static void assert_action_a2(struct pim_ifchannel
*ch
,
631 struct pim_assert_metric winner_metric
)
633 pim_ifassert_winner_set(ch
, PIM_IFASSERT_I_AM_LOSER
,
634 winner_metric
.ip_address
, winner_metric
);
636 pim_assert_timer_set(ch
, PIM_ASSERT_TIME
);
638 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
) {
639 if (PIM_DEBUG_PIM_EVENTS
)
641 "%s: channel%s not in expected PIM_IFASSERT_I_AM_LOSER state",
642 __PRETTY_FUNCTION__
, ch
->sg_str
);
647 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
649 (S,G) Assert State machine Actions
651 A3: Send Assert(S,G).
652 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
654 static int assert_action_a3(struct pim_ifchannel
*ch
)
656 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_WINNER
) {
657 if (PIM_DEBUG_PIM_EVENTS
)
659 "%s: channel%s expected to be in PIM_IFASSERT_I_AM_WINNER state",
660 __PRETTY_FUNCTION__
, ch
->sg_str
);
664 pim_assert_timer_reset(ch
);
666 if (pim_assert_send(ch
)) {
667 zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
668 __PRETTY_FUNCTION__
, ch
->sg_str
, ch
->interface
->name
);
676 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
678 (S,G) Assert State machine Actions
680 A4: Send AssertCancel(S,G).
681 Delete assert info (AssertWinner(S,G,I) and
682 AssertWinnerMetric(S,G,I) will then return their default
685 void assert_action_a4(struct pim_ifchannel
*ch
)
687 if (pim_assert_cancel(ch
)) {
688 zlog_warn("%s: failure sending AssertCancel%s on interface %s",
689 __PRETTY_FUNCTION__
, ch
->sg_str
, ch
->interface
->name
);
690 /* log warning only */
693 assert_action_a5(ch
);
695 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
696 if (PIM_DEBUG_PIM_EVENTS
)
698 "%s: channel%s not in PIM_IFASSERT_NOINFO state as expected",
699 __PRETTY_FUNCTION__
, ch
->sg_str
);
704 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
706 (S,G) Assert State machine Actions
708 A5: Delete assert info (AssertWinner(S,G,I) and
709 AssertWinnerMetric(S,G,I) will then return their default values).
711 void assert_action_a5(struct pim_ifchannel
*ch
)
713 reset_ifassert_state(ch
);
714 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
715 if (PIM_DEBUG_PIM_EVENTS
)
717 "%s: channel%s not in PIM_IFSSERT_NOINFO state as expected",
718 __PRETTY_FUNCTION__
, ch
->sg_str
);
723 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
725 (S,G) Assert State machine Actions
727 A6: Store new assert winner as AssertWinner(S,G,I) and assert
728 winner metric as AssertWinnerMetric(S,G,I).
729 Set Assert Timer to Assert_Time.
730 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
731 set SPTbit(S,G) to true.
733 static void assert_action_a6(struct pim_ifchannel
*ch
,
734 struct pim_assert_metric winner_metric
)
736 assert_action_a2(ch
, winner_metric
);
739 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
742 if (ch
->upstream
->rpf
.source_nexthop
.interface
== ch
->interface
)
743 if (ch
->upstream
->join_state
== PIM_UPSTREAM_JOINED
)
744 ch
->upstream
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
746 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
) {
747 if (PIM_DEBUG_PIM_EVENTS
)
749 "%s: channel%s not in PIM_IFASSERT_I_AM_LOSER state as expected",
750 __PRETTY_FUNCTION__
, ch
->sg_str
);