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