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