aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/mrouted/prune.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/mrouted/prune.c')
-rw-r--r--usr.sbin/mrouted/prune.c1270
1 files changed, 477 insertions, 793 deletions
diff --git a/usr.sbin/mrouted/prune.c b/usr.sbin/mrouted/prune.c
index 358613702a79..23ba6384bd03 100644
--- a/usr.sbin/mrouted/prune.c
+++ b/usr.sbin/mrouted/prune.c
@@ -5,37 +5,45 @@
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
- *
- *
- * prune.c,v 3.8.4.59 1998/03/01 02:06:32 fenner Exp
*/
#ifndef lint
static const char rcsid[] =
- "$Id: prune.c,v 1.15 1998/01/16 07:17:44 charnier Exp $";
+ "$Id$";
#endif /* not lint */
#include "defs.h"
extern int cache_lifetime;
-extern int prune_lifetime;
+extern int max_prune_lifetime;
extern struct rtentry *routing_table;
extern int phys_vif;
-extern int allow_black_holes;
-
/*
- * randomize value to obtain a value between .5x and 1.5x
- * in order to prevent synchronization
+ * dither cache lifetime to obtain a value between x and 2*x
*/
#ifdef SYSV
-#define JITTERED_VALUE(x) ((x)/2 + (lrand48() % (x)))
+#define CACHE_LIFETIME(x) ((x) + (lrand48() % (x)))
#else
-#define JITTERED_VALUE(x) ((x)/2 + (random() % (x)))
+#define CACHE_LIFETIME(x) ((x) + (random() % (x)))
#endif
-#define CACHE_LIFETIME(x) JITTERED_VALUE(x) /* XXX */
+#define CHK_GS(x, y) { \
+ switch(x) { \
+ case 2: \
+ case 4: \
+ case 8: \
+ case 16: \
+ case 32: \
+ case 64: \
+ case 128: \
+ case 256: y = 1; \
+ break; \
+ default: y = 0; \
+ } \
+ }
+
struct gtable *kernel_table; /* ptr to list of kernel grp entries*/
static struct gtable *kernel_no_route; /* list of grp entries w/o routes */
struct gtable *gtp; /* pointer for kernel rt entries */
@@ -44,20 +52,17 @@ unsigned int kroutes; /* current number of cache entries */
/****************************************************************************
Functions that are local to prune.c
****************************************************************************/
-static int scoped_addr __P((vifi_t vifi, u_int32 addr));
static void prun_add_ttls __P((struct gtable *gt));
static int pruning_neighbor __P((vifi_t vifi, u_int32 addr));
static int can_mtrace __P((vifi_t vifi, u_int32 addr));
static struct ptable * find_prune_entry __P((u_int32 vr, struct ptable *pt));
-static void remove_sources __P((struct gtable *gt));
-static void rexmit_prune __P((void *arg));
static void expire_prune __P((vifi_t vifi, struct gtable *gt));
static void send_prune __P((struct gtable *gt));
static void send_graft __P((struct gtable *gt));
static void send_graft_ack __P((u_int32 src, u_int32 dst,
- u_int32 origin, u_int32 grp,
- vifi_t vifi));
+ u_int32 origin, u_int32 grp));
static void update_kernel __P((struct gtable *g));
+static char * scaletime __P((u_long t));
/*
* Updates the ttl values for each vif.
@@ -79,34 +84,16 @@ prun_add_ttls(gt)
/*
* checks for scoped multicast addresses
- * XXX I want to make the check of allow_black_holes based on ALLOW_BLACK_HOLES
- * but macros are not functions.
*/
#define GET_SCOPE(gt) { \
register vifi_t _i; \
- VIFM_CLRALL((gt)->gt_scope); \
- if (allow_black_holes || \
- (ntohl((gt)->gt_mcastgrp) & 0xff000000) == 0xef000000) \
+ if ((ntohl((gt)->gt_mcastgrp) & 0xff000000) == 0xef000000) \
for (_i = 0; _i < numvifs; _i++) \
if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
VIFM_SET(_i, (gt)->gt_scope); \
- } \
- if ((gt)->gt_route == NULL || ((gt)->gt_route->rt_parent != NO_VIF && \
- VIFM_ISSET((gt)->gt_route->rt_parent, (gt)->gt_scope))) \
- VIFM_SETALL((gt)->gt_scope);
-
-#define APPLY_SCOPE(gt) VIFM_CLR_MASK((gt)->gt_grpmems, (gt)->gt_scope)
-
-#define GET_MEMBERSHIP(gt, vifi) { \
- if ((gt)->gt_route && \
- VIFM_ISSET((vifi), (gt)->gt_route->rt_children) && \
- (!SUBS_ARE_PRUNED((gt)->gt_route->rt_subordinates, \
- uvifs[vifi].uv_nbrmap, (gt)->gt_prunes) || \
- grplst_mem((vifi), (gt)->gt_mcastgrp))) \
- VIFM_SET((vifi), (gt)->gt_grpmems); \
}
-static int
+int
scoped_addr(vifi, addr)
vifi_t vifi;
u_int32 addr;
@@ -120,38 +107,6 @@ scoped_addr(vifi, addr)
return 0;
}
-/*
- * Determine the list of outgoing vifs, based upon
- * route subordinates, prunes received, and group
- * memberships.
- */
-void
-determine_forwvifs(gt)
- struct gtable *gt;
-{
- vifi_t i;
-
- VIFM_CLRALL(gt->gt_grpmems);
- for (i = 0; i < numvifs; i++) {
- GET_MEMBERSHIP(gt, i);
- }
- GET_SCOPE(gt);
- APPLY_SCOPE(gt);
-}
-
-/*
- * Send a prune or a graft if necessary.
- */
-void
-send_prune_or_graft(gt)
- struct gtable *gt;
-{
- if (VIFM_ISEMPTY(gt->gt_grpmems))
- send_prune(gt);
- else if (gt->gt_prsent_timer)
- send_graft(gt);
-}
-
/*
* Determine if mcastgrp has a listener on vifi
*/
@@ -226,8 +181,15 @@ pruning_neighbor(vifi, addr)
if (n == NULL)
return 0;
+ if (n->al_flags & NF_PRUNE)
+ return 1;
+
+ /*
+ * Versions from 3.0 to 3.4 relied on the version number to identify
+ * that they could handle pruning.
+ */
vers = NBR_VERS(n);
- return (vers >= 0x0300 && ((vers & 0xff00) != 0x0a00));
+ return (vers >= 0x0300 && vers <= 0x0304);
}
/*
@@ -242,10 +204,17 @@ can_mtrace(vifi, addr)
int vers;
if (n == NULL)
- return 1; /* fail "safe" */
+ return 0;
+
+ if (n->al_flags & NF_MTRACE)
+ return 1;
+ /*
+ * Versions 3.3 and 3.4 relied on the version number to identify
+ * that they could handle traceroute.
+ */
vers = NBR_VERS(n);
- return (vers >= 0x0303 && ((vers & 0xff00) != 0x0a00));
+ return (vers >= 0x0303 && vers <= 0x0304);
}
/*
@@ -266,76 +235,6 @@ find_prune_entry(vr, pt)
}
/*
- * Remove all the sources hanging off the group table entry from the kernel
- * cache. Remember the packet counts wherever possible, to keep the mtrace
- * counters consistent. This prepares for possible prune retransmission,
- * either on a multi-access network or when a prune that we sent upstream
- * has expired.
- */
-static void
-remove_sources(gt)
- struct gtable *gt;
-{
- struct stable *st;
- struct sioc_sg_req sg_req;
-
- sg_req.grp.s_addr = gt->gt_mcastgrp;
-
- /*
- * call k_del_rg() on every one of the gt->gt_srctbl entries
- * but first save the packet count so that the mtrace packet
- * counters can remain approximately correct. There's a race
- * here but it's minor.
- */
- for (st = gt->gt_srctbl; st; st = st->st_next) {
- if (st->st_ctime == 0)
- continue;
- IF_DEBUG(DEBUG_PRUNE)
- log(LOG_DEBUG, 0, "rexmit_prune deleting (%s %s) (next is %d sec)",
- inet_fmt(st->st_origin, s1),
- inet_fmt(gt->gt_mcastgrp, s2),
- gt->gt_prune_rexmit);
- sg_req.src.s_addr = st->st_origin;
- if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) {
- sg_req.pktcnt = 0;
- }
- k_del_rg(st->st_origin, gt);
- st->st_ctime = 0; /* flag that it's not in the kernel any more */
- st->st_savpkt += sg_req.pktcnt;
- kroutes--;
- }
-
- /*
- * Now, add_table_entry will prune when asked to add a cache entry.
- */
-}
-
-/*
- * Prepare for possible prune retransmission
- */
-static void
-rexmit_prune(arg)
- void *arg;
-{
- struct gtable *gt = *(struct gtable **)arg;
-
- free(arg);
-
- gt->gt_rexmit_timer = 0;
-
- /* Make sure we're still not forwarding traffic */
- if (!VIFM_ISEMPTY(gt->gt_grpmems)) {
- IF_DEBUG(DEBUG_PRUNE)
- log(LOG_DEBUG, 0, "rexmit_prune (%s %s): gm:%x",
- RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2),
- gt->gt_grpmems);
- return;
- }
-
- remove_sources(gt);
-}
-
-/*
* Send a prune message to the dominant router for
* this source.
*
@@ -349,77 +248,38 @@ send_prune(gt)
char *p;
int i;
int datalen;
+ u_int32 src;
u_int32 dst;
u_int32 tmp;
- int rexmitting = 0;
- struct uvif *v;
- /*
- * Can't process a prune if we don't have an associated route
- * or if the route points to a local interface.
- */
- if (gt->gt_route == NULL || gt->gt_route->rt_parent == NO_VIF ||
- gt->gt_route->rt_gateway == 0)
+ /* Don't process any prunes if router is not pruning */
+ if (pruning == 0)
+ return;
+
+ /* Can't process a prune if we don't have an associated route */
+ if (gt->gt_route == NULL)
return;
/* Don't send a prune to a non-pruning router */
if (!pruning_neighbor(gt->gt_route->rt_parent, gt->gt_route->rt_gateway))
return;
- v = &uvifs[gt->gt_route->rt_parent];
/*
* sends a prune message to the router upstream.
*/
-#if 0
- dst = v->uv_flags & VIFF_TUNNEL ? dvmrp_group : gt->gt_route->rt_gateway; /*XXX*/
-#else
+ src = uvifs[gt->gt_route->rt_parent].uv_lcl_addr;
dst = gt->gt_route->rt_gateway;
-#endif
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
datalen = 0;
/*
- * determine prune lifetime, if this isn't a retransmission.
- *
- * Use interface-specified lifetime if there is one.
+ * determine prune lifetime
*/
- if (gt->gt_prsent_timer == 0) {
- int l = prune_lifetime;
-
- if (v->uv_prune_lifetime != 0)
- l = v->uv_prune_lifetime;
-
- gt->gt_prsent_timer = JITTERED_VALUE(l);
- for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next)
- if (pt->pt_timer < gt->gt_prsent_timer)
- gt->gt_prsent_timer = pt->pt_timer;
- } else if (gt->gt_prsent_timer < 0) {
- IF_DEBUG(DEBUG_PRUNE)
- log(LOG_DEBUG, 0, "asked to rexmit? (%s,%s)/%d on vif %d to %s with negative time",
- RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2),
- gt->gt_prsent_timer, gt->gt_route->rt_parent,
- inet_fmt(gt->gt_route->rt_gateway, s3));
- return;
- } else
- rexmitting = 1;
-
- if (rexmitting && !(v->uv_flags & VIFF_REXMIT_PRUNES)) {
- IF_DEBUG(DEBUG_PRUNE)
- log(LOG_DEBUG, 0, "not rexmitting prune for (%s %s)/%d on vif %d to %s",
- RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2),
- gt->gt_prsent_timer, gt->gt_route->rt_parent,
- inet_fmt(gt->gt_route->rt_gateway, s3));
- return;
- }
- if (gt->gt_prsent_timer <= MIN_PRUNE_LIFE) {
- IF_DEBUG(DEBUG_PRUNE)
- log(LOG_DEBUG, 0, "not bothering to send prune for (%s,%s)/%d on vif %d to %s because it's too short",
- RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2),
- gt->gt_prsent_timer, gt->gt_route->rt_parent,
- inet_fmt(gt->gt_route->rt_gateway, s3));
- return;
- }
+ gt->gt_prsent_timer = gt->gt_timer;
+ for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next)
+ if (pt->pt_timer < gt->gt_prsent_timer)
+ gt->gt_prsent_timer = pt->pt_timer;
/*
* If we have a graft pending, cancel graft retransmission
@@ -435,27 +295,14 @@ send_prune(gt)
*p++ = ((char *)&(tmp))[i];
datalen += 12;
- send_on_vif(v, dst, DVMRP_PRUNE, datalen);
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_PRUNE,
+ htonl(MROUTED_LEVEL), datalen);
- IF_DEBUG(DEBUG_PRUNE)
- log(LOG_DEBUG, 0, "%s prune for (%s %s)/%d on vif %d to %s",
- rexmitting ? "rexmitted" : "sent",
- RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2),
+ log(LOG_DEBUG, 0, "sent prune for (%s %s)/%d on vif %d to %s",
+ inet_fmts(gt->gt_route->rt_origin, gt->gt_route->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2),
gt->gt_prsent_timer, gt->gt_route->rt_parent,
inet_fmt(gt->gt_route->rt_gateway, s3));
-
- if ((v->uv_flags & VIFF_REXMIT_PRUNES) &&
- gt->gt_rexmit_timer == 0 &&
- gt->gt_prsent_timer > gt->gt_prune_rexmit) {
- struct gtable **arg =
- (struct gtable **)malloc(sizeof (struct gtable **));
-
- *arg = gt;
- gt->gt_rexmit_timer = timer_setTimer(
- JITTERED_VALUE(gt->gt_prune_rexmit),
- rexmit_prune, arg);
- gt->gt_prune_rexmit *= 2;
- }
}
/*
@@ -472,28 +319,16 @@ send_graft(gt)
register char *p;
register int i;
int datalen;
+ u_int32 src;
u_int32 dst;
/* Can't send a graft without an associated route */
- if (gt->gt_route == NULL || gt->gt_route->rt_parent == NO_VIF) {
- gt->gt_grftsnt = 0;
+ if (gt->gt_route == NULL)
return;
- }
-
- gt->gt_prsent_timer = 0;
- gt->gt_prune_rexmit = PRUNE_REXMIT_VAL;
- if (gt->gt_rexmit_timer)
- timer_clearTimer(gt->gt_rexmit_timer);
-
- if (gt->gt_grftsnt == 0)
- gt->gt_grftsnt = 1;
-
-#if 0
- dst = uvifs[gt->gt_route->rt_parent].uv_flags & VIFF_TUNNEL ? dvmrp_group : gt->gt_route->rt_gateway; /*XXX*/
-#else
+
+ src = uvifs[gt->gt_route->rt_parent].uv_lcl_addr;
dst = gt->gt_route->rt_gateway;
-#endif
-
+
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
datalen = 0;
@@ -503,10 +338,13 @@ send_graft(gt)
*p++ = ((char *)&(gt->gt_mcastgrp))[i];
datalen += 8;
- send_on_vif(&uvifs[gt->gt_route->rt_parent], dst, DVMRP_GRAFT, datalen);
- IF_DEBUG(DEBUG_PRUNE)
+ if (datalen != 0) {
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT,
+ htonl(MROUTED_LEVEL), datalen);
+ }
log(LOG_DEBUG, 0, "sent graft for (%s %s) to %s on vif %d",
- RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2),
+ inet_fmts(gt->gt_route->rt_origin, gt->gt_route->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2),
inet_fmt(gt->gt_route->rt_gateway, s3), gt->gt_route->rt_parent);
}
@@ -514,12 +352,11 @@ send_graft(gt)
* Send an ack that a graft was received
*/
static void
-send_graft_ack(src, dst, origin, grp, vifi)
+send_graft_ack(src, dst, origin, grp)
u_int32 src;
u_int32 dst;
u_int32 origin;
u_int32 grp;
- vifi_t vifi;
{
register char *p;
register int i;
@@ -534,24 +371,11 @@ send_graft_ack(src, dst, origin, grp, vifi)
*p++ = ((char *)&(grp))[i];
datalen += 8;
- if (vifi == NO_VIF)
- send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT_ACK,
- htonl(MROUTED_LEVEL), datalen);
- else {
-#if 0
- if (uvifs[vifi].uv_flags & VIFF_TUNNEL)
- dst = dvmrp_group; /* XXX */
-#endif
- send_on_vif(&uvifs[vifi], dst, DVMRP_GRAFT_ACK, datalen);
- }
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT_ACK,
+ htonl(MROUTED_LEVEL), datalen);
- IF_DEBUG(DEBUG_PRUNE)
- if (vifi == NO_VIF)
- log(LOG_DEBUG, 0, "sent graft ack for (%s, %s) to %s",
- inet_fmt(origin, s1), inet_fmt(grp, s2), inet_fmt(dst, s3));
- else
- log(LOG_DEBUG, 0, "sent graft ack for (%s, %s) to %s on vif %d",
- inet_fmt(origin, s1), inet_fmt(grp, s2), inet_fmt(dst, s3), vifi);
+ log(LOG_DEBUG, 0, "sent graft ack for (%s, %s) to %s",
+ inet_fmt(origin, s1), inet_fmt(grp, s2), inet_fmt(dst, s3));
}
/*
@@ -564,8 +388,7 @@ update_kernel(g)
struct stable *st;
for (st = g->gt_srctbl; st; st = st->st_next)
- if (st->st_ctime != 0)
- k_add_rg(st->st_origin, g);
+ k_add_rg(st->st_origin, g);
}
/****************************************************************************
@@ -581,7 +404,7 @@ update_kernel(g)
*/
struct gtable *
find_grp(grp)
- u_int32 grp;
+ u_long grp;
{
struct gtable *gt;
@@ -601,7 +424,7 @@ find_grp(grp)
struct stable *
find_grp_src(gt, src)
struct gtable *gt;
- u_int32 src;
+ u_long src;
{
struct stable *st;
u_long grp = gt->gt_mcastgrp;
@@ -622,9 +445,9 @@ int
next_grp_src_mask(gtpp, stpp, grp, src, mask)
struct gtable **gtpp; /* ordered by group */
struct stable **stpp; /* ordered by source */
- u_int32 grp;
- u_int32 src;
- u_int32 mask;
+ u_long grp;
+ u_long src;
+ u_long mask;
{
struct gtable *gt, *gbest = NULL;
struct stable *st, *sbest = NULL;
@@ -686,6 +509,76 @@ refresh_sg(sg, gt, st)
}
/*
+ * Return pointer to a specific route entry. This must be a separate
+ * function from find_route() which modifies rtp.
+ */
+struct rtentry *
+snmp_find_route(src, mask)
+ register u_long src, mask;
+{
+ register struct rtentry *rt;
+
+ for (rt = routing_table; rt; rt = rt->rt_next) {
+ if (src == rt->rt_origin && mask == rt->rt_originmask)
+ return rt;
+ }
+ return NULL;
+}
+
+/*
+ * Find next route entry > specification
+ */
+int
+next_route(rtpp, src, mask)
+ struct rtentry **rtpp;
+ u_long src;
+ u_long mask;
+{
+ struct rtentry *rt, *rbest = NULL;
+
+ /* Among all entries > spec, find "lowest" one in order */
+ for (rt = routing_table; rt; rt=rt->rt_next) {
+ if ((ntohl(rt->rt_origin) > ntohl(src)
+ || (ntohl(rt->rt_origin) == ntohl(src)
+ && ntohl(rt->rt_originmask) > ntohl(mask)))
+ && (!rbest || (ntohl(rt->rt_origin) < ntohl(rbest->rt_origin))
+ || (ntohl(rt->rt_origin) == ntohl(rbest->rt_origin)
+ && ntohl(rt->rt_originmask) < ntohl(rbest->rt_originmask))))
+ rbest = rt;
+ }
+ (*rtpp) = rbest;
+ return (*rtpp)!=0;
+}
+
+/*
+ * Given a routing table entry, and a vifi, find the next vifi/entry
+ */
+int
+next_route_child(rtpp, src, mask, vifi)
+ struct rtentry **rtpp;
+ u_long src;
+ u_long mask;
+ vifi_t *vifi; /* vif at which to start looking */
+{
+ struct rtentry *rt;
+
+ /* Get (S,M) entry */
+ if (!((*rtpp) = snmp_find_route(src,mask)))
+ if (!next_route(rtpp, src, mask))
+ return 0;
+
+ /* Continue until we get one with a valid next vif */
+ do {
+ for (; (*rtpp)->rt_children && *vifi<numvifs; (*vifi)++)
+ if (VIFM_ISSET(*vifi, (*rtpp)->rt_children))
+ return 1;
+ *vifi = 0;
+ } while( next_route(rtpp, (*rtpp)->rt_origin, (*rtpp)->rt_originmask) );
+
+ return 0;
+}
+
+/*
* Given a routing table entry, and a vifi, find the next entry
* equal to or greater than those
*/
@@ -693,11 +586,13 @@ int
next_child(gtpp, stpp, grp, src, mask, vifi)
struct gtable **gtpp;
struct stable **stpp;
- u_int32 grp;
- u_int32 src;
- u_int32 mask;
+ u_long grp;
+ u_long src;
+ u_long mask;
vifi_t *vifi; /* vif at which to start looking */
{
+ struct stable *st;
+
/* Get (G,S,M) entry */
if (mask!=0xFFFFFFFF
|| !((*gtpp) = find_grp(grp))
@@ -740,15 +635,7 @@ add_table_entry(origin, mcastgrp)
struct rtentry *r;
struct gtable *gt,**gtnp,*prev_gt;
struct stable *st,**stnp;
-
- /*
- * Since we have to enable mrouting to get the version number,
- * some cache creation requests can sneak through. Ignore them
- * since we're not going to do useful stuff until we've performed
- * final initialization.
- */
- if (!did_final_init)
- return;
+ vifi_t i;
#ifdef DEBUG_MFC
md_log(MD_MISS, origin, mcastgrp);
@@ -784,20 +671,35 @@ add_table_entry(origin, mcastgrp)
gt->gt_mcastgrp = mcastgrp;
gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
time(&gt->gt_ctime);
+ gt->gt_grpmems = 0;
+ gt->gt_scope = 0;
gt->gt_prsent_timer = 0;
gt->gt_grftsnt = 0;
gt->gt_srctbl = NULL;
gt->gt_pruntbl = NULL;
gt->gt_route = r;
- gt->gt_rexmit_timer = 0;
- NBRM_CLRALL(gt->gt_prunes);
- gt->gt_prune_rexmit = PRUNE_REXMIT_VAL;
#ifdef RSRR
gt->gt_rsrr_cache = NULL;
#endif
- /* Calculate forwarding vifs */
- determine_forwvifs(gt);
+ if (r != NULL) {
+ /* obtain the multicast group membership list */
+ for (i = 0; i < numvifs; i++) {
+ if (VIFM_ISSET(i, r->rt_children) &&
+ !(VIFM_ISSET(i, r->rt_leaves)))
+ VIFM_SET(i, gt->gt_grpmems);
+
+ if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp))
+ VIFM_SET(i, gt->gt_grpmems);
+ }
+ GET_SCOPE(gt);
+ if (VIFM_ISSET(r->rt_parent, gt->gt_scope))
+ gt->gt_scope = -1;
+ gt->gt_grpmems &= ~gt->gt_scope;
+ } else {
+ gt->gt_scope = -1;
+ gt->gt_grpmems = 0;
+ }
/* update ttls */
prun_add_ttls(gt);
@@ -814,7 +716,8 @@ add_table_entry(origin, mcastgrp)
g = gtp ? gtp->gt_gnext : kernel_table;
log(LOG_WARNING, 0, "Entry for (%s %s) (rt:%x) exists (rt:%x)",
- RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2),
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2),
r, g->gt_route);
} else {
if (gtp) {
@@ -848,46 +751,39 @@ add_table_entry(origin, mcastgrp)
st->st_origin = origin;
st->st_pktcnt = 0;
- st->st_savpkt = 0;
- time(&st->st_ctime);
st->st_next = *stnp;
*stnp = st;
} else {
- if (st->st_ctime == 0) {
- /* An old source which we're keeping around for statistics */
- time(&st->st_ctime);
- } else {
#ifdef DEBUG_MFC
- md_log(MD_DUPE, origin, mcastgrp);
+ md_log(MD_DUPE, origin, mcastgrp);
#endif
- /* Ignore kernel->mrouted retransmissions */
- if (time(0) - st->st_ctime > 5)
- log(LOG_WARNING, 0, "kernel entry already exists for (%s %s)",
- inet_fmt(origin, s1), inet_fmt(mcastgrp, s2));
- k_add_rg(origin, gt);
- return;
- }
+ log(LOG_WARNING, 0, "kernel entry already exists for (%s %s)",
+ inet_fmt(origin, s1), inet_fmt(mcastgrp, s2));
+ /* XXX Doing this should cause no harm, and may ensure
+ * kernel<>mrouted synchronization */
+ k_add_rg(origin, gt);
+ return;
}
kroutes++;
k_add_rg(origin, gt);
- IF_DEBUG(DEBUG_CACHE)
log(LOG_DEBUG, 0, "add cache entry (%s %s) gm:%x, parent-vif:%d",
inet_fmt(origin, s1),
inet_fmt(mcastgrp, s2),
gt->gt_grpmems, r ? r->rt_parent : -1);
-
- /*
- * If there are no downstream routers that want traffic for
- * this group, send (or retransmit) a prune upstream.
+
+ /* If there are no leaf vifs
+ * which have this group, then
+ * mark this src-grp as a prune candidate.
*/
- if (VIFM_ISEMPTY(gt->gt_grpmems))
+ if (!gt->gt_prsent_timer && !gt->gt_grpmems && r && r->rt_gateway)
send_prune(gt);
}
/*
- * A router has gone down. Remove prune state pertinent to that router.
+ * An mrouter has gone down and come up on an interface
+ * Forward on that interface immediately
*/
void
reset_neighbor_state(vifi, addr)
@@ -909,29 +805,35 @@ reset_neighbor_state(vifi, addr)
*/
if (vifi == r->rt_parent) {
if (addr == r->rt_gateway) {
- IF_DEBUG(DEBUG_PEER)
log(LOG_DEBUG, 0, "reset_neighbor_state parent reset (%s %s)",
- RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2));
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
g->gt_prsent_timer = 0;
g->gt_grftsnt = 0;
- while ((st = g->gt_srctbl) != NULL) {
+ while ((st = g->gt_srctbl)) {
g->gt_srctbl = st->st_next;
- if (st->st_ctime != 0) {
- k_del_rg(st->st_origin, g);
- kroutes--;
- }
+ k_del_rg(st->st_origin, g);
+ kroutes--;
free(st);
}
}
} else {
/*
+ * Neighbor was not the parent, send grafts to join the groups
+ */
+ if (g->gt_prsent_timer) {
+ g->gt_grftsnt = 1;
+ send_graft(g);
+ g->gt_prsent_timer = 0;
+ }
+
+ /*
* Remove any prunes that this router has sent us.
*/
ptnp = &g->gt_pruntbl;
while ((pt = *ptnp) != NULL) {
if (pt->pt_vifi == vifi && pt->pt_router == addr) {
- NBRM_CLR(pt->pt_index, g->gt_prunes);
*ptnp = pt->pt_next;
free(pt);
} else
@@ -942,8 +844,15 @@ reset_neighbor_state(vifi, addr)
* And see if we want to forward again.
*/
if (!VIFM_ISSET(vifi, g->gt_grpmems)) {
- GET_MEMBERSHIP(g, vifi);
- APPLY_SCOPE(g);
+ if (VIFM_ISSET(vifi, r->rt_children) &&
+ !(VIFM_ISSET(vifi, r->rt_leaves)))
+ VIFM_SET(vifi, g->gt_grpmems);
+
+ if (VIFM_ISSET(vifi, r->rt_leaves) &&
+ grplst_mem(vifi, g->gt_mcastgrp))
+ VIFM_SET(vifi, g->gt_grpmems);
+
+ g->gt_grpmems &= ~g->gt_scope;
prun_add_ttls(g);
/* Update kernel state */
@@ -953,17 +862,8 @@ reset_neighbor_state(vifi, addr)
rsrr_cache_send(g,1);
#endif /* RSRR */
- /*
- * If removing this prune causes us to start forwarding
- * (e.g. the neighbor rebooted), and we sent a prune upstream,
- * send a graft to cancel the prune.
- */
- if (!VIFM_ISEMPTY(g->gt_grpmems) && g->gt_prsent_timer)
- send_graft(g);
-
- IF_DEBUG(DEBUG_PEER)
- log(LOG_DEBUG, 0, "reset neighbor state (%s %s) gm:%x",
- RT_FMT(r, s1),
+ log(LOG_DEBUG, 0, "reset member state (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
}
}
@@ -987,20 +887,18 @@ del_table_entry(r, mcastgrp, del_flag)
if (del_flag == DEL_ALL_ROUTES) {
g = r->rt_groups;
while (g) {
- IF_DEBUG(DEBUG_CACHE)
log(LOG_DEBUG, 0, "del_table_entry deleting (%s %s)",
- RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2));
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
st = g->gt_srctbl;
while (st) {
- if (st->st_ctime != 0) {
- if (k_del_rg(st->st_origin, g) < 0) {
- log(LOG_WARNING, errno,
- "del_table_entry trying to delete (%s, %s)",
- inet_fmt(st->st_origin, s1),
- inet_fmt(g->gt_mcastgrp, s2));
- }
- kroutes--;
+ if (k_del_rg(st->st_origin, g) < 0) {
+ log(LOG_WARNING, errno,
+ "del_table_entry trying to delete (%s, %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
}
+ kroutes--;
prev_st = st;
st = st->st_next;
free(prev_st);
@@ -1027,9 +925,6 @@ del_table_entry(r, mcastgrp, del_flag)
rsrr_cache_send(g,0);
rsrr_cache_clean(g);
#endif /* RSRR */
- if (g->gt_rexmit_timer)
- timer_clearTimer(g->gt_rexmit_timer);
-
prev_g = g;
g = g->gt_next;
free(prev_g);
@@ -1044,20 +939,18 @@ del_table_entry(r, mcastgrp, del_flag)
prev_g = (struct gtable *)&r->rt_groups;
for (g = r->rt_groups; g; g = g->gt_next) {
if (g->gt_mcastgrp == mcastgrp) {
- IF_DEBUG(DEBUG_CACHE)
log(LOG_DEBUG, 0, "del_table_entry deleting (%s %s)",
- RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2));
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
st = g->gt_srctbl;
while (st) {
- if (st->st_ctime != 0) {
- if (k_del_rg(st->st_origin, g) < 0) {
- log(LOG_WARNING, errno,
- "del_table_entry trying to delete (%s, %s)",
- inet_fmt(st->st_origin, s1),
- inet_fmt(g->gt_mcastgrp, s2));
- }
- kroutes--;
+ if (k_del_rg(st->st_origin, g) < 0) {
+ log(LOG_WARNING, errno,
+ "del_table_entry trying to delete (%s, %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
}
+ kroutes--;
prev_st = st;
st = st->st_next;
free(prev_st);
@@ -1085,8 +978,6 @@ del_table_entry(r, mcastgrp, del_flag)
g->gt_next->gt_prev = NULL;
prev_g->gt_next = g->gt_next;
- if (g->gt_rexmit_timer)
- timer_clearTimer(g->gt_rexmit_timer);
#ifdef RSRR
/* Send route change notification to reservation protocol. */
rsrr_cache_send(g,0);
@@ -1105,70 +996,48 @@ del_table_entry(r, mcastgrp, del_flag)
* update kernel table entry when a route entry changes
*/
void
-update_table_entry(r, old_parent_gw)
+update_table_entry(r)
struct rtentry *r;
- u_int32 old_parent_gw;
{
struct gtable *g;
- struct ptable *pt, **ptnp;
+ struct ptable *pt, *prev_pt;
+ vifi_t i;
for (g = r->rt_groups; g; g = g->gt_next) {
- ptnp = &g->gt_pruntbl;
- /*
- * Delete prune entries from non-children, or non-subordinates.
- */
- while ((pt = *ptnp)) {
- if (!VIFM_ISSET(pt->pt_vifi, r->rt_children) ||
- !NBRM_ISSET(pt->pt_index, r->rt_subordinates)) {
+ pt = g->gt_pruntbl;
+ while (pt) {
+ prev_pt = pt->pt_next;
+ free(pt);
+ pt = prev_pt;
+ }
+ g->gt_pruntbl = NULL;
- IF_DEBUG(DEBUG_PRUNE)
- log(LOG_DEBUG, 0, "update_table_entry deleting prune for (%s %s) from %s on vif %d -%s%s",
- RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2),
- inet_fmt(pt->pt_router, s3), pt->pt_vifi,
- VIFM_ISSET(pt->pt_vifi, r->rt_children) ? "" : " not a child",
- NBRM_ISSET(pt->pt_index, r->rt_subordinates) ? "" : " not a subordinate");
+ g->gt_grpmems = 0;
- if (!NBRM_ISSET(pt->pt_index, g->gt_prunes)) {
- log(LOG_WARNING, 0,
- "gt_prunes lost track of (%s %s) from %s on vif %d",
- RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2),
- inet_fmt(pt->pt_router, s3), pt->pt_vifi);
- }
-
- NBRM_CLR(pt->pt_index, g->gt_prunes);
- *ptnp = pt->pt_next;
- free(pt);
- continue;
- }
- ptnp = &((*ptnp)->pt_next);
+ /* obtain the multicast group membership list */
+ for (i = 0; i < numvifs; i++) {
+ if (VIFM_ISSET(i, r->rt_children) &&
+ !(VIFM_ISSET(i, r->rt_leaves)))
+ VIFM_SET(i, g->gt_grpmems);
+
+ if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, g->gt_mcastgrp))
+ VIFM_SET(i, g->gt_grpmems);
}
+ if (VIFM_ISSET(r->rt_parent, g->gt_scope))
+ g->gt_scope = -1;
+ g->gt_grpmems &= ~g->gt_scope;
- IF_DEBUG(DEBUG_CACHE)
- log(LOG_DEBUG, 0, "updating cache entries (%s %s) old gm:%x",
- RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2),
+ log(LOG_DEBUG, 0, "updating cache entries (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2),
g->gt_grpmems);
- /*
- * Forget about a prune or graft that we sent previously if we
- * have a new parent router (since the new parent router will
- * know nothing about what I sent to the previous parent). The
- * old parent will forget any prune state it is keeping for us.
- */
- if (old_parent_gw != r->rt_gateway) {
+ if (g->gt_grpmems && g->gt_prsent_timer) {
+ g->gt_grftsnt = 1;
+ send_graft(g);
g->gt_prsent_timer = 0;
- g->gt_grftsnt = 0;
}
- /* Recalculate membership */
- determine_forwvifs(g);
- /* send a prune or graft if needed. */
- send_prune_or_graft(g);
-
- IF_DEBUG(DEBUG_CACHE)
- log(LOG_DEBUG, 0, "updating cache entries (%s %s) new gm:%x",
- RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2),
- g->gt_grpmems);
-
/* update ttls and add entry into kernel */
prun_add_ttls(g);
update_kernel(g);
@@ -1176,6 +1045,12 @@ update_table_entry(r, old_parent_gw)
/* Send route change notification to reservation protocol. */
rsrr_cache_send(g,1);
#endif /* RSRR */
+
+ /* Check if we want to prune this group */
+ if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway) {
+ g->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ send_prune(g);
+ }
}
}
@@ -1190,7 +1065,6 @@ update_lclgrp(vifi, mcastgrp)
struct rtentry *r;
struct gtable *g;
- IF_DEBUG(DEBUG_MEMBER)
log(LOG_DEBUG, 0, "group %s joined on vif %d",
inet_fmt(mcastgrp, s1), vifi);
@@ -1203,14 +1077,13 @@ update_lclgrp(vifi, mcastgrp)
VIFM_ISSET(vifi, r->rt_children)) {
VIFM_SET(vifi, g->gt_grpmems);
- APPLY_SCOPE(g);
- if (VIFM_ISEMPTY(g->gt_grpmems))
+ g->gt_grpmems &= ~g->gt_scope;
+ if (g->gt_grpmems == 0)
continue;
prun_add_ttls(g);
- IF_DEBUG(DEBUG_CACHE)
log(LOG_DEBUG, 0, "update lclgrp (%s %s) gm:%x",
- RT_FMT(r, s1),
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
update_kernel(g);
@@ -1230,9 +1103,9 @@ delete_lclgrp(vifi, mcastgrp)
vifi_t vifi;
u_int32 mcastgrp;
{
+ struct rtentry *r;
struct gtable *g;
- IF_DEBUG(DEBUG_MEMBER)
log(LOG_DEBUG, 0, "group %s left on vif %d",
inet_fmt(mcastgrp, s1), vifi);
@@ -1240,14 +1113,28 @@ delete_lclgrp(vifi, mcastgrp)
if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
break;
- if (g->gt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, g->gt_grpmems)) {
- if (g->gt_route == NULL ||
- SUBS_ARE_PRUNED(g->gt_route->rt_subordinates,
- uvifs[vifi].uv_nbrmap, g->gt_prunes)) {
+ if (g->gt_mcastgrp == mcastgrp) {
+ int stop_sending = 1;
+
+ r = g->gt_route;
+ /*
+ * If this is not a leaf, then we have router neighbors on this
+ * vif. Only turn off forwarding if they have all pruned.
+ */
+ if (!VIFM_ISSET(vifi, r->rt_leaves)) {
+ struct listaddr *vr;
+
+ for (vr = uvifs[vifi].uv_neighbors; vr; vr = vr->al_next)
+ if (find_prune_entry(vr->al_addr, g->gt_pruntbl) == NULL) {
+ stop_sending = 0;
+ break;
+ }
+ }
+
+ if (stop_sending) {
VIFM_CLR(vifi, g->gt_grpmems);
- IF_DEBUG(DEBUG_CACHE)
log(LOG_DEBUG, 0, "delete lclgrp (%s %s) gm:%x",
- RT_FMT(g->gt_route, s1),
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
prun_add_ttls(g);
@@ -1261,7 +1148,7 @@ delete_lclgrp(vifi, mcastgrp)
* If there are no more members of this particular group,
* send prune upstream
*/
- if (VIFM_ISEMPTY(g->gt_grpmems) && g->gt_route->rt_gateway)
+ if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway)
send_prune(g);
}
}
@@ -1290,9 +1177,15 @@ accept_prune(src, dst, p, datalen)
u_int32 prun_tmr;
vifi_t vifi;
int i;
+ int stop_sending;
struct rtentry *r;
struct gtable *g;
struct ptable *pt;
+ struct listaddr *vr;
+
+ /* Don't process any prunes if router is not pruning */
+ if (pruning == 0)
+ return;
if ((vifi = find_vif(src, dst)) == NO_VIF) {
log(LOG_INFO, 0,
@@ -1318,15 +1211,6 @@ accept_prune(src, dst, p, datalen)
((char *)&prun_tmr)[i] = *p++;
prun_tmr = ntohl(prun_tmr);
- if (prun_tmr <= MIN_PRUNE_LIFE) {
- IF_DEBUG(DEBUG_PRUNE)
- log(LOG_DEBUG, 0, "ignoring prune from %s on vif %d for (%s %s)/%d because its lifetime is too short",
- inet_fmt(src, s1), vifi,
- inet_fmt(prun_src, s2), inet_fmt(prun_grp, s3), prun_tmr);
- return;
- }
-
- IF_DEBUG(DEBUG_PRUNE)
log(LOG_DEBUG, 0, "%s on vif %d prunes (%s %s)/%d",
inet_fmt(src, s1), vifi,
inet_fmt(prun_src, s2), inet_fmt(prun_grp, s3), prun_tmr);
@@ -1338,19 +1222,10 @@ accept_prune(src, dst, p, datalen)
g = gtp ? gtp->gt_gnext : kernel_table;
r = g->gt_route;
- IF_DEBUG(DEBUG_PRUNE)
- log(LOG_DEBUG, 0, "found grp state, (%s %s), metric is %d, children are %x, subords are %08x%08x",
- RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2), r->rt_metric,
- r->rt_children, r->rt_subordinates.hi, r->rt_subordinates.lo);
if (!VIFM_ISSET(vifi, r->rt_children)) {
- IF_DEBUG(DEBUG_PRUNE)
- log(LOG_WARNING, 0, "prune received from non-child %s for (%s %s) (dominant on vif %d is %s)",
+ log(LOG_WARNING, 0, "prune received from non-child %s for (%s %s)",
inet_fmt(src, s1), inet_fmt(prun_src, s2),
- inet_fmt(prun_grp, s3), vifi,
- inet_fmt(r->rt_dominants[vifi], s4));
-#ifdef RINGBUFFER
- printringbuf();
-#endif
+ inet_fmt(prun_grp, s3));
return;
}
if (VIFM_ISSET(vifi, g->gt_scope)) {
@@ -1360,7 +1235,6 @@ accept_prune(src, dst, p, datalen)
return;
}
if ((pt = find_prune_entry(src, g->gt_pruntbl)) != NULL) {
- IF_DEBUG(DEBUG_PRUNE)
log(LOG_DEBUG, 0, "%s %d from %s for (%s %s)/%d %s %d %s %x",
"duplicate prune received on vif",
vifi, inet_fmt(src, s1), inet_fmt(prun_src, s2),
@@ -1368,14 +1242,6 @@ accept_prune(src, dst, p, datalen)
"old timer:", pt->pt_timer, "cur gm:", g->gt_grpmems);
pt->pt_timer = prun_tmr;
} else {
- struct listaddr *n = neighbor_info(vifi, src);
-
- if (!n) {
- log(LOG_WARNING, 0, "Prune from non-neighbor %s on vif %d!?",
- inet_fmt(src, s1), vifi);
- return;
- }
-
/* allocate space for the prune structure */
pt = (struct ptable *)(malloc(sizeof(struct ptable)));
if (pt == NULL)
@@ -1387,37 +1253,28 @@ accept_prune(src, dst, p, datalen)
pt->pt_next = g->gt_pruntbl;
g->gt_pruntbl = pt;
-
- if (n) {
- pt->pt_index = n->al_index;
- NBRM_SET(n->al_index, g->gt_prunes);
- }
}
+ /* Refresh the group's lifetime */
+ g->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ if (g->gt_timer < prun_tmr)
+ g->gt_timer = prun_tmr;
+
/*
* check if any more packets need to be sent on the
* vif which sent this message
*/
- if (SUBS_ARE_PRUNED(r->rt_subordinates,
- uvifs[vifi].uv_nbrmap, g->gt_prunes) &&
- !grplst_mem(vifi, prun_grp)) {
- nbrbitmap_t tmp;
+ stop_sending = 1;
+ for (vr = uvifs[vifi].uv_neighbors; vr; vr = vr->al_next)
+ if (find_prune_entry(vr->al_addr, g->gt_pruntbl) == NULL) {
+ stop_sending = 0;
+ break;
+ }
+ if (stop_sending && !grplst_mem(vifi, prun_grp)) {
VIFM_CLR(vifi, g->gt_grpmems);
- IF_DEBUG(DEBUG_PRUNE)
- log(LOG_DEBUG, 0, "vifnbrs=0x%08x%08x, subord=0x%08x%08x prunes=0x%08x%08x",
- uvifs[vifi].uv_nbrmap.hi,uvifs[vifi].uv_nbrmap.lo,
- r->rt_subordinates.hi, r->rt_subordinates.lo,
- g->gt_prunes.hi, g->gt_prunes.lo);
- /* XXX debugging */
- NBRM_COPY(r->rt_subordinates, tmp);
- NBRM_MASK(tmp, uvifs[vifi].uv_nbrmap);
- if (!NBRM_ISSETALLMASK(g->gt_prunes, tmp))
- log(LOG_WARNING, 0, "subordinate error");
- /* XXX end debugging */
- IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE)
log(LOG_DEBUG, 0, "prune (%s %s), stop sending on vif %d, gm:%x",
- RT_FMT(r, s1),
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(g->gt_mcastgrp, s2), vifi, g->gt_grpmems);
prun_add_ttls(g);
@@ -1434,7 +1291,7 @@ accept_prune(src, dst, p, datalen)
* interface
* Send a prune message then upstream
*/
- if (VIFM_ISEMPTY(g->gt_grpmems) && r->rt_gateway) {
+ if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway) {
send_prune(g);
}
} else {
@@ -1443,7 +1300,6 @@ accept_prune(src, dst, p, datalen)
* simply ignore the prune, as we are not forwarding this traffic
* downstream.
*/
- IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE)
log(LOG_DEBUG, 0, "%s (%s %s)/%d from %s",
"prune message received with no kernel entry for",
inet_fmt(prun_src, s1), inet_fmt(prun_grp, s2),
@@ -1477,19 +1333,22 @@ chkgrp_graft(vifi, mcastgrp)
* If the vif that was joined was a scoped vif,
* ignore it ; don't graft back
*/
- APPLY_SCOPE(g);
- if (VIFM_ISEMPTY(g->gt_grpmems))
+ g->gt_grpmems &= ~g->gt_scope;
+ if (g->gt_grpmems == 0)
continue;
+ /* set the flag for graft retransmission */
+ g->gt_grftsnt = 1;
+
/* send graft upwards */
send_graft(g);
- /* update cache timer*/
- g->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ /* reset the prune timer and update cache timer*/
+ g->gt_prsent_timer = 0;
+ g->gt_timer = max_prune_lifetime;
- IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE)
log(LOG_DEBUG, 0, "chkgrp graft (%s %s) gm:%x",
- RT_FMT(r, s1),
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
prun_add_ttls(g);
@@ -1529,6 +1388,13 @@ accept_graft(src, dst, p, datalen)
struct gtable *g;
struct ptable *pt, **ptnp;
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring graft from non-neighbor %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
if (datalen < 8) {
log(LOG_WARNING, 0,
"received non-decipherable graft from %s",
@@ -1540,19 +1406,7 @@ accept_graft(src, dst, p, datalen)
((char *)&graft_src)[i] = *p++;
for (i = 0; i< 4; i++)
((char *)&graft_grp)[i] = *p++;
-
- vifi = find_vif(src, dst);
- send_graft_ack(dst, src, graft_src, graft_grp, vifi);
-
- if (vifi == NO_VIF) {
- log(LOG_INFO, 0,
- "ignoring graft for (%s %s) from non-neighbor %s",
- inet_fmt(graft_src, s2), inet_fmt(graft_grp, s3),
- inet_fmt(src, s1));
- return;
- }
-
- IF_DEBUG(DEBUG_PRUNE)
+
log(LOG_DEBUG, 0, "%s on vif %d grafts (%s %s)",
inet_fmt(src, s1), vifi,
inet_fmt(graft_src, s2), inet_fmt(graft_grp, s3));
@@ -1574,14 +1428,12 @@ accept_graft(src, dst, p, datalen)
ptnp = &g->gt_pruntbl;
while ((pt = *ptnp) != NULL) {
if ((pt->pt_vifi == vifi) && (pt->pt_router == src)) {
- NBRM_CLR(pt->pt_index, g->gt_prunes);
*ptnp = pt->pt_next;
free(pt);
VIFM_SET(vifi, g->gt_grpmems);
- IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE)
log(LOG_DEBUG, 0, "accept graft (%s %s) gm:%x",
- RT_FMT(r, s1),
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
prun_add_ttls(g);
@@ -1596,18 +1448,28 @@ accept_graft(src, dst, p, datalen)
}
}
- g->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ /* send ack downstream */
+ send_graft_ack(dst, src, graft_src, graft_grp);
+ g->gt_timer = max_prune_lifetime;
- if (g->gt_prsent_timer)
+ if (g->gt_prsent_timer) {
+ /* set the flag for graft retransmission */
+ g->gt_grftsnt = 1;
+
/* send graft upwards */
send_graft(g);
+
+ /* reset the prune sent timer */
+ g->gt_prsent_timer = 0;
+ }
} else {
/*
* We have no state for the source and group in question.
- * This is fine, since we know that we have no prune state, and
- * grafts are requests to remove prune state.
+ * We can simply acknowledge the graft, since we know
+ * that we have no prune state, and grafts are requests
+ * to remove prune state.
*/
- IF_DEBUG(DEBUG_PRUNE)
+ send_graft_ack(dst, src, graft_src, graft_grp);
log(LOG_DEBUG, 0, "%s (%s %s) from %s",
"graft received with no kernel entry for",
inet_fmt(graft_src, s1), inet_fmt(graft_grp, s2),
@@ -1656,7 +1518,6 @@ accept_g_ack(src, dst, p, datalen)
for (i = 0; i< 4; i++)
((char *)&grft_grp)[i] = *p++;
- IF_DEBUG(DEBUG_PRUNE)
log(LOG_DEBUG, 0, "%s on vif %d acks graft (%s, %s)",
inet_fmt(src, s1), vifi,
inet_fmt(grft_src, s2), inet_fmt(grft_grp, s3));
@@ -1672,9 +1533,6 @@ accept_g_ack(src, dst, p, datalen)
"rcvd graft ack with no kernel entry for",
inet_fmt(grft_src, s1), inet_fmt(grft_grp, s2),
inet_fmt(src, s3));
-#ifdef RINGBUFFER
- printringbuf();
-#endif
return;
}
}
@@ -1713,8 +1571,6 @@ free_all_prunes()
prev_g = g;
g = g->gt_next;
- if (prev_g->gt_rexmit_timer)
- timer_clearTimer(prev_g->gt_rexmit_timer);
free(prev_g);
}
r->rt_groups = NULL;
@@ -1728,8 +1584,6 @@ free_all_prunes()
prev_g = g;
g = g->gt_next;
- if (prev_g->gt_rexmit_timer)
- timer_clearTimer(prev_g->gt_rexmit_timer);
free(prev_g);
}
kernel_no_route = NULL;
@@ -1753,32 +1607,27 @@ steal_sources(rt)
register struct stable *st, **stnp;
for (rp = rt->rt_next; rp; rp = rp->rt_next) {
- if (rp->rt_groups == NULL)
- continue;
if ((rt->rt_origin & rp->rt_originmask) == rp->rt_origin) {
- IF_DEBUG(DEBUG_ROUTE)
log(LOG_DEBUG, 0, "Route for %s stealing sources from %s",
- RT_FMT(rt, s1), RT_FMT(rp, s2));
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
+ inet_fmts(rp->rt_origin, rp->rt_originmask, s2));
for (gt = rp->rt_groups; gt; gt = gt->gt_next) {
stnp = &gt->gt_srctbl;
while ((st = *stnp) != NULL) {
if ((st->st_origin & rt->rt_originmask) == rt->rt_origin) {
- IF_DEBUG(DEBUG_ROUTE)
log(LOG_DEBUG, 0, "%s stealing (%s %s) from %s",
- RT_FMT(rt, s1),
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
inet_fmt(st->st_origin, s3),
inet_fmt(gt->gt_mcastgrp, s4),
- RT_FMT(rp, s2));
- if (st->st_ctime != 0) {
- if (k_del_rg(st->st_origin, gt) < 0) {
- log(LOG_WARNING, errno, "%s (%s, %s)",
- "steal_sources trying to delete",
- inet_fmt(st->st_origin, s1),
- inet_fmt(gt->gt_mcastgrp, s2));
- }
- kroutes--;
+ inet_fmts(rp->rt_origin, rp->rt_originmask, s2));
+ if (k_del_rg(st->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno, "%s (%s, %s)",
+ "steal_sources trying to delete",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
}
*stnp = st->st_next;
+ kroutes--;
free(st);
} else {
stnp = &st->st_next;
@@ -1792,27 +1641,22 @@ steal_sources(rt)
while ((gt = *gtnp) != NULL) {
if (gt->gt_srctbl && ((gt->gt_srctbl->st_origin & rt->rt_originmask)
== rt->rt_origin)) {
- IF_DEBUG(DEBUG_ROUTE)
log(LOG_DEBUG, 0, "%s stealing (%s %s) from %s",
- RT_FMT(rt, s1),
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
inet_fmt(gt->gt_srctbl->st_origin, s3),
inet_fmt(gt->gt_mcastgrp, s4),
"no_route table");
- if (gt->gt_srctbl->st_ctime != 0) {
- if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
- log(LOG_WARNING, errno, "%s (%s %s)",
- "steal_sources trying to delete",
- inet_fmt(gt->gt_srctbl->st_origin, s1),
- inet_fmt(gt->gt_mcastgrp, s2));
- }
- kroutes--;
+ if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno, "%s (%s %s)",
+ "steal_sources trying to delete",
+ inet_fmt(gt->gt_srctbl->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
}
+ kroutes--;
free(gt->gt_srctbl);
*gtnp = gt->gt_next;
if (gt->gt_next)
gt->gt_next->gt_prev = gt->gt_prev;
- if (gt->gt_rexmit_timer)
- timer_clearTimer(gt->gt_rexmit_timer);
free(gt);
} else {
gtnp = &gt->gt_next;
@@ -1834,98 +1678,31 @@ age_table_entry()
struct ptable *pt, **ptnp;
struct sioc_sg_req sg_req;
- IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE)
- log(LOG_DEBUG, 0, "aging forwarding cache entries");
+ log(LOG_DEBUG, 0, "ageing entries");
gtnptr = &kernel_table;
while ((gt = *gtnptr) != NULL) {
- vifi_t i; /* XXX Debugging */
- int fixit = 0; /* XXX Debugging */
-
r = gt->gt_route;
- /* XXX Debugging... */
- for (i = 0; i < numvifs; i++) {
- /*
- * If we're not sending on this vif,
- * And this group isn't scoped on this vif,
- * And I'm the parent for this route on this vif,
- * And there are subordinates on this vif,
- * And all of the subordinates haven't pruned,
- * YELL LOUDLY
- * and remember to fix it up later
- */
- if (!VIFM_ISSET(i, gt->gt_grpmems) &&
- !VIFM_ISSET(i, gt->gt_scope) &&
- VIFM_ISSET(i, r->rt_children) &&
- NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates) &&
- !SUBS_ARE_PRUNED(r->rt_subordinates, uvifs[i].uv_nbrmap, gt->gt_prunes)) {
- log(LOG_WARNING, 0, "(%s %s) is blackholing on vif %d",
- RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2), i);
- fixit = 1;
- }
- }
- if (fixit) {
- log(LOG_WARNING, 0, "fixing membership for (%s %s) gm:%x",
- RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems);
- determine_forwvifs(gt);
- send_prune_or_graft(gt);
- log(LOG_WARNING, 0, "fixed membership for (%s %s) gm:%x",
- RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems);
-#ifdef RINGBUFFER
- printringbuf();
-#endif
- }
- /*DEBUG2*/
- /* If there are group members,
- * and there are recent sources,
- * and we have a route,
- * and it's not directly connected,
- * and we haven't sent a prune,
- * if there are any cache entries in the kernel
- * [if there aren't we're probably waiting to rexmit],
- * YELL LOUDLY
- * and send a prune
- */
- if (VIFM_ISEMPTY(gt->gt_grpmems) && gt->gt_srctbl && r && r->rt_gateway && gt->gt_prsent_timer == 0) {
- for (st = gt->gt_srctbl; st; st = st->st_next)
- if (st->st_ctime != 0)
- break;
- if (st != NULL) {
- log(LOG_WARNING, 0, "grpmems for (%s %s) is empty but no prune state!", RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2));
- send_prune_or_graft(gt);
-#ifdef RINGBUFFER
- printringbuf();
-#endif
- }
- }
- /* XXX ...Debugging */
-
/* advance the timer for the kernel entry */
- gt->gt_timer -= TIMER_INTERVAL;
+ gt->gt_timer -= ROUTE_MAX_REPORT_DELAY;
/* decrement prune timer if need be */
if (gt->gt_prsent_timer > 0) {
- gt->gt_prsent_timer -= TIMER_INTERVAL;
+ gt->gt_prsent_timer -= ROUTE_MAX_REPORT_DELAY;
if (gt->gt_prsent_timer <= 0) {
- IF_DEBUG(DEBUG_PRUNE)
log(LOG_DEBUG, 0, "upstream prune tmo (%s %s)",
- RT_FMT(r, s1),
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(gt->gt_mcastgrp, s2));
gt->gt_prsent_timer = -1;
- /* Reset the prune retransmission timer to its initial value */
- gt->gt_prune_rexmit = PRUNE_REXMIT_VAL;
}
}
- /* retransmit graft with exponential backoff */
+ /* retransmit graft if graft sent flag is still set */
if (gt->gt_grftsnt) {
register int y;
-
- y = ++gt->gt_grftsnt;
- while (y && !(y & 1))
- y >>= 1;
- if (y == 1)
+ CHK_GS(gt->gt_grftsnt++, y);
+ if (y)
send_graft(gt);
}
@@ -1936,24 +1713,13 @@ age_table_entry()
*/
ptnp = &gt->gt_pruntbl;
while ((pt = *ptnp) != NULL) {
- if ((pt->pt_timer -= TIMER_INTERVAL) <= 0) {
- IF_DEBUG(DEBUG_PRUNE)
+ if ((pt->pt_timer -= ROUTE_MAX_REPORT_DELAY) <= 0) {
log(LOG_DEBUG, 0, "expire prune (%s %s) from %s on vif %d",
- RT_FMT(r, s1),
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(gt->gt_mcastgrp, s2),
inet_fmt(pt->pt_router, s3),
pt->pt_vifi);
- if (gt->gt_prsent_timer > 0) {
- log(LOG_WARNING, 0, "prune (%s %s) from %s on vif %d expires with %d left on prsent timer",
- RT_FMT(r, s1),
- inet_fmt(gt->gt_mcastgrp, s2),
- inet_fmt(pt->pt_router, s3),
- pt->pt_vifi, gt->gt_prsent_timer);
- /* Send a graft to heal the tree. */
- send_graft(gt);
- }
- NBRM_CLR(pt->pt_index, gt->gt_prunes);
expire_prune(pt->pt_vifi, gt);
/* remove the router's prune entry and await new one */
@@ -1971,47 +1737,31 @@ age_table_entry()
* Otherwise, the cache entry's timer is refreshed.
*/
if (gt->gt_timer <= 0) {
- IF_DEBUG(DEBUG_CACHE)
- log(LOG_DEBUG, 0, "(%s %s) timed out, checking for traffic",
- RT_FMT(gt->gt_route, s1),
- inet_fmt(gt->gt_mcastgrp, s2));
/* Check for traffic before deleting source entries */
sg_req.grp.s_addr = gt->gt_mcastgrp;
stnp = &gt->gt_srctbl;
while ((st = *stnp) != NULL) {
- /*
- * Source entries with no ctime are not actually in the
- * kernel; they have been removed by rexmit_prune() so
- * are safe to remove from the list at this point.
- */
- if (st->st_ctime) {
- sg_req.src.s_addr = st->st_origin;
- if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) {
- log(LOG_WARNING, errno, "%s (%s %s)",
- "age_table_entry: SIOCGETSGCNT failing for",
- inet_fmt(st->st_origin, s1),
- inet_fmt(gt->gt_mcastgrp, s2));
- /* Make sure it gets deleted below */
- sg_req.pktcnt = st->st_pktcnt;
- }
- } else {
+ sg_req.src.s_addr = st->st_origin;
+ if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) {
+ log(LOG_WARNING, errno, "%s (%s %s)",
+ "age_table_entry: SIOCGETSGCNT failing for",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ /* Make sure it gets deleted below */
sg_req.pktcnt = st->st_pktcnt;
}
if (sg_req.pktcnt == st->st_pktcnt) {
*stnp = st->st_next;
- IF_DEBUG(DEBUG_CACHE)
log(LOG_DEBUG, 0, "age_table_entry deleting (%s %s)",
inet_fmt(st->st_origin, s1),
inet_fmt(gt->gt_mcastgrp, s2));
- if (st->st_ctime != 0) {
- if (k_del_rg(st->st_origin, gt) < 0) {
- log(LOG_WARNING, errno,
- "age_table_entry trying to delete (%s %s)",
- inet_fmt(st->st_origin, s1),
- inet_fmt(gt->gt_mcastgrp, s2));
- }
- kroutes--;
+ if (k_del_rg(st->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno,
+ "age_table_entry trying to delete (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
}
+ kroutes--;
free(st);
} else {
st->st_pktcnt = sg_req.pktcnt;
@@ -2022,39 +1772,22 @@ age_table_entry()
/*
* Retain the group entry if we have downstream prunes or if
* there is at least one source in the list that still has
- * traffic, or if our upstream prune timer or graft
- * retransmission timer is running.
+ * traffic, or if our upstream prune timer is running.
*/
if (gt->gt_pruntbl != NULL || gt->gt_srctbl != NULL ||
- gt->gt_prsent_timer > 0 || gt->gt_grftsnt > 0) {
- IF_DEBUG(DEBUG_CACHE)
- log(LOG_DEBUG, 0, "refresh lifetim of cache entry %s%s%s%s(%s, %s)",
- gt->gt_pruntbl ? "(dstrm prunes) " : "",
- gt->gt_srctbl ? "(trfc flow) " : "",
- gt->gt_prsent_timer > 0 ? "(upstrm prune) " : "",
- gt->gt_grftsnt > 0 ? "(grft rexmit) " : "",
- RT_FMT(r, s1),
- inet_fmt(gt->gt_mcastgrp, s2));
+ gt->gt_prsent_timer > 0) {
gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
- if (gt->gt_prsent_timer == -1) {
- /*
- * The upstream prune timed out. Remove any kernel
- * state.
- */
- gt->gt_prsent_timer = 0;
- if (gt->gt_pruntbl) {
- log(LOG_WARNING, 0, "upstream prune for (%s %s) expires with downstream prunes active",
- RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2));
- }
- remove_sources(gt);
- }
+ if (gt->gt_prsent_timer == -1)
+ if (gt->gt_grpmems == 0)
+ send_prune(gt);
+ else
+ gt->gt_prsent_timer = 0;
gtnptr = &gt->gt_gnext;
continue;
}
- IF_DEBUG(DEBUG_CACHE)
log(LOG_DEBUG, 0, "timeout cache entry (%s, %s)",
- RT_FMT(r, s1),
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(gt->gt_mcastgrp, s2));
if (gt->gt_prev)
@@ -2079,23 +1812,13 @@ age_table_entry()
rsrr_cache_send(gt,0);
rsrr_cache_clean(gt);
#endif /* RSRR */
- if (gt->gt_rexmit_timer)
- timer_clearTimer(gt->gt_rexmit_timer);
-
free((char *)gt);
} else {
- if (gt->gt_prsent_timer == -1) {
- /*
- * The upstream prune timed out. Remove any kernel
- * state.
- */
- gt->gt_prsent_timer = 0;
- if (gt->gt_pruntbl) {
- log(LOG_WARNING, 0, "upstream prune for (%s %s) expires with downstream prunes active",
- RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2));
- }
- remove_sources(gt);
- }
+ if (gt->gt_prsent_timer == -1)
+ if (gt->gt_grpmems == 0)
+ send_prune(gt);
+ else
+ gt->gt_prsent_timer = 0;
gtnptr = &gt->gt_gnext;
}
}
@@ -2107,18 +1830,15 @@ age_table_entry()
gtnptr = &kernel_no_route;
while ((gt = *gtnptr) != NULL) {
/* advance the timer for the kernel entry */
- gt->gt_timer -= TIMER_INTERVAL;
+ gt->gt_timer -= ROUTE_MAX_REPORT_DELAY;
if (gt->gt_timer < 0) {
if (gt->gt_srctbl) {
- if (gt->gt_srctbl->st_ctime != 0) {
- if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
- log(LOG_WARNING, errno, "%s (%s %s)",
- "age_table_entry trying to delete no-route",
- inet_fmt(gt->gt_srctbl->st_origin, s1),
- inet_fmt(gt->gt_mcastgrp, s2));
- }
- kroutes--;
+ if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno, "%s (%s %s)",
+ "age_table_entry trying to delete no-route",
+ inet_fmt(gt->gt_srctbl->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
}
free(gt->gt_srctbl);
}
@@ -2126,9 +1846,6 @@ age_table_entry()
if (gt->gt_next)
gt->gt_next->gt_prev = gt->gt_prev;
- if (gt->gt_rexmit_timer)
- timer_clearTimer(gt->gt_rexmit_timer);
-
free((char *)gt);
} else {
gtnptr = &gt->gt_next;
@@ -2149,24 +1866,19 @@ expire_prune(vifi, gt)
/*
* No need to send a graft, any prunes that we sent
* will expire before any prunes that we have received.
- * However, in the case that we did make a mistake,
- * send a graft to compensate.
*/
- if (gt->gt_prsent_timer >= MIN_PRUNE_LIFE) {
- IF_DEBUG(DEBUG_PRUNE)
+ if (gt->gt_prsent_timer > 0) {
log(LOG_DEBUG, 0, "prune expired with %d left on %s",
gt->gt_prsent_timer, "prsent_timer");
gt->gt_prsent_timer = 0;
- send_graft(gt);
}
/* modify the kernel entry to forward packets */
if (!VIFM_ISSET(vifi, gt->gt_grpmems)) {
struct rtentry *rt = gt->gt_route;
VIFM_SET(vifi, gt->gt_grpmems);
- IF_DEBUG(DEBUG_CACHE)
log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
- RT_FMT(rt, s1),
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems, vifi);
prun_add_ttls(gt);
@@ -2178,6 +1890,46 @@ expire_prune(vifi, gt)
}
}
+
+static char *
+scaletime(t)
+ u_long t;
+{
+ static char buf1[5];
+ static char buf2[5];
+ static char *buf=buf1;
+ char s;
+ char *p;
+
+ p = buf;
+ if (buf == buf1)
+ buf = buf2;
+ else
+ buf = buf1;
+
+ if (t < 120) {
+ s = 's';
+ } else if (t < 3600) {
+ t /= 60;
+ s = 'm';
+ } else if (t < 86400) {
+ t /= 3600;
+ s = 'h';
+ } else if (t < 864000) {
+ t /= 86400;
+ s = 'd';
+ } else {
+ t /= 604800;
+ s = 'w';
+ }
+ if (t > 999)
+ return "*** ";
+
+ sprintf(p,"%3d%c", (int)t, s);
+
+ return p;
+}
+
/*
* Print the contents of the cache table on file 'fp2'.
*/
@@ -2195,14 +1947,11 @@ dump_cache(fp2)
fprintf(fp2,
"Multicast Routing Cache Table (%d entries)\n%s", kroutes,
- " Origin Mcast-group CTmr Age Ptmr Rx IVif Forwvifs\n");
- fprintf(fp2,
- "<(prunesrc:vif[idx]/tmr) prunebitmap\n%s",
- ">Source Lifetime SavPkt Pkts Bytes RPFf\n");
+ " Origin Mcast-group CTmr Age Ptmr IVif Forwvifs\n");
for (gt = kernel_no_route; gt; gt = gt->gt_next) {
if (gt->gt_srctbl) {
- fprintf(fp2, " %-18s %-15s %-8s %-8s - -1 (no route)\n",
+ fprintf(fp2, " %-18s %-15s %-4s %-4s - -1\n",
inet_fmts(gt->gt_srctbl->st_origin, 0xffffffff, s1),
inet_fmt(gt->gt_mcastgrp, s2), scaletime(gt->gt_timer),
scaletime(thyme - gt->gt_ctime));
@@ -2213,78 +1962,40 @@ dump_cache(fp2)
for (gt = kernel_table; gt; gt = gt->gt_gnext) {
r = gt->gt_route;
fprintf(fp2, " %-18s %-15s",
- RT_FMT(r, s1),
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(gt->gt_mcastgrp, s2));
- fprintf(fp2, " %-8s", scaletime(gt->gt_timer));
+ fprintf(fp2, " %-4s", scaletime(gt->gt_timer));
- fprintf(fp2, " %-8s %-8s ", scaletime(thyme - gt->gt_ctime),
+ fprintf(fp2, " %-4s %-4s ", scaletime(thyme - gt->gt_ctime),
gt->gt_prsent_timer ? scaletime(gt->gt_prsent_timer) :
- " -");
-
- if (gt->gt_prune_rexmit) {
- int i = gt->gt_prune_rexmit;
- int n = 0;
+ " -");
- while (i > PRUNE_REXMIT_VAL) {
- n++;
- i /= 2;
- }
- if (n == 0 && gt->gt_prsent_timer == 0)
- fprintf(fp2, " -");
- else
- fprintf(fp2, "%2d", n);
- } else {
- fprintf(fp2, " -");
- }
-
- fprintf(fp2, " %2u%c%c", r->rt_parent,
- gt->gt_prsent_timer ? 'P' :
- gt->gt_grftsnt ? 'G' : ' ',
+ fprintf(fp2, "%2u%c%c ", r->rt_parent,
+ gt->gt_prsent_timer ? 'P' : ' ',
VIFM_ISSET(r->rt_parent, gt->gt_scope) ? 'B' : ' ');
for (i = 0; i < numvifs; ++i) {
if (VIFM_ISSET(i, gt->gt_grpmems))
fprintf(fp2, " %u ", i);
else if (VIFM_ISSET(i, r->rt_children) &&
- NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates))
+ !VIFM_ISSET(i, r->rt_leaves))
fprintf(fp2, " %u%c", i,
- VIFM_ISSET(i, gt->gt_scope) ? 'b' :
- SUBS_ARE_PRUNED(r->rt_subordinates,
- uvifs[i].uv_nbrmap, gt->gt_prunes) ? 'p' : '!');
+ VIFM_ISSET(i, gt->gt_scope) ? 'b' : 'p');
}
fprintf(fp2, "\n");
if (gt->gt_pruntbl) {
fprintf(fp2, "<");
c = '(';
for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next) {
- fprintf(fp2, "%c%s:%d[%d]/%d", c, inet_fmt(pt->pt_router, s1),
- pt->pt_vifi, pt->pt_index, pt->pt_timer);
+ fprintf(fp2, "%c%s:%d/%d", c, inet_fmt(pt->pt_router, s1),
+ pt->pt_vifi, pt->pt_timer);
c = ',';
}
- fprintf(fp2, ")");
- fprintf(fp2, " 0x%08lx%08lx\n",/*XXX*/
- gt->gt_prunes.hi, gt->gt_prunes.lo);
+ fprintf(fp2, ")\n");
}
for (st = gt->gt_srctbl; st; st = st->st_next) {
- fprintf(fp2, ">%-18s %-8s %6ld", inet_fmt(st->st_origin, s1),
- st->st_ctime ? scaletime(thyme - st->st_ctime) : "-",
- st->st_savpkt);
- if (st->st_ctime) {
- struct sioc_sg_req sg_req;
-
- sg_req.src.s_addr = st->st_origin;
- sg_req.grp.s_addr = gt->gt_mcastgrp;
- if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) {
- log(LOG_WARNING, errno, "SIOCGETSGCNT on (%s %s)",
- inet_fmt(st->st_origin, s1),
- inet_fmt(gt->gt_mcastgrp, s2));
- } else {
- fprintf(fp2, " %8ld %8ld %4ld", sg_req.pktcnt,
- sg_req.bytecnt, sg_req.wrong_if);
- }
- }
- fprintf(fp2, "\n");
+ fprintf(fp2, ">%s\n", inet_fmt(st->st_origin, s1));
}
}
}
@@ -2327,17 +2038,14 @@ accept_mtrace(src, dst, group, data, no, datalen)
*/
if (datalen == QLEN) {
type = QUERY;
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Initial traceroute query rcvd from %s to %s",
inet_fmt(src, s1), inet_fmt(dst, s2));
}
else if ((datalen - QLEN) % RLEN == 0) {
type = RESP;
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "In-transit traceroute query rcvd from %s to %s",
inet_fmt(src, s1), inet_fmt(dst, s2));
if (IN_MULTICAST(ntohl(dst))) {
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Dropping multicast response");
return;
}
@@ -2355,27 +2063,23 @@ accept_mtrace(src, dst, group, data, no, datalen)
* if it is a packet with all reports filled, drop it
*/
if ((rcount = (datalen - QLEN)/RLEN) == no) {
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "packet with all reports filled in");
return;
}
- IF_DEBUG(DEBUG_TRACE) {
log(LOG_DEBUG, 0, "s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1),
inet_fmt(group, s2), inet_fmt(qry->tr_dst, s3));
log(LOG_DEBUG, 0, "rttl: %d rd: %s", qry->tr_rttl,
inet_fmt(qry->tr_raddr, s1));
log(LOG_DEBUG, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qid);
- }
/* determine the routing table entry for this traceroute */
rt = determine_route(qry->tr_src);
- IF_DEBUG(DEBUG_TRACE)
if (rt) {
log(LOG_DEBUG, 0, "rt parent vif: %d rtr: %s metric: %d",
rt->rt_parent, inet_fmt(rt->rt_gateway, s1), rt->rt_metric);
log(LOG_DEBUG, 0, "rt origin %s",
- RT_FMT(rt, s1));
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1));
} else
log(LOG_DEBUG, 0, "...no route");
@@ -2396,13 +2100,11 @@ accept_mtrace(src, dst, group, data, no, datalen)
* only get N copies, N <= the number of interfaces on the router,
* it is not fatal.
*/
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
return;
}
if (rt == NULL) {
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s",
inet_fmt(qry->tr_src, s1));
if (IN_MULTICAST(ntohl(dst)))
@@ -2412,14 +2114,12 @@ accept_mtrace(src, dst, group, data, no, datalen)
if (vifi == NO_VIF) {
/* The traceroute destination is not on one of my subnet vifs. */
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Destination %s not an interface",
inet_fmt(qry->tr_dst, s1));
if (IN_MULTICAST(ntohl(dst)))
return;
errcode = TR_WRONG_IF;
} else if (rt != NULL && !VIFM_ISSET(vifi, rt->rt_children)) {
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s",
inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
if (IN_MULTICAST(ntohl(dst)))
@@ -2434,7 +2134,6 @@ accept_mtrace(src, dst, group, data, no, datalen)
* a tunnel or came from a directly attached mrouter.
*/
if ((vifi = find_vif(src, dst)) == NO_VIF) {
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Wrong interface for packet");
errcode = TR_WRONG_IF;
}
@@ -2443,7 +2142,6 @@ accept_mtrace(src, dst, group, data, no, datalen)
/* Now that we've decided to send a response, save the qid */
oqid = qry->tr_qid;
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Sending traceroute response");
/* copy the packet to the sending buffer */
@@ -2475,18 +2173,21 @@ accept_mtrace(src, dst, group, data, no, datalen)
((tp.tv_usec << 10) / 15625));
resp->tr_rproto = PROTO_DVMRP;
- resp->tr_outaddr = (vifi == NO_VIF) ? dst : uvifs[vifi].uv_lcl_addr;
- resp->tr_fttl = (vifi == NO_VIF) ? 0 : uvifs[vifi].uv_threshold;
- resp->tr_rflags = errcode;
+ if (errcode != TR_NO_ERR) {
+ resp->tr_rflags = errcode;
+ rt = NULL; /* hack to enforce send straight to requestor */
+ goto sendit;
+ }
+ resp->tr_outaddr = uvifs[vifi].uv_lcl_addr;
+ resp->tr_fttl = uvifs[vifi].uv_threshold;
+ resp->tr_rflags = TR_NO_ERR;
/*
* obtain # of packets out on interface
*/
v_req.vifi = vifi;
- if (vifi != NO_VIF && ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
+ if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
resp->tr_vifout = htonl(v_req.ocount);
- else
- resp->tr_vifout = 0xffffffff;
/*
* fill in scoping & pruning information
@@ -2500,34 +2201,23 @@ accept_mtrace(src, dst, group, data, no, datalen)
gt = NULL;
if (gt && gt->gt_mcastgrp == group) {
- struct stable *st;
-
- for (st = gt->gt_srctbl; st; st = st->st_next)
- if (qry->tr_src == st->st_origin)
- break;
-
sg_req.src.s_addr = qry->tr_src;
sg_req.grp.s_addr = group;
- if (st && st->st_ctime != 0 &&
- ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0)
- resp->tr_pktcnt = htonl(sg_req.pktcnt + st->st_savpkt);
- else
- resp->tr_pktcnt = htonl(st ? st->st_savpkt : 0xffffffff);
+ if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0)
+ resp->tr_pktcnt = htonl(sg_req.pktcnt);
if (VIFM_ISSET(vifi, gt->gt_scope))
resp->tr_rflags = TR_SCOPED;
else if (gt->gt_prsent_timer)
resp->tr_rflags = TR_PRUNED;
else if (!VIFM_ISSET(vifi, gt->gt_grpmems))
- if (!NBRM_ISEMPTY(uvifs[vifi].uv_nbrmap) &&
- SUBS_ARE_PRUNED(rt->rt_subordinates,
- uvifs[vifi].uv_nbrmap, gt->gt_prunes))
+ if (VIFM_ISSET(vifi, rt->rt_children) &&
+ !VIFM_ISSET(vifi, rt->rt_leaves))
resp->tr_rflags = TR_OPRUNED;
else
resp->tr_rflags = TR_NO_FWD;
} else {
- if ((vifi != NO_VIF && scoped_addr(vifi, group)) ||
- (rt && scoped_addr(rt->rt_parent, group)))
+ if (scoped_addr(vifi, group))
resp->tr_rflags = TR_SCOPED;
else if (rt && !VIFM_ISSET(vifi, rt->rt_children))
resp->tr_rflags = TR_NO_FWD;
@@ -2546,15 +2236,12 @@ accept_mtrace(src, dst, group, data, no, datalen)
v_req.vifi = rt->rt_parent;
if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
resp->tr_vifin = htonl(v_req.icount);
- else
- resp->tr_vifin = 0xffffffff;
MASK_TO_VAL(rt->rt_originmask, resp->tr_smask);
src = uvifs[rt->rt_parent].uv_lcl_addr;
resp->tr_inaddr = src;
resp->tr_rmtaddr = rt->rt_gateway;
if (!VIFM_ISSET(vifi, rt->rt_children)) {
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s",
inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
resp->tr_rflags = TR_WRONG_IF;
@@ -2572,7 +2259,6 @@ sendit:
* else send to upstream router. If the upstream router can't handle
* mtrace, set an error code and send to requestor anyway.
*/
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "rcount:%d, no:%d", rcount, no);
if ((rcount + 1 == no) || (rt == NULL) || (rt->rt_metric == 1)) {
@@ -2594,7 +2280,6 @@ sendit:
* If we don't have one, we can't source any multicasts anyway.
*/
if (phys_vif != -1) {
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Sending reply to %s from %s",
inet_fmt(dst, s1), inet_fmt(uvifs[phys_vif].uv_lcl_addr, s2));
k_set_ttl(qry->tr_rttl);
@@ -2606,7 +2291,6 @@ sendit:
log(LOG_INFO, 0, "No enabled phyints -- %s",
"dropping traceroute reply");
} else {
- IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Sending %s to %s from %s",
resptype == IGMP_MTRACE_RESP ? "reply" : "request on",
inet_fmt(dst, s1), inet_fmt(src, s2));