]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_assert.c
pimd: Add debug messages as to why a register packet is rejected.
[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,
4df01a4e 477 pim_ifp->primary_address,
12e41d03
DL
478 qpim_all_pim_routers_addr,
479 pim_msg,
480 pim_msg_size,
481 ifp->name)) {
482 zlog_warn("%s: could not send PIM message on interface %s",
483 __PRETTY_FUNCTION__, ifp->name);
484 return -3;
485 }
486
487 return 0;
488}
489
490int pim_assert_send(struct pim_ifchannel *ch)
491{
492 return pim_assert_do(ch, ch->ifassert_my_metric);
493}
494
495/*
496 RFC 4601: 4.6.4. AssertCancel Messages
497
498 An AssertCancel(S,G) is an infinite metric assert with the RPT bit
499 set that names S as the source.
500 */
501static int pim_assert_cancel(struct pim_ifchannel *ch)
502{
503 struct pim_assert_metric metric;
504
505 metric.rpt_bit_flag = 0;
506 metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
507 metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
4ed0af70 508 metric.ip_address = ch->sg.src;
12e41d03
DL
509
510 return pim_assert_do(ch, metric);
511}
512
513static int on_assert_timer(struct thread *t)
514{
515 struct pim_ifchannel *ch;
516 struct interface *ifp;
517
518 zassert(t);
519 ch = THREAD_ARG(t);
520 zassert(ch);
521
522 ifp = ch->interface;
523 zassert(ifp);
524
525 if (PIM_DEBUG_PIM_TRACE) {
99064df9 526 zlog_debug("%s: (S,G)=%s timer expired on interface %s",
12e41d03 527 __PRETTY_FUNCTION__,
99064df9 528 pim_str_sg_dump (&ch->sg), ifp->name);
12e41d03
DL
529 }
530
59ba0ac3 531 ch->t_ifassert_timer = NULL;
12e41d03
DL
532
533 switch (ch->ifassert_state) {
534 case PIM_IFASSERT_I_AM_WINNER:
535 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
536 assert_action_a3(ch);
537 break;
538 case PIM_IFASSERT_I_AM_LOSER:
539 assert_action_a5(ch);
540 break;
541 default:
542 {
99064df9 543 zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
12e41d03 544 __PRETTY_FUNCTION__,
99064df9 545 pim_str_sg_dump (&ch->sg), ch->ifassert_state, ifp->name);
12e41d03
DL
546 }
547 }
548
549 return 0;
550}
551
552static void assert_timer_off(struct pim_ifchannel *ch)
553{
554 struct interface *ifp;
555
556 zassert(ch);
557 ifp = ch->interface;
558 zassert(ifp);
559
560 if (PIM_DEBUG_PIM_TRACE) {
561 if (ch->t_ifassert_timer) {
99064df9 562 zlog_debug("%s: (S,G)=%s cancelling timer on interface %s",
12e41d03 563 __PRETTY_FUNCTION__,
99064df9 564 pim_str_sg_dump (&ch->sg), ifp->name);
12e41d03
DL
565 }
566 }
567 THREAD_OFF(ch->t_ifassert_timer);
568 zassert(!ch->t_ifassert_timer);
569}
570
571static void pim_assert_timer_set(struct pim_ifchannel *ch,
572 int interval)
573{
574 struct interface *ifp;
575
576 zassert(ch);
577 ifp = ch->interface;
578 zassert(ifp);
579
580 assert_timer_off(ch);
581
582 if (PIM_DEBUG_PIM_TRACE) {
99064df9 583 zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
12e41d03 584 __PRETTY_FUNCTION__,
99064df9 585 pim_str_sg_dump(&ch->sg), interval, ifp->name);
12e41d03
DL
586 }
587
588 THREAD_TIMER_ON(master, ch->t_ifassert_timer,
589 on_assert_timer,
590 ch, interval);
591}
592
593static void pim_assert_timer_reset(struct pim_ifchannel *ch)
594{
595 pim_assert_timer_set(ch, PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
596}
597
598/*
599 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
600
601 (S,G) Assert State machine Actions
602
603 A1: Send Assert(S,G).
604 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
605 Store self as AssertWinner(S,G,I).
606 Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
607*/
608int assert_action_a1(struct pim_ifchannel *ch)
609{
610 struct interface *ifp = ch->interface;
611 struct pim_interface *pim_ifp;
612
613 zassert(ifp);
614
615 pim_ifp = ifp->info;
616 if (!pim_ifp) {
99064df9 617 zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
12e41d03 618 __PRETTY_FUNCTION__,
99064df9 619 pim_str_sg_dump (&ch->sg), ifp->name);
12e41d03
DL
620 return -1; /* must return since pim_ifp is used below */
621 }
622
623 /* Switch to I_AM_WINNER before performing action_a3 below */
624 pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_WINNER,
625 pim_ifp->primary_address,
626 pim_macro_spt_assert_metric(&ch->upstream->rpf,
627 pim_ifp->primary_address));
628
629 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
630 if (assert_action_a3(ch)) {
99064df9 631 zlog_warn("%s: (S,G)=%s assert_action_a3 failure on interface %s",
12e41d03 632 __PRETTY_FUNCTION__,
99064df9 633 pim_str_sg_dump (&ch->sg), ifp->name);
12e41d03
DL
634 /* warning only */
635 }
636
637 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
638
639 return 0;
640}
641
642/*
643 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
644
645 (S,G) Assert State machine Actions
646
647 A2: Store new assert winner as AssertWinner(S,G,I) and assert
648 winner metric as AssertWinnerMetric(S,G,I).
649 Set Assert Timer to Assert_Time.
650*/
651static void assert_action_a2(struct pim_ifchannel *ch,
652 struct pim_assert_metric winner_metric)
653{
654 pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
655 winner_metric.ip_address,
656 winner_metric);
657
658 pim_assert_timer_set(ch, PIM_ASSERT_TIME);
659
660 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
661}
662
663/*
664 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
665
666 (S,G) Assert State machine Actions
667
668 A3: Send Assert(S,G).
669 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
670*/
671static int assert_action_a3(struct pim_ifchannel *ch)
672{
673 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
674
675 pim_assert_timer_reset(ch);
676
677 if (pim_assert_send(ch)) {
99064df9 678 zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
12e41d03 679 __PRETTY_FUNCTION__,
99064df9 680 pim_str_sg_dump (&ch->sg), ch->interface->name);
12e41d03
DL
681 return -1;
682 }
683
684 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
685
686 return 0;
687}
688
689/*
690 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
691
692 (S,G) Assert State machine Actions
693
694 A4: Send AssertCancel(S,G).
695 Delete assert info (AssertWinner(S,G,I) and
696 AssertWinnerMetric(S,G,I) will then return their default
697 values).
698*/
699void assert_action_a4(struct pim_ifchannel *ch)
700{
701 if (pim_assert_cancel(ch)) {
99064df9 702 zlog_warn("%s: failure sending AssertCancel%s on interface %s",
12e41d03 703 __PRETTY_FUNCTION__,
99064df9 704 pim_str_sg_dump (&ch->sg), ch->interface->name);
12e41d03
DL
705 /* log warning only */
706 }
707
708 assert_action_a5(ch);
709
710 zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
711}
712
713/*
714 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
715
716 (S,G) Assert State machine Actions
717
718 A5: Delete assert info (AssertWinner(S,G,I) and
719 AssertWinnerMetric(S,G,I) will then return their default values).
720*/
721void assert_action_a5(struct pim_ifchannel *ch)
722{
723 reset_ifassert_state(ch);
724 zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
725}
726
727/*
728 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
729
730 (S,G) Assert State machine Actions
731
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.
737*/
738static void assert_action_a6(struct pim_ifchannel *ch,
739 struct pim_assert_metric winner_metric)
740{
741 assert_action_a2(ch, winner_metric);
742
743 /*
744 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
745 SPTbit(S,G) to TRUE.
12e41d03 746 */
d99764f6
DS
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;
12e41d03
DL
750
751 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
752}
753