]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_assert.c
Merge pull request #9953 from donaldsharp/system_route_replace
[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 uint8_t *buf_pastend = pim_msg + buf_size;
342 uint8_t *pim_msg_curr;
343 int pim_msg_size;
344 int remain;
345
346 pim_msg_curr =
347 pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */
348
349 /* Encode group */
350 remain = buf_pastend - pim_msg_curr;
351 pim_msg_curr = pim_msg_addr_encode_group(pim_msg_curr, group_addr);
352 if (!pim_msg_curr) {
353 zlog_warn(
354 "%s: failure encoding group address %pPA: space left=%d",
355 __func__, &group_addr, remain);
356 return -1;
357 }
358
359 /* Encode source */
360 remain = buf_pastend - pim_msg_curr;
361 pim_msg_curr = pim_msg_addr_encode_ucast(pim_msg_curr, source_addr);
362 if (!pim_msg_curr) {
363 zlog_warn(
364 "%s: failure encoding source address %pPA: space left=%d",
365 __func__, &source_addr, remain);
366 return -2;
367 }
368
369 /* Metric preference */
370 pim_write_uint32(pim_msg_curr,
371 rpt_bit_flag ? metric_preference | 0x80000000
372 : metric_preference);
373 pim_msg_curr += 4;
374
375 /* Route metric */
376 pim_write_uint32(pim_msg_curr, route_metric);
377 pim_msg_curr += 4;
378
379 /*
380 Add PIM header
381 */
382 pim_msg_size = pim_msg_curr - pim_msg;
383 pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_ASSERT, false);
384
385 return pim_msg_size;
386 }
387
388 static int pim_assert_do(struct pim_ifchannel *ch,
389 struct pim_assert_metric metric)
390 {
391 struct interface *ifp;
392 struct pim_interface *pim_ifp;
393 uint8_t pim_msg[1000];
394 int pim_msg_size;
395
396 ifp = ch->interface;
397 if (!ifp) {
398 if (PIM_DEBUG_PIM_TRACE)
399 zlog_debug("%s: channel%s has no associated interface!",
400 __func__, ch->sg_str);
401 return -1;
402 }
403 pim_ifp = ifp->info;
404 if (!pim_ifp) {
405 if (PIM_DEBUG_PIM_TRACE)
406 zlog_debug(
407 "%s: channel %s pim not enabled on interface: %s",
408 __func__, ch->sg_str, ifp->name);
409 return -1;
410 }
411
412 pim_msg_size =
413 pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp, ch->sg.grp,
414 ch->sg.src, metric.metric_preference,
415 metric.route_metric, metric.rpt_bit_flag);
416 if (pim_msg_size < 1) {
417 zlog_warn(
418 "%s: failure building PIM assert message: msg_size=%d",
419 __func__, pim_msg_size);
420 return -2;
421 }
422
423 /*
424 RFC 4601: 4.3.1. Sending Hello Messages
425
426 Thus, if a router needs to send a Join/Prune or Assert message on
427 an interface on which it has not yet sent a Hello message with the
428 currently configured IP address, then it MUST immediately send the
429 relevant Hello message without waiting for the Hello Timer to
430 expire, followed by the Join/Prune or Assert message.
431 */
432 pim_hello_require(ifp);
433
434 if (PIM_DEBUG_PIM_TRACE) {
435 zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
436 __func__, ifp->name, ch->sg_str,
437 metric.metric_preference, metric.route_metric,
438 PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
439 }
440 ++pim_ifp->pim_ifstat_assert_send;
441
442 if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
443 qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
444 ifp->name)) {
445 zlog_warn("%s: could not send PIM message on interface %s",
446 __func__, ifp->name);
447 return -3;
448 }
449
450 return 0;
451 }
452
453 int pim_assert_send(struct pim_ifchannel *ch)
454 {
455 return pim_assert_do(ch, ch->ifassert_my_metric);
456 }
457
458 /*
459 RFC 4601: 4.6.4. AssertCancel Messages
460
461 An AssertCancel(S,G) is an infinite metric assert with the RPT bit
462 set that names S as the source.
463 */
464 static int pim_assert_cancel(struct pim_ifchannel *ch)
465 {
466 struct pim_assert_metric metric;
467
468 metric.rpt_bit_flag = 0;
469 metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
470 metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
471 metric.ip_address = ch->sg.src;
472
473 return pim_assert_do(ch, metric);
474 }
475
476 static void on_assert_timer(struct thread *t)
477 {
478 struct pim_ifchannel *ch;
479 struct interface *ifp;
480
481 ch = THREAD_ARG(t);
482
483 ifp = ch->interface;
484
485 if (PIM_DEBUG_PIM_TRACE) {
486 zlog_debug("%s: (S,G)=%s timer expired on interface %s",
487 __func__, ch->sg_str, ifp->name);
488 }
489
490 ch->t_ifassert_timer = NULL;
491
492 switch (ch->ifassert_state) {
493 case PIM_IFASSERT_I_AM_WINNER:
494 assert_action_a3(ch);
495 break;
496 case PIM_IFASSERT_I_AM_LOSER:
497 assert_action_a5(ch);
498 break;
499 default: {
500 if (PIM_DEBUG_PIM_EVENTS)
501 zlog_warn(
502 "%s: (S,G)=%s invalid assert state %d on interface %s",
503 __func__, ch->sg_str, ch->ifassert_state,
504 ifp->name);
505 }
506 }
507 }
508
509 static void assert_timer_off(struct pim_ifchannel *ch)
510 {
511 if (PIM_DEBUG_PIM_TRACE) {
512 if (ch->t_ifassert_timer) {
513 zlog_debug(
514 "%s: (S,G)=%s cancelling timer on interface %s",
515 __func__, ch->sg_str, ch->interface->name);
516 }
517 }
518 THREAD_OFF(ch->t_ifassert_timer);
519 }
520
521 static void pim_assert_timer_set(struct pim_ifchannel *ch, int interval)
522 {
523 assert_timer_off(ch);
524
525 if (PIM_DEBUG_PIM_TRACE) {
526 zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
527 __func__, ch->sg_str, interval, ch->interface->name);
528 }
529
530 thread_add_timer(router->master, on_assert_timer, ch, interval,
531 &ch->t_ifassert_timer);
532 }
533
534 static void pim_assert_timer_reset(struct pim_ifchannel *ch)
535 {
536 pim_assert_timer_set(ch,
537 PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
538 }
539
540 /*
541 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
542
543 (S,G) Assert State machine Actions
544
545 A1: Send Assert(S,G).
546 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
547 Store self as AssertWinner(S,G,I).
548 Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
549 */
550 int assert_action_a1(struct pim_ifchannel *ch)
551 {
552 struct interface *ifp = ch->interface;
553 struct pim_interface *pim_ifp;
554
555 pim_ifp = ifp->info;
556 if (!pim_ifp) {
557 zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
558 __func__, ch->sg_str, ifp->name);
559 return -1; /* must return since pim_ifp is used below */
560 }
561
562 /* Switch to I_AM_WINNER before performing action_a3 below */
563 pim_ifassert_winner_set(
564 ch, PIM_IFASSERT_I_AM_WINNER, pim_ifp->primary_address,
565 pim_macro_spt_assert_metric(&ch->upstream->rpf,
566 pim_ifp->primary_address));
567
568 if (assert_action_a3(ch)) {
569 zlog_warn(
570 "%s: (S,G)=%s assert_action_a3 failure on interface %s",
571 __func__, ch->sg_str, ifp->name);
572 /* warning only */
573 }
574
575 if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER) {
576 if (PIM_DEBUG_PIM_EVENTS)
577 zlog_warn(
578 "%s: channel%s not in expected PIM_IFASSERT_I_AM_WINNER state",
579 __func__, ch->sg_str);
580 }
581
582 return 0;
583 }
584
585 /*
586 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
587
588 (S,G) Assert State machine Actions
589
590 A2: Store new assert winner as AssertWinner(S,G,I) and assert
591 winner metric as AssertWinnerMetric(S,G,I).
592 Set Assert Timer to Assert_Time.
593 */
594 static void assert_action_a2(struct pim_ifchannel *ch,
595 struct pim_assert_metric winner_metric)
596 {
597 pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
598 winner_metric.ip_address, winner_metric);
599
600 pim_assert_timer_set(ch, PIM_ASSERT_TIME);
601
602 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) {
603 if (PIM_DEBUG_PIM_EVENTS)
604 zlog_warn(
605 "%s: channel%s not in expected PIM_IFASSERT_I_AM_LOSER state",
606 __func__, ch->sg_str);
607 }
608 }
609
610 /*
611 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
612
613 (S,G) Assert State machine Actions
614
615 A3: Send Assert(S,G).
616 Set Assert Timer to (Assert_Time - Assert_Override_Interval).
617 */
618 static int assert_action_a3(struct pim_ifchannel *ch)
619 {
620 if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER) {
621 if (PIM_DEBUG_PIM_EVENTS)
622 zlog_warn(
623 "%s: channel%s expected to be in PIM_IFASSERT_I_AM_WINNER state",
624 __func__, ch->sg_str);
625 return -1;
626 }
627
628 pim_assert_timer_reset(ch);
629
630 if (pim_assert_send(ch)) {
631 zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
632 __func__, ch->sg_str, ch->interface->name);
633 return -1;
634 }
635
636 return 0;
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 A4: Send AssertCancel(S,G).
645 Delete assert info (AssertWinner(S,G,I) and
646 AssertWinnerMetric(S,G,I) will then return their default
647 values).
648 */
649 void assert_action_a4(struct pim_ifchannel *ch)
650 {
651 if (pim_assert_cancel(ch)) {
652 zlog_warn("%s: failure sending AssertCancel%s on interface %s",
653 __func__, ch->sg_str, ch->interface->name);
654 /* log warning only */
655 }
656
657 assert_action_a5(ch);
658
659 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
660 if (PIM_DEBUG_PIM_EVENTS)
661 zlog_warn(
662 "%s: channel%s not in PIM_IFASSERT_NOINFO state as expected",
663 __func__, ch->sg_str);
664 }
665 }
666
667 /*
668 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
669
670 (S,G) Assert State machine Actions
671
672 A5: Delete assert info (AssertWinner(S,G,I) and
673 AssertWinnerMetric(S,G,I) will then return their default values).
674 */
675 void assert_action_a5(struct pim_ifchannel *ch)
676 {
677 reset_ifassert_state(ch);
678 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
679 if (PIM_DEBUG_PIM_EVENTS)
680 zlog_warn(
681 "%s: channel%s not in PIM_IFSSERT_NOINFO state as expected",
682 __func__, ch->sg_str);
683 }
684 }
685
686 /*
687 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
688
689 (S,G) Assert State machine Actions
690
691 A6: Store new assert winner as AssertWinner(S,G,I) and assert
692 winner metric as AssertWinnerMetric(S,G,I).
693 Set Assert Timer to Assert_Time.
694 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
695 set SPTbit(S,G) to true.
696 */
697 static void assert_action_a6(struct pim_ifchannel *ch,
698 struct pim_assert_metric winner_metric)
699 {
700 assert_action_a2(ch, winner_metric);
701
702 /*
703 If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
704 SPTbit(S,G) to true.
705 */
706 if (ch->upstream->rpf.source_nexthop.interface == ch->interface)
707 if (ch->upstream->join_state == PIM_UPSTREAM_JOINED)
708 ch->upstream->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
709
710 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) {
711 if (PIM_DEBUG_PIM_EVENTS)
712 zlog_warn(
713 "%s: channel%s not in PIM_IFASSERT_I_AM_LOSER state as expected",
714 __func__, ch->sg_str);
715 }
716 }