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