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