Annotation of embedaddon/pimd/timer.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) 1998-2001
                      3:  * 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:  *  $Id: timer.c,v 1.31 2001/09/10 20:31:37 pavlin Exp $
                     32:  */
                     33: 
                     34: 
                     35: #include "defs.h"
                     36: 
                     37: /*
                     38:  * Global variables
                     39:  */
                     40: 
                     41: /* To account for header overhead, we apx 1 byte/s = 10 bits/s (bps)
                     42:  * Note, in the new spt_threshold setting the rate is in kbps as well! */
                     43: spt_threshold_t spt_threshold = {
                     44:     .mode     = SPT_THRESHOLD_DEFAULT_MODE,
                     45:     .bytes    = SPT_THRESHOLD_DEFAULT_RATE * SPT_THRESHOLD_DEFAULT_INTERVAL / 10 * 1000,
                     46:     .packets  = SPT_THRESHOLD_DEFAULT_PACKETS,
                     47:     .interval = SPT_THRESHOLD_DEFAULT_INTERVAL,
                     48: };
                     49: 
                     50: /*
                     51:  * Local variables
                     52:  */
                     53: uint16_t unicast_routing_interval = UCAST_ROUTING_CHECK_INTERVAL;
                     54: uint16_t unicast_routing_timer;   /* Used to check periodically for any
                     55:                                   * change in the unicast routing. */
                     56: uint8_t ucast_flag;
                     57: 
                     58: uint16_t pim_spt_threshold_timer; /* Used for periodic check of spt-threshold
                     59:                                   * for the RP or the lasthop router. */
                     60: uint8_t rate_flag;
                     61: 
                     62: /*
                     63:  * TODO: XXX: the timers below are not used. Instead, the data rate timer is used.
                     64:  */
                     65: uint16_t kernel_cache_timer;      /* Used to timeout the kernel cache
                     66:                                   * entries for idle sources */
                     67: uint16_t kernel_cache_interval;
                     68: 
                     69: /* to request and compare any route changes */
                     70: srcentry_t srcentry_save;
                     71: rpentry_t  rpentry_save;
                     72: 
                     73: /*
                     74:  * Init some timers
                     75:  */
                     76: void init_timers(void)
                     77: {
                     78:     SET_TIMER(unicast_routing_timer, unicast_routing_interval);
                     79:     SET_TIMER(pim_spt_threshold_timer, spt_threshold.interval);
                     80: 
                     81:     /* Initialize the srcentry and rpentry used to save the old routes
                     82:      * during unicast routing change discovery process. */
                     83:     srcentry_save.prev       = NULL;
                     84:     srcentry_save.next       = NULL;
                     85:     srcentry_save.address    = INADDR_ANY_N;
                     86:     srcentry_save.mrtlink    = NULL;
                     87:     srcentry_save.incoming   = NO_VIF;
                     88:     srcentry_save.upstream   = NULL;
                     89:     srcentry_save.metric     = ~0;
                     90:     srcentry_save.preference = ~0;
                     91:     RESET_TIMER(srcentry_save.timer);
                     92:     srcentry_save.cand_rp    = NULL;
                     93: 
                     94:     rpentry_save.prev       = NULL;
                     95:     rpentry_save.next       = NULL;
                     96:     rpentry_save.address    = INADDR_ANY_N;
                     97:     rpentry_save.mrtlink    = NULL;
                     98:     rpentry_save.incoming   = NO_VIF;
                     99:     rpentry_save.upstream   = NULL;
                    100:     rpentry_save.metric     = ~0;
                    101:     rpentry_save.preference = ~0;
                    102:     RESET_TIMER(rpentry_save.timer);
                    103:     rpentry_save.cand_rp    = NULL;
                    104: }
                    105: 
                    106: /*
                    107:  * On every timer interrupt, advance (i.e. decrease) the timer for each
                    108:  * neighbor and group entry for each vif.
                    109:  */
                    110: void age_vifs(void)
                    111: {
                    112:     vifi_t           vifi;
                    113:     struct uvif     *v;
                    114:     pim_nbr_entry_t *next, *curr;
                    115: 
                    116:     /* XXX: TODO: currently, sending to qe* interface which is DOWN
                    117:      * doesn't return error (ENETDOWN) on my Solaris machine,
                    118:      * so have to check periodically the
                    119:      * interfaces status. If this is fixed, just remove the defs around
                    120:      * the "if (vifs_down)" line.
                    121:      */
                    122: 
                    123: #if (!((defined SunOS) && (SunOS >= 50)))
                    124:     if (vifs_down)
                    125: #endif /* Solaris */
                    126:        check_vif_state();
                    127: 
                    128:     /* Age many things */
                    129:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                    130:        if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER))
                    131:            continue;
                    132: 
                    133:        /* Timeout neighbors */
                    134:        for (curr = v->uv_pim_neighbors; curr; curr = next) {
                    135:            next = curr->next;
                    136: 
                    137:            /* Never timeout neighbors with holdtime = 0xffff.
                    138:             * This may be used with ISDN lines to avoid keeping the
                    139:             * link up with periodic Hello messages.
                    140:             */
                    141:            /* TODO: XXX: TIMER implem. dependency! */
                    142:            if (PIM_HELLO_HOLDTIME_FOREVER == curr->timer)
                    143:                continue;
                    144:            IF_NOT_TIMEOUT(curr->timer)
                    145:                continue;
                    146: 
                    147:            logit(LOG_INFO, 0, "Delete PIM neighbor %s on %s (holdtime timeout)",
                    148:                  inet_fmt(curr->address, s2, sizeof(s2)), v->uv_name);
                    149: 
                    150:            delete_pim_nbr(curr);
                    151:        }
                    152: 
                    153:        /* PIM_HELLO periodic */
                    154:        IF_TIMEOUT(v->uv_hello_timer)
                    155:            send_pim_hello(v, pim_timer_hello_holdtime);
                    156: 
                    157: #ifdef TOBE_DELETED
                    158:        /* PIM_JOIN_PRUNE periodic */
                    159:        /* TODO: XXX: TIMER implem. dependency! */
                    160:        if (v->uv_jp_timer <= TIMER_INTERVAL)
                    161:            /* TODO: need to scan the whole routing table,
                    162:             * because different entries have different Join/Prune timer.
                    163:             * Probably don't need the Join/Prune timer per vif.
                    164:             */
                    165:            send_pim_join_prune(vifi, NULL, PIM_JOIN_PRUNE_HOLDTIME);
                    166:        else
                    167:            /* TODO: XXX: TIMER implem. dependency! */
                    168:            v->uv_jp_timer -= TIMER_INTERVAL;
                    169: #endif /* TOBE_DELETED */
                    170: 
                    171:        /* IGMP query periodic */
                    172:        IF_TIMEOUT(v->uv_gq_timer)
                    173:            query_groups(v);
                    174: 
                    175:        if (v->uv_querier &&
                    176:            (v->uv_querier->al_timer += TIMER_INTERVAL) > igmp_querier_timeout) {
                    177:            /*
                    178:             * The current querier has timed out.  We must become the
                    179:             * querier.
                    180:             */
                    181:            IF_DEBUG(DEBUG_IGMP) {
                    182:                logit(LOG_DEBUG, 0, "IGMP Querier %s timed out.",
                    183:                      inet_fmt(v->uv_querier->al_addr, s1, sizeof(s1)));
                    184:            }
                    185:            free(v->uv_querier);
                    186:            v->uv_querier = NULL;
                    187:            v->uv_flags |= VIFF_QUERIER;
                    188:            query_groups(v);
                    189:        }
                    190:     }
                    191: 
                    192:     IF_DEBUG(DEBUG_IF) {
                    193:        fputs("\n", stderr);
                    194:        dump_vifs(stderr);
                    195:     }
                    196: }
                    197: 
                    198: #define MRT_IS_LASTHOP(mrt) VIFM_LASTHOP_ROUTER(mrt->leaves, mrt->oifs)
                    199: #define MRT_IS_RP(mrt)      mrt->incoming == reg_vif_num
                    200: 
                    201: static void try_switch_to_spt(mrtentry_t *mrt, kernel_cache_t *kc)
                    202: {
                    203:     if (MRT_IS_LASTHOP(mrt) || MRT_IS_RP(mrt)) {
                    204: #ifdef KERNEL_MFC_WC_G
                    205:        if (kc->source == INADDR_ANY_N) {
                    206:            delete_single_kernel_cache(mrt, kc);
                    207:            mrt->flags |= MRTF_MFC_CLONE_SG;
                    208:            return;
                    209:        }
                    210: #endif /* KERNEL_MFC_WC_G */
                    211: 
                    212:        switch_shortest_path(kc->source, kc->group);
                    213:     }
                    214: }
                    215: 
                    216: /*
                    217:  * Check the SPT threshold for a given (*,*,RP) or (*,G) entry
                    218:  *
                    219:  * XXX: the spec says to start monitoring first the total traffic for
                    220:  * all senders for particular (*,*,RP) or (*,G) and if the total traffic
                    221:  * exceeds some predefined threshold, then start monitoring the data
                    222:  * traffic for each particular sender for this group: (*,G) or
                    223:  * (*,*,RP). However, because the kernel cache/traffic info is of the
                    224:  * form (S,G), it is easier if we are simply collecting (S,G) traffic
                    225:  * all the time.
                    226:  *
                    227:  * For (*,*,RP) if the number of bytes received between the last check
                    228:  * and now exceeds some precalculated value (based on interchecking
                    229:  * period and datarate threshold AND if there are directly connected
                    230:  * members (i.e. we are their last hop(e) router), then create (S,G) and
                    231:  * start initiating (S,G) Join toward the source. The same applies for
                    232:  * (*,G).  The spec does not say that if the datarate goes below a given
                    233:  * threshold, then will switch back to the shared tree, hence after a
                    234:  * switch to the source-specific tree occurs, a source with low
                    235:  * datarate, but periodically sending will keep the (S,G) states.
                    236:  *
                    237:  * If a source with kernel cache entry has been idle after the last time
                    238:  * a check of the datarate for the whole routing table, then delete its
                    239:  * kernel cache entry.
                    240:  */
                    241: static void check_spt_threshold(mrtentry_t *mrt)
                    242: {
                    243:     int status;
                    244:     uint32_t prev_bytecnt, prev_pktcnt;
                    245:     kernel_cache_t *kc, *kc_next;
                    246: 
                    247:     /* XXX: TODO: When we add group-list support to spt-threshold we need
                    248:      * to move this infinity check to inside the for-loop ... obviously. */
                    249:     if (!rate_flag || spt_threshold.mode == SPT_INF)
                    250:        return;
                    251: 
                    252:     for (kc = mrt->kernel_cache; kc; kc = kc_next) {
                    253:        kc_next = kc->next;
                    254: 
                    255:        prev_bytecnt = kc->sg_count.bytecnt;
                    256:        prev_pktcnt  = kc->sg_count.pktcnt;
                    257: 
                    258:        status = k_get_sg_cnt(udp_socket, kc->source, kc->group, &kc->sg_count);
                    259:        if (status || prev_bytecnt == kc->sg_count.bytecnt) {
                    260:            /* Either (for whatever reason) there is no such routing
                    261:             * entry, or that particular (S,G) was idle.  Delete the
                    262:             * routing entry from the kernel. */
                    263:            delete_single_kernel_cache(mrt, kc);
                    264:            continue;
                    265:        }
                    266: 
                    267:        // TODO: Why is this needed?
                    268:        try_switch_to_spt(mrt, kc);
                    269: 
                    270:        /* Check spt-threshold for forwarder and RP, should we switch to
                    271:         * source specific tree (SPT).  Need to check only when we have
                    272:         * (S,G)RPbit in the forwarder or the RP itself. */
                    273:        switch (spt_threshold.mode) {
                    274:            case SPT_RATE:
                    275:                if (prev_bytecnt + spt_threshold.bytes < kc->sg_count.bytecnt)
                    276:                    try_switch_to_spt(mrt, kc);
                    277:                break;
                    278: 
                    279:            case SPT_PACKETS:
                    280:                if (prev_pktcnt + spt_threshold.packets < kc->sg_count.pktcnt)
                    281:                    try_switch_to_spt(mrt, kc);
                    282:                break;
                    283: 
                    284:            default:
                    285:                ;               /* INF not handled here yet. */
                    286:        }
                    287: 
                    288:        /* XXX: currently the spec doesn't say to switch back to the
                    289:         * shared tree if low datarate, but if needed to implement, the
                    290:         * check must be done here. Don't forget to check whether I am a
                    291:         * forwarder for that source. */
                    292:     }
                    293: }
                    294: 
                    295: 
                    296: /*
                    297:  * Scan the whole routing table and timeout a bunch of timers:
                    298:  *  - oifs timers
                    299:  *  - Join/Prune timer
                    300:  *  - routing entry
                    301:  *  - Assert timer
                    302:  *  - Register-Suppression timer
                    303:  *
                    304:  *  - If the global timer for checking the unicast routing has expired, perform
                    305:  *  also iif/upstream router change verification
                    306:  *  - If the global timer for checking the data rate has expired, check the
                    307:  *  number of bytes forwarded after the lastest timeout. If bigger than
                    308:  *  a given threshold, then switch to the shortest path.
                    309:  *  If `number_of_bytes == 0`, then delete the kernel cache entry.
                    310:  *
                    311:  * Only the entries which have the Join/Prune timer expired are sent.
                    312:  * In the special case when we have ~(S,G)RPbit Prune entry, we must
                    313:  * include any (*,G) or (*,*,RP) XXX: ???? what and why?
                    314:  *
                    315:  * Below is a table which summarizes the segmantic rules.
                    316:  *
                    317:  * On the left side is "if A must be included in the J/P message".
                    318:  * On the top is "shall/must include B?"
                    319:  * "Y" means "MUST include"
                    320:  * "SY" means "SHOULD include"
                    321:  * "N" means  "NO NEED to include"
                    322:  * (G is a group that matches to RP)
                    323:  *
                    324:  *              -----------||-----------||-----------
                    325:  *            ||  (*,*,RP) ||   (*,G)   ||   (S,G)   ||
                    326:  *            ||-----------||-----------||-----------||
                    327:  *            ||  J  |  P  ||  J  |  P  ||  J  |  P  ||
                    328:  * ==================================================||
                    329:  *          J || n/a | n/a ||  N  |  Y  ||  N  |  Y  ||
                    330:  * (*,*,RP) -----------------------------------------||
                    331:  *          P || n/a | n/a ||  SY |  N  ||  SY |  N  ||
                    332:  * ==================================================||
                    333:  *          J ||  N  |  N  || n/a | n/a ||  N  |  Y  ||
                    334:  *   (*,G)  -----------------------------------------||
                    335:  *          P ||  N  |  N  || n/a | n/a ||  SY |  N  ||
                    336:  * ==================================================||
                    337:  *          J ||  N  |  N  ||  N  |  N  || n/a | n/a ||
                    338:  *   (S,G)  -----------------------------------------||
                    339:  *          P ||  N  |  N  ||  N  |  N  || n/a | n/a ||
                    340:  * ==================================================
                    341:  *
                    342:  */
                    343: void age_routes(void)
                    344: {
                    345:     cand_rp_t  *cand_rp;
                    346:     grpentry_t *grp;
                    347:     grpentry_t *grp_next;
                    348:     mrtentry_t *mrt_grp;
                    349:     mrtentry_t *mrt_rp;
                    350:     mrtentry_t *mrt_wide;
                    351:     mrtentry_t *mrt_srcs;
                    352:     mrtentry_t *mrt_srcs_next;
                    353:     rp_grp_entry_t *rp_grp;
                    354:     struct uvif *v;
                    355:     vifi_t  vifi;
                    356:     pim_nbr_entry_t *nbr;
                    357:     int change_flag;
                    358:     int rp_action, grp_action, src_action = PIM_ACTION_NOTHING, src_action_rp = PIM_ACTION_NOTHING;
                    359:     int dont_calc_action;
                    360:     rpentry_t *rp;
                    361:     int update_rp_iif;
                    362:     int update_src_iif;
                    363:     vifbitmap_t new_pruned_oifs;
                    364:     int assert_timer_expired = 0;
                    365: 
                    366:     /*
                    367:      * Timing out of the global `unicast_routing_timer`
                    368:      * and `data_rate_timer`
                    369:      */
                    370:     IF_TIMEOUT(unicast_routing_timer) {
                    371:        ucast_flag = TRUE;
                    372:        SET_TIMER(unicast_routing_timer, unicast_routing_interval);
                    373:     }
                    374:     ELSE {
                    375:        ucast_flag = FALSE;
                    376:     }
                    377: 
                    378:     IF_TIMEOUT(pim_spt_threshold_timer) {
                    379:        rate_flag = TRUE;
                    380:        SET_TIMER(pim_spt_threshold_timer, spt_threshold.interval);
                    381:     }
                    382:     ELSE {
                    383:        rate_flag = FALSE;
                    384:     }
                    385: 
                    386:     /* Scan the (*,*,RP) entries */
                    387:     for (cand_rp = cand_rp_list; cand_rp; cand_rp = cand_rp->next) {
                    388:        rp = cand_rp->rpentry;
                    389: 
                    390:        /* Need to save only `incoming` and `upstream` to discover
                    391:         * unicast route changes. `metric` and `preference` are not
                    392:         * interesting for us.
                    393:         */
                    394:        rpentry_save.incoming = rp->incoming;
                    395:        rpentry_save.upstream = rp->upstream;
                    396: 
                    397:        update_rp_iif = FALSE;
                    398:        if ((ucast_flag == TRUE) && (rp->address != my_cand_rp_address)) {
                    399:            /* I am not the RP. If I was the RP, then the iif is
                    400:             * register_vif and no need to reset it. */
                    401:            if (set_incoming(rp, PIM_IIF_RP) != TRUE) {
                    402:                /* TODO: XXX: no route to that RP. Panic? There is a high
                    403:                 * probability the network is partitioning so immediately
                    404:                 * remapping to other RP is not a good idea. Better wait
                    405:                 * the Bootstrap mechanism to take care of it and provide
                    406:                 * me with correct Cand-RP-Set. */
                    407:            }
                    408:            else {
                    409:                if ((rpentry_save.upstream != rp->upstream) ||
                    410:                    (rpentry_save.incoming != rp->incoming)) {
                    411:                    /* Routing change has occur. Update all (*,G)
                    412:                     * and (S,G)RPbit iifs mapping to that RP */
                    413:                    update_rp_iif = TRUE;
                    414:                }
                    415:            }
                    416:        }
                    417: 
                    418:        rp_action = PIM_ACTION_NOTHING;
                    419:        mrt_rp = cand_rp->rpentry->mrtlink;
                    420:        if (mrt_rp) {
                    421:            /* outgoing interfaces timers */
                    422:            change_flag = FALSE;
                    423:            for (vifi = 0; vifi < numvifs; vifi++) {
                    424:                if (VIFM_ISSET(vifi, mrt_rp->joined_oifs)) {
                    425:                    IF_TIMEOUT(mrt_rp->vif_timers[vifi]) {
                    426:                        VIFM_CLR(vifi, mrt_rp->joined_oifs);
                    427:                        change_flag = TRUE;
                    428:                    }
                    429:                }
                    430:            }
                    431:            if ((change_flag == TRUE) || (update_rp_iif == TRUE)) {
                    432:                change_interfaces(mrt_rp,
                    433:                                  rp->incoming,
                    434:                                  mrt_rp->joined_oifs,
                    435:                                  mrt_rp->pruned_oifs,
                    436:                                  mrt_rp->leaves,
                    437:                                  mrt_rp->asserted_oifs, 0);
                    438:                mrt_rp->upstream = rp->upstream;
                    439:            }
                    440: 
                    441:            /* Check the activity for this entry */
                    442:            check_spt_threshold(mrt_rp);
                    443: 
                    444:            /* Join/Prune timer */
                    445:            IF_TIMEOUT(mrt_rp->jp_timer) {
                    446:                rp_action = join_or_prune(mrt_rp, mrt_rp->upstream);
                    447: 
                    448:                if (rp_action != PIM_ACTION_NOTHING)
                    449:                    add_jp_entry(mrt_rp->upstream,
                    450:                                 PIM_JOIN_PRUNE_HOLDTIME,
                    451:                                 htonl(CLASSD_PREFIX),
                    452:                                 STAR_STAR_RP_MSKLEN,
                    453:                                 mrt_rp->source->address,
                    454:                                 SINGLE_SRC_MSKLEN,
                    455:                                 MRTF_RP | MRTF_WC,
                    456:                                 rp_action);
                    457: 
                    458:                SET_TIMER(mrt_rp->jp_timer, PIM_JOIN_PRUNE_PERIOD);
                    459:            }
                    460: 
                    461:            /* Assert timer */
                    462:            if (mrt_rp->flags & MRTF_ASSERTED) {
                    463:                IF_TIMEOUT(mrt_rp->assert_timer) {
                    464:                    /* TODO: XXX: reset the upstream router now */
                    465:                    mrt_rp->flags &= ~MRTF_ASSERTED;
                    466:                }
                    467:            }
                    468: 
                    469:            /* Register-Suppression timer */
                    470:            /* TODO: to reduce the kernel calls, if the timer is running,
                    471:             * install a negative cache entry in the kernel?
                    472:             */
                    473:            /* TODO: can we have Register-Suppression timer for (*,*,RP)?
                    474:             * Currently no...
                    475:             */
                    476:            IF_TIMEOUT(mrt_rp->rs_timer) {}
                    477: 
                    478:            /* routing entry */
                    479:            if ((TIMEOUT(mrt_rp->timer)) && (VIFM_ISEMPTY(mrt_rp->leaves)))
                    480:                delete_mrtentry(mrt_rp);
                    481:        } /* if (mrt_rp) */
                    482: 
                    483:        /* Just in case if that (*,*,RP) was deleted */
                    484:        mrt_rp = cand_rp->rpentry->mrtlink;
                    485: 
                    486:        /* Check the (*,G) and (S,G) entries */
                    487:        for (rp_grp = cand_rp->rp_grp_next; rp_grp; rp_grp = rp_grp->rp_grp_next) {
                    488:            for (grp = rp_grp->grplink; grp; grp = grp_next) {
                    489:                grp_next   = grp->rpnext;
                    490:                grp_action = PIM_ACTION_NOTHING;
                    491:                mrt_grp    = grp->grp_route;
                    492:                mrt_srcs   = grp->mrtlink;
                    493: 
                    494:                if (mrt_grp) {
                    495:                    /* The (*,G) entry */
                    496:                    /* outgoing interfaces timers */
                    497:                    change_flag = FALSE;
                    498:                    assert_timer_expired = 0;
                    499:                    if (mrt_grp->flags & MRTF_ASSERTED)
                    500:                        assert_timer_expired = TIMEOUT(mrt_grp->assert_timer);
                    501: 
                    502:                    for (vifi = 0; vifi < numvifs; vifi++) {
                    503:                        if (VIFM_ISSET(vifi, mrt_grp->joined_oifs)) {
                    504:                            IF_TIMEOUT(mrt_grp->vif_timers[vifi]) {
                    505:                                VIFM_CLR(vifi, mrt_grp->joined_oifs);
                    506:                                change_flag = TRUE;
                    507:                            }
                    508:                        }
                    509: 
                    510:                        if (assert_timer_expired) {
                    511:                            VIFM_CLR(vifi, mrt_grp->asserted_oifs);
                    512:                            change_flag = TRUE;
                    513:                            mrt_grp->flags &= ~MRTF_ASSERTED;
                    514:                        }
                    515:                    }
                    516: 
                    517:                    if ((change_flag == TRUE) || (update_rp_iif == TRUE)) {
                    518:                        change_interfaces(mrt_grp,
                    519:                                          rp->incoming,
                    520:                                          mrt_grp->joined_oifs,
                    521:                                          mrt_grp->pruned_oifs,
                    522:                                          mrt_grp->leaves,
                    523:                                          mrt_grp->asserted_oifs, 0);
                    524:                        mrt_grp->upstream = rp->upstream;
                    525:                    }
                    526: 
                    527:                    /* Check the sources activity */
                    528:                    check_spt_threshold(mrt_grp);
                    529: 
                    530:                    dont_calc_action = FALSE;
                    531:                    if (rp_action != PIM_ACTION_NOTHING) {
                    532:                        dont_calc_action = TRUE;
                    533: 
                    534:                        grp_action = join_or_prune(mrt_grp, mrt_grp->upstream);
                    535:                        if (((rp_action == PIM_ACTION_JOIN)  && (grp_action == PIM_ACTION_PRUNE)) ||
                    536:                            ((rp_action == PIM_ACTION_PRUNE) && (grp_action == PIM_ACTION_JOIN)))
                    537:                            FIRE_TIMER(mrt_grp->jp_timer);
                    538:                    }
                    539: 
                    540: 
                    541:                    /* Join/Prune timer */
                    542:                    IF_TIMEOUT(mrt_grp->jp_timer) {
                    543:                        if (dont_calc_action != TRUE)
                    544:                            grp_action = join_or_prune(mrt_grp, mrt_grp->upstream);
                    545: 
                    546:                        if (grp_action != PIM_ACTION_NOTHING)
                    547:                            add_jp_entry(mrt_grp->upstream,
                    548:                                         PIM_JOIN_PRUNE_HOLDTIME,
                    549:                                         mrt_grp->group->group,
                    550:                                         SINGLE_GRP_MSKLEN,
                    551:                                         cand_rp->rpentry->address,
                    552:                                         SINGLE_SRC_MSKLEN,
                    553:                                         MRTF_RP | MRTF_WC,
                    554:                                         grp_action);
                    555:                        SET_TIMER(mrt_grp->jp_timer, PIM_JOIN_PRUNE_PERIOD);
                    556:                    }
                    557: 
                    558:                    /* Register-Suppression timer */
                    559:                    /* TODO: to reduce the kernel calls, if the timer
                    560:                     * is running, install a negative cache entry in
                    561:                     * the kernel?
                    562:                     */
                    563:                    /* TODO: currently cannot have Register-Suppression
                    564:                     * timer for (*,G) entry, but keep this around.
                    565:                     */
                    566:                    IF_TIMEOUT(mrt_grp->rs_timer) {}
                    567: 
                    568:                    /* routing entry */
                    569:                    if ((TIMEOUT(mrt_grp->timer)) && (VIFM_ISEMPTY(mrt_grp->leaves)))
                    570:                        delete_mrtentry(mrt_grp);
                    571:                } /* if (mrt_grp) */
                    572: 
                    573: 
                    574:                /* For all (S,G) for this group */
                    575:                /* XXX: mrt_srcs was set before */
                    576:                for (; mrt_srcs; mrt_srcs = mrt_srcs_next) {
                    577:                    /* routing entry */
                    578:                    mrt_srcs_next = mrt_srcs->grpnext;
                    579: 
                    580:                    /* outgoing interfaces timers */
                    581:                    change_flag = FALSE;
                    582:                    assert_timer_expired = 0;
                    583:                    if (mrt_srcs->flags & MRTF_ASSERTED)
                    584:                        assert_timer_expired = TIMEOUT(mrt_srcs->assert_timer);
                    585: 
                    586:                    for (vifi = 0; vifi < numvifs; vifi++) {
                    587:                        if (VIFM_ISSET(vifi, mrt_srcs->joined_oifs)) {
                    588:                            /* TODO: checking for reg_num_vif is slow! */
                    589:                            if (vifi != reg_vif_num) {
                    590:                                IF_TIMEOUT(mrt_srcs->vif_timers[vifi]) {
                    591:                                    VIFM_CLR(vifi, mrt_srcs->joined_oifs);
                    592:                                    change_flag = TRUE;
                    593:                                }
                    594:                            }
                    595:                        }
                    596: 
                    597:                        if (assert_timer_expired) {
                    598:                            VIFM_CLR(vifi, mrt_srcs->asserted_oifs);
                    599:                            change_flag = TRUE;
                    600:                            mrt_srcs->flags &= ~MRTF_ASSERTED;
                    601:                        }
                    602:                    }
                    603: 
                    604:                    update_src_iif = FALSE;
                    605:                    if (ucast_flag == TRUE) {
                    606:                        if (!(mrt_srcs->flags & MRTF_RP)) {
                    607:                            /* iif toward the source */
                    608:                            srcentry_save.incoming = mrt_srcs->source->incoming;
                    609:                            srcentry_save.upstream = mrt_srcs->source->upstream;
                    610:                            if (set_incoming(mrt_srcs->source, PIM_IIF_SOURCE) != TRUE) {
                    611:                                /* XXX: not in the spec!
                    612:                                 * Cannot find route toward that source.
                    613:                                 * This is bad. Delete the entry.
                    614:                                 */
                    615:                                delete_mrtentry(mrt_srcs);
                    616:                                continue;
                    617:                            }
                    618: 
                    619:                            /* iif info found */
                    620:                            if ((srcentry_save.incoming != mrt_srcs->incoming) ||
                    621:                                (srcentry_save.upstream != mrt_srcs->upstream)) {
                    622:                                /* Route change has occur */
                    623:                                update_src_iif = TRUE;
                    624:                                mrt_srcs->incoming = mrt_srcs->source->incoming;
                    625:                                mrt_srcs->upstream = mrt_srcs->source->upstream;
                    626:                            }
                    627:                        } else {
                    628:                            /* (S,G)RPBit with iif toward RP */
                    629:                            if ((rpentry_save.upstream != mrt_srcs->upstream) ||
                    630:                                (rpentry_save.incoming != mrt_srcs->incoming)) {
                    631:                                update_src_iif = TRUE; /* XXX: a hack */
                    632:                                /* XXX: setup the iif now! */
                    633:                                mrt_srcs->incoming = rp->incoming;
                    634:                                mrt_srcs->upstream = rp->upstream;
                    635:                            }
                    636:                        }
                    637:                    }
                    638: 
                    639:                    if ((change_flag == TRUE) || (update_src_iif == TRUE))
                    640:                        /* Flush the changes */
                    641:                        change_interfaces(mrt_srcs,
                    642:                                          mrt_srcs->incoming,
                    643:                                          mrt_srcs->joined_oifs,
                    644:                                          mrt_srcs->pruned_oifs,
                    645:                                          mrt_srcs->leaves,
                    646:                                          mrt_srcs->asserted_oifs, 0);
                    647: 
                    648:                    check_spt_threshold(mrt_srcs);
                    649: 
                    650:                    mrt_wide = mrt_srcs->group->grp_route;
                    651:                    if (!mrt_wide)
                    652:                        mrt_wide = mrt_rp;
                    653: 
                    654:                    dont_calc_action = FALSE;
                    655:                    if ((rp_action  != PIM_ACTION_NOTHING) ||
                    656:                        (grp_action != PIM_ACTION_NOTHING)) {
                    657:                        src_action_rp    = join_or_prune(mrt_srcs, rp->upstream);
                    658:                        src_action       = src_action_rp;
                    659:                        dont_calc_action = TRUE;
                    660: 
                    661:                        if (src_action_rp == PIM_ACTION_JOIN) {
                    662:                            if ((grp_action == PIM_ACTION_PRUNE) ||
                    663:                                (rp_action  == PIM_ACTION_PRUNE))
                    664:                                FIRE_TIMER(mrt_srcs->jp_timer);
                    665:                        } else if (src_action_rp == PIM_ACTION_PRUNE) {
                    666:                            if ((grp_action == PIM_ACTION_JOIN) ||
                    667:                                (rp_action  == PIM_ACTION_JOIN))
                    668:                                FIRE_TIMER(mrt_srcs->jp_timer);
                    669:                        }
                    670:                    }
                    671: 
                    672:                    /* Join/Prune timer */
                    673:                    IF_TIMEOUT(mrt_srcs->jp_timer) {
                    674:                        if ((dont_calc_action != TRUE) || (rp->upstream != mrt_srcs->upstream))
                    675:                            src_action = join_or_prune(mrt_srcs, mrt_srcs->upstream);
                    676: 
                    677:                        if (src_action != PIM_ACTION_NOTHING)
                    678:                            add_jp_entry(mrt_srcs->upstream,
                    679:                                         PIM_JOIN_PRUNE_HOLDTIME,
                    680:                                         mrt_srcs->group->group,
                    681:                                         SINGLE_GRP_MSKLEN,
                    682:                                         mrt_srcs->source->address,
                    683:                                         SINGLE_SRC_MSKLEN,
                    684:                                         mrt_srcs->flags & MRTF_RP,
                    685:                                         src_action);
                    686: 
                    687:                        if (mrt_wide) {
                    688:                            /* Have both (S,G) and (*,G) (or (*,*,RP)).
                    689:                             * Check if need to send (S,G) PRUNE toward RP */
                    690:                            if (mrt_srcs->upstream != mrt_wide->upstream) {
                    691:                                if (dont_calc_action != TRUE)
                    692:                                    src_action_rp = join_or_prune(mrt_srcs, mrt_wide->upstream);
                    693: 
                    694:                                /* XXX: TODO: do error check if
                    695:                                 * src_action == PIM_ACTION_JOIN, which
                    696:                                 * should be an error. */
                    697:                                if (src_action_rp == PIM_ACTION_PRUNE)
                    698:                                    add_jp_entry(mrt_wide->upstream,
                    699:                                                 PIM_JOIN_PRUNE_HOLDTIME,
                    700:                                                 mrt_srcs->group->group,
                    701:                                                 SINGLE_GRP_MSKLEN,
                    702:                                                 mrt_srcs->source->address,
                    703:                                                 SINGLE_SRC_MSKLEN,
                    704:                                                 MRTF_RP,
                    705:                                                 src_action_rp);
                    706:                            }
                    707:                        }
                    708:                        SET_TIMER(mrt_srcs->jp_timer, PIM_JOIN_PRUNE_PERIOD);
                    709:                    }
                    710: 
                    711:                    /* Register-Suppression timer */
                    712:                    /* TODO: to reduce the kernel calls, if the timer
                    713:                     * is running, install a negative cache entry in
                    714:                     * the kernel? */
                    715:                    IF_TIMER_SET(mrt_srcs->rs_timer) {
                    716:                        IF_TIMEOUT(mrt_srcs->rs_timer) {
                    717:                            /* Start encapsulating the packets */
                    718:                            VIFM_COPY(mrt_srcs->pruned_oifs, new_pruned_oifs);
                    719:                            VIFM_CLR(reg_vif_num, new_pruned_oifs);
                    720:                            change_interfaces(mrt_srcs,
                    721:                                              mrt_srcs->incoming,
                    722:                                              mrt_srcs->joined_oifs,
                    723:                                              new_pruned_oifs,
                    724:                                              mrt_srcs->leaves,
                    725:                                              mrt_srcs->asserted_oifs, 0);
                    726:                        }
                    727:                        ELSE {
                    728:                            /* The register suppression timer is running. Check
                    729:                             * whether it is time to send PIM_NULL_REGISTER.
                    730:                             */
                    731:                            /* TODO: XXX: TIMER implem. dependency! */
                    732:                            if (mrt_srcs->rs_timer <= PIM_REGISTER_PROBE_TIME)
                    733:                                /* Time to send a PIM_NULL_REGISTER */
                    734:                                /* XXX: a (bad) hack! This will be sending
                    735:                                 * periodically NULL_REGISTERS between
                    736:                                 * PIM_REGISTER_PROBE_TIME and 0. Well,
                    737:                                 * because PROBE_TIME is 5 secs, it will
                    738:                                 * happen only once, so it helps to avoid
                    739:                                 * adding a flag to the routing entry whether
                    740:                                 * a NULL_REGISTER was sent.
                    741:                                 */
                    742:                                send_pim_null_register(mrt_srcs);
                    743:                        }
                    744:                    }
                    745: 
                    746:                    /* routing entry */
                    747:                    if (TIMEOUT(mrt_srcs->timer)) {
                    748:                        if (VIFM_ISEMPTY(mrt_srcs->leaves)) {
                    749:                            delete_mrtentry(mrt_srcs);
                    750:                            continue;
                    751:                        }
                    752:                        /* XXX: if DR, Register suppressed,
                    753:                         * and leaf oif inherited from (*,G), the
                    754:                         * directly connected source is not active anymore,
                    755:                         * this (S,G) entry won't timeout. Check if the leaf
                    756:                         * oifs are inherited from (*,G); if true. delete the
                    757:                         * (S,G) entry.
                    758:                         */
                    759:                        if (mrt_srcs->group->grp_route) {
                    760:                            if (!((mrt_srcs->group->grp_route->leaves & mrt_srcs->leaves) ^ mrt_srcs->leaves)) {
                    761:                                delete_mrtentry(mrt_srcs);
                    762:                                continue;
                    763:                            }
                    764:                        }
                    765:                    }
                    766:                } /* End of (S,G) loop */
                    767:            } /* End of (*,G) loop */
                    768:        }
                    769:     } /* For all cand RPs */
                    770: 
                    771:     /* TODO: check again! */
                    772:     for (vifi = 0, v = &uvifs[0]; vifi < numvifs; vifi++, v++) {
                    773:        /* Send all pending Join/Prune messages */
                    774:        for (nbr = v->uv_pim_neighbors; nbr; nbr = nbr->next)
                    775:            pack_and_send_jp_message(nbr);
                    776:     }
                    777: 
                    778:     IF_DEBUG(DEBUG_PIM_MRT) {
                    779:        fputs("\n", stderr);
                    780:        dump_pim_mrt(stderr);
                    781:     }
                    782: }
                    783: 
                    784: 
                    785: /*
                    786:  * TODO: timeout the RP-group mapping entries during the scan of the
                    787:  * whole routing table?
                    788:  */
                    789: void age_misc(void)
                    790: {
                    791:     rp_grp_entry_t *rp;
                    792:     rp_grp_entry_t *rp_next;
                    793:     grp_mask_t     *grp;
                    794:     grp_mask_t     *grp_next;
                    795: 
                    796:     /* Timeout the Cand-RP-set entries */
                    797:     for (grp = grp_mask_list; grp; grp = grp_next) {
                    798:        /* If we timeout an entry, the grp entry might be removed */
                    799:        grp_next = grp->next;
                    800:        for (rp = grp->grp_rp_next; rp; rp = rp_next) {
                    801:            rp_next = rp->grp_rp_next;
                    802: 
                    803:            if (rp->holdtime < 60000) {
                    804:                IF_TIMEOUT(rp->holdtime) {
                    805:                    if (rp->group!=NULL) {
                    806:                        logit(LOG_INFO, 0, "Delete RP group entry for group %s (holdtime timeout)",
                    807:                              inet_fmt(rp->group->group_addr, s2, sizeof(s2)));
                    808:                    }
                    809:                    delete_rp_grp_entry(&cand_rp_list, &grp_mask_list, rp);
                    810:                }
                    811:            }
                    812:        }
                    813:     }
                    814: 
                    815:     /* Cand-RP-Adv timer */
                    816:     if (cand_rp_flag == TRUE) {
                    817:        IF_TIMEOUT(pim_cand_rp_adv_timer) {
                    818:            send_pim_cand_rp_adv();
                    819:            SET_TIMER(pim_cand_rp_adv_timer, my_cand_rp_adv_period);
                    820:        }
                    821:     }
                    822: 
                    823:     /* bootstrap-timer */
                    824:     IF_TIMEOUT(pim_bootstrap_timer) {
                    825:        if (cand_bsr_flag == FALSE) {
                    826:            /* If I am not Cand-BSR, start accepting Bootstrap messages from anyone.
                    827:             * XXX: Even if the BSR has timeout, the existing Cand-RP-Set is kept. */
                    828:            SET_TIMER(pim_bootstrap_timer, PIM_BOOTSTRAP_TIMEOUT);
                    829:            curr_bsr_fragment_tag = 0;
                    830:            curr_bsr_priority     = 0;            /* Lowest priority */
                    831:            curr_bsr_address      = INADDR_ANY_N; /* Lowest priority */
                    832:            MASKLEN_TO_MASK(RP_DEFAULT_IPV4_HASHMASKLEN, curr_bsr_hash_mask);
                    833:        } else {
                    834:            /* I am Cand-BSR, so set the current BSR to me */
                    835:            if (curr_bsr_address == my_bsr_address) {
                    836:                SET_TIMER(pim_bootstrap_timer, PIM_BOOTSTRAP_PERIOD);
                    837:                send_pim_bootstrap();
                    838:            } else {
                    839:                /* Short delay before becoming the BSR and start sending
                    840:                 * of the Cand-RP set (to reduce the transient control
                    841:                 * overhead). */
                    842:                SET_TIMER(pim_bootstrap_timer, bootstrap_initial_delay());
                    843:                curr_bsr_fragment_tag = RANDOM();
                    844:                curr_bsr_priority     = my_bsr_priority;
                    845:                curr_bsr_address      = my_bsr_address;
                    846:                curr_bsr_hash_mask    = my_bsr_hash_mask;
                    847:            }
                    848:        }
                    849:     }
                    850: 
                    851:     IF_DEBUG(DEBUG_PIM_BOOTSTRAP | DEBUG_PIM_CAND_RP)
                    852:        dump_rp_set(stderr);
                    853:     /* TODO: XXX: anything else to timeout */
                    854: }
                    855: 
                    856: /**
                    857:  * Local Variables:
                    858:  *  version-control: t
                    859:  *  indent-tabs-mode: t
                    860:  *  c-file-style: "ellemtel"
                    861:  *  c-basic-offset: 4
                    862:  * End:
                    863:  */

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