Annotation of embedaddon/mrouted/prune.c, revision 1.1.1.1
1.1 misho 1: /*
2: * The mrouted program is covered by the license in the accompanying file
3: * named "LICENSE". Use of the mrouted program represents acceptance of
4: * the terms and conditions listed in that file.
5: *
6: * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
7: * Leland Stanford Junior University.
8: */
9:
10: #include "defs.h"
11:
12: extern int cache_lifetime;
13: extern int prune_lifetime;
14: extern struct rtentry *routing_table;
15:
16: extern int phys_vif;
17: extern int allow_black_holes;
18:
19: /*
20: * randomize value to obtain a value between .5x and 1.5x
21: * in order to prevent synchronization
22: */
23: #ifdef SYSV
24: #define JITTERED_VALUE(x) ((x)/2 + (lrand48() % (x)))
25: #else
26: #define JITTERED_VALUE(x) ((x)/2 + (random() % (x)))
27: #endif
28: #define CACHE_LIFETIME(x) JITTERED_VALUE(x) /* XXX */
29:
30: struct gtable *kernel_table; /* ptr to list of kernel grp entries*/
31: static struct gtable *kernel_no_route; /* list of grp entries w/o routes */
32: struct gtable *gtp; /* pointer for kernel rt entries */
33: unsigned int kroutes; /* current number of cache entries */
34:
35: /****************************************************************************
36: Functions that are local to prune.c
37: ****************************************************************************/
38: static int scoped_addr(vifi_t vifi, u_int32 addr);
39: static void prun_add_ttls(struct gtable *gt);
40: static int pruning_neighbor(vifi_t vifi, u_int32 addr);
41: static int can_mtrace(vifi_t vifi, u_int32 addr);
42: static struct ptable * find_prune_entry(u_int32 vr, struct ptable *pt);
43: static void remove_sources(struct gtable *gt);
44: static void rexmit_prune(void *arg);
45: static void expire_prune(vifi_t vifi, struct gtable *gt);
46: static void send_prune(struct gtable *gt);
47: static void send_graft(struct gtable *gt);
48: static void send_graft_ack(u_int32 src, u_int32 dst,
49: u_int32 origin, u_int32 grp,
50: vifi_t vifi);
51: static void update_kernel(struct gtable *g);
52:
53: /*
54: * Updates the ttl values for each vif.
55: */
56: static void prun_add_ttls(struct gtable *gt)
57: {
58: struct uvif *v;
59: vifi_t vifi;
60:
61: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
62: if (VIFM_ISSET(vifi, gt->gt_grpmems))
63: gt->gt_ttls[vifi] = v->uv_threshold;
64: else
65: gt->gt_ttls[vifi] = 0;
66: }
67: }
68:
69: /*
70: * checks for scoped multicast addresses
71: * XXX I want to make the check of allow_black_holes based on ALLOW_BLACK_HOLES
72: * but macros are not functions.
73: */
74: #define GET_SCOPE(gt) { \
75: vifi_t _i; \
76: VIFM_CLRALL((gt)->gt_scope); \
77: if (allow_black_holes || \
78: (ntohl((gt)->gt_mcastgrp) & 0xff000000) == 0xef000000) \
79: for (_i = 0; _i < numvifs; _i++) \
80: if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
81: VIFM_SET(_i, (gt)->gt_scope); \
82: if ((gt)->gt_route == NULL \
83: || ((gt)->gt_route->rt_parent != NO_VIF \
84: && VIFM_ISSET((gt)->gt_route->rt_parent, (gt)->gt_scope))) \
85: VIFM_SETALL((gt)->gt_scope); \
86: }
87:
88: #define APPLY_SCOPE(gt) VIFM_CLR_MASK((gt)->gt_grpmems, (gt)->gt_scope)
89:
90: #define GET_MEMBERSHIP(gt, vifi) { \
91: if ((gt)->gt_route \
92: && VIFM_ISSET((vifi), (gt)->gt_route->rt_children) \
93: && (!SUBS_ARE_PRUNED((gt)->gt_route->rt_subordinates, \
94: uvifs[vifi].uv_nbrmap, (gt)->gt_prunes) \
95: || grplst_mem((vifi), (gt)->gt_mcastgrp))) \
96: VIFM_SET((vifi), (gt)->gt_grpmems); \
97: }
98:
99: static int scoped_addr(vifi_t vifi, u_int32 addr)
100: {
101: struct vif_acl *acl;
102:
103: for (acl = uvifs[vifi].uv_acl; acl; acl = acl->acl_next)
104: if ((addr & acl->acl_mask) == acl->acl_addr)
105: return 1;
106:
107: return 0;
108: }
109:
110: /*
111: * Determine the list of outgoing vifs, based upon
112: * route subordinates, prunes received, and group
113: * memberships.
114: */
115: void determine_forwvifs(struct gtable *gt)
116: {
117: vifi_t i;
118:
119: VIFM_CLRALL(gt->gt_grpmems);
120: for (i = 0; i < numvifs; i++) {
121: GET_MEMBERSHIP(gt, i);
122: }
123: GET_SCOPE(gt);
124: APPLY_SCOPE(gt);
125: }
126:
127: /*
128: * Send a prune or a graft if necessary.
129: */
130: void send_prune_or_graft(struct gtable *gt)
131: {
132: if (VIFM_ISEMPTY(gt->gt_grpmems))
133: send_prune(gt);
134: else if (gt->gt_prsent_timer)
135: send_graft(gt);
136: }
137:
138: /*
139: * Determine if mcastgrp has a listener on vifi
140: */
141: int grplst_mem(vifi_t vifi, u_int32 mcastgrp)
142: {
143: struct listaddr *g;
144: struct uvif *v;
145:
146: v = &uvifs[vifi];
147:
148: for (g = v->uv_groups; g != NULL; g = g->al_next)
149: if (mcastgrp == g->al_addr)
150: return 1;
151:
152: return 0;
153: }
154:
155: /*
156: * Finds the group entry with the specified source and netmask.
157: * If netmask is 0, it uses the route's netmask.
158: *
159: * Returns TRUE if found a match, and the global variable gtp is left
160: * pointing to entry before the found entry.
161: * Returns FALSE if no exact match found, gtp is left pointing to before
162: * the entry in question belongs, or is NULL if the it belongs at the
163: * head of the list.
164: */
165: int find_src_grp(u_int32 src, u_int32 mask, u_int32 grp)
166: {
167: struct gtable *gt;
168:
169: gtp = NULL;
170: gt = kernel_table;
171: while (gt != NULL) {
172: if (grp == gt->gt_mcastgrp &&
173: (mask ? (gt->gt_route->rt_origin == src &&
174: gt->gt_route->rt_originmask == mask) :
175: ((src & gt->gt_route->rt_originmask) ==
176: gt->gt_route->rt_origin)))
177: return TRUE;
178: if (ntohl(grp) > ntohl(gt->gt_mcastgrp) ||
179: (grp == gt->gt_mcastgrp &&
180: (ntohl(mask) < ntohl(gt->gt_route->rt_originmask) ||
181: (mask == gt->gt_route->rt_originmask &&
182: (ntohl(src) > ntohl(gt->gt_route->rt_origin)))))) {
183: gtp = gt;
184: gt = gt->gt_gnext;
185: }
186: else break;
187: }
188: return FALSE;
189: }
190:
191: /*
192: * Check if the neighbor supports pruning
193: */
194: static int pruning_neighbor(vifi_t vifi, u_int32 addr)
195: {
196: struct listaddr *n = neighbor_info(vifi, addr);
197: int vers;
198:
199: if (n == NULL)
200: return 0;
201:
202: vers = NBR_VERS(n);
203: return (vers >= 0x0300 && ((vers & 0xff00) != 0x0a00));
204: }
205:
206: /*
207: * Can the neighbor in question handle multicast traceroute?
208: */
209: static int can_mtrace(vifi_t vifi, u_int32 addr)
210: {
211: struct listaddr *n = neighbor_info(vifi, addr);
212: int vers;
213:
214: if (n == NULL)
215: return 1; /* fail "safe" */
216:
217: vers = NBR_VERS(n);
218: return (vers >= 0x0303 && ((vers & 0xff00) != 0x0a00));
219: }
220:
221: /*
222: * Returns the prune entry of the router, or NULL if none exists
223: */
224: static struct ptable *find_prune_entry(u_int32 vr, struct ptable *pt)
225: {
226: while (pt) {
227: if (pt->pt_router == vr)
228: return pt;
229: pt = pt->pt_next;
230: }
231:
232: return NULL;
233: }
234:
235: /*
236: * Remove all the sources hanging off the group table entry from the kernel
237: * cache. Remember the packet counts wherever possible, to keep the mtrace
238: * counters consistent. This prepares for possible prune retransmission,
239: * either on a multi-access network or when a prune that we sent upstream
240: * has expired.
241: */
242: static void remove_sources(struct gtable *gt)
243: {
244: struct stable *st;
245: struct sioc_sg_req sg_req;
246:
247: sg_req.grp.s_addr = gt->gt_mcastgrp;
248:
249: /*
250: * call k_del_rg() on every one of the gt->gt_srctbl entries
251: * but first save the packet count so that the mtrace packet
252: * counters can remain approximately correct. There's a race
253: * here but it's minor.
254: */
255: for (st = gt->gt_srctbl; st; st = st->st_next) {
256: if (st->st_ctime == 0)
257: continue;
258:
259: IF_DEBUG(DEBUG_PRUNE) {
260: logit(LOG_DEBUG, 0, "rexmit_prune() deleting (%s %s) (next is %d sec)",
261: inet_fmt(st->st_origin, s1, sizeof(s1)),
262: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)),
263: gt->gt_prune_rexmit);
264: }
265: sg_req.src.s_addr = st->st_origin;
266: if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) {
267: sg_req.pktcnt = 0;
268: }
269: k_del_rg(st->st_origin, gt);
270: st->st_ctime = 0; /* flag that it's not in the kernel any more */
271: st->st_savpkt += sg_req.pktcnt;
272: kroutes--;
273: }
274:
275: /*
276: * Now, add_table_entry will prune when asked to add a cache entry.
277: */
278: }
279:
280: /*
281: * Prepare for possible prune retransmission
282: */
283: static void rexmit_prune(void *arg)
284: {
285: struct gtable *gt = *(struct gtable **)arg;
286:
287: free(arg);
288:
289: gt->gt_rexmit_timer = 0;
290:
291: /* Make sure we're still not forwarding traffic */
292: if (!VIFM_ISEMPTY(gt->gt_grpmems)) {
293: IF_DEBUG(DEBUG_PRUNE) {
294: logit(LOG_DEBUG, 0, "rexmit_prune() (%s %s): gm:%x", RT_FMT(gt->gt_route, s1),
295: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)), gt->gt_grpmems);
296: }
297: return;
298: }
299:
300: remove_sources(gt);
301: }
302:
303: /*
304: * Send a prune message to the dominant router for
305: * this source.
306: *
307: * Record an entry that a prune was sent for this group
308: */
309: static void send_prune(struct gtable *gt)
310: {
311: struct ptable *pt;
312: char *p;
313: int i;
314: int datalen;
315: u_int32 dst;
316: u_int32 tmp;
317: int rexmitting = 0;
318: struct uvif *v;
319:
320: /*
321: * Can't process a prune if we don't have an associated route
322: * or if the route points to a local interface.
323: */
324: if (gt->gt_route == NULL || gt->gt_route->rt_parent == NO_VIF || gt->gt_route->rt_gateway == 0)
325: return;
326:
327: /* Don't send a prune to a non-pruning router */
328: if (!pruning_neighbor(gt->gt_route->rt_parent, gt->gt_route->rt_gateway))
329: return;
330:
331: v = &uvifs[gt->gt_route->rt_parent];
332: /*
333: * sends a prune message to the router upstream.
334: */
335: #if 0
336: dst = v->uv_flags & VIFF_TUNNEL ? dvmrp_group : gt->gt_route->rt_gateway; /*XXX*/
337: #else
338: dst = gt->gt_route->rt_gateway;
339: #endif
340:
341: p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
342: datalen = 0;
343:
344: /*
345: * determine prune lifetime, if this isn't a retransmission.
346: *
347: * Use interface-specified lifetime if there is one.
348: */
349: if (gt->gt_prsent_timer == 0) {
350: int l = prune_lifetime;
351:
352: if (v->uv_prune_lifetime != 0)
353: l = v->uv_prune_lifetime;
354:
355: gt->gt_prsent_timer = JITTERED_VALUE(l);
356: for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next)
357: if (pt->pt_timer < gt->gt_prsent_timer)
358: gt->gt_prsent_timer = pt->pt_timer;
359: } else if (gt->gt_prsent_timer < 0) {
360: IF_DEBUG(DEBUG_PRUNE) {
361: logit(LOG_DEBUG, 0, "Asked to rexmit? (%s,%s)/%d on vif %d to %s with negative time",
362: RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)),
363: gt->gt_prsent_timer, gt->gt_route->rt_parent,
364: inet_fmt(gt->gt_route->rt_gateway, s3, sizeof(s3)));
365: }
366: return;
367: } else {
368: rexmitting = 1;
369: }
370:
371: if (rexmitting && !(v->uv_flags & VIFF_REXMIT_PRUNES)) {
372: IF_DEBUG(DEBUG_PRUNE) {
373: logit(LOG_DEBUG, 0, "Not rexmitting prune for (%s %s)/%d on vif %d to %s",
374: RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)),
375: gt->gt_prsent_timer, gt->gt_route->rt_parent,
376: inet_fmt(gt->gt_route->rt_gateway, s3, sizeof(s3)));
377: }
378: return;
379: }
380:
381: if (gt->gt_prsent_timer <= MIN_PRUNE_LIFE) {
382: IF_DEBUG(DEBUG_PRUNE) {
383: logit(LOG_DEBUG, 0, "Not bothering to send prune for (%s,%s)/%d on vif %d to %s because it's too short",
384: RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)),
385: gt->gt_prsent_timer, gt->gt_route->rt_parent,
386: inet_fmt(gt->gt_route->rt_gateway, s3, sizeof(s3)));
387: }
388: return;
389: }
390:
391: /*
392: * If we have a graft pending, cancel graft retransmission
393: */
394: gt->gt_grftsnt = 0;
395:
396: for (i = 0; i < 4; i++)
397: *p++ = ((char *)&(gt->gt_route->rt_origin))[i];
398: for (i = 0; i < 4; i++)
399: *p++ = ((char *)&(gt->gt_mcastgrp))[i];
400: tmp = htonl(gt->gt_prsent_timer);
401: for (i = 0; i < 4; i++)
402: *p++ = ((char *)&(tmp))[i];
403: datalen += 12;
404:
405: send_on_vif(v, dst, DVMRP_PRUNE, datalen);
406:
407: IF_DEBUG(DEBUG_PRUNE) {
408: logit(LOG_DEBUG, 0, "%s prune for (%s %s)/%d on vif %d to %s",
409: rexmitting ? "rexmitted" : "sent",
410: RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)),
411: gt->gt_prsent_timer, gt->gt_route->rt_parent,
412: inet_fmt(gt->gt_route->rt_gateway, s3, sizeof(s3)));
413: }
414:
415: if ((v->uv_flags & VIFF_REXMIT_PRUNES) && gt->gt_rexmit_timer == 0 &&
416: gt->gt_prsent_timer > gt->gt_prune_rexmit) {
417: struct gtable **arg;
418:
419: arg = (struct gtable **)malloc(sizeof(struct gtable **));
420: if (!arg) {
421: logit(LOG_ERR, 0, "Malloc failed in prune.c:send_prune()\n");
422: return; /* NOTREACHED */
423: }
424:
425: *arg = gt;
426: gt->gt_rexmit_timer = timer_setTimer(JITTERED_VALUE(gt->gt_prune_rexmit), rexmit_prune, arg);
427: gt->gt_prune_rexmit *= 2;
428: }
429: }
430:
431: /*
432: * a prune was sent upstream
433: * so, a graft has to be sent to annul the prune
434: * set up a graft timer so that if an ack is not
435: * heard within that time, another graft request
436: * is sent out.
437: */
438: static void send_graft(struct gtable *gt)
439: {
440: register char *p;
441: register int i;
442: int datalen;
443: u_int32 dst;
444:
445: /* Can't send a graft without an associated route */
446: if (gt->gt_route == NULL || gt->gt_route->rt_parent == NO_VIF) {
447: gt->gt_grftsnt = 0;
448: return;
449: }
450:
451: gt->gt_prsent_timer = 0;
452: gt->gt_prune_rexmit = PRUNE_REXMIT_VAL;
453: if (gt->gt_rexmit_timer)
454: timer_clearTimer(gt->gt_rexmit_timer);
455:
456: if (gt->gt_grftsnt == 0)
457: gt->gt_grftsnt = 1;
458:
459: #if 0
460: dst = uvifs[gt->gt_route->rt_parent].uv_flags & VIFF_TUNNEL ? dvmrp_group : gt->gt_route->rt_gateway; /*XXX*/
461: #else
462: dst = gt->gt_route->rt_gateway;
463: #endif
464:
465: p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
466: datalen = 0;
467:
468: for (i = 0; i < 4; i++)
469: *p++ = ((char *)&(gt->gt_route->rt_origin))[i];
470: for (i = 0; i < 4; i++)
471: *p++ = ((char *)&(gt->gt_mcastgrp))[i];
472: datalen += 8;
473:
474: send_on_vif(&uvifs[gt->gt_route->rt_parent], dst, DVMRP_GRAFT, datalen);
475: IF_DEBUG(DEBUG_PRUNE) {
476: logit(LOG_DEBUG, 0, "Sent graft for (%s %s) to %s on vif %d",
477: RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)),
478: inet_fmt(gt->gt_route->rt_gateway, s3, sizeof(s3)), gt->gt_route->rt_parent);
479: }
480: }
481:
482: /*
483: * Send an ack that a graft was received
484: */
485: static void send_graft_ack(u_int32 src, u_int32 dst, u_int32 origin, u_int32 grp, vifi_t vifi)
486: {
487: register char *p;
488: register int i;
489: int datalen;
490:
491: p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
492: datalen = 0;
493:
494: for (i = 0; i < 4; i++)
495: *p++ = ((char *)&(origin))[i];
496: for (i = 0; i < 4; i++)
497: *p++ = ((char *)&(grp))[i];
498: datalen += 8;
499:
500: if (vifi == NO_VIF)
501: send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT_ACK,
502: htonl(MROUTED_LEVEL), datalen);
503: else {
504: #if 0
505: if (uvifs[vifi].uv_flags & VIFF_TUNNEL)
506: dst = dvmrp_group; /* XXX */
507: #endif
508: send_on_vif(&uvifs[vifi], dst, DVMRP_GRAFT_ACK, datalen);
509: }
510:
511: IF_DEBUG(DEBUG_PRUNE) {
512: if (vifi == NO_VIF)
513: logit(LOG_DEBUG, 0, "Sent graft ack for (%s, %s) to %s",
514: inet_fmt(origin, s1, sizeof(s1)), inet_fmt(grp, s2, sizeof(s2)), inet_fmt(dst, s3, sizeof(s3)));
515: else
516: logit(LOG_DEBUG, 0, "Sent graft ack for (%s, %s) to %s on vif %d",
517: inet_fmt(origin, s1, sizeof(s1)), inet_fmt(grp, s2, sizeof(s2)), inet_fmt(dst, s3, sizeof(s3)), vifi);
518: }
519: }
520:
521: /*
522: * Update the kernel cache with all the routes hanging off the group entry
523: */
524: static void update_kernel(struct gtable *g)
525: {
526: struct stable *st;
527:
528: for (st = g->gt_srctbl; st; st = st->st_next)
529: if (st->st_ctime != 0)
530: k_add_rg(st->st_origin, g);
531: }
532:
533: /****************************************************************************
534: Functions that are used externally
535: ****************************************************************************/
536:
537: #ifdef SNMP
538: #include <sys/types.h>
539: #include "snmp.h"
540:
541: /*
542: * Find a specific group entry in the group table
543: */
544: struct gtable *find_grp(u_int32 grp)
545: {
546: struct gtable *gt;
547:
548: for (gt = kernel_table; gt; gt = gt->gt_gnext) {
549: if (ntohl(grp) < ntohl(gt->gt_mcastgrp))
550: break;
551: if (gt->gt_mcastgrp == grp)
552: return gt;
553: }
554:
555: return NULL;
556: }
557:
558: /*
559: * Given a group entry and source, find the corresponding source table
560: * entry
561: */
562: struct stable *find_grp_src(struct gtable *gt, u_int32 src)
563: {
564: struct stable *st;
565: u_long grp = gt->gt_mcastgrp;
566: struct gtable *gtcurr;
567:
568: for (gtcurr = gt; gtcurr->gt_mcastgrp == grp; gtcurr = gtcurr->gt_gnext) {
569: for (st = gtcurr->gt_srctbl; st; st = st->st_next)
570: if (st->st_origin == src)
571: return st;
572: }
573:
574: return NULL;
575: }
576:
577: /*
578: * Find next entry > specification
579: * @gtpp: ordered by group
580: * @stpp: ordered by source
581: * @grp:
582: * @src:
583: * @mask:
584: */
585: int next_grp_src_mask(struct gtable **gtpp, struct stable **stpp, u_int32 grp, u_int32 src, u_int32 mask)
586: {
587: struct gtable *gt, *gbest = NULL;
588: struct stable *st, *sbest = NULL;
589:
590: /* Find first group entry >= grp spec */
591: (*gtpp) = kernel_table;
592: while ((*gtpp) && ntohl((*gtpp)->gt_mcastgrp) < ntohl(grp))
593: (*gtpp)=(*gtpp)->gt_gnext;
594: if (!(*gtpp))
595: return 0; /* no more groups */
596:
597: for (gt = kernel_table; gt; gt=gt->gt_gnext) {
598: /* Since grps are ordered, we can stop when group changes from gbest */
599: if (gbest && gbest->gt_mcastgrp != gt->gt_mcastgrp)
600: break;
601: for (st = gt->gt_srctbl; st; st=st->st_next) {
602:
603: /* Among those entries > spec, find "lowest" one */
604: if (((ntohl(gt->gt_mcastgrp)> ntohl(grp))
605: || (ntohl(gt->gt_mcastgrp)==ntohl(grp)
606: && ntohl(st->st_origin)> ntohl(src))
607: || (ntohl(gt->gt_mcastgrp)==ntohl(grp)
608: && ntohl(st->st_origin)==src && 0xFFFFFFFF>ntohl(mask)))
609: && (!gbest
610: || (ntohl(gt->gt_mcastgrp)< ntohl(gbest->gt_mcastgrp))
611: || (ntohl(gt->gt_mcastgrp)==ntohl(gbest->gt_mcastgrp)
612: && ntohl(st->st_origin)< ntohl(sbest->st_origin)))) {
613: gbest = gt;
614: sbest = st;
615: }
616: }
617: }
618: (*gtpp) = gbest;
619: (*stpp) = sbest;
620: return (*gtpp)!=0;
621: }
622:
623: /*
624: * Ensure that sg contains current information for the given group,source.
625: * This is fetched from the kernel as a unit so that counts for the entry
626: * are consistent, i.e. packet and byte counts for the same entry are
627: * read at the same time.
628: */
629: void refresh_sg(struct sioc_sg_req *sg, struct gtable *gt, struct stable *st)
630: {
631: static int lastq = -1;
632:
633: if (quantum != lastq || sg->src.s_addr!=st->st_origin
634: || sg->grp.s_addr!=gt->gt_mcastgrp) {
635: lastq = quantum;
636: sg->src.s_addr = st->st_origin;
637: sg->grp.s_addr = gt->gt_mcastgrp;
638: ioctl(udp_socket, SIOCGETSGCNT, (char *)sg);
639: }
640: }
641:
642: /*
643: * next_child
644: * @gtpp:
645: * @stpp:
646: * @grp:
647: * @src
648: * @mask:
649: * @vifi: vif at which to start looking
650: *
651: * Given a routing table entry, and a vifi, find the next entry
652: * equal to or greater than those
653: */
654: int next_child(struct gtable **gtpp, struct stable **stpp, u_int32 grp, u_int32 src, u_int32 mask, vifi_t vifi)
655: {
656: /* Get (G,S,M) entry */
657: if (mask!=0xFFFFFFFF
658: || !((*gtpp) = find_grp(grp))
659: || !((*stpp) = find_grp_src((*gtpp),src)))
660: if (!next_grp_src_mask(gtpp, stpp, grp, src, mask))
661: return 0;
662:
663: /* Continue until we get one with a valid next vif */
664: do {
665: for (; (*gtpp)->gt_route->rt_children && *vifi<numvifs; (*vifi)++)
666: if (VIFM_ISSET(*vifi, (*gtpp)->gt_route->rt_children))
667: return 1;
668: *vifi = 0;
669: } while (next_grp_src_mask(gtpp, stpp, (*gtpp)->gt_mcastgrp,
670: (*stpp)->st_origin, 0xFFFFFFFF));
671:
672: return 0;
673: }
674: #endif /* SNMP */
675:
676: /*
677: * Initialize the kernel table structure
678: */
679: void init_ktable(void)
680: {
681: kernel_table = NULL;
682: kernel_no_route = NULL;
683: kroutes = 0;
684: }
685:
686: /*
687: * Add a new table entry for (origin, mcastgrp)
688: */
689: void add_table_entry(u_int32 origin, u_int32 mcastgrp)
690: {
691: struct rtentry *r;
692: struct gtable *gt,**gtnp,*prev_gt;
693: struct stable *st,**stnp;
694:
695: /*
696: * Since we have to enable mrouting to get the version number,
697: * some cache creation requests can sneak through. Ignore them
698: * since we're not going to do useful stuff until we've performed
699: * final initialization.
700: */
701: if (!did_final_init)
702: return;
703:
704: #ifdef DEBUG_MFC
705: md_log(MD_MISS, origin, mcastgrp);
706: #endif
707:
708: r = determine_route(origin);
709: prev_gt = NULL;
710: if (r == NULL) {
711: /*
712: * Look for it on the no_route table; if it is found then
713: * it will be detected as a duplicate below.
714: */
715: for (gt = kernel_no_route; gt; gt = gt->gt_next)
716: if (mcastgrp == gt->gt_mcastgrp &&
717: gt->gt_srctbl && gt->gt_srctbl->st_origin == origin)
718: break;
719: gtnp = &kernel_no_route;
720: } else {
721: gtnp = &r->rt_groups;
722: while ((gt = *gtnp) != NULL) {
723: if (gt->gt_mcastgrp >= mcastgrp)
724: break;
725: gtnp = >->gt_next;
726: prev_gt = gt;
727: }
728: }
729:
730: if (gt == NULL || gt->gt_mcastgrp != mcastgrp) {
731: gt = (struct gtable *)malloc(sizeof(struct gtable));
732: if (gt == NULL) {
733: logit(LOG_ERR, 0, "Malloc failed in prune.c:add_table_entry()\n");
734: return; /* NOTREACHED */
735: }
736:
737: gt->gt_mcastgrp = mcastgrp;
738: gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
739: time(>->gt_ctime);
740: gt->gt_prsent_timer = 0;
741: gt->gt_grftsnt = 0;
742: gt->gt_srctbl = NULL;
743: gt->gt_pruntbl = NULL;
744: gt->gt_route = r;
745: gt->gt_rexmit_timer = 0;
746: NBRM_CLRALL(gt->gt_prunes);
747: gt->gt_prune_rexmit = PRUNE_REXMIT_VAL;
748: #ifdef RSRR
749: gt->gt_rsrr_cache = NULL;
750: #endif
751:
752: /* Calculate forwarding vifs */
753: determine_forwvifs(gt);
754:
755: /* update ttls */
756: prun_add_ttls(gt);
757:
758: gt->gt_next = *gtnp;
759: *gtnp = gt;
760: if (gt->gt_next)
761: gt->gt_next->gt_prev = gt;
762: gt->gt_prev = prev_gt;
763:
764: if (r) {
765: if (find_src_grp(r->rt_origin, r->rt_originmask, gt->gt_mcastgrp)) {
766: struct gtable *g = gtp ? gtp->gt_gnext : kernel_table;
767:
768: logit(LOG_WARNING, 0, "Entry for (%s %s) (rt:%x) exists (rt:%x)",
769: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)),
770: r, g->gt_route);
771: } else {
772: if (gtp) {
773: gt->gt_gnext = gtp->gt_gnext;
774: gt->gt_gprev = gtp;
775: gtp->gt_gnext = gt;
776: } else {
777: gt->gt_gnext = kernel_table;
778: gt->gt_gprev = NULL;
779: kernel_table = gt;
780: }
781: if (gt->gt_gnext)
782: gt->gt_gnext->gt_gprev = gt;
783: }
784: } else {
785: gt->gt_gnext = gt->gt_gprev = NULL;
786: }
787: }
788:
789: stnp = >->gt_srctbl;
790: while ((st = *stnp) != NULL) {
791: if (ntohl(st->st_origin) >= ntohl(origin))
792: break;
793: stnp = &st->st_next;
794: }
795:
796: if (st == NULL || st->st_origin != origin) {
797: st = (struct stable *)malloc(sizeof(struct stable));
798: if (st == NULL) {
799: logit(LOG_ERR, 0, "Malloc failed in prune.c:add_table_entry()\n");
800: return; /* NOTREACHED */
801: }
802:
803: st->st_origin = origin;
804: st->st_pktcnt = 0;
805: st->st_savpkt = 0;
806: time(&st->st_ctime);
807: st->st_next = *stnp;
808: *stnp = st;
809: } else {
810: if (st->st_ctime == 0) {
811: /* An old source which we're keeping around for statistics */
812: time(&st->st_ctime);
813: } else {
814: #ifdef DEBUG_MFC
815: md_log(MD_DUPE, origin, mcastgrp);
816: #endif
817: /* Ignore kernel->mrouted retransmissions */
818: if (time(0) - st->st_ctime > 5)
819: logit(LOG_WARNING, 0, "Kernel entry already exists for (%s %s)",
820: inet_fmt(origin, s1, sizeof(s1)), inet_fmt(mcastgrp, s2, sizeof(s2)));
821: k_add_rg(origin, gt);
822: return;
823: }
824: }
825:
826: kroutes++;
827: k_add_rg(origin, gt);
828:
829: IF_DEBUG(DEBUG_CACHE) {
830: logit(LOG_DEBUG, 0, "Add cache entry (%s %s) gm:%x, parent-vif:%d",
831: inet_fmt(origin, s1, sizeof(s1)),
832: inet_fmt(mcastgrp, s2, sizeof(s2)),
833: gt->gt_grpmems, r ? r->rt_parent : -1);
834: }
835:
836: /*
837: * If there are no downstream routers that want traffic for
838: * this group, send (or retransmit) a prune upstream.
839: */
840: if (VIFM_ISEMPTY(gt->gt_grpmems))
841: send_prune(gt);
842: }
843:
844: /*
845: * A router has gone down. Remove prune state pertinent to that router.
846: */
847: void reset_neighbor_state(vifi_t vifi, u_int32 addr)
848: {
849: struct rtentry *r;
850: struct gtable *g;
851: struct ptable *pt, **ptnp;
852: struct stable *st;
853:
854: for (g = kernel_table; g; g = g->gt_gnext) {
855: r = g->gt_route;
856:
857: /*
858: * If neighbor was the parent, remove the prune sent state
859: * and all of the source cache info so that prunes get
860: * regenerated.
861: */
862: if (vifi == r->rt_parent) {
863: if (addr == r->rt_gateway) {
864: IF_DEBUG(DEBUG_PEER) {
865: logit(LOG_DEBUG, 0, "reset_neighbor_state() parent reset (%s %s)",
866: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)));
867: }
868:
869: g->gt_prsent_timer = 0;
870: g->gt_grftsnt = 0;
871: while ((st = g->gt_srctbl) != NULL) {
872: g->gt_srctbl = st->st_next;
873: if (st->st_ctime != 0) {
874: k_del_rg(st->st_origin, g);
875: kroutes--;
876: }
877: free(st);
878: }
879: }
880: } else {
881: /*
882: * Remove any prunes that this router has sent us.
883: */
884: ptnp = &g->gt_pruntbl;
885: while ((pt = *ptnp) != NULL) {
886: if (pt->pt_vifi == vifi && pt->pt_router == addr) {
887: NBRM_CLR(pt->pt_index, g->gt_prunes);
888: *ptnp = pt->pt_next;
889: free(pt);
890: } else
891: ptnp = &pt->pt_next;
892: }
893:
894: /*
895: * And see if we want to forward again.
896: */
897: if (!VIFM_ISSET(vifi, g->gt_grpmems)) {
898: GET_MEMBERSHIP(g, vifi);
899: APPLY_SCOPE(g);
900: prun_add_ttls(g);
901:
902: /* Update kernel state */
903: update_kernel(g);
904: #ifdef RSRR
905: /* Send route change notification to reservation protocol. */
906: rsrr_cache_send(g,1);
907: #endif /* RSRR */
908:
909: /*
910: * If removing this prune causes us to start forwarding
911: * (e.g. the neighbor rebooted), and we sent a prune upstream,
912: * send a graft to cancel the prune.
913: */
914: if (!VIFM_ISEMPTY(g->gt_grpmems) && g->gt_prsent_timer)
915: send_graft(g);
916:
917: IF_DEBUG(DEBUG_PEER) {
918: logit(LOG_DEBUG, 0, "Reset neighbor state (%s %s) gm:%x",
919: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)), g->gt_grpmems);
920: }
921: }
922: }
923: }
924: }
925:
926: /*
927: * Delete table entry from the kernel
928: * del_flag determines how many entries to delete
929: */
930: void del_table_entry(struct rtentry *r, u_int32 mcastgrp, u_int del_flag)
931: {
932: struct gtable *g, *prev_g;
933: struct stable *st, *prev_st;
934: struct ptable *pt, *prev_pt;
935:
936: if (del_flag == DEL_ALL_ROUTES) {
937: g = r->rt_groups;
938: while (g) {
939: IF_DEBUG(DEBUG_CACHE) {
940: logit(LOG_DEBUG, 0, "del_table_entry() deleting (%s %s)",
941: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)));
942: }
943:
944: st = g->gt_srctbl;
945: while (st) {
946: if (st->st_ctime != 0) {
947: if (k_del_rg(st->st_origin, g) < 0) {
948: logit(LOG_WARNING, errno, "del_table_entry() trying to delete (%s, %s)",
949: inet_fmt(st->st_origin, s1, sizeof(s1)),
950: inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)));
951: }
952: kroutes--;
953: }
954: prev_st = st;
955: st = st->st_next;
956: free(prev_st);
957: }
958: g->gt_srctbl = NULL;
959:
960: pt = g->gt_pruntbl;
961: while (pt) {
962: prev_pt = pt;
963: pt = pt->pt_next;
964: free(prev_pt);
965: }
966: g->gt_pruntbl = NULL;
967:
968: if (g->gt_gnext)
969: g->gt_gnext->gt_gprev = g->gt_gprev;
970: if (g->gt_gprev)
971: g->gt_gprev->gt_gnext = g->gt_gnext;
972: else
973: kernel_table = g->gt_gnext;
974:
975: #ifdef RSRR
976: /* Send route change notification to reservation protocol. */
977: rsrr_cache_send(g,0);
978: rsrr_cache_clean(g);
979: #endif /* RSRR */
980: if (g->gt_rexmit_timer)
981: timer_clearTimer(g->gt_rexmit_timer);
982:
983: prev_g = g;
984: g = g->gt_next;
985: free(prev_g);
986: }
987: r->rt_groups = NULL;
988: }
989:
990: /*
991: * Dummy routine - someday this may be needed, so it is just there
992: */
993: if (del_flag == DEL_RTE_GROUP) {
994: prev_g = (struct gtable *)&r->rt_groups;
995: for (g = r->rt_groups; g; g = g->gt_next) {
996: if (g->gt_mcastgrp == mcastgrp) {
997: IF_DEBUG(DEBUG_CACHE) {
998: logit(LOG_DEBUG, 0, "del_table_entry() deleting (%s %s)",
999: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)));
1000: }
1001:
1002: st = g->gt_srctbl;
1003: while (st) {
1004: if (st->st_ctime != 0) {
1005: if (k_del_rg(st->st_origin, g) < 0) {
1006: logit(LOG_WARNING, errno, "del_table_entry() trying to delete (%s, %s)",
1007: inet_fmt(st->st_origin, s1, sizeof(s1)),
1008: inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)));
1009: }
1010: kroutes--;
1011: }
1012: prev_st = st;
1013: st = st->st_next;
1014: free(prev_st);
1015: }
1016: g->gt_srctbl = NULL;
1017:
1018: pt = g->gt_pruntbl;
1019: while (pt) {
1020: prev_pt = pt;
1021: pt = pt->pt_next;
1022: free(prev_pt);
1023: }
1024: g->gt_pruntbl = NULL;
1025:
1026: if (g->gt_gnext)
1027: g->gt_gnext->gt_gprev = g->gt_gprev;
1028: if (g->gt_gprev)
1029: g->gt_gprev->gt_gnext = g->gt_gnext;
1030: else
1031: kernel_table = g->gt_gnext;
1032:
1033: if (prev_g != (struct gtable *)&r->rt_groups)
1034: g->gt_next->gt_prev = prev_g;
1035: else
1036: g->gt_next->gt_prev = NULL;
1037: prev_g->gt_next = g->gt_next;
1038:
1039: if (g->gt_rexmit_timer)
1040: timer_clearTimer(g->gt_rexmit_timer);
1041: #ifdef RSRR
1042: /* Send route change notification to reservation protocol. */
1043: rsrr_cache_send(g,0);
1044: rsrr_cache_clean(g);
1045: #endif /* RSRR */
1046: free(g);
1047: g = prev_g;
1048: } else {
1049: prev_g = g;
1050: }
1051: }
1052: }
1053: }
1054:
1055: /*
1056: * update kernel table entry when a route entry changes
1057: */
1058: void update_table_entry(struct rtentry *r, u_int32 old_parent_gw)
1059: {
1060: struct gtable *g;
1061: struct ptable *pt, **ptnp;
1062:
1063: for (g = r->rt_groups; g; g = g->gt_next) {
1064: ptnp = &g->gt_pruntbl;
1065: /*
1066: * Delete prune entries from non-children, or non-subordinates.
1067: */
1068: while ((pt = *ptnp)) {
1069: if (!VIFM_ISSET(pt->pt_vifi, r->rt_children) ||
1070: !NBRM_ISSET(pt->pt_index, r->rt_subordinates)) {
1071:
1072: IF_DEBUG(DEBUG_PRUNE) {
1073: logit(LOG_DEBUG, 0, "update_table_entry() deleting prune for (%s %s) from %s on vif %d -%s%s",
1074: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)),
1075: inet_fmt(pt->pt_router, s3, sizeof(s3)), pt->pt_vifi,
1076: VIFM_ISSET(pt->pt_vifi, r->rt_children) ? "" : " not a child",
1077: NBRM_ISSET(pt->pt_index, r->rt_subordinates) ? "" : " not a subordinate");
1078: }
1079:
1080: if (!NBRM_ISSET(pt->pt_index, g->gt_prunes)) {
1081: logit(LOG_WARNING, 0, "gt_prunes lost track of (%s %s) from %s on vif %d",
1082: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)),
1083: inet_fmt(pt->pt_router, s3, sizeof(s3)), pt->pt_vifi);
1084: }
1085:
1086: NBRM_CLR(pt->pt_index, g->gt_prunes);
1087: *ptnp = pt->pt_next;
1088: free(pt);
1089: continue;
1090: }
1091: ptnp = &((*ptnp)->pt_next);
1092: }
1093:
1094: IF_DEBUG(DEBUG_CACHE) {
1095: logit(LOG_DEBUG, 0, "Updating cache entries (%s %s) old gm:%x",
1096: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)), g->gt_grpmems);
1097: }
1098:
1099: /*
1100: * Forget about a prune or graft that we sent previously if we
1101: * have a new parent router (since the new parent router will
1102: * know nothing about what I sent to the previous parent). The
1103: * old parent will forget any prune state it is keeping for us.
1104: */
1105: if (old_parent_gw != r->rt_gateway) {
1106: g->gt_prsent_timer = 0;
1107: g->gt_grftsnt = 0;
1108: }
1109:
1110: /* Recalculate membership */
1111: determine_forwvifs(g);
1112: /* send a prune or graft if needed. */
1113: send_prune_or_graft(g);
1114:
1115: IF_DEBUG(DEBUG_CACHE) {
1116: logit(LOG_DEBUG, 0, "Updating cache entries (%s %s) new gm:%x",
1117: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)), g->gt_grpmems);
1118: }
1119:
1120: /* update ttls and add entry into kernel */
1121: prun_add_ttls(g);
1122: update_kernel(g);
1123: #ifdef RSRR
1124: /* Send route change notification to reservation protocol. */
1125: rsrr_cache_send(g,1);
1126: #endif /* RSRR */
1127: }
1128: }
1129:
1130: /*
1131: * set the forwarding flag for all mcastgrps on this vifi
1132: */
1133: void update_lclgrp(vifi_t vifi, u_int32 mcastgrp)
1134: {
1135: struct rtentry *r;
1136: struct gtable *g;
1137:
1138: IF_DEBUG(DEBUG_MEMBER) {
1139: logit(LOG_DEBUG, 0, "Group %s joined on vif %d", inet_fmt(mcastgrp, s1, sizeof(s1)), vifi);
1140: }
1141:
1142: for (g = kernel_table; g; g = g->gt_gnext) {
1143: if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
1144: break;
1145:
1146: r = g->gt_route;
1147: if (g->gt_mcastgrp == mcastgrp &&
1148: VIFM_ISSET(vifi, r->rt_children)) {
1149:
1150: VIFM_SET(vifi, g->gt_grpmems);
1151: APPLY_SCOPE(g);
1152: if (VIFM_ISEMPTY(g->gt_grpmems))
1153: continue;
1154:
1155: prun_add_ttls(g);
1156: IF_DEBUG(DEBUG_CACHE){
1157: logit(LOG_DEBUG, 0, "Update lclgrp (%s %s) gm:%x", RT_FMT(r, s1),
1158: inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)), g->gt_grpmems);
1159: }
1160:
1161: update_kernel(g);
1162: #ifdef RSRR
1163: /* Send route change notification to reservation protocol. */
1164: rsrr_cache_send(g,1);
1165: #endif /* RSRR */
1166: }
1167: }
1168: }
1169:
1170: /*
1171: * reset forwarding flag for all mcastgrps on this vifi
1172: */
1173: void delete_lclgrp(vifi_t vifi, u_int32 mcastgrp)
1174: {
1175: struct gtable *g;
1176:
1177: IF_DEBUG(DEBUG_MEMBER) {
1178: logit(LOG_DEBUG, 0, "Group %s left on vif %d", inet_fmt(mcastgrp, s1, sizeof(s1)), vifi);
1179: }
1180:
1181: for (g = kernel_table; g; g = g->gt_gnext) {
1182: if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
1183: break;
1184:
1185: if (g->gt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, g->gt_grpmems)) {
1186: if (g->gt_route == NULL ||
1187: SUBS_ARE_PRUNED(g->gt_route->rt_subordinates,
1188: uvifs[vifi].uv_nbrmap, g->gt_prunes)) {
1189: VIFM_CLR(vifi, g->gt_grpmems);
1190:
1191: IF_DEBUG(DEBUG_CACHE) {
1192: logit(LOG_DEBUG, 0, "Delete lclgrp (%s %s) gm:%x",
1193: RT_FMT(g->gt_route, s1),
1194: inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)), g->gt_grpmems);
1195: }
1196:
1197: prun_add_ttls(g);
1198: update_kernel(g);
1199: #ifdef RSRR
1200: /* Send route change notification to reservation protocol. */
1201: rsrr_cache_send(g,1);
1202: #endif /* RSRR */
1203:
1204: /*
1205: * If there are no more members of this particular group,
1206: * send prune upstream
1207: */
1208: if (VIFM_ISEMPTY(g->gt_grpmems) && g->gt_route->rt_gateway)
1209: send_prune(g);
1210: }
1211: }
1212: }
1213: }
1214:
1215: /*
1216: * Takes the prune message received and then strips it to
1217: * determine the (src, grp) pair to be pruned.
1218: *
1219: * Adds the router to the (src, grp) entry then.
1220: *
1221: * Determines if further packets have to be sent down that vif
1222: *
1223: * Determines if a corresponding prune message has to be generated
1224: */
1225: void accept_prune(u_int32 src, u_int32 dst, char *p, size_t datalen)
1226: {
1227: u_int32 prun_src;
1228: u_int32 prun_grp;
1229: u_int32 prun_tmr;
1230: vifi_t vifi;
1231: int i;
1232: struct rtentry *r;
1233: struct gtable *g;
1234: struct ptable *pt;
1235:
1236: if ((vifi = find_vif(src, dst)) == NO_VIF) {
1237: logit(LOG_INFO, 0, "Ignoring prune report from non-neighbor %s",
1238: inet_fmt(src, s1, sizeof(s1)));
1239: return;
1240: }
1241:
1242: /* Check if enough data is present */
1243: if (datalen < 12) {
1244: logit(LOG_WARNING, 0, "Non-decipherable prune from %s",
1245: inet_fmt(src, s1, sizeof(s1)));
1246: return;
1247: }
1248:
1249: for (i = 0; i< 4; i++)
1250: ((char *)&prun_src)[i] = *p++;
1251: for (i = 0; i< 4; i++)
1252: ((char *)&prun_grp)[i] = *p++;
1253: for (i = 0; i< 4; i++)
1254: ((char *)&prun_tmr)[i] = *p++;
1255: prun_tmr = ntohl(prun_tmr);
1256:
1257: if (prun_tmr <= MIN_PRUNE_LIFE) {
1258: IF_DEBUG(DEBUG_PRUNE) {
1259: logit(LOG_DEBUG, 0, "Ignoring prune from %s on vif %d for (%s %s)/%d because its lifetime is too short",
1260: inet_fmt(src, s1, sizeof(s1)), vifi,
1261: inet_fmt(prun_src, s2, sizeof(s2)), inet_fmt(prun_grp, s3, sizeof(s3)), prun_tmr);
1262: }
1263: return;
1264: }
1265:
1266: IF_DEBUG(DEBUG_PRUNE) {
1267: logit(LOG_DEBUG, 0, "%s on vif %d prunes (%s %s)/%d", inet_fmt(src, s1, sizeof(s1)),
1268: vifi, inet_fmt(prun_src, s2, sizeof(s2)),
1269: inet_fmt(prun_grp, s3, sizeof(s3)), prun_tmr);
1270: }
1271:
1272: /*
1273: * Find the subnet for the prune
1274: */
1275: if (find_src_grp(prun_src, 0, prun_grp)) {
1276: g = gtp ? gtp->gt_gnext : kernel_table;
1277: r = g->gt_route;
1278:
1279: IF_DEBUG(DEBUG_PRUNE) {
1280: logit(LOG_DEBUG, 0, "Found grp state, (%s %s), metric is %d, children are %x, subords are %08x%08x",
1281: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)), r->rt_metric,
1282: r->rt_children, r->rt_subordinates.hi, r->rt_subordinates.lo);
1283: }
1284:
1285: if (!VIFM_ISSET(vifi, r->rt_children)) {
1286: IF_DEBUG(DEBUG_PRUNE) {
1287: logit(LOG_WARNING, 0, "Prune received from non-child %s for (%s %s) (dominant on vif %d is %s)",
1288: inet_fmt(src, s1, sizeof(s1)), inet_fmt(prun_src, s2, sizeof(s2)),
1289: inet_fmt(prun_grp, s3, sizeof(s3)), vifi, inet_fmt(r->rt_dominants[vifi], s4, sizeof(s4)));
1290: }
1291: #ifdef RINGBUFFER
1292: printringbuf();
1293: #endif
1294: return;
1295: }
1296: if (VIFM_ISSET(vifi, g->gt_scope)) {
1297: logit(LOG_WARNING, 0, "Prune received from %s on scoped grp (%s %s)",
1298: inet_fmt(src, s1, sizeof(s1)), inet_fmt(prun_src, s2, sizeof(s2)),
1299: inet_fmt(prun_grp, s3, sizeof(s3)));
1300: return;
1301: }
1302: if ((pt = find_prune_entry(src, g->gt_pruntbl)) != NULL) {
1303: IF_DEBUG(DEBUG_PRUNE) {
1304: logit(LOG_DEBUG, 0, "Duplicate prune received on vif %d from %s for (%s %s)/%d old timer: %d cur gm: %x",
1305: vifi, inet_fmt(src, s1, sizeof(s1)), inet_fmt(prun_src, s2, sizeof(s2)),
1306: inet_fmt(prun_grp, s3, sizeof(s3)), prun_tmr, pt->pt_timer, g->gt_grpmems);
1307: }
1308: pt->pt_timer = prun_tmr;
1309: } else {
1310: struct listaddr *n = neighbor_info(vifi, src);
1311:
1312: if (!n) {
1313: logit(LOG_WARNING, 0, "Prune from non-neighbor %s on vif %d!?",
1314: inet_fmt(src, s1, sizeof(s1)), vifi);
1315: return;
1316: }
1317:
1318: /* allocate space for the prune structure */
1319: pt = (struct ptable *)(malloc(sizeof(struct ptable)));
1320: if (pt == NULL) {
1321: logit(LOG_ERR, 0, "pt: ran out of memory");
1322: return; /* NOTREACHED */
1323: }
1324:
1325: pt->pt_vifi = vifi;
1326: pt->pt_router = src;
1327: pt->pt_timer = prun_tmr;
1328:
1329: pt->pt_next = g->gt_pruntbl;
1330: g->gt_pruntbl = pt;
1331:
1332: if (n) {
1333: pt->pt_index = n->al_index;
1334: NBRM_SET(n->al_index, g->gt_prunes);
1335: }
1336: }
1337:
1338: /*
1339: * check if any more packets need to be sent on the
1340: * vif which sent this message
1341: */
1342: if (SUBS_ARE_PRUNED(r->rt_subordinates, uvifs[vifi].uv_nbrmap, g->gt_prunes) &&
1343: !grplst_mem(vifi, prun_grp)) {
1344: nbrbitmap_t tmp;
1345:
1346: VIFM_CLR(vifi, g->gt_grpmems);
1347: IF_DEBUG(DEBUG_PRUNE) {
1348: logit(LOG_DEBUG, 0, "vifnbrs=0x%08x%08x, subord=0x%08x%08x prunes=0x%08x%08x",
1349: uvifs[vifi].uv_nbrmap.hi,uvifs[vifi].uv_nbrmap.lo,
1350: r->rt_subordinates.hi, r->rt_subordinates.lo,
1351: g->gt_prunes.hi, g->gt_prunes.lo);
1352: }
1353:
1354: /* XXX debugging */
1355: NBRM_COPY(r->rt_subordinates, tmp);
1356: NBRM_MASK(tmp, uvifs[vifi].uv_nbrmap);
1357: if (!NBRM_ISSETALLMASK(g->gt_prunes, tmp))
1358: logit(LOG_WARNING, 0, "Subordinate error");
1359: /* XXX end debugging */
1360:
1361: IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE) {
1362: logit(LOG_DEBUG, 0, "Prune (%s %s), stop sending on vif %d, gm:%x",
1363: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)), vifi, g->gt_grpmems);
1364: }
1365:
1366: prun_add_ttls(g);
1367: update_kernel(g);
1368: #ifdef RSRR
1369: /* Send route change notification to reservation protocol. */
1370: rsrr_cache_send(g,1);
1371: #endif /* RSRR */
1372: }
1373:
1374: /*
1375: * check if all the child routers have expressed no interest
1376: * in this group and if this group does not exist in the
1377: * interface
1378: * Send a prune message then upstream
1379: */
1380: if (VIFM_ISEMPTY(g->gt_grpmems) && r->rt_gateway) {
1381: send_prune(g);
1382: }
1383: } else {
1384: /*
1385: * There is no kernel entry for this group. Therefore, we can
1386: * simply ignore the prune, as we are not forwarding this traffic
1387: * downstream.
1388: */
1389: IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE) {
1390: logit(LOG_DEBUG, 0, "Prune message received with no kernel entry for (%s %s)/%d from %s",
1391: inet_fmt(prun_src, s1, sizeof(s1)), inet_fmt(prun_grp, s2, sizeof(s2)),
1392: prun_tmr, inet_fmt(src, s3, sizeof(s3)));
1393: }
1394: return;
1395: }
1396: }
1397:
1398: /*
1399: * Checks if this mcastgrp is present in the kernel table
1400: * If so and if a prune was sent, it sends a graft upwards
1401: */
1402: void chkgrp_graft(vifi_t vifi, u_int32 mcastgrp)
1403: {
1404: struct rtentry *r;
1405: struct gtable *g;
1406:
1407: for (g = kernel_table; g; g = g->gt_gnext) {
1408: if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
1409: break;
1410:
1411: r = g->gt_route;
1412: if (g->gt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, r->rt_children))
1413: if (g->gt_prsent_timer) {
1414: VIFM_SET(vifi, g->gt_grpmems);
1415:
1416: /*
1417: * If the vif that was joined was a scoped vif,
1418: * ignore it ; don't graft back
1419: */
1420: APPLY_SCOPE(g);
1421: if (VIFM_ISEMPTY(g->gt_grpmems))
1422: continue;
1423:
1424: /* send graft upwards */
1425: send_graft(g);
1426:
1427: /* update cache timer*/
1428: g->gt_timer = CACHE_LIFETIME(cache_lifetime);
1429:
1430: IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE) {
1431: logit(LOG_DEBUG, 0, "chkgrp graft (%s %s) gm:%x",
1432: RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)), g->gt_grpmems);
1433: }
1434:
1435: prun_add_ttls(g);
1436: update_kernel(g);
1437: #ifdef RSRR
1438: /* Send route change notification to reservation protocol. */
1439: rsrr_cache_send(g,1);
1440: #endif /* RSRR */
1441: }
1442: }
1443: }
1444:
1445: /* determine the multicast group and src
1446: *
1447: * if it does, then determine if a prune was sent
1448: * upstream.
1449: * if prune sent upstream, send graft upstream and send
1450: * ack downstream.
1451: *
1452: * if no prune sent upstream, change the forwarding bit
1453: * for this interface and send ack downstream.
1454: *
1455: * if no entry exists for this group send ack downstream.
1456: */
1457: void accept_graft(u_int32 src, u_int32 dst, char *p, size_t datalen)
1458: {
1459: vifi_t vifi;
1460: u_int32 graft_src;
1461: u_int32 graft_grp;
1462: int i;
1463: struct rtentry *r;
1464: struct gtable *g;
1465: struct ptable *pt, **ptnp;
1466:
1467: if (datalen < 8) {
1468: logit(LOG_WARNING, 0, "Received non-decipherable graft from %s",
1469: inet_fmt(src, s1, sizeof(s1)));
1470: return;
1471: }
1472:
1473: for (i = 0; i< 4; i++)
1474: ((char *)&graft_src)[i] = *p++;
1475: for (i = 0; i< 4; i++)
1476: ((char *)&graft_grp)[i] = *p++;
1477:
1478: vifi = find_vif(src, dst);
1479: send_graft_ack(dst, src, graft_src, graft_grp, vifi);
1480:
1481: if (vifi == NO_VIF) {
1482: logit(LOG_INFO, 0, "Ignoring graft for (%s %s) from non-neighbor %s",
1483: inet_fmt(graft_src, s2, sizeof(s2)), inet_fmt(graft_grp, s3, sizeof(s3)),
1484: inet_fmt(src, s1, sizeof(s1)));
1485: return;
1486: }
1487:
1488: IF_DEBUG(DEBUG_PRUNE) {
1489: logit(LOG_DEBUG, 0, "%s on vif %d grafts (%s %s)", inet_fmt(src, s1, sizeof(s1)), vifi,
1490: inet_fmt(graft_src, s2, sizeof(s2)), inet_fmt(graft_grp, s3, sizeof(s3)));
1491: }
1492:
1493: /*
1494: * Find the subnet for the graft
1495: */
1496: if (find_src_grp(graft_src, 0, graft_grp)) {
1497: g = gtp ? gtp->gt_gnext : kernel_table;
1498: r = g->gt_route;
1499:
1500: if (VIFM_ISSET(vifi, g->gt_scope)) {
1501: logit(LOG_WARNING, 0, "Graft received from %s on scoped grp (%s %s)",
1502: inet_fmt(src, s1, sizeof(s1)), inet_fmt(graft_src, s2, sizeof(s2)),
1503: inet_fmt(graft_grp, s3, sizeof(s3)));
1504: return;
1505: }
1506:
1507: ptnp = &g->gt_pruntbl;
1508: while ((pt = *ptnp) != NULL) {
1509: if ((pt->pt_vifi == vifi) && (pt->pt_router == src)) {
1510: NBRM_CLR(pt->pt_index, g->gt_prunes);
1511: *ptnp = pt->pt_next;
1512: free(pt);
1513:
1514: VIFM_SET(vifi, g->gt_grpmems);
1515: IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE) {
1516: logit(LOG_DEBUG, 0, "Accept graft (%s %s) gm:%x", RT_FMT(r, s1),
1517: inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)), g->gt_grpmems);
1518: }
1519:
1520: prun_add_ttls(g);
1521: update_kernel(g);
1522: #ifdef RSRR
1523: /* Send route change notification to reservation protocol. */
1524: rsrr_cache_send(g,1);
1525: #endif /* RSRR */
1526: break;
1527: } else {
1528: ptnp = &pt->pt_next;
1529: }
1530: }
1531:
1532: g->gt_timer = CACHE_LIFETIME(cache_lifetime);
1533:
1534: if (g->gt_prsent_timer)
1535: /* send graft upwards */
1536: send_graft(g);
1537: } else {
1538: /*
1539: * We have no state for the source and group in question.
1540: * This is fine, since we know that we have no prune state, and
1541: * grafts are requests to remove prune state.
1542: */
1543: IF_DEBUG(DEBUG_PRUNE){
1544: logit(LOG_DEBUG, 0, "Graft received with no kernel entry for (%s %s) from %s",
1545: inet_fmt(graft_src, s1, sizeof(s1)), inet_fmt(graft_grp, s2, sizeof(s2)),
1546: inet_fmt(src, s3, sizeof(s3)));
1547: }
1548: return;
1549: }
1550: }
1551:
1552: /*
1553: * find out which group is involved first of all
1554: * then determine if a graft was sent.
1555: * if no graft sent, ignore the message
1556: * if graft was sent and the ack is from the right
1557: * source, remove the graft timer so that we don't
1558: * have send a graft again
1559: */
1560: void accept_g_ack(u_int32 src, u_int32 dst, char *p, size_t datalen)
1561: {
1562: struct gtable *g;
1563: vifi_t vifi;
1564: u_int32 grft_src;
1565: u_int32 grft_grp;
1566: int i;
1567:
1568: if ((vifi = find_vif(src, dst)) == NO_VIF) {
1569: logit(LOG_INFO, 0, "Ignoring graft ack from non-neighbor %s",
1570: inet_fmt(src, s1, sizeof(s1)));
1571: return;
1572: }
1573:
1574: if (datalen > 8) {
1575: logit(LOG_WARNING, 0, "Received non-decipherable graft ack from %s",
1576: inet_fmt(src, s1, sizeof(s1)));
1577: return;
1578: }
1579:
1580: for (i = 0; i< 4; i++)
1581: ((char *)&grft_src)[i] = *p++;
1582: for (i = 0; i< 4; i++)
1583: ((char *)&grft_grp)[i] = *p++;
1584:
1585: IF_DEBUG(DEBUG_PRUNE) {
1586: logit(LOG_DEBUG, 0, "%s on vif %d acks graft (%s, %s)", inet_fmt(src, s1, sizeof(s1)),
1587: vifi, inet_fmt(grft_src, s2, sizeof(s2)), inet_fmt(grft_grp, s3, sizeof(s3)));
1588: }
1589:
1590: /*
1591: * Find the subnet for the graft ack
1592: */
1593: if (find_src_grp(grft_src, 0, grft_grp)) {
1594: g = gtp ? gtp->gt_gnext : kernel_table;
1595: g->gt_grftsnt = 0;
1596: } else {
1597: logit(LOG_WARNING, 0, "Received graft ACK with no kernel entry for (%s, %s) from %s",
1598: inet_fmt(grft_src, s1, sizeof(s1)), inet_fmt(grft_grp, s2, sizeof(s2)),
1599: inet_fmt(src, s3, sizeof(s3)));
1600: #ifdef RINGBUFFER
1601: printringbuf();
1602: #endif
1603: return;
1604: }
1605: }
1606:
1607:
1608: /*
1609: * free all prune entries and kernel routes
1610: * normally, this should inform the kernel that all of its routes
1611: * are going away, but this is only called by restart(), which is
1612: * about to call MRT_DONE which does that anyway.
1613: */
1614: void free_all_prunes(void)
1615: {
1616: register struct rtentry *r;
1617: register struct gtable *g, *prev_g;
1618: register struct stable *s, *prev_s;
1619: register struct ptable *p, *prev_p;
1620:
1621: for (r = routing_table; r; r = r->rt_next) {
1622: g = r->rt_groups;
1623: while (g) {
1624: s = g->gt_srctbl;
1625: while (s) {
1626: prev_s = s;
1627: s = s->st_next;
1628: free(prev_s);
1629: }
1630:
1631: p = g->gt_pruntbl;
1632: while (p) {
1633: prev_p = p;
1634: p = p->pt_next;
1635: free(prev_p);
1636: }
1637:
1638: prev_g = g;
1639: g = g->gt_next;
1640: if (prev_g->gt_rexmit_timer)
1641: timer_clearTimer(prev_g->gt_rexmit_timer);
1642: free(prev_g);
1643: }
1644: r->rt_groups = NULL;
1645: }
1646: kernel_table = NULL;
1647:
1648: g = kernel_no_route;
1649: while (g) {
1650: if (g->gt_srctbl)
1651: free(g->gt_srctbl);
1652:
1653: prev_g = g;
1654: g = g->gt_next;
1655: if (prev_g->gt_rexmit_timer)
1656: timer_clearTimer(prev_g->gt_rexmit_timer);
1657: free(prev_g);
1658: }
1659: kernel_no_route = NULL;
1660: }
1661:
1662: /*
1663: * When a new route is created, search
1664: * a) The less-specific part of the routing table
1665: * b) The route-less kernel table
1666: * for sources that the new route might want to handle.
1667: *
1668: * "Inheriting" these sources might be cleanest, but simply deleting
1669: * them is easier, and letting the kernel re-request them.
1670: */
1671: void steal_sources(struct rtentry *rt)
1672: {
1673: struct rtentry *rp;
1674: struct gtable *gt, **gtnp;
1675: struct stable *st, **stnp;
1676:
1677: for (rp = rt->rt_next; rp; rp = rp->rt_next) {
1678: if (rp->rt_groups == NULL)
1679: continue;
1680: if ((rt->rt_origin & rp->rt_originmask) == rp->rt_origin) {
1681: IF_DEBUG(DEBUG_ROUTE) {
1682: logit(LOG_DEBUG, 0, "Route for %s stealing sources from %s",
1683: RT_FMT(rt, s1), RT_FMT(rp, s2));
1684: }
1685:
1686: for (gt = rp->rt_groups; gt; gt = gt->gt_next) {
1687: stnp = >->gt_srctbl;
1688: while ((st = *stnp) != NULL) {
1689: if ((st->st_origin & rt->rt_originmask) == rt->rt_origin) {
1690: IF_DEBUG(DEBUG_ROUTE) {
1691: logit(LOG_DEBUG, 0, "%s stealing (%s %s) from %s",
1692: RT_FMT(rt, s1), inet_fmt(st->st_origin, s3, sizeof(s3)),
1693: inet_fmt(gt->gt_mcastgrp, s4, sizeof(s4)), RT_FMT(rp, s2));
1694: }
1695:
1696: if (st->st_ctime != 0) {
1697: if (k_del_rg(st->st_origin, gt) < 0) {
1698: logit(LOG_WARNING, errno, "steal_sources() trying to delete (%s, %s)",
1699: inet_fmt(st->st_origin, s1, sizeof(s1)),
1700: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
1701: }
1702: kroutes--;
1703: }
1704: *stnp = st->st_next;
1705: free(st);
1706: } else {
1707: stnp = &st->st_next;
1708: }
1709: }
1710: }
1711: }
1712: }
1713:
1714: gtnp = &kernel_no_route;
1715: while ((gt = *gtnp) != NULL) {
1716: if (gt->gt_srctbl &&
1717: (gt->gt_srctbl->st_origin & rt->rt_originmask) == rt->rt_origin) {
1718: IF_DEBUG(DEBUG_ROUTE) {
1719: logit(LOG_DEBUG, 0, "%s stealing (%s %s) from no_route table", RT_FMT(rt, s1),
1720: inet_fmt(gt->gt_srctbl->st_origin, s3, sizeof(s3)),
1721: inet_fmt(gt->gt_mcastgrp, s4, sizeof(s4)));
1722: }
1723:
1724: if (gt->gt_srctbl->st_ctime != 0) {
1725: if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
1726: logit(LOG_WARNING, errno, "steal_sources() trying to delete (%s %s)",
1727: inet_fmt(gt->gt_srctbl->st_origin, s1, sizeof(s1)),
1728: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
1729: }
1730: kroutes--;
1731: }
1732: free(gt->gt_srctbl);
1733: *gtnp = gt->gt_next;
1734: if (gt->gt_next)
1735: gt->gt_next->gt_prev = gt->gt_prev;
1736: if (gt->gt_rexmit_timer)
1737: timer_clearTimer(gt->gt_rexmit_timer);
1738: free(gt);
1739: } else {
1740: gtnp = >->gt_next;
1741: }
1742: }
1743: }
1744:
1745: /*
1746: * Advance the timers on all the cache entries.
1747: * If there are any entries whose timers have expired,
1748: * remove these entries from the kernel cache.
1749: */
1750: void age_table_entry(void)
1751: {
1752: struct rtentry *r;
1753: struct gtable *gt, **gtnptr;
1754: struct stable *st, **stnp;
1755: struct ptable *pt, **ptnp;
1756: struct sioc_sg_req sg_req;
1757:
1758: IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE) {
1759: logit(LOG_DEBUG, 0, "Aging forwarding cache entries");
1760: }
1761:
1762: gtnptr = &kernel_table;
1763: while ((gt = *gtnptr) != NULL) {
1764: vifi_t i; /* XXX Debugging */
1765: int fixit = 0; /* XXX Debugging */
1766:
1767: r = gt->gt_route;
1768:
1769: /* XXX Debugging... */
1770: for (i = 0; i < numvifs; i++) {
1771: /*
1772: * If we're not sending on this vif,
1773: * And this group isn't scoped on this vif,
1774: * And I'm the parent for this route on this vif,
1775: * And there are subordinates on this vif,
1776: * And all of the subordinates haven't pruned,
1777: * YELL LOUDLY
1778: * and remember to fix it up later
1779: */
1780: if (!VIFM_ISSET(i, gt->gt_grpmems) &&
1781: !VIFM_ISSET(i, gt->gt_scope) &&
1782: VIFM_ISSET(i, r->rt_children) &&
1783: NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates) &&
1784: !SUBS_ARE_PRUNED(r->rt_subordinates, uvifs[i].uv_nbrmap, gt->gt_prunes)) {
1785: logit(LOG_WARNING, 0, "(%s %s) is blackholing on vif %d",
1786: RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)), i);
1787: fixit = 1;
1788: }
1789: }
1790: if (fixit) {
1791: logit(LOG_WARNING, 0, "Fixing membership for (%s %s) gm:%x",
1792: RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)), gt->gt_grpmems);
1793: determine_forwvifs(gt);
1794: send_prune_or_graft(gt);
1795: logit(LOG_WARNING, 0, "Fixed membership for (%s %s) gm:%x",
1796: RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)), gt->gt_grpmems);
1797: #ifdef RINGBUFFER
1798: printringbuf();
1799: #endif
1800: }
1801: /*DEBUG2*/
1802: /* If there are group members,
1803: * and there are recent sources,
1804: * and we have a route,
1805: * and it's not directly connected,
1806: * and we haven't sent a prune,
1807: * if there are any cache entries in the kernel
1808: * [if there aren't we're probably waiting to rexmit],
1809: * YELL LOUDLY
1810: * and send a prune
1811: */
1812: if (VIFM_ISEMPTY(gt->gt_grpmems) && gt->gt_srctbl && r && r->rt_gateway && gt->gt_prsent_timer == 0) {
1813: for (st = gt->gt_srctbl; st; st = st->st_next)
1814: if (st->st_ctime != 0)
1815: break;
1816: if (st != NULL) {
1817: logit(LOG_WARNING, 0, "Group members for (%s %s) is empty but no prune state!", RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
1818: send_prune_or_graft(gt);
1819: #ifdef RINGBUFFER
1820: printringbuf();
1821: #endif
1822: }
1823: }
1824: /* XXX ...Debugging */
1825:
1826: /* advance the timer for the kernel entry */
1827: gt->gt_timer -= TIMER_INTERVAL;
1828:
1829: /* decrement prune timer if need be */
1830: if (gt->gt_prsent_timer > 0) {
1831: gt->gt_prsent_timer -= TIMER_INTERVAL;
1832: if (gt->gt_prsent_timer <= 0) {
1833: IF_DEBUG(DEBUG_PRUNE) {
1834: logit(LOG_DEBUG, 0, "Upstream prune tmo (%s %s)", RT_FMT(r, s1),
1835: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
1836: }
1837:
1838: /* Reset the prune retransmission timer to its initial value */
1839: gt->gt_prune_rexmit = PRUNE_REXMIT_VAL;
1840: gt->gt_prsent_timer = -1;
1841: }
1842: }
1843:
1844: /* retransmit graft with exponential backoff */
1845: if (gt->gt_grftsnt) {
1846: register int y;
1847:
1848: y = ++gt->gt_grftsnt;
1849: while (y && !(y & 1))
1850: y >>= 1;
1851: if (y == 1)
1852: send_graft(gt);
1853: }
1854:
1855: /*
1856: * Age prunes
1857: *
1858: * If a prune expires, forward again on that vif.
1859: */
1860: ptnp = >->gt_pruntbl;
1861: while ((pt = *ptnp) != NULL) {
1862: if ((pt->pt_timer -= TIMER_INTERVAL) <= 0) {
1863: IF_DEBUG(DEBUG_PRUNE) {
1864: logit(LOG_DEBUG, 0, "Expire prune (%s %s) from %s on vif %d",
1865: RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)),
1866: inet_fmt(pt->pt_router, s3, sizeof(s3)), pt->pt_vifi);
1867: }
1868:
1869: if (gt->gt_prsent_timer > 0) {
1870: logit(LOG_WARNING, 0, "Prune (%s %s) from %s on vif %d expires with %d left on prsent timer",
1871: RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)),
1872: inet_fmt(pt->pt_router, s3, sizeof(s3)), pt->pt_vifi, gt->gt_prsent_timer);
1873:
1874: /* Send a graft to heal the tree. */
1875: send_graft(gt);
1876: }
1877:
1878: NBRM_CLR(pt->pt_index, gt->gt_prunes);
1879: expire_prune(pt->pt_vifi, gt);
1880:
1881: /* remove the router's prune entry and await new one */
1882: *ptnp = pt->pt_next;
1883: free(pt);
1884: } else {
1885: ptnp = &pt->pt_next;
1886: }
1887: }
1888:
1889: /*
1890: * If the cache entry has expired, delete source table entries for
1891: * silent sources. If there are no source entries left, and there
1892: * are no downstream prunes, then the entry is deleted.
1893: * Otherwise, the cache entry's timer is refreshed.
1894: */
1895: if (gt->gt_timer <= 0) {
1896: IF_DEBUG(DEBUG_CACHE) {
1897: logit(LOG_DEBUG, 0, "(%s %s) timed out, checking for traffic",
1898: RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
1899: }
1900: /* Check for traffic before deleting source entries */
1901: sg_req.grp.s_addr = gt->gt_mcastgrp;
1902: stnp = >->gt_srctbl;
1903: while ((st = *stnp) != NULL) {
1904: /*
1905: * Source entries with no ctime are not actually in the
1906: * kernel; they have been removed by rexmit_prune() so
1907: * are safe to remove from the list at this point.
1908: */
1909: if (st->st_ctime) {
1910: sg_req.src.s_addr = st->st_origin;
1911: if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) {
1912: logit(LOG_WARNING, errno, "age_table_entry() Failed ioctl SIOCGETSGCNT for (%s %s)",
1913: inet_fmt(st->st_origin, s1, sizeof(s1)),
1914: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
1915:
1916: /* Make sure it gets deleted below */
1917: sg_req.pktcnt = st->st_pktcnt;
1918: }
1919: } else {
1920: sg_req.pktcnt = st->st_pktcnt;
1921: }
1922: if (sg_req.pktcnt == st->st_pktcnt) {
1923: *stnp = st->st_next;
1924: IF_DEBUG(DEBUG_CACHE) {
1925: logit(LOG_DEBUG, 0, "age_table_entry() deleting (%s %s)",
1926: inet_fmt(st->st_origin, s1, sizeof(s1)),
1927: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
1928: }
1929: if (st->st_ctime != 0) {
1930: if (k_del_rg(st->st_origin, gt) < 0) {
1931: logit(LOG_WARNING, errno, "age_table_entry() trying to delete (%s %s)",
1932: inet_fmt(st->st_origin, s1, sizeof(s1)),
1933: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
1934: }
1935: kroutes--;
1936: }
1937: free(st);
1938: } else {
1939: st->st_pktcnt = sg_req.pktcnt;
1940: stnp = &st->st_next;
1941: }
1942: }
1943:
1944: /*
1945: * Retain the group entry if we have downstream prunes or if
1946: * there is at least one source in the list that still has
1947: * traffic, or if our upstream prune timer or graft
1948: * retransmission timer is running.
1949: */
1950: if (gt->gt_pruntbl != NULL || gt->gt_srctbl != NULL ||
1951: gt->gt_prsent_timer > 0 || gt->gt_grftsnt > 0) {
1952: IF_DEBUG(DEBUG_CACHE) {
1953: logit(LOG_DEBUG, 0, "Refresh lifetime of cache entry %s%s%s%s(%s, %s)",
1954: gt->gt_pruntbl ? "(dstrm prunes) " : "",
1955: gt->gt_srctbl ? "(trfc flow) " : "",
1956: gt->gt_prsent_timer > 0 ? "(upstrm prune) " : "",
1957: gt->gt_grftsnt > 0 ? "(grft rexmit) " : "",
1958: RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
1959: }
1960: gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
1961: if (gt->gt_prsent_timer == -1) {
1962: /*
1963: * The upstream prune timed out. Remove any kernel
1964: * state.
1965: */
1966: gt->gt_prsent_timer = 0;
1967: if (gt->gt_pruntbl) {
1968: logit(LOG_WARNING, 0, "Upstream prune for (%s %s) expires with downstream prunes active",
1969: RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
1970: }
1971: remove_sources(gt);
1972: }
1973: gtnptr = >->gt_gnext;
1974: continue;
1975: }
1976:
1977: IF_DEBUG(DEBUG_CACHE){
1978: logit(LOG_DEBUG, 0, "Timeout cache entry (%s, %s)",
1979: RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
1980: }
1981:
1982: if (gt->gt_prev)
1983: gt->gt_prev->gt_next = gt->gt_next;
1984: else
1985: gt->gt_route->rt_groups = gt->gt_next;
1986: if (gt->gt_next)
1987: gt->gt_next->gt_prev = gt->gt_prev;
1988:
1989: if (gt->gt_gprev) {
1990: gt->gt_gprev->gt_gnext = gt->gt_gnext;
1991: gtnptr = >->gt_gprev->gt_gnext;
1992: } else {
1993: kernel_table = gt->gt_gnext;
1994: gtnptr = &kernel_table;
1995: }
1996: if (gt->gt_gnext)
1997: gt->gt_gnext->gt_gprev = gt->gt_gprev;
1998:
1999: #ifdef RSRR
2000: /* Send route change notification to reservation protocol. */
2001: rsrr_cache_send(gt,0);
2002: rsrr_cache_clean(gt);
2003: #endif /* RSRR */
2004: if (gt->gt_rexmit_timer)
2005: timer_clearTimer(gt->gt_rexmit_timer);
2006:
2007: free((char *)gt);
2008: } else {
2009: if (gt->gt_prsent_timer == -1) {
2010: /*
2011: * The upstream prune timed out. Remove any kernel
2012: * state.
2013: */
2014: gt->gt_prsent_timer = 0;
2015: if (gt->gt_pruntbl) {
2016: logit(LOG_WARNING, 0, "Upstream prune for (%s %s) expires with downstream prunes active",
2017: RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
2018: }
2019: remove_sources(gt);
2020: }
2021: gtnptr = >->gt_gnext;
2022: }
2023: }
2024:
2025: /*
2026: * When traversing the no_route table, the decision is much easier.
2027: * Just delete it if it has timed out.
2028: */
2029: gtnptr = &kernel_no_route;
2030: while ((gt = *gtnptr) != NULL) {
2031: /* advance the timer for the kernel entry */
2032: gt->gt_timer -= TIMER_INTERVAL;
2033:
2034: if (gt->gt_timer < 0) {
2035: if (gt->gt_srctbl) {
2036: if (gt->gt_srctbl->st_ctime != 0) {
2037: if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
2038: logit(LOG_WARNING, errno, "age_table_entry() trying to delete no-route (%s %s)",
2039: inet_fmt(gt->gt_srctbl->st_origin, s1, sizeof(s1)),
2040: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
2041: }
2042: kroutes--;
2043: }
2044: free(gt->gt_srctbl);
2045: }
2046: *gtnptr = gt->gt_next;
2047: if (gt->gt_next)
2048: gt->gt_next->gt_prev = gt->gt_prev;
2049:
2050: if (gt->gt_rexmit_timer)
2051: timer_clearTimer(gt->gt_rexmit_timer);
2052:
2053: free((char *)gt);
2054: } else {
2055: gtnptr = >->gt_next;
2056: }
2057: }
2058: }
2059:
2060: /*
2061: * Modify the kernel to forward packets when one or multiple prunes that
2062: * were received on the vif given by vifi, for the group given by gt,
2063: * have expired.
2064: */
2065: static void expire_prune(vifi_t vifi, struct gtable *gt)
2066: {
2067: /*
2068: * No need to send a graft, any prunes that we sent
2069: * will expire before any prunes that we have received.
2070: * However, in the case that we did make a mistake,
2071: * send a graft to compensate.
2072: */
2073: if (gt->gt_prsent_timer >= MIN_PRUNE_LIFE) {
2074: IF_DEBUG(DEBUG_PRUNE) {
2075: logit(LOG_DEBUG, 0, "Prune expired with %d left on prsent_timer", gt->gt_prsent_timer);
2076: }
2077: gt->gt_prsent_timer = 0;
2078: send_graft(gt);
2079: }
2080:
2081: /* modify the kernel entry to forward packets */
2082: if (!VIFM_ISSET(vifi, gt->gt_grpmems)) {
2083: struct rtentry *rt = gt->gt_route;
2084:
2085: VIFM_SET(vifi, gt->gt_grpmems);
2086: IF_DEBUG(DEBUG_CACHE) {
2087: logit(LOG_DEBUG, 0, "Forwarding again (%s %s) gm:%x vif:%d",
2088: RT_FMT(rt, s1), inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)), gt->gt_grpmems, vifi);
2089: }
2090:
2091: prun_add_ttls(gt);
2092: update_kernel(gt);
2093: #ifdef RSRR
2094: /* Send route change notification to reservation protocol. */
2095: rsrr_cache_send(gt,1);
2096: #endif /* RSRR */
2097: }
2098: }
2099:
2100: /*
2101: * Print the contents of the cache table on file 'fp2'.
2102: */
2103: void dump_cache(FILE *fp2)
2104: {
2105: struct rtentry *r;
2106: struct gtable *gt;
2107: struct stable *st;
2108: struct ptable *pt;
2109: vifi_t i;
2110: char c;
2111: time_t thyme = time(0);
2112:
2113: fprintf(fp2,
2114: "Multicast Routing Cache Table (%d entries)\n%s", kroutes,
2115: " Origin Mcast-group CTmr Age Ptmr Rx IVif Forwvifs\n");
2116: fprintf(fp2,
2117: "<(prunesrc:vif[idx]/tmr) prunebitmap\n%s",
2118: ">Source Lifetime SavPkt Pkts Bytes RPFf\n");
2119:
2120: for (gt = kernel_no_route; gt; gt = gt->gt_next) {
2121: if (gt->gt_srctbl) {
2122: fprintf(fp2, " %-18s %-15s %-8s %-8s - -1 (no route)\n",
2123: inet_fmts(gt->gt_srctbl->st_origin, 0xffffffff, s1, sizeof(s1)),
2124: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)), scaletime(gt->gt_timer),
2125: scaletime(thyme - gt->gt_ctime));
2126: fprintf(fp2, ">%s\n", inet_fmt(gt->gt_srctbl->st_origin, s1, sizeof(s1)));
2127: }
2128: }
2129:
2130: for (gt = kernel_table; gt; gt = gt->gt_gnext) {
2131: r = gt->gt_route;
2132: fprintf(fp2, " %-18s %-15s",
2133: RT_FMT(r, s1),
2134: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
2135:
2136: fprintf(fp2, " %-8s", scaletime(gt->gt_timer));
2137:
2138: fprintf(fp2, " %-8s %-8s ", scaletime(thyme - gt->gt_ctime),
2139: gt->gt_prsent_timer ? scaletime(gt->gt_prsent_timer) :
2140: " -");
2141:
2142: if (gt->gt_prune_rexmit) {
2143: int i = gt->gt_prune_rexmit;
2144: int n = 0;
2145:
2146: while (i > PRUNE_REXMIT_VAL) {
2147: n++;
2148: i /= 2;
2149: }
2150: if (n == 0 && gt->gt_prsent_timer == 0)
2151: fprintf(fp2, " -");
2152: else
2153: fprintf(fp2, "%2d", n);
2154: } else {
2155: fprintf(fp2, " -");
2156: }
2157:
2158: fprintf(fp2, " %2u%c%c", r->rt_parent,
2159: gt->gt_prsent_timer ? 'P' :
2160: gt->gt_grftsnt ? 'G' : ' ',
2161: VIFM_ISSET(r->rt_parent, gt->gt_scope) ? 'B' : ' ');
2162:
2163: for (i = 0; i < numvifs; ++i) {
2164: if (VIFM_ISSET(i, gt->gt_grpmems))
2165: fprintf(fp2, " %u ", i);
2166: else if (VIFM_ISSET(i, r->rt_children) &&
2167: NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates))
2168: fprintf(fp2, " %u%c", i,
2169: VIFM_ISSET(i, gt->gt_scope) ? 'b' :
2170: SUBS_ARE_PRUNED(r->rt_subordinates,
2171: uvifs[i].uv_nbrmap, gt->gt_prunes) ? 'p' : '!');
2172: }
2173: fprintf(fp2, "\n");
2174: if (gt->gt_pruntbl) {
2175: fprintf(fp2, "<");
2176: c = '(';
2177: for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next) {
2178: fprintf(fp2, "%c%s:%d[%d]/%d", c, inet_fmt(pt->pt_router, s1, sizeof(s1)),
2179: pt->pt_vifi, pt->pt_index, pt->pt_timer);
2180: c = ',';
2181: }
2182: fprintf(fp2, ")");
2183: fprintf(fp2, " 0x%08lx%08lx\n",/*XXX*/
2184: gt->gt_prunes.hi, gt->gt_prunes.lo);
2185: }
2186: for (st = gt->gt_srctbl; st; st = st->st_next) {
2187: fprintf(fp2, ">%-18s %-8s %6ld", inet_fmt(st->st_origin, s1, sizeof(s1)),
2188: st->st_ctime ? scaletime(thyme - st->st_ctime) : "-",
2189: st->st_savpkt);
2190: if (st->st_ctime) {
2191: struct sioc_sg_req sg_req;
2192:
2193: sg_req.src.s_addr = st->st_origin;
2194: sg_req.grp.s_addr = gt->gt_mcastgrp;
2195: if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) {
2196: logit(LOG_WARNING, errno, "dump_cache() Failed ioctl SIOCGETSGCNT on (%s %s)",
2197: inet_fmt(st->st_origin, s1, sizeof(s1)),
2198: inet_fmt(gt->gt_mcastgrp, s2, sizeof(s2)));
2199: } else {
2200: fprintf(fp2, " %8ld %8ld %4ld", sg_req.pktcnt,
2201: sg_req.bytecnt, sg_req.wrong_if);
2202: }
2203: }
2204: fprintf(fp2, "\n");
2205: }
2206: }
2207: }
2208:
2209: /*
2210: * Traceroute function which returns traceroute replies to the requesting
2211: * router. Also forwards the request to downstream routers.
2212: */
2213: void accept_mtrace(u_int32 src, u_int32 dst, u_int32 group, char *data, u_int8_t no, size_t datalen)
2214: {
2215: u_char type;
2216: struct rtentry *rt;
2217: struct gtable *gt;
2218: struct tr_query *qry;
2219: struct tr_resp *resp;
2220: int vifi;
2221: char *p;
2222: size_t rcount;
2223: int errcode = TR_NO_ERR;
2224: int resptype;
2225: struct timeval tp;
2226: struct sioc_vif_req v_req;
2227: struct sioc_sg_req sg_req;
2228:
2229: /* Remember qid across invocations */
2230: static u_int32 oqid = 0;
2231:
2232: /* timestamp the request/response */
2233: gettimeofday(&tp, 0);
2234:
2235: /*
2236: * Check if it is a query or a response
2237: */
2238: if (datalen == QLEN) {
2239: type = QUERY;
2240: IF_DEBUG(DEBUG_TRACE) {
2241: logit(LOG_DEBUG, 0, "Initial traceroute query rcvd from %s to %s",
2242: inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
2243: }
2244: } else if ((datalen - QLEN) % RLEN == 0) {
2245: type = RESP;
2246: IF_DEBUG(DEBUG_TRACE) {
2247: logit(LOG_DEBUG, 0, "In-transit traceroute query rcvd from %s to %s",
2248: inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
2249: }
2250:
2251: if (IN_MULTICAST(ntohl(dst))) {
2252: IF_DEBUG(DEBUG_TRACE) {
2253: logit(LOG_DEBUG, 0, "Dropping multicast response");
2254: }
2255: return;
2256: }
2257: } else {
2258: logit(LOG_WARNING, 0, "Non decipherable traceroute request received from %s to %s",
2259: inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
2260: return;
2261: }
2262:
2263: qry = (struct tr_query *)data;
2264:
2265: /*
2266: * if it is a packet with all reports filled, drop it
2267: */
2268: if ((rcount = (datalen - QLEN)/RLEN) == no) {
2269: IF_DEBUG(DEBUG_TRACE) {
2270: logit(LOG_DEBUG, 0, "Packet with all reports filled in");
2271: }
2272: return;
2273: }
2274:
2275: IF_DEBUG(DEBUG_TRACE) {
2276: logit(LOG_DEBUG, 0, "s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1, sizeof(s1)),
2277: inet_fmt(group, s2, sizeof(s2)), inet_fmt(qry->tr_dst, s3, sizeof(s3)));
2278: logit(LOG_DEBUG, 0, "rttl: %d rd: %s", qry->tr_rttl,
2279: inet_fmt(qry->tr_raddr, s1, sizeof(s1)));
2280: logit(LOG_DEBUG, 0, "rcount:%u, qid:%06x", rcount, qry->tr_qid);
2281: }
2282:
2283: /* determine the routing table entry for this traceroute */
2284: rt = determine_route(qry->tr_src);
2285: IF_DEBUG(DEBUG_TRACE) {
2286: if (rt) {
2287: logit(LOG_DEBUG, 0, "rt parent vif: %d rtr: %s metric: %d",
2288: rt->rt_parent, inet_fmt(rt->rt_gateway, s1, sizeof(s1)), rt->rt_metric);
2289: logit(LOG_DEBUG, 0, "rt origin %s", RT_FMT(rt, s1));
2290: } else
2291: logit(LOG_DEBUG, 0, "...no route");
2292: }
2293:
2294: /*
2295: * Query type packet - check if rte exists
2296: * Check if the query destination is a vif connected to me.
2297: * and if so, whether I should start response back
2298: */
2299: if (type == QUERY) {
2300: if (oqid == qry->tr_qid) {
2301: /*
2302: * If the multicast router is a member of the group being
2303: * queried, and the query is multicasted, then the router can
2304: * receive multiple copies of the same query. If we have already
2305: * replied to this traceroute, just ignore it this time.
2306: *
2307: * This is not a total solution, but since if this fails you
2308: * only get N copies, N <= the number of interfaces on the router,
2309: * it is not fatal.
2310: */
2311: IF_DEBUG(DEBUG_TRACE) {
2312: logit(LOG_DEBUG, 0, "Ignoring duplicate traceroute packet");
2313: }
2314: return;
2315: }
2316:
2317: if (rt == NULL) {
2318: IF_DEBUG(DEBUG_TRACE) {
2319: logit(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s",
2320: inet_fmt(qry->tr_src, s1, sizeof(s1)));
2321: }
2322: if (IN_MULTICAST(ntohl(dst)))
2323: return;
2324: }
2325: vifi = find_vif(qry->tr_dst, 0);
2326:
2327: if (vifi == NO_VIF) {
2328: /* The traceroute destination is not on one of my subnet vifs. */
2329: IF_DEBUG(DEBUG_TRACE) {
2330: logit(LOG_DEBUG, 0, "Destination %s not an interface",
2331: inet_fmt(qry->tr_dst, s1, sizeof(s1)));
2332: }
2333: if (IN_MULTICAST(ntohl(dst)))
2334: return;
2335: errcode = TR_WRONG_IF;
2336: } else if (rt != NULL && !VIFM_ISSET(vifi, rt->rt_children)) {
2337: IF_DEBUG(DEBUG_TRACE) {
2338: logit(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s",
2339: inet_fmt(qry->tr_dst, s1, sizeof(s1)), inet_fmt(qry->tr_src, s2, sizeof(s2)));
2340: }
2341: if (IN_MULTICAST(ntohl(dst)))
2342: return;
2343: errcode = TR_WRONG_IF;
2344: }
2345: } else {
2346: /*
2347: * determine which interface the packet came in on
2348: * RESP packets travel hop-by-hop so this either traversed
2349: * a tunnel or came from a directly attached mrouter.
2350: */
2351: if ((vifi = find_vif(src, dst)) == NO_VIF) {
2352: IF_DEBUG(DEBUG_TRACE) {
2353: logit(LOG_DEBUG, 0, "Wrong interface for packet");
2354: }
2355: errcode = TR_WRONG_IF;
2356: }
2357: }
2358:
2359: /* Now that we've decided to send a response, save the qid */
2360: oqid = qry->tr_qid;
2361:
2362: IF_DEBUG(DEBUG_TRACE) {
2363: logit(LOG_DEBUG, 0, "Sending traceroute response");
2364: }
2365:
2366: /* copy the packet to the sending buffer */
2367: p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
2368:
2369: memmove(p, data, datalen);
2370: p += datalen;
2371:
2372: /*
2373: * If there is no room to insert our reply, coopt the previous hop
2374: * error indication to relay this fact.
2375: */
2376: if (p + sizeof(struct tr_resp) > send_buf + RECV_BUF_SIZE) {
2377: resp = (struct tr_resp *)p - 1;
2378: resp->tr_rflags = TR_NO_SPACE;
2379: rt = NULL;
2380: goto sendit;
2381: }
2382:
2383: /*
2384: * fill in initial response fields
2385: */
2386: resp = (struct tr_resp *)p;
2387: memset(resp, 0, sizeof(struct tr_resp));
2388: datalen += RLEN;
2389:
2390: resp->tr_qarr = htonl(((tp.tv_sec + JAN_1970) << 16) +
2391: ((tp.tv_usec << 10) / 15625));
2392:
2393: resp->tr_rproto = PROTO_DVMRP;
2394: resp->tr_outaddr = (vifi == NO_VIF) ? dst : uvifs[vifi].uv_lcl_addr;
2395: resp->tr_fttl = (vifi == NO_VIF) ? 0 : uvifs[vifi].uv_threshold;
2396: resp->tr_rflags = errcode;
2397:
2398: /*
2399: * obtain # of packets out on interface
2400: */
2401: v_req.vifi = vifi;
2402: if (vifi != NO_VIF && ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
2403: resp->tr_vifout = htonl(v_req.ocount);
2404: else
2405: resp->tr_vifout = 0xffffffff;
2406:
2407: /*
2408: * fill in scoping & pruning information
2409: */
2410: if (rt)
2411: for (gt = rt->rt_groups; gt; gt = gt->gt_next) {
2412: if (gt->gt_mcastgrp >= group)
2413: break;
2414: }
2415: else
2416: gt = NULL;
2417:
2418: if (gt && gt->gt_mcastgrp == group) {
2419: struct stable *st;
2420:
2421: for (st = gt->gt_srctbl; st; st = st->st_next)
2422: if (qry->tr_src == st->st_origin)
2423: break;
2424:
2425: sg_req.src.s_addr = qry->tr_src;
2426: sg_req.grp.s_addr = group;
2427: if (st && st->st_ctime != 0 &&
2428: ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0)
2429: resp->tr_pktcnt = htonl(sg_req.pktcnt + st->st_savpkt);
2430: else
2431: resp->tr_pktcnt = htonl(st ? st->st_savpkt : 0xffffffff);
2432:
2433: if (VIFM_ISSET(vifi, gt->gt_scope))
2434: resp->tr_rflags = TR_SCOPED;
2435: else if (gt->gt_prsent_timer)
2436: resp->tr_rflags = TR_PRUNED;
2437: else if (!VIFM_ISSET(vifi, gt->gt_grpmems)) {
2438: if (!NBRM_ISEMPTY(uvifs[vifi].uv_nbrmap) &&
2439: SUBS_ARE_PRUNED(rt->rt_subordinates,
2440: uvifs[vifi].uv_nbrmap, gt->gt_prunes))
2441: resp->tr_rflags = TR_OPRUNED;
2442: else
2443: resp->tr_rflags = TR_NO_FWD;
2444: }
2445: } else {
2446: if ((vifi != NO_VIF && scoped_addr(vifi, group)) ||
2447: (rt && scoped_addr(rt->rt_parent, group)))
2448: resp->tr_rflags = TR_SCOPED;
2449: else if (rt && !VIFM_ISSET(vifi, rt->rt_children))
2450: resp->tr_rflags = TR_NO_FWD;
2451: }
2452:
2453: /*
2454: * if no rte exists, set NO_RTE error
2455: */
2456: if (rt == NULL) {
2457: src = dst; /* the dst address of resp. pkt */
2458: resp->tr_inaddr = 0;
2459: resp->tr_rflags = TR_NO_RTE;
2460: resp->tr_rmtaddr = 0;
2461: } else {
2462: /* get # of packets in on interface */
2463: v_req.vifi = rt->rt_parent;
2464: if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
2465: resp->tr_vifin = htonl(v_req.icount);
2466: else
2467: resp->tr_vifin = 0xffffffff;
2468:
2469: MASK_TO_VAL(rt->rt_originmask, resp->tr_smask);
2470: src = uvifs[rt->rt_parent].uv_lcl_addr;
2471: resp->tr_inaddr = src;
2472: resp->tr_rmtaddr = rt->rt_gateway;
2473: if (!VIFM_ISSET(vifi, rt->rt_children)) {
2474: IF_DEBUG(DEBUG_TRACE) {
2475: logit(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s",
2476: inet_fmt(qry->tr_dst, s1, sizeof(s1)), inet_fmt(qry->tr_src, s2, sizeof(s2)));
2477: }
2478: resp->tr_rflags = TR_WRONG_IF;
2479: }
2480: if (rt->rt_metric >= UNREACHABLE) {
2481: resp->tr_rflags = TR_NO_RTE;
2482: /* Hack to send reply directly */
2483: rt = NULL;
2484: }
2485: }
2486:
2487: sendit:
2488: /*
2489: * if metric is 1 or no. of reports is 1, send response to requestor
2490: * else send to upstream router. If the upstream router can't handle
2491: * mtrace, set an error code and send to requestor anyway.
2492: */
2493: IF_DEBUG(DEBUG_TRACE) {
2494: logit(LOG_DEBUG, 0, "rcount:%u, no:%u", rcount, no);
2495: }
2496:
2497: if ((rcount + 1 == no) || (rt == NULL) || (rt->rt_metric == 1)) {
2498: resptype = IGMP_MTRACE_RESP;
2499: dst = qry->tr_raddr;
2500: } else {
2501: if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) {
2502: dst = qry->tr_raddr;
2503: resp->tr_rflags = TR_OLD_ROUTER;
2504: resptype = IGMP_MTRACE_RESP;
2505: } else {
2506: dst = rt->rt_gateway;
2507: resptype = IGMP_MTRACE;
2508: }
2509: }
2510:
2511: if (IN_MULTICAST(ntohl(dst))) {
2512: /*
2513: * Send the reply on a known multicast capable vif.
2514: * If we don't have one, we can't source any multicasts anyway.
2515: */
2516: if (phys_vif != -1) {
2517: IF_DEBUG(DEBUG_TRACE) {
2518: logit(LOG_DEBUG, 0, "Sending reply to %s from %s", inet_fmt(dst, s1, sizeof(s1)),
2519: inet_fmt(uvifs[phys_vif].uv_lcl_addr, s2, sizeof(s2)));
2520: }
2521: k_set_ttl(qry->tr_rttl);
2522: send_igmp(uvifs[phys_vif].uv_lcl_addr, dst, resptype, no, group, datalen);
2523: k_set_ttl(1);
2524: } else {
2525: logit(LOG_INFO, 0, "No enabled phyints -- dropping traceroute reply");
2526: }
2527: } else {
2528: IF_DEBUG(DEBUG_TRACE) {
2529: logit(LOG_DEBUG, 0, "Sending %s to %s from %s",
2530: resptype == IGMP_MTRACE_RESP ? "reply" : "request on",
2531: inet_fmt(dst, s1, sizeof(s1)), inet_fmt(src, s2, sizeof(s2)));
2532: }
2533: send_igmp(src, dst, resptype, no, group, datalen);
2534: }
2535: }
2536:
2537: /**
2538: * Local Variables:
2539: * version-control: t
2540: * indent-tabs-mode: t
2541: * c-file-style: "ellemtel"
2542: * c-basic-offset: 4
2543: * End:
2544: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>