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