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