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