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