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