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>