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