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