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