Annotation of embedaddon/pimdd/vif.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *  Copyright (c) 1998 by the University of Southern California.
                      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 Southern
                     13:  *  California and/or Information Sciences Institute.
                     14:  *  The name of the University of Southern California may not
                     15:  *  be used to endorse or promote products derived from this software
                     16:  *  without specific prior written permission.
                     17:  *
                     18:  *  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
                     19:  *  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
                     20:  *  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
                     21:  *  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     22:  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND 
                     23:  *  NON-INFRINGEMENT.
                     24:  *
                     25:  *  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
                     26:  *  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
                     27:  *  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
                     28:  *  THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     29:  *
                     30:  *  Other copyrights might apply to parts of this software and are so
                     31:  *  noted when applicable.
                     32:  */
                     33: /*
                     34:  *  Questions concerning this software should be directed to 
                     35:  *  Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
                     36:  *
                     37:  *  $Id: vif.c,v 1.6 1998/12/22 21:50:19 kurtw Exp $
                     38:  */
                     39: /*
                     40:  * Part of this program has been derived from mrouted.
                     41:  * The mrouted program is covered by the license in the accompanying file
                     42:  * named "LICENSE.mrouted".
                     43:  *
                     44:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
                     45:  * Leland Stanford Junior University.
                     46:  *
                     47:  */
                     48: 
                     49: #include "defs.h"
                     50: 
                     51: /*
                     52:  * Exported variables.
                     53:  */
                     54: struct uvif    uvifs[MAXVIFS]; /* array of all virtual interfaces          */
                     55: vifi_t         numvifs;        /* Number of vifs in use                    */
                     56: int             vifs_down;      /* 1=>some interfaces are down              */
                     57: int             phys_vif;       /* An enabled vif                           */
                     58: int            udp_socket;     /* Since the honkin' kernel doesn't support */
                     59:                                /* ioctls on raw IP sockets, we need a UDP  */
                     60:                                /* socket as well as our IGMP (raw) socket. */
                     61:                                /* How dumb.                                */
                     62: int             total_interfaces; /* Number of all interfaces: including the
                     63:                                   * non-configured, but excluding the
                     64:                                   * loopback interface and the non-multicast
                     65:                                   * capable interfaces.
                     66:                                   */
                     67: 
                     68: /*
                     69:  * Forward declarations.
                     70:  */
                     71: static void start_vif      __P((vifi_t vifi));
                     72: static void stop_vif       __P((vifi_t vifi));
                     73: static void start_all_vifs __P(());
                     74: 
                     75: 
                     76: void
                     77: init_vifs()
                     78: {
                     79:     vifi_t vifi;
                     80:     struct uvif *v;
                     81:     int enabled_vifs;
                     82:        
                     83:     numvifs    = 0;
                     84:     vifs_down = FALSE;
                     85: 
                     86:     /*
                     87:      * Configure the vifs based on the interface configuration of the
                     88:      * the kernel and the contents of the configuration file.
                     89:      * (Open a UDP socket for ioctl use in the config procedures if
                     90:      * the kernel can't handle IOCTL's on the IGMP socket.)
                     91:      */
                     92: #ifdef IOCTL_OK_ON_RAW_SOCKET
                     93:     udp_socket = igmp_socket;
                     94: #else
                     95:     if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
                     96:        log(LOG_ERR, errno, "UDP socket");
                     97: #endif
                     98: 
                     99:     /*
                    100:      * Clean up all vifs
                    101:      */
                    102:     for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v) {
                    103:        v->uv_flags             = 0;
                    104:        v->uv_metric            = DEFAULT_METRIC;
                    105:        v->uv_admetric          = 0;
                    106:        v->uv_threshold         = DEFAULT_THRESHOLD;
                    107:        v->uv_rate_limit        = DEFAULT_PHY_RATE_LIMIT;
                    108:        v->uv_lcl_addr          = INADDR_ANY_N;
                    109:        v->uv_rmt_addr          = INADDR_ANY_N;
                    110:        v->uv_dst_addr          = INADDR_ANY_N;
                    111:        v->uv_subnet            = INADDR_ANY_N;
                    112:        v->uv_subnetmask        = INADDR_ANY_N;
                    113:        v->uv_subnetbcast       = INADDR_ANY_N;
                    114:        strncpy(v->uv_name, "", IFNAMSIZ);
                    115:        v->uv_groups            = (struct listaddr *)NULL;
                    116:        v->uv_dvmrp_neighbors   = (struct listaddr *)NULL;
                    117:        NBRM_CLRALL(v->uv_nbrmap);
                    118:        v->uv_querier           = (struct listaddr *)NULL;
                    119:        v->uv_igmpv1_warn       = 0;
                    120:        v->uv_prune_lifetime    = 0;
                    121:        v->uv_acl               = (struct vif_acl *)NULL;
                    122:        RESET_TIMER(v->uv_leaf_timer);
                    123:        v->uv_addrs             = (struct phaddr *)NULL;
                    124:        v->uv_filter            = (struct vif_filter *)NULL;
                    125:        RESET_TIMER(v->uv_pim_hello_timer);
                    126:        RESET_TIMER(v->uv_gq_timer);
                    127:        v->uv_pim_neighbors     = (struct pim_nbr_entry *)NULL;
                    128:        v->uv_local_pref        = default_source_preference;
                    129:        v->uv_local_metric      = default_source_metric;
                    130:     }
                    131: 
                    132:     log(LOG_INFO, 0, "Getting vifs from kernel");
                    133:     config_vifs_from_kernel();
                    134:     log(LOG_INFO, 0, "Getting vifs from %s", configfilename);
                    135:     config_vifs_from_file();
                    136: 
                    137:     /*
                    138:      * Quit if there are fewer than two enabled vifs.
                    139:      */
                    140:     enabled_vifs    = 0;
                    141:     phys_vif        = -1;
                    142:         
                    143:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                    144:        if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
                    145:            continue;
                    146:        if (phys_vif == -1)
                    147:            phys_vif = vifi;
                    148:        enabled_vifs++;
                    149:     }
                    150: 
                    151:     if (enabled_vifs < 2)
                    152:        log(LOG_ERR, 0, "can't forward: %s",
                    153:            enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
                    154:     
                    155:     k_init_pim(igmp_socket);   /* Call to kernel to initiliaze structures */
                    156: 
                    157:     start_all_vifs();
                    158: }
                    159: 
                    160: 
                    161: static void
                    162: start_all_vifs()
                    163: {
                    164:     vifi_t vifi;
                    165:     struct uvif *v;
                    166: 
                    167:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                    168:        /* Start vif if not DISABLED or DOWN */
                    169:        if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN)) {
                    170:            if (v->uv_flags & VIFF_DISABLED)
                    171:                log(LOG_INFO, 0,
                    172:                    "%s is DISABLED; vif #%u out of service", 
                    173:                    v->uv_name, vifi);
                    174:            else
                    175:                log(LOG_INFO, 0,
                    176:                    "%s is DOWN; vif #%u out of service", 
                    177:                    v->uv_name, vifi);
                    178:            }
                    179:        else
                    180:            start_vif(vifi);
                    181:     }
                    182: }
                    183: 
                    184: 
                    185: 
                    186: /*
                    187:  * stop all vifs
                    188:  */
                    189: void
                    190: stop_all_vifs()
                    191: {
                    192:     vifi_t vifi;
                    193: 
                    194:     for (vifi = 0; vifi < numvifs; vifi++) {
                    195:        stop_vif(vifi);
                    196:     }
                    197: }
                    198: 
                    199: 
                    200: /*
                    201:  * Initialize the vif and add to the kernel. The vif can be either
                    202:  * physical, tunnel (tunnels will be used in the future
                    203:  * when this code becomes PIM multicast boarder router.
                    204:  */
                    205: static void 
                    206: start_vif(vifi)
                    207:     vifi_t vifi;
                    208: {
                    209:     struct uvif *v;
                    210:     u_int32    src;
                    211: 
                    212:     v              = &uvifs[vifi];
                    213:     src             = v->uv_lcl_addr;
                    214:     /* Initialy no router on any vif */
                    215:     v->uv_flags = (v->uv_flags | VIFF_DR | VIFF_NONBRS) & ~VIFF_DOWN;
                    216:     SET_TIMER(v->uv_pim_hello_timer, 1 + RANDOM() % PIM_TIMER_HELLO_PERIOD);
                    217:     RESET_TIMER(v->uv_gq_timer);
                    218:     v->uv_pim_neighbors = (pim_nbr_entry_t *)NULL;
                    219:     
                    220:     /* Tell kernel to add, i.e. start this vif */
                    221:     k_add_vif(igmp_socket, vifi, &uvifs[vifi]);   
                    222:     log(LOG_INFO, 0, "%s comes up; vif #%u now in service", v->uv_name, vifi);
                    223:     
                    224:     /*
                    225:      * Join the PIM multicast group on the interface.
                    226:      */
                    227:     k_join(igmp_socket, allpimrouters_group, src);
                    228:        
                    229:     /*
                    230:      * Join the ALL-ROUTERS multicast group on the interface.
                    231:      * This allows mtrace requests to loop back if they are run
                    232:      * on the multicast router.
                    233:      */
                    234:     k_join(igmp_socket, allrouters_group, src);
                    235:        
                    236:     /*
                    237:      * Until neighbors are discovered, assume responsibility for sending
                    238:      * periodic group membership queries to the subnet.  Send the first
                    239:      * query.
                    240:      */
                    241:     v->uv_flags |= VIFF_QUERIER;
                    242:     query_groups(v);
                    243:        
                    244:     /*
                    245:      * Send a probe via the new vif to look for neighbors.
                    246:      */
                    247:     send_pim_hello(v, PIM_TIMER_HELLO_HOLDTIME);
                    248: }
                    249: 
                    250: 
                    251: /*
                    252:  * Stop a vif (either physical interface or tunnel).
                    253:  * If we are running only PIM we don't have tunnels.
                    254:  */
                    255: static void 
                    256: stop_vif(vifi)
                    257:     vifi_t vifi;
                    258: {
                    259:     struct uvif *v;
                    260:     struct listaddr *a;
                    261:     register pim_nbr_entry_t *n, *next;
                    262:     struct vif_acl *acl;
                    263:     
                    264:     /*
                    265:      * TODO: make sure that the kernel viftable is 
                    266:      * consistent with the daemon table
                    267:      */        
                    268:     v = &uvifs[vifi];
                    269:     k_leave(igmp_socket, allpimrouters_group, v->uv_lcl_addr);
                    270:     k_leave(igmp_socket, allrouters_group, v->uv_lcl_addr);
                    271:     /*
                    272:      * Discard all group addresses.  (No need to tell kernel;
                    273:      * the k_del_vif() call will clean up kernel state.)
                    274:      */
                    275:     while (v->uv_groups != NULL) {
                    276:        a = v->uv_groups;
                    277:        v->uv_groups = a->al_next;
                    278:        free((char *)a);
                    279:     }
                    280:     
                    281:     /*
                    282:      * TODO: inform (eventually) the neighbors I am going down by sending
                    283:      * PIM_HELLO with holdtime=0 so someone else should become a DR.
                    284:      */ 
                    285:     /* TODO: dummy! Implement it!! Any problems if don't use it? */
                    286:     delete_vif_from_mrt(vifi);
                    287:     
                    288:     /*
                    289:      * Delete the interface from the kernel's vif structure.
                    290:      */
                    291:     k_del_vif(igmp_socket, vifi);
                    292:     v->uv_flags     = (v->uv_flags & ~VIFF_DR & ~VIFF_QUERIER & ~VIFF_NONBRS )
                    293:                      | VIFF_DOWN;
                    294:     RESET_TIMER(v->uv_pim_hello_timer);
                    295:     RESET_TIMER(v->uv_gq_timer);
                    296:     for (n = v->uv_pim_neighbors; n != NULL; n = next) {
                    297:        next = n->next; /* Free the space for each neighbour */
                    298:        free((char *)n);
                    299:     }
                    300:     v->uv_pim_neighbors = NULL;
                    301: 
                    302:     /* TODO: currently not used */
                    303:    /* The Access Control List (list with the scoped addresses) */
                    304:     while (v->uv_acl != NULL) {
                    305:        acl = v->uv_acl;
                    306:        v->uv_acl = acl->acl_next;
                    307:        free((char *)acl);
                    308:     }
                    309: 
                    310:     vifs_down = TRUE;
                    311:     log(LOG_INFO, 0,
                    312:        "%s goes down; vif #%u out of service", v->uv_name, vifi);
                    313: }              
                    314: 
                    315: 
                    316: /*
                    317:  * See if any interfaces have changed from up state to down, or vice versa,
                    318:  * including any non-multicast-capable interfaces that are in use as local
                    319:  * tunnel end-points.  Ignore interfaces that have been administratively
                    320:  * disabled.
                    321:  */
                    322: void
                    323: check_vif_state()
                    324: {
                    325:     register vifi_t vifi;
                    326:     register struct uvif *v;
                    327:     struct ifreq ifr;
                    328:     static int checking_vifs = 0;
                    329: 
                    330:     /*
                    331:      * XXX: TODO: True only for DVMRP?? Check.
                    332:      * If we get an error while checking, (e.g. two interfaces go down
                    333:      * at once, and we decide to send a prune out one of the failed ones)
                    334:      * then don't go into an infinite loop!
                    335:      */
                    336:     if (checking_vifs)
                    337:        return;
                    338: 
                    339:     vifs_down = FALSE;
                    340:     checking_vifs = 1;
                    341:     /* TODO: Check all potential interfaces!!! */
                    342:     /* Check the physical and tunnels only */
                    343:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                    344:        if (v->uv_flags & VIFF_DISABLED)
                    345:            continue;
                    346:        
                    347:        strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
                    348:        /* get the interface flags */
                    349:        if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
                    350:            log(LOG_ERR, errno,
                    351:                "check_vif_state: ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
                    352: 
                    353:        if (v->uv_flags & VIFF_DOWN) {
                    354:            if (ifr.ifr_flags & IFF_UP) {
                    355:                start_vif(vifi);
                    356:            }
                    357:            else vifs_down = TRUE;
                    358:        }
                    359:        else {
                    360:            if (!(ifr.ifr_flags & IFF_UP)) {
                    361:                log(LOG_NOTICE, 0,
                    362:                    "%s has gone down; vif #%u taken out of service",
                    363:                    v->uv_name, vifi);
                    364:                stop_vif(vifi);
                    365:                vifs_down = TRUE;
                    366:            }
                    367:        }
                    368:     }
                    369:     checking_vifs = 0;
                    370: }
                    371: 
                    372: 
                    373: /*
                    374:  * If the source is directly connected to us, find the vif number for
                    375:  * the corresponding physical interface (tunnels excluded).
                    376:  * Local addresses are excluded.
                    377:  * Return the vif number or NO_VIF if not found.
                    378:  */
                    379: vifi_t 
                    380: find_vif_direct(src)
                    381:     u_int32 src;
                    382: {
                    383:     vifi_t vifi;
                    384:     register struct uvif *v;
                    385:     register struct phaddr *p;
                    386:        
                    387:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                    388:        if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL))
                    389:            continue;
                    390:        if (src == v->uv_lcl_addr)
                    391:            return (NO_VIF);     /* src is one of our IP addresses */
                    392:        if ((src & v->uv_subnetmask) == v->uv_subnet && 
                    393:            ((v->uv_subnetmask == 0xffffffff) ||
                    394:             (src != v->uv_subnetbcast)))
                    395:            return(vifi);
                    396:        /* Check the extra subnets for this vif */
                    397:        /* TODO: don't think currently pimd can handle extra subnets */
                    398:        for (p = v->uv_addrs; p; p = p->pa_next) {
                    399:            if ((src & p->pa_subnetmask) == p->pa_subnet &&
                    400:                ((p->pa_subnetmask == 0xffffffff) ||
                    401:                 (src != p->pa_subnetbcast)))
                    402:                return(vifi);
                    403:        }
                    404:     }
                    405:     return (NO_VIF);
                    406: } 
                    407: 
                    408: 
                    409: /*
                    410:  * Checks if src is local address. If "yes" return the vif index,
                    411:  * otherwise return value is NO_VIF.
                    412:  */
                    413: vifi_t
                    414: local_address(src)
                    415:     u_int32 src;
                    416: {
                    417:     vifi_t vifi;
                    418:     register struct uvif *v;
                    419:     
                    420:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                    421:        if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
                    422:            continue;
                    423:        if (src != v->uv_lcl_addr)
                    424:            continue;
                    425:        else 
                    426:            return(vifi);
                    427:     }   
                    428:     /* Returning NO_VIF means not a local address */
                    429:     return (NO_VIF);   
                    430: }
                    431: 
                    432: /*
                    433:  * If the source is directly connected, or is local address,
                    434:  * find the vif number for the corresponding physical interface
                    435:  * (tunnels excluded).
                    436:  * Return the vif number or NO_VIF if not found.
                    437:  */
                    438: vifi_t 
                    439: find_vif_direct_local(src)
                    440:     u_int32 src;
                    441: {
                    442:     vifi_t vifi;
                    443:     register struct uvif *v;
                    444:     register struct phaddr *p;
                    445:        
                    446:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                    447:        if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL))
                    448:            continue;
                    449:        if (src == v->uv_lcl_addr)
                    450:            return (vifi);     /* src is one of our IP addresses */
                    451:        if ((src & v->uv_subnetmask) == v->uv_subnet && 
                    452:            ((v->uv_subnetmask == 0xffffffff) ||
                    453:             (src != v->uv_subnetbcast)))
                    454:            return(vifi);
                    455:        /* Check the extra subnets for this vif */
                    456:        /* TODO: don't think currently pimd can handle extra subnets */
                    457:        for (p = v->uv_addrs; p; p = p->pa_next) {
                    458:            if ((src & p->pa_subnetmask) == p->pa_subnet &&
                    459:                ((p->pa_subnetmask == 0xffffffff) ||
                    460:                 (src != p->pa_subnetbcast)))
                    461:                return(vifi);
                    462:        }
                    463:     }
                    464:     return (NO_VIF);
                    465: } 
                    466: 
                    467: /*
                    468:  * Returns the highest address of local vif that is UP and ENABLED.
                    469:  */
                    470: u_int32
                    471: max_local_address()
                    472: {
                    473:     vifi_t vifi;
                    474:     struct uvif *v;
                    475:     u_int32 max_address = 0;
                    476:     
                    477:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                    478:        /* Count vif if not DISABLED or DOWN */
                    479:        if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
                    480:            continue;
                    481:        if (ntohl(v->uv_lcl_addr) > ntohl(max_address))
                    482:            max_address = v->uv_lcl_addr;
                    483:     }
                    484:     return(max_address);
                    485: }

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