]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_assert.c
pim6d: IPv6-adjust various pim_sgaddr uses
[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, pim_addr source_addr,
140 pim_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 pim_addr msg_source_addr;
220 bool wrong_af = false;
221 struct pim_assert_metric msg_metric;
222 int offset;
223 uint8_t *curr;
224 int curr_size;
225 struct pim_interface *pim_ifp = NULL;
226
227 on_trace(__func__, ifp, src_addr);
228
229 curr = buf;
230 curr_size = buf_size;
231
232 /*
233 Parse assert group addr
234 */
235 memset(&sg, 0, sizeof(sg));
236 offset = pim_parse_addr_group(&sg, curr, curr_size);
237 if (offset < 1) {
238 char src_str[INET_ADDRSTRLEN];
239 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
240 zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
241 __func__, src_str, ifp->name);
242 return -1;
243 }
244 curr += offset;
245 curr_size -= offset;
246
247 /*
248 Parse assert source addr
249 */
250 offset = pim_parse_addr_ucast(&msg_source_addr, curr, curr_size,
251 &wrong_af);
252 if (offset < 1 || wrong_af) {
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 __func__, 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 __func__, 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 pim_inet4_dump("<neigh?>", src_addr, neigh_str,
292 sizeof(neigh_str));
293 zlog_debug(
294 "%s: from %s on %s: (S,G)=(%pPAs,%pPAs) pref=%u metric=%u rpt_bit=%u",
295 __func__, neigh_str, ifp->name, &msg_source_addr,
296 &sg.grp, msg_metric.metric_preference,
297 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, sg.grp, msg_metric);
308 }
309
310 /*
311 RFC 4601: 4.6.3. Assert Metrics
312
313 Assert metrics are defined as:
314
315 When comparing assert_metrics, the rpt_bit_flag, metric_preference,
316 and route_metric field are compared in order, where the first lower
317 value wins. If all fields are equal, the primary IP address of the
318 router that sourced the Assert message is used as a tie-breaker,
319 with the highest IP address winning.
320 */
321 int pim_assert_metric_better(const struct pim_assert_metric *m1,
322 const struct pim_assert_metric *m2)
323 {
324 if (m1->rpt_bit_flag < m2->rpt_bit_flag)
325 return 1;
326 if (m1->rpt_bit_flag > m2->rpt_bit_flag)
327 return 0;
328
329 if (m1->metric_preference < m2->metric_preference)
330 return 1;
331 if (m1->metric_preference > m2->metric_preference)
332 return 0;
333
334 if (m1->route_metric < m2->route_metric)
335 return 1;
336 if (m1->route_metric > m2->route_metric)
337 return 0;
338
339 return pim_addr_cmp(m1->ip_address, m2->ip_address) > 0;
340 }
341
342 int pim_assert_metric_match(const struct pim_assert_metric *m1,
343 const struct pim_assert_metric *m2)
344 {
345 if (m1->rpt_bit_flag != m2->rpt_bit_flag)
346 return 0;
347 if (m1->metric_preference != m2->metric_preference)
348 return 0;
349 if (m1->route_metric != m2->route_metric)
350 return 0;
351
352 return !pim_addr_cmp(m1->ip_address, m2->ip_address);
353 }
354
355 int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp,
356 pim_addr group_addr, pim_addr source_addr,
357 uint32_t metric_preference, uint32_t route_metric,
358 uint32_t rpt_bit_flag)
359 {
360 uint8_t *buf_pastend = pim_msg + buf_size;
361 uint8_t *pim_msg_curr;
362 int pim_msg_size;
363 int remain;
364
365 pim_msg_curr =
366 pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */
367
368 /* Encode group */
369 remain = buf_pastend - pim_msg_curr;
370 pim_msg_curr = pim_msg_addr_encode_group(pim_msg_curr, group_addr);
371 if (!pim_msg_curr) {
372 zlog_warn(
373 "%s: failure encoding group address %pPA: space left=%d",
374 __func__, &group_addr, remain);
375 return -1;
376 }
377
378 /* Encode source */
379 remain = buf_pastend - pim_msg_curr;
380 pim_msg_curr = pim_msg_addr_encode_ucast(pim_msg_curr, source_addr);
381 if (!pim_msg_curr) {
382 zlog_warn(
383 "%s: failure encoding source address %pPA: space left=%d",
384 __func__, &source_addr, remain);
385 return -2;
386 }
387
388 /* Metric preference */
389 pim_write_uint32(pim_msg_curr,
390 rpt_bit_flag ? metric_preference | 0x80000000
391 : metric_preference);
392 pim_msg_curr += 4;
393
394 /* Route metric */
395 pim_write_uint32(pim_msg_curr, route_metric);
396 pim_msg_curr += 4;
397
398 /*
399 Add PIM header
400 */
401 pim_msg_size = pim_msg_curr - pim_msg;
402 pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_ASSERT, false);
403
404 return pim_msg_size;
405 }
406
407 static int pim_assert_do(struct pim_ifchannel *ch,
408 struct pim_assert_metric metric)
409 {
410 struct interface *ifp;
411 struct pim_interface *pim_ifp;
412 uint8_t pim_msg[1000];
413 int pim_msg_size;
414
415 ifp = ch->interface;
416 if (!ifp) {
417 if (PIM_DEBUG_PIM_TRACE)
418 zlog_debug("%s: channel%s has no associated interface!",
419 __func__, ch->sg_str);
420 return -1;
421 }
422 pim_ifp = ifp->info;
423 if (!pim_ifp) {
424 if (PIM_DEBUG_PIM_TRACE)
425 zlog_debug(
426 "%s: channel %s pim not enabled on interface: %s",
427 __func__, ch->sg_str, ifp->name);
428 return -1;
429 }
430
431 pim_msg_size =
432 pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp, ch->sg.grp,
433 ch->sg.src, metric.metric_preference,
434 metric.route_metric, metric.rpt_bit_flag);
435 if (pim_msg_size < 1) {
436 zlog_warn(
437 "%s: failure building PIM assert message: msg_size=%d",
438 __func__, pim_msg_size);
439 return -2;
440 }
441
442 /*
443 RFC 4601: 4.3.1. Sending Hello Messages
444
445 Thus, if a router needs to send a Join/Prune or Assert message on
446 an interface on which it has not yet sent a Hello message with the
447 currently configured IP address, then it MUST immediately send the
448 relevant Hello message without waiting for the Hello Timer to
449 expire, followed by the Join/Prune or Assert message.
450 */
451 pim_hello_require(ifp);
452
453 if (PIM_DEBUG_PIM_TRACE) {
454 zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
455 __func__, ifp->name, ch->sg_str,
456 metric.metric_preference, metric.route_metric,
457 PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
458 }
459 ++pim_ifp->pim_ifstat_assert_send;
460
461 if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
462 qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
463 ifp->name)) {
464 zlog_warn("%s: could not send PIM message on interface %s",
465 __func__, ifp->name);
466 return -3;
467 }
468
469 return 0;
470 }
471
472 int pim_assert_send(struct pim_ifchannel *ch)
473 {
474 return pim_assert_do(ch, ch->ifassert_my_metric);
475 }
476
477 /*
478 RFC 4601: 4.6.4. AssertCancel Messages
479
480 An AssertCancel(S,G) is an infinite metric assert with the RPT bit
481 set that names S as the source.
482 */
483 static int pim_assert_cancel(struct pim_ifchannel *ch)
484 {
485 struct pim_assert_metric metric;
486
487 metric.rpt_bit_flag = 0;
488 metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
489 metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
490 metric.ip_address = ch->sg.src;
491
492 return pim_assert_do(ch, metric);
493 }
494
495 static int on_assert_timer(struct thread *t)
496 {
497 struct pim_ifchannel *ch;
498 struct interface *ifp;
499
500 ch = THREAD_ARG(t);
501
502 ifp = ch->interface;
503
504 if (PIM_DEBUG_PIM_TRACE) {
505 zlog_debug("%s: (S,G)=%s timer expired on interface %s",
506 __func__, ch->sg_str, ifp->name);
507 }
508
509 ch->t_ifassert_timer = NULL;
510
511 switch (ch->ifassert_state) {
512 case PIM_IFASSERT_I_AM_WINNER:
513 assert_action_a3(ch);
514 break;
515 case PIM_IFASSERT_I_AM_LOSER:
516 assert_action_a5(ch);
517 break;
518 default: {
519 if (PIM_DEBUG_PIM_EVENTS)
520 zlog_warn(
521 "%s: (S,G)=%s invalid assert state %d on interface %s",
522 __func__, ch->sg_str, ch->ifassert_state,
523 ifp->name);
524 }
525 }
526
527 return 0;
528 }
529
530 static void assert_timer_off(struct pim_ifchannel *ch)
531 {
532 if (PIM_DEBUG_PIM_TRACE) {
533 if (ch->t_ifassert_timer) {
534 zlog_debug(
535 "%s: (S,G)=%s cancelling timer on interface %s",
536 __func__, ch->sg_str, ch->interface->name);
537 }
538 }
539 THREAD_OFF(ch->t_ifassert_timer);
540 }
541
542 static void pim_assert_timer_set(struct pim_ifchannel *ch, int interval)
543 {
544 assert_timer_off(ch);
545
546 if (PIM_DEBUG_PIM_TRACE) {
547 zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
548 __func__, ch->sg_str, interval, ch->interface->name);
549 }
550
551 thread_add_timer(router->master, on_assert_timer, ch, interval,
552 &ch->t_ifassert_timer);
553 }
554
555 static void pim_assert_timer_reset(struct pim_ifchannel *ch)
556 {
557 pim_assert_timer_set(ch,
558 PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
559 }
560
561 /*
562 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
563
564 (S,G) Assert State machine Actions
565
566 A1: Send Assert(S,G).
567 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
568 Store self as AssertWinner(S,G,I).
569 Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
570 */
571 int assert_action_a1(struct pim_ifchannel *ch)
572 {
573 struct interface *ifp = ch->interface;
574 struct pim_interface *pim_ifp;
575
576 pim_ifp = ifp->info;
577 if (!pim_ifp) {
578 zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
579 __func__, ch->sg_str, ifp->name);
580 return -1; /* must return since pim_ifp is used below */
581 }
582
583 /* Switch to I_AM_WINNER before performing action_a3 below */
584 pim_ifassert_winner_set(
585 ch, PIM_IFASSERT_I_AM_WINNER, pim_ifp->primary_address,
586 pim_macro_spt_assert_metric(&ch->upstream->rpf,
587 pim_ifp->primary_address));
588
589 if (assert_action_a3(ch)) {
590 zlog_warn(
591 "%s: (S,G)=%s assert_action_a3 failure on interface %s",
592 __func__, ch->sg_str, ifp->name);
593 /* warning only */
594 }
595
596 if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER) {
597 if (PIM_DEBUG_PIM_EVENTS)
598 zlog_warn(
599 "%s: channel%s not in expected PIM_IFASSERT_I_AM_WINNER state",
600 __func__, ch->sg_str);
601 }
602
603 return 0;
604 }
605
606 /*
607 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
608
609 (S,G) Assert State machine Actions
610
611 A2: Store new assert winner as AssertWinner(S,G,I) and assert
612 winner metric as AssertWinnerMetric(S,G,I).
613 Set Assert Timer to Assert_Time.
614 */
615 static void assert_action_a2(struct pim_ifchannel *ch,
616 struct pim_assert_metric winner_metric)
617 {
618 pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
619 winner_metric.ip_address, winner_metric);
620
621 pim_assert_timer_set(ch, PIM_ASSERT_TIME);
622
623 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) {
624 if (PIM_DEBUG_PIM_EVENTS)
625 zlog_warn(
626 "%s: channel%s not in expected PIM_IFASSERT_I_AM_LOSER state",
627 __func__, ch->sg_str);
628 }
629 }
630
631 /*
632 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
633
634 (S,G) Assert State machine Actions
635
636 A3: Send Assert(S,G).
637 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
638 */
639 static int assert_action_a3(struct pim_ifchannel *ch)
640 {
641 if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER) {
642 if (PIM_DEBUG_PIM_EVENTS)
643 zlog_warn(
644 "%s: channel%s expected to be in PIM_IFASSERT_I_AM_WINNER state",
645 __func__, ch->sg_str);
646 return -1;
647 }
648
649 pim_assert_timer_reset(ch);
650
651 if (pim_assert_send(ch)) {
652 zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
653 __func__, ch->sg_str, ch->interface->name);
654 return -1;
655 }
656
657 return 0;
658 }
659
660 /*
661 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
662
663 (S,G) Assert State machine Actions
664
665 A4: Send AssertCancel(S,G).
666 Delete assert info (AssertWinner(S,G,I) and
667 AssertWinnerMetric(S,G,I) will then return their default
668 values).
669 */
670 void assert_action_a4(struct pim_ifchannel *ch)
671 {
672 if (pim_assert_cancel(ch)) {
673 zlog_warn("%s: failure sending AssertCancel%s on interface %s",
674 __func__, ch->sg_str, ch->interface->name);
675 /* log warning only */
676 }
677
678 assert_action_a5(ch);
679
680 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
681 if (PIM_DEBUG_PIM_EVENTS)
682 zlog_warn(
683 "%s: channel%s not in PIM_IFASSERT_NOINFO state as expected",
684 __func__, ch->sg_str);
685 }
686 }
687
688 /*
689 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
690
691 (S,G) Assert State machine Actions
692
693 A5: Delete assert info (AssertWinner(S,G,I) and
694 AssertWinnerMetric(S,G,I) will then return their default values).
695 */
696 void assert_action_a5(struct pim_ifchannel *ch)
697 {
698 reset_ifassert_state(ch);
699 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
700 if (PIM_DEBUG_PIM_EVENTS)
701 zlog_warn(
702 "%s: channel%s not in PIM_IFSSERT_NOINFO state as expected",
703 __func__, ch->sg_str);
704 }
705 }
706
707 /*
708 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
709
710 (S,G) Assert State machine Actions
711
712 A6: Store new assert winner as AssertWinner(S,G,I) and assert
713 winner metric as AssertWinnerMetric(S,G,I).
714 Set Assert Timer to Assert_Time.
715 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
716 set SPTbit(S,G) to true.
717 */
718 static void assert_action_a6(struct pim_ifchannel *ch,
719 struct pim_assert_metric winner_metric)
720 {
721 assert_action_a2(ch, winner_metric);
722
723 /*
724 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
725 SPTbit(S,G) to true.
726 */
727 if (ch->upstream->rpf.source_nexthop.interface == ch->interface)
728 if (ch->upstream->join_state == PIM_UPSTREAM_JOINED)
729 ch->upstream->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
730
731 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) {
732 if (PIM_DEBUG_PIM_EVENTS)
733 zlog_warn(
734 "%s: channel%s not in PIM_IFASSERT_I_AM_LOSER state as expected",
735 __func__, ch->sg_str);
736 }
737 }