Annotation of embedaddon/pimd/rp.c, revision 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: #include "defs.h"
        !            32: 
        !            33: 
        !            34: /*
        !            35:  * The hash function. Stollen from Eddy's (eddy@isi.edu)
        !            36:  * implementation (for compatibility ;)
        !            37:  */
        !            38: #define SEED1   1103515245
        !            39: #define SEED2   12345
        !            40: #define RP_HASH_VALUE(G, M, C) (((SEED1) * (((SEED1) * ((G) & (M)) + (SEED2)) ^ (C)) + (SEED2)) % 0x80000000)
        !            41: 
        !            42: cand_rp_t               *cand_rp_list;
        !            43: grp_mask_t              *grp_mask_list;
        !            44: cand_rp_t               *segmented_cand_rp_list;
        !            45: grp_mask_t              *segmented_grp_mask_list;
        !            46: uint16_t                 curr_bsr_fragment_tag;
        !            47: uint8_t                  curr_bsr_priority;
        !            48: uint32_t                 curr_bsr_address;
        !            49: uint32_t                 curr_bsr_hash_mask;
        !            50: uint16_t                 pim_bootstrap_timer;   /* For electing the BSR and
        !            51:                                                 * sending Cand-RP-set msgs */
        !            52: uint8_t                  my_bsr_priority;
        !            53: uint32_t                 my_bsr_address;
        !            54: uint32_t                 my_bsr_hash_mask;
        !            55: uint8_t                  cand_bsr_flag = FALSE; /* Set to TRUE if I am
        !            56:                                                 * a candidate BSR */
        !            57: uint32_t                 my_cand_rp_address;
        !            58: uint8_t                  my_cand_rp_priority;
        !            59: uint16_t                 my_cand_rp_holdtime;
        !            60: uint16_t                 my_cand_rp_adv_period; /* The locally configured
        !            61:                                                 * Cand-RP adv. period. */
        !            62: uint16_t                 pim_cand_rp_adv_timer;
        !            63: uint8_t                  cand_rp_flag  = FALSE;  /* Candidate RP flag */
        !            64: struct cand_rp_adv_message_ cand_rp_adv_message;
        !            65: uint32_t                 rp_my_ipv4_hashmask;
        !            66: 
        !            67: 
        !            68: /*
        !            69:  * Local functions definition.
        !            70:  */
        !            71: static cand_rp_t  *add_cand_rp          (cand_rp_t **used_cand_rp_list, uint32_t address);
        !            72: static grp_mask_t *add_grp_mask         (grp_mask_t **used_grp_mask_list,
        !            73:                                         uint32_t group_addr,
        !            74:                                         uint32_t group_mask,
        !            75:                                         uint32_t hash_mask);
        !            76: static void       delete_grp_mask_entry (cand_rp_t **used_cand_rp_list,
        !            77:                                         grp_mask_t **used_grp_mask_list,
        !            78:                                         grp_mask_t *grp_mask_delete);
        !            79: static void       delete_rp_entry       (cand_rp_t **used_cand_rp_list,
        !            80:                                         grp_mask_t **used_grp_mask_list,
        !            81:                                         cand_rp_t *cand_rp_ptr);
        !            82: 
        !            83: 
        !            84: void init_rp_and_bsr(void)
        !            85: {
        !            86:     /* TODO: if the grplist is not NULL, remap all groups ASAP! */
        !            87:     delete_rp_list(&cand_rp_list, &grp_mask_list);
        !            88:     delete_rp_list(&segmented_cand_rp_list, &segmented_grp_mask_list);
        !            89: 
        !            90:     if (cand_bsr_flag == FALSE) {
        !            91:        /*
        !            92:         * If I am not candidat BSR, initialize the "current BSR"
        !            93:         * as having the lowest priority.
        !            94:         */
        !            95:        curr_bsr_fragment_tag = 0;
        !            96:        curr_bsr_priority = 0;             /* Lowest priority */
        !            97:        curr_bsr_address  = INADDR_ANY_N;  /* Lowest priority */
        !            98:        MASKLEN_TO_MASK(RP_DEFAULT_IPV4_HASHMASKLEN, curr_bsr_hash_mask);
        !            99:        SET_TIMER(pim_bootstrap_timer, PIM_BOOTSTRAP_TIMEOUT);
        !           100:     } else {
        !           101:        curr_bsr_fragment_tag = RANDOM();
        !           102:        curr_bsr_priority = my_bsr_priority;
        !           103:        curr_bsr_address = my_bsr_address;
        !           104:        curr_bsr_hash_mask = my_bsr_hash_mask;
        !           105:        SET_TIMER(pim_bootstrap_timer, bootstrap_initial_delay());
        !           106:     }
        !           107: 
        !           108:     if (cand_rp_flag != FALSE) {
        !           109:        MASKLEN_TO_MASK(RP_DEFAULT_IPV4_HASHMASKLEN, rp_my_ipv4_hashmask);
        !           110:        /* Setup the Cand-RP-Adv-Timer */
        !           111:        SET_TIMER(pim_cand_rp_adv_timer, RANDOM() % my_cand_rp_adv_period);
        !           112:     }
        !           113: }
        !           114: 
        !           115: 
        !           116: uint16_t bootstrap_initial_delay(void)
        !           117: {
        !           118:     uint32_t addr_delay;
        !           119:     uint32_t delay;
        !           120:     uint32_t log_mask;
        !           121:     int32_t  log_of_2;
        !           122:     uint8_t  best_priority;
        !           123: 
        !           124:     /*
        !           125:      * The bootstrap timer initial value (if Cand-BSR).
        !           126:      * It depends of the bootstrap router priority:
        !           127:      * higher priority has shorter value:
        !           128:      *
        !           129:      * delay = 5 + 2 * log_2(1 + best_priority - myPriority) + addr_delay;
        !           130:      *
        !           131:      *    best_priority = Max(storedPriority, myPriority);
        !           132:      *    if (best_priority == myPriority)
        !           133:      *        addr_delay = log_2(bestAddr - myAddr)/16;
        !           134:      *    else
        !           135:      *        addr_delay = 2 - (myAddr/2^31);
        !           136:      */
        !           137: 
        !           138:     best_priority = max(curr_bsr_priority, my_bsr_priority);
        !           139:     if (best_priority == my_bsr_priority) {
        !           140:        addr_delay = ntohl(curr_bsr_address) - ntohl(my_bsr_address);
        !           141:        /* Calculate the integer part of log_2 of (bestAddr - myAddr) */
        !           142:        /* To do so, have to find the position number of the first bit
        !           143:         * from left which is `1`
        !           144:         */
        !           145:        log_mask = sizeof(addr_delay) << 3;
        !           146:        log_mask = (1 << (log_mask - 1));  /* Set the leftmost bit to `1` */
        !           147:        for (log_of_2 = (sizeof(addr_delay) << 3) - 1 ; log_of_2; log_of_2--) {
        !           148:            if (addr_delay & log_mask)
        !           149:                break;
        !           150: 
        !           151:            log_mask >>= 1;  /* Start shifting `1` on right */
        !           152:        }
        !           153:        addr_delay = log_of_2 / 16;
        !           154:     } else {
        !           155:        addr_delay = 2 - (ntohl(my_bsr_address) / ( 1 << 31));
        !           156:     }
        !           157: 
        !           158:     delay = 1 + best_priority - my_bsr_priority;
        !           159:     /* Calculate log_2(delay) */
        !           160:     log_mask = sizeof(delay) << 3;
        !           161:     log_mask = (1 << (log_mask - 1));  /* Set the leftmost bit to `1` */
        !           162:     for (log_of_2 = (sizeof(delay) << 3) - 1 ; log_of_2; log_of_2--) {
        !           163:        if (delay & log_mask)
        !           164:            break;
        !           165: 
        !           166:        log_mask >>= 1;  /* Start shifting `1` on right */
        !           167:     }
        !           168: 
        !           169:     delay = 5 + 2 * log_of_2 + addr_delay;
        !           170: 
        !           171:     return (uint16_t)delay;
        !           172: }
        !           173: 
        !           174: 
        !           175: static cand_rp_t *add_cand_rp(cand_rp_t **used_cand_rp_list, uint32_t address)
        !           176: {
        !           177:     cand_rp_t *prev = NULL;
        !           178:     cand_rp_t *next;
        !           179:     cand_rp_t *ptr;
        !           180:     rpentry_t *entry;
        !           181:     uint32_t addr_h = ntohl(address);
        !           182: 
        !           183:     /* The ordering is the bigger first */
        !           184:     for (next = *used_cand_rp_list; next; prev = next, next = next->next) {
        !           185:        if (ntohl(next->rpentry->address) > addr_h)
        !           186:            continue;
        !           187: 
        !           188:        if (next->rpentry->address == address)
        !           189:            return next;
        !           190:        else
        !           191:            break;
        !           192:     }
        !           193: 
        !           194:     /* Create and insert the new entry between prev and next */
        !           195:     ptr = (cand_rp_t *)calloc(1, sizeof(cand_rp_t));
        !           196:     if (!ptr)
        !           197:        logit(LOG_ERR, 0, "Ran out of memory in add_cand_rp()");
        !           198:     ptr->rp_grp_next = NULL;
        !           199:     ptr->next = next;
        !           200:     ptr->prev = prev;
        !           201:     if (next)
        !           202:        next->prev = ptr;
        !           203:     if (prev == NULL)
        !           204:        *used_cand_rp_list = ptr;
        !           205:     else
        !           206:        prev->next = ptr;
        !           207: 
        !           208:     entry = (rpentry_t *)calloc(1, sizeof(rpentry_t));
        !           209:     if (!entry)
        !           210:        logit(LOG_ERR, 0, "Ran out of memory in add_cand_rp()");
        !           211:     ptr->rpentry = entry;
        !           212:     entry->next = NULL;
        !           213:     entry->prev  = NULL;
        !           214:     entry->address = address;
        !           215:     entry->mrtlink = NULL;
        !           216:     entry->incoming = NO_VIF;
        !           217:     entry->upstream = NULL;
        !           218:     /* TODO: setup the metric and the preference as ~0 (the lowest)? */
        !           219:     entry->metric = ~0;
        !           220:     entry->preference = ~0;
        !           221:     RESET_TIMER(entry->timer);
        !           222:     entry->cand_rp = ptr;
        !           223: 
        !           224:     /* TODO: XXX: check whether there is a route to that RP: if return value
        !           225:      * is FALSE, then no route.
        !           226:      */
        !           227:     if (local_address(entry->address) == NO_VIF)
        !           228:        /* TODO: check for error and delete */
        !           229:        set_incoming(entry, PIM_IIF_RP);
        !           230:     else
        !           231:        /* TODO: XXX: CHECK!!! */
        !           232:        entry->incoming = reg_vif_num;
        !           233: 
        !           234:     return ptr;
        !           235: }
        !           236: 
        !           237: 
        !           238: static grp_mask_t *add_grp_mask(grp_mask_t **used_grp_mask_list, uint32_t group_addr, uint32_t group_mask, uint32_t hash_mask)
        !           239: {
        !           240:     grp_mask_t *prev = NULL;
        !           241:     grp_mask_t *next;
        !           242:     grp_mask_t *ptr;
        !           243:     uint32_t prefix_h = ntohl(group_addr & group_mask);
        !           244: 
        !           245:     /* The ordering of group_addr is: bigger first */
        !           246:     for (next = *used_grp_mask_list; next; prev = next, next = next->next) {
        !           247:        if (ntohl(next->group_addr & next->group_mask) > prefix_h)
        !           248:            continue;
        !           249: 
        !           250:        /* The ordering of group_mask is: bigger (longer) first */
        !           251:        if ((next->group_addr & next->group_mask) == (group_addr & group_mask)) {
        !           252:            if (ntohl(next->group_mask) > ntohl(group_mask))
        !           253:                continue;
        !           254:            else if (next->group_mask == group_mask)
        !           255:                return next;
        !           256:            else
        !           257:                break;
        !           258:        }
        !           259:     }
        !           260: 
        !           261:     ptr = (grp_mask_t *)calloc(1, sizeof(grp_mask_t));
        !           262:     if (!ptr)
        !           263:        logit(LOG_ERR, 0, "Ran out of memory in add_grp_mask()");
        !           264: 
        !           265:     ptr->grp_rp_next = (rp_grp_entry_t *)NULL;
        !           266:     ptr->next = next;
        !           267:     ptr->prev = prev;
        !           268:     if (next)
        !           269:        next->prev = ptr;
        !           270:     if (prev == NULL)
        !           271:        *used_grp_mask_list = ptr;
        !           272:     else
        !           273:        prev->next = ptr;
        !           274: 
        !           275:     ptr->group_addr = group_addr;
        !           276:     ptr->group_mask = group_mask;
        !           277:     ptr->hash_mask  = hash_mask;
        !           278:     ptr->group_rp_number = 0;
        !           279:     ptr->fragment_tag = 0;
        !           280: 
        !           281:     return ptr;
        !           282: }
        !           283: 
        !           284: 
        !           285: /* TODO: XXX: BUG: a remapping for some groups currently using some other
        !           286:  * grp_mask may be required by the addition of the new entry!!!
        !           287:  * Remapping all groups might be a costly process...
        !           288:  */
        !           289: rp_grp_entry_t *add_rp_grp_entry(cand_rp_t  **used_cand_rp_list,
        !           290:                                 grp_mask_t **used_grp_mask_list,
        !           291:                                 uint32_t rp_addr,
        !           292:                                 uint8_t  rp_priority,
        !           293:                                 uint16_t rp_holdtime,
        !           294:                                 uint32_t group_addr,
        !           295:                                 uint32_t group_mask,
        !           296:                                 uint32_t bsr_hash_mask,
        !           297:                                 uint16_t fragment_tag)
        !           298: {
        !           299:     cand_rp_t *cand_rp_ptr;
        !           300:     grp_mask_t *mask_ptr;
        !           301:     rpentry_t *rpentry_ptr;
        !           302:     rp_grp_entry_t *entry_next;
        !           303:     rp_grp_entry_t *entry_new;
        !           304:     rp_grp_entry_t *entry_prev = NULL;
        !           305:     grpentry_t *grpentry_ptr_prev;
        !           306:     grpentry_t *grpentry_ptr_next;
        !           307:     uint32_t rp_addr_h;
        !           308:     uint8_t old_highest_priority = ~0;  /* Smaller value means "higher" */
        !           309: 
        !           310:     /* Input data verification */
        !           311:     if (!inet_valid_host(rp_addr))
        !           312:        return NULL;
        !           313:     if (!IN_CLASSD(ntohl(group_addr)))
        !           314:        return NULL;
        !           315: 
        !           316:     mask_ptr = add_grp_mask(used_grp_mask_list, group_addr, group_mask, bsr_hash_mask);
        !           317:     if (mask_ptr == NULL)
        !           318:        return NULL;
        !           319: 
        !           320: /* TODO: delete */
        !           321: #if 0
        !           322:     if (mask_ptr->grp_rp_next) {
        !           323:        /* Check for obsolete grp_rp chain */
        !           324:        if ((my_bsr_address != curr_bsr_address) && (mask_ptr->grp_rp_next->fragment_tag != fragment_tag)) {
        !           325:            /* This grp_rp chain is obsolete. Delete it. */
        !           326:            delete_grp_mask(used_cand_rp_list, used_grp_mask_list, group_addr, group_mask);
        !           327:            mask_ptr = add_grp_mask(used_grp_mask_list, group_addr, group_mask, bsr_hash_mask);
        !           328: 
        !           329:            if (mask_ptr == NULL)
        !           330:                return NULL;
        !           331:        }
        !           332:     }
        !           333: #endif /* 0 */
        !           334: 
        !           335:     cand_rp_ptr = add_cand_rp(used_cand_rp_list, rp_addr);
        !           336:     if (cand_rp_ptr == NULL) {
        !           337:        if (mask_ptr->grp_rp_next == NULL)
        !           338:            delete_grp_mask(used_cand_rp_list, used_grp_mask_list,
        !           339:                            group_addr, group_mask);
        !           340:        return NULL;
        !           341:     }
        !           342: 
        !           343:     rpentry_ptr = cand_rp_ptr->rpentry;
        !           344:     SET_TIMER(rpentry_ptr->timer, rp_holdtime);
        !           345:     rp_addr_h = ntohl(rp_addr);
        !           346:     mask_ptr->fragment_tag = fragment_tag;   /* For garbage collection */
        !           347: 
        !           348:     entry_prev = NULL;
        !           349:     entry_next = mask_ptr->grp_rp_next;
        !           350:     /* TODO: improve it */
        !           351:     if (entry_next != NULL)
        !           352:        old_highest_priority = entry_next->priority;
        !           353:     for ( ; entry_next; entry_prev = entry_next,
        !           354:              entry_next = entry_next->grp_rp_next) {
        !           355:        /* Smaller value means higher priority. The entries are
        !           356:         * sorted with the highest priority first.
        !           357:         */
        !           358:        if (entry_next->priority < rp_priority)
        !           359:            continue;
        !           360:        if (entry_next->priority > rp_priority)
        !           361:            break;
        !           362: 
        !           363:        /*
        !           364:         * Here we don't care about higher/lower addresses, because
        !           365:         * higher address does not guarantee higher hash_value,
        !           366:         * but anyway we do order with the higher address first,
        !           367:         * so it will be easier to find an existing entry and update the
        !           368:         * holdtime.
        !           369:         */
        !           370:        if (ntohl(entry_next->rp->rpentry->address) > rp_addr_h)
        !           371:            continue;
        !           372:        if (ntohl(entry_next->rp->rpentry->address) < rp_addr_h)
        !           373:            break;
        !           374:        /* We already have this entry. Update the holdtime */
        !           375:        /* TODO: We shoudn't have old existing entry, because with the
        !           376:         * current implementation all of them will be deleted
        !           377:         * (different fragment_tag). Debug and check and eventually
        !           378:         * delete.
        !           379:         */
        !           380:        entry_next->holdtime = rp_holdtime;
        !           381:        entry_next->fragment_tag = fragment_tag;
        !           382: 
        !           383:        return entry_next;
        !           384:     }
        !           385: 
        !           386:     /* Create and link the new entry */
        !           387:     entry_new = (rp_grp_entry_t *)calloc(1, sizeof(rp_grp_entry_t));
        !           388:     if (!entry_new)
        !           389:        logit(LOG_ERR, 0, "Ran out of memory in add_rp_grp_entry()");
        !           390:     entry_new->grp_rp_next = entry_next;
        !           391:     entry_new->grp_rp_prev = entry_prev;
        !           392:     if (entry_next)
        !           393:        entry_next->grp_rp_prev = entry_new;
        !           394:     if (entry_prev == NULL)
        !           395:        mask_ptr->grp_rp_next = entry_new;
        !           396:     else
        !           397:        entry_prev->grp_rp_next = entry_new;
        !           398: 
        !           399:     /*
        !           400:      * The rp_grp_entry chain is not ordered, so just plug
        !           401:      * the new entry at the head.
        !           402:      */
        !           403:     entry_new->rp_grp_next = cand_rp_ptr->rp_grp_next;
        !           404:     if (cand_rp_ptr->rp_grp_next)
        !           405:        cand_rp_ptr->rp_grp_next->rp_grp_prev = entry_new;
        !           406:     entry_new->rp_grp_prev = NULL;
        !           407:     cand_rp_ptr->rp_grp_next = entry_new;
        !           408: 
        !           409:     entry_new->holdtime = rp_holdtime;
        !           410:     entry_new->fragment_tag = fragment_tag;
        !           411:     entry_new->priority = rp_priority;
        !           412:     entry_new->group = mask_ptr;
        !           413:     entry_new->rp = cand_rp_ptr;
        !           414:     entry_new->grplink = NULL;
        !           415: 
        !           416:     /* If I am BSR candidate and rp_addr is NOT hacked SSM address, then log it */
        !           417:     if( cand_bsr_flag && rp_addr != 0x0100fea9 ) {
        !           418:        uint32_t mask;
        !           419:        MASK_TO_MASKLEN(group_mask, mask);
        !           420:        logit(LOG_INFO, 0, "New RP candidate %s for group %s/%d, priority %d",
        !           421:              inet_fmt(rp_addr, s1, sizeof(s1)), inet_fmt(group_addr, s2, sizeof(s2)), mask, rp_priority);
        !           422:     }
        !           423: 
        !           424:     mask_ptr->group_rp_number++;
        !           425: 
        !           426:     if (mask_ptr->grp_rp_next->priority == rp_priority) {
        !           427:        /* The first entries are with the best priority. */
        !           428:        /* Adding this rp_grp_entry may result in group_to_rp remapping */
        !           429:        for (entry_next = mask_ptr->grp_rp_next; entry_next; entry_next = entry_next->grp_rp_next) {
        !           430:            if (entry_next->priority > old_highest_priority)
        !           431:                break;
        !           432: 
        !           433:            for (grpentry_ptr_prev = entry_next->grplink; grpentry_ptr_prev; ) {
        !           434:                grpentry_ptr_next = grpentry_ptr_prev->rpnext;
        !           435:                remap_grpentry(grpentry_ptr_prev);
        !           436:                grpentry_ptr_prev = grpentry_ptr_next;
        !           437:            }
        !           438:        }
        !           439:     }
        !           440: 
        !           441:     return entry_new;
        !           442: }
        !           443: 
        !           444: 
        !           445: void delete_rp_grp_entry(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, rp_grp_entry_t *entry)
        !           446: {
        !           447:     grpentry_t *ptr;
        !           448:     grpentry_t *ptr_next;
        !           449: 
        !           450:     if (entry == NULL)
        !           451:        return;
        !           452:     entry->group->group_rp_number--;
        !           453: 
        !           454:     /* Free the rp_grp* and grp_rp* links */
        !           455:     if (entry->rp_grp_prev)
        !           456:        entry->rp_grp_prev->rp_grp_next = entry->rp_grp_next;
        !           457:     else
        !           458:        entry->rp->rp_grp_next = entry->rp_grp_next;
        !           459:     if (entry->rp_grp_next)
        !           460:        entry->rp_grp_next->rp_grp_prev = entry->rp_grp_prev;
        !           461: 
        !           462:     if (entry->grp_rp_prev)
        !           463:        entry->grp_rp_prev->grp_rp_next = entry->grp_rp_next;
        !           464:     else
        !           465:        entry->group->grp_rp_next = entry->grp_rp_next;
        !           466: 
        !           467:     if (entry->grp_rp_next)
        !           468:        entry->grp_rp_next->grp_rp_prev = entry->grp_rp_prev;
        !           469: 
        !           470:     /* Delete Cand-RP or Group-prefix if useless */
        !           471:     if (entry->group->grp_rp_next == NULL)
        !           472:        delete_grp_mask_entry(used_cand_rp_list, used_grp_mask_list, entry->group);
        !           473: 
        !           474:     if (entry->rp->rp_grp_next == NULL)
        !           475:        delete_rp_entry(used_cand_rp_list, used_grp_mask_list, entry->rp);
        !           476: 
        !           477:     /* Remap all affected groups */
        !           478:     for (ptr = entry->grplink; ptr; ptr = ptr_next) {
        !           479:        ptr_next = ptr->rpnext;
        !           480:        remap_grpentry(ptr);
        !           481:     }
        !           482: 
        !           483:     free((char *)entry);
        !           484: }
        !           485: 
        !           486: /* TODO: XXX: the affected group entries will be partially
        !           487:  * setup, because may have group routing entry, but NULL pointers to RP.
        !           488:  * After the call to this function, must remap all group entries ASAP.
        !           489:  */
        !           490: void delete_rp_list(cand_rp_t  **used_cand_rp_list, grp_mask_t **used_grp_mask_list)
        !           491: {
        !           492:     cand_rp_t      *cand_ptr,  *cand_next;
        !           493:     rp_grp_entry_t *entry_ptr, *entry_next;
        !           494:     grp_mask_t     *mask_ptr, *mask_next;
        !           495:     grpentry_t     *gentry_ptr, *gentry_ptr_next;
        !           496: 
        !           497:     for (cand_ptr = *used_cand_rp_list; cand_ptr; ) {
        !           498:        cand_next = cand_ptr->next;
        !           499: 
        !           500:        /* Free the mrtentry (if any) for this RP */
        !           501:        if (cand_ptr->rpentry->mrtlink) {
        !           502:            if (cand_ptr->rpentry->mrtlink->flags & MRTF_KERNEL_CACHE)
        !           503:                delete_mrtentry_all_kernel_cache(cand_ptr->rpentry->mrtlink);
        !           504:            FREE_MRTENTRY(cand_ptr->rpentry->mrtlink);
        !           505:        }
        !           506:        free(cand_ptr->rpentry);
        !           507: 
        !           508:        /* Free the whole chain of entry for this RP */
        !           509:        for (entry_ptr = cand_ptr->rp_grp_next; entry_ptr; entry_ptr = entry_next) {
        !           510:            entry_next = entry_ptr->rp_grp_next;
        !           511: 
        !           512:            /* Clear the RP related invalid pointers for all group entries */
        !           513:            for (gentry_ptr = entry_ptr->grplink; gentry_ptr; gentry_ptr = gentry_ptr_next) {
        !           514:                gentry_ptr_next = gentry_ptr->rpnext;
        !           515:                gentry_ptr->rpnext = NULL;
        !           516:                gentry_ptr->rpprev = NULL;
        !           517:                gentry_ptr->active_rp_grp = NULL;
        !           518:                gentry_ptr->rpaddr = INADDR_ANY_N;
        !           519:            }
        !           520: 
        !           521:            free(entry_ptr);
        !           522:        }
        !           523: 
        !           524:        free(cand_ptr);
        !           525:        cand_ptr = cand_next;
        !           526:     }
        !           527:     *used_cand_rp_list = NULL;
        !           528: 
        !           529:     for (mask_ptr = *used_grp_mask_list; mask_ptr; mask_ptr = mask_next) {
        !           530:        mask_next = mask_ptr->next;
        !           531:        free(mask_ptr);
        !           532:     }
        !           533:     *used_grp_mask_list = NULL;
        !           534: }
        !           535: 
        !           536: 
        !           537: void delete_grp_mask(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, uint32_t group_addr, uint32_t group_mask)
        !           538: {
        !           539:     grp_mask_t *ptr;
        !           540:     uint32_t prefix_h = ntohl(group_addr & group_mask);
        !           541: 
        !           542:     for (ptr = *used_grp_mask_list; ptr; ptr = ptr->next) {
        !           543:        if (ntohl(ptr->group_addr & ptr->group_mask) > prefix_h)
        !           544:            continue;
        !           545: 
        !           546:        if (ptr->group_addr == group_addr) {
        !           547:            if (ntohl(ptr->group_mask) > ntohl(group_mask))
        !           548:                continue;
        !           549:            else if (ptr->group_mask == group_mask)
        !           550:                break;
        !           551:            else
        !           552:                return;   /* Not found */
        !           553:        }
        !           554:     }
        !           555: 
        !           556:     if (ptr == (grp_mask_t *)NULL)
        !           557:        return;       /* Not found */
        !           558: 
        !           559:     delete_grp_mask_entry(used_cand_rp_list, used_grp_mask_list, ptr);
        !           560: }
        !           561: 
        !           562: static void delete_grp_mask_entry(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, grp_mask_t *grp_mask_delete)
        !           563: {
        !           564:     grpentry_t *grp_ptr, *grp_ptr_next;
        !           565:     rp_grp_entry_t *entry_ptr;
        !           566:     rp_grp_entry_t *entry_next;
        !           567: 
        !           568:     if (grp_mask_delete == NULL)
        !           569:        return;
        !           570: 
        !           571:     /* Remove from the grp_mask_list first */
        !           572:     if (grp_mask_delete->prev)
        !           573:        grp_mask_delete->prev->next = grp_mask_delete->next;
        !           574:     else
        !           575:        *used_grp_mask_list = grp_mask_delete->next;
        !           576: 
        !           577:     if (grp_mask_delete->next)
        !           578:        grp_mask_delete->next->prev = grp_mask_delete->prev;
        !           579: 
        !           580:     /* Remove all grp_rp entries for this grp_mask */
        !           581:     for (entry_ptr = grp_mask_delete->grp_rp_next; entry_ptr; entry_ptr = entry_next) {
        !           582:        entry_next = entry_ptr->grp_rp_next;
        !           583: 
        !           584:        /* Remap all related grpentry */
        !           585:        for (grp_ptr = entry_ptr->grplink; grp_ptr; grp_ptr = grp_ptr_next) {
        !           586:            grp_ptr_next = grp_ptr->rpnext;
        !           587:            remap_grpentry(grp_ptr);
        !           588:        }
        !           589: 
        !           590:        if (entry_ptr->rp_grp_prev != (rp_grp_entry_t *)NULL)
        !           591:            entry_ptr->rp_grp_prev->rp_grp_next = entry_ptr->rp_grp_next;
        !           592:        else
        !           593:            entry_ptr->rp->rp_grp_next = entry_ptr->rp_grp_next;
        !           594: 
        !           595:        if (entry_ptr->rp_grp_next != NULL)
        !           596:            entry_ptr->rp_grp_next->rp_grp_prev = entry_ptr->rp_grp_prev;
        !           597: 
        !           598:        /* Delete the RP entry */
        !           599:        if (entry_ptr->rp->rp_grp_next == NULL)
        !           600:            delete_rp_entry(used_cand_rp_list, used_grp_mask_list, entry_ptr->rp);
        !           601: 
        !           602:        free(entry_ptr);
        !           603:     }
        !           604: 
        !           605:     free(grp_mask_delete);
        !           606: }
        !           607: 
        !           608: /*
        !           609:  * TODO: currently not used.
        !           610:  */
        !           611: void delete_rp(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, uint32_t rp_addr)
        !           612: {
        !           613:     cand_rp_t *ptr;
        !           614:     uint32_t rp_addr_h = ntohl(rp_addr);
        !           615: 
        !           616:     for(ptr = *used_cand_rp_list; ptr != NULL; ptr = ptr->next) {
        !           617:        if (ntohl(ptr->rpentry->address) > rp_addr_h)
        !           618:            continue;
        !           619: 
        !           620:        if (ptr->rpentry->address == rp_addr)
        !           621:            break;
        !           622:        else
        !           623:            return;   /* Not found */
        !           624:     }
        !           625: 
        !           626:     if (ptr == NULL)
        !           627:        return;       /* Not found */
        !           628: 
        !           629:     delete_rp_entry(used_cand_rp_list, used_grp_mask_list, ptr);
        !           630: }
        !           631: 
        !           632: 
        !           633: static void delete_rp_entry(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, cand_rp_t *cand_rp_delete)
        !           634: {
        !           635:     rp_grp_entry_t *entry_ptr;
        !           636:     rp_grp_entry_t *entry_next;
        !           637:     grpentry_t *grp_ptr;
        !           638:     grpentry_t *grp_ptr_next;
        !           639: 
        !           640:     if (cand_rp_delete == NULL)
        !           641:        return;
        !           642: 
        !           643:     /* Remove from the cand-RP chain */
        !           644:     if (cand_rp_delete->prev)
        !           645:        cand_rp_delete->prev->next = cand_rp_delete->next;
        !           646:     else
        !           647:        *used_cand_rp_list = cand_rp_delete->next;
        !           648: 
        !           649:     if (cand_rp_delete->next)
        !           650:        cand_rp_delete->next->prev = cand_rp_delete->prev;
        !           651: 
        !           652:     if (cand_rp_delete->rpentry->mrtlink) {
        !           653:        if (cand_rp_delete->rpentry->mrtlink->flags & MRTF_KERNEL_CACHE)
        !           654:            delete_mrtentry_all_kernel_cache(cand_rp_delete->rpentry->mrtlink);
        !           655: 
        !           656:        FREE_MRTENTRY(cand_rp_delete->rpentry->mrtlink);
        !           657:     }
        !           658:     free ((char *)cand_rp_delete->rpentry);
        !           659: 
        !           660:     /* Remove all rp_grp entries for this RP */
        !           661:     for (entry_ptr = cand_rp_delete->rp_grp_next; entry_ptr; entry_ptr = entry_next) {
        !           662:        entry_next = entry_ptr->rp_grp_next;
        !           663:        entry_ptr->group->group_rp_number--;
        !           664: 
        !           665:        /* First take care of the grp_rp chain */
        !           666:        if (entry_ptr->grp_rp_prev)
        !           667:            entry_ptr->grp_rp_prev->grp_rp_next = entry_ptr->grp_rp_next;
        !           668:        else
        !           669:            entry_ptr->group->grp_rp_next = entry_ptr->grp_rp_next;
        !           670: 
        !           671:        if (entry_ptr->grp_rp_next)
        !           672:            entry_ptr->grp_rp_next->grp_rp_prev = entry_ptr->grp_rp_prev;
        !           673: 
        !           674:        if (entry_ptr->grp_rp_next == NULL)
        !           675:            delete_grp_mask_entry(used_cand_rp_list, used_grp_mask_list, entry_ptr->group);
        !           676: 
        !           677:        /* Remap the related groups */
        !           678:        for (grp_ptr = entry_ptr->grplink; grp_ptr; grp_ptr = grp_ptr_next) {
        !           679:            grp_ptr_next = grp_ptr->rpnext;
        !           680:            remap_grpentry(grp_ptr);
        !           681:        }
        !           682: 
        !           683:        free(entry_ptr);
        !           684:     }
        !           685: 
        !           686:     free((char *)cand_rp_delete);
        !           687: }
        !           688: 
        !           689: 
        !           690: /*
        !           691:  * Rehash the RP for the group.
        !           692:  * XXX: currently, every time when remap_grpentry() is called, there has
        !           693:  * being a good reason to change the RP, so for performancy reasons
        !           694:  * no check is performed whether the RP will be really different one.
        !           695:  */
        !           696: int remap_grpentry(grpentry_t *grpentry_ptr)
        !           697: {
        !           698:     rpentry_t *rpentry_ptr;
        !           699:     rp_grp_entry_t *entry_ptr;
        !           700:     mrtentry_t *grp_route;
        !           701:     mrtentry_t *mrtentry_ptr;
        !           702: 
        !           703:     if (grpentry_ptr == NULL)
        !           704:        return FALSE;
        !           705: 
        !           706:     /* Remove from the list of all groups matching to the same RP */
        !           707:     if (grpentry_ptr->rpprev) {
        !           708:        grpentry_ptr->rpprev->rpnext = grpentry_ptr->rpnext;
        !           709:     } else {
        !           710:        if (grpentry_ptr->active_rp_grp)
        !           711:            grpentry_ptr->active_rp_grp->grplink = grpentry_ptr->rpnext;
        !           712:     }
        !           713: 
        !           714:     if (grpentry_ptr->rpnext)
        !           715:        grpentry_ptr->rpnext->rpprev = grpentry_ptr->rpprev;
        !           716: 
        !           717:     entry_ptr = rp_grp_match(grpentry_ptr->group);
        !           718:     if (entry_ptr == NULL) {
        !           719:        /* If cannot remap, delete the group */
        !           720:        delete_grpentry(grpentry_ptr);
        !           721:        return FALSE;
        !           722:     }
        !           723:     rpentry_ptr = entry_ptr->rp->rpentry;
        !           724: 
        !           725:     /* Add to the new chain of all groups mapping to the same RP */
        !           726:     grpentry_ptr->rpaddr  = rpentry_ptr->address;
        !           727:     grpentry_ptr->active_rp_grp = entry_ptr;
        !           728:     grpentry_ptr->rpnext = entry_ptr->grplink;
        !           729:     if (grpentry_ptr->rpnext)
        !           730:        grpentry_ptr->rpnext->rpprev = grpentry_ptr;
        !           731:     grpentry_ptr->rpprev = NULL;
        !           732:     entry_ptr->grplink = grpentry_ptr;
        !           733: 
        !           734:     grp_route = grpentry_ptr->grp_route;
        !           735:     if (grp_route) {
        !           736:        grp_route->upstream   = rpentry_ptr->upstream;
        !           737:        grp_route->metric     = rpentry_ptr->metric;
        !           738:        grp_route->preference = rpentry_ptr->preference;
        !           739:        change_interfaces(grp_route, rpentry_ptr->incoming,
        !           740:                          grp_route->joined_oifs,
        !           741:                          grp_route->pruned_oifs,
        !           742:                          grp_route->leaves,
        !           743:                          grp_route->asserted_oifs, MFC_UPDATE_FORCE);
        !           744:     }
        !           745: 
        !           746:     for (mrtentry_ptr = grpentry_ptr->mrtlink; mrtentry_ptr; mrtentry_ptr = mrtentry_ptr->grpnext) {
        !           747:        if (!(mrtentry_ptr->flags & MRTF_RP))
        !           748:            continue;
        !           749: 
        !           750:        mrtentry_ptr->upstream = rpentry_ptr->upstream;
        !           751:        mrtentry_ptr->metric   = rpentry_ptr->metric;
        !           752:        mrtentry_ptr->preference = rpentry_ptr->preference;
        !           753:        change_interfaces(mrtentry_ptr, rpentry_ptr->incoming,
        !           754:                          mrtentry_ptr->joined_oifs,
        !           755:                          mrtentry_ptr->pruned_oifs,
        !           756:                          mrtentry_ptr->leaves,
        !           757:                          mrtentry_ptr->asserted_oifs, MFC_UPDATE_FORCE);
        !           758:     }
        !           759: 
        !           760:     return TRUE;
        !           761: }
        !           762: 
        !           763: 
        !           764: rpentry_t *rp_match(uint32_t group)
        !           765: {
        !           766:     rp_grp_entry_t *ptr;
        !           767: 
        !           768:     ptr = rp_grp_match(group);
        !           769:     if (ptr)
        !           770:        return ptr->rp->rpentry;
        !           771: 
        !           772:     return NULL;
        !           773: }
        !           774: 
        !           775: rp_grp_entry_t *rp_grp_match(uint32_t group)
        !           776: {
        !           777:     grp_mask_t *mask_ptr;
        !           778:     rp_grp_entry_t *entry_ptr;
        !           779:     rp_grp_entry_t *best_entry = NULL;
        !           780:     uint8_t best_priority       = ~0; /* Smaller is better */
        !           781:     uint32_t best_hash_value    = 0;  /* Bigger is better */
        !           782:     uint32_t best_address_h     = 0;  /* Bigger is better */
        !           783:     uint32_t curr_hash_value    = 0;
        !           784:     uint32_t curr_address_h     = 0;
        !           785:     uint32_t group_h            = ntohl(group);
        !           786: 
        !           787:     if (grp_mask_list == NULL)
        !           788:        return NULL;
        !           789: 
        !           790:     for (mask_ptr = grp_mask_list; mask_ptr; mask_ptr = mask_ptr->next) {
        !           791:        /* Search the grp_mask (group-prefix) list */
        !           792:        if ((group_h & ntohl(mask_ptr->group_mask))
        !           793:            != ntohl(mask_ptr->group_mask & mask_ptr->group_addr))
        !           794:            continue;
        !           795: 
        !           796:        for (entry_ptr = mask_ptr->grp_rp_next; entry_ptr; entry_ptr = entry_ptr->grp_rp_next) {
        !           797:            if (best_priority < entry_ptr->priority)
        !           798:                break;
        !           799: 
        !           800:            curr_hash_value = RP_HASH_VALUE(group_h, mask_ptr->hash_mask, curr_address_h);
        !           801:            curr_address_h = ntohl(entry_ptr->rp->rpentry->address);
        !           802: 
        !           803:            if (best_priority == entry_ptr->priority) {
        !           804:                /* Compare the hash_value and then the addresses */
        !           805:                if (curr_hash_value < best_hash_value)
        !           806:                    continue;
        !           807: 
        !           808:                if (curr_hash_value == best_hash_value) {
        !           809:                    if (curr_address_h < best_address_h)
        !           810:                        continue;
        !           811:                }
        !           812:            }
        !           813: 
        !           814:            /* The current entry in the loop is preferred */
        !           815:            best_entry = entry_ptr;
        !           816:            best_priority = best_entry->priority;
        !           817:            best_address_h = curr_address_h;
        !           818:            best_hash_value = curr_hash_value;
        !           819:        }
        !           820:     }
        !           821: 
        !           822:     return best_entry;
        !           823: }
        !           824: 
        !           825: 
        !           826: rpentry_t *rp_find(uint32_t rp_address)
        !           827: {
        !           828:     cand_rp_t *cand_rp_ptr;
        !           829:     uint32_t address_h = ntohl(rp_address);
        !           830: 
        !           831:     for(cand_rp_ptr = cand_rp_list; cand_rp_ptr != NULL; cand_rp_ptr = cand_rp_ptr->next) {
        !           832:        if (ntohl(cand_rp_ptr->rpentry->address) > address_h)
        !           833:            continue;
        !           834: 
        !           835:        if (cand_rp_ptr->rpentry->address == rp_address)
        !           836:            return cand_rp_ptr->rpentry;
        !           837: 
        !           838:        return NULL;
        !           839:     }
        !           840: 
        !           841:     return NULL;
        !           842: }
        !           843: 
        !           844: 
        !           845: /*
        !           846:  * Create a bootstrap message in "send_buff" and returns the data size
        !           847:  * (excluding the IP header and the PIM header) Can be used both by the
        !           848:  * Bootstrap router to multicast the RP-set or by the DR to unicast it to
        !           849:  * a new neighbor. It DOES NOT change any timers.
        !           850:  */
        !           851: int create_pim_bootstrap_message(char *send_buff)
        !           852: {
        !           853:     uint8_t *data_ptr;
        !           854:     grp_mask_t *mask_ptr;
        !           855:     rp_grp_entry_t *entry_ptr;
        !           856:     int datalen;
        !           857:     uint8_t masklen;
        !           858: 
        !           859:     if (curr_bsr_address == INADDR_ANY_N)
        !           860:        return 0;
        !           861: 
        !           862:     data_ptr = (uint8_t *)(send_buff + sizeof(struct ip) + sizeof(pim_header_t));
        !           863:     if (curr_bsr_address == my_bsr_address)
        !           864:        curr_bsr_fragment_tag++;
        !           865: 
        !           866:     PUT_HOSTSHORT(curr_bsr_fragment_tag, data_ptr);
        !           867:     MASK_TO_MASKLEN(curr_bsr_hash_mask, masklen);
        !           868:     PUT_BYTE(masklen, data_ptr);
        !           869:     PUT_BYTE(curr_bsr_priority, data_ptr);
        !           870:     PUT_EUADDR(curr_bsr_address, data_ptr);
        !           871: 
        !           872:     /* TODO: XXX: No fragmentation support (yet) */
        !           873:     for (mask_ptr = grp_mask_list; mask_ptr; mask_ptr = mask_ptr->next) {
        !           874:        if (IN_PIM_SSM_RANGE(mask_ptr->group_addr)) {
        !           875:            continue;  /* Do not advertise internal virtual RP for SSM groups */
        !           876:        }
        !           877:        MASK_TO_MASKLEN(mask_ptr->group_mask, masklen);
        !           878:        PUT_EGADDR(mask_ptr->group_addr, masklen, 0, data_ptr);
        !           879:        PUT_BYTE(mask_ptr->group_rp_number, data_ptr);
        !           880:        PUT_BYTE(mask_ptr->group_rp_number, data_ptr); /* TODO: if frag.*/
        !           881:        PUT_HOSTSHORT(0, data_ptr);
        !           882: 
        !           883:        for (entry_ptr = mask_ptr->grp_rp_next; entry_ptr; entry_ptr = entry_ptr->grp_rp_next) {
        !           884:            PUT_EUADDR(entry_ptr->rp->rpentry->address, data_ptr);
        !           885:            PUT_HOSTSHORT(entry_ptr->holdtime, data_ptr);
        !           886:            PUT_BYTE(entry_ptr->priority, data_ptr);
        !           887:            PUT_BYTE(0, data_ptr);  /* The reserved field */
        !           888:        }
        !           889:     }
        !           890: 
        !           891:     datalen = (data_ptr - (uint8_t *)send_buff) - sizeof(struct ip) - sizeof(pim_header_t);
        !           892: 
        !           893:     return datalen;
        !           894: }
        !           895: 
        !           896: 
        !           897: /*
        !           898:  * Check if the addr is the RP for the group corresponding to mrt.
        !           899:  * Return TRUE or FALSE.
        !           900:  */
        !           901: int check_mrtentry_rp(mrtentry_t *mrt, uint32_t addr)
        !           902: {
        !           903:     rp_grp_entry_t *ptr;
        !           904: 
        !           905:     if (!mrt)
        !           906:        return FALSE;
        !           907: 
        !           908:     if (addr == INADDR_ANY_N)
        !           909:        return FALSE;
        !           910: 
        !           911:     ptr = mrt->group->active_rp_grp;
        !           912:     if (!ptr)
        !           913:        return FALSE;
        !           914: 
        !           915:     if (mrt->group->rpaddr == addr)
        !           916:        return TRUE;
        !           917: 
        !           918:     return FALSE;
        !           919: }
        !           920: 
        !           921: /**
        !           922:  * Local Variables:
        !           923:  *  version-control: t
        !           924:  *  indent-tabs-mode: t
        !           925:  *  c-file-style: "ellemtel"
        !           926:  *  c-basic-offset: 4
        !           927:  * End:
        !           928:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>