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