Annotation of embedaddon/pimd/mrt.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: mrt.c,v 1.27 2001/09/10 20:31:36 pavlin Exp $
32: */
33:
34:
35: #include "defs.h"
36:
37:
38: srcentry_t *srclist;
39: grpentry_t *grplist;
40:
41: /*
42: * Local functions definition
43: */
44: static srcentry_t *create_srcentry (uint32_t);
45: static int search_srclist (uint32_t, srcentry_t **);
46: static int search_srcmrtlink (srcentry_t *, uint32_t, mrtentry_t **);
47: static void insert_srcmrtlink (mrtentry_t *, mrtentry_t *, srcentry_t *);
48:
49: static grpentry_t *create_grpentry (uint32_t);
50: static int search_grplist (uint32_t, grpentry_t **);
51: static int search_grpmrtlink (grpentry_t *, uint32_t, mrtentry_t **);
52: static void insert_grpmrtlink (mrtentry_t *, mrtentry_t *, grpentry_t *);
53:
54: static mrtentry_t *alloc_mrtentry (srcentry_t *, grpentry_t *);
55: static mrtentry_t *create_mrtentry (srcentry_t *, grpentry_t *, uint16_t);
56:
57: static void move_kernel_cache (mrtentry_t *, uint16_t);
58:
59:
60: void init_pim_mrt(void)
61: {
62: /* TODO: delete any existing routing table */
63:
64: /* Initialize the source list */
65: /* The first entry has address 'INADDR_ANY' and is not used */
66: /* The order is the smallest address first. */
67: srclist = (srcentry_t *)calloc(1, sizeof(srcentry_t));
68: if (!srclist)
69: logit(LOG_ERR, 0, "Ran out of memory in init_pim_mrt()");
70: srclist->next = NULL;
71: srclist->prev = NULL;
72: srclist->address = INADDR_ANY_N;
73: srclist->mrtlink = NULL;
74: srclist->incoming = NO_VIF;
75: srclist->upstream = NULL;
76: srclist->metric = 0;
77: srclist->preference = 0;
78: RESET_TIMER(srclist->timer);
79: srclist->cand_rp = NULL;
80:
81: /* Initialize the group list */
82: /* The first entry has address 'INADDR_ANY' and is not used */
83: /* The order is the smallest address first. */
84: grplist = (grpentry_t *)calloc(1, sizeof(grpentry_t));
85: if (!grplist)
86: logit(LOG_ERR, 0, "Ran out of memory in init_pim_mrt()");
87: grplist->next = NULL;
88: grplist->prev = NULL;
89: grplist->rpnext = NULL;
90: grplist->rpprev = NULL;
91: grplist->group = INADDR_ANY_N;
92: grplist->rpaddr = INADDR_ANY_N;
93: grplist->mrtlink = NULL;
94: grplist->active_rp_grp = NULL;
95: grplist->grp_route = NULL;
96: }
97:
98:
99: grpentry_t *find_group(uint32_t group)
100: {
101: grpentry_t *grp;
102:
103: if (!IN_MULTICAST(ntohl(group)))
104: return NULL;
105:
106: if (search_grplist(group, &grp) == TRUE)
107: return grp; /* Group found! */
108:
109: return NULL;
110: }
111:
112:
113: srcentry_t *find_source(uint32_t source)
114: {
115: srcentry_t *src;
116:
117: if (!inet_valid_host(source))
118: return NULL;
119:
120: if (search_srclist(source, &src) == TRUE)
121: return src; /* Source found! */
122:
123: return NULL;
124: }
125:
126:
127: mrtentry_t *find_route(uint32_t source, uint32_t group, uint16_t flags, char create)
128: {
129: srcentry_t *src = NULL;
130: grpentry_t *grp = NULL;
131: mrtentry_t *mrt = NULL;
132: mrtentry_t *mrt_wc = NULL;
133: mrtentry_t *mrt_pmbr = NULL;
134: mrtentry_t *mrt2 = NULL;
135: rpentry_t *rp = NULL;
136: rp_grp_entry_t *rp_grp = NULL;
137:
138: if (flags & (MRTF_SG | MRTF_WC)) {
139: if (!IN_MULTICAST(ntohl(group))) {
140: logit(LOG_WARNING, 0, "find_route: Not a multicast group address (%s) ...",
141: inet_fmt(group, s1, sizeof(s1)));
142: return NULL;
143: }
144: }
145:
146: if (flags & MRTF_SG) {
147: if (!inet_valid_host(source) && !IN_PIM_SSM_RANGE(group)) {
148: logit(LOG_WARNING, 0, "find_route: Not a valid host (%s) ...",
149: inet_fmt(source, s1, sizeof(s1)));
150: return NULL;
151: }
152: }
153:
154: if (create == DONT_CREATE) {
155: if (flags & (MRTF_SG | MRTF_WC)) {
156: if (search_grplist(group, &grp) == FALSE) {
157: /* Group not found. Return the (*,*,RP) entry */
158: if (flags & MRTF_PMBR) {
159: rp = rp_match(group);
160: if (rp) {
161: logit(LOG_DEBUG, 0 , "find_route: Group not found. Return the (*,*,RP) entry");
162: return rp->mrtlink;
163: }
164: }
165:
166: logit(LOG_DEBUG, 0 , "find_route: Not PMBR, return NULL");
167: return NULL;
168: }
169:
170: /* Search for the source */
171: if (flags & MRTF_SG) {
172: if (search_grpmrtlink(grp, source, &mrt) == TRUE) {
173: /* Exact (S,G) entry found */
174: logit(LOG_DEBUG, 0 , "find_route: exact (S,G) entry found");
175: return mrt;
176: }
177:
178: logit(LOG_DEBUG, 0 , "find_route:(S,G) entry not found");
179: }
180:
181: /* No (S,G) entry. Return the (*,G) entry (if exist) */
182: if ((flags & MRTF_WC) && grp->grp_route) {
183: logit(LOG_DEBUG, 0 , "find_route: No (S,G) entry. Return the (*,G) entry");
184: return grp->grp_route;
185: }
186: }
187:
188: /* Return the (*,*,RP) entry */
189: if (flags & MRTF_PMBR) {
190: rp = NULL;
191: if (group != INADDR_ANY_N)
192: rp = rp_match(group);
193: else if (source != INADDR_ANY_N)
194: rp = rp_find(source);
195:
196: if (rp) {
197: logit(LOG_DEBUG, 0 , "find_route: Return the (*,*,RP) entry");
198: return rp->mrtlink;
199: }
200: }
201:
202: logit(LOG_DEBUG, 0 , "find_route: No SG|WC, return NULL");
203: return NULL;
204: }
205:
206:
207: /* Creation allowed */
208:
209: if (flags & (MRTF_SG | MRTF_WC)) {
210: grp = create_grpentry(group);
211: if (!grp)
212: return NULL;
213:
214: if (IN_PIM_SSM_RANGE(group)) {
215: if (rp_match(group) == (rpentry_t *) NULL) {
216: /* For SSM, virtual RP entry has to be created. RP is at local link 169.254.0.1
217: to be sure not to send any register messages outside, although sending them
218: has been disabled for SSM also in PIM protocol.
219: The address does not need to be really configured in any interface.
220: TODO: Avoid need for virtual RP by implementing SSM-specific state structures */
221: add_rp_grp_entry(&cand_rp_list, &grp_mask_list, 0x0100fea9, 20, 90, group,
222: 0xffffffff, curr_bsr_hash_mask, curr_bsr_fragment_tag);
223: }
224: }
225:
226: if (!grp->active_rp_grp) {
227: rp_grp = rp_grp_match(group);
228: if (!rp_grp) {
229: if (!grp->mrtlink && !grp->grp_route)
230: /* New created grpentry. Delete it. */
231: delete_grpentry(grp);
232:
233: return NULL;
234: }
235:
236: rp = rp_grp->rp->rpentry;
237: grp->active_rp_grp = rp_grp;
238: grp->rpaddr = rp->address;
239:
240: /* Link to the top of the rp_grp_chain */
241: grp->rpnext = rp_grp->grplink;
242: rp_grp->grplink = grp;
243: if (grp->rpnext)
244: grp->rpnext->rpprev = grp;
245: } else {
246: rp = grp->active_rp_grp->rp->rpentry;
247: }
248: }
249:
250: mrt_wc = mrt_pmbr = NULL;
251:
252: if (flags & MRTF_WC) {
253: /* Setup the (*,G) routing entry */
254: mrt_wc = create_mrtentry(NULL, grp, MRTF_WC);
255: if (!mrt_wc) {
256: if (!grp->mrtlink)
257: /* New created grpentry. Delete it. */
258: delete_grpentry(grp);
259:
260: return NULL;
261: }
262:
263: if (mrt_wc->flags & MRTF_NEW) {
264: mrt_pmbr = rp->mrtlink;
265:
266: /* Copy the oif list from the (*,*,RP) entry */
267: if (mrt_pmbr)
268: VOIF_COPY(mrt_pmbr, mrt_wc);
269:
270: mrt_wc->incoming = rp->incoming;
271: mrt_wc->upstream = rp->upstream;
272: mrt_wc->metric = rp->metric;
273: mrt_wc->preference = rp->preference;
274: move_kernel_cache(mrt_wc, 0);
275: #ifdef RSRR
276: rsrr_cache_bring_up(mrt_wc);
277: #endif /* RSRR */
278: }
279:
280: if (!(flags & MRTF_SG))
281: return mrt_wc;
282: }
283:
284: if (flags & MRTF_SG) {
285: /* Setup the (S,G) routing entry */
286: src = create_srcentry(source);
287: if (!src) {
288: /* TODO: XXX: The MRTF_NEW flag check may be misleading?? check */
289: if ((!grp->grp_route || (grp->grp_route && (grp->grp_route->flags & MRTF_NEW)))
290: && !grp->mrtlink) {
291: /* New created grpentry. Delete it. */
292: delete_grpentry(grp);
293: }
294:
295: return NULL;
296: }
297:
298: mrt = create_mrtentry(src, grp, MRTF_SG);
299: if (!mrt) {
300: if ((!grp->grp_route
301: || (grp->grp_route && (grp->grp_route->flags & MRTF_NEW)))
302: && !grp->mrtlink) {
303: /* New created grpentry. Delete it. */
304: delete_grpentry(grp);
305: }
306:
307: if (!src->mrtlink)
308: /* New created srcentry. Delete it. */
309: delete_srcentry(src);
310:
311: return NULL;
312: }
313:
314: if (mrt->flags & MRTF_NEW) {
315: mrt2 = grp->grp_route;
316: if (!mrt2)
317: mrt2 = rp->mrtlink;
318:
319: /* Copy the oif list from the existing (*,G) or (*,*,RP) entry */
320: if (mrt2) {
321: VOIF_COPY(mrt2, mrt);
322: if (flags & MRTF_RP) {
323: /* ~(S,G) prune entry */
324: mrt->incoming = mrt2->incoming;
325: mrt->upstream = mrt2->upstream;
326: mrt->metric = mrt2->metric;
327: mrt->preference = mrt2->preference;
328: mrt->flags |= MRTF_RP;
329: }
330: }
331:
332: if (!(mrt->flags & MRTF_RP)) {
333: mrt->incoming = src->incoming;
334: mrt->upstream = src->upstream;
335: mrt->metric = src->metric;
336: mrt->preference = src->preference;
337: }
338: move_kernel_cache(mrt, 0);
339: #ifdef RSRR
340: rsrr_cache_bring_up(mrt);
341: #endif /* RSRR */
342: }
343:
344: return mrt;
345: }
346:
347: if (flags & MRTF_PMBR) {
348: /* Get/return the (*,*,RP) routing entry */
349: if (group != INADDR_ANY_N)
350: rp = rp_match(group);
351: else if (source != INADDR_ANY_N)
352: rp = rp_find(source);
353: else
354: return NULL; /* source == group == INADDR_ANY */
355:
356: if (!rp)
357: return NULL;
358:
359: if (rp->mrtlink)
360: return rp->mrtlink;
361:
362: mrt = create_mrtentry(rp, NULL, MRTF_PMBR);
363: if (!mrt)
364: return NULL;
365:
366: mrt->incoming = rp->incoming;
367: mrt->upstream = rp->upstream;
368: mrt->metric = rp->metric;
369: mrt->preference = rp->preference;
370:
371: return mrt;
372: }
373:
374: return NULL;
375: }
376:
377:
378: void delete_srcentry(srcentry_t *src)
379: {
380: mrtentry_t *node;
381: mrtentry_t *next;
382:
383: if (!src)
384: return;
385:
386: /* TODO: XXX: the first entry is unused and always there */
387: src->prev->next = src->next;
388: if (src->next)
389: src->next->prev = src->prev;
390:
391: for (node = src->mrtlink; node; node = next) {
392: next = node->srcnext;
393: if (node->flags & MRTF_KERNEL_CACHE)
394: /* Delete the kernel cache first */
395: delete_mrtentry_all_kernel_cache(node);
396:
397: if (node->grpprev) {
398: node->grpprev->grpnext = node->grpnext;
399: } else {
400: node->group->mrtlink = node->grpnext;
401: if (!node->grpnext && !node->group->grp_route)
402: /* Delete the group entry if it has no (*,G) routing entry */
403: delete_grpentry(node->group);
404: }
405:
406: if (node->grpnext)
407: node->grpnext->grpprev = node->grpprev;
408:
409: FREE_MRTENTRY(node);
410: }
411:
412: free(src);
413: }
414:
415:
416: void delete_grpentry(grpentry_t *grp)
417: {
418: mrtentry_t *node;
419: mrtentry_t *next;
420:
421: if (!grp)
422: return;
423:
424: /* TODO: XXX: the first entry is unused and always there */
425: grp->prev->next = grp->next;
426: if (grp->next)
427: grp->next->prev = grp->prev;
428:
429: if (grp->grp_route) {
430: if (grp->grp_route->flags & MRTF_KERNEL_CACHE)
431: delete_mrtentry_all_kernel_cache(grp->grp_route);
432: FREE_MRTENTRY(grp->grp_route);
433: }
434:
435: /* Delete from the rp_grp_entry chain */
436: if (grp->active_rp_grp) {
437: if (grp->rpnext)
438: grp->rpnext->rpprev = grp->rpprev;
439:
440: if (grp->rpprev)
441: grp->rpprev->rpnext = grp->rpnext;
442: else
443: grp->active_rp_grp->grplink = grp->rpnext;
444: }
445:
446: for (node = grp->mrtlink; node; node = next) {
447: next = node->grpnext;
448: if (node->flags & MRTF_KERNEL_CACHE)
449: /* Delete the kernel cache first */
450: delete_mrtentry_all_kernel_cache(node);
451:
452: if (node->srcprev) {
453: node->srcprev->srcnext = node->srcnext;
454: } else {
455: node->source->mrtlink = node->srcnext;
456: if (!node->srcnext) {
457: /* Delete the srcentry if this was the last routing entry */
458: delete_srcentry(node->source);
459: }
460: }
461:
462: if (node->srcnext)
463: node->srcnext->srcprev = node->srcprev;
464:
465: FREE_MRTENTRY(node);
466: }
467:
468: free(grp);
469: }
470:
471:
472: void delete_mrtentry(mrtentry_t *mrt)
473: {
474: grpentry_t *grp;
475: mrtentry_t *mrt_wc;
476: mrtentry_t *mrt_rp;
477:
478: if (!mrt)
479: return;
480:
481: /* Delete the kernel cache first */
482: if (mrt->flags & MRTF_KERNEL_CACHE)
483: delete_mrtentry_all_kernel_cache(mrt);
484:
485: #ifdef RSRR
486: /* Tell the reservation daemon */
487: rsrr_cache_clean(mrt);
488: #endif /* RSRR */
489:
490: if (mrt->flags & MRTF_PMBR) {
491: /* (*,*,RP) mrtentry */
492: mrt->source->mrtlink = NULL;
493: } else if (mrt->flags & MRTF_SG) {
494: /* (S,G) mrtentry */
495:
496: /* Delete from the grpentry MRT chain */
497: if (mrt->grpprev) {
498: mrt->grpprev->grpnext = mrt->grpnext;
499: } else {
500: mrt->group->mrtlink = mrt->grpnext;
501: if (!mrt->grpnext) {
502: /* All (S,G) MRT entries are gone. Allow creating (*,G) MFC entries. */
503: mrt_rp = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
504: mrt_wc = mrt->group->grp_route;
505: if (mrt_rp)
506: mrt_rp->flags &= ~MRTF_MFC_CLONE_SG;
507:
508: if (mrt_wc)
509: mrt_wc->flags &= ~MRTF_MFC_CLONE_SG;
510: else
511: /* Delete the group entry if it has no (*,G) routing entry */
512: delete_grpentry(mrt->group);
513: }
514: }
515:
516: if (mrt->grpnext)
517: mrt->grpnext->grpprev = mrt->grpprev;
518:
519: /* Delete from the srcentry MRT chain */
520: if (mrt->srcprev) {
521: mrt->srcprev->srcnext = mrt->srcnext;
522: } else {
523: mrt->source->mrtlink = mrt->srcnext;
524: if (!mrt->srcnext)
525: /* Delete the srcentry if this was the last routing entry */
526: delete_srcentry(mrt->source);
527: }
528:
529: if (mrt->srcnext)
530: mrt->srcnext->srcprev = mrt->srcprev;
531: } else {
532: /* This mrtentry should be (*,G) */
533: grp = mrt->group;
534: grp->grp_route = NULL;
535:
536: /* Delete the group entry if it has no (S,G) entries */
537: if (!grp->mrtlink)
538: delete_grpentry(grp);
539: }
540:
541: FREE_MRTENTRY(mrt);
542: }
543:
544:
545: static int search_srclist(uint32_t source, srcentry_t **found)
546: {
547: srcentry_t *prev, *node;
548: uint32_t source_h = ntohl(source);
549:
550: for (prev = srclist, node = prev->next; node; prev = node, node = node->next) {
551: /* The srclist is ordered with the smallest addresses first.
552: * The first entry is not used. */
553: if (ntohl(node->address) < source_h)
554: continue;
555:
556: if (node->address == source) {
557: *found = node;
558: return TRUE;
559: }
560: break;
561: }
562:
563: *found = prev; /* The insertion point is between s_prev and s */
564:
565: return FALSE;
566: }
567:
568:
569: static int search_grplist(uint32_t group, grpentry_t **found)
570: {
571: grpentry_t *prev, *node;
572: uint32_t group_h = ntohl(group);
573:
574: for (prev = grplist, node = prev->next; node; prev = node, node = node->next) {
575: /* The grplist is ordered with the smallest address first.
576: * The first entry is not used. */
577: if (ntohl(node->group) < group_h)
578: continue;
579:
580: if (node->group == group) {
581: *found = node;
582: return TRUE;
583: }
584: break;
585: }
586:
587: *found = prev; /* The insertion point is between prev and g */
588:
589: return FALSE;
590: }
591:
592:
593: static srcentry_t *create_srcentry(uint32_t source)
594: {
595: srcentry_t *node;
596: srcentry_t *prev;
597:
598: if (search_srclist(source, &prev) == TRUE)
599: return prev;
600:
601: node = calloc(1, sizeof(srcentry_t));
602: if (!node) {
603: logit(LOG_WARNING, 0, "Memory allocation error for srcentry %s",
604: inet_fmt(source, s1, sizeof(s1)));
605: return NULL;
606: }
607:
608: node->address = source;
609: /* Free the memory if there is error getting the iif and
610: * the next hop (upstream) router. */
611: if (set_incoming(node, PIM_IIF_SOURCE) == FALSE) {
612: free(node);
613: return NULL;
614: }
615:
616: RESET_TIMER(node->timer);
617: node->mrtlink = NULL;
618: node->cand_rp = NULL;
619: node->next = prev->next;
620: prev->next = node;
621: node->prev = prev;
622: if (node->next)
623: node->next->prev = node;
624:
625: IF_DEBUG(DEBUG_MFC) {
626: logit(LOG_DEBUG, 0, "create source entry, source %s",
627: inet_fmt(source, s1, sizeof(s1)));
628: }
629:
630: return node;
631: }
632:
633:
634: static grpentry_t *create_grpentry(uint32_t group)
635: {
636: grpentry_t *node;
637: grpentry_t *prev;
638:
639: /* If already exists, return it. Otheriwse search_grplist() returns the
640: * insertion point in prev. */
641: if (search_grplist(group, &prev) == TRUE)
642: return prev;
643:
644: node = calloc(1, sizeof(grpentry_t));
645: if (!node) {
646: logit(LOG_WARNING, 0, "Memory allocation error for grpentry %s",
647: inet_fmt(group, s1, sizeof(s1)));
648: return NULL;
649: }
650:
651: /*
652: * TODO: XXX: Note that this is NOT a (*,G) routing entry, but simply
653: * a group entry, probably used to search the routing table (to find
654: * (S,G) entries for example.)
655: * To become (*,G) routing entry, we must setup node->grp_route
656: */
657: node->group = group;
658: node->rpaddr = INADDR_ANY_N;
659: node->mrtlink = NULL;
660: node->active_rp_grp = NULL;
661: node->grp_route = NULL;
662: node->rpnext = NULL;
663: node->rpprev = NULL;
664:
665: /* Now it is safe to include the new group entry */
666: node->next = prev->next;
667: prev->next = node;
668: node->prev = prev;
669: if (node->next)
670: node->next->prev = node;
671:
672: IF_DEBUG(DEBUG_MFC) {
673: logit(LOG_DEBUG, 0, "create group entry, group %s", inet_fmt(group, s1, sizeof(s1)));
674: }
675:
676: return node;
677: }
678:
679:
680: /*
681: * Return TRUE if the entry is found and then *found is set to point to
682: * that entry. Otherwise return FALSE and *found points the previous
683: * entry, or NULL if first in the chain.
684: */
685: static int search_srcmrtlink(srcentry_t *src, uint32_t group, mrtentry_t **found)
686: {
687: mrtentry_t *node;
688: mrtentry_t *prev = NULL;
689: uint32_t group_h = ntohl(group);
690:
691: for (node = src->mrtlink; node; prev = node, node = node->srcnext) {
692: /* The entries are ordered with the smaller group address first.
693: * The addresses are in network order. */
694: if (ntohl(node->group->group) < group_h)
695: continue;
696:
697: if (node->group->group == group) {
698: *found = node;
699: return TRUE;
700: }
701:
702: break;
703: }
704:
705: *found = prev;
706:
707: return FALSE;
708: }
709:
710:
711: /*
712: * Return TRUE if the entry is found and then *found is set to point to
713: * that entry. Otherwise return FALSE and *found points the previous
714: * entry, or NULL if first in the chain.
715: */
716: static int search_grpmrtlink(grpentry_t *grp, uint32_t source, mrtentry_t **found)
717: {
718: mrtentry_t *node;
719: mrtentry_t *prev = NULL;
720: uint32_t source_h = ntohl(source);
721:
722: for (node = grp->mrtlink; node; prev = node, node = node->grpnext) {
723: /* The entries are ordered with the smaller source address first.
724: * The addresses are in network order. */
725: if (ntohl(node->source->address) < source_h)
726: continue;
727:
728: if (source == node->source->address) {
729: *found = node;
730: return TRUE;
731: }
732:
733: break;
734: }
735:
736: *found = prev;
737:
738: return FALSE;
739: }
740:
741:
742: static void insert_srcmrtlink(mrtentry_t *node, mrtentry_t *prev, srcentry_t *src)
743: {
744: if (!prev) {
745: /* Has to be insert as the head entry for this source */
746: node->srcnext = src->mrtlink;
747: node->srcprev = NULL;
748: src->mrtlink = node;
749: } else {
750: /* Insert right after the prev */
751: node->srcnext = prev->srcnext;
752: node->srcprev = prev;
753: prev->srcnext = node;
754: }
755:
756: if (node->srcnext)
757: node->srcnext->srcprev = node;
758: }
759:
760:
761: static void insert_grpmrtlink(mrtentry_t *node, mrtentry_t *prev, grpentry_t *grp)
762: {
763: if (!prev) {
764: /* Has to be insert as the head entry for this group */
765: node->grpnext = grp->mrtlink;
766: node->grpprev = NULL;
767: grp->mrtlink = node;
768: } else {
769: /* Insert right after the prev */
770: node->grpnext = prev->grpnext;
771: node->grpprev = prev;
772: prev->grpnext = node;
773: }
774:
775: if (node->grpnext)
776: node->grpnext->grpprev = node;
777: }
778:
779:
780: static mrtentry_t *alloc_mrtentry(srcentry_t *src, grpentry_t *grp)
781: {
782: mrtentry_t *mrt;
783: uint16_t i, *timer;
784: uint8_t vif_numbers;
785:
786: mrt = calloc(1, sizeof(mrtentry_t));
787: if (!mrt) {
788: logit(LOG_WARNING, 0, "alloc_mrtentry(): out of memory");
789: return NULL;
790: }
791:
792: /*
793: * grpnext, grpprev, srcnext, srcprev will be setup when we link the
794: * mrtentry to the source and group chains
795: */
796: mrt->source = src;
797: mrt->group = grp;
798: mrt->incoming = NO_VIF;
799: VIFM_CLRALL(mrt->joined_oifs);
800: VIFM_CLRALL(mrt->leaves);
801: VIFM_CLRALL(mrt->pruned_oifs);
802: VIFM_CLRALL(mrt->asserted_oifs);
803: VIFM_CLRALL(mrt->oifs);
804: mrt->upstream = NULL;
805: mrt->metric = 0;
806: mrt->preference = 0;
807: mrt->pmbr_addr = INADDR_ANY_N;
808: #ifdef RSRR
809: mrt->rsrr_cache = NULL;
810: #endif /* RSRR */
811:
812: /* XXX: TODO: if we are short in memory, we can reserve as few as possible
813: * space for vif timers (per group and/or routing entry), but then everytime
814: * when a new interfaces is configured, the router will be restarted and
815: * will delete the whole routing table. The "memory is cheap" solution is
816: * to reserve timer space for all potential vifs in advance and then no
817: * need to delete the routing table and disturb the forwarding.
818: */
819: #ifdef SAVE_MEMORY
820: mrt->vif_timers = (uint16_t *)calloc(1, sizeof(uint16_t) * numvifs);
821: mrt->vif_deletion_delay = (uint16_t *)calloc(1, sizeof(uint16_t) * numvifs);
822: vif_numbers = numvifs;
823: #else
824: mrt->vif_timers = (uint16_t *)calloc(1, sizeof(uint16_t) * total_interfaces);
825: mrt->vif_deletion_delay = (uint16_t *)calloc(1, sizeof(uint16_t) * total_interfaces);
826: vif_numbers = total_interfaces;
827: #endif /* SAVE_MEMORY */
828: if (!mrt->vif_timers || !mrt->vif_deletion_delay) {
829: logit(LOG_WARNING, 0, "alloc_mrtentry(): out of memory");
830: FREE_MRTENTRY(mrt);
831: return NULL;
832: }
833:
834: /* Reset the timers */
835: for (i = 0, timer = mrt->vif_timers; i < vif_numbers; i++, timer++)
836: RESET_TIMER(*timer);
837:
838: for (i = 0, timer = mrt->vif_deletion_delay; i < vif_numbers; i++, timer++)
839: RESET_TIMER(*timer);
840:
841: mrt->flags = MRTF_NEW;
842: RESET_TIMER(mrt->timer);
843: RESET_TIMER(mrt->jp_timer);
844: RESET_TIMER(mrt->rs_timer);
845: RESET_TIMER(mrt->assert_timer);
846: RESET_TIMER(mrt->assert_rate_timer);
847: mrt->kernel_cache = NULL;
848:
849: return mrt;
850: }
851:
852:
853: static mrtentry_t *create_mrtentry(srcentry_t *src, grpentry_t *grp, uint16_t flags)
854: {
855: mrtentry_t *node;
856: mrtentry_t *grp_insert, *src_insert; /* pointers to insert */
857: uint32_t source;
858: uint32_t group;
859:
860: if (flags & MRTF_SG) {
861: /* (S,G) entry */
862: source = src->address;
863: group = grp->group;
864:
865: if (search_grpmrtlink(grp, source, &grp_insert) == TRUE)
866: return grp_insert;
867:
868: if (search_srcmrtlink(src, group, &src_insert) == TRUE) {
869: /* Hmmm, search_grpmrtlink() didn't find the entry, but
870: * search_srcmrtlink() did find it! Shouldn't happen. Panic! */
871: logit(LOG_ERR, 0, "MRT inconsistency for src %s and grp %s\n",
872: inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)));
873:
874: /* not reached but to make lint happy */
875: return NULL;
876: }
877:
878: /* Create and insert in group mrtlink and source mrtlink chains. */
879: node = alloc_mrtentry(src, grp);
880: if (!node)
881: return NULL;
882:
883: /* node has to be insert right after grp_insert in the grp
884: * mrtlink chain and right after src_insert in the src mrtlink
885: * chain */
886: insert_grpmrtlink(node, grp_insert, grp);
887: insert_srcmrtlink(node, src_insert, src);
888: node->flags |= MRTF_SG;
889:
890: return node;
891: }
892:
893: if (flags & MRTF_WC) {
894: /* (*,G) entry */
895: if (grp->grp_route)
896: return grp->grp_route;
897:
898: node = alloc_mrtentry(src, grp);
899: if (!node)
900: return NULL;
901:
902: grp->grp_route = node;
903: node->flags |= (MRTF_WC | MRTF_RP);
904:
905: return node;
906: }
907:
908: if (flags & MRTF_PMBR) {
909: /* (*,*,RP) entry */
910: if (src->mrtlink)
911: return src->mrtlink;
912:
913: node = alloc_mrtentry(src, grp);
914: if (!node)
915: return NULL;
916:
917: src->mrtlink = node;
918: node->flags |= (MRTF_PMBR | MRTF_RP);
919:
920: return node;
921: }
922:
923: return NULL;
924: }
925:
926:
927: /*
928: * Delete all kernel cache for this mrtentry
929: */
930: void delete_mrtentry_all_kernel_cache(mrtentry_t *mrt)
931: {
932: kernel_cache_t *prev;
933: kernel_cache_t *node;
934:
935: if (!(mrt->flags & MRTF_KERNEL_CACHE))
936: return;
937:
938: /* Free all kernel_cache entries */
939: for (node = mrt->kernel_cache; node; ) {
940: prev = node;
941: node = node->next;
942:
943: logit(LOG_DEBUG, 0, "delete_mrtentry_all_kernel_cache: SG");
944: k_del_mfc(igmp_socket, prev->source, prev->group);
945: free(prev);
946: }
947: mrt->kernel_cache = NULL;
948:
949: /* turn off the cache flag(s) */
950: mrt->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
951: }
952:
953:
954: void delete_single_kernel_cache(mrtentry_t *mrt, kernel_cache_t *node)
955: {
956: if (!mrt || !node)
957: return;
958:
959: if (!node->prev) {
960: mrt->kernel_cache = node->next;
961: if (!mrt->kernel_cache)
962: mrt->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
963: } else {
964: node->prev->next = node->next;
965: }
966:
967: if (node->next)
968: node->next->prev = node->prev;
969:
970: IF_DEBUG(DEBUG_MFC) {
971: logit(LOG_DEBUG, 0, "Deleting MFC entry for source %s and group %s",
972: inet_fmt(node->source, s1, sizeof(s1)),
973: inet_fmt(node->group, s2, sizeof(s2)));
974: }
975:
976: logit(LOG_DEBUG, 0, "delete_single_kernel_cache: SG");
977: k_del_mfc(igmp_socket, node->source, node->group);
978: free(node);
979: }
980:
981:
982: void delete_single_kernel_cache_addr(mrtentry_t *mrt, uint32_t source, uint32_t group)
983: {
984: uint32_t source_h;
985: uint32_t group_h;
986: kernel_cache_t *node;
987:
988: if (!mrt)
989: return;
990:
991: source_h = ntohl(source);
992: group_h = ntohl(group);
993:
994: /* Find the exact (S,G) kernel_cache entry */
995: for (node = mrt->kernel_cache; node; node = node->next) {
996: if (ntohl(node->group) < group_h)
997: continue;
998: if (ntohl(node->group) > group_h)
999: return; /* Not found */
1000: if (ntohl(node->source) < source_h)
1001: continue;
1002: if (ntohl(node->source) > source_h)
1003: return; /* Not found */
1004:
1005: /* Found exact match */
1006: break;
1007: }
1008:
1009: if (!node)
1010: return;
1011:
1012: /* Found. Delete it */
1013: if (!node->prev) {
1014: mrt->kernel_cache = node->next;
1015: if (!mrt->kernel_cache)
1016: mrt->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
1017: } else{
1018: node->prev->next = node->next;
1019: }
1020:
1021: if (node->next)
1022: node->next->prev = node->prev;
1023:
1024: IF_DEBUG(DEBUG_MFC) {
1025: logit(LOG_DEBUG, 0, "Deleting MFC entry for source %s and group %s",
1026: inet_fmt(node->source, s1, sizeof(s1)),
1027: inet_fmt(node->group, s2, sizeof(s2)));
1028: }
1029:
1030: logit(LOG_DEBUG, 0, "delete_single_kernel_cache_addr: SG");
1031: k_del_mfc(igmp_socket, node->source, node->group);
1032: free(node);
1033: }
1034:
1035:
1036: /*
1037: * Installs kernel cache for (source, group). Assumes mrt
1038: * is the correct entry.
1039: */
1040: void add_kernel_cache(mrtentry_t *mrt, uint32_t source, uint32_t group, uint16_t flags)
1041: {
1042: uint32_t source_h;
1043: uint32_t group_h;
1044: kernel_cache_t *next;
1045: kernel_cache_t *prev;
1046: kernel_cache_t *node;
1047:
1048: if (!mrt)
1049: return;
1050:
1051: move_kernel_cache(mrt, flags);
1052:
1053: if (mrt->flags & MRTF_SG) {
1054: /* (S,G) */
1055: if (mrt->flags & MRTF_KERNEL_CACHE)
1056: return;
1057:
1058: node = (kernel_cache_t *)calloc(1, sizeof(kernel_cache_t));
1059: node->next = NULL;
1060: node->prev = NULL;
1061: node->source = source;
1062: node->group = group;
1063: node->sg_count.pktcnt = 0;
1064: node->sg_count.bytecnt = 0;
1065: node->sg_count.wrong_if = 0;
1066: mrt->kernel_cache = node;
1067: mrt->flags |= MRTF_KERNEL_CACHE;
1068:
1069: return;
1070: }
1071:
1072: source_h = ntohl(source);
1073: group_h = ntohl(group);
1074: prev = NULL;
1075:
1076: for (next = mrt->kernel_cache; next; prev = next, next = next->next) {
1077: if (ntohl(next->group) < group_h)
1078: continue;
1079: if (ntohl(next->group) > group_h)
1080: break;
1081: if (ntohl(next->source) < source_h)
1082: continue;
1083: if (ntohl(next->source) > source_h)
1084: break;
1085:
1086: /* Found exact match. Nothing to change. */
1087: return;
1088: }
1089:
1090: /* The new entry must be placed between prev and
1091: * next */
1092: node = calloc(1, sizeof(kernel_cache_t));
1093: if (prev)
1094: prev->next = node;
1095: else
1096: mrt->kernel_cache = node;
1097:
1098: if (next)
1099: next->prev = node;
1100:
1101: node->prev = prev;
1102: node->next = next;
1103: node->source = source;
1104: node->group = group;
1105: node->sg_count.pktcnt = 0;
1106: node->sg_count.bytecnt = 0;
1107: node->sg_count.wrong_if = 0;
1108:
1109: mrt->flags |= MRTF_KERNEL_CACHE;
1110: }
1111:
1112: /*
1113: * Bring the kernel cache "UP": from the (*,*,RP) to (*,G) or (S,G)
1114: */
1115: static void move_kernel_cache(mrtentry_t *mrt, uint16_t flags)
1116: {
1117: kernel_cache_t *node;
1118: kernel_cache_t *insert_node;
1119: kernel_cache_t *first_node;
1120: kernel_cache_t *last_node;
1121: kernel_cache_t *prev_node;
1122: mrtentry_t *mrtentry_pmbr;
1123: mrtentry_t *mrtentry_rp;
1124: uint32_t group_h;
1125: uint32_t source_h;
1126: int found;
1127:
1128: if (!mrt)
1129: return;
1130:
1131: if (mrt->flags & MRTF_PMBR)
1132: return;
1133:
1134: if (mrt->flags & MRTF_WC) {
1135: /* Move the cache info from (*,*,RP) to (*,G) */
1136: group_h = ntohl(mrt->group->group);
1137: mrtentry_pmbr = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
1138: if (!mrtentry_pmbr)
1139: return; /* Nothing to move */
1140:
1141: first_node = last_node = NULL;
1142: for (node = mrtentry_pmbr->kernel_cache; node; node = node->next) {
1143: /*
1144: * The order is: (1) smaller group;
1145: * (2) smaller source within group
1146: */
1147: if (ntohl(node->group) < group_h)
1148: continue;
1149:
1150: if (ntohl(node->group) != group_h)
1151: break;
1152:
1153: /* Select the kernel_cache entries to move */
1154: if (!first_node)
1155: first_node = last_node = node;
1156: else
1157: last_node = node;
1158: }
1159:
1160: if (first_node) {
1161: /* Fix the old chain */
1162: if (first_node->prev)
1163: first_node->prev->next = last_node->next;
1164: else
1165: mrtentry_pmbr->kernel_cache = last_node->next;
1166:
1167: if (last_node->next)
1168: last_node->next->prev = first_node->prev;
1169:
1170: if (!mrtentry_pmbr->kernel_cache)
1171: mrtentry_pmbr->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
1172:
1173: /* Insert in the new place */
1174: prev_node = NULL;
1175: last_node->next = NULL;
1176: mrt->flags |= MRTF_KERNEL_CACHE;
1177:
1178: for (node = mrt->kernel_cache; node; ) {
1179: if (!first_node)
1180: break; /* All entries have been inserted */
1181:
1182: if (ntohl(node->source) > ntohl(first_node->source)) {
1183: /* Insert the entry before node */
1184: insert_node = first_node;
1185: first_node = first_node->next;
1186:
1187: if (node->prev)
1188: node->prev->next = insert_node;
1189: else
1190: mrt->kernel_cache = insert_node;
1191:
1192: insert_node->prev = node->prev;
1193: insert_node->next = node;
1194: node->prev = insert_node;
1195: }
1196: prev_node = node;
1197: node = node->next;
1198: }
1199:
1200: if (first_node) {
1201: /* Place all at the end after prev_node */
1202: if (prev_node)
1203: prev_node->next = first_node;
1204: else
1205: mrt->kernel_cache = first_node;
1206:
1207: first_node->prev = prev_node;
1208: }
1209: }
1210:
1211: return;
1212: }
1213:
1214: if (mrt->flags & MRTF_SG) {
1215: logit(LOG_DEBUG, 0, "move_kernel_cache: SG");
1216: /* (S,G) entry. Move the whole group cache from (*,*,RP) to (*,G) and
1217: * then get the necessary entry from (*,G).
1218: * TODO: Not optimized! The particular entry is moved first to (*,G),
1219: * then we have to search again (*,G) to find it and move to (S,G).
1220: */
1221: /* TODO: XXX: No need for this? Thinking.... */
1222: /* move_kernel_cache(mrt->group->grp_route, flags); */
1223: mrtentry_rp = mrt->group->grp_route;
1224: if (!mrtentry_rp) {
1225: mrtentry_rp = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
1226: if (!mrtentry_rp)
1227: return;
1228: }
1229:
1230: if (mrtentry_rp->incoming != mrt->incoming) {
1231: /* XXX: the (*,*,RP) (or (*,G)) iif is different from the
1232: * (S,G) iif. No need to move the cache, because (S,G) don't
1233: * need it. After the first packet arrives on the shortest path,
1234: * the correct cache entry will be created.
1235: * If (flags & MFC_MOVE_FORCE) then we must move the cache.
1236: * This usually happens when switching to the shortest path.
1237: * The calling function will immediately call k_chg_mfc()
1238: * to modify the kernel cache.
1239: */
1240: if (!(flags & MFC_MOVE_FORCE))
1241: return;
1242: }
1243:
1244: /* Find the exact entry */
1245: source_h = ntohl(mrt->source->address);
1246: group_h = ntohl(mrt->group->group);
1247: found = FALSE;
1248: for (node = mrtentry_rp->kernel_cache; node; node = node->next) {
1249: if (ntohl(node->group) < group_h)
1250: continue;
1251:
1252: if (ntohl(node->group) > group_h)
1253: break;
1254:
1255: if (ntohl(node->source) < source_h)
1256: continue;
1257:
1258: if (ntohl(node->source) > source_h)
1259: break;
1260:
1261: /* We found it! */
1262: if (node->prev)
1263: node->prev->next = node->next;
1264: else
1265: mrtentry_rp->kernel_cache = node->next;
1266:
1267: if (node->next)
1268: node->next->prev = node->prev;
1269:
1270: found = TRUE;
1271:
1272: break;
1273: }
1274:
1275: if (found == TRUE) {
1276: if (!mrtentry_rp->kernel_cache)
1277: mrtentry_rp->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
1278:
1279: if (mrt->kernel_cache)
1280: free(mrt->kernel_cache);
1281:
1282: mrt->flags |= MRTF_KERNEL_CACHE;
1283: mrt->kernel_cache = node;
1284:
1285: node->prev = NULL;
1286: node->next = NULL;
1287: }
1288: }
1289: }
1290:
1291: /**
1292: * Local Variables:
1293: * version-control: t
1294: * indent-tabs-mode: t
1295: * c-file-style: "ellemtel"
1296: * c-basic-offset: 4
1297: * End:
1298: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>