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