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