File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mrouted / rsrr.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:10:48 2012 UTC (12 years, 7 months ago) by misho
Branches: mrouted, MAIN
CVS tags: v3_9_6p0, v3_9_6, v3_9_5, HEAD
mrouted

    1: /*
    2:  * Copyright (c) 1993, 1998-2001.
    3:  * The 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: /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
   32:  * April 1995.
   33:  */
   34: 
   35: /* May 1995 -- Added support for Route Change Notification */
   36: 
   37: #ifdef RSRR
   38: 
   39: #include "defs.h"
   40: #include <sys/param.h>
   41: #ifdef HAVE_SA_LEN
   42: #include <stddef.h>		/* for offsetof */
   43: #endif
   44: 
   45: /* 
   46:  * Local RSRR variables.
   47:  */
   48: static int rsrr_socket;		/* interface to reservation protocol */
   49: static char *rsrr_recv_buf;    	/* RSRR receive buffer */
   50: static char *rsrr_send_buf;    	/* RSRR send buffer */
   51: 
   52: static struct sockaddr_un client_addr;
   53: static socklen_t client_length = sizeof(client_addr);
   54: 
   55: /*
   56:  * Procedure definitions needed internally.
   57:  */
   58: static void	rsrr_accept(size_t recvlen);
   59: static void	rsrr_accept_iq(void);
   60: static int	rsrr_accept_rq(struct rsrr_rq *route_query, u_char flags, struct gtable *gt_notify);
   61: static void	rsrr_read(int, fd_set *);
   62: static int	rsrr_send(int sendlen);
   63: static void	rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query);
   64: 
   65: /* Initialize RSRR socket */
   66: void rsrr_init(void)
   67: {
   68:     int servlen;
   69:     struct sockaddr_un serv_addr;
   70: 
   71:     rsrr_recv_buf = (char *)malloc(RSRR_MAX_LEN);
   72:     rsrr_send_buf = (char *)malloc(RSRR_MAX_LEN);
   73:     if (!rsrr_recv_buf || !rsrr_send_buf)
   74: 	logit(LOG_ERR, 0, "Ran out of memory in rsrr_init()");
   75: 
   76:     if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
   77: 	logit(LOG_ERR, errno, "Cannot create RSRR socket");
   78: 
   79:     unlink(RSRR_SERV_PATH);
   80:     memset(&serv_addr, 0, sizeof(serv_addr));
   81:     serv_addr.sun_family = AF_UNIX;
   82:     strlcpy(serv_addr.sun_path, RSRR_SERV_PATH, sizeof(serv_addr.sun_path));
   83: #ifdef HAVE_SA_LEN
   84:     servlen = offsetof(struct sockaddr_un, sun_path) + strlen(serv_addr.sun_path);
   85:     serv_addr.sun_len = servlen;
   86: #else
   87:     servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
   88: #endif
   89:  
   90:     if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
   91: 	logit(LOG_ERR, errno, "Cannot bind RSRR socket");
   92: 
   93:     if (register_input_handler(rsrr_socket, rsrr_read) < 0)
   94: 	logit(LOG_ERR, 0, "Could not register RSRR as an input handler");
   95: }
   96: 
   97: /* Read a message from the RSRR socket */
   98: static void rsrr_read(int fd, fd_set UNUSED *rfd)
   99: {
  100:     ssize_t rsrr_recvlen;
  101:     
  102:     memset(&client_addr, 0, sizeof(client_addr));
  103:     rsrr_recvlen = recvfrom(fd, rsrr_recv_buf, sizeof(rsrr_recv_buf),
  104: 			    0, (struct sockaddr *)&client_addr, &client_length);
  105:     if (rsrr_recvlen < 0) {	
  106: 	if (errno != EINTR)
  107: 	    logit(LOG_ERR, errno, "RSRR recvfrom");
  108: 	return;
  109:     }
  110:     rsrr_accept(rsrr_recvlen);
  111: }
  112: 
  113: /* Accept a message from the reservation protocol and take
  114:  * appropriate action.
  115:  */
  116: static void rsrr_accept(size_t recvlen)
  117: {
  118:     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_recv_buf;
  119:     struct rsrr_rq *route_query;
  120:     
  121:     if (recvlen < RSRR_HEADER_LEN) {
  122: 	logit(LOG_WARNING, 0, "Received RSRR packet of %d bytes, which is less than MIN size %d.",
  123: 	      recvlen, RSRR_HEADER_LEN);
  124: 	return;
  125:     }
  126:     
  127:     if (rsrr->version > RSRR_MAX_VERSION || rsrr->version != 1) {
  128: 	logit(LOG_WARNING, 0, "Received RSRR packet version %d, which I don't understand",
  129: 	      rsrr->version);
  130: 	return;
  131:     }
  132: 
  133:     switch (rsrr->type) {
  134: 	case RSRR_INITIAL_QUERY:
  135: 	    /* Send Initial Reply to client */
  136: 	    IF_DEBUG(DEBUG_RSRR) {
  137: 		logit(LOG_DEBUG, 0, "Received Initial Query\n");
  138: 	    }
  139: 	    rsrr_accept_iq();
  140: 	    break;
  141: 
  142: 	case RSRR_ROUTE_QUERY:
  143: 	    /* Check size */
  144: 	    if (recvlen < RSRR_RQ_LEN) {
  145: 		logit(LOG_WARNING, 0, "Received Route Query of %d bytes, which is too small", recvlen);
  146: 		break;
  147: 	    }
  148: 	    /* Get the query */
  149: 	    route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
  150: 	    IF_DEBUG(DEBUG_RSRR) {
  151: 		logit(LOG_DEBUG, 0,
  152: 		      "Received Route Query for src %s grp %s notification %d",
  153: 		      inet_fmt(route_query->source_addr.s_addr, s1, sizeof(s1)),
  154: 		      inet_fmt(route_query->dest_addr.s_addr, s2, sizeof(s2)),
  155: 		      BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
  156: 	    }
  157: 	    /* Send Route Reply to client */
  158: 	    rsrr_accept_rq(route_query, rsrr->flags, NULL);
  159: 	    break;
  160: 
  161: 	default:
  162: 	    logit(LOG_WARNING, 0, "Received RSRR packet type %d, which I don't handle", rsrr->type);
  163: 	    break;
  164:     }
  165: }
  166: 
  167: /* Send an Initial Reply to the reservation protocol. */
  168: static void rsrr_accept_iq(void)
  169: {
  170:     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
  171:     struct rsrr_vif *vif_list;
  172:     struct uvif *v;
  173:     int vifi, sendlen;
  174:     
  175:     /* Check for space.  There should be room for plenty of vifs,
  176:      * but we should check anyway.
  177:      */
  178:     if (numvifs > RSRR_MAX_VIFS) {
  179: 	logit(LOG_WARNING, 0,
  180: 	    "Cannot send RSRR Route Reply because %d is too many vifs %d",
  181: 	    numvifs);
  182: 	return;
  183:     }
  184:     
  185:     /* Set up message */
  186:     rsrr->version = 1;
  187:     rsrr->type = RSRR_INITIAL_REPLY;
  188:     rsrr->flags = 0;
  189:     rsrr->num = numvifs;
  190:     
  191:     vif_list = (struct rsrr_vif *)(rsrr_send_buf + RSRR_HEADER_LEN);
  192:     
  193:     /* Include the vif list. */
  194:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
  195: 	vif_list[vifi].id = vifi;
  196: 	vif_list[vifi].status = 0;
  197: 	if (v->uv_flags & VIFF_DISABLED)
  198: 	    BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
  199: 	vif_list[vifi].threshold = v->uv_threshold;
  200: 	vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
  201:     }
  202:     
  203:     /* Get the size. */
  204:     sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
  205:     
  206:     /* Send it. */
  207:     IF_DEBUG(DEBUG_RSRR) {
  208: 	logit(LOG_DEBUG, 0, "Send RSRR Initial Reply");
  209:     }
  210:     rsrr_send(sendlen);
  211: }
  212: 
  213: /* Send a Route Reply to the reservation protocol.  The Route Query
  214:  * contains the query to which we are responding.  The flags contain
  215:  * the incoming flags from the query or, for route change
  216:  * notification, the flags that should be set for the reply.  The
  217:  * kernel table entry contains the routing info to use for a route
  218:  * change notification.
  219:  */
  220: /* XXX: must modify if your routing table structure/search is different */
  221: static int rsrr_accept_rq(struct rsrr_rq *route_query, u_char flags, struct gtable *gt_notify)
  222: {
  223:     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
  224:     struct rsrr_rr *route_reply;
  225:     struct gtable *gt,local_g;
  226:     struct rtentry *r;
  227:     int sendlen;
  228:     u_long mcastgrp;
  229:     
  230:     /* Set up message */
  231:     rsrr->version = 1;
  232:     rsrr->type = RSRR_ROUTE_REPLY;
  233:     rsrr->flags = 0;
  234:     rsrr->num = 0;
  235:     
  236:     route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
  237:     route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
  238:     route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
  239:     route_reply->query_id = route_query->query_id;
  240:     
  241:     /* Blank routing entry for error. */
  242:     route_reply->in_vif = 0;
  243:     route_reply->reserved = 0;
  244:     route_reply->out_vif_bm = 0;
  245:     
  246:     /* Get the size. */
  247:     sendlen = RSRR_RR_LEN;
  248: 
  249:     /* If kernel table entry is defined, then we are sending a Route Reply
  250:      * due to a Route Change Notification event.  Use the kernel table entry
  251:      * to supply the routing info.
  252:      */
  253:     if (gt_notify) {
  254: 	/* Set flags */
  255: 	rsrr->flags = flags;
  256: 	/* Include the routing entry. */
  257: 	route_reply->in_vif = gt_notify->gt_route->rt_parent;
  258: 	if (BIT_TST(flags,RSRR_NOTIFICATION_BIT))
  259: 	    route_reply->out_vif_bm = gt_notify->gt_grpmems;
  260: 	else
  261: 	    route_reply->out_vif_bm = 0;
  262:     } else if (find_src_grp(route_query->source_addr.s_addr, 0,
  263: 			    route_query->dest_addr.s_addr)) {
  264: 
  265: 	/* Found kernel entry. Code taken from add_table_entry() */
  266: 	gt = gtp ? gtp->gt_gnext : kernel_table;
  267: 	
  268: 	/* Include the routing entry. */
  269: 	route_reply->in_vif = gt->gt_route->rt_parent;
  270: 	route_reply->out_vif_bm = gt->gt_grpmems;
  271: 
  272: 	/* Cache reply if using route change notification. */
  273: 	if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) {
  274: 	    /* TODO: XXX: Originally the rsrr_cache() call was first, but
  275: 	     * I think this is incorrect, because rsrr_cache() checks the
  276: 	     * rsrr_send_buf "flag" first.
  277: 	     */
  278: 	    BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT);
  279: 	    rsrr_cache(gt, route_query);
  280: 	}
  281:     } else {
  282: 	/* No kernel entry; use routing table. */
  283: 	r = determine_route(route_query->source_addr.s_addr);
  284: 	
  285: 	if (r != NULL) {
  286: 	    /* We need to mimic what will happen if a data packet
  287: 	     * is forwarded by multicast routing -- the kernel will
  288: 	     * make an upcall and mrouted will install a route in the kernel.
  289: 	     * Our outgoing vif bitmap should reflect what that table
  290: 	     * will look like.  Grab code from add_table_entry().
  291: 	     * This is gross, but it's probably better to be accurate.
  292: 	     */
  293: 	    
  294: 	    gt = &local_g;
  295: 	    mcastgrp = route_query->dest_addr.s_addr;
  296: 	    
  297: 	    gt->gt_mcastgrp    	= mcastgrp;
  298: 	    gt->gt_grpmems	= 0;
  299: 	    gt->gt_scope	= 0;
  300: 	    gt->gt_route        = r;
  301: 	    
  302: 	    /* obtain the multicast group membership list */
  303: 	    determine_forwvifs(gt);
  304: 	    
  305: 	    /* Include the routing entry. */
  306: 	    route_reply->in_vif = gt->gt_route->rt_parent;
  307: 	    route_reply->out_vif_bm = gt->gt_grpmems;
  308: 	} else {
  309: 	    /* Set error bit. */
  310: 	    BIT_SET(rsrr->flags, RSRR_ERROR_BIT);
  311: 	}
  312:     }
  313:     
  314:     IF_DEBUG(DEBUG_RSRR) {
  315: 	logit(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vif %d\n",
  316: 	      gt_notify ? "Route Change: " : "",
  317: 	      inet_fmt(route_reply->source_addr.s_addr, s1, sizeof(s1)),
  318: 	      inet_fmt(route_reply->dest_addr.s_addr, s2, sizeof(s2)),
  319: 	      route_reply->in_vif,route_reply->out_vif_bm);
  320:     }
  321: 
  322:     /* Send it. */
  323:     return rsrr_send(sendlen);
  324: }
  325: 
  326: /* Send an RSRR message. */
  327: static int rsrr_send(int sendlen)
  328: {
  329:     int error;
  330:     
  331:     /* Send it. */
  332:     error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
  333: 		   (struct sockaddr *)&client_addr, client_length);
  334:     
  335:     /* Check for errors. */
  336:     if (error < 0) {
  337: 	logit(LOG_WARNING, errno, "Failed send on RSRR socket");
  338:     } else if (error != sendlen) {
  339: 	logit(LOG_WARNING, 0,
  340: 	    "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
  341:     }
  342:     return error;
  343: }
  344: 
  345: /* TODO: need to sort the rsrr_cache entries for faster access */
  346: /* Cache a message being sent to a client.  Currently only used for
  347:  * caching Route Reply messages for route change notification.
  348:  */
  349: static void rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query)
  350: {
  351:     struct rsrr_cache *rc, **rcnp;
  352:     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
  353: 
  354:     rcnp = &gt->gt_rsrr_cache;
  355:     while ((rc = *rcnp) != NULL) {
  356: 	if ((rc->route_query.source_addr.s_addr == 
  357: 	     route_query->source_addr.s_addr) &&
  358: 	    (rc->route_query.dest_addr.s_addr == 
  359: 	     route_query->dest_addr.s_addr) &&
  360: 	    (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
  361: 	    /* Cache entry already exists.
  362: 	     * Check if route notification bit has been cleared.
  363: 	     */
  364: 	    if (!BIT_TST(rsrr->flags, RSRR_NOTIFICATION_BIT)) {
  365: 		/* Delete cache entry. */
  366: 		*rcnp = rc->next;
  367: 		free(rc);
  368: 	    } else {
  369: 		/* Update */
  370: 		/* TODO: XXX: No need to update iif, oifs, flags */
  371: 		rc->route_query.query_id = route_query->query_id;
  372: 		IF_DEBUG(DEBUG_RSRR) {
  373: 		    logit(LOG_DEBUG, 0,
  374: 			  "Update cached query id %ld from client %s\n",
  375: 			  rc->route_query.query_id, rc->client_addr.sun_path);
  376: 		}
  377: 	    }
  378: 	    return;
  379: 	}
  380: 	rcnp = &rc->next;
  381:     }
  382: 
  383:     /* Cache entry doesn't already exist.  Create one and insert at
  384:      * front of list.
  385:      */
  386:     rc = (struct rsrr_cache *)malloc(sizeof(struct rsrr_cache));
  387:     if (rc == NULL)
  388: 	logit(LOG_ERR, 0, "Ran out of memory in rsrr_cache()");
  389: 
  390:     rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
  391:     rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
  392:     rc->route_query.query_id = route_query->query_id;
  393:     strlcpy(rc->client_addr.sun_path, client_addr.sun_path, sizeof(rc->client_addr.sun_path));
  394:     rc->client_length = client_length;
  395:     rc->next = gt->gt_rsrr_cache;
  396:     gt->gt_rsrr_cache = rc;
  397:     IF_DEBUG(DEBUG_RSRR) {
  398: 	logit(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
  399: 	      rc->route_query.query_id, rc->client_addr.sun_path);
  400:     }
  401: }
  402: 
  403: /* Send all the messages in the cache for particular routing entry.
  404:  * Currently this is used to send all the cached Route Reply messages
  405:  * for route change notification.
  406:  */
  407: void rsrr_cache_send(struct gtable *gt, int notify)
  408: {
  409:     struct rsrr_cache *rc, **rcnp;
  410:     u_char flags = 0;
  411: 
  412:     if (notify) {
  413: 	BIT_SET(flags, RSRR_NOTIFICATION_BIT);
  414:     }
  415: 
  416:     rcnp = &gt->gt_rsrr_cache;
  417:     while ((rc = *rcnp) != NULL) {
  418: 	if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) {
  419: 	    IF_DEBUG(DEBUG_RSRR) {
  420: 		logit(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
  421: 		      rc->route_query.query_id,rc->client_addr.sun_path);
  422: 	    }
  423: 	    /* Delete cache entry. */
  424: 	    *rcnp = rc->next;
  425: 	    free(rc);
  426: 	} else {
  427: 	    rcnp = &rc->next;
  428: 	}
  429:     }
  430: }
  431: 
  432: /* Clean the cache by deleting all entries. */
  433: void rsrr_cache_clean(struct gtable *gt)
  434: {
  435:     struct rsrr_cache *rc, *rc_next;
  436: 
  437:     IF_DEBUG(DEBUG_RSRR) {
  438: 	logit(LOG_DEBUG, 0, "cleaning cache for group %s\n",
  439: 	      inet_fmt(gt->gt_mcastgrp, s1, sizeof(s1)));
  440:     }
  441:     rc = gt->gt_rsrr_cache;
  442:     while (rc) {
  443: 	rc_next = rc->next;
  444: 	free(rc);
  445: 	rc = rc_next;
  446:     }
  447:     gt->gt_rsrr_cache = NULL;
  448: }
  449: 
  450: void rsrr_clean(void)
  451: {
  452:     unlink(RSRR_SERV_PATH);
  453: }
  454: 
  455: #endif /* RSRR */
  456: 
  457: /**
  458:  * Local Variables:
  459:  *  version-control: t
  460:  *  indent-tabs-mode: t
  461:  *  c-file-style: "ellemtel"
  462:  *  c-basic-offset: 4
  463:  * End:
  464:  */

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