Annotation of embedaddon/pimdd/route.c, revision 1.1.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>