File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimdd / rsrr.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) 1993, 1998 by the University of Southern California
    3:  * All rights reserved.
    4:  *
    5:  * Permission to use, copy, modify, and distribute this software and its
    6:  * documentation in source and binary forms for lawful purposes
    7:  * and without fee is hereby granted, provided that the above copyright
    8:  * notice appear in all copies and that both the copyright notice and
    9:  * this permission notice appear in supporting documentation. and that
   10:  * any documentation, advertising materials, and other materials related
   11:  * to such distribution and use acknowledge that the software was
   12:  * developed by the University of Southern California, Information
   13:  * Sciences Institute.  The name of the University may not be used to
   14:  * endorse or promote products derived from this software without
   15:  * specific prior written permission.
   16:  *
   17:  * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
   18:  * the suitability of this software for any purpose.  THIS SOFTWARE IS
   19:  * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
   20:  * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
   21:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   22:  *
   23:  * Other copyrights might apply to parts of this software and are so
   24:  * noted when applicable.
   25:  */
   26: 
   27: /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
   28:  * April 1995.
   29:  *
   30:  * Modified by Kurtw Windisch (kurtw@antc.uoregon.edu) for use with 
   31:  * Dense-mode pimd.
   32:  */
   33: 
   34: /* May 1995 -- Added support for Route Change Notification */
   35: 
   36: #ifdef RSRR
   37: 
   38: #include "defs.h"
   39: #include <sys/param.h>
   40: #if (defined(BSD) && (BSD >= 199103))
   41: #include <stddef.h>
   42: #endif
   43: 
   44: 
   45: /*
   46:  * Exported variables.
   47:  */
   48: int rsrr_socket;		/* interface to reservation protocol */
   49: 
   50: /* 
   51:  * Global RSRR variables.
   52:  */
   53: char *rsrr_recv_buf;    	/* RSRR receive buffer */
   54: char *rsrr_send_buf;    	/* RSRR send buffer */
   55: 
   56: struct sockaddr_un client_addr;
   57: int client_length = sizeof(client_addr);
   58: 
   59: 
   60: /*
   61:  * Local functions definition
   62:  */
   63: static void	rsrr_accept    __P((int recvlen));
   64: static void	rsrr_accept_iq __P((void));
   65: static int	rsrr_accept_rq __P((struct rsrr_rq *route_query, u_int8 flags,
   66: 				    struct gtable *gt_notify));
   67: static void	rsrr_read      __P((int, fd_set *));
   68: static int	rsrr_send      __P((int sendlen));
   69: static void	rsrr_cache     __P((struct gtable *gt,
   70: 					struct rsrr_rq *route_query));
   71: 
   72: /* Initialize RSRR socket */
   73: void
   74: rsrr_init()
   75: {
   76:     int servlen;
   77:     struct sockaddr_un serv_addr;
   78: 
   79:     rsrr_recv_buf = malloc(RSRR_MAX_LEN);
   80:     rsrr_send_buf = malloc(RSRR_MAX_LEN);
   81: 
   82:     if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
   83: 	log(LOG_ERR, errno, "Can't create RSRR socket");
   84: 
   85:     unlink(RSRR_SERV_PATH);
   86:     bzero((char *) &serv_addr, sizeof(serv_addr));
   87:     serv_addr.sun_family = AF_UNIX;
   88:     strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
   89: #if (defined(BSD) && (BSD >= 199103))
   90:     servlen = offsetof(struct sockaddr_un, sun_path) +
   91: 		strlen(serv_addr.sun_path);
   92:     serv_addr.sun_len = servlen;
   93: #else
   94:     servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
   95: #endif
   96:  
   97:     if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
   98: 	log(LOG_ERR, errno, "Can't bind RSRR socket");
   99: 
  100:     if (register_input_handler(rsrr_socket, rsrr_read) < 0)
  101: 	log(LOG_ERR, 0, "Couldn't register RSRR as an input handler");
  102: }
  103: 
  104: /* Read a message from the RSRR socket */
  105: static void
  106: rsrr_read(f, rfd)
  107: 	int f;
  108: 	fd_set *rfd;
  109: {
  110:     register int rsrr_recvlen;
  111:     
  112:     bzero((char *) &client_addr, sizeof(client_addr));
  113:     rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
  114: 			    0, (struct sockaddr *)&client_addr,
  115: 			    &client_length);
  116:     if (rsrr_recvlen < 0) {	
  117: 	if (errno != EINTR)
  118: 	    log(LOG_ERR, errno, "RSRR recvfrom");
  119: 	return;
  120:     }
  121:     rsrr_accept(rsrr_recvlen);
  122: }
  123: 
  124: /*
  125:  * Accept a message from the reservation protocol and take
  126:  * appropriate action.
  127:  */
  128: static void
  129: rsrr_accept(recvlen)
  130:     int recvlen;
  131: {
  132:     struct rsrr_header *rsrr;
  133:     struct rsrr_rq *route_query;
  134:     
  135:     if (recvlen < RSRR_HEADER_LEN) {
  136: 	log(LOG_WARNING, 0,
  137: 	    "Received RSRR packet of %d bytes, which is less than min size",
  138: 	    recvlen);
  139: 	return;
  140:     }
  141:     
  142:     rsrr = (struct rsrr_header *) rsrr_recv_buf;
  143:     
  144:     if (rsrr->version > RSRR_MAX_VERSION) {
  145: 	log(LOG_WARNING, 0,
  146: 	    "Received RSRR packet version %d, which I don't understand",
  147: 	    rsrr->version);
  148: 	return;
  149:     }
  150:     
  151:     switch (rsrr->version) {
  152:       case 1:
  153: 	switch (rsrr->type) {
  154: 	  case RSRR_INITIAL_QUERY:
  155: 	    /* Send Initial Reply to client */
  156: 	    IF_DEBUG(DEBUG_RSRR)
  157: 		log(LOG_DEBUG, 0, "Received Initial Query\n");
  158: 	    rsrr_accept_iq();
  159: 	    break;
  160: 	  case RSRR_ROUTE_QUERY:
  161: 	    /* Check size */
  162: 	    if (recvlen < RSRR_RQ_LEN) {
  163: 		log(LOG_WARNING, 0,
  164: 		    "Received Route Query of %d bytes, which is too small",
  165: 		    recvlen);
  166: 		break;
  167: 	    }
  168: 	    /* Get the query */
  169: 	    route_query =
  170: 		(struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
  171: 	    IF_DEBUG(DEBUG_RSRR)
  172: 		log(LOG_DEBUG, 0,
  173: 		    "Received Route Query for src %s grp %s notification %d",
  174: 		    inet_fmt(route_query->source_addr, s1),
  175: 		    inet_fmt(route_query->dest_addr, s2),
  176: 		    BIT_TST(rsrr->flags, RSRR_NOTIFICATION_BIT));
  177: 	    /* Send Route Reply to client */
  178: 	    rsrr_accept_rq(route_query, rsrr->flags, (struct gtable *)NULL);
  179: 	    break;
  180: 	  default:
  181: 	    log(LOG_WARNING, 0,
  182: 		"Received RSRR packet type %d, which I don't handle",
  183: 		rsrr->type);
  184: 	    break;
  185: 	}
  186: 	break;
  187: 	
  188:       default:
  189: 	log(LOG_WARNING, 0,
  190: 	    "Received RSRR packet version %d, which I don't understand",
  191: 	    rsrr->version);
  192: 	break;
  193:     }
  194: }
  195: 
  196: /* Send an Initial Reply to the reservation protocol. */
  197: /*
  198:  * TODO: XXX: if a new interfaces come up and _IF_ the multicast routing
  199:  * daemon automatically include it, have to inform the RSVP daemon.
  200:  * However, this is not in the RSRRv1 draft (just expired and is not
  201:  * available anymore from the internet-draft ftp sites). Probably has to
  202:  * be included in RSRRv2.
  203:  */
  204: static void
  205: rsrr_accept_iq()
  206: {
  207:     struct rsrr_header *rsrr;
  208:     struct rsrr_vif *vif_list;
  209:     struct uvif *v;
  210:     vifi_t vifi;
  211:     int sendlen;
  212:     
  213:     /* Check for space.  There should be room for plenty of vifs,
  214:      * but we should check anyway.
  215:      */
  216:     if (numvifs > RSRR_MAX_VIFS) {
  217: 	log(LOG_WARNING, 0,
  218: 	    "Can't send RSRR Route Reply because %d is too many vifs %d",
  219: 	    numvifs);
  220: 	return;
  221:     }
  222:     
  223:     /* Set up message */
  224:     rsrr = (struct rsrr_header *) rsrr_send_buf;
  225:     rsrr->version = 1;
  226:     rsrr->type = RSRR_INITIAL_REPLY;
  227:     rsrr->flags = 0;
  228:     rsrr->num = numvifs;
  229:     
  230:     vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
  231:     
  232:     /* Include the vif list. */
  233:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
  234: 	vif_list[vifi].id = vifi;
  235: 	vif_list[vifi].status = 0;
  236: 	if (v->uv_flags & (VIFF_DISABLED))
  237: 	    BIT_SET(vif_list[vifi].status, RSRR_DISABLED_BIT);
  238: 	vif_list[vifi].threshold = v->uv_threshold;
  239: 	vif_list[vifi].local_addr = v->uv_lcl_addr;
  240:     }
  241:     
  242:     /* Get the size. */
  243:     sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
  244:     
  245:     /* Send it. */
  246:     IF_DEBUG(DEBUG_RSRR)
  247: 	log(LOG_DEBUG, 0, "Send RSRR Initial Reply");
  248:     rsrr_send(sendlen);
  249: }
  250: 
  251: /* Send a Route Reply to the reservation protocol.  The Route Query
  252:  * contains the query to which we are responding.  The flags contain
  253:  * the incoming flags from the query or, for route change
  254:  * notification, the flags that should be set for the reply.  The
  255:  * kernel table entry contains the routing info to use for a route
  256:  * change notification.
  257:  */
  258: /* XXX: must modify if your routing table structure/search is different */
  259: static int
  260: rsrr_accept_rq(route_query, flags, gt_notify)
  261:     struct rsrr_rq *route_query;
  262:     u_int8 flags;
  263:     struct gtable *gt_notify;
  264: {
  265:     struct rsrr_header *rsrr;
  266:     struct rsrr_rr *route_reply;
  267:     int sendlen;
  268:     struct gtable *gt;
  269:     int status_ok;
  270:     
  271:     /* Set up message */
  272:     rsrr = (struct rsrr_header *) rsrr_send_buf;
  273:     rsrr->version = 1;
  274:     rsrr->type = RSRR_ROUTE_REPLY;
  275:     rsrr->flags = flags;
  276:     rsrr->num = 0;
  277:     
  278:     route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
  279:     route_reply->dest_addr = route_query->dest_addr;
  280:     route_reply->source_addr = route_query->source_addr;
  281:     route_reply->query_id = route_query->query_id;
  282:     
  283:     /* Blank routing entry for error. */
  284:     route_reply->in_vif = 0;
  285:     route_reply->reserved = 0;
  286:     route_reply->out_vif_bm = 0;
  287:     
  288:     /* Get the size. */
  289:     sendlen = RSRR_RR_LEN;
  290:     
  291:     /* If routing table entry is defined, then we are sending a Route Reply
  292:      * due to a Route Change Notification event.  Use the routing table entry
  293:      * to supply the routing info.
  294:      */
  295:     status_ok = FALSE;
  296:     if (gt_notify) {
  297: 	/* Include the routing entry. */
  298: 	route_reply->in_vif = gt_notify->incoming;
  299: 	route_reply->out_vif_bm = gt_notify->oifs;
  300: 	gt = gt_notify;
  301: 	status_ok = TRUE;
  302:     } else if ((gt = find_route(route_query->source_addr,
  303: 				route_query->dest_addr,
  304: 				MRTF_SG | MRTF_WC | MRTF_PMBR,
  305: 				DONT_CREATE)) != (struct gtable *)NULL) {
  306: 	status_ok = TRUE;
  307: 	route_reply->in_vif = gt->incoming;
  308: 	route_reply->out_vif_bm = gt->oifs;
  309:     }
  310:     if (status_ok != TRUE) {
  311: 	/* Set error bit. */
  312: 	rsrr->flags = 0;
  313: 	BIT_SET(rsrr->flags, RSRR_ERROR_BIT);
  314:     }
  315:     else {
  316: 	/* Cache reply if using route change notification. */
  317: 	if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) {
  318: 	    /* TODO: XXX: Originally the rsrr_cache() call was first, but
  319: 	     * I think this is incorrect, because rsrr_cache() checks the
  320: 	     * rsrr_send_buf "flag" first.
  321: 	     */
  322: 	    BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT);
  323: 	    rsrr_cache(gt, route_query);
  324: 	}
  325:     }
  326:     
  327:     IF_DEBUG(DEBUG_RSRR)
  328: 	log(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vifs 0x%x\n",
  329: 	    gt_notify ? "Route Change: " : "",
  330: 	    inet_fmt(route_reply->source_addr,s1),
  331: 	    inet_fmt(route_reply->dest_addr,s2),
  332: 	    route_reply->in_vif, route_reply->out_vif_bm);
  333:     
  334:     /* Send it. */
  335:     return rsrr_send(sendlen);
  336: }
  337: 
  338: /* Send an RSRR message. */
  339: static int
  340: rsrr_send(sendlen)
  341:     int sendlen;
  342: {
  343:     int error;
  344:     
  345:     /* Send it. */
  346:     error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
  347: 		   (struct sockaddr *)&client_addr, client_length);
  348:     
  349:     /* Check for errors. */
  350:     if (error < 0) {
  351: 	log(LOG_WARNING, errno, "Failed send on RSRR socket");
  352:     } else if (error != sendlen) {
  353: 	log(LOG_WARNING, 0,
  354: 	    "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
  355:     }
  356:     return error;
  357: }
  358: 
  359: /* TODO: need to sort the rsrr_cache entries for faster access */
  360: /* Cache a message being sent to a client.  Currently only used for
  361:  * caching Route Reply messages for route change notification.
  362:  */
  363: static void
  364: rsrr_cache(gt, route_query)
  365:     struct gtable *gt;
  366:     struct rsrr_rq *route_query;
  367: {
  368:     struct rsrr_cache *rc, **rcnp;
  369:     struct rsrr_header *rsrr;
  370: 
  371:     rsrr = (struct rsrr_header *) rsrr_send_buf;
  372: 
  373:     rcnp = &gt->rsrr_cache;
  374:     while ((rc = *rcnp) != NULL) {
  375: 	if ((rc->route_query.source_addr == 
  376: 	     route_query->source_addr) &&
  377: 	    (rc->route_query.dest_addr == 
  378: 	     route_query->dest_addr) &&
  379: 	    (!strcmp(rc->client_addr.sun_path, client_addr.sun_path))) {
  380: 	    /* Cache entry already exists.
  381: 	     * Check if route notification bit has been cleared.
  382: 	     */
  383: 	    if (!BIT_TST(rsrr->flags, RSRR_NOTIFICATION_BIT)) {
  384: 		/* Delete cache entry. */
  385: 		*rcnp = rc->next;
  386: 		free(rc);
  387: 	    } else {
  388: 		/* Update */
  389: 		/* TODO: XXX: No need to update iif, oifs, flags */
  390: 		rc->route_query.query_id = route_query->query_id;
  391: 		IF_DEBUG(DEBUG_RSRR)
  392: 		    log(LOG_DEBUG, 0,
  393: 			"Update cached query id %ld from client %s\n",
  394: 			rc->route_query.query_id, rc->client_addr.sun_path);
  395: 	    }
  396: 	    return;
  397: 	}
  398: 	rcnp = &rc->next;
  399:     }
  400:     
  401:     /* Cache entry doesn't already exist.  Create one and insert at
  402:      * front of list.
  403:      */
  404:     rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
  405:     if (rc == NULL)
  406: 	log(LOG_ERR, 0, "ran out of memory");
  407:     rc->route_query.source_addr = route_query->source_addr;
  408:     rc->route_query.dest_addr = route_query->dest_addr;
  409:     rc->route_query.query_id = route_query->query_id;
  410:     strcpy(rc->client_addr.sun_path, client_addr.sun_path);
  411:     rc->client_length = client_length;
  412:     rc->next = gt->rsrr_cache;
  413:     gt->rsrr_cache = rc;
  414:     IF_DEBUG(DEBUG_RSRR)
  415: 	log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
  416: 	    rc->route_query.query_id, rc->client_addr.sun_path);
  417: }
  418: 
  419: /* Send all the messages in the cache for particular routing entry.
  420:  * Currently this is used to send all the cached Route Reply messages
  421:  * for route change notification.
  422:  */
  423: void
  424: rsrr_cache_send(gt, notify)
  425:     struct gtable *gt;
  426:     int notify;
  427: {
  428:     struct rsrr_cache *rc, **rcnp;
  429:     u_int8 flags = 0;
  430: 
  431:     if (notify)
  432: 	BIT_SET(flags, RSRR_NOTIFICATION_BIT);
  433: 
  434:     rcnp = &gt->rsrr_cache;
  435: 
  436:     while ((rc = *rcnp) != NULL) {
  437: 	if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) {
  438: 	    IF_DEBUG(DEBUG_RSRR)
  439: 		log(LOG_DEBUG, 0,
  440: 		    "Deleting cached query id %ld from client %s\n",
  441: 		    rc->route_query.query_id, rc->client_addr.sun_path);
  442: 	    /* Delete cache entry. */
  443: 	    *rcnp = rc->next;
  444: 	    free(rc);
  445: 	} else {
  446: 	    rcnp = &rc->next;
  447: 	}
  448:     }
  449: }
  450: 
  451: /* Clean the cache by deleting or moving all entries. */
  452: /* XXX: for PIM, if the routing entry is (S,G), will try first to
  453:  * "transfer" the RSRR cache entry to the (*,G) or (*,*,RP) routing entry
  454:  * (if any). If the current routing entry is (*,G), it will move the
  455:  * cache entries to the (*,*,RP) routing entry (if existing).
  456:  * If the old and the new (iif, oifs) are the same, then no need to send
  457:  * route change message to the reservation daemon: just plug all entries at
  458:  * the front of the rsrr_cache chain.
  459:  */
  460: void
  461: rsrr_cache_clean(gt)
  462:     struct gtable *gt;
  463: {
  464:     struct rsrr_cache *rc, *rc_next;
  465: 
  466:     IF_DEBUG(DEBUG_RSRR) {
  467: 	log(LOG_DEBUG, 0, "cleaning cache for source %s and group %s",
  468: 	    inet_fmt(gt->source->address, s1),
  469: 	    inet_fmt(gt->group->group, s2));
  470:     }
  471:     rc = gt->rsrr_cache;
  472:     if (rc == (struct rsrr_cache *)NULL)
  473: 	return;
  474: 
  475:     while(rc) {
  476:         rc_next = rc->next;
  477:         free(rc);
  478:         rc = rc_next;
  479:      }
  480: 
  481:     gt->rsrr_cache = (struct rsrr_cache *)NULL;
  482: }
  483: 
  484: void
  485: rsrr_clean()
  486: {
  487:     unlink(RSRR_SERV_PATH);
  488: }
  489: 
  490: #endif /* RSRR */

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