]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_assert.c
lib, pimd: Fix borked up prefix code
[mirror_frr.git] / pimd / pim_assert.c
CommitLineData
12e41d03
DL
1/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
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.
9
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.
14
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,
18 MA 02110-1301 USA
19
12e41d03
DL
20*/
21
22#include <zebra.h>
23
24#include "log.h"
25#include "prefix.h"
744d91b3 26#include "if.h"
12e41d03
DL
27
28#include "pimd.h"
29#include "pim_str.h"
30#include "pim_tlv.h"
31#include "pim_msg.h"
32#include "pim_pim.h"
33#include "pim_int.h"
34#include "pim_time.h"
35#include "pim_iface.h"
36#include "pim_hello.h"
37#include "pim_macro.h"
38#include "pim_assert.h"
39#include "pim_ifchannel.h"
40
41static int assert_action_a3(struct pim_ifchannel *ch);
42static void assert_action_a2(struct pim_ifchannel *ch,
43 struct pim_assert_metric winner_metric);
44static void assert_action_a6(struct pim_ifchannel *ch,
45 struct pim_assert_metric winner_metric);
46
47void pim_ifassert_winner_set(struct pim_ifchannel *ch,
48 enum pim_ifassert_state new_state,
49 struct in_addr winner,
50 struct pim_assert_metric winner_metric)
51{
52 int winner_changed = (ch->ifassert_winner.s_addr != winner.s_addr);
53 int metric_changed = !pim_assert_metric_match(&ch->ifassert_winner_metric,
54 &winner_metric);
55
56 if (PIM_DEBUG_PIM_EVENTS) {
57 if (ch->ifassert_state != new_state) {
99064df9
DS
58 zlog_debug("%s: (S,G)=%s assert state changed from %s to %s on interface %s",
59 __PRETTY_FUNCTION__,
60 pim_str_sg_dump (&ch->sg),
61 pim_ifchannel_ifassert_name(ch->ifassert_state),
62 pim_ifchannel_ifassert_name(new_state),
63 ch->interface->name);
12e41d03
DL
64 }
65
66 if (winner_changed) {
12e41d03
DL
67 char was_str[100];
68 char winner_str[100];
12e41d03
DL
69 pim_inet4_dump("<was?>", ch->ifassert_winner, was_str, sizeof(was_str));
70 pim_inet4_dump("<winner?>", winner, winner_str, sizeof(winner_str));
99064df9
DS
71 zlog_debug("%s: (S,G)=%s assert winner changed from %s to %s on interface %s",
72 __PRETTY_FUNCTION__,
73 pim_str_sg_dump (&ch->sg),
74 was_str, winner_str, ch->interface->name);
12e41d03
DL
75 }
76 } /* PIM_DEBUG_PIM_EVENTS */
77
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();
82
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);
87 }
88}
89
90static void on_trace(const char *label,
91 struct interface *ifp, struct in_addr src)
92{
93 if (PIM_DEBUG_PIM_TRACE) {
94 char src_str[100];
95 pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
96 zlog_debug("%s: from %s on %s",
97 label, src_str, ifp->name);
98 }
99}
100
101static int preferred_assert(const struct pim_ifchannel *ch,
102 const struct pim_assert_metric *recv_metric)
103{
104 return pim_assert_metric_better(recv_metric,
105 &ch->ifassert_winner_metric);
106}
107
108static int acceptable_assert(const struct pim_assert_metric *my_metric,
109 const struct pim_assert_metric *recv_metric)
110{
111 return pim_assert_metric_better(recv_metric,
112 my_metric);
113}
114
115static int inferior_assert(const struct pim_assert_metric *my_metric,
116 const struct pim_assert_metric *recv_metric)
117{
118 return pim_assert_metric_better(my_metric,
119 recv_metric);
120}
121
122static int cancel_assert(const struct pim_assert_metric *recv_metric)
123{
124 return (recv_metric->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX)
125 &&
126 (recv_metric->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX);
127}
128
129static void if_could_assert_do_a1(const char *caller,
130 struct pim_ifchannel *ch)
131{
132 if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
133 if (assert_action_a1(ch)) {
99064df9 134 zlog_warn("%s: %s: (S,G)=%s assert_action_a1 failure on interface %s",
12e41d03 135 __PRETTY_FUNCTION__, caller,
99064df9 136 pim_str_sg_dump (&ch->sg), ch->interface->name);
12e41d03
DL
137 /* log warning only */
138 }
139 }
140}
141
142static int dispatch_assert(struct interface *ifp,
143 struct in_addr source_addr,
144 struct in_addr group_addr,
145 struct pim_assert_metric recv_metric)
146{
147 struct pim_ifchannel *ch;
4ed0af70 148 struct prefix_sg sg;
12e41d03 149
4ed0af70
DS
150 memset (&sg, 0, sizeof (struct prefix_sg));
151 sg.src = source_addr;
152 sg.grp = group_addr;
5074a423 153 ch = pim_ifchannel_add(ifp, &sg);
12e41d03 154 if (!ch) {
5074a423 155 zlog_warn("%s: (S,G)=%s failure creating channel on interface %s",
12e41d03 156 __PRETTY_FUNCTION__,
5074a423 157 pim_str_sg_dump (&sg), ifp->name);
12e41d03
DL
158 return -1;
159 }
160
161 switch (ch->ifassert_state) {
162 case PIM_IFASSERT_NOINFO:
163 if (recv_metric.rpt_bit_flag) {
164 /* RPT bit set */
165 if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
166 }
167 else {
168 /* RPT bit clear */
169 if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
170 if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
171 }
172 else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) {
173 if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)) {
174 assert_action_a6(ch, recv_metric);
175 }
176 }
177 }
178 break;
179 case PIM_IFASSERT_I_AM_WINNER:
180 if (preferred_assert(ch, &recv_metric)) {
181 assert_action_a2(ch, recv_metric);
182 }
183 else {
184 if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
185 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
186 assert_action_a3(ch);
187 }
188 }
189 break;
190 case PIM_IFASSERT_I_AM_LOSER:
191 if (recv_metric.ip_address.s_addr == ch->ifassert_winner.s_addr) {
192 /* Assert from current winner */
193
194 if (cancel_assert(&recv_metric)) {
195 assert_action_a5(ch);
196 }
197 else {
198 if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
199 assert_action_a5(ch);
200 }
201 else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) {
202 if (!recv_metric.rpt_bit_flag) {
203 assert_action_a2(ch, recv_metric);
204 }
205 }
206 }
207 }
208 else if (preferred_assert(ch, &recv_metric)) {
209 assert_action_a2(ch, recv_metric);
210 }
211 break;
212 default:
213 {
5074a423 214 zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
12e41d03 215 __PRETTY_FUNCTION__,
5074a423 216 pim_str_sg_dump (&sg), ch->ifassert_state, ifp->name);
12e41d03
DL
217 }
218 return -2;
219 }
220
221 return 0;
222}
223
224int pim_assert_recv(struct interface *ifp,
225 struct pim_neighbor *neigh,
226 struct in_addr src_addr,
227 uint8_t *buf, int buf_size)
228{
229 struct prefix msg_group_addr;
230 struct prefix msg_source_addr;
231 struct pim_assert_metric msg_metric;
232 int offset;
233 uint8_t *curr;
234 int curr_size;
235
236 on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
237
238 curr = buf;
239 curr_size = buf_size;
240
241 /*
242 Parse assert group addr
243 */
4416b1f6 244 offset = pim_parse_addr_group (&msg_group_addr, curr, curr_size);
12e41d03
DL
245 if (offset < 1) {
246 char src_str[100];
247 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
248 zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
249 __PRETTY_FUNCTION__,
250 src_str, ifp->name);
251 return -1;
252 }
253 curr += offset;
254 curr_size -= offset;
255
256 /*
257 Parse assert source addr
258 */
4416b1f6 259 offset = pim_parse_addr_ucast (&msg_source_addr, curr, curr_size);
12e41d03
DL
260 if (offset < 1) {
261 char src_str[100];
262 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
263 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
264 __PRETTY_FUNCTION__,
265 src_str, ifp->name);
266 return -2;
267 }
268 curr += offset;
269 curr_size -= offset;
270
271 if (curr_size != 8) {
272 char src_str[100];
273 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
274 zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s",
275 __PRETTY_FUNCTION__,
276 curr_size,
277 src_str, ifp->name);
278 return -3;
279 }
280
281 /*
282 Parse assert metric preference
283 */
284
285 msg_metric.metric_preference = pim_read_uint32_host(curr);
286
287 msg_metric.rpt_bit_flag = msg_metric.metric_preference & 0x80000000; /* save highest bit */
288 msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */
289
290 curr += 4;
291
292 /*
293 Parse assert route metric
294 */
295
296 msg_metric.route_metric = pim_read_uint32_host(curr);
297
298 if (PIM_DEBUG_PIM_TRACE) {
299 char neigh_str[100];
300 char source_str[100];
301 char group_str[100];
302 pim_inet4_dump("<neigh?>", src_addr, neigh_str, sizeof(neigh_str));
303 pim_inet4_dump("<src?>", msg_source_addr.u.prefix4, source_str, sizeof(source_str));
304 pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4, group_str, sizeof(group_str));
305 zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
306 __PRETTY_FUNCTION__, neigh_str, ifp->name,
307 source_str, group_str,
308 msg_metric.metric_preference,
309 msg_metric.route_metric,
310 PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag));
311 }
312
313 msg_metric.ip_address = src_addr;
314
315 return dispatch_assert(ifp,
316 msg_source_addr.u.prefix4,
317 msg_group_addr.u.prefix4,
318 msg_metric);
319}
320
321/*
322 RFC 4601: 4.6.3. Assert Metrics
323
324 Assert metrics are defined as:
325
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.
331*/
332int pim_assert_metric_better(const struct pim_assert_metric *m1,
333 const struct pim_assert_metric *m2)
334{
335 if (m1->rpt_bit_flag < m2->rpt_bit_flag)
336 return 1;
337 if (m1->rpt_bit_flag > m2->rpt_bit_flag)
338 return 0;
339
340 if (m1->metric_preference < m2->metric_preference)
341 return 1;
342 if (m1->metric_preference > m2->metric_preference)
343 return 0;
344
345 if (m1->route_metric < m2->route_metric)
346 return 1;
347 if (m1->route_metric > m2->route_metric)
348 return 0;
349
350 return ntohl(m1->ip_address.s_addr) > ntohl(m2->ip_address.s_addr);
351}
352
353int pim_assert_metric_match(const struct pim_assert_metric *m1,
354 const struct pim_assert_metric *m2)
355{
356 if (m1->rpt_bit_flag != m2->rpt_bit_flag)
357 return 0;
358 if (m1->metric_preference != m2->metric_preference)
359 return 0;
360 if (m1->route_metric != m2->route_metric)
361 return 0;
362
363 return m1->ip_address.s_addr == m2->ip_address.s_addr;
364}
365
366int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
367 struct interface *ifp,
368 struct in_addr group_addr,
369 struct in_addr source_addr,
370 uint32_t metric_preference,
371 uint32_t route_metric,
372 uint32_t rpt_bit_flag)
373{
374 uint8_t *buf_pastend = pim_msg + buf_size;
375 uint8_t *pim_msg_curr;
376 int pim_msg_size;
377 int remain;
378
379 pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */
380
381 /* Encode group */
382 remain = buf_pastend - pim_msg_curr;
383 pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
384 remain,
385 group_addr);
386 if (!pim_msg_curr) {
387 char group_str[100];
388 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
389 zlog_warn("%s: failure encoding group address %s: space left=%d",
390 __PRETTY_FUNCTION__, group_str, remain);
391 return -1;
392 }
393
394 /* Encode source */
395 remain = buf_pastend - pim_msg_curr;
396 pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
397 remain,
398 source_addr);
399 if (!pim_msg_curr) {
400 char source_str[100];
401 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
402 zlog_warn("%s: failure encoding source address %s: space left=%d",
403 __PRETTY_FUNCTION__, source_str, remain);
404 return -2;
405 }
406
407 /* Metric preference */
408 pim_write_uint32(pim_msg_curr, rpt_bit_flag ?
409 metric_preference | 0x80000000 :
410 metric_preference);
411 pim_msg_curr += 4;
412
413 /* Route metric */
414 pim_write_uint32(pim_msg_curr, route_metric);
415 pim_msg_curr += 4;
416
417 /*
418 Add PIM header
419 */
420 pim_msg_size = pim_msg_curr - pim_msg;
421 pim_msg_build_header(pim_msg, pim_msg_size,
422 PIM_MSG_TYPE_ASSERT);
423
424 return pim_msg_size;
425}
426
427static int pim_assert_do(struct pim_ifchannel *ch,
428 struct pim_assert_metric metric)
429{
430 struct interface *ifp;
431 struct pim_interface *pim_ifp;
432 uint8_t pim_msg[1000];
433 int pim_msg_size;
434
435 ifp = ch->interface;
436 zassert(ifp);
437
438 pim_ifp = ifp->info;
439 if (!pim_ifp) {
440 zlog_warn("%s: pim not enabled on interface: %s",
441 __PRETTY_FUNCTION__, ifp->name);
442 return -1;
443 }
444
445 pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp,
4ed0af70 446 ch->sg.grp, ch->sg.src,
12e41d03
DL
447 metric.metric_preference,
448 metric.route_metric,
449 metric.rpt_bit_flag);
450 if (pim_msg_size < 1) {
451 zlog_warn("%s: failure building PIM assert message: msg_size=%d",
452 __PRETTY_FUNCTION__, pim_msg_size);
453 return -2;
454 }
455
456 /*
457 RFC 4601: 4.3.1. Sending Hello Messages
458
459 Thus, if a router needs to send a Join/Prune or Assert message on
460 an interface on which it has not yet sent a Hello message with the
461 currently configured IP address, then it MUST immediately send the
462 relevant Hello message without waiting for the Hello Timer to
463 expire, followed by the Join/Prune or Assert message.
464 */
465 pim_hello_require(ifp);
466
467 if (PIM_DEBUG_PIM_TRACE) {
99064df9 468 zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
12e41d03 469 __PRETTY_FUNCTION__,
99064df9 470 ifp->name, pim_str_sg_dump (&ch->sg),
12e41d03
DL
471 metric.metric_preference,
472 metric.route_metric,
473 PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
474 }
475
476 if (pim_msg_send(pim_ifp->pim_sock_fd,
477 qpim_all_pim_routers_addr,
478 pim_msg,
479 pim_msg_size,
480 ifp->name)) {
481 zlog_warn("%s: could not send PIM message on interface %s",
482 __PRETTY_FUNCTION__, ifp->name);
483 return -3;
484 }
485
486 return 0;
487}
488
489int pim_assert_send(struct pim_ifchannel *ch)
490{
491 return pim_assert_do(ch, ch->ifassert_my_metric);
492}
493
494/*
495 RFC 4601: 4.6.4. AssertCancel Messages
496
497 An AssertCancel(S,G) is an infinite metric assert with the RPT bit
498 set that names S as the source.
499 */
500static int pim_assert_cancel(struct pim_ifchannel *ch)
501{
502 struct pim_assert_metric metric;
503
504 metric.rpt_bit_flag = 0;
505 metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
506 metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
4ed0af70 507 metric.ip_address = ch->sg.src;
12e41d03
DL
508
509 return pim_assert_do(ch, metric);
510}
511
512static int on_assert_timer(struct thread *t)
513{
514 struct pim_ifchannel *ch;
515 struct interface *ifp;
516
517 zassert(t);
518 ch = THREAD_ARG(t);
519 zassert(ch);
520
521 ifp = ch->interface;
522 zassert(ifp);
523
524 if (PIM_DEBUG_PIM_TRACE) {
99064df9 525 zlog_debug("%s: (S,G)=%s timer expired on interface %s",
12e41d03 526 __PRETTY_FUNCTION__,
99064df9 527 pim_str_sg_dump (&ch->sg), ifp->name);
12e41d03
DL
528 }
529
59ba0ac3 530 ch->t_ifassert_timer = NULL;
12e41d03
DL
531
532 switch (ch->ifassert_state) {
533 case PIM_IFASSERT_I_AM_WINNER:
534 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
535 assert_action_a3(ch);
536 break;
537 case PIM_IFASSERT_I_AM_LOSER:
538 assert_action_a5(ch);
539 break;
540 default:
541 {
99064df9 542 zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
12e41d03 543 __PRETTY_FUNCTION__,
99064df9 544 pim_str_sg_dump (&ch->sg), ch->ifassert_state, ifp->name);
12e41d03
DL
545 }
546 }
547
548 return 0;
549}
550
551static void assert_timer_off(struct pim_ifchannel *ch)
552{
553 struct interface *ifp;
554
555 zassert(ch);
556 ifp = ch->interface;
557 zassert(ifp);
558
559 if (PIM_DEBUG_PIM_TRACE) {
560 if (ch->t_ifassert_timer) {
99064df9 561 zlog_debug("%s: (S,G)=%s cancelling timer on interface %s",
12e41d03 562 __PRETTY_FUNCTION__,
99064df9 563 pim_str_sg_dump (&ch->sg), ifp->name);
12e41d03
DL
564 }
565 }
566 THREAD_OFF(ch->t_ifassert_timer);
567 zassert(!ch->t_ifassert_timer);
568}
569
570static void pim_assert_timer_set(struct pim_ifchannel *ch,
571 int interval)
572{
573 struct interface *ifp;
574
575 zassert(ch);
576 ifp = ch->interface;
577 zassert(ifp);
578
579 assert_timer_off(ch);
580
581 if (PIM_DEBUG_PIM_TRACE) {
99064df9 582 zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
12e41d03 583 __PRETTY_FUNCTION__,
99064df9 584 pim_str_sg_dump(&ch->sg), interval, ifp->name);
12e41d03
DL
585 }
586
587 THREAD_TIMER_ON(master, ch->t_ifassert_timer,
588 on_assert_timer,
589 ch, interval);
590}
591
592static void pim_assert_timer_reset(struct pim_ifchannel *ch)
593{
594 pim_assert_timer_set(ch, PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
595}
596
597/*
598 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
599
600 (S,G) Assert State machine Actions
601
602 A1: Send Assert(S,G).
603 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
604 Store self as AssertWinner(S,G,I).
605 Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
606*/
607int assert_action_a1(struct pim_ifchannel *ch)
608{
609 struct interface *ifp = ch->interface;
610 struct pim_interface *pim_ifp;
611
612 zassert(ifp);
613
614 pim_ifp = ifp->info;
615 if (!pim_ifp) {
99064df9 616 zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
12e41d03 617 __PRETTY_FUNCTION__,
99064df9 618 pim_str_sg_dump (&ch->sg), ifp->name);
12e41d03
DL
619 return -1; /* must return since pim_ifp is used below */
620 }
621
622 /* Switch to I_AM_WINNER before performing action_a3 below */
623 pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_WINNER,
624 pim_ifp->primary_address,
625 pim_macro_spt_assert_metric(&ch->upstream->rpf,
626 pim_ifp->primary_address));
627
628 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
629 if (assert_action_a3(ch)) {
99064df9 630 zlog_warn("%s: (S,G)=%s assert_action_a3 failure on interface %s",
12e41d03 631 __PRETTY_FUNCTION__,
99064df9 632 pim_str_sg_dump (&ch->sg), ifp->name);
12e41d03
DL
633 /* warning only */
634 }
635
636 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
637
638 return 0;
639}
640
641/*
642 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
643
644 (S,G) Assert State machine Actions
645
646 A2: Store new assert winner as AssertWinner(S,G,I) and assert
647 winner metric as AssertWinnerMetric(S,G,I).
648 Set Assert Timer to Assert_Time.
649*/
650static void assert_action_a2(struct pim_ifchannel *ch,
651 struct pim_assert_metric winner_metric)
652{
653 pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
654 winner_metric.ip_address,
655 winner_metric);
656
657 pim_assert_timer_set(ch, PIM_ASSERT_TIME);
658
659 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
660}
661
662/*
663 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
664
665 (S,G) Assert State machine Actions
666
667 A3: Send Assert(S,G).
668 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
669*/
670static int assert_action_a3(struct pim_ifchannel *ch)
671{
672 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
673
674 pim_assert_timer_reset(ch);
675
676 if (pim_assert_send(ch)) {
99064df9 677 zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
12e41d03 678 __PRETTY_FUNCTION__,
99064df9 679 pim_str_sg_dump (&ch->sg), ch->interface->name);
12e41d03
DL
680 return -1;
681 }
682
683 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
684
685 return 0;
686}
687
688/*
689 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
690
691 (S,G) Assert State machine Actions
692
693 A4: Send AssertCancel(S,G).
694 Delete assert info (AssertWinner(S,G,I) and
695 AssertWinnerMetric(S,G,I) will then return their default
696 values).
697*/
698void assert_action_a4(struct pim_ifchannel *ch)
699{
700 if (pim_assert_cancel(ch)) {
99064df9 701 zlog_warn("%s: failure sending AssertCancel%s on interface %s",
12e41d03 702 __PRETTY_FUNCTION__,
99064df9 703 pim_str_sg_dump (&ch->sg), ch->interface->name);
12e41d03
DL
704 /* log warning only */
705 }
706
707 assert_action_a5(ch);
708
709 zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
710}
711
712/*
713 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
714
715 (S,G) Assert State machine Actions
716
717 A5: Delete assert info (AssertWinner(S,G,I) and
718 AssertWinnerMetric(S,G,I) will then return their default values).
719*/
720void assert_action_a5(struct pim_ifchannel *ch)
721{
722 reset_ifassert_state(ch);
723 zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
724}
725
726/*
727 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
728
729 (S,G) Assert State machine Actions
730
731 A6: Store new assert winner as AssertWinner(S,G,I) and assert
732 winner metric as AssertWinnerMetric(S,G,I).
733 Set Assert Timer to Assert_Time.
734 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
735 set SPTbit(S,G) to TRUE.
736*/
737static void assert_action_a6(struct pim_ifchannel *ch,
738 struct pim_assert_metric winner_metric)
739{
740 assert_action_a2(ch, winner_metric);
741
742 /*
743 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
744 SPTbit(S,G) to TRUE.
12e41d03 745 */
d99764f6
DS
746 if (ch->upstream->rpf.source_nexthop.interface == ch->interface)
747 if (ch->upstream->join_state == PIM_UPSTREAM_JOINED)
748 ch->upstream->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
12e41d03
DL
749
750 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
751}
752