File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / timer.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:59:37 2017 UTC (6 years, 11 months ago) by misho
Branches: pimd, MAIN
CVS tags: v2_3_2, HEAD
pimd 2.3.2

    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.1.1.1 2017/06/12 07:59:37 misho 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>