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