File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / rsrr.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:59:37 2017 UTC (7 years ago) by misho
Branches: pimd, MAIN
CVS tags: v2_3_2, HEAD
pimd 2.3.2

    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 = &gt->rsrr_cache;
  452: #else
  453:     rcnp = &gt->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 = &gt->rsrr_cache;
  523: #else
  524:     rcnp = &gt->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 = &gt_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 = &gt_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 = &gt_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 = &gt->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>