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