]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_assert.c
build: remove $Format tags
[mirror_frr.git] / pimd / pim_assert.c
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 */
20
21 #include <zebra.h>
22
23 #include "log.h"
24 #include "prefix.h"
25 #include "if.h"
26
27 #include "pimd.h"
28 #include "pim_str.h"
29 #include "pim_tlv.h"
30 #include "pim_msg.h"
31 #include "pim_pim.h"
32 #include "pim_int.h"
33 #include "pim_time.h"
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"
39
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);
45
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)
50 {
51 int winner_changed = (ch->ifassert_winner.s_addr != winner.s_addr);
52 int metric_changed = !pim_assert_metric_match(&ch->ifassert_winner_metric,
53 &winner_metric);
54
55 if (PIM_DEBUG_PIM_EVENTS) {
56 if (ch->ifassert_state != new_state) {
57 char src_str[100];
58 char grp_str[100];
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",
62 __PRETTY_FUNCTION__,
63 src_str, grp_str,
64 pim_ifchannel_ifassert_name(ch->ifassert_state),
65 pim_ifchannel_ifassert_name(new_state),
66 ch->interface->name);
67 }
68
69 if (winner_changed) {
70 char src_str[100];
71 char grp_str[100];
72 char was_str[100];
73 char winner_str[100];
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",
79 __PRETTY_FUNCTION__,
80 src_str, grp_str,
81 was_str, winner_str, ch->interface->name);
82 }
83 } /* PIM_DEBUG_PIM_EVENTS */
84
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();
89
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);
94 }
95 }
96
97 static void on_trace(const char *label,
98 struct interface *ifp, struct in_addr src)
99 {
100 if (PIM_DEBUG_PIM_TRACE) {
101 char src_str[100];
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);
105 }
106 }
107
108 static int preferred_assert(const struct pim_ifchannel *ch,
109 const struct pim_assert_metric *recv_metric)
110 {
111 return pim_assert_metric_better(recv_metric,
112 &ch->ifassert_winner_metric);
113 }
114
115 static int acceptable_assert(const struct pim_assert_metric *my_metric,
116 const struct pim_assert_metric *recv_metric)
117 {
118 return pim_assert_metric_better(recv_metric,
119 my_metric);
120 }
121
122 static int inferior_assert(const struct pim_assert_metric *my_metric,
123 const struct pim_assert_metric *recv_metric)
124 {
125 return pim_assert_metric_better(my_metric,
126 recv_metric);
127 }
128
129 static int cancel_assert(const struct pim_assert_metric *recv_metric)
130 {
131 return (recv_metric->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX)
132 &&
133 (recv_metric->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX);
134 }
135
136 static void if_could_assert_do_a1(const char *caller,
137 struct pim_ifchannel *ch)
138 {
139 if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
140 if (assert_action_a1(ch)) {
141 char src_str[100];
142 char grp_str[100];
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 */
149 }
150 }
151 }
152
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)
157 {
158 struct pim_ifchannel *ch;
159
160 ch = pim_ifchannel_add(ifp, source_addr, group_addr);
161 if (!ch) {
162 char source_str[100];
163 char group_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",
167 __PRETTY_FUNCTION__,
168 source_str, group_str, ifp->name);
169 return -1;
170 }
171
172 switch (ch->ifassert_state) {
173 case PIM_IFASSERT_NOINFO:
174 if (recv_metric.rpt_bit_flag) {
175 /* RPT bit set */
176 if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
177 }
178 else {
179 /* RPT bit clear */
180 if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
181 if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
182 }
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);
186 }
187 }
188 }
189 break;
190 case PIM_IFASSERT_I_AM_WINNER:
191 if (preferred_assert(ch, &recv_metric)) {
192 assert_action_a2(ch, recv_metric);
193 }
194 else {
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);
198 }
199 }
200 break;
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 */
204
205 if (cancel_assert(&recv_metric)) {
206 assert_action_a5(ch);
207 }
208 else {
209 if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
210 assert_action_a5(ch);
211 }
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);
215 }
216 }
217 }
218 }
219 else if (preferred_assert(ch, &recv_metric)) {
220 assert_action_a2(ch, recv_metric);
221 }
222 break;
223 default:
224 {
225 char source_str[100];
226 char group_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",
230 __PRETTY_FUNCTION__,
231 source_str, group_str, ch->ifassert_state, ifp->name);
232 }
233 return -2;
234 }
235
236 return 0;
237 }
238
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)
243 {
244 struct prefix msg_group_addr;
245 struct prefix msg_source_addr;
246 struct pim_assert_metric msg_metric;
247 int offset;
248 uint8_t *curr;
249 int curr_size;
250
251 on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
252
253 curr = buf;
254 curr_size = buf_size;
255
256 /*
257 Parse assert group addr
258 */
259 offset = pim_parse_addr_group (&msg_group_addr, curr, curr_size);
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_group() failure: from %s on %s",
264 __PRETTY_FUNCTION__,
265 src_str, ifp->name);
266 return -1;
267 }
268 curr += offset;
269 curr_size -= offset;
270
271 /*
272 Parse assert source addr
273 */
274 offset = pim_parse_addr_ucast (&msg_source_addr, curr, curr_size);
275 if (offset < 1) {
276 char src_str[100];
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",
279 __PRETTY_FUNCTION__,
280 src_str, ifp->name);
281 return -2;
282 }
283 curr += offset;
284 curr_size -= offset;
285
286 if (curr_size != 8) {
287 char src_str[100];
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",
290 __PRETTY_FUNCTION__,
291 curr_size,
292 src_str, ifp->name);
293 return -3;
294 }
295
296 /*
297 Parse assert metric preference
298 */
299
300 msg_metric.metric_preference = pim_read_uint32_host(curr);
301
302 msg_metric.rpt_bit_flag = msg_metric.metric_preference & 0x80000000; /* save highest bit */
303 msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */
304
305 curr += 4;
306
307 /*
308 Parse assert route metric
309 */
310
311 msg_metric.route_metric = pim_read_uint32_host(curr);
312
313 if (PIM_DEBUG_PIM_TRACE) {
314 char neigh_str[100];
315 char source_str[100];
316 char group_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));
326 }
327
328 msg_metric.ip_address = src_addr;
329
330 return dispatch_assert(ifp,
331 msg_source_addr.u.prefix4,
332 msg_group_addr.u.prefix4,
333 msg_metric);
334 }
335
336 /*
337 RFC 4601: 4.6.3. Assert Metrics
338
339 Assert metrics are defined as:
340
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.
346 */
347 int pim_assert_metric_better(const struct pim_assert_metric *m1,
348 const struct pim_assert_metric *m2)
349 {
350 if (m1->rpt_bit_flag < m2->rpt_bit_flag)
351 return 1;
352 if (m1->rpt_bit_flag > m2->rpt_bit_flag)
353 return 0;
354
355 if (m1->metric_preference < m2->metric_preference)
356 return 1;
357 if (m1->metric_preference > m2->metric_preference)
358 return 0;
359
360 if (m1->route_metric < m2->route_metric)
361 return 1;
362 if (m1->route_metric > m2->route_metric)
363 return 0;
364
365 return ntohl(m1->ip_address.s_addr) > ntohl(m2->ip_address.s_addr);
366 }
367
368 int pim_assert_metric_match(const struct pim_assert_metric *m1,
369 const struct pim_assert_metric *m2)
370 {
371 if (m1->rpt_bit_flag != m2->rpt_bit_flag)
372 return 0;
373 if (m1->metric_preference != m2->metric_preference)
374 return 0;
375 if (m1->route_metric != m2->route_metric)
376 return 0;
377
378 return m1->ip_address.s_addr == m2->ip_address.s_addr;
379 }
380
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)
388 {
389 uint8_t *buf_pastend = pim_msg + buf_size;
390 uint8_t *pim_msg_curr;
391 int pim_msg_size;
392 int remain;
393
394 pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */
395
396 /* Encode group */
397 remain = buf_pastend - pim_msg_curr;
398 pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
399 remain,
400 group_addr);
401 if (!pim_msg_curr) {
402 char group_str[100];
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);
406 return -1;
407 }
408
409 /* Encode source */
410 remain = buf_pastend - pim_msg_curr;
411 pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
412 remain,
413 source_addr);
414 if (!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);
419 return -2;
420 }
421
422 /* Metric preference */
423 pim_write_uint32(pim_msg_curr, rpt_bit_flag ?
424 metric_preference | 0x80000000 :
425 metric_preference);
426 pim_msg_curr += 4;
427
428 /* Route metric */
429 pim_write_uint32(pim_msg_curr, route_metric);
430 pim_msg_curr += 4;
431
432 /*
433 Add PIM header
434 */
435 pim_msg_size = pim_msg_curr - pim_msg;
436 pim_msg_build_header(pim_msg, pim_msg_size,
437 PIM_MSG_TYPE_ASSERT);
438
439 return pim_msg_size;
440 }
441
442 static int pim_assert_do(struct pim_ifchannel *ch,
443 struct pim_assert_metric metric)
444 {
445 struct interface *ifp;
446 struct pim_interface *pim_ifp;
447 uint8_t pim_msg[1000];
448 int pim_msg_size;
449
450 ifp = ch->interface;
451 zassert(ifp);
452
453 pim_ifp = ifp->info;
454 if (!pim_ifp) {
455 zlog_warn("%s: pim not enabled on interface: %s",
456 __PRETTY_FUNCTION__, ifp->name);
457 return -1;
458 }
459
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,
463 metric.route_metric,
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);
468 return -2;
469 }
470
471 /*
472 RFC 4601: 4.3.1. Sending Hello Messages
473
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.
479 */
480 pim_hello_require(ifp);
481
482 if (PIM_DEBUG_PIM_TRACE) {
483 char source_str[100];
484 char group_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",
488 __PRETTY_FUNCTION__,
489 ifp->name, source_str, group_str,
490 metric.metric_preference,
491 metric.route_metric,
492 PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
493 }
494
495 if (pim_msg_send(pim_ifp->pim_sock_fd,
496 qpim_all_pim_routers_addr,
497 pim_msg,
498 pim_msg_size,
499 ifp->name)) {
500 zlog_warn("%s: could not send PIM message on interface %s",
501 __PRETTY_FUNCTION__, ifp->name);
502 return -3;
503 }
504
505 return 0;
506 }
507
508 int pim_assert_send(struct pim_ifchannel *ch)
509 {
510 return pim_assert_do(ch, ch->ifassert_my_metric);
511 }
512
513 /*
514 RFC 4601: 4.6.4. AssertCancel Messages
515
516 An AssertCancel(S,G) is an infinite metric assert with the RPT bit
517 set that names S as the source.
518 */
519 static int pim_assert_cancel(struct pim_ifchannel *ch)
520 {
521 struct pim_assert_metric metric;
522
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;
527
528 return pim_assert_do(ch, metric);
529 }
530
531 static int on_assert_timer(struct thread *t)
532 {
533 struct pim_ifchannel *ch;
534 struct interface *ifp;
535
536 zassert(t);
537 ch = THREAD_ARG(t);
538 zassert(ch);
539
540 ifp = ch->interface;
541 zassert(ifp);
542
543 if (PIM_DEBUG_PIM_TRACE) {
544 char src_str[100];
545 char grp_str[100];
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",
549 __PRETTY_FUNCTION__,
550 src_str, grp_str, ifp->name);
551 }
552
553 ch->t_ifassert_timer = 0;
554
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);
559 break;
560 case PIM_IFASSERT_I_AM_LOSER:
561 assert_action_a5(ch);
562 break;
563 default:
564 {
565 char source_str[100];
566 char group_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",
570 __PRETTY_FUNCTION__,
571 source_str, group_str, ch->ifassert_state, ifp->name);
572 }
573 }
574
575 return 0;
576 }
577
578 static void assert_timer_off(struct pim_ifchannel *ch)
579 {
580 struct interface *ifp;
581
582 zassert(ch);
583 ifp = ch->interface;
584 zassert(ifp);
585
586 if (PIM_DEBUG_PIM_TRACE) {
587 if (ch->t_ifassert_timer) {
588 char src_str[100];
589 char grp_str[100];
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",
593 __PRETTY_FUNCTION__,
594 src_str, grp_str, ifp->name);
595 }
596 }
597 THREAD_OFF(ch->t_ifassert_timer);
598 zassert(!ch->t_ifassert_timer);
599 }
600
601 static void pim_assert_timer_set(struct pim_ifchannel *ch,
602 int interval)
603 {
604 struct interface *ifp;
605
606 zassert(ch);
607 ifp = ch->interface;
608 zassert(ifp);
609
610 assert_timer_off(ch);
611
612 if (PIM_DEBUG_PIM_TRACE) {
613 char src_str[100];
614 char grp_str[100];
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",
618 __PRETTY_FUNCTION__,
619 src_str, grp_str, interval, ifp->name);
620 }
621
622 THREAD_TIMER_ON(master, ch->t_ifassert_timer,
623 on_assert_timer,
624 ch, interval);
625 }
626
627 static void pim_assert_timer_reset(struct pim_ifchannel *ch)
628 {
629 pim_assert_timer_set(ch, PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
630 }
631
632 /*
633 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
634
635 (S,G) Assert State machine Actions
636
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).
641 */
642 int assert_action_a1(struct pim_ifchannel *ch)
643 {
644 struct interface *ifp = ch->interface;
645 struct pim_interface *pim_ifp;
646
647 zassert(ifp);
648
649 pim_ifp = ifp->info;
650 if (!pim_ifp) {
651 char src_str[100];
652 char grp_str[100];
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",
656 __PRETTY_FUNCTION__,
657 src_str, grp_str, ifp->name);
658 return -1; /* must return since pim_ifp is used below */
659 }
660
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));
666
667 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
668 if (assert_action_a3(ch)) {
669 char src_str[100];
670 char grp_str[100];
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",
674 __PRETTY_FUNCTION__,
675 src_str, grp_str, ifp->name);
676 /* warning only */
677 }
678
679 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
680
681 return 0;
682 }
683
684 /*
685 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
686
687 (S,G) Assert State machine Actions
688
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.
692 */
693 static void assert_action_a2(struct pim_ifchannel *ch,
694 struct pim_assert_metric winner_metric)
695 {
696 pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
697 winner_metric.ip_address,
698 winner_metric);
699
700 pim_assert_timer_set(ch, PIM_ASSERT_TIME);
701
702 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
703 }
704
705 /*
706 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
707
708 (S,G) Assert State machine Actions
709
710 A3: Send Assert(S,G).
711 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
712 */
713 static int assert_action_a3(struct pim_ifchannel *ch)
714 {
715 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
716
717 pim_assert_timer_reset(ch);
718
719 if (pim_assert_send(ch)) {
720 char src_str[100];
721 char grp_str[100];
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));
724
725 zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s",
726 __PRETTY_FUNCTION__,
727 src_str, grp_str, ch->interface->name);
728 return -1;
729 }
730
731 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
732
733 return 0;
734 }
735
736 /*
737 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
738
739 (S,G) Assert State machine Actions
740
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
744 values).
745 */
746 void assert_action_a4(struct pim_ifchannel *ch)
747 {
748 if (pim_assert_cancel(ch)) {
749 char src_str[100];
750 char grp_str[100];
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",
754 __PRETTY_FUNCTION__,
755 src_str, grp_str, ch->interface->name);
756 /* log warning only */
757 }
758
759 assert_action_a5(ch);
760
761 zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
762 }
763
764 /*
765 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
766
767 (S,G) Assert State machine Actions
768
769 A5: Delete assert info (AssertWinner(S,G,I) and
770 AssertWinnerMetric(S,G,I) will then return their default values).
771 */
772 void assert_action_a5(struct pim_ifchannel *ch)
773 {
774 reset_ifassert_state(ch);
775 zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
776 }
777
778 /*
779 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
780
781 (S,G) Assert State machine Actions
782
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.
788 */
789 static void assert_action_a6(struct pim_ifchannel *ch,
790 struct pim_assert_metric winner_metric)
791 {
792 assert_action_a2(ch, winner_metric);
793
794 /*
795 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
796 SPTbit(S,G) to TRUE.
797 */
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;
801
802 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
803 }
804