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