Annotation of embedaddon/pimdd/route.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *  Copyright (c) 1998 by the University of Oregon.
        !             3:  *  All rights reserved.
        !             4:  *
        !             5:  *  Permission to use, copy, modify, and distribute this software and
        !             6:  *  its documentation in source and binary forms for lawful
        !             7:  *  purposes and without fee is hereby granted, provided
        !             8:  *  that the above copyright notice appear in all copies and that both
        !             9:  *  the copyright notice and this permission notice appear in supporting
        !            10:  *  documentation, and that any documentation, advertising materials,
        !            11:  *  and other materials related to such distribution and use acknowledge
        !            12:  *  that the software was developed by the University of Oregon.
        !            13:  *  The name of the University of Oregon may not be used to endorse or 
        !            14:  *  promote products derived from this software without specific prior 
        !            15:  *  written permission.
        !            16:  *
        !            17:  *  THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
        !            18:  *  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
        !            19:  *  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
        !            20:  *  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            21:  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND 
        !            22:  *  NON-INFRINGEMENT.
        !            23:  *
        !            24:  *  IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
        !            25:  *  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
        !            26:  *  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
        !            27:  *  THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            28:  *
        !            29:  *  Other copyrights might apply to parts of this software and are so
        !            30:  *  noted when applicable.
        !            31:  */
        !            32: /*
        !            33:  *  Questions concerning this software should be directed to 
        !            34:  *  Kurt Windisch (kurtw@antc.uoregon.edu)
        !            35:  *
        !            36:  *  $Id: route.c,v 1.27 1998/12/30 20:26:21 kurtw Exp $
        !            37:  */
        !            38: /*
        !            39:  * Part of this program has been derived from PIM sparse-mode pimd.
        !            40:  * The pimd program is covered by the license in the accompanying file
        !            41:  * named "LICENSE.pimd".
        !            42:  *  
        !            43:  * The pimd program is COPYRIGHT 1998 by University of Southern California.
        !            44:  *
        !            45:  * Part of this program has been derived from mrouted.
        !            46:  * The mrouted program is covered by the license in the accompanying file
        !            47:  * named "LICENSE.mrouted".
        !            48:  * 
        !            49:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
        !            50:  * Leland Stanford Junior University.
        !            51:  *
        !            52:  */
        !            53: 
        !            54: #include "defs.h"
        !            55: 
        !            56: 
        !            57: static void   process_cache_miss  __P((struct igmpmsg *igmpctl));
        !            58: static void   process_wrong_iif   __P((struct igmpmsg *igmpctl));
        !            59: 
        !            60: u_int32         default_source_preference = DEFAULT_LOCAL_PREF;
        !            61: u_int32         default_source_metric     = DEFAULT_LOCAL_METRIC;
        !            62: 
        !            63: /* Return the iif for given address */
        !            64: vifi_t
        !            65: get_iif(address)
        !            66:     u_int32 address;
        !            67: {
        !            68:     struct rpfctl rpfc;
        !            69: 
        !            70:     k_req_incoming(address, &rpfc);
        !            71:     if (rpfc.rpfneighbor.s_addr == INADDR_ANY_N)
        !            72:        return (NO_VIF);
        !            73:     return (rpfc.iif);
        !            74: }
        !            75: 
        !            76: /* Return the PIM neighbor toward a source */
        !            77: /* If route not found or if a local source or if a directly connected source,
        !            78:  * but is not PIM router, or if the first hop router is not a PIM router,
        !            79:  * then return NULL.
        !            80:  */
        !            81: pim_nbr_entry_t *
        !            82: find_pim_nbr(source)
        !            83:     u_int32 source;
        !            84: {
        !            85:     struct rpfctl rpfc;
        !            86:     pim_nbr_entry_t *pim_nbr;
        !            87:     u_int32 next_hop_router_addr;
        !            88: 
        !            89:     if (local_address(source) != NO_VIF)
        !            90:        return (pim_nbr_entry_t *)NULL;
        !            91:     k_req_incoming(source, &rpfc);
        !            92:     if ((rpfc.rpfneighbor.s_addr == INADDR_ANY_N)
        !            93:        || (rpfc.iif == NO_VIF))
        !            94:        return (pim_nbr_entry_t *)NULL;
        !            95:     next_hop_router_addr = rpfc.rpfneighbor.s_addr;
        !            96:     for (pim_nbr = uvifs[rpfc.iif].uv_pim_neighbors;
        !            97:         pim_nbr != (pim_nbr_entry_t *)NULL;
        !            98:         pim_nbr = pim_nbr->next)
        !            99:        if (pim_nbr->address == next_hop_router_addr)
        !           100:            return(pim_nbr);
        !           101:     return (pim_nbr_entry_t *)NULL;
        !           102: }
        !           103: 
        !           104: 
        !           105: /* TODO: check again the exact setup if the source is local or directly
        !           106:  * connected!!!
        !           107:  */
        !           108: /* TODO: XXX: change the metric and preference for all (S,G) entries per
        !           109:  * source?
        !           110:  */
        !           111: /* PIMDM TODO - If possible, this would be the place to correct set the
        !           112:  * source's preference and metric to that obtained from the kernel
        !           113:  * and/or unicast routing protocol.  For now, set it to the configured
        !           114:  * default for local pref/metric.
        !           115:  */
        !           116: /*
        !           117:  * Set the iif, upstream router, preference and metric for the route
        !           118:  * toward the source. Return TRUE is the route was found, othewise FALSE.
        !           119:  * If srctype==PIM_IIF_SOURCE and if the source is directly connected
        !           120:  * then the "upstream" is set to NULL. 
        !           121:  * Note that srctype is a hold-over from the PIM-SM daemon and is unused.
        !           122:  */
        !           123: int
        !           124: set_incoming(srcentry_ptr, srctype)
        !           125:     srcentry_t *srcentry_ptr;
        !           126:     int srctype;
        !           127: {
        !           128:     struct rpfctl rpfc;
        !           129:     u_int32 source = srcentry_ptr->address;
        !           130:     u_int32 neighbor_addr;
        !           131:     register struct uvif *v;
        !           132:     register pim_nbr_entry_t *n;
        !           133: 
        !           134:     /* Preference will be 0 if directly connected */
        !           135:     srcentry_ptr->preference = 0; 
        !           136:     srcentry_ptr->metric = 0;
        !           137: 
        !           138:     if ((srcentry_ptr->incoming = local_address(source)) != NO_VIF) {
        !           139:        /* The source is a local address */
        !           140:        /* TODO: set the upstream to myself? */
        !           141:        srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL;
        !           142:        return (TRUE);
        !           143:     }
        !           144: 
        !           145:     if ((srcentry_ptr->incoming = find_vif_direct(source)) == NO_VIF) {
        !           146:     /* TODO: probably need to check the case if the iif is disabled */
        !           147:        /* Use the lastest resource: the kernel unicast routing table */
        !           148:        k_req_incoming(source, &rpfc);
        !           149:        if ((rpfc.iif == NO_VIF) ||
        !           150:            rpfc.rpfneighbor.s_addr == INADDR_ANY_N) {
        !           151:            /* couldn't find a route */
        !           152:            IF_DEBUG(DEBUG_PIM_MRT | DEBUG_RPF)
        !           153:                log(LOG_DEBUG, 0, "NO ROUTE found for %s",
        !           154:                    inet_fmt(source, s1));
        !           155:            return(FALSE);
        !           156:        }
        !           157:        srcentry_ptr->incoming = rpfc.iif;
        !           158:        neighbor_addr = rpfc.rpfneighbor.s_addr;
        !           159:     }
        !           160:     else {
        !           161:        /* The source is directly connected. 
        !           162:         */
        !           163:        srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL;
        !           164:        return (TRUE);
        !           165:     }
        !           166: 
        !           167:     /* set the preference for sources that aren't directly connected. */
        !           168:     v = &uvifs[srcentry_ptr->incoming];
        !           169:     srcentry_ptr->preference = v->uv_local_pref;
        !           170:     srcentry_ptr->metric = v->uv_local_metric;
        !           171: 
        !           172:     /*
        !           173:      * The upstream router must be a (PIM router) neighbor, otherwise we
        !           174:      * are in big trouble ;-)
        !           175:      */
        !           176:     for (n = v->uv_pim_neighbors; n != NULL; n = n->next) {
        !           177:        if (ntohl(neighbor_addr) < ntohl(n->address))
        !           178:            continue;
        !           179:        if (neighbor_addr == n->address) {
        !           180:            /*
        !           181:             *The upstream router is found in the list of neighbors.
        !           182:             * We are safe!
        !           183:             */
        !           184:            srcentry_ptr->upstream = n;
        !           185:            IF_DEBUG(DEBUG_RPF)
        !           186:                log(LOG_DEBUG, 0,
        !           187:                    "For src %s, iif is %d, next hop router is %s",
        !           188:                    inet_fmt(source, s1), srcentry_ptr->incoming,
        !           189:                    inet_fmt(neighbor_addr, s2));
        !           190:            return(TRUE);
        !           191:        }
        !           192:        else break;
        !           193:     }
        !           194:     
        !           195:     /* TODO: control the number of messages! */
        !           196:     log(LOG_INFO, 0,
        !           197:        "For src %s, iif is %d, next hop router is %s: NOT A PIM ROUTER",
        !           198:        inet_fmt(source, s1), srcentry_ptr->incoming,
        !           199:        inet_fmt(neighbor_addr, s2));
        !           200:     srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL; 
        !           201: 
        !           202:     return(FALSE);
        !           203: }
        !           204: 
        !           205: 
        !           206: /* Set the leaves in a new mrtentry */
        !           207: void set_leaves(mrtentry_ptr)
        !           208:      mrtentry_t *mrtentry_ptr;
        !           209: {
        !           210:     vifi_t vifi;
        !           211:     struct uvif *v;
        !           212:     
        !           213:     /* Check for a group report on each vif */
        !           214:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) 
        !           215:        if(check_grp_membership(v, mrtentry_ptr->group->group)) 
        !           216:            VIFM_SET(vifi, mrtentry_ptr->leaves);
        !           217: }
        !           218: 
        !           219: 
        !           220: /* Handle new receiver
        !           221:  *
        !           222:  * TODO: XXX: currently `source` is not used. Will be used with IGMPv3 where
        !           223:  * we have source-specific Join/Prune.
        !           224:  */
        !           225: void
        !           226: add_leaf(vifi, source, group)
        !           227:     vifi_t vifi;
        !           228:     u_int32 source;
        !           229:     u_int32 group;
        !           230: {
        !           231:     grpentry_t *grpentry_ptr;
        !           232:     mrtentry_t *mrtentry_srcs;
        !           233:     vifbitmap_t new_leaves;
        !           234:     int state_change;
        !           235: 
        !           236:     grpentry_ptr = find_group(group);
        !           237:     if (grpentry_ptr == (grpentry_t *)NULL)
        !           238:        return;
        !           239: 
        !           240:     /* walk the source list for the group and add vif to oiflist */
        !           241:     for (mrtentry_srcs = grpentry_ptr->mrtlink;
        !           242:         mrtentry_srcs != (mrtentry_t *)NULL;
        !           243:         mrtentry_srcs = mrtentry_srcs->grpnext) {
        !           244: 
        !           245:        /* if applicable, add the vif to the leaves */
        !           246:        if (mrtentry_srcs->incoming == vifi) 
        !           247:            continue;
        !           248: 
        !           249:        if(!(VIFM_ISSET(vifi, mrtentry_srcs->leaves))) {
        !           250: 
        !           251:            IF_DEBUG(DEBUG_MRT)
        !           252:                log(LOG_DEBUG, 0, "Adding leaf vif %d for src %s group %s", 
        !           253:                    vifi,
        !           254:                    inet_fmt(mrtentry_srcs->source->address, s1),
        !           255:                    inet_fmt(group, s2));
        !           256:            
        !           257:            VIFM_COPY(mrtentry_srcs->leaves, new_leaves);
        !           258:            VIFM_SET(vifi, new_leaves);    /* Add the leaf */
        !           259:            
        !           260:            state_change = 
        !           261:                change_interfaces(mrtentry_srcs,
        !           262:                                  mrtentry_srcs->incoming,
        !           263:                                  mrtentry_srcs->pruned_oifs,
        !           264:                                  new_leaves);
        !           265: 
        !           266:            /* Handle transition from negative cache */
        !           267:            if(state_change == 1) 
        !           268:                trigger_join_alert(mrtentry_srcs);
        !           269:        }
        !           270:     }
        !           271: }
        !           272: 
        !           273: 
        !           274: /*
        !           275:  * TODO: XXX: currently `source` is not used. To be used with IGMPv3 where
        !           276:  * we have source-specific joins/prunes.
        !           277:  */
        !           278: void
        !           279: delete_leaf(vifi, source, group)
        !           280:     vifi_t vifi;
        !           281:     u_int32 source;
        !           282:     u_int32 group;
        !           283: {
        !           284:     grpentry_t *grpentry_ptr;
        !           285:     mrtentry_t *mrtentry_srcs;
        !           286:     vifbitmap_t new_leaves;
        !           287:     int state_change;
        !           288: 
        !           289:     /* mrtentry_t *mrtentry_ptr;
        !           290:      * mrtentry_t *mrtentry_srcs;
        !           291:      * vifbitmap_t new_oifs;
        !           292:      * vifbitmap_t old_oifs;
        !           293:      * vifbitmap_t new_leaves;
        !           294:      */
        !           295: 
        !           296:     grpentry_ptr = find_group(group);
        !           297:     if (grpentry_ptr == (grpentry_t *)NULL)
        !           298:        return;
        !           299: 
        !           300:     /* walk the source list for the group and delete vif to leaves */
        !           301:     for (mrtentry_srcs = grpentry_ptr->mrtlink;
        !           302:         mrtentry_srcs != (mrtentry_t *)NULL;
        !           303:         mrtentry_srcs = mrtentry_srcs->grpnext) {
        !           304: 
        !           305:        /* if applicable, delete the vif from the leaves */
        !           306:        if (mrtentry_srcs->incoming == vifi) 
        !           307:            continue;
        !           308: 
        !           309:        if(VIFM_ISSET(vifi, mrtentry_srcs->leaves)) {
        !           310: 
        !           311:            IF_DEBUG(DEBUG_MRT)
        !           312:                log(LOG_DEBUG, 0, "Deleting leaf vif %d for src %s, group %s",
        !           313:                    vifi,
        !           314:                    inet_fmt(mrtentry_srcs->source->address, s1), 
        !           315:                    inet_fmt(group, s2));
        !           316:            
        !           317:            VIFM_COPY(mrtentry_srcs->leaves, new_leaves);
        !           318:            VIFM_CLR(vifi, new_leaves);    /* Remove the leaf */
        !           319:            
        !           320:            state_change = 
        !           321:                change_interfaces(mrtentry_srcs,
        !           322:                                  mrtentry_srcs->incoming,
        !           323:                                  mrtentry_srcs->pruned_oifs,
        !           324:                                  new_leaves);
        !           325: 
        !           326:            /* Handle transition to negative cache */
        !           327:            if(state_change == -1)
        !           328:                trigger_prune_alert(mrtentry_srcs);
        !           329:        }
        !           330:     }
        !           331: }
        !           332: 
        !           333: void
        !           334: calc_oifs(mrtentry_ptr, oifs_ptr)
        !           335:     mrtentry_t *mrtentry_ptr;
        !           336:     vifbitmap_t *oifs_ptr;
        !           337: {
        !           338:     vifbitmap_t oifs;
        !           339: 
        !           340:     /*
        !           341:      * oifs =
        !           342:      * ((nbr_ifs - my_prune) + my_leaves) - incoming_interface,
        !           343:      * i.e. `leaves` have higher priority than `prunes`. 
        !           344:      * Asserted oifs (those that lost assert) are handled as pruned oifs.
        !           345:      * The incoming interface is always deleted from the oifs
        !           346:      */
        !           347: 
        !           348:     if (mrtentry_ptr == (mrtentry_t *)NULL) {
        !           349:         VIFM_CLRALL(*oifs_ptr);
        !           350:         return;
        !           351:     }
        !           352:  
        !           353:     VIFM_COPY(nbr_vifs, oifs);
        !           354:     VIFM_CLR_MASK(oifs, mrtentry_ptr->pruned_oifs);
        !           355:     VIFM_MERGE(oifs, mrtentry_ptr->leaves, oifs);
        !           356:     VIFM_CLR(mrtentry_ptr->incoming, oifs);
        !           357:     VIFM_COPY(oifs, *oifs_ptr);
        !           358: }
        !           359: 
        !           360: 
        !           361: /*
        !           362:  * Set the iif, join/prune/leaves/asserted interfaces. Calculate and
        !           363:  * set the oifs.
        !           364:  * Return 1 if oifs change from NULL to not-NULL.
        !           365:  * Return -1 if oifs change from non-NULL to NULL
        !           366:  *  else return 0
        !           367:  * If the iif change or if the oifs change from NULL to non-NULL
        !           368:  * or vice-versa, then schedule that mrtentry join/prune timer to
        !           369:  * timeout immediately. 
        !           370:  */
        !           371: int
        !           372: change_interfaces(mrtentry_ptr, new_iif, new_pruned_oifs,
        !           373:                  new_leaves_)
        !           374:     mrtentry_t *mrtentry_ptr;
        !           375:     vifi_t new_iif;
        !           376:     vifbitmap_t new_pruned_oifs;
        !           377:     vifbitmap_t new_leaves_;
        !           378: {
        !           379:     vifbitmap_t old_pruned_oifs;
        !           380:     vifbitmap_t old_leaves;
        !           381:     vifbitmap_t new_leaves;
        !           382:     vifbitmap_t new_real_oifs;    /* The result oifs */
        !           383:     vifbitmap_t old_real_oifs;
        !           384:     vifi_t      old_iif;
        !           385:     int return_value;
        !           386:     
        !           387:     if (mrtentry_ptr == (mrtentry_t *)NULL)
        !           388:        return (0);
        !           389: 
        !           390:     VIFM_COPY(new_leaves_, new_leaves);
        !           391: 
        !           392:     old_iif = mrtentry_ptr->incoming;
        !           393:     VIFM_COPY(mrtentry_ptr->leaves, old_leaves);
        !           394:     VIFM_COPY(mrtentry_ptr->pruned_oifs, old_pruned_oifs);
        !           395: 
        !           396:     VIFM_COPY(mrtentry_ptr->oifs, old_real_oifs);
        !           397:     
        !           398:     mrtentry_ptr->incoming = new_iif;
        !           399:     VIFM_COPY(new_pruned_oifs, mrtentry_ptr->pruned_oifs);
        !           400:     VIFM_COPY(new_leaves, mrtentry_ptr->leaves);
        !           401:     calc_oifs(mrtentry_ptr, &new_real_oifs);
        !           402: 
        !           403:     if (VIFM_ISEMPTY(old_real_oifs)) {
        !           404:        if (VIFM_ISEMPTY(new_real_oifs))
        !           405:            return_value = 0;
        !           406:        else
        !           407:            return_value = 1;
        !           408:     } else {
        !           409:        if (VIFM_ISEMPTY(new_real_oifs))
        !           410:            return_value = -1;
        !           411:        else
        !           412:            return_value = 0;
        !           413:     }
        !           414: 
        !           415:     if ((VIFM_SAME(new_real_oifs, old_real_oifs))
        !           416:        && (new_iif == old_iif))
        !           417:        return 0;                  /* Nothing to change */
        !           418: 
        !           419:     VIFM_COPY(new_real_oifs, mrtentry_ptr->oifs);
        !           420:     
        !           421:     k_chg_mfc(igmp_socket, mrtentry_ptr->source->address,
        !           422:              mrtentry_ptr->group->group, new_iif, new_real_oifs);
        !           423: 
        !           424: #ifdef RSRR
        !           425:     rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
        !           426: #endif /* RSRR */
        !           427: 
        !           428:     return (return_value);
        !           429: }
        !           430:     
        !           431: 
        !           432: /* TODO: implement it. Required to allow changing of the physical interfaces
        !           433:  * configuration without need to restart pimd.
        !           434:  */
        !           435: int
        !           436: delete_vif_from_mrt(vifi)
        !           437: vifi_t vifi;
        !           438: {
        !           439:     return TRUE;
        !           440: }
        !           441: 
        !           442: 
        !           443: static u_int16
        !           444: max_prune_timeout(mrtentry_ptr)
        !           445:      mrtentry_t *mrtentry_ptr;
        !           446: {
        !           447:     vifi_t vifi;
        !           448:     u_int16 time_left, max_holdtime = 0;
        !           449: 
        !           450:     for(vifi=0; vifi < numvifs; ++vifi) 
        !           451:        if(VIFM_ISSET(vifi, mrtentry_ptr->pruned_oifs))
        !           452:            IF_TIMER_SET(mrtentry_ptr->prune_timers[vifi]) 
        !           453:                /* XXX - too expensive ? */
        !           454:                /* XXX: TIMER implem. dependency! */
        !           455:                if(mrtentry_ptr->prune_timers[vifi] > max_holdtime) 
        !           456:                    max_holdtime = time_left;
        !           457:     
        !           458:     if(max_holdtime == 0) 
        !           459:        max_holdtime = (u_int16)PIM_JOIN_PRUNE_HOLDTIME;
        !           460: 
        !           461:     return(max_holdtime);
        !           462: }
        !           463: 
        !           464: 
        !           465: void process_kernel_call()
        !           466: {
        !           467:     register struct igmpmsg *igmpctl; /* igmpmsg control struct */
        !           468:     
        !           469:     igmpctl = (struct igmpmsg *) igmp_recv_buf;
        !           470:     
        !           471:     switch (igmpctl->im_msgtype) {
        !           472:     case IGMPMSG_NOCACHE:
        !           473:        process_cache_miss(igmpctl);
        !           474:        break;
        !           475:     case IGMPMSG_WRONGVIF:
        !           476:        process_wrong_iif(igmpctl);
        !           477:        break;
        !           478:     default:
        !           479:        IF_DEBUG(DEBUG_KERN)
        !           480:            log(LOG_DEBUG, 0, "Unknown kernel_call code");
        !           481:        break;
        !           482:     }
        !           483: }
        !           484: 
        !           485: 
        !           486: /*
        !           487:  * Protocol actions:
        !           488:  *   1. Create (S,G) entry (find_route(CREATE))
        !           489:  *      a. set iif and oifs
        !           490:  */
        !           491: static void
        !           492: process_cache_miss(igmpctl)
        !           493:     struct igmpmsg *igmpctl;
        !           494: {
        !           495:     u_int32 source;
        !           496:     u_int32 group;
        !           497:     mrtentry_t *mrtentry_ptr;
        !           498: 
        !           499:     /*
        !           500:      * When there is a cache miss, we check only the header of the packet
        !           501:      * (and only it should be sent up by the kernel.
        !           502:      */
        !           503: 
        !           504:     group  = igmpctl->im_dst.s_addr;
        !           505:     source = igmpctl->im_src.s_addr;
        !           506:     
        !           507:     IF_DEBUG(DEBUG_MFC)
        !           508:        log(LOG_DEBUG, 0, "Cache miss, src %s, dst %s",
        !           509:            inet_fmt(source, s1), inet_fmt(group, s2)); 
        !           510: 
        !           511:     /* Don't create routing entries for the LAN scoped addresses */
        !           512:     if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP)
        !           513:        return; 
        !           514:     
        !           515:     /* Create the (S,G) entry */
        !           516:     mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE);
        !           517:     if (mrtentry_ptr == (mrtentry_t *)NULL)
        !           518:        return;
        !           519:     mrtentry_ptr->flags &= ~MRTF_NEW;
        !           520:     
        !           521:     /* Initialize Entry Timer */
        !           522:     SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT);
        !           523:     
        !           524:     /* Set oifs */     
        !           525:     set_leaves(mrtentry_ptr);
        !           526:     calc_oifs(mrtentry_ptr, &(mrtentry_ptr->oifs));
        !           527: 
        !           528:     /* Add it to the kernel */
        !           529:     k_chg_mfc(igmp_socket, source, group, mrtentry_ptr->incoming,
        !           530:              mrtentry_ptr->oifs);
        !           531: 
        !           532: #ifdef RSRR
        !           533:     rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
        !           534: #endif /* RSRR */
        !           535: 
        !           536:     /* No need to call change_interfaces, but check for NULL oiflist */
        !           537:     if(VIFM_ISEMPTY(mrtentry_ptr->oifs))
        !           538:        trigger_prune_alert(mrtentry_ptr);
        !           539: }
        !           540: 
        !           541: 
        !           542: /*
        !           543:  * A multicast packet has been received on wrong iif by the kernel.
        !           544:  * If the packet was received on a point-to-point interface, rate-limit
        !           545:  * prunes.  if the packet was received on a LAN interface, rate-limit 
        !           546:  * asserts.
        !           547:  */
        !           548: static void
        !           549: process_wrong_iif(igmpctl)
        !           550:     struct igmpmsg *igmpctl;
        !           551: {
        !           552:     u_int32 source;
        !           553:     u_int32 group;
        !           554:     vifi_t  vifi;
        !           555:     mrtentry_t *mrtentry_ptr;
        !           556: 
        !           557:     group  = igmpctl->im_dst.s_addr;
        !           558:     source = igmpctl->im_src.s_addr;
        !           559:     vifi   = igmpctl->im_vif;
        !           560: 
        !           561:     /* PIMDM TODO Don't create routing entries for the LAN scoped addresses */
        !           562:     if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP)
        !           563:        return;
        !           564: 
        !           565:     /* Ratelimit prunes or asserts */
        !           566:     if(uvifs[vifi].uv_flags & VIFF_POINT_TO_POINT) {
        !           567: 
        !           568:        mrtentry_ptr = find_route(source, group, MRTF_SG, DONT_CREATE);
        !           569:        if(mrtentry_ptr == (mrtentry_t *)NULL)
        !           570:            return;
        !           571: 
        !           572:        /* Wrong vif on P2P interface - rate-limit prunes */
        !           573: 
        !           574:        if(mrtentry_ptr->last_prune[vifi] == virtual_time)
        !           575:            /* Skip due to rate-limiting */
        !           576:            return;
        !           577:        mrtentry_ptr->last_prune[vifi] = virtual_time;
        !           578: 
        !           579:        if(uvifs[vifi].uv_rmt_addr)
        !           580:            send_pim_jp(mrtentry_ptr, PIM_ACTION_PRUNE, vifi, 
        !           581:                        uvifs[vifi].uv_rmt_addr, 
        !           582:                        max_prune_timeout(mrtentry_ptr));
        !           583:        else 
        !           584:            log(LOG_WARNING, 0, 
        !           585:                "Can't send wrongvif prune on p2p %s: no remote address",
        !           586:                uvifs[vifi].uv_lcl_addr);
        !           587:     } else {
        !           588:        u_int32 pref, metric;
        !           589: 
        !           590:        /* Wrong vif on LAN interface - rate-limit asserts */
        !           591: 
        !           592:        mrtentry_ptr = find_route(source, group, MRTF_SG, DONT_CREATE);
        !           593:        if(mrtentry_ptr == (mrtentry_t *)NULL) {
        !           594:            pref = 0x7fffffff;
        !           595:            metric = 0x7fffffff;
        !           596:        }
        !           597:        else {
        !           598:            pref = mrtentry_ptr->source->preference;
        !           599:            metric = mrtentry_ptr->source->metric;
        !           600:        }
        !           601:            
        !           602:        if(mrtentry_ptr->last_assert[vifi] == virtual_time)
        !           603:            /* Skip due to rate-limiting */
        !           604:            return;
        !           605:        mrtentry_ptr->last_assert[vifi] = virtual_time;
        !           606: 
        !           607:        /* Send the assert */
        !           608:        send_pim_assert(source, group, vifi, pref, metric);
        !           609:     }
        !           610: }
        !           611: 
        !           612: 
        !           613: void trigger_prune_alert(mrtentry_ptr)
        !           614:      mrtentry_t *mrtentry_ptr;
        !           615: {
        !           616:     IF_DEBUG(DEBUG_MRT)
        !           617:        log(LOG_DEBUG, 0, "Now negative cache for src %s, grp %s - pruning",
        !           618:            inet_fmt(mrtentry_ptr->source->address, s1), 
        !           619:            inet_fmt(mrtentry_ptr->group->group, s2));
        !           620: 
        !           621:     /* Set the entry timer to the max of the prune timers */
        !           622:     SET_TIMER(mrtentry_ptr->timer, max_prune_timeout(mrtentry_ptr));
        !           623: 
        !           624:     /* Send a prune */
        !           625:     if(mrtentry_ptr->upstream) 
        !           626:        send_pim_jp(mrtentry_ptr, PIM_ACTION_PRUNE, mrtentry_ptr->incoming,
        !           627:                    mrtentry_ptr->upstream->address, 
        !           628:                    max_prune_timeout(mrtentry_ptr));
        !           629: }
        !           630: 
        !           631: void trigger_join_alert(mrtentry_ptr)
        !           632:      mrtentry_t *mrtentry_ptr;
        !           633: {
        !           634:     IF_DEBUG(DEBUG_MRT)
        !           635:        log(LOG_DEBUG, 0, "Now forwarding state for src %s, grp %s - grafting",
        !           636:            inet_fmt(mrtentry_ptr->source->address, s1), 
        !           637:            inet_fmt(mrtentry_ptr->group->group, s2));
        !           638: 
        !           639:     /* Refresh the entry timer */
        !           640:     SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT);
        !           641: 
        !           642:     /* Send graft */
        !           643:     send_pim_graft(mrtentry_ptr);
        !           644: }

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