File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimdd / vif.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:58:55 2017 UTC (6 years, 11 months ago) by misho
Branches: pimdd, MAIN
CVS tags: v0_2_1p0, v0_2_1, HEAD
pimdd-dense 0.2.1.0_2

    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.1.1.1 2017/06/12 07:58:55 misho 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>