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