Annotation of embedaddon/pimd/route.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1998-2001
3: * University of Southern California/Information Sciences Institute.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: * 3. Neither the name of the project nor the names of its contributors
15: * may be used to endorse or promote products derived from this software
16: * without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28: * SUCH DAMAGE.
29: */
30: /*
31: * $Id: route.c,v 1.39 2003/02/12 21:56:55 pavlin Exp $
32: */
33:
34:
35: #include "defs.h"
36:
37:
38: /* Marian Stagarescu : 07/31/01:
39: *
40: * Administrative scoped multicast filtering im PIMD. This allows an
41: * interface to be configured as an administrative boundary for the
42: * specified scoped address. Packets belonging to the scoped address will
43: * not be forwarded.
44: *
45: * Please note the in order to minimize the search for the matching groups
46: * the implementation is limited to:
47: *
48: * Packets are stopped from being forwarded by installing a NULL outgoing
49: * interface; the user space (pimd) is not up-call-ed any more for
50: * these packets which are dropped by kernel (nil oif) except for
51: * when we de-install the route are re-create it (timer 3 minute).
52: * uses the VIF acl that was installed via config scoped statements.
53: *
54: * this is not an all-purpose packet filtering mechanism.
55: * we tried here to achieve the filtering with minimal processing
56: * (inspect (g) when we are about to install a route for it).
57: *
58: * to use it edit pimd.conf and compile with -DSCOPED_ACL
59: */
60:
61: static void process_cache_miss (struct igmpmsg *igmpctl);
62: static void process_wrong_iif (struct igmpmsg *igmpctl);
63: static void process_whole_pkt (char *buf);
64:
65: #ifdef SCOPED_ACL
66: /* from mrouted. Contributed by Marian Stagarescu <marian@bile.cidera.com>*/
67: static int scoped_addr(vifi_t vifi, uint32_t addr)
68: {
69: struct vif_acl *acl;
70:
71: for (acl = uvifs[vifi].uv_acl; acl; acl = acl->acl_next) {
72: if ((addr & acl->acl_mask) == acl->acl_addr)
73: return 1;
74: }
75:
76: return 0;
77: }
78:
79: /* Contributed by Marian Stagarescu <marian@bile.cidera.com>
80: * adapted from mrouted: check for scoped multicast addresses
81: * install null oif if matched
82: */
83: #define APPLY_SCOPE(g, mp) { \
84: vifi_t i; \
85: for (i = 0; i < numvifs; i++) \
86: if (scoped_addr(i, g)) \
87: (mp)->oifs = 0; \
88: }
89: #endif /* SCOPED_ACL */
90:
91: /* Return the iif for given address */
92: vifi_t get_iif(uint32_t address)
93: {
94: struct rpfctl rpfc;
95:
96: k_req_incoming(address, &rpfc);
97: if (rpfc.rpfneighbor.s_addr == INADDR_ANY_N)
98: return NO_VIF;
99:
100: return rpfc.iif;
101: }
102:
103: /* Return the PIM neighbor toward a source */
104: /* If route not found or if a local source or if a directly connected source,
105: * but is not PIM router, or if the first hop router is not a PIM router,
106: * then return NULL.
107: */
108: pim_nbr_entry_t *find_pim_nbr(uint32_t source)
109: {
110: struct rpfctl rpfc;
111: pim_nbr_entry_t *nbr;
112: uint32_t addr;
113:
114: if (local_address(source) != NO_VIF)
115: return NULL;
116: k_req_incoming(source, &rpfc);
117:
118: if ((rpfc.rpfneighbor.s_addr == INADDR_ANY_N) || (rpfc.iif == NO_VIF))
119: return NULL;
120:
121: /* Figure out the nexthop neighbor by checking the reverse path */
122: addr = rpfc.rpfneighbor.s_addr;
123: for (nbr = uvifs[rpfc.iif].uv_pim_neighbors; nbr; nbr = nbr->next)
124: if (nbr->address == addr)
125: return nbr;
126:
127: return NULL;
128: }
129:
130:
131: /* TODO: check again the exact setup if the source is local or directly
132: * connected!!!
133: */
134: /* TODO: XXX: change the metric and preference for all (S,G) entries per
135: * source or RP?
136: */
137: /* TODO - If possible, this would be the place to correct set the
138: * source's preference and metric to that obtained from the kernel
139: * and/or unicast routing protocol. For now, set it to the configured
140: * default for local pref/metric.
141: */
142:
143: /*
144: * Set the iif, upstream router, preference and metric for the route
145: * toward the source. Return TRUE is the route was found, othewise FALSE.
146: * If type==PIM_IIF_SOURCE and if the source is directly connected
147: * then the "upstream" is set to NULL. If srcentry==PIM_IIF_RP, then
148: * "upstream" in case of directly connected "source" will be that "source"
149: * (if it is also PIM router).,
150: */
151: int set_incoming(srcentry_t *src, int type)
152: {
153: struct rpfctl rpfc;
154: uint32_t src_addr = src->address;
155: uint32_t nbr_addr;
156: struct uvif *vif;
157: pim_nbr_entry_t *nbr;
158:
159: /* Preference will be 0 if directly connected */
160: src->metric = 0;
161: src->preference = 0;
162:
163: /* The source is a local address */
164: src->incoming = local_address(src_addr);
165: if (src->incoming != NO_VIF) {
166: /* iif of (*,G) at RP has to be register_if */
167: if (type == PIM_IIF_RP)
168: src->incoming = reg_vif_num;
169:
170: /* TODO: set the upstream to myself? */
171: src->upstream = NULL;
172: return TRUE;
173: }
174:
175: src->incoming = find_vif_direct(src_addr);
176: if (src->incoming != NO_VIF) {
177: /* The source is directly connected. Check whether we are
178: * looking for real source or RP */
179: if (type == PIM_IIF_SOURCE) {
180: src->upstream = NULL;
181: return TRUE;
182: }
183:
184: /* PIM_IIF_RP */
185: nbr_addr = src_addr;
186: } else {
187: /* TODO: probably need to check the case if the iif is disabled */
188: /* Use the lastest resource: the kernel unicast routing table */
189: k_req_incoming(src_addr, &rpfc);
190: if ((rpfc.iif == NO_VIF) || rpfc.rpfneighbor.s_addr == INADDR_ANY_N) {
191: /* couldn't find a route */
192: if (!IN_LINK_LOCAL_RANGE(src_addr)) {
193: IF_DEBUG(DEBUG_PIM_MRT | DEBUG_RPF)
194: logit(LOG_DEBUG, 0, "NO ROUTE found for %s", inet_fmt(src_addr, s1, sizeof(s1)));
195: }
196: return FALSE;
197: }
198:
199: src->incoming = rpfc.iif;
200: nbr_addr = rpfc.rpfneighbor.s_addr;
201:
202: /* set the preference for sources that aren't directly connected. */
203: vif = &uvifs[src->incoming];
204: src->preference = vif->uv_local_pref;
205: src->metric = vif->uv_local_metric;
206: }
207:
208: /* The upstream router must be a (PIM router) neighbor, otherwise we
209: * are in big trouble ;-) */
210: vif = &uvifs[src->incoming];
211: for (nbr = vif->uv_pim_neighbors; nbr; nbr = nbr->next) {
212: if (ntohl(nbr_addr) < ntohl(nbr->address))
213: continue;
214:
215: if (nbr_addr == nbr->address) {
216: /* The upstream router is found in the list of neighbors.
217: * We are safe! */
218: src->upstream = nbr;
219: IF_DEBUG(DEBUG_RPF)
220: logit(LOG_DEBUG, 0, "For src %s, iif is %d, next hop router is %s",
221: inet_fmt(src_addr, s1, sizeof(s1)), src->incoming,
222: inet_fmt(nbr_addr, s2, sizeof(s2)));
223:
224: return TRUE;
225: }
226:
227: break;
228: }
229:
230: /* TODO: control the number of messages! */
231: logit(LOG_INFO, 0, "For src %s, iif is %d, next hop router is %s: NOT A PIM ROUTER",
232: inet_fmt(src_addr, s1, sizeof(s1)), src->incoming,
233: inet_fmt(nbr_addr, s2, sizeof(s2)));
234: src->upstream = NULL;
235:
236: return FALSE;
237: }
238:
239:
240: /*
241: * TODO: XXX: currently `source` is not used. Will be used with IGMPv3 where
242: * we have source-specific Join/Prune.
243: */
244: void add_leaf(vifi_t vifi, uint32_t source, uint32_t group)
245: {
246: mrtentry_t *mrt;
247: mrtentry_t *srcs;
248: vifbitmap_t old_oifs;
249: vifbitmap_t new_oifs;
250: vifbitmap_t new_leaves;
251:
252: /* Don't create routing entries for the LAN scoped addresses */
253: if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP) { /* group <= 224.0.0.255? */
254: IF_DEBUG(DEBUG_IGMP)
255: logit(LOG_DEBUG, 0, "Not creating routing entry for LAN scoped group %s",
256: inet_fmt(group, s1, sizeof(s1)));
257: return;
258: }
259:
260: /*
261: * XXX: only if I am a DR, the IGMP Join should result in creating
262: * a PIM MRT state.
263: * XXX: Each router must know if it has local members, i.e., whether
264: * it is a last-hop router as well. This info is needed so it will
265: * know whether is allowed to initiate a SPT switch by sending
266: * a PIM (S,G) Join to the high datarate source.
267: * However, if a non-DR last-hop router has not received
268: * a PIM Join, it should not create a PIM state, otherwise later
269: * this state may incorrectly trigger PIM joins.
270: * There is a design flow in pimd, so without making major changes
271: * the best we can do is that the non-DR last-hop router will
272: * record the local members only after it receives PIM Join from the DR
273: * (i.e. after the second or third IGMP Join by the local member).
274: * The downside is that a last-hop router may delay the initiation
275: * of the SPT switch. Sigh...
276: */
277: if (IN_PIM_SSM_RANGE(group))
278: mrt = find_route(source, group, MRTF_SG, CREATE);
279: else if (uvifs[vifi].uv_flags & VIFF_DR)
280: mrt = find_route(INADDR_ANY_N, group, MRTF_WC, CREATE);
281: else
282: mrt = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE);
283:
284: if (!mrt)
285: return;
286:
287: IF_DEBUG(DEBUG_MRT)
288: logit(LOG_DEBUG, 0, "Adding vif %d for group %s", vifi, inet_fmt(group, s1, sizeof(s1)));
289:
290: if (VIFM_ISSET(vifi, mrt->leaves))
291: return; /* Already a leaf */
292:
293: calc_oifs(mrt, &old_oifs);
294: VIFM_COPY(mrt->leaves, new_leaves);
295: VIFM_SET(vifi, new_leaves); /* Add the leaf */
296: change_interfaces(mrt,
297: mrt->incoming,
298: mrt->joined_oifs,
299: mrt->pruned_oifs,
300: new_leaves,
301: mrt->asserted_oifs, 0);
302: calc_oifs(mrt, &new_oifs);
303:
304: /* Only if I am the DR for that subnet, eventually initiate a Join */
305: if (!(uvifs[vifi].uv_flags & VIFF_DR))
306: return;
307:
308: if ((mrt->flags & MRTF_NEW) || (VIFM_ISEMPTY(old_oifs) && (!VIFM_ISEMPTY(new_oifs)))) {
309: /* A new created entry or the oifs have changed
310: * from NULL to non-NULL. */
311: mrt->flags &= ~MRTF_NEW;
312: FIRE_TIMER(mrt->jp_timer); /* Timeout the Join/Prune timer */
313:
314: /* TODO: explicitly call the function below?
315: send_pim_join_prune(mrt->upstream->vifi,
316: mrt->upstream,
317: PIM_JOIN_PRUNE_HOLDTIME);
318: */
319: }
320:
321: /* Check all (S,G) entries and set the inherited "leaf" flag.
322: * TODO: XXX: This won't work for IGMPv3, because there we don't know
323: * whether the (S,G) leaf oif was inherited from the (*,G) entry or
324: * was created by source specific IGMP join.
325: */
326: for (srcs = mrt->group->mrtlink; srcs; srcs = srcs->grpnext) {
327: VIFM_COPY(srcs->leaves, new_leaves);
328: VIFM_SET(vifi, new_leaves);
329: change_interfaces(srcs,
330: srcs->incoming,
331: srcs->joined_oifs,
332: srcs->pruned_oifs,
333: new_leaves,
334: srcs->asserted_oifs, 0);
335: }
336: }
337:
338:
339: /*
340: * TODO: XXX: currently `source` is not used. To be used with IGMPv3 where
341: * we have source-specific joins/prunes.
342: */
343: void delete_leaf(vifi_t vifi, uint32_t source, uint32_t group)
344: {
345: mrtentry_t *mrt;
346: mrtentry_t *srcs;
347: vifbitmap_t new_oifs;
348: vifbitmap_t old_oifs;
349: vifbitmap_t new_leaves;
350:
351: if (IN_PIM_SSM_RANGE(group))
352: mrt = find_route(source, group, MRTF_SG, DONT_CREATE);
353: else
354: mrt = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE);
355:
356: if (!mrt)
357: return;
358:
359: if (!VIFM_ISSET(vifi, mrt->leaves))
360: return; /* This interface wasn't leaf */
361:
362: IF_DEBUG(DEBUG_MRT)
363: logit(LOG_DEBUG, 0, "Deleting vif %d for group %s", vifi, inet_fmt(group, s1, sizeof(s1)));
364:
365: calc_oifs(mrt, &old_oifs);
366:
367: /* For SSM, source must match */
368: if (!IN_PIM_SSM_RANGE(group) || (mrt->source->address==source)) {
369: VIFM_COPY(mrt->leaves, new_leaves);
370: VIFM_CLR(vifi, new_leaves);
371: change_interfaces(mrt,
372: mrt->incoming,
373: mrt->joined_oifs,
374: mrt->pruned_oifs,
375: new_leaves,
376: mrt->asserted_oifs, 0);
377: }
378: calc_oifs(mrt, &new_oifs);
379:
380: if ((!VIFM_ISEMPTY(old_oifs)) && VIFM_ISEMPTY(new_oifs)) {
381: /* The result oifs have changed from non-NULL to NULL */
382: FIRE_TIMER(mrt->jp_timer); /* Timeout the Join/Prune timer */
383:
384: /* TODO: explicitly call the function below?
385: send_pim_join_prune(mrt->upstream->vifi,
386: mrt->upstream,
387: PIM_JOIN_PRUNE_HOLDTIME);
388: */
389: }
390:
391: /* Check all (S,G) entries and clear the inherited "leaf" flag.
392: * TODO: XXX: This won't work for IGMPv3, because there we don't know
393: * whether the (S,G) leaf oif was inherited from the (*,G) entry or
394: * was created by source specific IGMP join.
395: */
396: for (srcs = mrt->group->mrtlink; srcs; srcs = srcs->grpnext) {
397: VIFM_COPY(srcs->leaves, new_leaves);
398: VIFM_CLR(vifi, new_leaves);
399: change_interfaces(srcs,
400: srcs->incoming,
401: srcs->joined_oifs,
402: srcs->pruned_oifs,
403: new_leaves,
404: srcs->asserted_oifs, 0);
405: }
406: }
407:
408:
409: void calc_oifs(mrtentry_t *mrt, vifbitmap_t *oifs_ptr)
410: {
411: vifbitmap_t oifs;
412: mrtentry_t *grp;
413: mrtentry_t *mrp;
414:
415: /*
416: * oifs =
417: * (((copied_outgoing + my_join) - my_prune) + my_leaves)
418: * - my_asserted_oifs - incoming_interface,
419: * i.e. `leaves` have higher priority than `prunes`, but lower priority
420: * than `asserted`. The incoming interface is always deleted from the oifs
421: */
422:
423: if (!mrt) {
424: VIFM_CLRALL(*oifs_ptr);
425: return;
426: }
427:
428: VIFM_CLRALL(oifs);
429: if (!(mrt->flags & MRTF_PMBR)) {
430: /* Either (*,G) or (S,G). Merge with the oifs from the (*,*,RP) */
431: mrp = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
432: if (mrp) {
433: VIFM_MERGE(oifs, mrp->joined_oifs, oifs);
434: VIFM_CLR_MASK(oifs, mrp->pruned_oifs);
435: VIFM_MERGE(oifs, mrp->leaves, oifs);
436: VIFM_CLR_MASK(oifs, mrp->asserted_oifs);
437: }
438: }
439: if (mrt->flags & MRTF_SG) {
440: /* (S,G) entry. Merge with the oifs from (*,G) */
441: grp = mrt->group->grp_route;
442: if (grp) {
443: VIFM_MERGE(oifs, grp->joined_oifs, oifs);
444: VIFM_CLR_MASK(oifs, grp->pruned_oifs);
445: VIFM_MERGE(oifs, grp->leaves, oifs);
446: VIFM_CLR_MASK(oifs, grp->asserted_oifs);
447: }
448: }
449:
450: /* Calculate my own stuff */
451: VIFM_MERGE(oifs, mrt->joined_oifs, oifs);
452: VIFM_CLR_MASK(oifs, mrt->pruned_oifs);
453: VIFM_MERGE(oifs, mrt->leaves, oifs);
454: VIFM_CLR_MASK(oifs, mrt->asserted_oifs);
455:
456: VIFM_COPY(oifs, *oifs_ptr);
457: }
458:
459: /*
460: * Set the iif, join/prune/leaves/asserted interfaces. Calculate and
461: * set the oifs.
462: * Return 1 if oifs change from NULL to not-NULL.
463: * Return -1 if oifs change from non-NULL to NULL
464: * else return 0
465: * If the iif change or if the oifs change from NULL to non-NULL
466: * or vice-versa, then schedule that mrtentry join/prune timer to
467: * timeout immediately.
468: */
469: int change_interfaces(mrtentry_t *mrt,
470: vifi_t new_iif,
471: vifbitmap_t new_joined_oifs_,
472: vifbitmap_t new_pruned_oifs,
473: vifbitmap_t new_leaves_,
474: vifbitmap_t new_asserted_oifs,
475: uint16_t flags)
476: {
477: vifbitmap_t new_joined_oifs; /* The oifs for that particular mrtentry */
478: vifbitmap_t old_joined_oifs __attribute__ ((unused));
479: vifbitmap_t old_pruned_oifs __attribute__ ((unused));
480: vifbitmap_t old_leaves __attribute__ ((unused));
481: vifbitmap_t new_leaves;
482: vifbitmap_t old_asserted_oifs __attribute__ ((unused));
483: vifbitmap_t new_real_oifs; /* The result oifs */
484: vifbitmap_t old_real_oifs;
485: vifi_t old_iif;
486: rpentry_t *rp;
487: cand_rp_t *cand_rp;
488: kernel_cache_t *kc;
489: rp_grp_entry_t *rp_grp;
490: grpentry_t *grp;
491: mrtentry_t *srcs;
492: mrtentry_t *mwc;
493: mrtentry_t *mrp;
494: int delete_mrt_flag;
495: int result;
496: int fire_timer_flag;
497:
498: if (!mrt)
499: return 0;
500:
501: VIFM_COPY(new_joined_oifs_, new_joined_oifs);
502: VIFM_COPY(new_leaves_, new_leaves);
503:
504: old_iif = mrt->incoming;
505: VIFM_COPY(mrt->joined_oifs, old_joined_oifs);
506: VIFM_COPY(mrt->leaves, old_leaves);
507: VIFM_COPY(mrt->pruned_oifs, old_pruned_oifs);
508: VIFM_COPY(mrt->asserted_oifs, old_asserted_oifs);
509:
510: VIFM_COPY(mrt->oifs, old_real_oifs);
511:
512: mrt->incoming = new_iif;
513: VIFM_COPY(new_joined_oifs, mrt->joined_oifs);
514: VIFM_COPY(new_pruned_oifs, mrt->pruned_oifs);
515: VIFM_COPY(new_leaves, mrt->leaves);
516: VIFM_COPY(new_asserted_oifs, mrt->asserted_oifs);
517: calc_oifs(mrt, &new_real_oifs);
518:
519: if (VIFM_ISEMPTY(old_real_oifs)) {
520: if (VIFM_ISEMPTY(new_real_oifs))
521: result = 0;
522: else
523: result = 1;
524: } else {
525: if (VIFM_ISEMPTY(new_real_oifs))
526: result = -1;
527: else
528: result = 0;
529: }
530:
531: if ((VIFM_SAME(new_real_oifs, old_real_oifs))
532: && (new_iif == old_iif)
533: && !(flags & MFC_UPDATE_FORCE))
534: return 0; /* Nothing to change */
535:
536: if ((result != 0) || (new_iif != old_iif) || (flags & MFC_UPDATE_FORCE)) {
537: FIRE_TIMER(mrt->jp_timer);
538: }
539: VIFM_COPY(new_real_oifs, mrt->oifs);
540:
541: if (mrt->flags & MRTF_PMBR) {
542: /* (*,*,RP) entry */
543: rp = mrt->source;
544: if (!rp)
545: return 0; /* Shouldn't happen */
546:
547: rp->incoming = new_iif;
548: cand_rp = rp->cand_rp;
549:
550: if (VIFM_ISEMPTY(new_real_oifs)) {
551: delete_mrt_flag = TRUE;
552: } else {
553: delete_mrt_flag = FALSE;
554: #ifdef RSRR
555: rsrr_cache_send(mrt, RSRR_NOTIFICATION_OK);
556: #endif /* RSRR */
557: }
558:
559: if (mrt->flags & MRTF_KERNEL_CACHE) {
560: /* Update the kernel MFC entries */
561: if (delete_mrt_flag == TRUE) {
562: /* XXX: no need to send RSRR message. Will do it when
563: * delete the mrtentry.
564: */
565: for (kc = mrt->kernel_cache; kc; kc = kc->next)
566: delete_mrtentry_all_kernel_cache(mrt);
567: } else {
568: /* here mrt->source->address is the RP address */
569: for (kc = mrt->kernel_cache; kc; kc = kc->next)
570: k_chg_mfc(igmp_socket, kc->source,
571: kc->group, new_iif,
572: new_real_oifs, mrt->source->address);
573: }
574: }
575:
576: /*
577: * Update all (*,G) entries associated with this RP.
578: * The particular (*,G) outgoing are not changed, but the change
579: * in the (*,*,RP) oifs may have affect the real oifs.
580: */
581: fire_timer_flag = FALSE;
582: for (rp_grp = cand_rp->rp_grp_next; rp_grp; rp_grp = rp_grp->rp_grp_next) {
583: for (grp = rp_grp->grplink; grp; grp = grp->rpnext) {
584: if (grp->grp_route) {
585: if (change_interfaces(grp->grp_route, new_iif,
586: grp->grp_route->joined_oifs,
587: grp->grp_route->pruned_oifs,
588: grp->grp_route->leaves,
589: grp->grp_route->asserted_oifs,
590: flags))
591: fire_timer_flag = TRUE;
592: } else {
593: /* Change all (S,G) entries if no (*,G) */
594: for (srcs = grp->mrtlink; srcs; srcs = srcs->grpnext) {
595: if (srcs->flags & MRTF_RP) {
596: if (change_interfaces(srcs, new_iif,
597: srcs->joined_oifs,
598: srcs->pruned_oifs,
599: srcs->leaves,
600: srcs->asserted_oifs,
601: flags))
602: fire_timer_flag = TRUE;
603: } else {
604: if (change_interfaces(srcs,
605: srcs->incoming,
606: srcs->joined_oifs,
607: srcs->pruned_oifs,
608: srcs->leaves,
609: srcs->asserted_oifs,
610: flags))
611: fire_timer_flag = TRUE;
612: }
613: }
614: }
615: }
616: }
617: if (fire_timer_flag == TRUE)
618: FIRE_TIMER(mrt->jp_timer);
619: if (delete_mrt_flag == TRUE) {
620: /* TODO: XXX: trigger a Prune message? Don't delete now, it will
621: * be automatically timed out. If want to delete now, don't
622: * reference to it anymore!
623: delete_mrtentry(mrt);
624: */
625: }
626:
627: return result; /* (*,*,RP) */
628: }
629:
630: if (mrt->flags & MRTF_WC) {
631: /* (*,G) entry */
632: if (VIFM_ISEMPTY(new_real_oifs)) {
633: delete_mrt_flag = TRUE;
634: } else {
635: delete_mrt_flag = FALSE;
636: #ifdef RSRR
637: rsrr_cache_send(mrt, RSRR_NOTIFICATION_OK);
638: #endif /* RSRR */
639: }
640:
641: if (mrt->flags & MRTF_KERNEL_CACHE) {
642: if (delete_mrt_flag == TRUE) {
643: delete_mrtentry_all_kernel_cache(mrt);
644: } else {
645: for (kc = mrt->kernel_cache; kc; kc = kc->next)
646: k_chg_mfc(igmp_socket, kc->source,
647: kc->group, new_iif,
648: new_real_oifs, mrt->group->rpaddr);
649: }
650: }
651:
652: /* Update all (S,G) entries for this group.
653: * For the (S,G)RPbit entries the iif is the iif toward the RP;
654: * The particular (S,G) oifs are not changed, but the change in the
655: * (*,G) oifs may affect the real oifs.
656: */
657: fire_timer_flag = FALSE;
658: for (srcs = mrt->group->mrtlink; srcs; srcs = srcs->grpnext) {
659: if (srcs->flags & MRTF_RP) {
660: if (change_interfaces(srcs, new_iif,
661: srcs->joined_oifs,
662: srcs->pruned_oifs,
663: srcs->leaves,
664: srcs->asserted_oifs, flags))
665: fire_timer_flag = TRUE;
666: } else {
667: if (change_interfaces(srcs, srcs->incoming,
668: srcs->joined_oifs,
669: srcs->pruned_oifs,
670: srcs->leaves,
671: srcs->asserted_oifs, flags))
672: fire_timer_flag = TRUE;
673: }
674: }
675:
676: if (fire_timer_flag == TRUE)
677: FIRE_TIMER(mrt->jp_timer);
678:
679: if (delete_mrt_flag == TRUE) {
680: /* TODO: XXX: the oifs are NULL. Send a Prune message? */
681: }
682:
683: return result; /* (*,G) */
684: }
685:
686: /* (S,G) entry */
687: if (mrt->flags & MRTF_SG) {
688: mrp = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
689: mwc = mrt->group->grp_route;
690:
691: #ifdef KERNEL_MFC_WC_G
692: mrtentry_t *tmp;
693:
694: /* Check whether (*,*,RP) or (*,G) have different (iif,oifs) from
695: * the (S,G). If "yes", then forbid creating (*,G) MFC. */
696: for (tmp = mrp; 1; tmp = mwc) {
697: while (1) {
698: vifbitmap_t oifs;
699:
700: if (!tmp)
701: break;
702:
703: if (tmp->flags & MRTF_MFC_CLONE_SG)
704: break;
705:
706: if (tmp->incoming != mrt->incoming) {
707: delete_single_kernel_cache_addr(tmp, INADDR_ANY_N, mrt->group->group);
708: tmp->flags |= MRTF_MFC_CLONE_SG;
709: break;
710: }
711:
712: calc_oifs(tmp, &oifs);
713: if (!(VIFM_SAME(new_real_oifs, oifs)))
714: tmp->flags |= MRTF_MFC_CLONE_SG;
715:
716: break;
717: }
718:
719: if (tmp == mwc)
720: break;
721: }
722: #endif /* KERNEL_MFC_WC_G */
723:
724: if (VIFM_ISEMPTY(new_real_oifs)) {
725: delete_mrt_flag = TRUE;
726: } else {
727: delete_mrt_flag = FALSE;
728: #ifdef RSRR
729: rsrr_cache_send(mrt, RSRR_NOTIFICATION_OK);
730: #endif
731: }
732:
733: if (mrt->flags & MRTF_KERNEL_CACHE) {
734: if (delete_mrt_flag == TRUE)
735: delete_mrtentry_all_kernel_cache(mrt);
736: else
737: k_chg_mfc(igmp_socket, mrt->source->address,
738: mrt->group->group, new_iif, new_real_oifs,
739: mrt->group->rpaddr);
740: }
741:
742: if (old_iif != new_iif) {
743: if (new_iif == mrt->source->incoming) {
744: /* For example, if this was (S,G)RPbit with iif toward the RP,
745: * and now switch to the Shortest Path.
746: * The setup of MRTF_SPT flag must be
747: * done by the external calling function (triggered only
748: * by receiving of a data from the source.)
749: */
750: mrt->flags &= ~MRTF_RP;
751: /* TODO: XXX: delete? Check again where will be the best
752: * place to set it.
753: mrt->flags |= MRTF_SPT;
754: */
755: }
756:
757: if ((mwc && mwc->incoming == new_iif) ||
758: (mrp && mrp->incoming == new_iif)) {
759: /* If the new iif points toward the RP, reset the SPT flag.
760: * (PIM-SM-spec-10.ps pp. 11, 2.10, last sentence of first
761: * paragraph. */
762:
763: /* TODO: XXX: check again! */
764: mrt->flags &= ~MRTF_SPT;
765: mrt->flags |= MRTF_RP;
766: }
767: }
768:
769: /* TODO: XXX: if this is (S,G)RPbit entry and the oifs==(*,G)oifs,
770: * then delete the (S,G) entry?? The same if we have (*,*,RP) ? */
771: if (delete_mrt_flag == TRUE) {
772: /* TODO: XXX: the oifs are NULL. Send a Prune message ? */
773: }
774:
775: /* TODO: XXX: have the feeling something is missing.... */
776: return result; /* (S,G) */
777: }
778:
779: return result;
780: }
781:
782:
783: /* TODO: implement it. Required to allow changing of the physical interfaces
784: * configuration without need to restart pimd.
785: */
786: int delete_vif_from_mrt(vifi_t vifi __attribute__((unused)))
787: {
788: return TRUE;
789: }
790:
791:
792: void process_kernel_call(void)
793: {
794: struct igmpmsg *igmpctl = (struct igmpmsg *)igmp_recv_buf;
795:
796: switch (igmpctl->im_msgtype) {
797: case IGMPMSG_NOCACHE:
798: process_cache_miss(igmpctl);
799: break;
800:
801: case IGMPMSG_WRONGVIF:
802: process_wrong_iif(igmpctl);
803: break;
804:
805: case IGMPMSG_WHOLEPKT:
806: process_whole_pkt(igmp_recv_buf);
807: break;
808:
809: default:
810: IF_DEBUG(DEBUG_KERN)
811: logit(LOG_DEBUG, 0, "Unknown IGMP message type from kernel: %d", igmpctl->im_msgtype);
812: break;
813: }
814: }
815:
816:
817: /*
818: * TODO: when cache miss, check the iif, because probably ASSERTS
819: * shoult take place
820: */
821: static void process_cache_miss(struct igmpmsg *igmpctl)
822: {
823: uint32_t source, mfc_source;
824: uint32_t group;
825: uint32_t rp_addr;
826: vifi_t iif;
827: mrtentry_t *mrt;
828: mrtentry_t *mrp;
829:
830: /* When there is a cache miss, we check only the header of the packet
831: * (and only it should be sent up by the kernel. */
832:
833: group = igmpctl->im_dst.s_addr;
834: source = mfc_source = igmpctl->im_src.s_addr;
835: iif = igmpctl->im_vif;
836:
837: IF_DEBUG(DEBUG_MRT)
838: logit(LOG_DEBUG, 0, "Cache miss, src %s, dst %s, iif %d",
839: inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)), iif);
840:
841: /* TODO: XXX: check whether the kernel generates cache miss for the LAN scoped addresses */
842: if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP)
843: return; /* Don't create routing entries for the LAN scoped addresses */
844:
845: /* TODO: check if correct in case the source is one of my addresses */
846: /* If I am the DR for this source, create (S,G) and add the register_vif
847: * to the oifs. */
848:
849: if ((uvifs[iif].uv_flags & VIFF_DR) && (find_vif_direct_local(source) == iif)) {
850: mrt = find_route(source, group, MRTF_SG, CREATE);
851: if (!mrt)
852: return;
853:
854: mrt->flags &= ~MRTF_NEW;
855: /* set reg_vif_num as outgoing interface ONLY if I am not the RP */
856: if (mrt->group->rpaddr != my_cand_rp_address)
857: VIFM_SET(reg_vif_num, mrt->joined_oifs);
858: change_interfaces(mrt,
859: mrt->incoming,
860: mrt->joined_oifs,
861: mrt->pruned_oifs,
862: mrt->leaves,
863: mrt->asserted_oifs, 0);
864: } else {
865: mrt = find_route(source, group, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE);
866: switch_shortest_path(source, group);
867: if (!mrt)
868: return;
869: }
870:
871: /* TODO: if there are too many cache miss for the same (S,G),
872: * install negative cache entry in the kernel (oif==NULL) to prevent
873: * too many upcalls. */
874:
875: if (mrt->incoming == iif) {
876: if (!VIFM_ISEMPTY(mrt->oifs)) {
877: if (mrt->flags & MRTF_SG) {
878: /* TODO: check that the RPbit is not set? */
879: /* TODO: XXX: TIMER implem. dependency! */
880: if (mrt->timer < PIM_DATA_TIMEOUT)
881: SET_TIMER(mrt->timer, PIM_DATA_TIMEOUT);
882:
883: if (!(mrt->flags & MRTF_SPT)) {
884: mrp = mrt->group->grp_route;
885: if (!mrp)
886: mrp = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
887:
888: if (mrp) {
889: /* Check if the (S,G) iif is different from
890: * the (*,G) or (*,*,RP) iif */
891: if ((mrt->incoming != mrp->incoming) ||
892: (mrt->upstream != mrp->upstream)) {
893: mrt->flags |= MRTF_SPT;
894: mrt->flags &= ~MRTF_RP;
895: }
896: }
897: }
898: }
899:
900: if (mrt->flags & MRTF_PMBR)
901: rp_addr = mrt->source->address;
902: else
903: rp_addr = mrt->group->rpaddr;
904:
905: mfc_source = source;
906: #ifdef KERNEL_MFC_WC_G
907: if (mrt->flags & (MRTF_WC | MRTF_PMBR))
908: if (!(mrt->flags & MRTF_MFC_CLONE_SG))
909: mfc_source = INADDR_ANY_N;
910: #endif /* KERNEL_MFC_WC_G */
911:
912: add_kernel_cache(mrt, mfc_source, group, MFC_MOVE_FORCE);
913:
914: #ifdef SCOPED_ACL
915: APPLY_SCOPE(group, mrt);
916: #endif
917: k_chg_mfc(igmp_socket, mfc_source, group, iif, mrt->oifs, rp_addr);
918:
919: /* No need for RSRR message, because nothing has changed. */
920: }
921:
922: return; /* iif match */
923: }
924:
925: /* The iif doesn't match */
926: if (mrt->flags & MRTF_SG) {
927: /* Arrived on wrong interface */
928: if (mrt->flags & MRTF_SPT)
929: return;
930:
931: mrp = mrt->group->grp_route;
932: if (!mrp)
933: mrp = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
934:
935: if (mrp) {
936: /* Forward on (*,G) or (*,*,RP) */
937: if (mrp->incoming == iif) {
938: #ifdef KERNEL_MFC_WC_G
939: if (!(mrp->flags & MRTF_MFC_CLONE_SG))
940: mfc_source = INADDR_ANY_N;
941: #endif /* KERNEL_MFC_WC_G */
942:
943: add_kernel_cache(mrp, mfc_source, group, 0);
944:
945: #ifdef SCOPED_ACL
946: /* marian: not sure if we reach here with our scoped traffic? */
947: APPLY_SCOPE(group, mrt);
948: #endif
949: k_chg_mfc(igmp_socket, mfc_source, group, iif,
950: mrp->oifs, mrt->group->rpaddr);
951: #ifdef RSRR
952: rsrr_cache_send(mrp, RSRR_NOTIFICATION_OK);
953: #endif /* RSRR */
954: }
955: }
956: }
957: }
958:
959:
960: /*
961: * A multicast packet has been received on wrong iif by the kernel.
962: * Check for a matching entry. If there is (S,G) with reset SPTbit and
963: * the packet was received on the iif toward the source, this completes
964: * the switch to the shortest path and triggers (S,G) prune toward the RP
965: * (unless I am the RP).
966: * Otherwise, if the packet's iif is in the oiflist of the routing entry,
967: * trigger an Assert.
968: */
969: static void process_wrong_iif(struct igmpmsg *igmpctl)
970: {
971: uint32_t source;
972: uint32_t group;
973: vifi_t iif;
974: mrtentry_t *mrt;
975:
976: group = igmpctl->im_dst.s_addr;
977: source = igmpctl->im_src.s_addr;
978: iif = igmpctl->im_vif;
979:
980: IF_DEBUG(DEBUG_MRT)
981: logit(LOG_DEBUG, 0, "Wrong iif: src %s, dst %s, iif %d",
982: inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)), iif);
983:
984: /* Don't create routing entries for the LAN scoped addresses */
985: if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP)
986: return;
987:
988: /* Ignore if it comes on register vif. register vif is neither SPT iif,
989: * neither is used to send asserts out.
990: */
991: if (uvifs[iif].uv_flags & VIFF_REGISTER)
992: return;
993:
994: mrt = find_route(source, group, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE);
995: if (!mrt)
996: return;
997:
998: /*
999: * TODO: check again!
1000: */
1001: if (mrt->flags & MRTF_SG) {
1002: if (!(mrt->flags & MRTF_SPT)) {
1003: if (mrt->source->incoming == iif) {
1004: /* Switch to the Shortest Path */
1005: mrt->flags |= MRTF_SPT;
1006: mrt->flags &= ~MRTF_RP;
1007: add_kernel_cache(mrt, source, group, MFC_MOVE_FORCE);
1008: k_chg_mfc(igmp_socket, source, group, iif,
1009: mrt->oifs, mrt->group->rpaddr);
1010: FIRE_TIMER(mrt->jp_timer);
1011: #ifdef RSRR
1012: rsrr_cache_send(mrt, RSRR_NOTIFICATION_OK);
1013: #endif /* RSRR */
1014:
1015: return;
1016: }
1017: }
1018: }
1019:
1020: /* Trigger an Assert */
1021: if (VIFM_ISSET(iif, mrt->oifs))
1022: send_pim_assert(source, group, iif, mrt);
1023: }
1024:
1025: /*
1026: * Receives whole packets from the register vif entries
1027: * in the kernel, and calls the send_pim_register procedure to
1028: * encapsulate the packets and unicasts them to the RP.
1029: */
1030: static void process_whole_pkt(char *buf)
1031: {
1032: send_pim_register((char *)(buf + sizeof(struct igmpmsg)));
1033: }
1034:
1035:
1036: mrtentry_t *switch_shortest_path(uint32_t source, uint32_t group)
1037: {
1038: mrtentry_t *mrt;
1039:
1040: IF_DEBUG(DEBUG_MRT)
1041: logit(LOG_DEBUG, 0, "Switch shortest path (SPT): src %s, group %s",
1042: inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)));
1043:
1044: /* TODO: XXX: prepare and send immediately the (S,G) join? */
1045: mrt = find_route(source, group, MRTF_SG, CREATE);
1046: if (mrt) {
1047: if (mrt->flags & MRTF_NEW) {
1048: mrt->flags &= ~MRTF_NEW;
1049: } else if (mrt->flags & MRTF_RP || IN_PIM_SSM_RANGE(group)) {
1050: /* (S,G)RPbit with iif toward RP. Reset to (S,G) with iif
1051: * toward S. Delete the kernel cache (if any), because
1052: * change_interfaces() will reset it with iif toward S
1053: * and no data will arrive from RP before the switch
1054: * really occurs.
1055: * For SSM, (S,G)RPbit entry does not exist but switch to
1056: * SPT must be allowed right away.
1057: */
1058: mrt->flags &= ~MRTF_RP;
1059: mrt->incoming = mrt->source->incoming;
1060: mrt->upstream = mrt->source->upstream;
1061: delete_mrtentry_all_kernel_cache(mrt);
1062: change_interfaces(mrt,
1063: mrt->incoming,
1064: mrt->joined_oifs,
1065: mrt->pruned_oifs,
1066: mrt->leaves,
1067: mrt->asserted_oifs, 0);
1068: }
1069:
1070: SET_TIMER(mrt->timer, PIM_DATA_TIMEOUT);
1071: FIRE_TIMER(mrt->jp_timer);
1072: }
1073:
1074: return mrt;
1075: }
1076:
1077: /**
1078: * Local Variables:
1079: * version-control: t
1080: * indent-tabs-mode: t
1081: * c-file-style: "ellemtel"
1082: * c-basic-offset: 4
1083: * End:
1084: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>