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->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->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>