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

1.1     ! misho       1: /*
        !             2:  *  Copyright (c) 1998 by the University of Oregon.
        !             3:  *  All rights reserved.
        !             4:  *
        !             5:  *  Permission to use, copy, modify, and distribute this software and
        !             6:  *  its documentation in source and binary forms for lawful
        !             7:  *  purposes and without fee is hereby granted, provided
        !             8:  *  that the above copyright notice appear in all copies and that both
        !             9:  *  the copyright notice and this permission notice appear in supporting
        !            10:  *  documentation, and that any documentation, advertising materials,
        !            11:  *  and other materials related to such distribution and use acknowledge
        !            12:  *  that the software was developed by the University of Oregon.
        !            13:  *  The name of the University of Oregon may not be used to endorse or 
        !            14:  *  promote products derived from this software without specific prior 
        !            15:  *  written permission.
        !            16:  *
        !            17:  *  THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
        !            18:  *  ABOUT 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, TITLE, AND 
        !            22:  *  NON-INFRINGEMENT.
        !            23:  *
        !            24:  *  IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
        !            25:  *  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
        !            26:  *  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
        !            27:  *  THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            28:  *
        !            29:  *  Other copyrights might apply to parts of this software and are so
        !            30:  *  noted when applicable.
        !            31:  */
        !            32: /*
        !            33:  *  Questions concerning this software should be directed to 
        !            34:  *  Kurt Windisch (kurtw@antc.uoregon.edu)
        !            35:  *
        !            36:  *  $Id: timer.c,v 1.21 1998/12/30 20:26:21 kurtw Exp $
        !            37:  */
        !            38: /*
        !            39:  * Part of this program has been derived from PIM sparse-mode pimd.
        !            40:  * The pimd program is covered by the license in the accompanying file
        !            41:  * named "LICENSE.pimd".
        !            42:  *  
        !            43:  * The pimd program is COPYRIGHT 1998 by University of Southern California.
        !            44:  *
        !            45:  * Part of this program has been derived from mrouted.
        !            46:  * The mrouted program is covered by the license in the accompanying file
        !            47:  * named "LICENSE.mrouted".
        !            48:  * 
        !            49:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
        !            50:  * Leland Stanford Junior University.
        !            51:  *
        !            52:  */
        !            53: 
        !            54: #include "defs.h"
        !            55: 
        !            56: 
        !            57: /*
        !            58:  * Global variables
        !            59:  */
        !            60: 
        !            61: /*
        !            62:  * Local functions definitions.
        !            63:  */
        !            64: 
        !            65: 
        !            66: /*
        !            67:  * Local variables
        !            68:  */
        !            69: u_int16 unicast_routing_timer;    /* Used to check periodically for any
        !            70:                                   * change in the unicast routing.
        !            71:                                   */
        !            72: u_int16 unicast_routing_check_interval;
        !            73: u_int8  ucast_flag;               /* Used to indicate there was a timeout */
        !            74: 
        !            75: 
        !            76: /* to request and compare any route changes */
        !            77: srcentry_t srcentry_save;
        !            78: 
        !            79: /*
        !            80:  * Init some timers
        !            81:  */
        !            82: void
        !            83: init_timers()
        !            84: {
        !            85:     unicast_routing_check_interval = UCAST_ROUTING_CHECK_INTERVAL;
        !            86:     SET_TIMER(unicast_routing_timer, unicast_routing_check_interval);
        !            87: 
        !            88:     /* Initialize the srcentry used to save the old routes
        !            89:      * during unicast routing change discovery process.
        !            90:      */
        !            91:     srcentry_save.prev       = (srcentry_t *)NULL;
        !            92:     srcentry_save.next       = (srcentry_t *)NULL;
        !            93:     srcentry_save.address    = INADDR_ANY_N;
        !            94:     srcentry_save.mrtlink    = (mrtentry_t *)NULL;
        !            95:     srcentry_save.incoming   = NO_VIF;
        !            96:     srcentry_save.upstream   = (pim_nbr_entry_t *)NULL;
        !            97:     srcentry_save.metric     = ~0;
        !            98:     srcentry_save.preference = ~0;
        !            99:     RESET_TIMER(srcentry_save.timer);
        !           100: 
        !           101: }
        !           102: 
        !           103: 
        !           104: /*
        !           105:  * On every timer interrupt, advance (i.e. decrease) the timer for each
        !           106:  * neighbor and group entry for each vif.
        !           107:  */
        !           108: void
        !           109: age_vifs()
        !           110: {
        !           111:     vifi_t vifi;
        !           112:     register struct uvif *v;
        !           113:     register pim_nbr_entry_t *next_nbr, *curr_nbr;
        !           114: 
        !           115: /* XXX: TODO: currently, sending to qe* interface which is DOWN
        !           116:  * doesn't return error (ENETDOWN) on my Solaris machine,
        !           117:  * so have to check periodically the 
        !           118:  * interfaces status. If this is fixed, just remove the defs around
        !           119:  * the "if (vifs_down)" line.
        !           120:  */
        !           121: 
        !           122: #if (!((defined SunOS) && (SunOS >= 50)))
        !           123:     if (vifs_down)
        !           124: #endif /* Solaris */
        !           125:        check_vif_state();
        !           126: 
        !           127:     /* Age many things */
        !           128:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
        !           129:        if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
        !           130:            continue;
        !           131:        /* Timeout neighbors */
        !           132:        for (curr_nbr = v->uv_pim_neighbors; curr_nbr != NULL;
        !           133:             curr_nbr = next_nbr) {
        !           134:            next_nbr = curr_nbr->next;
        !           135:            /*
        !           136:             * Never timeout neighbors with holdtime = 0xffff.
        !           137:             * This may be used with ISDN lines to avoid keeping the
        !           138:             * link up with periodic Hello messages.
        !           139:             */
        !           140:            /* TODO: XXX: TIMER implem. dependency! */
        !           141:            if (PIM_MESSAGE_HELLO_HOLDTIME_FOREVER == curr_nbr->timer)
        !           142:                continue;
        !           143:            IF_NOT_TIMEOUT(curr_nbr->timer)
        !           144:                continue;
        !           145: 
        !           146:            delete_pim_nbr(curr_nbr);
        !           147:        }
        !           148:        
        !           149:        /* PIM_HELLO periodic */
        !           150:        IF_TIMEOUT(v->uv_pim_hello_timer)
        !           151:            send_pim_hello(v, PIM_TIMER_HELLO_HOLDTIME);
        !           152: 
        !           153:        /* IGMP query periodic */
        !           154:        IF_TIMEOUT(v->uv_gq_timer)
        !           155:            query_groups(v);
        !           156:     }
        !           157: 
        !           158:     IF_DEBUG(DEBUG_IF)
        !           159:        dump_vifs(stderr);
        !           160: }
        !           161: 
        !           162: 
        !           163: /*
        !           164:  * Scan the whole routing table and timeout a bunch of timers:
        !           165:  *  - prune timers
        !           166:  *  - Join/Prune delay timer
        !           167:  *  - routing entry
        !           168:  *  - Assert timer
        !           169:  */
        !           170: void
        !           171: age_routes()
        !           172: {
        !           173:     mrtentry_t *mrtentry_ptr, *mrtentry_next;
        !           174:     grpentry_t *grpentry_ptr, *grpentry_next;
        !           175:     vifi_t  vifi;
        !           176:     int change_flag, state_change;
        !           177:     int update_src_iif;
        !           178:     u_long curr_bytecnt;
        !           179: 
        !           180:     /*
        !           181:      * Timing out of the global `unicast_routing_timer` and data rate timer
        !           182:      */
        !           183:    IF_TIMEOUT(unicast_routing_timer) {
        !           184:        ucast_flag = TRUE;
        !           185:        SET_TIMER(unicast_routing_timer, unicast_routing_check_interval);
        !           186:     }
        !           187:     ELSE {
        !           188:        ucast_flag = FALSE;
        !           189:     }
        !           190: 
        !           191:     /* Walk the the (S,G) entries */
        !           192:     if(grplist == (grpentry_t *)NULL) 
        !           193:        return;
        !           194:     for(grpentry_ptr = grplist;
        !           195:        grpentry_ptr != (grpentry_t *)NULL; 
        !           196:        grpentry_ptr = grpentry_next) {
        !           197:        grpentry_next = grpentry_ptr->next;
        !           198: 
        !           199:        for(mrtentry_ptr = grpentry_ptr->mrtlink; 
        !           200:            mrtentry_ptr != (mrtentry_t *)NULL; 
        !           201:            mrtentry_ptr = mrtentry_next) {
        !           202: 
        !           203:            int mrtentry_is_timedout;
        !           204:            u_int16 mrtentry_timeout;
        !           205:            u_int16 prune_timeout;
        !           206:            u_int16 min_prune_timeout;
        !           207: 
        !           208:            mrtentry_next = mrtentry_ptr->grpnext;
        !           209: 
        !           210:            /* Age the entry timer */
        !           211:            /* TODO: XXX: TIMER implem. dependency! */
        !           212:            COPY_TIMER(mrtentry_ptr->timer, mrtentry_timeout);
        !           213:            mrtentry_is_timedout = TIMEOUT(mrtentry_ptr->timer);
        !           214:          
        !           215:            /* Refresh entry timer if data forwarded */
        !           216:            curr_bytecnt = mrtentry_ptr->sg_count.bytecnt;
        !           217:            if (k_get_sg_cnt(udp_socket,
        !           218:                             mrtentry_ptr->source->address,
        !           219:                             mrtentry_ptr->group->group,
        !           220:                             &mrtentry_ptr->sg_count)) {
        !           221:                /* No such routing entry in kernel */
        !           222:                delete_mrtentry(mrtentry_ptr);
        !           223:                continue;
        !           224:            }
        !           225:            if(!(VIFM_ISEMPTY(mrtentry_ptr->oifs)) && 
        !           226:               curr_bytecnt != mrtentry_ptr->sg_count.bytecnt) {
        !           227:                /* Packets have been forwarded - refresh timer
        !           228:                 * Note that these counters count packets received, 
        !           229:                 * not packets forwarded.  So only refresh if packets
        !           230:                 * received and non-null oiflist.
        !           231:                 */
        !           232:                IF_DEBUG(DEBUG_MFC)
        !           233:                    log(LOG_DEBUG, 0, 
        !           234:                        "Refreshing src %s, dst %s after %d bytes forwarded",
        !           235:                        inet_fmt(mrtentry_ptr->source->address, s1), 
        !           236:                        inet_fmt(mrtentry_ptr->group->group, s2), 
        !           237:                        mrtentry_ptr->sg_count.bytecnt); 
        !           238:                SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT);
        !           239:                mrtentry_is_timedout = FALSE;
        !           240:            }       
        !           241: 
        !           242:            /* Time out asserts */
        !           243:            if(mrtentry_ptr->flags & MRTF_ASSERTED) 
        !           244:                IF_TIMEOUT(mrtentry_ptr->assert_timer) {
        !           245:                    mrtentry_ptr->flags &= ~MRTF_ASSERTED;
        !           246:                    mrtentry_ptr->upstream = mrtentry_ptr->source->upstream;
        !           247:                    mrtentry_ptr->metric   = mrtentry_ptr->source->metric;
        !           248:                    mrtentry_ptr->preference = mrtentry_ptr->source->preference;
        !           249:                }
        !           250: 
        !           251:            /* Time out Pruned interfaces */
        !           252:            change_flag = FALSE;
        !           253:            min_prune_timeout = 0x7fff;
        !           254:            for (vifi = 0; vifi < numvifs; vifi++) {
        !           255:                COPY_TIMER(mrtentry_ptr->prune_timers[vifi], prune_timeout);
        !           256:                if (VIFM_ISSET(vifi, mrtentry_ptr->pruned_oifs))
        !           257:                    IF_TIMEOUT(mrtentry_ptr->prune_timers[vifi]) {
        !           258:                        /* TODO: XXX: TIMER implem. dependency! */
        !           259:                        if(prune_timeout < min_prune_timeout) 
        !           260:                            min_prune_timeout = prune_timeout;
        !           261:                        VIFM_CLR(vifi, mrtentry_ptr->pruned_oifs);
        !           262:                        RESET_TIMER(mrtentry_ptr->prune_timers[vifi]);
        !           263:                        change_flag = TRUE;
        !           264:                    }
        !           265:            }
        !           266:            
        !           267:            /* Unicast Route changes */
        !           268:            update_src_iif = FALSE;
        !           269:            if (ucast_flag == TRUE) {
        !           270:                /* iif toward the source */
        !           271:                srcentry_save.incoming = mrtentry_ptr->source->incoming;
        !           272:                srcentry_save.upstream = mrtentry_ptr->source->upstream;
        !           273:                srcentry_save.preference = mrtentry_ptr->source->preference;
        !           274:                srcentry_save.metric = mrtentry_ptr->source->metric;
        !           275:                
        !           276:                if (set_incoming(mrtentry_ptr->source,
        !           277:                                 PIM_IIF_SOURCE) != TRUE) {
        !           278:                    /*
        !           279:                     * XXX: not in the spec!
        !           280:                     * Cannot find route toward that source.
        !           281:                     * This is bad. Delete the entry.
        !           282:                     */
        !           283:                    delete_mrtentry(mrtentry_ptr);
        !           284:                    continue;
        !           285:                }
        !           286:                else {
        !           287:                    /* iif info found */
        !           288:                    if (!(mrtentry_ptr->flags & MRTF_ASSERTED) && 
        !           289:                        ((srcentry_save.incoming !=
        !           290:                          mrtentry_ptr->incoming)
        !           291:                         || (srcentry_save.upstream !=
        !           292:                             mrtentry_ptr->upstream))) {
        !           293:                        /* Route change has occur */
        !           294:                        update_src_iif = TRUE;
        !           295:                        mrtentry_ptr->incoming =
        !           296:                            mrtentry_ptr->source->incoming;
        !           297:                        mrtentry_ptr->upstream =
        !           298:                            mrtentry_ptr->source->upstream;
        !           299:                        /* mrtentry should have pref/metric of upstream
        !           300:                         * assert winner, but we dont have that info,
        !           301:                         * so use the source pref/metric, which will be
        !           302:                         * larger and thus the correct assert winner
        !           303:                         * from upstream will be chosen.
        !           304:                         */
        !           305:                        mrtentry_ptr->preference = 
        !           306:                            mrtentry_ptr->source->preference;
        !           307:                        mrtentry_ptr->metric = 
        !           308:                            mrtentry_ptr->source->metric;
        !           309:                    }
        !           310:                }
        !           311:            }
        !           312:            
        !           313:            /* Do the interface changes if the mrt is still alive
        !           314:             * or if a prune timed out before the mrt
        !           315:             */
        !           316:            /* TODO: XXX: TIMER implem. dependency! */
        !           317:            if ((mrtentry_is_timedout &&
        !           318:                 min_prune_timeout <= mrtentry_timeout)
        !           319:                || 
        !           320:                (!mrtentry_is_timedout && 
        !           321:                 (change_flag == TRUE || update_src_iif == TRUE))) {
        !           322:                /* Flush the changes */
        !           323:                state_change = 
        !           324:                    change_interfaces(mrtentry_ptr,
        !           325:                                      mrtentry_ptr->incoming,
        !           326:                                      mrtentry_ptr->pruned_oifs,
        !           327:                                      mrtentry_ptr->leaves);
        !           328:                if(state_change == -1)
        !           329:                    trigger_prune_alert(mrtentry_ptr);
        !           330:                if(state_change == 1) 
        !           331:                    trigger_join_alert(mrtentry_ptr);
        !           332:            }
        !           333:            
        !           334:            /* Time out the entry */
        !           335:            IF_TIMER_NOT_SET(mrtentry_ptr->timer) {
        !           336:                delete_mrtentry(mrtentry_ptr);
        !           337:                continue;
        !           338:            }
        !           339:        }
        !           340:     }
        !           341: 
        !           342:     IF_DEBUG(DEBUG_PIM_MRT)
        !           343:        dump_pim_mrt(stderr);
        !           344:     return;
        !           345: }

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