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