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