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