blob: ad21e08efedccf5ea46a45e4fff3406f6d71dea2 [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
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
28#include "pimd.h"
29#include "pim_str.h"
30#include "pim_tlv.h"
31#include "pim_msg.h"
32#include "pim_pim.h"
Everton Marques7c5f5012009-11-19 17:00:23 -020033#include "pim_int.h"
Everton Marques871dbcf2009-08-11 15:43:05 -030034#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
Everton Marquesc1b228c2014-08-27 15:27:26 -030056 if (PIM_DEBUG_PIM_EVENTS) {
57 if (ch->ifassert_state != new_state) {
58 char src_str[100];
59 char grp_str[100];
60 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
61 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
62 zlog_debug("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s",
63 __PRETTY_FUNCTION__,
64 src_str, grp_str,
65 pim_ifchannel_ifassert_name(ch->ifassert_state),
66 pim_ifchannel_ifassert_name(new_state),
67 ch->interface->name);
68 }
Everton Marques871dbcf2009-08-11 15:43:05 -030069
Everton Marquesc1b228c2014-08-27 15:27:26 -030070 if (winner_changed) {
71 char src_str[100];
72 char grp_str[100];
73 char was_str[100];
74 char winner_str[100];
75 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
76 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
77 pim_inet4_dump("<was?>", ch->ifassert_winner, was_str, sizeof(was_str));
78 pim_inet4_dump("<winner?>", winner, winner_str, sizeof(winner_str));
79 zlog_debug("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s",
80 __PRETTY_FUNCTION__,
81 src_str, grp_str,
82 was_str, winner_str, ch->interface->name);
83 }
84 } /* PIM_DEBUG_PIM_EVENTS */
Everton Marques871dbcf2009-08-11 15:43:05 -030085
86 ch->ifassert_state = new_state;
87 ch->ifassert_winner = winner;
88 ch->ifassert_winner_metric = winner_metric;
89 ch->ifassert_creation = pim_time_monotonic_sec();
90
91 if (winner_changed || metric_changed) {
92 pim_upstream_update_join_desired(ch->upstream);
93 pim_ifchannel_update_could_assert(ch);
94 pim_ifchannel_update_assert_tracking_desired(ch);
95 }
96}
97
98static void on_trace(const char *label,
99 struct interface *ifp, struct in_addr src)
100{
101 if (PIM_DEBUG_PIM_TRACE) {
102 char src_str[100];
103 pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
104 zlog_debug("%s: from %s on %s",
105 label, src_str, ifp->name);
106 }
107}
108
109static int preferred_assert(const struct pim_ifchannel *ch,
110 const struct pim_assert_metric *recv_metric)
111{
112 return pim_assert_metric_better(recv_metric,
113 &ch->ifassert_winner_metric);
114}
115
116static int acceptable_assert(const struct pim_assert_metric *my_metric,
117 const struct pim_assert_metric *recv_metric)
118{
119 return pim_assert_metric_better(recv_metric,
120 my_metric);
121}
122
123static int inferior_assert(const struct pim_assert_metric *my_metric,
124 const struct pim_assert_metric *recv_metric)
125{
126 return pim_assert_metric_better(my_metric,
127 recv_metric);
128}
129
130static int cancel_assert(const struct pim_assert_metric *recv_metric)
131{
132 return (recv_metric->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX)
133 &&
134 (recv_metric->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX);
135}
136
137static void if_could_assert_do_a1(const char *caller,
138 struct pim_ifchannel *ch)
139{
140 if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
141 if (assert_action_a1(ch)) {
142 char src_str[100];
143 char grp_str[100];
144 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
145 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
146 zlog_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
147 __PRETTY_FUNCTION__, caller,
148 src_str, grp_str, ch->interface->name);
149 /* log warning only */
150 }
151 }
152}
153
154static int dispatch_assert(struct interface *ifp,
155 struct in_addr source_addr,
156 struct in_addr group_addr,
157 struct pim_assert_metric recv_metric)
158{
159 struct pim_ifchannel *ch;
160
161 ch = pim_ifchannel_add(ifp, source_addr, group_addr);
162 if (!ch) {
163 char source_str[100];
164 char group_str[100];
165 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
166 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
167 zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s",
168 __PRETTY_FUNCTION__,
169 source_str, group_str, ifp->name);
170 return -1;
171 }
172
173 switch (ch->ifassert_state) {
174 case PIM_IFASSERT_NOINFO:
175 if (recv_metric.rpt_bit_flag) {
176 /* RPT bit set */
177 if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
178 }
179 else {
180 /* RPT bit clear */
181 if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
182 if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
183 }
184 else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) {
185 if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)) {
186 assert_action_a6(ch, recv_metric);
187 }
188 }
189 }
190 break;
191 case PIM_IFASSERT_I_AM_WINNER:
192 if (preferred_assert(ch, &recv_metric)) {
193 assert_action_a2(ch, recv_metric);
194 }
195 else {
196 if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
197 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
198 assert_action_a3(ch);
199 }
200 }
201 break;
202 case PIM_IFASSERT_I_AM_LOSER:
203 if (recv_metric.ip_address.s_addr == ch->ifassert_winner.s_addr) {
204 /* Assert from current winner */
205
206 if (cancel_assert(&recv_metric)) {
207 assert_action_a5(ch);
208 }
209 else {
210 if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
211 assert_action_a5(ch);
212 }
213 else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) {
214 if (!recv_metric.rpt_bit_flag) {
215 assert_action_a2(ch, recv_metric);
216 }
217 }
218 }
219 }
220 else if (preferred_assert(ch, &recv_metric)) {
221 assert_action_a2(ch, recv_metric);
222 }
223 break;
224 default:
225 {
226 char source_str[100];
227 char group_str[100];
228 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
229 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
230 zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
231 __PRETTY_FUNCTION__,
232 source_str, group_str, ch->ifassert_state, ifp->name);
233 }
234 return -2;
235 }
236
237 return 0;
238}
239
240int pim_assert_recv(struct interface *ifp,
241 struct pim_neighbor *neigh,
242 struct in_addr src_addr,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000243 uint8_t *buf, int buf_size)
Everton Marques871dbcf2009-08-11 15:43:05 -0300244{
245 struct prefix msg_group_addr;
246 struct prefix msg_source_addr;
247 struct pim_assert_metric msg_metric;
248 int offset;
David Lamparterf8cfeb22012-02-16 04:31:08 +0000249 uint8_t *curr;
Everton Marques871dbcf2009-08-11 15:43:05 -0300250 int curr_size;
251
252 on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
253
254 curr = buf;
255 curr_size = buf_size;
256
257 /*
258 Parse assert group addr
259 */
260 offset = pim_parse_addr_group(ifp->name, src_addr,
261 &msg_group_addr,
262 curr, curr_size);
263 if (offset < 1) {
264 char src_str[100];
265 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
266 zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
267 __PRETTY_FUNCTION__,
268 src_str, ifp->name);
269 return -1;
270 }
271 curr += offset;
272 curr_size -= offset;
273
274 /*
275 Parse assert source addr
276 */
277 offset = pim_parse_addr_ucast(ifp->name, src_addr,
278 &msg_source_addr,
279 curr, curr_size);
280 if (offset < 1) {
281 char src_str[100];
282 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
283 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
284 __PRETTY_FUNCTION__,
285 src_str, ifp->name);
286 return -2;
287 }
288 curr += offset;
289 curr_size -= offset;
290
291 if (curr_size != 8) {
292 char src_str[100];
293 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
294 zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s",
295 __PRETTY_FUNCTION__,
296 curr_size,
297 src_str, ifp->name);
298 return -3;
299 }
300
301 /*
302 Parse assert metric preference
303 */
304
Everton Marques7c5f5012009-11-19 17:00:23 -0200305 msg_metric.metric_preference = pim_read_uint32_host(curr);
Everton Marques871dbcf2009-08-11 15:43:05 -0300306
307 msg_metric.rpt_bit_flag = msg_metric.metric_preference & 0x80000000; /* save highest bit */
308 msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */
309
310 curr += 4;
311
312 /*
313 Parse assert route metric
314 */
315
Everton Marques7c5f5012009-11-19 17:00:23 -0200316 msg_metric.route_metric = pim_read_uint32_host(curr);
Everton Marques871dbcf2009-08-11 15:43:05 -0300317
318 if (PIM_DEBUG_PIM_TRACE) {
319 char neigh_str[100];
320 char source_str[100];
321 char group_str[100];
322 pim_inet4_dump("<neigh?>", src_addr, neigh_str, sizeof(neigh_str));
323 pim_inet4_dump("<src?>", msg_source_addr.u.prefix4, source_str, sizeof(source_str));
324 pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4, group_str, sizeof(group_str));
325 zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
326 __PRETTY_FUNCTION__, neigh_str, ifp->name,
327 source_str, group_str,
328 msg_metric.metric_preference,
329 msg_metric.route_metric,
330 PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag));
331 }
332
333 msg_metric.ip_address = src_addr;
334
335 return dispatch_assert(ifp,
336 msg_source_addr.u.prefix4,
337 msg_group_addr.u.prefix4,
338 msg_metric);
339}
340
341/*
342 RFC 4601: 4.6.3. Assert Metrics
343
344 Assert metrics are defined as:
345
346 When comparing assert_metrics, the rpt_bit_flag, metric_preference,
347 and route_metric field are compared in order, where the first lower
348 value wins. If all fields are equal, the primary IP address of the
349 router that sourced the Assert message is used as a tie-breaker,
350 with the highest IP address winning.
351*/
352int pim_assert_metric_better(const struct pim_assert_metric *m1,
353 const struct pim_assert_metric *m2)
354{
355 if (m1->rpt_bit_flag < m2->rpt_bit_flag)
356 return 1;
357 if (m1->rpt_bit_flag > m2->rpt_bit_flag)
358 return 0;
359
360 if (m1->metric_preference < m2->metric_preference)
361 return 1;
362 if (m1->metric_preference > m2->metric_preference)
363 return 0;
364
365 if (m1->route_metric < m2->route_metric)
366 return 1;
367 if (m1->route_metric > m2->route_metric)
368 return 0;
369
370 return ntohl(m1->ip_address.s_addr) > ntohl(m2->ip_address.s_addr);
371}
372
373int pim_assert_metric_match(const struct pim_assert_metric *m1,
374 const struct pim_assert_metric *m2)
375{
376 if (m1->rpt_bit_flag != m2->rpt_bit_flag)
377 return 0;
378 if (m1->metric_preference != m2->metric_preference)
379 return 0;
380 if (m1->route_metric != m2->route_metric)
381 return 0;
382
383 return m1->ip_address.s_addr == m2->ip_address.s_addr;
384}
385
Everton Marques7c5f5012009-11-19 17:00:23 -0200386int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
Everton Marques871dbcf2009-08-11 15:43:05 -0300387 struct interface *ifp,
388 struct in_addr group_addr,
389 struct in_addr source_addr,
390 uint32_t metric_preference,
391 uint32_t route_metric,
392 uint32_t rpt_bit_flag)
393{
Everton Marques7c5f5012009-11-19 17:00:23 -0200394 uint8_t *buf_pastend = pim_msg + buf_size;
395 uint8_t *pim_msg_curr;
Everton Marques871dbcf2009-08-11 15:43:05 -0300396 int pim_msg_size;
397 int remain;
398
399 pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */
400
401 /* Encode group */
402 remain = buf_pastend - pim_msg_curr;
403 pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
404 remain,
405 group_addr);
406 if (!pim_msg_curr) {
407 char group_str[100];
408 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
409 zlog_warn("%s: failure encoding group address %s: space left=%d",
410 __PRETTY_FUNCTION__, group_str, remain);
411 return -1;
412 }
413
414 /* Encode source */
415 remain = buf_pastend - pim_msg_curr;
416 pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
417 remain,
418 source_addr);
419 if (!pim_msg_curr) {
420 char source_str[100];
421 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
422 zlog_warn("%s: failure encoding source address %s: space left=%d",
423 __PRETTY_FUNCTION__, source_str, remain);
424 return -2;
425 }
426
427 /* Metric preference */
Everton Marques7c5f5012009-11-19 17:00:23 -0200428 pim_write_uint32(pim_msg_curr, rpt_bit_flag ?
429 metric_preference | 0x80000000 :
430 metric_preference);
Everton Marques871dbcf2009-08-11 15:43:05 -0300431 pim_msg_curr += 4;
432
433 /* Route metric */
Everton Marques7c5f5012009-11-19 17:00:23 -0200434 pim_write_uint32(pim_msg_curr, route_metric);
Everton Marques871dbcf2009-08-11 15:43:05 -0300435 pim_msg_curr += 4;
436
437 /*
438 Add PIM header
439 */
440 pim_msg_size = pim_msg_curr - pim_msg;
441 pim_msg_build_header(pim_msg, pim_msg_size,
442 PIM_MSG_TYPE_ASSERT);
443
444 return pim_msg_size;
445}
446
447static int pim_assert_do(struct pim_ifchannel *ch,
448 struct pim_assert_metric metric)
449{
450 struct interface *ifp;
451 struct pim_interface *pim_ifp;
David Lamparterf8cfeb22012-02-16 04:31:08 +0000452 uint8_t pim_msg[1000];
Everton Marques871dbcf2009-08-11 15:43:05 -0300453 int pim_msg_size;
454
455 ifp = ch->interface;
456 zassert(ifp);
457
458 pim_ifp = ifp->info;
459 if (!pim_ifp) {
460 zlog_warn("%s: pim not enabled on interface: %s",
461 __PRETTY_FUNCTION__, ifp->name);
462 return -1;
463 }
464
465 pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp,
466 ch->group_addr, ch->source_addr,
467 metric.metric_preference,
468 metric.route_metric,
469 metric.rpt_bit_flag);
470 if (pim_msg_size < 1) {
471 zlog_warn("%s: failure building PIM assert message: msg_size=%d",
472 __PRETTY_FUNCTION__, pim_msg_size);
473 return -2;
474 }
475
476 /*
477 RFC 4601: 4.3.1. Sending Hello Messages
478
479 Thus, if a router needs to send a Join/Prune or Assert message on
480 an interface on which it has not yet sent a Hello message with the
481 currently configured IP address, then it MUST immediately send the
482 relevant Hello message without waiting for the Hello Timer to
483 expire, followed by the Join/Prune or Assert message.
484 */
485 pim_hello_require(ifp);
486
487 if (PIM_DEBUG_PIM_TRACE) {
488 char source_str[100];
489 char group_str[100];
490 pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
491 pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
492 zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
493 __PRETTY_FUNCTION__,
494 ifp->name, source_str, group_str,
495 metric.metric_preference,
496 metric.route_metric,
497 PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
498 }
499
500 if (pim_msg_send(pim_ifp->pim_sock_fd,
501 qpim_all_pim_routers_addr,
502 pim_msg,
503 pim_msg_size,
504 ifp->name)) {
505 zlog_warn("%s: could not send PIM message on interface %s",
506 __PRETTY_FUNCTION__, ifp->name);
507 return -3;
508 }
509
510 return 0;
511}
512
513int pim_assert_send(struct pim_ifchannel *ch)
514{
515 return pim_assert_do(ch, ch->ifassert_my_metric);
516}
517
518/*
519 RFC 4601: 4.6.4. AssertCancel Messages
520
521 An AssertCancel(S,G) is an infinite metric assert with the RPT bit
522 set that names S as the source.
523 */
524static int pim_assert_cancel(struct pim_ifchannel *ch)
525{
526 struct pim_assert_metric metric;
527
528 metric.rpt_bit_flag = 0;
529 metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
530 metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
531 metric.ip_address = ch->source_addr;
532
533 return pim_assert_do(ch, metric);
534}
535
536static int on_assert_timer(struct thread *t)
537{
538 struct pim_ifchannel *ch;
539 struct interface *ifp;
540
541 zassert(t);
542 ch = THREAD_ARG(t);
543 zassert(ch);
544
545 ifp = ch->interface;
546 zassert(ifp);
547
548 if (PIM_DEBUG_PIM_TRACE) {
549 char src_str[100];
550 char grp_str[100];
551 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
552 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
553 zlog_debug("%s: (S,G)=(%s,%s) timer expired on interface %s",
554 __PRETTY_FUNCTION__,
555 src_str, grp_str, ifp->name);
556 }
557
558 ch->t_ifassert_timer = 0;
559
560 switch (ch->ifassert_state) {
561 case PIM_IFASSERT_I_AM_WINNER:
562 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
563 assert_action_a3(ch);
564 break;
565 case PIM_IFASSERT_I_AM_LOSER:
566 assert_action_a5(ch);
567 break;
568 default:
569 {
570 char source_str[100];
571 char group_str[100];
572 pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
573 pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
574 zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
575 __PRETTY_FUNCTION__,
576 source_str, group_str, ch->ifassert_state, ifp->name);
577 }
578 }
579
580 return 0;
581}
582
583static void assert_timer_off(struct pim_ifchannel *ch)
584{
585 struct interface *ifp;
586
587 zassert(ch);
588 ifp = ch->interface;
589 zassert(ifp);
590
591 if (PIM_DEBUG_PIM_TRACE) {
592 if (ch->t_ifassert_timer) {
593 char src_str[100];
594 char grp_str[100];
595 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
596 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
597 zlog_debug("%s: (S,G)=(%s,%s) cancelling timer on interface %s",
598 __PRETTY_FUNCTION__,
599 src_str, grp_str, ifp->name);
600 }
601 }
602 THREAD_OFF(ch->t_ifassert_timer);
603 zassert(!ch->t_ifassert_timer);
604}
605
606static void pim_assert_timer_set(struct pim_ifchannel *ch,
607 int interval)
608{
609 struct interface *ifp;
610
611 zassert(ch);
612 ifp = ch->interface;
613 zassert(ifp);
614
615 assert_timer_off(ch);
616
617 if (PIM_DEBUG_PIM_TRACE) {
618 char src_str[100];
619 char grp_str[100];
620 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
621 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
622 zlog_debug("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s",
623 __PRETTY_FUNCTION__,
624 src_str, grp_str, interval, ifp->name);
625 }
626
627 THREAD_TIMER_ON(master, ch->t_ifassert_timer,
628 on_assert_timer,
629 ch, interval);
630}
631
632static void pim_assert_timer_reset(struct pim_ifchannel *ch)
633{
634 pim_assert_timer_set(ch, PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
635}
636
637/*
638 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
639
640 (S,G) Assert State machine Actions
641
642 A1: Send Assert(S,G).
643 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
644 Store self as AssertWinner(S,G,I).
645 Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
646*/
647int assert_action_a1(struct pim_ifchannel *ch)
648{
649 struct interface *ifp = ch->interface;
650 struct pim_interface *pim_ifp;
651
652 zassert(ifp);
653
654 pim_ifp = ifp->info;
655 if (!pim_ifp) {
656 char src_str[100];
657 char grp_str[100];
658 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
659 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
Everton Marquesc1b228c2014-08-27 15:27:26 -0300660 zlog_warn("%s: (S,G)=(%s,%s) multicast not enabled on interface %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300661 __PRETTY_FUNCTION__,
662 src_str, grp_str, ifp->name);
663 return -1; /* must return since pim_ifp is used below */
664 }
665
666 /* Switch to I_AM_WINNER before performing action_a3 below */
667 pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_WINNER,
668 pim_ifp->primary_address,
669 pim_macro_spt_assert_metric(&ch->upstream->rpf,
670 pim_ifp->primary_address));
671
672 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
673 if (assert_action_a3(ch)) {
674 char src_str[100];
675 char grp_str[100];
676 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
677 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
678 zlog_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s",
679 __PRETTY_FUNCTION__,
680 src_str, grp_str, ifp->name);
681 /* warning only */
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 A2: Store new assert winner as AssertWinner(S,G,I) and assert
695 winner metric as AssertWinnerMetric(S,G,I).
696 Set Assert Timer to Assert_Time.
697*/
698static void assert_action_a2(struct pim_ifchannel *ch,
699 struct pim_assert_metric winner_metric)
700{
701 pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
702 winner_metric.ip_address,
703 winner_metric);
704
705 pim_assert_timer_set(ch, PIM_ASSERT_TIME);
706
707 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
708}
709
710/*
711 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
712
713 (S,G) Assert State machine Actions
714
715 A3: Send Assert(S,G).
716 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
717*/
718static int assert_action_a3(struct pim_ifchannel *ch)
719{
720 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
721
722 pim_assert_timer_reset(ch);
723
724 if (pim_assert_send(ch)) {
725 char src_str[100];
726 char grp_str[100];
727 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
728 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
729
730 zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s",
731 __PRETTY_FUNCTION__,
732 src_str, grp_str, ch->interface->name);
733 return -1;
734 }
735
736 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
737
738 return 0;
739}
740
741/*
742 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
743
744 (S,G) Assert State machine Actions
745
746 A4: Send AssertCancel(S,G).
747 Delete assert info (AssertWinner(S,G,I) and
748 AssertWinnerMetric(S,G,I) will then return their default
749 values).
750*/
751void assert_action_a4(struct pim_ifchannel *ch)
752{
753 if (pim_assert_cancel(ch)) {
754 char src_str[100];
755 char grp_str[100];
756 pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
757 pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
758 zlog_warn("%s: failure sending AssertCancel(%s,%s) on interface %s",
759 __PRETTY_FUNCTION__,
760 src_str, grp_str, ch->interface->name);
761 /* log warning only */
762 }
763
764 assert_action_a5(ch);
765
766 zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
767}
768
769/*
770 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
771
772 (S,G) Assert State machine Actions
773
774 A5: Delete assert info (AssertWinner(S,G,I) and
775 AssertWinnerMetric(S,G,I) will then return their default values).
776*/
777void assert_action_a5(struct pim_ifchannel *ch)
778{
779 reset_ifassert_state(ch);
780 zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
781}
782
783/*
784 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
785
786 (S,G) Assert State machine Actions
787
788 A6: Store new assert winner as AssertWinner(S,G,I) and assert
789 winner metric as AssertWinnerMetric(S,G,I).
790 Set Assert Timer to Assert_Time.
791 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
792 set SPTbit(S,G) to TRUE.
793*/
794static void assert_action_a6(struct pim_ifchannel *ch,
795 struct pim_assert_metric winner_metric)
796{
797 assert_action_a2(ch, winner_metric);
798
799 /*
800 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
801 SPTbit(S,G) to TRUE.
802
803 Notice: For PIM SSM, SPTbit(S,G) is already always true.
804 */
805
806 zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
807}
808