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