Annotation of embedaddon/pimd/rp.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: #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>