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$ $
36 #include "pim_iface.h"
37 #include "pim_hello.h"
38 #include "pim_macro.h"
39 #include "pim_assert.h"
40 #include "pim_ifchannel.h"
42 static int assert_action_a3(struct pim_ifchannel
*ch
);
43 static void assert_action_a2(struct pim_ifchannel
*ch
,
44 struct pim_assert_metric winner_metric
);
45 static void assert_action_a6(struct pim_ifchannel
*ch
,
46 struct pim_assert_metric winner_metric
);
48 void pim_ifassert_winner_set(struct pim_ifchannel
*ch
,
49 enum pim_ifassert_state new_state
,
50 struct in_addr winner
,
51 struct pim_assert_metric winner_metric
)
53 int winner_changed
= (ch
->ifassert_winner
.s_addr
!= winner
.s_addr
);
54 int metric_changed
= !pim_assert_metric_match(&ch
->ifassert_winner_metric
,
57 if (PIM_DEBUG_PIM_EVENTS
) {
58 if (ch
->ifassert_state
!= new_state
) {
61 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
62 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
63 zlog_debug("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s",
66 pim_ifchannel_ifassert_name(ch
->ifassert_state
),
67 pim_ifchannel_ifassert_name(new_state
),
76 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
77 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
78 pim_inet4_dump("<was?>", ch
->ifassert_winner
, was_str
, sizeof(was_str
));
79 pim_inet4_dump("<winner?>", winner
, winner_str
, sizeof(winner_str
));
80 zlog_debug("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s",
83 was_str
, winner_str
, ch
->interface
->name
);
85 } /* PIM_DEBUG_PIM_EVENTS */
87 ch
->ifassert_state
= new_state
;
88 ch
->ifassert_winner
= winner
;
89 ch
->ifassert_winner_metric
= winner_metric
;
90 ch
->ifassert_creation
= pim_time_monotonic_sec();
92 if (winner_changed
|| metric_changed
) {
93 pim_upstream_update_join_desired(ch
->upstream
);
94 pim_ifchannel_update_could_assert(ch
);
95 pim_ifchannel_update_assert_tracking_desired(ch
);
99 static void on_trace(const char *label
,
100 struct interface
*ifp
, struct in_addr src
)
102 if (PIM_DEBUG_PIM_TRACE
) {
104 pim_inet4_dump("<src?>", src
, src_str
, sizeof(src_str
));
105 zlog_debug("%s: from %s on %s",
106 label
, src_str
, ifp
->name
);
110 static int preferred_assert(const struct pim_ifchannel
*ch
,
111 const struct pim_assert_metric
*recv_metric
)
113 return pim_assert_metric_better(recv_metric
,
114 &ch
->ifassert_winner_metric
);
117 static int acceptable_assert(const struct pim_assert_metric
*my_metric
,
118 const struct pim_assert_metric
*recv_metric
)
120 return pim_assert_metric_better(recv_metric
,
124 static int inferior_assert(const struct pim_assert_metric
*my_metric
,
125 const struct pim_assert_metric
*recv_metric
)
127 return pim_assert_metric_better(my_metric
,
131 static int cancel_assert(const struct pim_assert_metric
*recv_metric
)
133 return (recv_metric
->metric_preference
== PIM_ASSERT_METRIC_PREFERENCE_MAX
)
135 (recv_metric
->route_metric
== PIM_ASSERT_ROUTE_METRIC_MAX
);
138 static void if_could_assert_do_a1(const char *caller
,
139 struct pim_ifchannel
*ch
)
141 if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
142 if (assert_action_a1(ch
)) {
145 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
146 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
147 zlog_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
148 __PRETTY_FUNCTION__
, caller
,
149 src_str
, grp_str
, ch
->interface
->name
);
150 /* log warning only */
155 static int dispatch_assert(struct interface
*ifp
,
156 struct in_addr source_addr
,
157 struct in_addr group_addr
,
158 struct pim_assert_metric recv_metric
)
160 struct pim_ifchannel
*ch
;
162 ch
= pim_ifchannel_add(ifp
, source_addr
, group_addr
);
164 char source_str
[100];
166 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
167 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
168 zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s",
170 source_str
, group_str
, ifp
->name
);
174 switch (ch
->ifassert_state
) {
175 case PIM_IFASSERT_NOINFO
:
176 if (recv_metric
.rpt_bit_flag
) {
178 if_could_assert_do_a1(__PRETTY_FUNCTION__
, ch
);
182 if (inferior_assert(&ch
->ifassert_my_metric
, &recv_metric
)) {
183 if_could_assert_do_a1(__PRETTY_FUNCTION__
, ch
);
185 else if (acceptable_assert(&ch
->ifassert_my_metric
, &recv_metric
)) {
186 if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch
->flags
)) {
187 assert_action_a6(ch
, recv_metric
);
192 case PIM_IFASSERT_I_AM_WINNER
:
193 if (preferred_assert(ch
, &recv_metric
)) {
194 assert_action_a2(ch
, recv_metric
);
197 if (inferior_assert(&ch
->ifassert_my_metric
, &recv_metric
)) {
198 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
); /* a3 requirement */
199 assert_action_a3(ch
);
203 case PIM_IFASSERT_I_AM_LOSER
:
204 if (recv_metric
.ip_address
.s_addr
== ch
->ifassert_winner
.s_addr
) {
205 /* Assert from current winner */
207 if (cancel_assert(&recv_metric
)) {
208 assert_action_a5(ch
);
211 if (inferior_assert(&ch
->ifassert_my_metric
, &recv_metric
)) {
212 assert_action_a5(ch
);
214 else if (acceptable_assert(&ch
->ifassert_my_metric
, &recv_metric
)) {
215 if (!recv_metric
.rpt_bit_flag
) {
216 assert_action_a2(ch
, recv_metric
);
221 else if (preferred_assert(ch
, &recv_metric
)) {
222 assert_action_a2(ch
, recv_metric
);
227 char source_str
[100];
229 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
230 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
231 zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
233 source_str
, group_str
, ch
->ifassert_state
, ifp
->name
);
241 int pim_assert_recv(struct interface
*ifp
,
242 struct pim_neighbor
*neigh
,
243 struct in_addr src_addr
,
244 uint8_t *buf
, int buf_size
)
246 struct prefix msg_group_addr
;
247 struct prefix msg_source_addr
;
248 struct pim_assert_metric msg_metric
;
253 on_trace(__PRETTY_FUNCTION__
, ifp
, src_addr
);
256 curr_size
= buf_size
;
259 Parse assert group addr
261 offset
= pim_parse_addr_group (&msg_group_addr
, curr
, curr_size
);
264 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
265 zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
274 Parse assert source addr
276 offset
= pim_parse_addr_ucast (&msg_source_addr
, curr
, curr_size
);
279 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
280 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
288 if (curr_size
!= 8) {
290 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
291 zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s",
299 Parse assert metric preference
302 msg_metric
.metric_preference
= pim_read_uint32_host(curr
);
304 msg_metric
.rpt_bit_flag
= msg_metric
.metric_preference
& 0x80000000; /* save highest bit */
305 msg_metric
.metric_preference
&= ~0x80000000; /* clear highest bit */
310 Parse assert route metric
313 msg_metric
.route_metric
= pim_read_uint32_host(curr
);
315 if (PIM_DEBUG_PIM_TRACE
) {
317 char source_str
[100];
319 pim_inet4_dump("<neigh?>", src_addr
, neigh_str
, sizeof(neigh_str
));
320 pim_inet4_dump("<src?>", msg_source_addr
.u
.prefix4
, source_str
, sizeof(source_str
));
321 pim_inet4_dump("<grp?>", msg_group_addr
.u
.prefix4
, group_str
, sizeof(group_str
));
322 zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
323 __PRETTY_FUNCTION__
, neigh_str
, ifp
->name
,
324 source_str
, group_str
,
325 msg_metric
.metric_preference
,
326 msg_metric
.route_metric
,
327 PIM_FORCE_BOOLEAN(msg_metric
.rpt_bit_flag
));
330 msg_metric
.ip_address
= src_addr
;
332 return dispatch_assert(ifp
,
333 msg_source_addr
.u
.prefix4
,
334 msg_group_addr
.u
.prefix4
,
339 RFC 4601: 4.6.3. Assert Metrics
341 Assert metrics are defined as:
343 When comparing assert_metrics, the rpt_bit_flag, metric_preference,
344 and route_metric field are compared in order, where the first lower
345 value wins. If all fields are equal, the primary IP address of the
346 router that sourced the Assert message is used as a tie-breaker,
347 with the highest IP address winning.
349 int pim_assert_metric_better(const struct pim_assert_metric
*m1
,
350 const struct pim_assert_metric
*m2
)
352 if (m1
->rpt_bit_flag
< m2
->rpt_bit_flag
)
354 if (m1
->rpt_bit_flag
> m2
->rpt_bit_flag
)
357 if (m1
->metric_preference
< m2
->metric_preference
)
359 if (m1
->metric_preference
> m2
->metric_preference
)
362 if (m1
->route_metric
< m2
->route_metric
)
364 if (m1
->route_metric
> m2
->route_metric
)
367 return ntohl(m1
->ip_address
.s_addr
) > ntohl(m2
->ip_address
.s_addr
);
370 int pim_assert_metric_match(const struct pim_assert_metric
*m1
,
371 const struct pim_assert_metric
*m2
)
373 if (m1
->rpt_bit_flag
!= m2
->rpt_bit_flag
)
375 if (m1
->metric_preference
!= m2
->metric_preference
)
377 if (m1
->route_metric
!= m2
->route_metric
)
380 return m1
->ip_address
.s_addr
== m2
->ip_address
.s_addr
;
383 int pim_assert_build_msg(uint8_t *pim_msg
, int buf_size
,
384 struct interface
*ifp
,
385 struct in_addr group_addr
,
386 struct in_addr source_addr
,
387 uint32_t metric_preference
,
388 uint32_t route_metric
,
389 uint32_t rpt_bit_flag
)
391 uint8_t *buf_pastend
= pim_msg
+ buf_size
;
392 uint8_t *pim_msg_curr
;
396 pim_msg_curr
= pim_msg
+ PIM_MSG_HEADER_LEN
; /* skip room for pim header */
399 remain
= buf_pastend
- pim_msg_curr
;
400 pim_msg_curr
= pim_msg_addr_encode_ipv4_group(pim_msg_curr
,
405 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
406 zlog_warn("%s: failure encoding group address %s: space left=%d",
407 __PRETTY_FUNCTION__
, group_str
, remain
);
412 remain
= buf_pastend
- pim_msg_curr
;
413 pim_msg_curr
= pim_msg_addr_encode_ipv4_ucast(pim_msg_curr
,
417 char source_str
[100];
418 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
419 zlog_warn("%s: failure encoding source address %s: space left=%d",
420 __PRETTY_FUNCTION__
, source_str
, remain
);
424 /* Metric preference */
425 pim_write_uint32(pim_msg_curr
, rpt_bit_flag
?
426 metric_preference
| 0x80000000 :
431 pim_write_uint32(pim_msg_curr
, route_metric
);
437 pim_msg_size
= pim_msg_curr
- pim_msg
;
438 pim_msg_build_header(pim_msg
, pim_msg_size
,
439 PIM_MSG_TYPE_ASSERT
);
444 static int pim_assert_do(struct pim_ifchannel
*ch
,
445 struct pim_assert_metric metric
)
447 struct interface
*ifp
;
448 struct pim_interface
*pim_ifp
;
449 uint8_t pim_msg
[1000];
457 zlog_warn("%s: pim not enabled on interface: %s",
458 __PRETTY_FUNCTION__
, ifp
->name
);
462 pim_msg_size
= pim_assert_build_msg(pim_msg
, sizeof(pim_msg
), ifp
,
463 ch
->group_addr
, ch
->source_addr
,
464 metric
.metric_preference
,
466 metric
.rpt_bit_flag
);
467 if (pim_msg_size
< 1) {
468 zlog_warn("%s: failure building PIM assert message: msg_size=%d",
469 __PRETTY_FUNCTION__
, pim_msg_size
);
474 RFC 4601: 4.3.1. Sending Hello Messages
476 Thus, if a router needs to send a Join/Prune or Assert message on
477 an interface on which it has not yet sent a Hello message with the
478 currently configured IP address, then it MUST immediately send the
479 relevant Hello message without waiting for the Hello Timer to
480 expire, followed by the Join/Prune or Assert message.
482 pim_hello_require(ifp
);
484 if (PIM_DEBUG_PIM_TRACE
) {
485 char source_str
[100];
487 pim_inet4_dump("<src?>", ch
->source_addr
, source_str
, sizeof(source_str
));
488 pim_inet4_dump("<grp?>", ch
->group_addr
, group_str
, sizeof(group_str
));
489 zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
491 ifp
->name
, source_str
, group_str
,
492 metric
.metric_preference
,
494 PIM_FORCE_BOOLEAN(metric
.rpt_bit_flag
));
497 if (pim_msg_send(pim_ifp
->pim_sock_fd
,
498 qpim_all_pim_routers_addr
,
502 zlog_warn("%s: could not send PIM message on interface %s",
503 __PRETTY_FUNCTION__
, ifp
->name
);
510 int pim_assert_send(struct pim_ifchannel
*ch
)
512 return pim_assert_do(ch
, ch
->ifassert_my_metric
);
516 RFC 4601: 4.6.4. AssertCancel Messages
518 An AssertCancel(S,G) is an infinite metric assert with the RPT bit
519 set that names S as the source.
521 static int pim_assert_cancel(struct pim_ifchannel
*ch
)
523 struct pim_assert_metric metric
;
525 metric
.rpt_bit_flag
= 0;
526 metric
.metric_preference
= PIM_ASSERT_METRIC_PREFERENCE_MAX
;
527 metric
.route_metric
= PIM_ASSERT_ROUTE_METRIC_MAX
;
528 metric
.ip_address
= ch
->source_addr
;
530 return pim_assert_do(ch
, metric
);
533 static int on_assert_timer(struct thread
*t
)
535 struct pim_ifchannel
*ch
;
536 struct interface
*ifp
;
545 if (PIM_DEBUG_PIM_TRACE
) {
548 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
549 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
550 zlog_debug("%s: (S,G)=(%s,%s) timer expired on interface %s",
552 src_str
, grp_str
, ifp
->name
);
555 ch
->t_ifassert_timer
= 0;
557 switch (ch
->ifassert_state
) {
558 case PIM_IFASSERT_I_AM_WINNER
:
559 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
); /* a3 requirement */
560 assert_action_a3(ch
);
562 case PIM_IFASSERT_I_AM_LOSER
:
563 assert_action_a5(ch
);
567 char source_str
[100];
569 pim_inet4_dump("<src?>", ch
->source_addr
, source_str
, sizeof(source_str
));
570 pim_inet4_dump("<grp?>", ch
->group_addr
, group_str
, sizeof(group_str
));
571 zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
573 source_str
, group_str
, ch
->ifassert_state
, ifp
->name
);
580 static void assert_timer_off(struct pim_ifchannel
*ch
)
582 struct interface
*ifp
;
588 if (PIM_DEBUG_PIM_TRACE
) {
589 if (ch
->t_ifassert_timer
) {
592 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
593 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
594 zlog_debug("%s: (S,G)=(%s,%s) cancelling timer on interface %s",
596 src_str
, grp_str
, ifp
->name
);
599 THREAD_OFF(ch
->t_ifassert_timer
);
600 zassert(!ch
->t_ifassert_timer
);
603 static void pim_assert_timer_set(struct pim_ifchannel
*ch
,
606 struct interface
*ifp
;
612 assert_timer_off(ch
);
614 if (PIM_DEBUG_PIM_TRACE
) {
617 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
618 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
619 zlog_debug("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s",
621 src_str
, grp_str
, interval
, ifp
->name
);
624 THREAD_TIMER_ON(master
, ch
->t_ifassert_timer
,
629 static void pim_assert_timer_reset(struct pim_ifchannel
*ch
)
631 pim_assert_timer_set(ch
, PIM_ASSERT_TIME
- PIM_ASSERT_OVERRIDE_INTERVAL
);
635 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
637 (S,G) Assert State machine Actions
639 A1: Send Assert(S,G).
640 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
641 Store self as AssertWinner(S,G,I).
642 Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
644 int assert_action_a1(struct pim_ifchannel
*ch
)
646 struct interface
*ifp
= ch
->interface
;
647 struct pim_interface
*pim_ifp
;
655 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
656 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
657 zlog_warn("%s: (S,G)=(%s,%s) multicast not enabled on interface %s",
659 src_str
, grp_str
, ifp
->name
);
660 return -1; /* must return since pim_ifp is used below */
663 /* Switch to I_AM_WINNER before performing action_a3 below */
664 pim_ifassert_winner_set(ch
, PIM_IFASSERT_I_AM_WINNER
,
665 pim_ifp
->primary_address
,
666 pim_macro_spt_assert_metric(&ch
->upstream
->rpf
,
667 pim_ifp
->primary_address
));
669 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
); /* a3 requirement */
670 if (assert_action_a3(ch
)) {
673 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
674 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
675 zlog_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s",
677 src_str
, grp_str
, ifp
->name
);
681 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
);
687 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
689 (S,G) Assert State machine Actions
691 A2: Store new assert winner as AssertWinner(S,G,I) and assert
692 winner metric as AssertWinnerMetric(S,G,I).
693 Set Assert Timer to Assert_Time.
695 static void assert_action_a2(struct pim_ifchannel
*ch
,
696 struct pim_assert_metric winner_metric
)
698 pim_ifassert_winner_set(ch
, PIM_IFASSERT_I_AM_LOSER
,
699 winner_metric
.ip_address
,
702 pim_assert_timer_set(ch
, PIM_ASSERT_TIME
);
704 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
);
708 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
710 (S,G) Assert State machine Actions
712 A3: Send Assert(S,G).
713 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
715 static int assert_action_a3(struct pim_ifchannel
*ch
)
717 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
);
719 pim_assert_timer_reset(ch
);
721 if (pim_assert_send(ch
)) {
724 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
725 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
727 zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s",
729 src_str
, grp_str
, ch
->interface
->name
);
733 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
);
739 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
741 (S,G) Assert State machine Actions
743 A4: Send AssertCancel(S,G).
744 Delete assert info (AssertWinner(S,G,I) and
745 AssertWinnerMetric(S,G,I) will then return their default
748 void assert_action_a4(struct pim_ifchannel
*ch
)
750 if (pim_assert_cancel(ch
)) {
753 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
754 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
755 zlog_warn("%s: failure sending AssertCancel(%s,%s) on interface %s",
757 src_str
, grp_str
, ch
->interface
->name
);
758 /* log warning only */
761 assert_action_a5(ch
);
763 zassert(ch
->ifassert_state
== PIM_IFASSERT_NOINFO
);
767 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
769 (S,G) Assert State machine Actions
771 A5: Delete assert info (AssertWinner(S,G,I) and
772 AssertWinnerMetric(S,G,I) will then return their default values).
774 void assert_action_a5(struct pim_ifchannel
*ch
)
776 reset_ifassert_state(ch
);
777 zassert(ch
->ifassert_state
== PIM_IFASSERT_NOINFO
);
781 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
783 (S,G) Assert State machine Actions
785 A6: Store new assert winner as AssertWinner(S,G,I) and assert
786 winner metric as AssertWinnerMetric(S,G,I).
787 Set Assert Timer to Assert_Time.
788 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
789 set SPTbit(S,G) to TRUE.
791 static void assert_action_a6(struct pim_ifchannel
*ch
,
792 struct pim_assert_metric winner_metric
)
794 assert_action_a2(ch
, winner_metric
);
797 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
800 if (ch
->upstream
->rpf
.source_nexthop
.interface
== ch
->interface
)
801 if (ch
->upstream
->join_state
== PIM_UPSTREAM_JOINED
)
802 ch
->upstream
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
804 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
);