Annotation of embedaddon/pimd/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, uint8_t 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 *)calloc(1, RSRR_MAX_LEN);
! 72: rsrr_send_buf = (char *)calloc(1, 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 *rfd __attribute__ ((unused)))
! 99: {
! 100: ssize_t len;
! 101:
! 102: memset(&client_addr, 0, sizeof(client_addr));
! 103: while ((len = recvfrom(fd, rsrr_recv_buf, sizeof(rsrr_recv_buf),
! 104: 0, (struct sockaddr *)&client_addr, &client_length)) < 0) {
! 105: if (errno == EINTR)
! 106: continue; /* Received signal, retry syscall. */
! 107:
! 108: logit(LOG_ERR, errno, "Failed recvfrom() in rsrr_read()");
! 109: return;
! 110: }
! 111:
! 112: rsrr_accept(len);
! 113: }
! 114:
! 115: /* Accept a message from the reservation protocol and take
! 116: * appropriate action.
! 117: */
! 118: static void rsrr_accept(size_t recvlen)
! 119: {
! 120: struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_recv_buf;
! 121: struct rsrr_rq *route_query;
! 122:
! 123: if (recvlen < RSRR_HEADER_LEN) {
! 124: logit(LOG_WARNING, 0, "Received RSRR packet of %d bytes, which is less than MIN size %d.",
! 125: recvlen, RSRR_HEADER_LEN);
! 126: return;
! 127: }
! 128:
! 129: if (rsrr->version > RSRR_MAX_VERSION || rsrr->version != 1) {
! 130: logit(LOG_WARNING, 0, "Received RSRR packet version %d, which I don't understand",
! 131: rsrr->version);
! 132: return;
! 133: }
! 134:
! 135: switch (rsrr->type) {
! 136: case RSRR_INITIAL_QUERY:
! 137: /* Send Initial Reply to client */
! 138: IF_DEBUG(DEBUG_RSRR) {
! 139: logit(LOG_DEBUG, 0, "Received Initial Query\n");
! 140: }
! 141: rsrr_accept_iq();
! 142: break;
! 143:
! 144: case RSRR_ROUTE_QUERY:
! 145: /* Check size */
! 146: if (recvlen < RSRR_RQ_LEN) {
! 147: logit(LOG_WARNING, 0, "Received Route Query of %d bytes, which is too small", recvlen);
! 148: break;
! 149: }
! 150: /* Get the query */
! 151: route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
! 152: IF_DEBUG(DEBUG_RSRR) {
! 153: logit(LOG_DEBUG, 0,
! 154: "Received Route Query for src %s grp %s notification %d",
! 155: inet_fmt(route_query->source_addr, s1, sizeof(s1)),
! 156: inet_fmt(route_query->dest_addr, s2, sizeof(s2)),
! 157: BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
! 158: }
! 159: /* Send Route Reply to client */
! 160: rsrr_accept_rq(route_query, rsrr->flags, NULL);
! 161: break;
! 162:
! 163: default:
! 164: logit(LOG_WARNING, 0, "Received RSRR packet type %d, which I don't handle", rsrr->type);
! 165: break;
! 166: }
! 167: }
! 168:
! 169: /* Send an Initial Reply to the reservation protocol. */
! 170: /*
! 171: * TODO: XXX: if a new interfaces come up and _IF_ the multicast routing
! 172: * daemon automatically include it, have to inform the RSVP daemon.
! 173: * However, this is not in the RSRRv1 draft (just expired and is not
! 174: * available anymore from the internet-draft ftp sites). Probably has to
! 175: * be included in RSRRv2.
! 176: */
! 177: static void rsrr_accept_iq(void)
! 178: {
! 179: struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
! 180: struct rsrr_vif *vif_list;
! 181: struct uvif *v;
! 182: vifi_t vifi;
! 183: int sendlen;
! 184:
! 185: /* Check for space. There should be room for plenty of vifs,
! 186: * but we should check anyway.
! 187: */
! 188: if (numvifs > RSRR_MAX_VIFS) {
! 189: logit(LOG_WARNING, 0,
! 190: "Cannot send RSRR Route Reply because %d is too many vifs %d",
! 191: numvifs);
! 192: return;
! 193: }
! 194:
! 195: /* Set up message */
! 196: rsrr->version = 1;
! 197: rsrr->type = RSRR_INITIAL_REPLY;
! 198: rsrr->flags = 0;
! 199: rsrr->num = numvifs;
! 200:
! 201: vif_list = (struct rsrr_vif *)(rsrr_send_buf + RSRR_HEADER_LEN);
! 202:
! 203: /* Include the vif list. */
! 204: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
! 205: vif_list[vifi].id = vifi;
! 206: vif_list[vifi].status = 0;
! 207: if (v->uv_flags & VIFF_DISABLED)
! 208: BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
! 209: vif_list[vifi].threshold = v->uv_threshold;
! 210: vif_list[vifi].local_addr = v->uv_lcl_addr;
! 211: }
! 212:
! 213: /* Get the size. */
! 214: sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
! 215:
! 216: /* Send it. */
! 217: IF_DEBUG(DEBUG_RSRR) {
! 218: logit(LOG_DEBUG, 0, "Send RSRR Initial Reply");
! 219: }
! 220: rsrr_send(sendlen);
! 221: }
! 222:
! 223: /* Send a Route Reply to the reservation protocol. The Route Query
! 224: * contains the query to which we are responding. The flags contain
! 225: * the incoming flags from the query or, for route change
! 226: * notification, the flags that should be set for the reply. The
! 227: * kernel table entry contains the routing info to use for a route
! 228: * change notification.
! 229: */
! 230: /* XXX: must modify if your routing table structure/search is different */
! 231: static int rsrr_accept_rq(struct rsrr_rq *route_query, uint8_t flags, struct gtable *gt_notify)
! 232: {
! 233: struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
! 234: struct rsrr_rr *route_reply;
! 235: int sendlen;
! 236: struct gtable *gt;
! 237: int status_ok;
! 238: #ifdef PIM
! 239: int found;
! 240: uint8_t tmp_flags;
! 241: rp_grp_entry_t *rp_grp_entry;
! 242: grpentry_t *grpentry_ptr;
! 243: #else
! 244: struct gtable local_g;
! 245: struct rtentry *r;
! 246: uint32_t mcastgrp;
! 247: #endif /* PIM */
! 248:
! 249: /* Set up message */
! 250: rsrr->version = 1;
! 251: rsrr->type = RSRR_ROUTE_REPLY;
! 252: rsrr->flags = flags;
! 253: rsrr->num = 0;
! 254:
! 255: route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
! 256: route_reply->dest_addr = route_query->dest_addr;
! 257: route_reply->source_addr = route_query->source_addr;
! 258: route_reply->query_id = route_query->query_id;
! 259:
! 260: /* Blank routing entry for error. */
! 261: route_reply->in_vif = 0;
! 262: route_reply->reserved = 0;
! 263: route_reply->out_vif_bm = 0;
! 264:
! 265: /* Get the size. */
! 266: sendlen = RSRR_RR_LEN;
! 267:
! 268: /* If routing table entry is defined, then we are sending a Route Reply
! 269: * due to a Route Change Notification event. Use the routing table entry
! 270: * to supply the routing info.
! 271: */
! 272: status_ok = FALSE;
! 273: #ifdef PIM
! 274: if (gt_notify) {
! 275: /* Include the routing entry. */
! 276: route_reply->in_vif = gt_notify->incoming;
! 277: route_reply->out_vif_bm = gt_notify->oifs;
! 278: gt = gt_notify;
! 279: status_ok = TRUE;
! 280: } else if ((gt = find_route(route_query->source_addr,
! 281: route_query->dest_addr,
! 282: MRTF_SG | MRTF_WC | MRTF_PMBR,
! 283: DONT_CREATE)) != (struct gtable *)NULL) {
! 284: status_ok = TRUE;
! 285: route_reply->in_vif = gt->incoming;
! 286: route_reply->out_vif_bm = gt->oifs;
! 287: }
! 288: if (status_ok != TRUE) {
! 289: /* Set error bit. */
! 290: rsrr->flags = 0;
! 291: BIT_SET(rsrr->flags, RSRR_ERROR_BIT);
! 292: }
! 293: else {
! 294: if (gt->flags & (MRTF_WC | MRTF_PMBR)) {
! 295: tmp_flags = 0;
! 296: BIT_SET(tmp_flags, RSRR_THIS_SENDER_SHARED_TREE);
! 297: BIT_SET(tmp_flags, RSRR_ALL_SENDERS_SHARED_TREE);
! 298: if (!(flags & tmp_flags)) {
! 299: /* Check whether need to setup the (*,G) related flags */
! 300: found = FALSE;
! 301: if (gt->flags & MRTF_PMBR) {
! 302: /* Check whether there is at least one (S,G) entry which is
! 303: * a longer match than this (*,*,RP) entry.
! 304: */
! 305: for (rp_grp_entry = gt->source->cand_rp->rp_grp_next;
! 306: rp_grp_entry != (rp_grp_entry_t *)NULL;
! 307: rp_grp_entry = rp_grp_entry->rp_grp_next) {
! 308: for (grpentry_ptr = rp_grp_entry->grplink;
! 309: grpentry_ptr != (grpentry_t *)NULL;
! 310: grpentry_ptr = grpentry_ptr->rpnext) {
! 311: if (grpentry_ptr->mrtlink != (mrtentry_t *)NULL) {
! 312: found = TRUE;
! 313: break;
! 314: }
! 315: }
! 316: if (found == TRUE)
! 317: break;
! 318: }
! 319: }
! 320: else if (gt->flags & MRTF_WC) {
! 321: if (gt->group->mrtlink != (mrtentry_t *)NULL)
! 322: found = TRUE;
! 323: }
! 324: if (found == TRUE) {
! 325: RSRR_THIS_SENDER_SHARED_TREE_SOME_OTHER_NOT(rsrr->flags);
! 326: }
! 327: else {
! 328: RSRR_SET_ALL_SENDERS_SHARED_TREE(rsrr->flags);
! 329: }
! 330: }
! 331: }
! 332: /* Cache reply if using route change notification. */
! 333: if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) {
! 334: /* TODO: XXX: Originally the rsrr_cache() call was first, but
! 335: * I think this is incorrect, because rsrr_cache() checks the
! 336: * rsrr_send_buf "flag" first.
! 337: */
! 338: BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT);
! 339: rsrr_cache(gt, route_query);
! 340: }
! 341: }
! 342: #else /* Not PIM */
! 343: if (gt_notify) {
! 344: /* Set flags */
! 345: rsrr->flags = flags;
! 346: /* Include the routing entry. */
! 347: /* The original code from mrouted-3.9b2 */
! 348: route_reply->in_vif = gt_notify->gt_route->rt_parent;
! 349: /* TODO: XXX: bug? See the PIM code above */
! 350: if (BIT_TST(flags, RSRR_NOTIFICATION_BIT))
! 351: route_reply->out_vif_bm = gt_notify->gt_grpmems;
! 352: else
! 353: route_reply->out_vif_bm = 0;
! 354: } else if (find_src_grp(route_query->source_addr, 0,
! 355: route_query->dest_addr)) {
! 356:
! 357: /* Found kernel entry. Code taken from add_table_entry() */
! 358: gt = gtp ? gtp->gt_gnext : kernel_table;
! 359:
! 360: /* Include the routing entry. */
! 361: route_reply->in_vif = gt->gt_route->rt_parent;
! 362: route_reply->out_vif_bm = gt->gt_grpmems;
! 363:
! 364: /* Cache reply if using route change notification. */
! 365: if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) {
! 366: /* TODO: XXX: Originally the rsrr_cache() call was first, but
! 367: * I think this is incorrect, because rsrr_cache() checks the
! 368: * rsrr_send_buf "flag" first.
! 369: */
! 370: BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT);
! 371: rsrr_cache(gt, route_query);
! 372: }
! 373: } else {
! 374: /* No kernel entry; use routing table. */
! 375: r = determine_route(route_query->source_addr);
! 376:
! 377: if (r != NULL) {
! 378: /* We need to mimic what will happen if a data packet
! 379: * is forwarded by multicast routing -- the kernel will
! 380: * make an upcall and mrouted will install a route in the kernel.
! 381: * Our outgoing vif bitmap should reflect what that table
! 382: * will look like. Grab code from add_table_entry().
! 383: * This is gross, but it's probably better to be accurate.
! 384: */
! 385:
! 386: gt = &local_g;
! 387: mcastgrp = route_query->dest_addr;
! 388:
! 389: gt->gt_mcastgrp = mcastgrp;
! 390: gt->gt_grpmems = 0;
! 391: gt->gt_scope = 0;
! 392: gt->gt_route = r;
! 393:
! 394: /* obtain the multicast group membership list */
! 395: determine_forwvifs(gt);
! 396:
! 397: /* Include the routing entry. */
! 398: route_reply->in_vif = gt->gt_route->rt_parent;
! 399: route_reply->out_vif_bm = gt->gt_grpmems;
! 400: } else {
! 401: /* Set error bit. */
! 402: BIT_SET(rsrr->flags, RSRR_ERROR_BIT);
! 403: }
! 404: }
! 405: #endif /* pimd - mrouted specific code */
! 406:
! 407: IF_DEBUG(DEBUG_RSRR) {
! 408: logit(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vif %d\n",
! 409: gt_notify ? "Route Change: " : "",
! 410: inet_fmt(route_reply->source_addr, s1, sizeof(s1)),
! 411: inet_fmt(route_reply->dest_addr, s2, sizeof(s2)),
! 412: route_reply->in_vif,route_reply->out_vif_bm);
! 413: }
! 414:
! 415: /* Send it. */
! 416: return rsrr_send(sendlen);
! 417: }
! 418:
! 419: /* Send an RSRR message. */
! 420: static int rsrr_send(int sendlen)
! 421: {
! 422: int error;
! 423:
! 424: while ((error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
! 425: (struct sockaddr *)&client_addr, client_length)) < 0)
! 426: {
! 427: if (errno == EINTR)
! 428: continue; /* Received signal, retry syscall. */
! 429:
! 430: logit(LOG_WARNING, errno, "Failed sendto() in rsrr_send()");
! 431:
! 432: return error;
! 433: }
! 434:
! 435: if (error != sendlen)
! 436: logit(LOG_WARNING, 0, "Sent only %d out of %d bytes on RSRR socket", error, sendlen);
! 437:
! 438: return error;
! 439: }
! 440:
! 441: /* TODO: need to sort the rsrr_cache entries for faster access */
! 442: /* Cache a message being sent to a client. Currently only used for
! 443: * caching Route Reply messages for route change notification.
! 444: */
! 445: static void rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query)
! 446: {
! 447: struct rsrr_cache *rc, **rcnp;
! 448: struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
! 449:
! 450: #ifdef PIM
! 451: rcnp = >->rsrr_cache;
! 452: #else
! 453: rcnp = >->gt_rsrr_cache;
! 454: #endif /* PIM */
! 455: while ((rc = *rcnp) != NULL) {
! 456: if ((rc->route_query.source_addr ==
! 457: route_query->source_addr) &&
! 458: (rc->route_query.dest_addr ==
! 459: route_query->dest_addr) &&
! 460: (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
! 461: /* Cache entry already exists.
! 462: * Check if route notification bit has been cleared.
! 463: */
! 464: if (!BIT_TST(rsrr->flags, RSRR_NOTIFICATION_BIT)) {
! 465: /* Delete cache entry. */
! 466: *rcnp = rc->next;
! 467: free(rc);
! 468: } else {
! 469: /* Update */
! 470: /* TODO: XXX: No need to update iif, oifs, flags */
! 471: rc->route_query.query_id = route_query->query_id;
! 472: IF_DEBUG(DEBUG_RSRR) {
! 473: logit(LOG_DEBUG, 0,
! 474: "Update cached query id %ld from client %s\n",
! 475: rc->route_query.query_id, rc->client_addr.sun_path);
! 476: }
! 477: }
! 478: return;
! 479: }
! 480: rcnp = &rc->next;
! 481: }
! 482:
! 483: /* Cache entry doesn't already exist. Create one and insert at
! 484: * front of list.
! 485: */
! 486: rc = (struct rsrr_cache *)calloc(1, sizeof(struct rsrr_cache));
! 487: if (rc == NULL)
! 488: logit(LOG_ERR, 0, "Ran out of memory in rsrr_cache()");
! 489:
! 490: rc->route_query.source_addr = route_query->source_addr;
! 491: rc->route_query.dest_addr = route_query->dest_addr;
! 492: rc->route_query.query_id = route_query->query_id;
! 493: strlcpy(rc->client_addr.sun_path, client_addr.sun_path, sizeof(rc->client_addr.sun_path));
! 494: rc->client_length = client_length;
! 495: #ifdef PIM
! 496: rc->next = gt->rsrr_cache;
! 497: gt->rsrr_cache = rc;
! 498: #else
! 499: rc->next = gt->gt_rsrr_cache;
! 500: gt->gt_rsrr_cache = rc;
! 501: #endif /* PIM */
! 502: IF_DEBUG(DEBUG_RSRR) {
! 503: logit(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
! 504: rc->route_query.query_id, rc->client_addr.sun_path);
! 505: }
! 506: }
! 507:
! 508: /* Send all the messages in the cache for particular routing entry.
! 509: * Currently this is used to send all the cached Route Reply messages
! 510: * for route change notification.
! 511: */
! 512: void rsrr_cache_send(struct gtable *gt, int notify)
! 513: {
! 514: struct rsrr_cache *rc, **rcnp;
! 515: uint8_t flags = 0;
! 516:
! 517: if (notify) {
! 518: BIT_SET(flags, RSRR_NOTIFICATION_BIT);
! 519: }
! 520:
! 521: #ifdef PIM
! 522: rcnp = >->rsrr_cache;
! 523: #else
! 524: rcnp = >->gt_rsrr_cache;
! 525: #endif /* PIM */
! 526:
! 527: while ((rc = *rcnp) != NULL) {
! 528: if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) {
! 529: IF_DEBUG(DEBUG_RSRR) {
! 530: logit(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
! 531: rc->route_query.query_id,rc->client_addr.sun_path);
! 532: }
! 533: /* Delete cache entry. */
! 534: *rcnp = rc->next;
! 535: free(rc);
! 536: } else {
! 537: rcnp = &rc->next;
! 538: }
! 539: }
! 540: }
! 541:
! 542: /* Bring "up" the RSRR cache entries: the (S,G) entry brings up any
! 543: * matching entry from (*,*,RP) or (*,G). The (*,G) entry brings up
! 544: * any matching entries from (*,*,RP)
! 545: */
! 546: void rsrr_cache_bring_up(struct gtable *gt)
! 547: {
! 548: struct gtable *gt_rp, *gt_wide;
! 549: uint8_t flags = 0;
! 550: struct rsrr_cache *rc, **rcnp;
! 551:
! 552: if (gt == (struct gtable *)NULL)
! 553: return;
! 554: if (gt->flags & MRTF_PMBR)
! 555: /* (*,*,RP) */
! 556: return;
! 557: if (gt->flags & MRTF_WC) {
! 558: /* (*,G) */
! 559: if (((gt_rp = gt->group->active_rp_grp->rp->rpentry->mrtlink) ==
! 560: (struct gtable *)NULL)
! 561: || (gt_rp->rsrr_cache == (struct rsrr_cache *)NULL))
! 562: return;
! 563: if ((gt_rp->incoming == gt->incoming)
! 564: && (VIFM_SAME(gt->oifs, gt_rp->oifs))) {
! 565: /* The (iif, oifs) are the same. Just link to the new routing
! 566: * table entry. No need to send message to rsvpd */
! 567: rcnp = >_rp->rsrr_cache;
! 568: while ((rc = *rcnp) != NULL) {
! 569: if (rc->route_query.dest_addr == gt->group->group) {
! 570: *rcnp = rc->next;
! 571: rc->next = gt->rsrr_cache;
! 572: gt->rsrr_cache = rc;
! 573: }
! 574: else {
! 575: rcnp = &rc->next;
! 576: }
! 577: }
! 578: }
! 579: else {
! 580: /* Have to move the entries and at the same time
! 581: * send an update message to rsvpd for each of them.
! 582: */
! 583: /* TODO: XXX: this can be done faster */
! 584: rcnp = >_rp->rsrr_cache;
! 585: BIT_SET(flags, RSRR_NOTIFICATION_BIT);
! 586: if (gt->group->mrtlink != (mrtentry_t *)NULL) {
! 587: RSRR_THIS_SENDER_SHARED_TREE_SOME_OTHER_NOT(flags);
! 588: }
! 589: else {
! 590: RSRR_SET_ALL_SENDERS_SHARED_TREE(flags);
! 591: }
! 592: while ((rc = *rcnp) != NULL) {
! 593: if (rc->route_query.dest_addr == gt->group->group) {
! 594: *rcnp = rc->next;
! 595: if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) {
! 596: IF_DEBUG(DEBUG_RSRR) {
! 597: logit(LOG_DEBUG, 0,
! 598: "Deleting cached query id %ld from client %s\n",
! 599: rc->route_query.query_id,
! 600: rc->client_addr.sun_path);
! 601: }
! 602: }
! 603: /* Even on success have to delete it. */
! 604: *rcnp = rc->next;
! 605: free(rc);
! 606: }
! 607: }
! 608: }
! 609: return;
! 610: } /* end of (*,G) */
! 611:
! 612: if (gt->flags & MRTF_SG) {
! 613: /* (S,G) */
! 614: /* Check first (*,*,RP) */
! 615: if (((gt_wide = gt->group->active_rp_grp->rp->rpentry->mrtlink) ==
! 616: (struct gtable *)NULL)
! 617: || (gt_wide->rsrr_cache == (struct rsrr_cache *)NULL)) {
! 618: if (((gt_wide = gt->group->grp_route) == (struct gtable *)NULL)
! 619: || (gt_wide->rsrr_cache == (struct rsrr_cache *)NULL))
! 620: return;
! 621: }
! 622: BIT_SET(flags, RSRR_NOTIFICATION_BIT);
! 623: try_again:
! 624: rcnp = >_wide->rsrr_cache;
! 625: while((rc = *rcnp) != NULL) {
! 626: if ((rc->route_query.dest_addr == gt->group->group)
! 627: && (rc->route_query.source_addr ==
! 628: gt->source->address)) {
! 629: /* Found it. Need just this entry */
! 630: *rcnp = rc->next; /* Free from the original chain */
! 631: if ((gt_wide->incoming == gt->incoming)
! 632: && (VIFM_SAME(gt_wide->oifs, gt->oifs))) {
! 633: /* The (iif, oifs) are the same. Just link to the
! 634: * new routing table entry. No need to send
! 635: * message to rsvpd
! 636: */
! 637: rc->next = gt->rsrr_cache;
! 638: gt->rsrr_cache = rc;
! 639: }
! 640: else {
! 641: /* The iif and/or oifs are different. Send a message
! 642: * to rsvpd
! 643: */
! 644: if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) {
! 645: IF_DEBUG(DEBUG_RSRR) {
! 646: logit(LOG_DEBUG, 0,
! 647: "Deleting cached query id %ld from client %s\n",
! 648: rc->route_query.query_id,
! 649: rc->client_addr.sun_path);
! 650: }
! 651: }
! 652: /* Even on success have to delete it. */
! 653: free(rc);
! 654: }
! 655: return;
! 656: }
! 657: }
! 658: if (gt_wide->flags & MRTF_PMBR) {
! 659: if (((gt_wide = gt->group->grp_route) == (struct gtable *)NULL)
! 660: || (gt_wide->rsrr_cache == (struct rsrr_cache *)NULL))
! 661: return;
! 662: goto try_again;
! 663: }
! 664: }
! 665: }
! 666:
! 667: /* Clean the cache by deleting or moving all entries. */
! 668: /* XXX: for PIM, if the routing entry is (S,G), will try first to
! 669: * "transfer" the RSRR cache entry to the (*,G) or (*,*,RP) routing entry
! 670: * (if any). If the current routing entry is (*,G), it will move the
! 671: * cache entries to the (*,*,RP) routing entry (if existing).
! 672: * If the old and the new (iif, oifs) are the same, then no need to send
! 673: * route change message to the reservation daemon: just plug all entries at
! 674: * the front of the rsrr_cache chain.
! 675: */
! 676: void rsrr_cache_clean(struct gtable *gt)
! 677: {
! 678: struct rsrr_cache *rc, *rc_next, **rcnp;
! 679: struct gtable *gt_wide;
! 680: #ifdef PIM
! 681: uint8_t flags = 0;
! 682:
! 683: IF_DEBUG(DEBUG_RSRR) {
! 684: if (gt->flags & MRTF_SG)
! 685: logit(LOG_DEBUG, 0, "cleaning cache for source %s and group %s",
! 686: inet_fmt(gt->source->address, s1, sizeof(s1)),
! 687: inet_fmt(gt->group->group, s2, sizeof(s2)));
! 688: else if (gt->flags & MRTF_WC)
! 689: logit(LOG_DEBUG, 0, "cleaning cache for group %s and ANY sources",
! 690: inet_fmt(gt->group->group, s1, sizeof(s1)));
! 691: else if (gt->flags & MRTF_PMBR)
! 692: logit(LOG_DEBUG, 0,
! 693: "cleaning cache for ALL groups matching to RP %s",
! 694: inet_fmt(gt->source->address, s1, sizeof(s1)));
! 695: }
! 696: rc = gt->rsrr_cache;
! 697: if (rc == (struct rsrr_cache *)NULL)
! 698: return;
! 699: if (gt->flags & MRTF_SG) {
! 700: if ((gt_wide = gt->group->grp_route) == (struct gtable *)NULL)
! 701: gt_wide = gt->group->active_rp_grp->rp->rpentry->mrtlink;
! 702: }
! 703: else if (gt->flags & MRTF_WC)
! 704: gt_wide = gt->group->active_rp_grp->rp->rpentry->mrtlink;
! 705: else
! 706: gt_wide = (struct gtable *)NULL;
! 707:
! 708: if (gt_wide == (struct gtable *)NULL) {
! 709: /* No routing entry where to move down the rsrr cache entry.
! 710: * Send a message with "cannot_notify" bit set.
! 711: */
! 712: rsrr_cache_send(gt, 0);
! 713: while (rc) {
! 714: rc_next = rc->next;
! 715: free(rc);
! 716: rc = rc_next;
! 717: }
! 718: } else if ((gt_wide->incoming == gt->incoming)
! 719: && (VIFM_SAME(gt->oifs, gt_wide->oifs))) {
! 720: /* The (iif, oifs) are the same. Just move to the beginning of the
! 721: * RSRR cache chain. No need to send message */
! 722: while (rc->next != (struct rsrr_cache *)NULL)
! 723: rc = rc->next;
! 724: rc->next = gt_wide->rsrr_cache;
! 725: gt_wide->rsrr_cache = gt->rsrr_cache;
! 726: }
! 727: else {
! 728: /* Have to move to the RSRR cache entries and at the same time
! 729: * send an update for each of them.
! 730: */
! 731: rcnp = >->rsrr_cache;
! 732: BIT_SET(flags, RSRR_NOTIFICATION_BIT);
! 733: if (gt->group->mrtlink != (mrtentry_t *)NULL) {
! 734: RSRR_THIS_SENDER_SHARED_TREE_SOME_OTHER_NOT(flags);
! 735: }
! 736: else {
! 737: RSRR_SET_ALL_SENDERS_SHARED_TREE(flags);
! 738: }
! 739: while ((rc = *rcnp) != NULL) {
! 740: if (rsrr_accept_rq(&rc->route_query, flags, gt_wide) < 0) {
! 741: IF_DEBUG(DEBUG_RSRR) {
! 742: logit(LOG_DEBUG, 0,
! 743: "Deleting cached query id %ld from client %s\n",
! 744: rc->route_query.query_id, rc->client_addr.sun_path);
! 745: }
! 746: /* Delete cache entry. */
! 747: *rcnp = rc->next;
! 748: free(rc);
! 749: } else {
! 750: rcnp = &rc->next;
! 751: }
! 752: }
! 753: }
! 754: gt->rsrr_cache = (struct rsrr_cache *)NULL;
! 755:
! 756: #else
! 757: IF_DEBUG(DEBUG_RSRR) {
! 758: logit(LOG_DEBUG, 0, "cleaning cache for group %s\n",
! 759: inet_fmt(gt->gt_mcastgrp, s1, sizeof(s1)));
! 760: }
! 761: rc = gt->gt_rsrr_cache;
! 762: while (rc) {
! 763: rc_next = rc->next;
! 764: free(rc);
! 765: rc = rc_next;
! 766: }
! 767: gt->gt_rsrr_cache = NULL;
! 768: #endif /* PIM */
! 769: }
! 770:
! 771: void rsrr_clean(void)
! 772: {
! 773: unlink(RSRR_SERV_PATH);
! 774: }
! 775:
! 776: #else /* !RSRR */
! 777: static int dummy __attribute__((unused));
! 778: #endif /* RSRR */
! 779:
! 780: /**
! 781: * Local Variables:
! 782: * version-control: t
! 783: * indent-tabs-mode: t
! 784: * c-file-style: "ellemtel"
! 785: * c-basic-offset: 4
! 786: * End:
! 787: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>