]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_assert.c
Merge remote-tracking branch 'origin/master' into bgpafisafi
[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,
383 remain,
384 group_addr);
385 if (!pim_msg_curr) {
386 char group_str[INET_ADDRSTRLEN];
387 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
388 zlog_warn("%s: failure encoding group address %s: space left=%d",
389 __PRETTY_FUNCTION__, group_str, remain);
390 return -1;
391 }
392
393 /* Encode source */
394 remain = buf_pastend - pim_msg_curr;
395 pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
396 remain,
397 source_addr);
398 if (!pim_msg_curr) {
399 char source_str[INET_ADDRSTRLEN];
400 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
401 zlog_warn("%s: failure encoding source address %s: space left=%d",
402 __PRETTY_FUNCTION__, source_str, remain);
403 return -2;
404 }
405
406 /* Metric preference */
407 pim_write_uint32(pim_msg_curr, rpt_bit_flag ?
408 metric_preference | 0x80000000 :
409 metric_preference);
410 pim_msg_curr += 4;
411
412 /* Route metric */
413 pim_write_uint32(pim_msg_curr, route_metric);
414 pim_msg_curr += 4;
415
416 /*
417 Add PIM header
418 */
419 pim_msg_size = pim_msg_curr - pim_msg;
420 pim_msg_build_header(pim_msg, pim_msg_size,
421 PIM_MSG_TYPE_ASSERT);
422
423 return pim_msg_size;
424 }
425
426 static int pim_assert_do(struct pim_ifchannel *ch,
427 struct pim_assert_metric metric)
428 {
429 struct interface *ifp;
430 struct pim_interface *pim_ifp;
431 uint8_t pim_msg[1000];
432 int pim_msg_size;
433
434 ifp = ch->interface;
435 if (!ifp)
436 {
437 if (PIM_DEBUG_PIM_TRACE)
438 zlog_debug("%s: channel%s has no associated interface!",
439 __PRETTY_FUNCTION__, ch->sg_str);
440 return -1;
441 }
442 pim_ifp = ifp->info;
443 if (!pim_ifp) {
444 if (PIM_DEBUG_PIM_TRACE)
445 zlog_debug("%s: channel %s pim not enabled on interface: %s",
446 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
447 return -1;
448 }
449
450 pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp,
451 ch->sg.grp, ch->sg.src,
452 metric.metric_preference,
453 metric.route_metric,
454 metric.rpt_bit_flag);
455 if (pim_msg_size < 1) {
456 zlog_warn("%s: failure building PIM assert message: msg_size=%d",
457 __PRETTY_FUNCTION__, pim_msg_size);
458 return -2;
459 }
460
461 /*
462 RFC 4601: 4.3.1. Sending Hello Messages
463
464 Thus, if a router needs to send a Join/Prune or Assert message on
465 an interface on which it has not yet sent a Hello message with the
466 currently configured IP address, then it MUST immediately send the
467 relevant Hello message without waiting for the Hello Timer to
468 expire, followed by the Join/Prune or Assert message.
469 */
470 pim_hello_require(ifp);
471
472 if (PIM_DEBUG_PIM_TRACE) {
473 zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
474 __PRETTY_FUNCTION__,
475 ifp->name, ch->sg_str,
476 metric.metric_preference,
477 metric.route_metric,
478 PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
479 }
480
481 if (pim_msg_send(pim_ifp->pim_sock_fd,
482 pim_ifp->primary_address,
483 qpim_all_pim_routers_addr,
484 pim_msg,
485 pim_msg_size,
486 ifp->name)) {
487 zlog_warn("%s: could not send PIM message on interface %s",
488 __PRETTY_FUNCTION__, ifp->name);
489 return -3;
490 }
491
492 return 0;
493 }
494
495 int pim_assert_send(struct pim_ifchannel *ch)
496 {
497 return pim_assert_do(ch, ch->ifassert_my_metric);
498 }
499
500 /*
501 RFC 4601: 4.6.4. AssertCancel Messages
502
503 An AssertCancel(S,G) is an infinite metric assert with the RPT bit
504 set that names S as the source.
505 */
506 static int pim_assert_cancel(struct pim_ifchannel *ch)
507 {
508 struct pim_assert_metric metric;
509
510 metric.rpt_bit_flag = 0;
511 metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
512 metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
513 metric.ip_address = ch->sg.src;
514
515 return pim_assert_do(ch, metric);
516 }
517
518 static int on_assert_timer(struct thread *t)
519 {
520 struct pim_ifchannel *ch;
521 struct interface *ifp;
522
523 ch = THREAD_ARG(t);
524
525 ifp = ch->interface;
526
527 if (PIM_DEBUG_PIM_TRACE) {
528 zlog_debug("%s: (S,G)=%s timer expired on interface %s",
529 __PRETTY_FUNCTION__,
530 ch->sg_str, ifp->name);
531 }
532
533 ch->t_ifassert_timer = NULL;
534
535 switch (ch->ifassert_state) {
536 case PIM_IFASSERT_I_AM_WINNER:
537 assert_action_a3(ch);
538 break;
539 case PIM_IFASSERT_I_AM_LOSER:
540 assert_action_a5(ch);
541 break;
542 default:
543 {
544 if (PIM_DEBUG_PIM_EVENTS)
545 zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
546 __PRETTY_FUNCTION__,
547 ch->sg_str, ch->ifassert_state, ifp->name);
548 }
549 }
550
551 return 0;
552 }
553
554 static void assert_timer_off(struct pim_ifchannel *ch)
555 {
556 if (PIM_DEBUG_PIM_TRACE) {
557 if (ch->t_ifassert_timer) {
558 zlog_debug("%s: (S,G)=%s cancelling timer on interface %s",
559 __PRETTY_FUNCTION__,
560 ch->sg_str, ch->interface->name);
561 }
562 }
563 THREAD_OFF(ch->t_ifassert_timer);
564 }
565
566 static void pim_assert_timer_set(struct pim_ifchannel *ch,
567 int interval)
568 {
569 assert_timer_off(ch);
570
571 if (PIM_DEBUG_PIM_TRACE) {
572 zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
573 __PRETTY_FUNCTION__,
574 ch->sg_str, interval, ch->interface->name);
575 }
576
577 THREAD_TIMER_ON(master, ch->t_ifassert_timer,
578 on_assert_timer,
579 ch, interval);
580 }
581
582 static void pim_assert_timer_reset(struct pim_ifchannel *ch)
583 {
584 pim_assert_timer_set(ch, PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
585 }
586
587 /*
588 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
589
590 (S,G) Assert State machine Actions
591
592 A1: Send Assert(S,G).
593 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
594 Store self as AssertWinner(S,G,I).
595 Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
596 */
597 int assert_action_a1(struct pim_ifchannel *ch)
598 {
599 struct interface *ifp = ch->interface;
600 struct pim_interface *pim_ifp;
601
602 pim_ifp = ifp->info;
603 if (!pim_ifp) {
604 zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
605 __PRETTY_FUNCTION__,
606 ch->sg_str, ifp->name);
607 return -1; /* must return since pim_ifp is used below */
608 }
609
610 /* Switch to I_AM_WINNER before performing action_a3 below */
611 pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_WINNER,
612 pim_ifp->primary_address,
613 pim_macro_spt_assert_metric(&ch->upstream->rpf,
614 pim_ifp->primary_address));
615
616 if (assert_action_a3(ch)) {
617 zlog_warn("%s: (S,G)=%s assert_action_a3 failure on interface %s",
618 __PRETTY_FUNCTION__,
619 ch->sg_str, ifp->name);
620 /* warning only */
621 }
622
623 if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER)
624 {
625 if (PIM_DEBUG_PIM_EVENTS)
626 zlog_warn("%s: channel%s not in expected PIM_IFASSERT_I_AM_WINNER state",
627 __PRETTY_FUNCTION__, ch->sg_str);
628 }
629
630 return 0;
631 }
632
633 /*
634 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
635
636 (S,G) Assert State machine Actions
637
638 A2: Store new assert winner as AssertWinner(S,G,I) and assert
639 winner metric as AssertWinnerMetric(S,G,I).
640 Set Assert Timer to Assert_Time.
641 */
642 static void assert_action_a2(struct pim_ifchannel *ch,
643 struct pim_assert_metric winner_metric)
644 {
645 pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
646 winner_metric.ip_address,
647 winner_metric);
648
649 pim_assert_timer_set(ch, PIM_ASSERT_TIME);
650
651 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
652 {
653 if (PIM_DEBUG_PIM_EVENTS)
654 zlog_warn("%s: channel%s not in expected PIM_IFASSERT_I_AM_LOSER state",
655 __PRETTY_FUNCTION__, ch->sg_str);
656 }
657 }
658
659 /*
660 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
661
662 (S,G) Assert State machine Actions
663
664 A3: Send Assert(S,G).
665 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
666 */
667 static int assert_action_a3(struct pim_ifchannel *ch)
668 {
669 if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER)
670 {
671 if (PIM_DEBUG_PIM_EVENTS)
672 zlog_warn("%s: channel%s expected to be in PIM_IFASSERT_I_AM_WINNER state",
673 __PRETTY_FUNCTION__, ch->sg_str);
674 return -1;
675 }
676
677 pim_assert_timer_reset(ch);
678
679 if (pim_assert_send(ch)) {
680 zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
681 __PRETTY_FUNCTION__,
682 ch->sg_str, ch->interface->name);
683 return -1;
684 }
685
686 return 0;
687 }
688
689 /*
690 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
691
692 (S,G) Assert State machine Actions
693
694 A4: Send AssertCancel(S,G).
695 Delete assert info (AssertWinner(S,G,I) and
696 AssertWinnerMetric(S,G,I) will then return their default
697 values).
698 */
699 void assert_action_a4(struct pim_ifchannel *ch)
700 {
701 if (pim_assert_cancel(ch)) {
702 zlog_warn("%s: failure sending AssertCancel%s on interface %s",
703 __PRETTY_FUNCTION__,
704 ch->sg_str, ch->interface->name);
705 /* log warning only */
706 }
707
708 assert_action_a5(ch);
709
710 if (ch->ifassert_state != PIM_IFASSERT_NOINFO)
711 {
712 if (PIM_DEBUG_PIM_EVENTS)
713 zlog_warn("%s: channel%s not in PIM_IFASSERT_NOINFO state as expected",
714 __PRETTY_FUNCTION__, ch->sg_str);
715 }
716 }
717
718 /*
719 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
720
721 (S,G) Assert State machine Actions
722
723 A5: Delete assert info (AssertWinner(S,G,I) and
724 AssertWinnerMetric(S,G,I) will then return their default values).
725 */
726 void assert_action_a5(struct pim_ifchannel *ch)
727 {
728 reset_ifassert_state(ch);
729 if (ch->ifassert_state != PIM_IFASSERT_NOINFO)
730 {
731 if (PIM_DEBUG_PIM_EVENTS)
732 zlog_warn("%s: channel%s not in PIM_IFSSERT_NOINFO state as expected",
733 __PRETTY_FUNCTION__, ch->sg_str);
734 }
735 }
736
737 /*
738 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
739
740 (S,G) Assert State machine Actions
741
742 A6: Store new assert winner as AssertWinner(S,G,I) and assert
743 winner metric as AssertWinnerMetric(S,G,I).
744 Set Assert Timer to Assert_Time.
745 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
746 set SPTbit(S,G) to TRUE.
747 */
748 static void assert_action_a6(struct pim_ifchannel *ch,
749 struct pim_assert_metric winner_metric)
750 {
751 assert_action_a2(ch, winner_metric);
752
753 /*
754 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
755 SPTbit(S,G) to TRUE.
756 */
757 if (ch->upstream->rpf.source_nexthop.interface == ch->interface)
758 if (ch->upstream->join_state == PIM_UPSTREAM_JOINED)
759 ch->upstream->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
760
761 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
762 {
763 if(PIM_DEBUG_PIM_EVENTS)
764 zlog_warn("%s: channel%s not in PIM_IFASSERT_I_AM_LOSER state as expected",
765 __PRETTY_FUNCTION__, ch->sg_str);
766 }
767 }
768