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