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

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 1993, 1998-2001.
        !             3:  * The University of Southern California/Information Sciences Institute.
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  * 3. Neither the name of the project nor the names of its contributors
        !            15:  *    may be used to endorse or promote products derived from this software
        !            16:  *    without specific prior written permission.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
        !            19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
        !            22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            28:  * SUCH DAMAGE.
        !            29:  */
        !            30: 
        !            31: /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
        !            32:  * April 1995.
        !            33:  */
        !            34: 
        !            35: /* May 1995 -- Added support for Route Change Notification */
        !            36: 
        !            37: #ifdef RSRR
        !            38: 
        !            39: #include "defs.h"
        !            40: #include <sys/param.h>
        !            41: #ifdef HAVE_SA_LEN
        !            42: #include <stddef.h>            /* for offsetof */
        !            43: #endif
        !            44: 
        !            45: /* 
        !            46:  * Local RSRR variables.
        !            47:  */
        !            48: static int rsrr_socket;                /* interface to reservation protocol */
        !            49: static char *rsrr_recv_buf;            /* RSRR receive buffer */
        !            50: static char *rsrr_send_buf;            /* RSRR send buffer */
        !            51: 
        !            52: static struct sockaddr_un client_addr;
        !            53: static socklen_t client_length = sizeof(client_addr);
        !            54: 
        !            55: /*
        !            56:  * Procedure definitions needed internally.
        !            57:  */
        !            58: static void    rsrr_accept    (size_t recvlen);
        !            59: static void    rsrr_accept_iq (void);
        !            60: static int     rsrr_accept_rq (struct rsrr_rq *route_query, uint8_t flags, struct gtable *gt_notify);
        !            61: static void    rsrr_read      (int, fd_set *);
        !            62: static int     rsrr_send      (int sendlen);
        !            63: static void    rsrr_cache     (struct gtable *gt, struct rsrr_rq *route_query);
        !            64: 
        !            65: /* Initialize RSRR socket */
        !            66: void rsrr_init(void)
        !            67: {
        !            68:     int servlen;
        !            69:     struct sockaddr_un serv_addr;
        !            70: 
        !            71:     rsrr_recv_buf = (char *)calloc(1, RSRR_MAX_LEN);
        !            72:     rsrr_send_buf = (char *)calloc(1, RSRR_MAX_LEN);
        !            73:     if (!rsrr_recv_buf || !rsrr_send_buf)
        !            74:        logit(LOG_ERR, 0, "Ran out of memory in rsrr_init()");
        !            75: 
        !            76:     if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
        !            77:        logit(LOG_ERR, errno, "Cannot create RSRR socket");
        !            78: 
        !            79:     unlink(RSRR_SERV_PATH);
        !            80:     memset(&serv_addr, 0, sizeof(serv_addr));
        !            81:     serv_addr.sun_family = AF_UNIX;
        !            82:     strlcpy(serv_addr.sun_path, RSRR_SERV_PATH, sizeof(serv_addr.sun_path));
        !            83: #ifdef HAVE_SA_LEN
        !            84:     servlen = offsetof(struct sockaddr_un, sun_path) + strlen(serv_addr.sun_path);
        !            85:     serv_addr.sun_len = servlen;
        !            86: #else
        !            87:     servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
        !            88: #endif
        !            89:  
        !            90:     if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
        !            91:        logit(LOG_ERR, errno, "Cannot bind RSRR socket");
        !            92: 
        !            93:     if (register_input_handler(rsrr_socket, rsrr_read) < 0)
        !            94:        logit(LOG_ERR, 0, "Could not register RSRR as an input handler");
        !            95: }
        !            96: 
        !            97: /* Read a message from the RSRR socket */
        !            98: static void rsrr_read(int fd, fd_set *rfd __attribute__ ((unused)))
        !            99: {
        !           100:     ssize_t len;
        !           101:     
        !           102:     memset(&client_addr, 0, sizeof(client_addr));
        !           103:     while ((len = recvfrom(fd, rsrr_recv_buf, sizeof(rsrr_recv_buf),
        !           104:                           0, (struct sockaddr *)&client_addr, &client_length)) < 0) {
        !           105:        if (errno == EINTR)
        !           106:            continue;           /* Received signal, retry syscall. */
        !           107: 
        !           108:        logit(LOG_ERR, errno, "Failed recvfrom() in rsrr_read()");
        !           109:        return;
        !           110:     }
        !           111: 
        !           112:     rsrr_accept(len);
        !           113: }
        !           114: 
        !           115: /* Accept a message from the reservation protocol and take
        !           116:  * appropriate action.
        !           117:  */
        !           118: static void rsrr_accept(size_t recvlen)
        !           119: {
        !           120:     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_recv_buf;
        !           121:     struct rsrr_rq *route_query;
        !           122:     
        !           123:     if (recvlen < RSRR_HEADER_LEN) {
        !           124:        logit(LOG_WARNING, 0, "Received RSRR packet of %d bytes, which is less than MIN size %d.",
        !           125:              recvlen, RSRR_HEADER_LEN);
        !           126:        return;
        !           127:     }
        !           128:     
        !           129:     if (rsrr->version > RSRR_MAX_VERSION || rsrr->version != 1) {
        !           130:        logit(LOG_WARNING, 0, "Received RSRR packet version %d, which I don't understand",
        !           131:              rsrr->version);
        !           132:        return;
        !           133:     }
        !           134: 
        !           135:     switch (rsrr->type) {
        !           136:        case RSRR_INITIAL_QUERY:
        !           137:            /* Send Initial Reply to client */
        !           138:            IF_DEBUG(DEBUG_RSRR) {
        !           139:                logit(LOG_DEBUG, 0, "Received Initial Query\n");
        !           140:            }
        !           141:            rsrr_accept_iq();
        !           142:            break;
        !           143: 
        !           144:        case RSRR_ROUTE_QUERY:
        !           145:            /* Check size */
        !           146:            if (recvlen < RSRR_RQ_LEN) {
        !           147:                logit(LOG_WARNING, 0, "Received Route Query of %d bytes, which is too small", recvlen);
        !           148:                break;
        !           149:            }
        !           150:            /* Get the query */
        !           151:            route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
        !           152:            IF_DEBUG(DEBUG_RSRR) {
        !           153:                logit(LOG_DEBUG, 0,
        !           154:                      "Received Route Query for src %s grp %s notification %d",
        !           155:                      inet_fmt(route_query->source_addr, s1, sizeof(s1)),
        !           156:                      inet_fmt(route_query->dest_addr, s2, sizeof(s2)),
        !           157:                      BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
        !           158:            }
        !           159:            /* Send Route Reply to client */
        !           160:            rsrr_accept_rq(route_query, rsrr->flags, NULL);
        !           161:            break;
        !           162: 
        !           163:        default:
        !           164:            logit(LOG_WARNING, 0, "Received RSRR packet type %d, which I don't handle", rsrr->type);
        !           165:            break;
        !           166:     }
        !           167: }
        !           168: 
        !           169: /* Send an Initial Reply to the reservation protocol. */
        !           170: /*
        !           171:  * TODO: XXX: if a new interfaces come up and _IF_ the multicast routing
        !           172:  * daemon automatically include it, have to inform the RSVP daemon.
        !           173:  * However, this is not in the RSRRv1 draft (just expired and is not
        !           174:  * available anymore from the internet-draft ftp sites). Probably has to
        !           175:  * be included in RSRRv2.
        !           176:  */
        !           177: static void rsrr_accept_iq(void)
        !           178: {
        !           179:     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
        !           180:     struct rsrr_vif *vif_list;
        !           181:     struct uvif *v;
        !           182:     vifi_t vifi;
        !           183:     int sendlen;
        !           184:     
        !           185:     /* Check for space.  There should be room for plenty of vifs,
        !           186:      * but we should check anyway.
        !           187:      */
        !           188:     if (numvifs > RSRR_MAX_VIFS) {
        !           189:        logit(LOG_WARNING, 0,
        !           190:            "Cannot send RSRR Route Reply because %d is too many vifs %d",
        !           191:            numvifs);
        !           192:        return;
        !           193:     }
        !           194:     
        !           195:     /* Set up message */
        !           196:     rsrr->version = 1;
        !           197:     rsrr->type = RSRR_INITIAL_REPLY;
        !           198:     rsrr->flags = 0;
        !           199:     rsrr->num = numvifs;
        !           200:     
        !           201:     vif_list = (struct rsrr_vif *)(rsrr_send_buf + RSRR_HEADER_LEN);
        !           202:     
        !           203:     /* Include the vif list. */
        !           204:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
        !           205:        vif_list[vifi].id = vifi;
        !           206:        vif_list[vifi].status = 0;
        !           207:        if (v->uv_flags & VIFF_DISABLED)
        !           208:            BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
        !           209:        vif_list[vifi].threshold = v->uv_threshold;
        !           210:        vif_list[vifi].local_addr = v->uv_lcl_addr;
        !           211:     }
        !           212:     
        !           213:     /* Get the size. */
        !           214:     sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
        !           215:     
        !           216:     /* Send it. */
        !           217:     IF_DEBUG(DEBUG_RSRR) {
        !           218:        logit(LOG_DEBUG, 0, "Send RSRR Initial Reply");
        !           219:     }
        !           220:     rsrr_send(sendlen);
        !           221: }
        !           222: 
        !           223: /* Send a Route Reply to the reservation protocol.  The Route Query
        !           224:  * contains the query to which we are responding.  The flags contain
        !           225:  * the incoming flags from the query or, for route change
        !           226:  * notification, the flags that should be set for the reply.  The
        !           227:  * kernel table entry contains the routing info to use for a route
        !           228:  * change notification.
        !           229:  */
        !           230: /* XXX: must modify if your routing table structure/search is different */
        !           231: static int rsrr_accept_rq(struct rsrr_rq *route_query, uint8_t flags, struct gtable *gt_notify)
        !           232: {
        !           233:     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
        !           234:     struct rsrr_rr *route_reply;
        !           235:     int sendlen;
        !           236:     struct gtable *gt;
        !           237:     int status_ok;
        !           238: #ifdef PIM
        !           239:     int found;
        !           240:     uint8_t tmp_flags;
        !           241:     rp_grp_entry_t *rp_grp_entry;
        !           242:     grpentry_t *grpentry_ptr;
        !           243: #else
        !           244:     struct gtable local_g;
        !           245:     struct rtentry *r;
        !           246:     uint32_t mcastgrp;
        !           247: #endif /* PIM */
        !           248:     
        !           249:     /* Set up message */
        !           250:     rsrr->version = 1;
        !           251:     rsrr->type = RSRR_ROUTE_REPLY;
        !           252:     rsrr->flags = flags;
        !           253:     rsrr->num = 0;
        !           254:     
        !           255:     route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
        !           256:     route_reply->dest_addr = route_query->dest_addr;
        !           257:     route_reply->source_addr = route_query->source_addr;
        !           258:     route_reply->query_id = route_query->query_id;
        !           259:     
        !           260:     /* Blank routing entry for error. */
        !           261:     route_reply->in_vif = 0;
        !           262:     route_reply->reserved = 0;
        !           263:     route_reply->out_vif_bm = 0;
        !           264:     
        !           265:     /* Get the size. */
        !           266:     sendlen = RSRR_RR_LEN;
        !           267:     
        !           268:     /* If routing table entry is defined, then we are sending a Route Reply
        !           269:      * due to a Route Change Notification event.  Use the routing table entry
        !           270:      * to supply the routing info.
        !           271:      */
        !           272:     status_ok = FALSE;
        !           273: #ifdef PIM
        !           274:     if (gt_notify) {
        !           275:        /* Include the routing entry. */
        !           276:        route_reply->in_vif = gt_notify->incoming;
        !           277:        route_reply->out_vif_bm = gt_notify->oifs;
        !           278:        gt = gt_notify;
        !           279:        status_ok = TRUE;
        !           280:     } else if ((gt = find_route(route_query->source_addr,
        !           281:                                route_query->dest_addr,
        !           282:                                MRTF_SG | MRTF_WC | MRTF_PMBR,
        !           283:                                DONT_CREATE)) != (struct gtable *)NULL) {
        !           284:        status_ok = TRUE;
        !           285:        route_reply->in_vif = gt->incoming;
        !           286:        route_reply->out_vif_bm = gt->oifs;
        !           287:     }
        !           288:     if (status_ok != TRUE) {
        !           289:        /* Set error bit. */
        !           290:        rsrr->flags = 0;
        !           291:        BIT_SET(rsrr->flags, RSRR_ERROR_BIT);
        !           292:     }
        !           293:     else {
        !           294:        if (gt->flags & (MRTF_WC | MRTF_PMBR)) {
        !           295:            tmp_flags = 0;
        !           296:            BIT_SET(tmp_flags, RSRR_THIS_SENDER_SHARED_TREE);
        !           297:            BIT_SET(tmp_flags, RSRR_ALL_SENDERS_SHARED_TREE);
        !           298:            if (!(flags & tmp_flags)) {
        !           299:                /* Check whether need to setup the (*,G) related flags */
        !           300:                found = FALSE;
        !           301:                if (gt->flags & MRTF_PMBR) {
        !           302:                    /* Check whether there is at least one (S,G) entry which is
        !           303:                     * a longer match than this (*,*,RP) entry.
        !           304:                     */
        !           305:                    for (rp_grp_entry = gt->source->cand_rp->rp_grp_next;
        !           306:                         rp_grp_entry != (rp_grp_entry_t *)NULL;
        !           307:                         rp_grp_entry = rp_grp_entry->rp_grp_next) {
        !           308:                        for (grpentry_ptr = rp_grp_entry->grplink;
        !           309:                             grpentry_ptr != (grpentry_t *)NULL;
        !           310:                             grpentry_ptr = grpentry_ptr->rpnext) {
        !           311:                            if (grpentry_ptr->mrtlink != (mrtentry_t *)NULL) {
        !           312:                                found = TRUE;
        !           313:                                break;
        !           314:                            }
        !           315:                        }
        !           316:                        if (found == TRUE)
        !           317:                            break;
        !           318:                    }
        !           319:                }
        !           320:                else if (gt->flags & MRTF_WC) {
        !           321:                    if (gt->group->mrtlink != (mrtentry_t *)NULL)
        !           322:                        found = TRUE;
        !           323:                }
        !           324:                if (found == TRUE) {
        !           325:                    RSRR_THIS_SENDER_SHARED_TREE_SOME_OTHER_NOT(rsrr->flags);
        !           326:                }
        !           327:                else {
        !           328:                    RSRR_SET_ALL_SENDERS_SHARED_TREE(rsrr->flags);
        !           329:                }
        !           330:            }
        !           331:        }
        !           332:        /* Cache reply if using route change notification. */
        !           333:        if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) {
        !           334:            /* TODO: XXX: Originally the rsrr_cache() call was first, but
        !           335:             * I think this is incorrect, because rsrr_cache() checks the
        !           336:             * rsrr_send_buf "flag" first.
        !           337:             */
        !           338:            BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT);
        !           339:            rsrr_cache(gt, route_query);
        !           340:        }
        !           341:     }
        !           342: #else /* Not PIM */
        !           343:     if (gt_notify) {
        !           344:        /* Set flags */
        !           345:        rsrr->flags = flags;
        !           346:        /* Include the routing entry. */
        !           347:        /* The original code from mrouted-3.9b2 */
        !           348:        route_reply->in_vif = gt_notify->gt_route->rt_parent;
        !           349:        /* TODO: XXX: bug? See the PIM code above */
        !           350:        if (BIT_TST(flags, RSRR_NOTIFICATION_BIT))
        !           351:            route_reply->out_vif_bm = gt_notify->gt_grpmems;
        !           352:        else
        !           353:            route_reply->out_vif_bm = 0;
        !           354:     } else if (find_src_grp(route_query->source_addr, 0,
        !           355:                            route_query->dest_addr)) {
        !           356: 
        !           357:        /* Found kernel entry. Code taken from add_table_entry() */
        !           358:        gt = gtp ? gtp->gt_gnext : kernel_table;
        !           359:        
        !           360:        /* Include the routing entry. */
        !           361:        route_reply->in_vif = gt->gt_route->rt_parent;
        !           362:        route_reply->out_vif_bm = gt->gt_grpmems;
        !           363:        
        !           364:        /* Cache reply if using route change notification. */
        !           365:        if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) {
        !           366:            /* TODO: XXX: Originally the rsrr_cache() call was first, but
        !           367:             * I think this is incorrect, because rsrr_cache() checks the
        !           368:             * rsrr_send_buf "flag" first.
        !           369:             */
        !           370:            BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT);
        !           371:            rsrr_cache(gt, route_query);
        !           372:        }
        !           373:     } else {
        !           374:        /* No kernel entry; use routing table. */
        !           375:        r = determine_route(route_query->source_addr);
        !           376:        
        !           377:        if (r != NULL) {
        !           378:            /* We need to mimic what will happen if a data packet
        !           379:             * is forwarded by multicast routing -- the kernel will
        !           380:             * make an upcall and mrouted will install a route in the kernel.
        !           381:             * Our outgoing vif bitmap should reflect what that table
        !           382:             * will look like.  Grab code from add_table_entry().
        !           383:             * This is gross, but it's probably better to be accurate.
        !           384:             */
        !           385:            
        !           386:            gt = &local_g;
        !           387:            mcastgrp = route_query->dest_addr;
        !           388:            
        !           389:            gt->gt_mcastgrp     = mcastgrp;
        !           390:            gt->gt_grpmems      = 0;
        !           391:            gt->gt_scope        = 0;
        !           392:            gt->gt_route        = r;
        !           393:            
        !           394:            /* obtain the multicast group membership list */
        !           395:            determine_forwvifs(gt);
        !           396:            
        !           397:            /* Include the routing entry. */
        !           398:            route_reply->in_vif = gt->gt_route->rt_parent;
        !           399:            route_reply->out_vif_bm = gt->gt_grpmems;
        !           400:        } else {
        !           401:            /* Set error bit. */
        !           402:            BIT_SET(rsrr->flags, RSRR_ERROR_BIT);
        !           403:        }
        !           404:     }
        !           405: #endif /* pimd - mrouted specific code */
        !           406:     
        !           407:     IF_DEBUG(DEBUG_RSRR) {
        !           408:        logit(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vif %d\n",
        !           409:              gt_notify ? "Route Change: " : "",
        !           410:              inet_fmt(route_reply->source_addr, s1, sizeof(s1)),
        !           411:              inet_fmt(route_reply->dest_addr, s2, sizeof(s2)),
        !           412:              route_reply->in_vif,route_reply->out_vif_bm);
        !           413:     }
        !           414: 
        !           415:     /* Send it. */
        !           416:     return rsrr_send(sendlen);
        !           417: }
        !           418: 
        !           419: /* Send an RSRR message. */
        !           420: static int rsrr_send(int sendlen)
        !           421: {
        !           422:     int error;
        !           423:     
        !           424:     while ((error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
        !           425:                           (struct sockaddr *)&client_addr, client_length)) < 0)
        !           426:     {
        !           427:        if (errno == EINTR)
        !           428:            continue;           /* Received signal, retry syscall. */
        !           429: 
        !           430:        logit(LOG_WARNING, errno, "Failed sendto() in rsrr_send()");
        !           431: 
        !           432:        return error;
        !           433:     } 
        !           434: 
        !           435:     if (error != sendlen)
        !           436:        logit(LOG_WARNING, 0, "Sent only %d out of %d bytes on RSRR socket", error, sendlen);
        !           437: 
        !           438:     return error;
        !           439: }
        !           440: 
        !           441: /* TODO: need to sort the rsrr_cache entries for faster access */
        !           442: /* Cache a message being sent to a client.  Currently only used for
        !           443:  * caching Route Reply messages for route change notification.
        !           444:  */
        !           445: static void rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query)
        !           446: {
        !           447:     struct rsrr_cache *rc, **rcnp;
        !           448:     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
        !           449: 
        !           450: #ifdef PIM
        !           451:     rcnp = &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>