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