Annotation of embedaddon/pimdd/rsrr.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 1993, 1998 by the University of Southern California
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software and its
        !             6:  * documentation in source and binary forms for lawful purposes
        !             7:  * and without fee is hereby granted, provided that the above copyright
        !             8:  * notice appear in all copies and that both the copyright notice and
        !             9:  * this permission notice appear in supporting documentation. and that
        !            10:  * any documentation, advertising materials, and other materials related
        !            11:  * to such distribution and use acknowledge that the software was
        !            12:  * developed by the University of Southern California, Information
        !            13:  * Sciences Institute.  The name of the University may not be used to
        !            14:  * endorse or promote products derived from this software without
        !            15:  * specific prior written permission.
        !            16:  *
        !            17:  * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
        !            18:  * the suitability of this software for any purpose.  THIS SOFTWARE IS
        !            19:  * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
        !            20:  * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            21:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            22:  *
        !            23:  * Other copyrights might apply to parts of this software and are so
        !            24:  * noted when applicable.
        !            25:  */
        !            26: 
        !            27: /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
        !            28:  * April 1995.
        !            29:  *
        !            30:  * Modified by Kurtw Windisch (kurtw@antc.uoregon.edu) for use with 
        !            31:  * Dense-mode pimd.
        !            32:  */
        !            33: 
        !            34: /* May 1995 -- Added support for Route Change Notification */
        !            35: 
        !            36: #ifdef RSRR
        !            37: 
        !            38: #include "defs.h"
        !            39: #include <sys/param.h>
        !            40: #if (defined(BSD) && (BSD >= 199103))
        !            41: #include <stddef.h>
        !            42: #endif
        !            43: 
        !            44: 
        !            45: /*
        !            46:  * Exported variables.
        !            47:  */
        !            48: int rsrr_socket;               /* interface to reservation protocol */
        !            49: 
        !            50: /* 
        !            51:  * Global RSRR variables.
        !            52:  */
        !            53: char *rsrr_recv_buf;           /* RSRR receive buffer */
        !            54: char *rsrr_send_buf;           /* RSRR send buffer */
        !            55: 
        !            56: struct sockaddr_un client_addr;
        !            57: int client_length = sizeof(client_addr);
        !            58: 
        !            59: 
        !            60: /*
        !            61:  * Local functions definition
        !            62:  */
        !            63: static void    rsrr_accept    __P((int recvlen));
        !            64: static void    rsrr_accept_iq __P((void));
        !            65: static int     rsrr_accept_rq __P((struct rsrr_rq *route_query, u_int8 flags,
        !            66:                                    struct gtable *gt_notify));
        !            67: static void    rsrr_read      __P((int, fd_set *));
        !            68: static int     rsrr_send      __P((int sendlen));
        !            69: static void    rsrr_cache     __P((struct gtable *gt,
        !            70:                                        struct rsrr_rq *route_query));
        !            71: 
        !            72: /* Initialize RSRR socket */
        !            73: void
        !            74: rsrr_init()
        !            75: {
        !            76:     int servlen;
        !            77:     struct sockaddr_un serv_addr;
        !            78: 
        !            79:     rsrr_recv_buf = malloc(RSRR_MAX_LEN);
        !            80:     rsrr_send_buf = malloc(RSRR_MAX_LEN);
        !            81: 
        !            82:     if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
        !            83:        log(LOG_ERR, errno, "Can't create RSRR socket");
        !            84: 
        !            85:     unlink(RSRR_SERV_PATH);
        !            86:     bzero((char *) &serv_addr, sizeof(serv_addr));
        !            87:     serv_addr.sun_family = AF_UNIX;
        !            88:     strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
        !            89: #if (defined(BSD) && (BSD >= 199103))
        !            90:     servlen = offsetof(struct sockaddr_un, sun_path) +
        !            91:                strlen(serv_addr.sun_path);
        !            92:     serv_addr.sun_len = servlen;
        !            93: #else
        !            94:     servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
        !            95: #endif
        !            96:  
        !            97:     if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
        !            98:        log(LOG_ERR, errno, "Can't bind RSRR socket");
        !            99: 
        !           100:     if (register_input_handler(rsrr_socket, rsrr_read) < 0)
        !           101:        log(LOG_ERR, 0, "Couldn't register RSRR as an input handler");
        !           102: }
        !           103: 
        !           104: /* Read a message from the RSRR socket */
        !           105: static void
        !           106: rsrr_read(f, rfd)
        !           107:        int f;
        !           108:        fd_set *rfd;
        !           109: {
        !           110:     register int rsrr_recvlen;
        !           111:     
        !           112:     bzero((char *) &client_addr, sizeof(client_addr));
        !           113:     rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
        !           114:                            0, (struct sockaddr *)&client_addr,
        !           115:                            &client_length);
        !           116:     if (rsrr_recvlen < 0) {    
        !           117:        if (errno != EINTR)
        !           118:            log(LOG_ERR, errno, "RSRR recvfrom");
        !           119:        return;
        !           120:     }
        !           121:     rsrr_accept(rsrr_recvlen);
        !           122: }
        !           123: 
        !           124: /*
        !           125:  * Accept a message from the reservation protocol and take
        !           126:  * appropriate action.
        !           127:  */
        !           128: static void
        !           129: rsrr_accept(recvlen)
        !           130:     int recvlen;
        !           131: {
        !           132:     struct rsrr_header *rsrr;
        !           133:     struct rsrr_rq *route_query;
        !           134:     
        !           135:     if (recvlen < RSRR_HEADER_LEN) {
        !           136:        log(LOG_WARNING, 0,
        !           137:            "Received RSRR packet of %d bytes, which is less than min size",
        !           138:            recvlen);
        !           139:        return;
        !           140:     }
        !           141:     
        !           142:     rsrr = (struct rsrr_header *) rsrr_recv_buf;
        !           143:     
        !           144:     if (rsrr->version > RSRR_MAX_VERSION) {
        !           145:        log(LOG_WARNING, 0,
        !           146:            "Received RSRR packet version %d, which I don't understand",
        !           147:            rsrr->version);
        !           148:        return;
        !           149:     }
        !           150:     
        !           151:     switch (rsrr->version) {
        !           152:       case 1:
        !           153:        switch (rsrr->type) {
        !           154:          case RSRR_INITIAL_QUERY:
        !           155:            /* Send Initial Reply to client */
        !           156:            IF_DEBUG(DEBUG_RSRR)
        !           157:                log(LOG_DEBUG, 0, "Received Initial Query\n");
        !           158:            rsrr_accept_iq();
        !           159:            break;
        !           160:          case RSRR_ROUTE_QUERY:
        !           161:            /* Check size */
        !           162:            if (recvlen < RSRR_RQ_LEN) {
        !           163:                log(LOG_WARNING, 0,
        !           164:                    "Received Route Query of %d bytes, which is too small",
        !           165:                    recvlen);
        !           166:                break;
        !           167:            }
        !           168:            /* Get the query */
        !           169:            route_query =
        !           170:                (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
        !           171:            IF_DEBUG(DEBUG_RSRR)
        !           172:                log(LOG_DEBUG, 0,
        !           173:                    "Received Route Query for src %s grp %s notification %d",
        !           174:                    inet_fmt(route_query->source_addr, s1),
        !           175:                    inet_fmt(route_query->dest_addr, s2),
        !           176:                    BIT_TST(rsrr->flags, RSRR_NOTIFICATION_BIT));
        !           177:            /* Send Route Reply to client */
        !           178:            rsrr_accept_rq(route_query, rsrr->flags, (struct gtable *)NULL);
        !           179:            break;
        !           180:          default:
        !           181:            log(LOG_WARNING, 0,
        !           182:                "Received RSRR packet type %d, which I don't handle",
        !           183:                rsrr->type);
        !           184:            break;
        !           185:        }
        !           186:        break;
        !           187:        
        !           188:       default:
        !           189:        log(LOG_WARNING, 0,
        !           190:            "Received RSRR packet version %d, which I don't understand",
        !           191:            rsrr->version);
        !           192:        break;
        !           193:     }
        !           194: }
        !           195: 
        !           196: /* Send an Initial Reply to the reservation protocol. */
        !           197: /*
        !           198:  * TODO: XXX: if a new interfaces come up and _IF_ the multicast routing
        !           199:  * daemon automatically include it, have to inform the RSVP daemon.
        !           200:  * However, this is not in the RSRRv1 draft (just expired and is not
        !           201:  * available anymore from the internet-draft ftp sites). Probably has to
        !           202:  * be included in RSRRv2.
        !           203:  */
        !           204: static void
        !           205: rsrr_accept_iq()
        !           206: {
        !           207:     struct rsrr_header *rsrr;
        !           208:     struct rsrr_vif *vif_list;
        !           209:     struct uvif *v;
        !           210:     vifi_t vifi;
        !           211:     int sendlen;
        !           212:     
        !           213:     /* Check for space.  There should be room for plenty of vifs,
        !           214:      * but we should check anyway.
        !           215:      */
        !           216:     if (numvifs > RSRR_MAX_VIFS) {
        !           217:        log(LOG_WARNING, 0,
        !           218:            "Can't send RSRR Route Reply because %d is too many vifs %d",
        !           219:            numvifs);
        !           220:        return;
        !           221:     }
        !           222:     
        !           223:     /* Set up message */
        !           224:     rsrr = (struct rsrr_header *) rsrr_send_buf;
        !           225:     rsrr->version = 1;
        !           226:     rsrr->type = RSRR_INITIAL_REPLY;
        !           227:     rsrr->flags = 0;
        !           228:     rsrr->num = numvifs;
        !           229:     
        !           230:     vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
        !           231:     
        !           232:     /* Include the vif list. */
        !           233:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
        !           234:        vif_list[vifi].id = vifi;
        !           235:        vif_list[vifi].status = 0;
        !           236:        if (v->uv_flags & (VIFF_DISABLED))
        !           237:            BIT_SET(vif_list[vifi].status, RSRR_DISABLED_BIT);
        !           238:        vif_list[vifi].threshold = v->uv_threshold;
        !           239:        vif_list[vifi].local_addr = v->uv_lcl_addr;
        !           240:     }
        !           241:     
        !           242:     /* Get the size. */
        !           243:     sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
        !           244:     
        !           245:     /* Send it. */
        !           246:     IF_DEBUG(DEBUG_RSRR)
        !           247:        log(LOG_DEBUG, 0, "Send RSRR Initial Reply");
        !           248:     rsrr_send(sendlen);
        !           249: }
        !           250: 
        !           251: /* Send a Route Reply to the reservation protocol.  The Route Query
        !           252:  * contains the query to which we are responding.  The flags contain
        !           253:  * the incoming flags from the query or, for route change
        !           254:  * notification, the flags that should be set for the reply.  The
        !           255:  * kernel table entry contains the routing info to use for a route
        !           256:  * change notification.
        !           257:  */
        !           258: /* XXX: must modify if your routing table structure/search is different */
        !           259: static int
        !           260: rsrr_accept_rq(route_query, flags, gt_notify)
        !           261:     struct rsrr_rq *route_query;
        !           262:     u_int8 flags;
        !           263:     struct gtable *gt_notify;
        !           264: {
        !           265:     struct rsrr_header *rsrr;
        !           266:     struct rsrr_rr *route_reply;
        !           267:     int sendlen;
        !           268:     struct gtable *gt;
        !           269:     int status_ok;
        !           270:     
        !           271:     /* Set up message */
        !           272:     rsrr = (struct rsrr_header *) rsrr_send_buf;
        !           273:     rsrr->version = 1;
        !           274:     rsrr->type = RSRR_ROUTE_REPLY;
        !           275:     rsrr->flags = flags;
        !           276:     rsrr->num = 0;
        !           277:     
        !           278:     route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
        !           279:     route_reply->dest_addr = route_query->dest_addr;
        !           280:     route_reply->source_addr = route_query->source_addr;
        !           281:     route_reply->query_id = route_query->query_id;
        !           282:     
        !           283:     /* Blank routing entry for error. */
        !           284:     route_reply->in_vif = 0;
        !           285:     route_reply->reserved = 0;
        !           286:     route_reply->out_vif_bm = 0;
        !           287:     
        !           288:     /* Get the size. */
        !           289:     sendlen = RSRR_RR_LEN;
        !           290:     
        !           291:     /* If routing table entry is defined, then we are sending a Route Reply
        !           292:      * due to a Route Change Notification event.  Use the routing table entry
        !           293:      * to supply the routing info.
        !           294:      */
        !           295:     status_ok = FALSE;
        !           296:     if (gt_notify) {
        !           297:        /* Include the routing entry. */
        !           298:        route_reply->in_vif = gt_notify->incoming;
        !           299:        route_reply->out_vif_bm = gt_notify->oifs;
        !           300:        gt = gt_notify;
        !           301:        status_ok = TRUE;
        !           302:     } else if ((gt = find_route(route_query->source_addr,
        !           303:                                route_query->dest_addr,
        !           304:                                MRTF_SG | MRTF_WC | MRTF_PMBR,
        !           305:                                DONT_CREATE)) != (struct gtable *)NULL) {
        !           306:        status_ok = TRUE;
        !           307:        route_reply->in_vif = gt->incoming;
        !           308:        route_reply->out_vif_bm = gt->oifs;
        !           309:     }
        !           310:     if (status_ok != TRUE) {
        !           311:        /* Set error bit. */
        !           312:        rsrr->flags = 0;
        !           313:        BIT_SET(rsrr->flags, RSRR_ERROR_BIT);
        !           314:     }
        !           315:     else {
        !           316:        /* Cache reply if using route change notification. */
        !           317:        if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) {
        !           318:            /* TODO: XXX: Originally the rsrr_cache() call was first, but
        !           319:             * I think this is incorrect, because rsrr_cache() checks the
        !           320:             * rsrr_send_buf "flag" first.
        !           321:             */
        !           322:            BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT);
        !           323:            rsrr_cache(gt, route_query);
        !           324:        }
        !           325:     }
        !           326:     
        !           327:     IF_DEBUG(DEBUG_RSRR)
        !           328:        log(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vifs 0x%x\n",
        !           329:            gt_notify ? "Route Change: " : "",
        !           330:            inet_fmt(route_reply->source_addr,s1),
        !           331:            inet_fmt(route_reply->dest_addr,s2),
        !           332:            route_reply->in_vif, route_reply->out_vif_bm);
        !           333:     
        !           334:     /* Send it. */
        !           335:     return rsrr_send(sendlen);
        !           336: }
        !           337: 
        !           338: /* Send an RSRR message. */
        !           339: static int
        !           340: rsrr_send(sendlen)
        !           341:     int sendlen;
        !           342: {
        !           343:     int error;
        !           344:     
        !           345:     /* Send it. */
        !           346:     error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
        !           347:                   (struct sockaddr *)&client_addr, client_length);
        !           348:     
        !           349:     /* Check for errors. */
        !           350:     if (error < 0) {
        !           351:        log(LOG_WARNING, errno, "Failed send on RSRR socket");
        !           352:     } else if (error != sendlen) {
        !           353:        log(LOG_WARNING, 0,
        !           354:            "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
        !           355:     }
        !           356:     return error;
        !           357: }
        !           358: 
        !           359: /* TODO: need to sort the rsrr_cache entries for faster access */
        !           360: /* Cache a message being sent to a client.  Currently only used for
        !           361:  * caching Route Reply messages for route change notification.
        !           362:  */
        !           363: static void
        !           364: rsrr_cache(gt, route_query)
        !           365:     struct gtable *gt;
        !           366:     struct rsrr_rq *route_query;
        !           367: {
        !           368:     struct rsrr_cache *rc, **rcnp;
        !           369:     struct rsrr_header *rsrr;
        !           370: 
        !           371:     rsrr = (struct rsrr_header *) rsrr_send_buf;
        !           372: 
        !           373:     rcnp = &gt->rsrr_cache;
        !           374:     while ((rc = *rcnp) != NULL) {
        !           375:        if ((rc->route_query.source_addr == 
        !           376:             route_query->source_addr) &&
        !           377:            (rc->route_query.dest_addr == 
        !           378:             route_query->dest_addr) &&
        !           379:            (!strcmp(rc->client_addr.sun_path, client_addr.sun_path))) {
        !           380:            /* Cache entry already exists.
        !           381:             * Check if route notification bit has been cleared.
        !           382:             */
        !           383:            if (!BIT_TST(rsrr->flags, RSRR_NOTIFICATION_BIT)) {
        !           384:                /* Delete cache entry. */
        !           385:                *rcnp = rc->next;
        !           386:                free(rc);
        !           387:            } else {
        !           388:                /* Update */
        !           389:                /* TODO: XXX: No need to update iif, oifs, flags */
        !           390:                rc->route_query.query_id = route_query->query_id;
        !           391:                IF_DEBUG(DEBUG_RSRR)
        !           392:                    log(LOG_DEBUG, 0,
        !           393:                        "Update cached query id %ld from client %s\n",
        !           394:                        rc->route_query.query_id, rc->client_addr.sun_path);
        !           395:            }
        !           396:            return;
        !           397:        }
        !           398:        rcnp = &rc->next;
        !           399:     }
        !           400:     
        !           401:     /* Cache entry doesn't already exist.  Create one and insert at
        !           402:      * front of list.
        !           403:      */
        !           404:     rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
        !           405:     if (rc == NULL)
        !           406:        log(LOG_ERR, 0, "ran out of memory");
        !           407:     rc->route_query.source_addr = route_query->source_addr;
        !           408:     rc->route_query.dest_addr = route_query->dest_addr;
        !           409:     rc->route_query.query_id = route_query->query_id;
        !           410:     strcpy(rc->client_addr.sun_path, client_addr.sun_path);
        !           411:     rc->client_length = client_length;
        !           412:     rc->next = gt->rsrr_cache;
        !           413:     gt->rsrr_cache = rc;
        !           414:     IF_DEBUG(DEBUG_RSRR)
        !           415:        log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
        !           416:            rc->route_query.query_id, rc->client_addr.sun_path);
        !           417: }
        !           418: 
        !           419: /* Send all the messages in the cache for particular routing entry.
        !           420:  * Currently this is used to send all the cached Route Reply messages
        !           421:  * for route change notification.
        !           422:  */
        !           423: void
        !           424: rsrr_cache_send(gt, notify)
        !           425:     struct gtable *gt;
        !           426:     int notify;
        !           427: {
        !           428:     struct rsrr_cache *rc, **rcnp;
        !           429:     u_int8 flags = 0;
        !           430: 
        !           431:     if (notify)
        !           432:        BIT_SET(flags, RSRR_NOTIFICATION_BIT);
        !           433: 
        !           434:     rcnp = &gt->rsrr_cache;
        !           435: 
        !           436:     while ((rc = *rcnp) != NULL) {
        !           437:        if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) {
        !           438:            IF_DEBUG(DEBUG_RSRR)
        !           439:                log(LOG_DEBUG, 0,
        !           440:                    "Deleting cached query id %ld from client %s\n",
        !           441:                    rc->route_query.query_id, rc->client_addr.sun_path);
        !           442:            /* Delete cache entry. */
        !           443:            *rcnp = rc->next;
        !           444:            free(rc);
        !           445:        } else {
        !           446:            rcnp = &rc->next;
        !           447:        }
        !           448:     }
        !           449: }
        !           450: 
        !           451: /* Clean the cache by deleting or moving all entries. */
        !           452: /* XXX: for PIM, if the routing entry is (S,G), will try first to
        !           453:  * "transfer" the RSRR cache entry to the (*,G) or (*,*,RP) routing entry
        !           454:  * (if any). If the current routing entry is (*,G), it will move the
        !           455:  * cache entries to the (*,*,RP) routing entry (if existing).
        !           456:  * If the old and the new (iif, oifs) are the same, then no need to send
        !           457:  * route change message to the reservation daemon: just plug all entries at
        !           458:  * the front of the rsrr_cache chain.
        !           459:  */
        !           460: void
        !           461: rsrr_cache_clean(gt)
        !           462:     struct gtable *gt;
        !           463: {
        !           464:     struct rsrr_cache *rc, *rc_next;
        !           465: 
        !           466:     IF_DEBUG(DEBUG_RSRR) {
        !           467:        log(LOG_DEBUG, 0, "cleaning cache for source %s and group %s",
        !           468:            inet_fmt(gt->source->address, s1),
        !           469:            inet_fmt(gt->group->group, s2));
        !           470:     }
        !           471:     rc = gt->rsrr_cache;
        !           472:     if (rc == (struct rsrr_cache *)NULL)
        !           473:        return;
        !           474: 
        !           475:     while(rc) {
        !           476:         rc_next = rc->next;
        !           477:         free(rc);
        !           478:         rc = rc_next;
        !           479:      }
        !           480: 
        !           481:     gt->rsrr_cache = (struct rsrr_cache *)NULL;
        !           482: }
        !           483: 
        !           484: void
        !           485: rsrr_clean()
        !           486: {
        !           487:     unlink(RSRR_SERV_PATH);
        !           488: }
        !           489: 
        !           490: #endif /* RSRR */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>