Annotation of embedaddon/quagga/pimd/pim_ifchannel.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 "linklist.h"
26: #include "thread.h"
27: #include "memory.h"
28:
29: #include "pimd.h"
30: #include "pim_str.h"
31: #include "pim_iface.h"
32: #include "pim_ifchannel.h"
33: #include "pim_zebra.h"
34: #include "pim_time.h"
35: #include "pim_msg.h"
36: #include "pim_pim.h"
37: #include "pim_join.h"
38: #include "pim_rpf.h"
39: #include "pim_macro.h"
40:
41: void pim_ifchannel_free(struct pim_ifchannel *ch)
42: {
43: zassert(!ch->t_ifjoin_expiry_timer);
44: zassert(!ch->t_ifjoin_prune_pending_timer);
45: zassert(!ch->t_ifassert_timer);
46:
47: XFREE(MTYPE_PIM_IFCHANNEL, ch);
48: }
49:
50: void pim_ifchannel_delete(struct pim_ifchannel *ch)
51: {
52: struct pim_interface *pim_ifp;
53:
54: pim_ifp = ch->interface->info;
55: zassert(pim_ifp);
56:
57: if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) {
58: pim_upstream_update_join_desired(ch->upstream);
59: }
60:
61: pim_upstream_del(ch->upstream);
62:
63: THREAD_OFF(ch->t_ifjoin_expiry_timer);
64: THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
65: THREAD_OFF(ch->t_ifassert_timer);
66:
67: /*
68: notice that listnode_delete() can't be moved
69: into pim_ifchannel_free() because the later is
70: called by list_delete_all_node()
71: */
72: listnode_delete(pim_ifp->pim_ifchannel_list, ch);
73:
74: pim_ifchannel_free(ch);
75: }
76:
77: #define IFCHANNEL_NOINFO(ch) \
78: ( \
79: ((ch)->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO) \
80: && \
81: ((ch)->ifjoin_state == PIM_IFJOIN_NOINFO) \
82: && \
83: ((ch)->ifassert_state == PIM_IFASSERT_NOINFO) \
84: )
85:
86: static void delete_on_noinfo(struct pim_ifchannel *ch)
87: {
88: if (IFCHANNEL_NOINFO(ch)) {
89:
90: /* In NOINFO state, timers should have been cleared */
91: zassert(!ch->t_ifjoin_expiry_timer);
92: zassert(!ch->t_ifjoin_prune_pending_timer);
93: zassert(!ch->t_ifassert_timer);
94:
95: pim_ifchannel_delete(ch);
96: }
97: }
98:
99: void pim_ifchannel_ifjoin_switch(const char *caller,
100: struct pim_ifchannel *ch,
101: enum pim_ifjoin_state new_state)
102: {
103: enum pim_ifjoin_state old_state = ch->ifjoin_state;
104:
105: if (old_state == new_state) {
106: if (PIM_DEBUG_PIM_EVENTS) {
107: zlog_debug("%s calledby %s: non-transition on state %d (%s)",
108: __PRETTY_FUNCTION__, caller, new_state,
109: pim_ifchannel_ifjoin_name(new_state));
110: }
111: return;
112: }
113:
114: zassert(old_state != new_state);
115:
116: ch->ifjoin_state = new_state;
117:
118: /* Transition to/from NOINFO ? */
119: if (
120: (old_state == PIM_IFJOIN_NOINFO)
121: ||
122: (new_state == PIM_IFJOIN_NOINFO)
123: ) {
124:
125: if (PIM_DEBUG_PIM_EVENTS) {
126: char src_str[100];
127: char grp_str[100];
128: pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
129: pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
130: zlog_debug("PIM_IFCHANNEL_%s: (S,G)=(%s,%s) on interface %s",
131: ((new_state == PIM_IFJOIN_NOINFO) ? "DOWN" : "UP"),
132: src_str, grp_str, ch->interface->name);
133: }
134:
135: /*
136: Record uptime of state transition to/from NOINFO
137: */
138: ch->ifjoin_creation = pim_time_monotonic_sec();
139:
140: pim_upstream_update_join_desired(ch->upstream);
141: pim_ifchannel_update_could_assert(ch);
142: pim_ifchannel_update_assert_tracking_desired(ch);
143: }
144: }
145:
146: const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state)
147: {
148: switch (ifjoin_state) {
149: case PIM_IFJOIN_NOINFO: return "NOINFO";
150: case PIM_IFJOIN_JOIN: return "JOIN";
151: case PIM_IFJOIN_PRUNE_PENDING: return "PRUNEP";
152: }
153:
154: return "ifjoin_bad_state";
155: }
156:
157: const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state)
158: {
159: switch (ifassert_state) {
160: case PIM_IFASSERT_NOINFO: return "NOINFO";
161: case PIM_IFASSERT_I_AM_WINNER: return "WINNER";
162: case PIM_IFASSERT_I_AM_LOSER: return "LOSER";
163: }
164:
165: return "ifassert_bad_state";
166: }
167:
168: /*
169: RFC 4601: 4.6.5. Assert State Macros
170:
171: AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I)
172: defaults to Infinity when in the NoInfo state.
173: */
174: void reset_ifassert_state(struct pim_ifchannel *ch)
175: {
176: THREAD_OFF(ch->t_ifassert_timer);
177:
178: pim_ifassert_winner_set(ch,
179: PIM_IFASSERT_NOINFO,
180: qpim_inaddr_any,
181: qpim_infinite_assert_metric);
182: }
183:
184: static struct pim_ifchannel *pim_ifchannel_new(struct interface *ifp,
185: struct in_addr source_addr,
186: struct in_addr group_addr)
187: {
188: struct pim_ifchannel *ch;
189: struct pim_interface *pim_ifp;
190: struct pim_upstream *up;
191:
192: pim_ifp = ifp->info;
193: zassert(pim_ifp);
194:
195: up = pim_upstream_add(source_addr, group_addr);
196: if (!up) {
197: char src_str[100];
198: char grp_str[100];
199: pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
200: pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
201: zlog_err("%s: could not attach upstream (S,G)=(%s,%s) on interface %s",
202: __PRETTY_FUNCTION__,
203: src_str, grp_str, ifp->name);
204: return 0;
205: }
206:
207: ch = XMALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch));
208: if (!ch) {
209: zlog_err("%s: PIM XMALLOC(%zu) failure",
210: __PRETTY_FUNCTION__, sizeof(*ch));
211: return 0;
212: }
213:
214: ch->flags = 0;
215: ch->upstream = up;
216: ch->interface = ifp;
217: ch->source_addr = source_addr;
218: ch->group_addr = group_addr;
219: ch->local_ifmembership = PIM_IFMEMBERSHIP_NOINFO;
220:
221: ch->ifjoin_state = PIM_IFJOIN_NOINFO;
222: ch->t_ifjoin_expiry_timer = 0;
223: ch->t_ifjoin_prune_pending_timer = 0;
224: ch->ifjoin_creation = 0;
225:
226: /* Assert state */
227: ch->t_ifassert_timer = 0;
228: reset_ifassert_state(ch);
229: if (pim_macro_ch_could_assert_eval(ch))
230: PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
231: else
232: PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
233:
234: if (pim_macro_assert_tracking_desired_eval(ch))
235: PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
236: else
237: PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
238:
239: ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
240:
241: /* Attach to list */
242: listnode_add(pim_ifp->pim_ifchannel_list, ch);
243:
244: zassert(IFCHANNEL_NOINFO(ch));
245:
246: return ch;
247: }
248:
249: struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
250: struct in_addr source_addr,
251: struct in_addr group_addr)
252: {
253: struct pim_interface *pim_ifp;
254: struct listnode *ch_node;
255: struct pim_ifchannel *ch;
256:
257: zassert(ifp);
258:
259: pim_ifp = ifp->info;
260:
261: if (!pim_ifp) {
262: char src_str[100];
263: char grp_str[100];
264: pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
265: pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
266: zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
267: __PRETTY_FUNCTION__,
268: src_str, grp_str,
269: ifp->name);
270: return 0;
271: }
272:
273: for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
274: if (
275: (source_addr.s_addr == ch->source_addr.s_addr) &&
276: (group_addr.s_addr == ch->group_addr.s_addr)
277: ) {
278: return ch;
279: }
280: }
281:
282: return 0;
283: }
284:
285: static void ifmembership_set(struct pim_ifchannel *ch,
286: enum pim_ifmembership membership)
287: {
288: if (ch->local_ifmembership == membership)
289: return;
290:
291: if (PIM_DEBUG_PIM_EVENTS) {
292: char src_str[100];
293: char grp_str[100];
294: pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
295: pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
296: zlog_debug("%s: (S,G)=(%s,%s) membership now is %s on interface %s",
297: __PRETTY_FUNCTION__,
298: src_str, grp_str,
299: membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE" : "NOINFO",
300: ch->interface->name);
301: }
302:
303: ch->local_ifmembership = membership;
304:
305: pim_upstream_update_join_desired(ch->upstream);
306: pim_ifchannel_update_could_assert(ch);
307: pim_ifchannel_update_assert_tracking_desired(ch);
308: }
309:
310:
311: void pim_ifchannel_membership_clear(struct interface *ifp)
312: {
313: struct pim_interface *pim_ifp;
314: struct listnode *ch_node;
315: struct pim_ifchannel *ch;
316:
317: pim_ifp = ifp->info;
318: zassert(pim_ifp);
319:
320: for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
321: ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
322: }
323: }
324:
325: void pim_ifchannel_delete_on_noinfo(struct interface *ifp)
326: {
327: struct pim_interface *pim_ifp;
328: struct listnode *node;
329: struct listnode *next_node;
330: struct pim_ifchannel *ch;
331:
332: pim_ifp = ifp->info;
333: zassert(pim_ifp);
334:
335: for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
336: delete_on_noinfo(ch);
337: }
338: }
339:
340: struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
341: struct in_addr source_addr,
342: struct in_addr group_addr)
343: {
344: struct pim_ifchannel *ch;
345: char src_str[100];
346: char grp_str[100];
347:
348: ch = pim_ifchannel_find(ifp, source_addr, group_addr);
349: if (ch)
350: return ch;
351:
352: ch = pim_ifchannel_new(ifp, source_addr, group_addr);
353: if (ch)
354: return ch;
355:
356: pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
357: pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
358: zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=(%s,%s) on interface %s",
359: __PRETTY_FUNCTION__,
360: src_str, grp_str, ifp->name);
361:
362: return 0;
363: }
364:
365: static void ifjoin_to_noinfo(struct pim_ifchannel *ch)
366: {
367: pim_forward_stop(ch);
368: pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO);
369: delete_on_noinfo(ch);
370: }
371:
372: static int on_ifjoin_expiry_timer(struct thread *t)
373: {
374: struct pim_ifchannel *ch;
375:
376: zassert(t);
377: ch = THREAD_ARG(t);
378: zassert(ch);
379:
380: ch->t_ifjoin_expiry_timer = 0;
381:
382: zassert(ch->ifjoin_state == PIM_IFJOIN_JOIN);
383:
384: ifjoin_to_noinfo(ch);
385: /* ch may have been deleted */
386:
387: return 0;
388: }
389:
390: static void prune_echo(struct interface *ifp,
391: struct in_addr source_addr,
392: struct in_addr group_addr)
393: {
394: struct pim_interface *pim_ifp;
395: struct in_addr neigh_dst_addr;
396:
397: pim_ifp = ifp->info;
398: zassert(pim_ifp);
399:
400: neigh_dst_addr = pim_ifp->primary_address;
401:
402: if (PIM_DEBUG_PIM_EVENTS) {
403: char source_str[100];
404: char group_str[100];
405: char neigh_dst_str[100];
406: pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
407: pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
408: pim_inet4_dump("<neigh?>", neigh_dst_addr, neigh_dst_str, sizeof(neigh_dst_str));
409: zlog_debug("%s: sending PruneEcho(S,G)=(%s,%s) to upstream=%s on interface %s",
410: __PRETTY_FUNCTION__, source_str, group_str, neigh_dst_str, ifp->name);
411: }
412:
413: pim_joinprune_send(ifp, neigh_dst_addr, source_addr, group_addr,
414: 0 /* boolean: send_join=false (prune) */);
415: }
416:
417: static int on_ifjoin_prune_pending_timer(struct thread *t)
418: {
419: struct pim_ifchannel *ch;
420: int send_prune_echo; /* boolean */
421: struct interface *ifp;
422: struct pim_interface *pim_ifp;
423: struct in_addr ch_source;
424: struct in_addr ch_group;
425:
426: zassert(t);
427: ch = THREAD_ARG(t);
428: zassert(ch);
429:
430: ch->t_ifjoin_prune_pending_timer = 0;
431:
432: zassert(ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING);
433:
434: /* Send PruneEcho(S,G) ? */
435: ifp = ch->interface;
436: pim_ifp = ifp->info;
437: send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1);
438:
439: /* Save (S,G) */
440: ch_source = ch->source_addr;
441: ch_group = ch->group_addr;
442:
443: ifjoin_to_noinfo(ch);
444: /* from here ch may have been deleted */
445:
446: if (send_prune_echo)
447: prune_echo(ifp, ch_source, ch_group);
448:
449: return 0;
450: }
451:
452: static void check_recv_upstream(int is_join,
453: struct interface *recv_ifp,
454: struct in_addr upstream,
455: struct in_addr source_addr,
456: struct in_addr group_addr,
457: uint8_t source_flags,
458: int holdtime)
459: {
460: struct pim_upstream *up;
461:
462: /* Upstream (S,G) in Joined state ? */
463: up = pim_upstream_find(source_addr, group_addr);
464: if (!up)
465: return;
466: if (up->join_state != PIM_UPSTREAM_JOINED)
467: return;
468:
469: /* Upstream (S,G) in Joined state */
470:
471: if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
472: /* RPF'(S,G) not found */
473: char src_str[100];
474: char grp_str[100];
475: pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
476: pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
477: zlog_warn("%s %s: RPF'(%s,%s) not found",
478: __FILE__, __PRETTY_FUNCTION__,
479: src_str, grp_str);
480: return;
481: }
482:
483: /* upstream directed to RPF'(S,G) ? */
484: if (upstream.s_addr != up->rpf.rpf_addr.s_addr) {
485: char src_str[100];
486: char grp_str[100];
487: char up_str[100];
488: char rpf_str[100];
489: pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
490: pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
491: pim_inet4_dump("<up?>", upstream, up_str, sizeof(up_str));
492: pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
493: zlog_warn("%s %s: (S,G)=(%s,%s) upstream=%s not directed to RPF'(S,G)=%s on interface %s",
494: __FILE__, __PRETTY_FUNCTION__,
495: src_str, grp_str,
496: up_str, rpf_str, recv_ifp->name);
497: return;
498: }
499: /* upstream directed to RPF'(S,G) */
500:
501: if (is_join) {
502: /* Join(S,G) to RPF'(S,G) */
503: pim_upstream_join_suppress(up, up->rpf.rpf_addr, holdtime);
504: return;
505: }
506:
507: /* Prune to RPF'(S,G) */
508:
509: if (source_flags & PIM_RPT_BIT_MASK) {
510: if (source_flags & PIM_WILDCARD_BIT_MASK) {
511: /* Prune(*,G) to RPF'(S,G) */
512: pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)",
513: up, up->rpf.rpf_addr);
514: return;
515: }
516:
517: /* Prune(S,G,rpt) to RPF'(S,G) */
518: pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)",
519: up, up->rpf.rpf_addr);
520: return;
521: }
522:
523: /* Prune(S,G) to RPF'(S,G) */
524: pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up,
525: up->rpf.rpf_addr);
526: }
527:
528: static int nonlocal_upstream(int is_join,
529: struct interface *recv_ifp,
530: struct in_addr upstream,
531: struct in_addr source_addr,
532: struct in_addr group_addr,
533: uint8_t source_flags,
534: uint16_t holdtime)
535: {
536: struct pim_interface *recv_pim_ifp;
537: int is_local; /* boolean */
538:
539: recv_pim_ifp = recv_ifp->info;
540: zassert(recv_pim_ifp);
541:
542: is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr);
543:
544: if (PIM_DEBUG_PIM_TRACE) {
545: char up_str[100];
546: char src_str[100];
547: char grp_str[100];
548: pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
549: pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
550: pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
551: zlog_warn("%s: recv %s (S,G)=(%s,%s) to %s upstream=%s on %s",
552: __PRETTY_FUNCTION__,
553: is_join ? "join" : "prune",
554: src_str, grp_str,
555: is_local ? "local" : "non-local",
556: up_str, recv_ifp->name);
557: }
558:
559: if (is_local)
560: return 0;
561:
562: /*
563: Since recv upstream addr was not directed to our primary
564: address, check if we should react to it in any way.
565: */
566: check_recv_upstream(is_join, recv_ifp, upstream, source_addr, group_addr,
567: source_flags, holdtime);
568:
569: return 1; /* non-local */
570: }
571:
572: void pim_ifchannel_join_add(struct interface *ifp,
573: struct in_addr neigh_addr,
574: struct in_addr upstream,
575: struct in_addr source_addr,
576: struct in_addr group_addr,
577: uint8_t source_flags,
578: uint16_t holdtime)
579: {
580: struct pim_interface *pim_ifp;
581: struct pim_ifchannel *ch;
582:
583: if (nonlocal_upstream(1 /* join */, ifp, upstream,
584: source_addr, group_addr, source_flags, holdtime)) {
585: return;
586: }
587:
588: ch = pim_ifchannel_add(ifp, source_addr, group_addr);
589: if (!ch)
590: return;
591:
592: /*
593: RFC 4601: 4.6.1. (S,G) Assert Message State Machine
594:
595: Transitions from "I am Assert Loser" State
596:
597: Receive Join(S,G) on Interface I
598:
599: We receive a Join(S,G) that has the Upstream Neighbor Address
600: field set to my primary IP address on interface I. The action is
601: to transition to NoInfo state, delete this (S,G) assert state
602: (Actions A5 below), and allow the normal PIM Join/Prune mechanisms
603: to operate.
604:
605: Notice: The nonlocal_upstream() test above ensures the upstream
606: address of the join message is our primary address.
607: */
608: if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
609: char src_str[100];
610: char grp_str[100];
611: char neigh_str[100];
612: pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
613: pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
614: pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
615: zlog_warn("%s: Assert Loser recv Join(%s,%s) from %s on %s",
616: __PRETTY_FUNCTION__,
617: src_str, grp_str, neigh_str, ifp->name);
618:
619: assert_action_a5(ch);
620: }
621:
622: pim_ifp = ifp->info;
623: zassert(pim_ifp);
624:
625: switch (ch->ifjoin_state) {
626: case PIM_IFJOIN_NOINFO:
627: pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
628: if (pim_macro_chisin_oiflist(ch)) {
629: pim_forward_start(ch);
630: }
631: break;
632: case PIM_IFJOIN_JOIN:
633: zassert(!ch->t_ifjoin_prune_pending_timer);
634:
635: /*
636: In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to a
637: previously received join message with holdtime=0xFFFF.
638: */
639: if (ch->t_ifjoin_expiry_timer) {
640: unsigned long remain =
641: thread_timer_remain_second(ch->t_ifjoin_expiry_timer);
642: if (remain > holdtime) {
643: /*
644: RFC 4601: 4.5.3. Receiving (S,G) Join/Prune Messages
645:
646: Transitions from Join State
647:
648: The (S,G) downstream state machine on interface I remains in
649: Join state, and the Expiry Timer (ET) is restarted, set to
650: maximum of its current value and the HoldTime from the
651: triggering Join/Prune message.
652:
653: Conclusion: Do not change the ET if the current value is
654: higher than the received join holdtime.
655: */
656: return;
657: }
658: }
659: THREAD_OFF(ch->t_ifjoin_expiry_timer);
660: break;
661: case PIM_IFJOIN_PRUNE_PENDING:
662: zassert(!ch->t_ifjoin_expiry_timer);
663: zassert(ch->t_ifjoin_prune_pending_timer);
664: THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
665: pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
666: break;
667: }
668:
669: zassert(!IFCHANNEL_NOINFO(ch));
670:
671: if (holdtime != 0xFFFF) {
672: THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
673: on_ifjoin_expiry_timer,
674: ch, holdtime);
675: }
676: }
677:
678: void pim_ifchannel_prune(struct interface *ifp,
679: struct in_addr upstream,
680: struct in_addr source_addr,
681: struct in_addr group_addr,
682: uint8_t source_flags,
683: uint16_t holdtime)
684: {
685: struct pim_ifchannel *ch;
686: int jp_override_interval_msec;
687:
688: if (nonlocal_upstream(0 /* prune */, ifp, upstream,
689: source_addr, group_addr, source_flags, holdtime)) {
690: return;
691: }
692:
693: ch = pim_ifchannel_add(ifp, source_addr, group_addr);
694: if (!ch)
695: return;
696:
697: switch (ch->ifjoin_state) {
698: case PIM_IFJOIN_NOINFO:
699: case PIM_IFJOIN_PRUNE_PENDING:
700: /* nothing to do */
701: break;
702: case PIM_IFJOIN_JOIN:
703: {
704: struct pim_interface *pim_ifp;
705:
706: pim_ifp = ifp->info;
707:
708: zassert(ch->t_ifjoin_expiry_timer);
709: zassert(!ch->t_ifjoin_prune_pending_timer);
710:
711: THREAD_OFF(ch->t_ifjoin_expiry_timer);
712:
713: pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_PRUNE_PENDING);
714:
715: if (listcount(pim_ifp->pim_neighbor_list) > 1) {
716: jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp);
717: }
718: else {
719: jp_override_interval_msec = 0; /* schedule to expire immediately */
720: /* If we called ifjoin_prune() directly instead, care should
721: be taken not to use "ch" afterwards since it would be
722: deleted. */
723: }
724:
725: THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer,
726: on_ifjoin_prune_pending_timer,
727: ch, jp_override_interval_msec);
728:
729: zassert(!ch->t_ifjoin_expiry_timer);
730: zassert(ch->t_ifjoin_prune_pending_timer);
731: }
732: break;
733: }
734:
735: }
736:
737: void pim_ifchannel_local_membership_add(struct interface *ifp,
738: struct in_addr source_addr,
739: struct in_addr group_addr)
740: {
741: struct pim_ifchannel *ch;
742: struct pim_interface *pim_ifp;
743:
744: /* PIM enabled on interface? */
745: pim_ifp = ifp->info;
746: if (!pim_ifp)
747: return;
748: if (!PIM_IF_TEST_PIM(pim_ifp->options))
749: return;
750:
751: ch = pim_ifchannel_add(ifp, source_addr, group_addr);
752: if (!ch) {
753: return;
754: }
755:
756: ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE);
757:
758: zassert(!IFCHANNEL_NOINFO(ch));
759: }
760:
761: void pim_ifchannel_local_membership_del(struct interface *ifp,
762: struct in_addr source_addr,
763: struct in_addr group_addr)
764: {
765: struct pim_ifchannel *ch;
766: struct pim_interface *pim_ifp;
767:
768: /* PIM enabled on interface? */
769: pim_ifp = ifp->info;
770: if (!pim_ifp)
771: return;
772: if (!PIM_IF_TEST_PIM(pim_ifp->options))
773: return;
774:
775: ch = pim_ifchannel_find(ifp, source_addr, group_addr);
776: if (!ch)
777: return;
778:
779: ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
780:
781: delete_on_noinfo(ch);
782: }
783:
784: void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch)
785: {
786: int old_couldassert = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags));
787: int new_couldassert = PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch));
788:
789: if (new_couldassert == old_couldassert)
790: return;
791:
792: if (PIM_DEBUG_PIM_EVENTS) {
793: char src_str[100];
794: char grp_str[100];
795: pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
796: pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
797: zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d",
798: __PRETTY_FUNCTION__,
799: src_str, grp_str, ch->interface->name,
800: old_couldassert, new_couldassert);
801: }
802:
803: if (new_couldassert) {
804: /* CouldAssert(S,G,I) switched from FALSE to TRUE */
805: PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
806: }
807: else {
808: /* CouldAssert(S,G,I) switched from TRUE to FALSE */
809: PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
810:
811: if (ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER) {
812: assert_action_a4(ch);
813: }
814: }
815:
816: pim_ifchannel_update_my_assert_metric(ch);
817: }
818:
819: /*
820: my_assert_metric may be affected by:
821:
822: CouldAssert(S,G)
823: pim_ifp->primary_address
824: rpf->source_nexthop.mrib_metric_preference;
825: rpf->source_nexthop.mrib_route_metric;
826: */
827: void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch)
828: {
829: struct pim_assert_metric my_metric_new = pim_macro_ch_my_assert_metric_eval(ch);
830:
831: if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric))
832: return;
833:
834: if (PIM_DEBUG_PIM_EVENTS) {
835: char src_str[100];
836: char grp_str[100];
837: char old_addr_str[100];
838: char new_addr_str[100];
839: pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
840: pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
841: pim_inet4_dump("<old_addr?>", ch->ifassert_my_metric.ip_address, old_addr_str, sizeof(old_addr_str));
842: pim_inet4_dump("<new_addr?>", my_metric_new.ip_address, new_addr_str, sizeof(new_addr_str));
843: zlog_debug("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s",
844: __PRETTY_FUNCTION__,
845: src_str, grp_str, ch->interface->name,
846: ch->ifassert_my_metric.rpt_bit_flag,
847: ch->ifassert_my_metric.metric_preference,
848: ch->ifassert_my_metric.route_metric,
849: old_addr_str,
850: my_metric_new.rpt_bit_flag,
851: my_metric_new.metric_preference,
852: my_metric_new.route_metric,
853: new_addr_str);
854: }
855:
856: ch->ifassert_my_metric = my_metric_new;
857:
858: if (pim_assert_metric_better(&ch->ifassert_my_metric,
859: &ch->ifassert_winner_metric)) {
860: assert_action_a5(ch);
861: }
862: }
863:
864: void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch)
865: {
866: int old_atd = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags));
867: int new_atd = PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch));
868:
869: if (new_atd == old_atd)
870: return;
871:
872: if (PIM_DEBUG_PIM_EVENTS) {
873: char src_str[100];
874: char grp_str[100];
875: pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
876: pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
877: zlog_debug("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d",
878: __PRETTY_FUNCTION__,
879: src_str, grp_str, ch->interface->name,
880: old_atd, new_atd);
881: }
882:
883: if (new_atd) {
884: /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */
885: PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
886: }
887: else {
888: /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */
889: PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
890:
891: if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
892: assert_action_a5(ch);
893: }
894: }
895: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>