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,
34 #include "pim_iface.h"
35 #include "pim_hello.h"
36 #include "pim_macro.h"
37 #include "pim_assert.h"
38 #include "pim_ifchannel.h"
40 static int assert_action_a3(struct pim_ifchannel
*ch
);
41 static void assert_action_a2(struct pim_ifchannel
*ch
,
42 struct pim_assert_metric winner_metric
);
43 static void assert_action_a6(struct pim_ifchannel
*ch
,
44 struct pim_assert_metric winner_metric
);
46 void pim_ifassert_winner_set(struct pim_ifchannel
*ch
,
47 enum pim_ifassert_state new_state
,
48 struct in_addr winner
,
49 struct pim_assert_metric winner_metric
)
51 int winner_changed
= (ch
->ifassert_winner
.s_addr
!= winner
.s_addr
);
52 int metric_changed
= !pim_assert_metric_match(&ch
->ifassert_winner_metric
,
55 if (PIM_DEBUG_PIM_EVENTS
) {
56 if (ch
->ifassert_state
!= new_state
) {
59 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
60 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
61 zlog_debug("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s",
64 pim_ifchannel_ifassert_name(ch
->ifassert_state
),
65 pim_ifchannel_ifassert_name(new_state
),
74 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
75 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
76 pim_inet4_dump("<was?>", ch
->ifassert_winner
, was_str
, sizeof(was_str
));
77 pim_inet4_dump("<winner?>", winner
, winner_str
, sizeof(winner_str
));
78 zlog_debug("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s",
81 was_str
, winner_str
, ch
->interface
->name
);
83 } /* PIM_DEBUG_PIM_EVENTS */
85 ch
->ifassert_state
= new_state
;
86 ch
->ifassert_winner
= winner
;
87 ch
->ifassert_winner_metric
= winner_metric
;
88 ch
->ifassert_creation
= pim_time_monotonic_sec();
90 if (winner_changed
|| metric_changed
) {
91 pim_upstream_update_join_desired(ch
->upstream
);
92 pim_ifchannel_update_could_assert(ch
);
93 pim_ifchannel_update_assert_tracking_desired(ch
);
97 static void on_trace(const char *label
,
98 struct interface
*ifp
, struct in_addr src
)
100 if (PIM_DEBUG_PIM_TRACE
) {
102 pim_inet4_dump("<src?>", src
, src_str
, sizeof(src_str
));
103 zlog_debug("%s: from %s on %s",
104 label
, src_str
, ifp
->name
);
108 static int preferred_assert(const struct pim_ifchannel
*ch
,
109 const struct pim_assert_metric
*recv_metric
)
111 return pim_assert_metric_better(recv_metric
,
112 &ch
->ifassert_winner_metric
);
115 static int acceptable_assert(const struct pim_assert_metric
*my_metric
,
116 const struct pim_assert_metric
*recv_metric
)
118 return pim_assert_metric_better(recv_metric
,
122 static int inferior_assert(const struct pim_assert_metric
*my_metric
,
123 const struct pim_assert_metric
*recv_metric
)
125 return pim_assert_metric_better(my_metric
,
129 static int cancel_assert(const struct pim_assert_metric
*recv_metric
)
131 return (recv_metric
->metric_preference
== PIM_ASSERT_METRIC_PREFERENCE_MAX
)
133 (recv_metric
->route_metric
== PIM_ASSERT_ROUTE_METRIC_MAX
);
136 static void if_could_assert_do_a1(const char *caller
,
137 struct pim_ifchannel
*ch
)
139 if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
140 if (assert_action_a1(ch
)) {
143 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
144 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
145 zlog_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
146 __PRETTY_FUNCTION__
, caller
,
147 src_str
, grp_str
, ch
->interface
->name
);
148 /* log warning only */
153 static int dispatch_assert(struct interface
*ifp
,
154 struct in_addr source_addr
,
155 struct in_addr group_addr
,
156 struct pim_assert_metric recv_metric
)
158 struct pim_ifchannel
*ch
;
160 ch
= pim_ifchannel_add(ifp
, source_addr
, group_addr
);
162 char source_str
[100];
164 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
165 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
166 zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s",
168 source_str
, group_str
, ifp
->name
);
172 switch (ch
->ifassert_state
) {
173 case PIM_IFASSERT_NOINFO
:
174 if (recv_metric
.rpt_bit_flag
) {
176 if_could_assert_do_a1(__PRETTY_FUNCTION__
, ch
);
180 if (inferior_assert(&ch
->ifassert_my_metric
, &recv_metric
)) {
181 if_could_assert_do_a1(__PRETTY_FUNCTION__
, ch
);
183 else if (acceptable_assert(&ch
->ifassert_my_metric
, &recv_metric
)) {
184 if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch
->flags
)) {
185 assert_action_a6(ch
, recv_metric
);
190 case PIM_IFASSERT_I_AM_WINNER
:
191 if (preferred_assert(ch
, &recv_metric
)) {
192 assert_action_a2(ch
, recv_metric
);
195 if (inferior_assert(&ch
->ifassert_my_metric
, &recv_metric
)) {
196 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
); /* a3 requirement */
197 assert_action_a3(ch
);
201 case PIM_IFASSERT_I_AM_LOSER
:
202 if (recv_metric
.ip_address
.s_addr
== ch
->ifassert_winner
.s_addr
) {
203 /* Assert from current winner */
205 if (cancel_assert(&recv_metric
)) {
206 assert_action_a5(ch
);
209 if (inferior_assert(&ch
->ifassert_my_metric
, &recv_metric
)) {
210 assert_action_a5(ch
);
212 else if (acceptable_assert(&ch
->ifassert_my_metric
, &recv_metric
)) {
213 if (!recv_metric
.rpt_bit_flag
) {
214 assert_action_a2(ch
, recv_metric
);
219 else if (preferred_assert(ch
, &recv_metric
)) {
220 assert_action_a2(ch
, recv_metric
);
225 char source_str
[100];
227 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
228 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
229 zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
231 source_str
, group_str
, ch
->ifassert_state
, ifp
->name
);
239 int pim_assert_recv(struct interface
*ifp
,
240 struct pim_neighbor
*neigh
,
241 struct in_addr src_addr
,
242 uint8_t *buf
, int buf_size
)
244 struct prefix msg_group_addr
;
245 struct prefix msg_source_addr
;
246 struct pim_assert_metric msg_metric
;
251 on_trace(__PRETTY_FUNCTION__
, ifp
, src_addr
);
254 curr_size
= buf_size
;
257 Parse assert group addr
259 offset
= pim_parse_addr_group (&msg_group_addr
, curr
, curr_size
);
262 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
263 zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
272 Parse assert source addr
274 offset
= pim_parse_addr_ucast (&msg_source_addr
, curr
, curr_size
);
277 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
278 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
286 if (curr_size
!= 8) {
288 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
289 zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s",
297 Parse assert metric preference
300 msg_metric
.metric_preference
= pim_read_uint32_host(curr
);
302 msg_metric
.rpt_bit_flag
= msg_metric
.metric_preference
& 0x80000000; /* save highest bit */
303 msg_metric
.metric_preference
&= ~0x80000000; /* clear highest bit */
308 Parse assert route metric
311 msg_metric
.route_metric
= pim_read_uint32_host(curr
);
313 if (PIM_DEBUG_PIM_TRACE
) {
315 char source_str
[100];
317 pim_inet4_dump("<neigh?>", src_addr
, neigh_str
, sizeof(neigh_str
));
318 pim_inet4_dump("<src?>", msg_source_addr
.u
.prefix4
, source_str
, sizeof(source_str
));
319 pim_inet4_dump("<grp?>", msg_group_addr
.u
.prefix4
, group_str
, sizeof(group_str
));
320 zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
321 __PRETTY_FUNCTION__
, neigh_str
, ifp
->name
,
322 source_str
, group_str
,
323 msg_metric
.metric_preference
,
324 msg_metric
.route_metric
,
325 PIM_FORCE_BOOLEAN(msg_metric
.rpt_bit_flag
));
328 msg_metric
.ip_address
= src_addr
;
330 return dispatch_assert(ifp
,
331 msg_source_addr
.u
.prefix4
,
332 msg_group_addr
.u
.prefix4
,
337 RFC 4601: 4.6.3. Assert Metrics
339 Assert metrics are defined as:
341 When comparing assert_metrics, the rpt_bit_flag, metric_preference,
342 and route_metric field are compared in order, where the first lower
343 value wins. If all fields are equal, the primary IP address of the
344 router that sourced the Assert message is used as a tie-breaker,
345 with the highest IP address winning.
347 int pim_assert_metric_better(const struct pim_assert_metric
*m1
,
348 const struct pim_assert_metric
*m2
)
350 if (m1
->rpt_bit_flag
< m2
->rpt_bit_flag
)
352 if (m1
->rpt_bit_flag
> m2
->rpt_bit_flag
)
355 if (m1
->metric_preference
< m2
->metric_preference
)
357 if (m1
->metric_preference
> m2
->metric_preference
)
360 if (m1
->route_metric
< m2
->route_metric
)
362 if (m1
->route_metric
> m2
->route_metric
)
365 return ntohl(m1
->ip_address
.s_addr
) > ntohl(m2
->ip_address
.s_addr
);
368 int pim_assert_metric_match(const struct pim_assert_metric
*m1
,
369 const struct pim_assert_metric
*m2
)
371 if (m1
->rpt_bit_flag
!= m2
->rpt_bit_flag
)
373 if (m1
->metric_preference
!= m2
->metric_preference
)
375 if (m1
->route_metric
!= m2
->route_metric
)
378 return m1
->ip_address
.s_addr
== m2
->ip_address
.s_addr
;
381 int pim_assert_build_msg(uint8_t *pim_msg
, int buf_size
,
382 struct interface
*ifp
,
383 struct in_addr group_addr
,
384 struct in_addr source_addr
,
385 uint32_t metric_preference
,
386 uint32_t route_metric
,
387 uint32_t rpt_bit_flag
)
389 uint8_t *buf_pastend
= pim_msg
+ buf_size
;
390 uint8_t *pim_msg_curr
;
394 pim_msg_curr
= pim_msg
+ PIM_MSG_HEADER_LEN
; /* skip room for pim header */
397 remain
= buf_pastend
- pim_msg_curr
;
398 pim_msg_curr
= pim_msg_addr_encode_ipv4_group(pim_msg_curr
,
403 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
404 zlog_warn("%s: failure encoding group address %s: space left=%d",
405 __PRETTY_FUNCTION__
, group_str
, remain
);
410 remain
= buf_pastend
- pim_msg_curr
;
411 pim_msg_curr
= pim_msg_addr_encode_ipv4_ucast(pim_msg_curr
,
415 char source_str
[100];
416 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
417 zlog_warn("%s: failure encoding source address %s: space left=%d",
418 __PRETTY_FUNCTION__
, source_str
, remain
);
422 /* Metric preference */
423 pim_write_uint32(pim_msg_curr
, rpt_bit_flag
?
424 metric_preference
| 0x80000000 :
429 pim_write_uint32(pim_msg_curr
, route_metric
);
435 pim_msg_size
= pim_msg_curr
- pim_msg
;
436 pim_msg_build_header(pim_msg
, pim_msg_size
,
437 PIM_MSG_TYPE_ASSERT
);
442 static int pim_assert_do(struct pim_ifchannel
*ch
,
443 struct pim_assert_metric metric
)
445 struct interface
*ifp
;
446 struct pim_interface
*pim_ifp
;
447 uint8_t pim_msg
[1000];
455 zlog_warn("%s: pim not enabled on interface: %s",
456 __PRETTY_FUNCTION__
, ifp
->name
);
460 pim_msg_size
= pim_assert_build_msg(pim_msg
, sizeof(pim_msg
), ifp
,
461 ch
->group_addr
, ch
->source_addr
,
462 metric
.metric_preference
,
464 metric
.rpt_bit_flag
);
465 if (pim_msg_size
< 1) {
466 zlog_warn("%s: failure building PIM assert message: msg_size=%d",
467 __PRETTY_FUNCTION__
, pim_msg_size
);
472 RFC 4601: 4.3.1. Sending Hello Messages
474 Thus, if a router needs to send a Join/Prune or Assert message on
475 an interface on which it has not yet sent a Hello message with the
476 currently configured IP address, then it MUST immediately send the
477 relevant Hello message without waiting for the Hello Timer to
478 expire, followed by the Join/Prune or Assert message.
480 pim_hello_require(ifp
);
482 if (PIM_DEBUG_PIM_TRACE
) {
483 char source_str
[100];
485 pim_inet4_dump("<src?>", ch
->source_addr
, source_str
, sizeof(source_str
));
486 pim_inet4_dump("<grp?>", ch
->group_addr
, group_str
, sizeof(group_str
));
487 zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
489 ifp
->name
, source_str
, group_str
,
490 metric
.metric_preference
,
492 PIM_FORCE_BOOLEAN(metric
.rpt_bit_flag
));
495 if (pim_msg_send(pim_ifp
->pim_sock_fd
,
496 qpim_all_pim_routers_addr
,
500 zlog_warn("%s: could not send PIM message on interface %s",
501 __PRETTY_FUNCTION__
, ifp
->name
);
508 int pim_assert_send(struct pim_ifchannel
*ch
)
510 return pim_assert_do(ch
, ch
->ifassert_my_metric
);
514 RFC 4601: 4.6.4. AssertCancel Messages
516 An AssertCancel(S,G) is an infinite metric assert with the RPT bit
517 set that names S as the source.
519 static int pim_assert_cancel(struct pim_ifchannel
*ch
)
521 struct pim_assert_metric metric
;
523 metric
.rpt_bit_flag
= 0;
524 metric
.metric_preference
= PIM_ASSERT_METRIC_PREFERENCE_MAX
;
525 metric
.route_metric
= PIM_ASSERT_ROUTE_METRIC_MAX
;
526 metric
.ip_address
= ch
->source_addr
;
528 return pim_assert_do(ch
, metric
);
531 static int on_assert_timer(struct thread
*t
)
533 struct pim_ifchannel
*ch
;
534 struct interface
*ifp
;
543 if (PIM_DEBUG_PIM_TRACE
) {
546 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
547 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
548 zlog_debug("%s: (S,G)=(%s,%s) timer expired on interface %s",
550 src_str
, grp_str
, ifp
->name
);
553 ch
->t_ifassert_timer
= 0;
555 switch (ch
->ifassert_state
) {
556 case PIM_IFASSERT_I_AM_WINNER
:
557 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
); /* a3 requirement */
558 assert_action_a3(ch
);
560 case PIM_IFASSERT_I_AM_LOSER
:
561 assert_action_a5(ch
);
565 char source_str
[100];
567 pim_inet4_dump("<src?>", ch
->source_addr
, source_str
, sizeof(source_str
));
568 pim_inet4_dump("<grp?>", ch
->group_addr
, group_str
, sizeof(group_str
));
569 zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
571 source_str
, group_str
, ch
->ifassert_state
, ifp
->name
);
578 static void assert_timer_off(struct pim_ifchannel
*ch
)
580 struct interface
*ifp
;
586 if (PIM_DEBUG_PIM_TRACE
) {
587 if (ch
->t_ifassert_timer
) {
590 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
591 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
592 zlog_debug("%s: (S,G)=(%s,%s) cancelling timer on interface %s",
594 src_str
, grp_str
, ifp
->name
);
597 THREAD_OFF(ch
->t_ifassert_timer
);
598 zassert(!ch
->t_ifassert_timer
);
601 static void pim_assert_timer_set(struct pim_ifchannel
*ch
,
604 struct interface
*ifp
;
610 assert_timer_off(ch
);
612 if (PIM_DEBUG_PIM_TRACE
) {
615 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
616 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
617 zlog_debug("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s",
619 src_str
, grp_str
, interval
, ifp
->name
);
622 THREAD_TIMER_ON(master
, ch
->t_ifassert_timer
,
627 static void pim_assert_timer_reset(struct pim_ifchannel
*ch
)
629 pim_assert_timer_set(ch
, PIM_ASSERT_TIME
- PIM_ASSERT_OVERRIDE_INTERVAL
);
633 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
635 (S,G) Assert State machine Actions
637 A1: Send Assert(S,G).
638 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
639 Store self as AssertWinner(S,G,I).
640 Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
642 int assert_action_a1(struct pim_ifchannel
*ch
)
644 struct interface
*ifp
= ch
->interface
;
645 struct pim_interface
*pim_ifp
;
653 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
654 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
655 zlog_warn("%s: (S,G)=(%s,%s) multicast not enabled on interface %s",
657 src_str
, grp_str
, ifp
->name
);
658 return -1; /* must return since pim_ifp is used below */
661 /* Switch to I_AM_WINNER before performing action_a3 below */
662 pim_ifassert_winner_set(ch
, PIM_IFASSERT_I_AM_WINNER
,
663 pim_ifp
->primary_address
,
664 pim_macro_spt_assert_metric(&ch
->upstream
->rpf
,
665 pim_ifp
->primary_address
));
667 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
); /* a3 requirement */
668 if (assert_action_a3(ch
)) {
671 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
672 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
673 zlog_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s",
675 src_str
, grp_str
, ifp
->name
);
679 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
);
685 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
687 (S,G) Assert State machine Actions
689 A2: Store new assert winner as AssertWinner(S,G,I) and assert
690 winner metric as AssertWinnerMetric(S,G,I).
691 Set Assert Timer to Assert_Time.
693 static void assert_action_a2(struct pim_ifchannel
*ch
,
694 struct pim_assert_metric winner_metric
)
696 pim_ifassert_winner_set(ch
, PIM_IFASSERT_I_AM_LOSER
,
697 winner_metric
.ip_address
,
700 pim_assert_timer_set(ch
, PIM_ASSERT_TIME
);
702 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
);
706 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
708 (S,G) Assert State machine Actions
710 A3: Send Assert(S,G).
711 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
713 static int assert_action_a3(struct pim_ifchannel
*ch
)
715 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
);
717 pim_assert_timer_reset(ch
);
719 if (pim_assert_send(ch
)) {
722 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
723 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
725 zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s",
727 src_str
, grp_str
, ch
->interface
->name
);
731 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_WINNER
);
737 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
739 (S,G) Assert State machine Actions
741 A4: Send AssertCancel(S,G).
742 Delete assert info (AssertWinner(S,G,I) and
743 AssertWinnerMetric(S,G,I) will then return their default
746 void assert_action_a4(struct pim_ifchannel
*ch
)
748 if (pim_assert_cancel(ch
)) {
751 pim_inet4_dump("<src?>", ch
->source_addr
, src_str
, sizeof(src_str
));
752 pim_inet4_dump("<grp?>", ch
->group_addr
, grp_str
, sizeof(grp_str
));
753 zlog_warn("%s: failure sending AssertCancel(%s,%s) on interface %s",
755 src_str
, grp_str
, ch
->interface
->name
);
756 /* log warning only */
759 assert_action_a5(ch
);
761 zassert(ch
->ifassert_state
== PIM_IFASSERT_NOINFO
);
765 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
767 (S,G) Assert State machine Actions
769 A5: Delete assert info (AssertWinner(S,G,I) and
770 AssertWinnerMetric(S,G,I) will then return their default values).
772 void assert_action_a5(struct pim_ifchannel
*ch
)
774 reset_ifassert_state(ch
);
775 zassert(ch
->ifassert_state
== PIM_IFASSERT_NOINFO
);
779 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
781 (S,G) Assert State machine Actions
783 A6: Store new assert winner as AssertWinner(S,G,I) and assert
784 winner metric as AssertWinnerMetric(S,G,I).
785 Set Assert Timer to Assert_Time.
786 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
787 set SPTbit(S,G) to TRUE.
789 static void assert_action_a6(struct pim_ifchannel
*ch
,
790 struct pim_assert_metric winner_metric
)
792 assert_action_a2(ch
, winner_metric
);
795 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
798 if (ch
->upstream
->rpf
.source_nexthop
.interface
== ch
->interface
)
799 if (ch
->upstream
->join_state
== PIM_UPSTREAM_JOINED
)
800 ch
->upstream
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
802 zassert(ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
);