Annotation of embedaddon/mrouted/rsrr.c, revision 1.1
1.1 ! misho 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_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_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>