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