File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / vif.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:59:38 2017 UTC (6 years, 11 months ago) by misho
Branches: pimd, MAIN
CVS tags: v2_3_2, HEAD
pimd 2.3.2

    1: /*
    2:  * Copyright (c) 1998-2001
    3:  * University of Southern California/Information Sciences Institute.
    4:  * All rights reserved.
    5:  *
    6:  * Redistribution and use in source and binary forms, with or without
    7:  * modification, are permitted provided that the following conditions
    8:  * are met:
    9:  * 1. Redistributions of source code must retain the above copyright
   10:  *    notice, this list of conditions and the following disclaimer.
   11:  * 2. Redistributions in binary form must reproduce the above copyright
   12:  *    notice, this list of conditions and the following disclaimer in the
   13:  *    documentation and/or other materials provided with the distribution.
   14:  * 3. Neither the name of the project nor the names of its contributors
   15:  *    may be used to endorse or promote products derived from this software
   16:  *    without specific prior written permission.
   17:  *
   18:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28:  * SUCH DAMAGE.
   29:  */
   30: /*
   31:  * Part of this program has been derived from mrouted.
   32:  * The mrouted program is covered by the license in the accompanying file
   33:  * named "LICENSE.mrouted".
   34:  *
   35:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
   36:  * Leland Stanford Junior University.
   37:  *
   38:  */
   39: 
   40: 
   41: #include "defs.h"
   42: 
   43: /*
   44:  * Helper macros
   45:  */
   46: #define is_uv_subnet(src, v) \
   47:     (src & v->uv_subnetmask) == v->uv_subnet && ((v->uv_subnetmask == 0xffffffff) || (src != v->uv_subnetbcast))
   48: 
   49: #define is_pa_subnet(src, v) \
   50:     (src & p->pa_subnetmask) == p->pa_subnet && ((p->pa_subnetmask == 0xffffffff) || (src != p->pa_subnetbcast))
   51: 
   52: /*
   53:  * Exported variables.
   54:  */
   55: struct uvif	uvifs[MAXVIFS]; /* array of all virtual interfaces          */
   56: vifi_t		numvifs;	/* Number of vifs in use                    */
   57: int             vifs_down;      /* 1=>some interfaces are down              */
   58: int             phys_vif;       /* An enabled vif                           */
   59: vifi_t		reg_vif_num;    /* really virtual interface for registers   */
   60: int		udp_socket;	/* Since the honkin' kernel doesn't support
   61: 				 * ioctls on raw IP sockets, we need a UDP
   62: 				 * socket as well as our IGMP (raw) socket. */
   63: int             total_interfaces; /* Number of all interfaces: including the
   64: 				   * non-configured, but excluding the
   65: 				   * loopback interface and the non-multicast
   66: 				   * capable interfaces.
   67: 				   */
   68: 
   69: uint32_t	default_route_metric   = UCAST_DEFAULT_ROUTE_METRIC;
   70: uint32_t	default_route_distance = UCAST_DEFAULT_ROUTE_DISTANCE;
   71: 
   72: /*
   73:  * Forward declarations
   74:  */
   75: static void start_vif      (vifi_t vifi);
   76: static void stop_vif       (vifi_t vifi);
   77: static void start_all_vifs (void);
   78: static int init_reg_vif    (void);
   79: static int update_reg_vif  (vifi_t register_vifi);
   80: 
   81: 
   82: void init_vifs(void)
   83: {
   84:     vifi_t vifi;
   85:     struct uvif *v;
   86:     int enabled_vifs;
   87: 
   88:     numvifs    = 0;
   89:     reg_vif_num = NO_VIF;
   90:     vifs_down = FALSE;
   91: 
   92:     /* Configure the vifs based on the interface configuration of the the kernel and
   93:      * the contents of the configuration file.  (Open a UDP socket for ioctl use in
   94:      * the config procedures if the kernel can't handle IOCTL's on the IGMP socket.) */
   95: #ifdef IOCTL_OK_ON_RAW_SOCKET
   96:     udp_socket = igmp_socket;
   97: #else
   98:     if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
   99: 	logit(LOG_ERR, errno, "UDP socket");
  100: #endif
  101: 
  102:     /* Clean up all vifs */
  103:     for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v)
  104: 	zero_vif(v, FALSE);
  105: 
  106:     logit(LOG_INFO, 0, "Getting vifs from kernel");
  107:     config_vifs_from_kernel();
  108:     if (disable_all_by_default) {
  109:        logit(LOG_INFO, 0, "Disabling all vifs from kernel");
  110: 
  111:        for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v)
  112:           v->uv_flags |= VIFF_DISABLED;
  113:     }
  114: 
  115:     logit(LOG_INFO, 0, "Getting vifs from %s", config_file);
  116:     config_vifs_from_file();
  117: 
  118:     /*
  119:      * Quit if there are fewer than two enabled vifs.
  120:      */
  121:     enabled_vifs    = 0;
  122:     phys_vif        = -1;
  123: 
  124:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  125: 	/* Initialize the outgoing timeout for each vif.  Currently use a fixed time
  126: 	 * 'PIM_JOIN_PRUNE_HOLDTIME'.  Later, may add a configurable array to feed
  127: 	 * these parameters, or compute them as function of the i/f bandwidth and the
  128: 	 * overall connectivity...etc. */
  129: 	SET_TIMER(v->uv_jp_timer, PIM_JOIN_PRUNE_HOLDTIME);
  130: 	if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_TUNNEL))
  131: 	    continue;
  132: 
  133: 	if (phys_vif == -1)
  134: 	    phys_vif = vifi;
  135: 
  136: 	enabled_vifs++;
  137:     }
  138: 
  139:     if (enabled_vifs < 1) /* XXX: TODO: */
  140: 	logit(LOG_ERR, 0, "Cannot forward: %s", enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
  141: 
  142:     k_init_pim(igmp_socket);	/* Call to kernel to initialize structures */
  143: 
  144:     /* Add a dummy virtual interface to support Registers in the kernel.
  145:      * In order for this to work, the kernel has to have been modified
  146:      * with the PIM patches to ip_mroute.{c,h} and ip.c
  147:      */
  148:     init_reg_vif();
  149: 
  150:     start_all_vifs();
  151: }
  152: 
  153: /*
  154:  * Initialize the passed vif with all appropriate default values.
  155:  * "t" is true if a tunnel or register_vif, or false if a phyint.
  156:  */
  157: void zero_vif(struct uvif *v, int t)
  158: {
  159:     v->uv_flags		= 0;	/* Default to IGMPv3 */
  160:     v->uv_metric	= DEFAULT_METRIC;
  161:     v->uv_admetric	= 0;
  162:     v->uv_threshold	= DEFAULT_THRESHOLD;
  163:     v->uv_rate_limit	= t ? DEFAULT_REG_RATE_LIMIT : DEFAULT_PHY_RATE_LIMIT;
  164:     v->uv_lcl_addr	= INADDR_ANY_N;
  165:     v->uv_rmt_addr	= INADDR_ANY_N;
  166:     v->uv_dst_addr	= t ? INADDR_ANY_N : allpimrouters_group;
  167:     v->uv_subnet	= INADDR_ANY_N;
  168:     v->uv_subnetmask	= INADDR_ANY_N;
  169:     v->uv_subnetbcast	= INADDR_ANY_N;
  170:     strlcpy(v->uv_name, "", IFNAMSIZ);
  171:     v->uv_groups	= (struct listaddr *)NULL;
  172:     v->uv_dvmrp_neighbors = (struct listaddr *)NULL;
  173:     NBRM_CLRALL(v->uv_nbrmap);
  174:     v->uv_querier	= (struct listaddr *)NULL;
  175:     v->uv_igmpv1_warn	= 0;
  176:     v->uv_prune_lifetime = 0;
  177:     v->uv_acl		= (struct vif_acl *)NULL;
  178:     RESET_TIMER(v->uv_leaf_timer);
  179:     v->uv_addrs		= (struct phaddr *)NULL;
  180:     v->uv_filter	= (struct vif_filter *)NULL;
  181: 
  182:     RESET_TIMER(v->uv_hello_timer);
  183:     v->uv_dr_prio       = PIM_HELLO_DR_PRIO_DEFAULT;
  184:     v->uv_genid         = 0;
  185: 
  186:     RESET_TIMER(v->uv_gq_timer);
  187:     RESET_TIMER(v->uv_jp_timer);
  188:     v->uv_pim_neighbors	= (struct pim_nbr_entry *)NULL;
  189:     v->uv_local_pref	= default_route_distance;
  190:     v->uv_local_metric	= default_route_metric;
  191: #ifdef __linux__
  192:     v->uv_ifindex	= -1;
  193: #endif /* __linux__ */
  194: }
  195: 
  196: 
  197: /*
  198:  * Add a (the) register vif to the vif table.
  199:  */
  200: static int init_reg_vif(void)
  201: {
  202:     struct uvif *v;
  203:     vifi_t i;
  204: 
  205:     v = &uvifs[numvifs];
  206:     v->uv_flags = 0;
  207: 
  208:     if ((numvifs + 1) == MAXVIFS) {
  209:         /* Exit the program! The PIM router must have a Register vif */
  210: 	logit(LOG_ERR, 0, "Cannot install the Register vif: too many interfaces");
  211: 
  212: 	return FALSE;
  213:     }
  214: 
  215:     /*
  216:      * So far in PIM we need only one register vif and we save its number in
  217:      * the global reg_vif_num.
  218:      */
  219:     reg_vif_num = numvifs;
  220: 
  221:     /* set the REGISTER flag */
  222:     v->uv_flags = VIFF_REGISTER;
  223: #ifdef PIM_EXPERIMENTAL
  224:     v->uv_flags |= VIFF_REGISTER_KERNEL_ENCAP;
  225: #endif
  226:     strlcpy(v->uv_name, "register_vif0", sizeof(v->uv_name));
  227: 
  228:     /* Use the address of the first available physical interface to
  229:      * create the register vif.
  230:      */
  231:     for (i = 0; i < numvifs; i++) {
  232: 	if (uvifs[i].uv_flags & (VIFF_DOWN | VIFF_DISABLED | VIFF_REGISTER | VIFF_TUNNEL))
  233: 	    continue;
  234: 
  235: 	break;
  236:     }
  237: 
  238:     if (i >= numvifs) {
  239: 	logit(LOG_ERR, 0, "No physical interface enabled");
  240: 	return -1;
  241:     }
  242: 
  243:     v->uv_lcl_addr = uvifs[i].uv_lcl_addr;
  244:     v->uv_threshold = MINTTL;
  245: 
  246:     numvifs++;
  247:     total_interfaces++;
  248: 
  249:     return 0;
  250: }
  251: 
  252: 
  253: static void start_all_vifs(void)
  254: {
  255:     vifi_t vifi;
  256:     struct uvif *v;
  257:     u_int action;
  258: 
  259:     /* Start first the NON-REGISTER vifs */
  260:     for (action = 0; ; action = VIFF_REGISTER) {
  261: 	for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  262: 	    /* If starting non-registers but the vif is a register or if starting
  263: 	     * registers, but the interface is not a register, then just continue. */
  264: 	    if ((v->uv_flags & VIFF_REGISTER) ^ action)
  265: 		continue;
  266: 
  267: 	    /* Start vif if not DISABLED or DOWN */
  268: 	    if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN)) {
  269: 		if (v->uv_flags & VIFF_DISABLED)
  270: 		    logit(LOG_INFO, 0, "Interface %s is DISABLED; vif #%u out of service", v->uv_name, vifi);
  271: 		else
  272: 		    logit(LOG_INFO, 0, "Interface %s is DOWN; vif #%u out of service", v->uv_name, vifi);
  273: 	    } else {
  274: 		start_vif(vifi);
  275: 	    }
  276: 	}
  277: 
  278: 	if (action == VIFF_REGISTER)
  279: 	    break;   /* We are done */
  280:     }
  281: }
  282: 
  283: 
  284: /*
  285:  * stop all vifs
  286:  */
  287: void stop_all_vifs(void)
  288: {
  289:     vifi_t vifi;
  290:     struct uvif *v;
  291: 
  292:     for (vifi = 0; vifi < numvifs; vifi++) {
  293: 	v = &uvifs[vifi];
  294: 	if (!(v->uv_flags & VIFF_DOWN))
  295: 	    stop_vif(vifi);
  296:     }
  297: }
  298: 
  299: 
  300: /*
  301:  * Initialize the vif and add to the kernel. The vif can be either
  302:  * physical, register or tunnel (tunnels will be used in the future
  303:  * when this code becomes PIM multicast boarder router.
  304:  */
  305: static void start_vif(vifi_t vifi)
  306: {
  307:     struct uvif *v;
  308: 
  309:     v	= &uvifs[vifi];
  310:     /* Initialy no router on any vif */
  311:     if (v->uv_flags & VIFF_REGISTER)
  312: 	v->uv_flags = v->uv_flags & ~VIFF_DOWN;
  313:     else {
  314: 	v->uv_flags = (v->uv_flags | VIFF_DR | VIFF_NONBRS) & ~VIFF_DOWN;
  315: 
  316: 	/* https://tools.ietf.org/html/draft-ietf-pim-hello-genid-01 */
  317: 	v->uv_genid = RANDOM();
  318: 
  319: 	SET_TIMER(v->uv_hello_timer, 1 + RANDOM() % pim_timer_hello_interval);
  320: 	SET_TIMER(v->uv_jp_timer, 1 + RANDOM() % PIM_JOIN_PRUNE_PERIOD);
  321: 	/* TODO: CHECK THE TIMERS!!!!! Set or reset? */
  322: 	RESET_TIMER(v->uv_gq_timer);
  323: 	v->uv_pim_neighbors = (pim_nbr_entry_t *)NULL;
  324:     }
  325: 
  326:     /* Tell kernel to add, i.e. start this vif */
  327:     k_add_vif(igmp_socket, vifi, &uvifs[vifi]);
  328:     logit(LOG_INFO, 0, "Interface %s comes up; vif #%u now in service", v->uv_name, vifi);
  329: 
  330:     if (!(v->uv_flags & VIFF_REGISTER)) {
  331: 	/* Join the PIM multicast group on the interface. */
  332: 	k_join(pim_socket, allpimrouters_group, v);
  333: 
  334: 	/* Join the ALL-ROUTERS multicast group on the interface.  This
  335: 	 * allows mtrace requests to loop back if they are run on the
  336: 	 * multicast router. */
  337: 	k_join(igmp_socket, allrouters_group, v);
  338: 
  339: 	/* Join INADDR_ALLRPTS_GROUP to support IGMPv3 membership reports */
  340: 	k_join(igmp_socket, allreports_group, v);
  341: 
  342: 	/* Until neighbors are discovered, assume responsibility for sending
  343: 	 * periodic group membership queries to the subnet.  Send the first
  344: 	 * query. */
  345: 	v->uv_flags |= VIFF_QUERIER;
  346: 	query_groups(v);
  347: 
  348: 	/* Send a probe via the new vif to look for neighbors. */
  349: 	send_pim_hello(v, pim_timer_hello_holdtime);
  350:     }
  351: #ifdef __linux__
  352:     else {
  353: 	struct ifreq ifr;
  354: 
  355: 	memset(&ifr, 0, sizeof(struct ifreq));
  356: 
  357: 	if (mrt_table_id != 0) {
  358: 	        logit(LOG_INFO, 0, "Initializing pimreg%u", mrt_table_id);
  359: 		snprintf(ifr.ifr_name, IFNAMSIZ, "pimreg%u", mrt_table_id);
  360: 	} else {
  361: 		strlcpy(ifr.ifr_name, "pimreg", IFNAMSIZ);
  362: 	}
  363: 
  364: 	if (ioctl(udp_socket, SIOGIFINDEX, (char *) &ifr) < 0) {
  365: 	    logit(LOG_ERR, errno, "ioctl SIOGIFINDEX for %s", ifr.ifr_name);
  366: 	    /* Not reached */
  367: 	    return;
  368: 	}
  369: 
  370: 	v->uv_ifindex = ifr.ifr_ifindex;
  371:     }
  372: #endif /* __linux__ */
  373: }
  374: 
  375: 
  376: /*
  377:  * Stop a vif (either physical interface, tunnel or
  378:  * register.) If we are running only PIM we don't have tunnels.
  379:  */
  380: static void stop_vif(vifi_t vifi)
  381: {
  382:     struct uvif *v;
  383:     struct listaddr *a, *b;
  384:     pim_nbr_entry_t *n, *next;
  385:     struct vif_acl *acl;
  386: 
  387:     /*
  388:      * TODO: make sure that the kernel viftable is
  389:      * consistent with the daemon table
  390:      */
  391:     v = &uvifs[vifi];
  392:     if (!(v->uv_flags & VIFF_REGISTER)) {
  393: 	k_leave(pim_socket, allpimrouters_group, v);
  394: 	k_leave(igmp_socket, allrouters_group, v);
  395: 	k_leave(igmp_socket, allreports_group, v);
  396: 
  397: 	/* Discard all group addresses.  (No need to tell kernel;
  398: 	 * the k_del_vif() call will clean up kernel state.) */
  399: 	while (v->uv_groups) {
  400: 	    a = v->uv_groups;
  401: 	    v->uv_groups = a->al_next;
  402: 
  403: 	    while (a->al_sources) {
  404: 		b = a->al_sources;
  405: 		a->al_sources = a->al_next;
  406: 		free(b);
  407: 	    }
  408: 
  409: 	    free(a);
  410: 	}
  411:     }
  412: 
  413:     /*
  414:      * TODO: inform (eventually) the neighbors I am going down by sending
  415:      * PIM_HELLO with holdtime=0 so someone else should become a DR.
  416:      */
  417:     /* TODO: dummy! Implement it!! Any problems if don't use it? */
  418:     delete_vif_from_mrt(vifi);
  419: 
  420:     /* Delete the interface from the kernel's vif structure. */
  421:     k_del_vif(igmp_socket, vifi, v);
  422: 
  423:     v->uv_flags = (v->uv_flags & ~VIFF_DR & ~VIFF_QUERIER & ~VIFF_NONBRS) | VIFF_DOWN;
  424:     if (!(v->uv_flags & VIFF_REGISTER)) {
  425: 	RESET_TIMER(v->uv_hello_timer);
  426: 	RESET_TIMER(v->uv_jp_timer);
  427: 	RESET_TIMER(v->uv_gq_timer);
  428: 
  429: 	for (n = v->uv_pim_neighbors; n; n = next) {
  430: 	    next = n->next;	/* Free the space for each neighbour */
  431: 	    delete_pim_nbr(n);
  432: 	}
  433: 	v->uv_pim_neighbors = NULL;
  434:     }
  435: 
  436:     /* TODO: currently not used */
  437:    /* The Access Control List (list with the scoped addresses) */
  438:     while (v->uv_acl) {
  439: 	acl = v->uv_acl;
  440: 	v->uv_acl = acl->acl_next;
  441: 	free(acl);
  442:     }
  443: 
  444:     vifs_down = TRUE;
  445:     logit(LOG_INFO, 0, "Interface %s goes down; vif #%u out of service", v->uv_name, vifi);
  446: }
  447: 
  448: 
  449: /*
  450:  * Update the register vif in the multicast routing daemon and the
  451:  * kernel because the interface used initially to get its local address
  452:  * is DOWN. register_vifi is the index to the Register vif which needs
  453:  * to be updated. As a result the Register vif has a new uv_lcl_addr and
  454:  * is UP (virtually :))
  455:  */
  456: static int update_reg_vif(vifi_t register_vifi)
  457: {
  458:     struct uvif *v;
  459:     vifi_t vifi;
  460: 
  461:     /* Find the first useable vif with solid physical background */
  462:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  463: 	if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_TUNNEL))
  464: 	    continue;
  465: 
  466:         /* Found. Stop the bogus Register vif first */
  467: 	stop_vif(register_vifi);
  468: 	uvifs[register_vifi].uv_lcl_addr = uvifs[vifi].uv_lcl_addr;
  469: 
  470: 	start_vif(register_vifi);
  471: 	IF_DEBUG(DEBUG_PIM_REGISTER | DEBUG_IF) {
  472: 	    logit(LOG_NOTICE, 0, "Interface %s has come up; vif #%u now in service",
  473: 		  uvifs[register_vifi].uv_name, register_vifi);
  474: 	}
  475: 
  476: 	return 0;
  477:     }
  478: 
  479:     vifs_down = TRUE;
  480:     logit(LOG_WARNING, 0, "Cannot start Register vif: %s", uvifs[vifi].uv_name);
  481: 
  482:     return -1;
  483: }
  484: 
  485: 
  486: /*
  487:  * See if any interfaces have changed from up state to down, or vice versa,
  488:  * including any non-multicast-capable interfaces that are in use as local
  489:  * tunnel end-points.  Ignore interfaces that have been administratively
  490:  * disabled.
  491:  */
  492: void check_vif_state(void)
  493: {
  494:     vifi_t vifi;
  495:     struct uvif *v;
  496:     struct ifreq ifr;
  497:     static int checking_vifs = 0;
  498: 
  499:     /*
  500:      * XXX: TODO: True only for DVMRP?? Check.
  501:      * If we get an error while checking, (e.g. two interfaces go down
  502:      * at once, and we decide to send a prune out one of the failed ones)
  503:      * then don't go into an infinite loop!
  504:      */
  505:     if (checking_vifs)
  506: 	return;
  507: 
  508:     vifs_down = FALSE;
  509:     checking_vifs = 1;
  510: 
  511:     /* TODO: Check all potential interfaces!!! */
  512:     /* Check the physical and tunnels only */
  513:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  514: 	if (v->uv_flags & (VIFF_DISABLED | VIFF_REGISTER))
  515: 	    continue;
  516: 
  517: 	/* get the interface flags */
  518: 	strlcpy(ifr.ifr_name, v->uv_name, sizeof(ifr.ifr_name));
  519: 	if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0) {
  520:            if (errno == ENODEV) {
  521:               logit(LOG_NOTICE, 0, "Interface %s has gone; vif #%u taken out of service", v->uv_name, vifi);
  522:               stop_vif(vifi);
  523:               vifs_down = TRUE;
  524:               continue;
  525:            }
  526: 
  527: 	   logit(LOG_ERR, errno, "check_vif_state: ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
  528: 	}
  529: 
  530: 	if (v->uv_flags & VIFF_DOWN) {
  531: 	    if (ifr.ifr_flags & IFF_UP)
  532: 		start_vif(vifi);
  533: 	    else
  534: 		vifs_down = TRUE;
  535: 	} else {
  536: 	    if (!(ifr.ifr_flags & IFF_UP)) {
  537: 		logit(LOG_NOTICE, 0, "Interface %s has gone down; vif #%u taken out of service", v->uv_name, vifi);
  538: 		stop_vif(vifi);
  539: 		vifs_down = TRUE;
  540: 	    }
  541: 	}
  542:     }
  543: 
  544:     /* Check the register(s) vif(s) */
  545:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  546: 	vifi_t vifi2;
  547: 	struct uvif *v2;
  548: 	int found;
  549: 
  550: 	if (!(v->uv_flags & VIFF_REGISTER))
  551: 	    continue;
  552: 
  553: 	found = 0;
  554: 
  555: 	/* Find a physical vif with the same IP address as the
  556: 	 * Register vif. */
  557: 	for (vifi2 = 0, v2 = uvifs; vifi2 < numvifs; ++vifi2, ++v2) {
  558: 	    if (v2->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_TUNNEL))
  559: 		continue;
  560: 
  561: 	    if (v->uv_lcl_addr != v2->uv_lcl_addr)
  562: 		continue;
  563: 
  564: 	    found = 1;
  565: 	    break;
  566: 	}
  567: 
  568: 	/* The physical interface with the IP address as the Register
  569: 	 * vif is probably DOWN. Get a replacement. */
  570: 	if (!found)
  571: 	    update_reg_vif(vifi);
  572:     }
  573: 
  574:     checking_vifs = 0;
  575: }
  576: 
  577: 
  578: /*
  579:  * If the source is directly connected to us, find the vif number for
  580:  * the corresponding physical interface (Register and tunnels excluded).
  581:  * Local addresses are excluded.
  582:  * Return the vif number or NO_VIF if not found.
  583:  */
  584: vifi_t find_vif_direct(uint32_t src)
  585: {
  586:     vifi_t vifi;
  587:     struct uvif *v;
  588:     struct phaddr *p;
  589: 
  590:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  591: 	if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_TUNNEL))
  592: 	    continue;
  593: 
  594: 	if (src == v->uv_lcl_addr)
  595: 	    return NO_VIF;	/* src is one of our IP addresses */
  596: 
  597: 	if (is_uv_subnet(src, v))
  598: 	    return vifi;
  599: 
  600: 	/* Check the extra subnets for this vif */
  601: 	/* TODO: don't think currently pimd can handle extra subnets */
  602: 	for (p = v->uv_addrs; p; p = p->pa_next) {
  603: 	    if (is_pa_subnet(src, v))
  604: 		return vifi;
  605: 	}
  606: 
  607: 	/* POINTOPOINT but not VIFF_TUNNEL interface (e.g., GRE) */
  608: 	if ((v->uv_flags & VIFF_POINT_TO_POINT) && (src == v->uv_rmt_addr))
  609: 	    return vifi;
  610:     }
  611: 
  612:     return NO_VIF;
  613: }
  614: 
  615: 
  616: /*
  617:  * Checks if src is local address. If "yes" return the vif index,
  618:  * otherwise return value is NO_VIF.
  619:  */
  620: vifi_t local_address(uint32_t src)
  621: {
  622:     vifi_t vifi;
  623:     struct uvif *v;
  624: 
  625:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  626: 	/* TODO: XXX: what about VIFF_TUNNEL? */
  627: 	if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER))
  628: 	    continue;
  629: 
  630: 	if (src == v->uv_lcl_addr)
  631: 	    return vifi;
  632:     }
  633: 
  634:     /* Returning NO_VIF means not a local address */
  635:     return NO_VIF;
  636: }
  637: 
  638: /*
  639:  * If the source is directly connected, or is local address,
  640:  * find the vif number for the corresponding physical interface
  641:  * (Register and tunnels excluded).
  642:  * Return the vif number or NO_VIF if not found.
  643:  */
  644: vifi_t find_vif_direct_local(uint32_t src)
  645: {
  646:     vifi_t vifi;
  647:     struct uvif *v;
  648:     struct phaddr *p;
  649: 
  650:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  651: 	/* TODO: XXX: what about VIFF_TUNNEL? */
  652: 	if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_TUNNEL))
  653: 	    continue;
  654: 
  655: 	if (src == v->uv_lcl_addr)
  656: 	    return vifi;	/* src is one of our IP addresses */
  657: 
  658: 	if (is_uv_subnet(src, v))
  659: 	    return vifi;
  660: 
  661: 	/* Check the extra subnets for this vif */
  662: 	/* TODO: don't think currently pimd can handle extra subnets */
  663: 	for (p = v->uv_addrs; p; p = p->pa_next) {
  664: 	    if (is_pa_subnet(src, v))
  665: 		return vifi;
  666: 	}
  667: 
  668: 	/* POINTOPOINT but not VIFF_TUNNEL interface (e.g., GRE) */
  669: 	if ((v->uv_flags & VIFF_POINT_TO_POINT) && (src == v->uv_rmt_addr))
  670: 	    return vifi;
  671:     }
  672: 
  673:     return NO_VIF;
  674: }
  675: 
  676: /*
  677:  * Returns the highest address of local vif that is UP and ENABLED.
  678:  * The VIFF_REGISTER interface(s) is/are excluded.
  679:  */
  680: uint32_t max_local_address(void)
  681: {
  682:     vifi_t vifi;
  683:     struct uvif *v;
  684:     uint32_t max_address = 0;
  685: 
  686:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  687: 	/* Count vif if not DISABLED or DOWN */
  688: 	/* TODO: XXX: What about VIFF_TUNNEL? */
  689: 	if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER))
  690: 	    continue;
  691: 
  692: 	if (ntohl(v->uv_lcl_addr) > ntohl(max_address))
  693: 	    max_address = v->uv_lcl_addr;
  694:     }
  695: 
  696:     return max_address;
  697: }
  698: 
  699: /**
  700:  * Local Variables:
  701:  *  version-control: t
  702:  *  indent-tabs-mode: t
  703:  *  c-file-style: "ellemtel"
  704:  *  c-basic-offset: 4
  705:  * End:
  706:  */

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