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>