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