Line data Source code
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 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 : */
19 :
20 : #include <zebra.h>
21 :
22 : #include "log.h"
23 : #include "prefix.h"
24 : #include "if.h"
25 :
26 : #include "pimd.h"
27 : #include "pim_instance.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_zebra.h"
39 : #include "pim_ifchannel.h"
40 :
41 : static int assert_action_a3(struct pim_ifchannel *ch);
42 : static void assert_action_a2(struct pim_ifchannel *ch,
43 : struct pim_assert_metric winner_metric);
44 : static void assert_action_a6(struct pim_ifchannel *ch,
45 : struct pim_assert_metric winner_metric);
46 :
47 15 : void pim_ifassert_winner_set(struct pim_ifchannel *ch,
48 : enum pim_ifassert_state new_state, pim_addr winner,
49 : struct pim_assert_metric winner_metric)
50 : {
51 15 : struct pim_interface *pim_ifp = ch->interface->info;
52 15 : int winner_changed = !!pim_addr_cmp(ch->ifassert_winner, winner);
53 15 : int metric_changed = !pim_assert_metric_match(
54 15 : &ch->ifassert_winner_metric, &winner_metric);
55 15 : enum pim_rpf_result rpf_result;
56 15 : struct pim_rpf old_rpf;
57 :
58 15 : if (PIM_DEBUG_PIM_EVENTS) {
59 0 : if (ch->ifassert_state != new_state) {
60 0 : zlog_debug(
61 : "%s: (S,G)=%s assert state changed from %s to %s on interface %s",
62 : __func__, ch->sg_str,
63 : pim_ifchannel_ifassert_name(ch->ifassert_state),
64 : pim_ifchannel_ifassert_name(new_state),
65 : ch->interface->name);
66 : }
67 :
68 0 : if (winner_changed)
69 0 : zlog_debug(
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);
73 : } /* PIM_DEBUG_PIM_EVENTS */
74 :
75 15 : ch->ifassert_state = new_state;
76 15 : ch->ifassert_winner = winner;
77 15 : ch->ifassert_winner_metric = winner_metric;
78 15 : ch->ifassert_creation = pim_time_monotonic_sec();
79 :
80 15 : if (winner_changed || metric_changed) {
81 0 : if (winner_changed) {
82 0 : old_rpf.source_nexthop.interface =
83 0 : ch->upstream->rpf.source_nexthop.interface;
84 0 : rpf_result = pim_rpf_update(pim_ifp->pim, ch->upstream,
85 : &old_rpf, __func__);
86 0 : if (rpf_result == PIM_RPF_CHANGED ||
87 0 : (rpf_result == PIM_RPF_FAILURE &&
88 0 : old_rpf.source_nexthop.interface))
89 0 : pim_zebra_upstream_rpf_changed(
90 : pim_ifp->pim, ch->upstream, &old_rpf);
91 : /* update kernel multicast forwarding cache (MFC) */
92 0 : if (ch->upstream->rpf.source_nexthop.interface &&
93 0 : ch->upstream->channel_oil)
94 0 : pim_upstream_mroute_iif_update(
95 : ch->upstream->channel_oil, __func__);
96 : }
97 0 : pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
98 0 : pim_ifchannel_update_could_assert(ch);
99 0 : pim_ifchannel_update_assert_tracking_desired(ch);
100 : }
101 15 : }
102 :
103 0 : static void on_trace(const char *label, struct interface *ifp, pim_addr src)
104 : {
105 0 : if (PIM_DEBUG_PIM_TRACE)
106 0 : zlog_debug("%s: from %pPAs on %s", label, &src, ifp->name);
107 0 : }
108 :
109 0 : static int preferred_assert(const struct pim_ifchannel *ch,
110 : const struct pim_assert_metric *recv_metric)
111 : {
112 0 : return pim_assert_metric_better(recv_metric,
113 : &ch->ifassert_winner_metric);
114 : }
115 :
116 0 : static int acceptable_assert(const struct pim_assert_metric *my_metric,
117 : const struct pim_assert_metric *recv_metric)
118 : {
119 0 : return pim_assert_metric_better(recv_metric, my_metric);
120 : }
121 :
122 0 : static int inferior_assert(const struct pim_assert_metric *my_metric,
123 : const struct pim_assert_metric *recv_metric)
124 : {
125 0 : return pim_assert_metric_better(my_metric, recv_metric);
126 : }
127 :
128 0 : static int cancel_assert(const struct pim_assert_metric *recv_metric)
129 : {
130 0 : return (recv_metric->metric_preference
131 : == PIM_ASSERT_METRIC_PREFERENCE_MAX)
132 0 : && (recv_metric->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX);
133 : }
134 :
135 0 : static void if_could_assert_do_a1(const char *caller, struct pim_ifchannel *ch)
136 : {
137 0 : if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
138 0 : if (assert_action_a1(ch)) {
139 0 : zlog_warn(
140 : "%s: %s: (S,G)=%s assert_action_a1 failure on interface %s",
141 : __func__, caller, ch->sg_str,
142 : ch->interface->name);
143 : /* log warning only */
144 : }
145 : }
146 0 : }
147 :
148 0 : static int dispatch_assert(struct interface *ifp, pim_addr source_addr,
149 : pim_addr group_addr,
150 : struct pim_assert_metric recv_metric)
151 : {
152 0 : struct pim_ifchannel *ch;
153 0 : pim_sgaddr sg;
154 :
155 0 : memset(&sg, 0, sizeof(sg));
156 0 : sg.src = source_addr;
157 0 : sg.grp = group_addr;
158 0 : ch = pim_ifchannel_add(ifp, &sg, 0, 0);
159 :
160 0 : switch (ch->ifassert_state) {
161 0 : case PIM_IFASSERT_NOINFO:
162 0 : if (recv_metric.rpt_bit_flag) {
163 : /* RPT bit set */
164 0 : if_could_assert_do_a1(__func__, ch);
165 : } else {
166 : /* RPT bit clear */
167 0 : if (inferior_assert(&ch->ifassert_my_metric,
168 : &recv_metric)) {
169 0 : if_could_assert_do_a1(__func__, ch);
170 0 : } else if (acceptable_assert(&ch->ifassert_my_metric,
171 : &recv_metric)) {
172 0 : if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(
173 : ch->flags)) {
174 0 : assert_action_a6(ch, recv_metric);
175 : }
176 : }
177 : }
178 : break;
179 : case PIM_IFASSERT_I_AM_WINNER:
180 0 : if (preferred_assert(ch, &recv_metric)) {
181 0 : assert_action_a2(ch, recv_metric);
182 : } else {
183 0 : if (inferior_assert(&ch->ifassert_my_metric,
184 : &recv_metric)) {
185 0 : assert_action_a3(ch);
186 : }
187 : }
188 : break;
189 0 : case PIM_IFASSERT_I_AM_LOSER:
190 0 : if (!pim_addr_cmp(recv_metric.ip_address,
191 : ch->ifassert_winner)) {
192 : /* Assert from current winner */
193 :
194 0 : if (cancel_assert(&recv_metric)) {
195 0 : assert_action_a5(ch);
196 : } else {
197 0 : if (inferior_assert(&ch->ifassert_my_metric,
198 : &recv_metric)) {
199 0 : assert_action_a5(ch);
200 0 : } else if (acceptable_assert(
201 0 : &ch->ifassert_my_metric,
202 : &recv_metric)) {
203 0 : if (!recv_metric.rpt_bit_flag) {
204 0 : assert_action_a2(ch,
205 : recv_metric);
206 : }
207 : }
208 : }
209 0 : } else if (preferred_assert(ch, &recv_metric)) {
210 0 : assert_action_a2(ch, recv_metric);
211 : }
212 : break;
213 0 : default: {
214 0 : zlog_warn(
215 : "%s: (S,G)=%s invalid assert state %d on interface %s",
216 : __func__, ch->sg_str, ch->ifassert_state, ifp->name);
217 : }
218 0 : return -2;
219 : }
220 :
221 : return 0;
222 : }
223 :
224 0 : int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh,
225 : pim_addr src_addr, uint8_t *buf, int buf_size)
226 : {
227 0 : pim_sgaddr sg;
228 0 : pim_addr msg_source_addr;
229 0 : bool wrong_af = false;
230 0 : struct pim_assert_metric msg_metric;
231 0 : int offset;
232 0 : uint8_t *curr;
233 0 : int curr_size;
234 0 : struct pim_interface *pim_ifp = NULL;
235 :
236 0 : on_trace(__func__, ifp, src_addr);
237 :
238 0 : curr = buf;
239 0 : curr_size = buf_size;
240 :
241 : /*
242 : Parse assert group addr
243 : */
244 0 : memset(&sg, 0, sizeof(sg));
245 0 : offset = pim_parse_addr_group(&sg, curr, curr_size);
246 0 : if (offset < 1) {
247 0 : zlog_warn(
248 : "%s: pim_parse_addr_group() failure: from %pPAs on %s",
249 : __func__, &src_addr, ifp->name);
250 0 : return -1;
251 : }
252 0 : curr += offset;
253 0 : curr_size -= offset;
254 :
255 : /*
256 : Parse assert source addr
257 : */
258 0 : offset = pim_parse_addr_ucast(&msg_source_addr, curr, curr_size,
259 : &wrong_af);
260 0 : if (offset < 1 || wrong_af) {
261 0 : zlog_warn(
262 : "%s: pim_parse_addr_ucast() failure: from %pPAs on %s",
263 : __func__, &src_addr, ifp->name);
264 0 : return -2;
265 : }
266 0 : curr += offset;
267 0 : curr_size -= offset;
268 :
269 0 : if (curr_size < 8) {
270 0 : zlog_warn(
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);
273 0 : return -3;
274 : }
275 :
276 : /*
277 : Parse assert metric preference
278 : */
279 :
280 0 : msg_metric.metric_preference = pim_read_uint32_host(curr);
281 :
282 0 : msg_metric.rpt_bit_flag = msg_metric.metric_preference
283 0 : & 0x80000000; /* save highest bit */
284 0 : msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */
285 :
286 0 : curr += 4;
287 :
288 : /*
289 : Parse assert route metric
290 : */
291 :
292 0 : msg_metric.route_metric = pim_read_uint32_host(curr);
293 :
294 0 : if (PIM_DEBUG_PIM_TRACE)
295 0 : zlog_debug(
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,
298 : &sg.grp, msg_metric.metric_preference,
299 : msg_metric.route_metric,
300 : PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag));
301 :
302 0 : msg_metric.ip_address = src_addr;
303 :
304 0 : pim_ifp = ifp->info;
305 0 : assert(pim_ifp);
306 :
307 0 : if (pim_ifp->pim_passive_enable) {
308 0 : if (PIM_DEBUG_PIM_PACKETS)
309 0 : zlog_debug(
310 : "skip receiving PIM message on passive interface %s",
311 : ifp->name);
312 0 : return 0;
313 : }
314 :
315 0 : ++pim_ifp->pim_ifstat_assert_recv;
316 :
317 0 : return dispatch_assert(ifp, msg_source_addr, sg.grp, msg_metric);
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 : */
331 6 : int pim_assert_metric_better(const struct pim_assert_metric *m1,
332 : const struct pim_assert_metric *m2)
333 : {
334 6 : if (m1->rpt_bit_flag < m2->rpt_bit_flag)
335 : return 1;
336 2 : if (m1->rpt_bit_flag > m2->rpt_bit_flag)
337 : return 0;
338 :
339 2 : if (m1->metric_preference < m2->metric_preference)
340 : return 1;
341 2 : if (m1->metric_preference > m2->metric_preference)
342 : return 0;
343 :
344 2 : if (m1->route_metric < m2->route_metric)
345 : return 1;
346 2 : if (m1->route_metric > m2->route_metric)
347 : return 0;
348 :
349 2 : return pim_addr_cmp(m1->ip_address, m2->ip_address) > 0;
350 : }
351 :
352 21 : int pim_assert_metric_match(const struct pim_assert_metric *m1,
353 : const struct pim_assert_metric *m2)
354 : {
355 21 : if (m1->rpt_bit_flag != m2->rpt_bit_flag)
356 : return 0;
357 15 : if (m1->metric_preference != m2->metric_preference)
358 : return 0;
359 15 : if (m1->route_metric != m2->route_metric)
360 : return 0;
361 :
362 15 : return !pim_addr_cmp(m1->ip_address, m2->ip_address);
363 : }
364 :
365 0 : int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp,
366 : pim_addr group_addr, pim_addr source_addr,
367 : uint32_t metric_preference, uint32_t route_metric,
368 : uint32_t rpt_bit_flag)
369 : {
370 0 : struct pim_interface *pim_ifp = ifp->info;
371 0 : uint8_t *buf_pastend = pim_msg + buf_size;
372 0 : uint8_t *pim_msg_curr;
373 0 : int pim_msg_size;
374 0 : int remain;
375 :
376 0 : pim_msg_curr =
377 : pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */
378 :
379 : /* Encode group */
380 0 : remain = buf_pastend - pim_msg_curr;
381 0 : pim_msg_curr = pim_msg_addr_encode_group(pim_msg_curr, group_addr);
382 0 : if (!pim_msg_curr) {
383 0 : zlog_warn(
384 : "%s: failure encoding group address %pPA: space left=%d",
385 : __func__, &group_addr, remain);
386 0 : return -1;
387 : }
388 :
389 : /* Encode source */
390 0 : remain = buf_pastend - pim_msg_curr;
391 0 : pim_msg_curr = pim_msg_addr_encode_ucast(pim_msg_curr, source_addr);
392 0 : if (!pim_msg_curr) {
393 0 : zlog_warn(
394 : "%s: failure encoding source address %pPA: space left=%d",
395 : __func__, &source_addr, remain);
396 0 : return -2;
397 : }
398 :
399 : /* Metric preference */
400 0 : pim_write_uint32(pim_msg_curr,
401 : rpt_bit_flag ? metric_preference | 0x80000000
402 : : metric_preference);
403 0 : pim_msg_curr += 4;
404 :
405 : /* Route metric */
406 0 : pim_write_uint32(pim_msg_curr, route_metric);
407 0 : pim_msg_curr += 4;
408 :
409 : /*
410 : Add PIM header
411 : */
412 0 : pim_msg_size = pim_msg_curr - pim_msg;
413 0 : 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);
416 :
417 0 : return pim_msg_size;
418 : }
419 :
420 0 : static int pim_assert_do(struct pim_ifchannel *ch,
421 : struct pim_assert_metric metric)
422 : {
423 0 : struct interface *ifp;
424 0 : struct pim_interface *pim_ifp;
425 0 : uint8_t pim_msg[1000];
426 0 : int pim_msg_size;
427 :
428 0 : ifp = ch->interface;
429 0 : if (!ifp) {
430 0 : if (PIM_DEBUG_PIM_TRACE)
431 0 : zlog_debug("%s: channel%s has no associated interface!",
432 : __func__, ch->sg_str);
433 0 : return -1;
434 : }
435 0 : pim_ifp = ifp->info;
436 0 : if (!pim_ifp) {
437 0 : if (PIM_DEBUG_PIM_TRACE)
438 0 : zlog_debug(
439 : "%s: channel %s pim not enabled on interface: %s",
440 : __func__, ch->sg_str, ifp->name);
441 0 : return -1;
442 : }
443 :
444 0 : pim_msg_size =
445 0 : 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 0 : if (pim_msg_size < 1) {
449 0 : zlog_warn(
450 : "%s: failure building PIM assert message: msg_size=%d",
451 : __func__, pim_msg_size);
452 0 : 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 0 : pim_hello_require(ifp);
465 :
466 0 : if (PIM_DEBUG_PIM_TRACE) {
467 0 : zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
468 : __func__, ifp->name, ch->sg_str,
469 : metric.metric_preference, metric.route_metric,
470 : PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
471 : }
472 0 : if (!pim_ifp->pim_passive_enable)
473 0 : ++pim_ifp->pim_ifstat_assert_send;
474 :
475 0 : if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
476 : qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
477 : ifp)) {
478 0 : zlog_warn("%s: could not send PIM message on interface %s",
479 : __func__, ifp->name);
480 0 : return -3;
481 : }
482 :
483 : return 0;
484 : }
485 :
486 0 : int pim_assert_send(struct pim_ifchannel *ch)
487 : {
488 0 : return pim_assert_do(ch, ch->ifassert_my_metric);
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 : */
497 0 : static int pim_assert_cancel(struct pim_ifchannel *ch)
498 : {
499 0 : struct pim_assert_metric metric;
500 :
501 0 : metric.rpt_bit_flag = 0;
502 0 : metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
503 0 : metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
504 0 : metric.ip_address = ch->sg.src;
505 :
506 0 : return pim_assert_do(ch, metric);
507 : }
508 :
509 0 : static void on_assert_timer(struct thread *t)
510 : {
511 0 : struct pim_ifchannel *ch;
512 0 : struct interface *ifp;
513 :
514 0 : ch = THREAD_ARG(t);
515 :
516 0 : ifp = ch->interface;
517 :
518 0 : if (PIM_DEBUG_PIM_TRACE) {
519 0 : zlog_debug("%s: (S,G)=%s timer expired on interface %s",
520 : __func__, ch->sg_str, ifp->name);
521 : }
522 :
523 0 : ch->t_ifassert_timer = NULL;
524 :
525 0 : switch (ch->ifassert_state) {
526 0 : case PIM_IFASSERT_I_AM_WINNER:
527 0 : assert_action_a3(ch);
528 0 : break;
529 0 : case PIM_IFASSERT_I_AM_LOSER:
530 0 : assert_action_a5(ch);
531 0 : break;
532 0 : case PIM_IFASSERT_NOINFO: {
533 0 : if (PIM_DEBUG_PIM_EVENTS)
534 0 : zlog_warn(
535 : "%s: (S,G)=%s invalid assert state %d on interface %s",
536 : __func__, ch->sg_str, ch->ifassert_state,
537 : ifp->name);
538 : }
539 : }
540 0 : }
541 :
542 0 : static void assert_timer_off(struct pim_ifchannel *ch)
543 : {
544 0 : if (PIM_DEBUG_PIM_TRACE) {
545 0 : if (ch->t_ifassert_timer) {
546 0 : zlog_debug(
547 : "%s: (S,G)=%s cancelling timer on interface %s",
548 : __func__, ch->sg_str, ch->interface->name);
549 : }
550 : }
551 0 : THREAD_OFF(ch->t_ifassert_timer);
552 0 : }
553 :
554 0 : static void pim_assert_timer_set(struct pim_ifchannel *ch, int interval)
555 : {
556 0 : assert_timer_off(ch);
557 :
558 0 : if (PIM_DEBUG_PIM_TRACE) {
559 0 : zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
560 : __func__, ch->sg_str, interval, ch->interface->name);
561 : }
562 :
563 0 : thread_add_timer(router->master, on_assert_timer, ch, interval,
564 : &ch->t_ifassert_timer);
565 0 : }
566 :
567 0 : static void pim_assert_timer_reset(struct pim_ifchannel *ch)
568 : {
569 0 : pim_assert_timer_set(ch,
570 : PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
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 : */
583 0 : int assert_action_a1(struct pim_ifchannel *ch)
584 : {
585 0 : struct interface *ifp = ch->interface;
586 0 : struct pim_interface *pim_ifp;
587 :
588 0 : pim_ifp = ifp->info;
589 0 : if (!pim_ifp) {
590 0 : zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
591 : __func__, ch->sg_str, ifp->name);
592 0 : return -1; /* must return since pim_ifp is used below */
593 : }
594 :
595 : /* Switch to I_AM_WINNER before performing action_a3 below */
596 0 : pim_ifassert_winner_set(
597 : ch, PIM_IFASSERT_I_AM_WINNER, pim_ifp->primary_address,
598 0 : pim_macro_spt_assert_metric(&ch->upstream->rpf,
599 : pim_ifp->primary_address));
600 :
601 0 : if (assert_action_a3(ch)) {
602 0 : zlog_warn(
603 : "%s: (S,G)=%s assert_action_a3 failure on interface %s",
604 : __func__, ch->sg_str, ifp->name);
605 : /* warning only */
606 : }
607 :
608 0 : if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER) {
609 0 : if (PIM_DEBUG_PIM_EVENTS)
610 0 : zlog_warn(
611 : "%s: channel%s not in expected PIM_IFASSERT_I_AM_WINNER state",
612 : __func__, ch->sg_str);
613 : }
614 :
615 : return 0;
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
624 : winner metric as AssertWinnerMetric(S,G,I).
625 : Set Assert Timer to Assert_Time.
626 : */
627 0 : static void assert_action_a2(struct pim_ifchannel *ch,
628 : struct pim_assert_metric winner_metric)
629 : {
630 0 : pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
631 : winner_metric.ip_address, winner_metric);
632 :
633 0 : pim_assert_timer_set(ch, PIM_ASSERT_TIME);
634 :
635 0 : if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) {
636 0 : if (PIM_DEBUG_PIM_EVENTS)
637 0 : zlog_warn(
638 : "%s: channel%s not in expected PIM_IFASSERT_I_AM_LOSER state",
639 : __func__, ch->sg_str);
640 : }
641 0 : }
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 : */
651 0 : static int assert_action_a3(struct pim_ifchannel *ch)
652 : {
653 0 : if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER) {
654 0 : if (PIM_DEBUG_PIM_EVENTS)
655 0 : zlog_warn(
656 : "%s: channel%s expected to be in PIM_IFASSERT_I_AM_WINNER state",
657 : __func__, ch->sg_str);
658 0 : return -1;
659 : }
660 :
661 0 : pim_assert_timer_reset(ch);
662 :
663 0 : if (pim_assert_send(ch)) {
664 0 : zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
665 : __func__, ch->sg_str, ch->interface->name);
666 0 : return -1;
667 : }
668 :
669 : return 0;
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).
678 : Delete assert info (AssertWinner(S,G,I) and
679 : AssertWinnerMetric(S,G,I) will then return their default
680 : values).
681 : */
682 0 : void assert_action_a4(struct pim_ifchannel *ch)
683 : {
684 0 : if (pim_assert_cancel(ch)) {
685 0 : zlog_warn("%s: failure sending AssertCancel%s on interface %s",
686 : __func__, ch->sg_str, ch->interface->name);
687 : /* log warning only */
688 : }
689 :
690 0 : assert_action_a5(ch);
691 :
692 0 : if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
693 0 : if (PIM_DEBUG_PIM_EVENTS)
694 0 : zlog_warn(
695 : "%s: channel%s not in PIM_IFASSERT_NOINFO state as expected",
696 : __func__, ch->sg_str);
697 : }
698 0 : }
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 : */
708 4 : void assert_action_a5(struct pim_ifchannel *ch)
709 : {
710 4 : reset_ifassert_state(ch);
711 4 : if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
712 0 : if (PIM_DEBUG_PIM_EVENTS)
713 0 : zlog_warn(
714 : "%s: channel%s not in PIM_IFSSERT_NOINFO state as expected",
715 : __func__, ch->sg_str);
716 : }
717 4 : }
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
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)
728 : set SPTbit(S,G) to true.
729 : */
730 0 : static void assert_action_a6(struct pim_ifchannel *ch,
731 : struct pim_assert_metric winner_metric)
732 : {
733 0 : assert_action_a2(ch, winner_metric);
734 :
735 : /*
736 : If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
737 : SPTbit(S,G) to true.
738 : */
739 0 : if (ch->upstream->rpf.source_nexthop.interface == ch->interface)
740 0 : if (ch->upstream->join_state == PIM_UPSTREAM_JOINED)
741 0 : ch->upstream->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
742 :
743 0 : if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) {
744 0 : if (PIM_DEBUG_PIM_EVENTS)
745 0 : zlog_warn(
746 : "%s: channel%s not in PIM_IFASSERT_I_AM_LOSER state as expected",
747 : __func__, ch->sg_str);
748 : }
749 0 : }
|