File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimdd / timer.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:58:55 2017 UTC (6 years, 11 months ago) by misho
Branches: pimdd, MAIN
CVS tags: v0_2_1p0, v0_2_1, HEAD
pimdd-dense 0.2.1.0_2

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

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