summaryrefslogtreecommitdiffstats
path: root/usr.sbin/mrouted/prune.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1996-01-06 21:10:30 +0000
committerpeter <peter@FreeBSD.org>1996-01-06 21:10:30 +0000
commitd4c03f31b99ac4bd269582b4d2fee704364a2c1e (patch)
treef1d0a40a2a6e33e9f309cdfe59bfbb0d9a7d4628 /usr.sbin/mrouted/prune.c
parenta8e9d6a2eaa9df5881201d40c5c05c6154333fef (diff)
downloadFreeBSD-src-d4c03f31b99ac4bd269582b4d2fee704364a2c1e.zip
FreeBSD-src-d4c03f31b99ac4bd269582b4d2fee704364a2c1e.tar.gz
Resync our mainline to mrouted release 3.8.
This will make FreeBSD boxes better behaved 'MBONE Citizens', based on a couple of the comments about the severity of fixes.. Agreed to by: wollman, fenner@parc.xerox.com
Diffstat (limited to 'usr.sbin/mrouted/prune.c')
-rw-r--r--usr.sbin/mrouted/prune.c354
1 files changed, 161 insertions, 193 deletions
diff --git a/usr.sbin/mrouted/prune.c b/usr.sbin/mrouted/prune.c
index fe4d507..fe3cdd5 100644
--- a/usr.sbin/mrouted/prune.c
+++ b/usr.sbin/mrouted/prune.c
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: prune.c,v 1.8 1995/06/28 17:58:42 wollman Exp $
+ * $Id: prune.c,v 3.8 1995/11/29 22:36:34 fenner Rel $
*/
@@ -55,6 +55,7 @@ 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 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,
@@ -84,7 +85,7 @@ prun_add_ttls(gt)
* checks for scoped multicast addresses
*/
#define GET_SCOPE(gt) { \
- register int _i; \
+ register vifi_t _i; \
if ((ntohl((gt)->gt_mcastgrp) & 0xff000000) == 0xef000000) \
for (_i = 0; _i < numvifs; _i++) \
if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
@@ -633,7 +634,11 @@ add_table_entry(origin, mcastgrp)
struct rtentry *r;
struct gtable *gt,**gtnp,*prev_gt;
struct stable *st,**stnp;
- int i;
+ vifi_t i;
+
+#ifdef DEBUG_MFC
+ md_log(MD_MISS, origin, mcastgrp);
+#endif
r = determine_route(origin);
prev_gt = NULL;
@@ -727,7 +732,7 @@ add_table_entry(origin, mcastgrp)
gt->gt_gnext->gt_gprev = gt;
}
} else {
- gt->gt_gnext = gt->gt_prev = NULL;
+ gt->gt_gnext = gt->gt_gprev = NULL;
}
}
@@ -748,8 +753,14 @@ add_table_entry(origin, mcastgrp)
st->st_next = *stnp;
*stnp = st;
} else {
+#ifdef DEBUG_MFC
+ md_log(MD_DUPE, origin, mcastgrp);
+#endif
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;
}
@@ -780,60 +791,31 @@ reset_neighbor_state(vifi, addr)
{
struct rtentry *r;
struct gtable *g;
- struct ptable *pt, *prev_pt;
- struct stable *st, *prev_st;
+ struct ptable *pt, **ptnp;
+ struct stable *st;
for (g = kernel_table; g; g = g->gt_gnext) {
r = g->gt_route;
/*
* If neighbor was the parent, remove the prune sent state
- * Don't send any grafts upstream.
+ * and all of the source cache info so that prunes get
+ * regenerated.
*/
if (vifi == r->rt_parent) {
if (addr == r->rt_gateway) {
- log(LOG_DEBUG, 0, "reset_neighbor_state del prunes (%s %s)",
+ log(LOG_DEBUG, 0, "reset_neighbor_state parent reset (%s %s)",
inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(g->gt_mcastgrp, s2));
- pt = g->gt_pruntbl;
- while (pt) {
- /*
- * Expire prune, send again on this vif.
- */
- VIFM_SET(pt->pt_vifi, g->gt_grpmems);
- prev_pt = pt;
- pt = prev_pt->pt_next;
- free(prev_pt);
- }
- g->gt_pruntbl = NULL;
-
- st = g->gt_srctbl;
- while (st) {
- log(LOG_DEBUG, 0, "reset_neighbor_state del sg (%s %s)",
- inet_fmt(st->st_origin, s1),
- inet_fmt(g->gt_mcastgrp, s2));
-
- if (k_del_rg(st->st_origin, g) < 0) {
- log(LOG_WARNING, errno,
- "reset_neighbor_state trying to delete (%s %s)",
- inet_fmt(st->st_origin, s1),
- inet_fmt(g->gt_mcastgrp, s2));
- }
- kroutes--;
- prev_st = st;
- st = prev_st->st_next;
- free(prev_st);
- }
- g->gt_srctbl = NULL;
- /*
- * Keep the group entries themselves around since the
- * state will likely just come right back, and if not,
- * the group entries will time out with no kernel entries
- * and no prune state.
- */
g->gt_prsent_timer = 0;
g->gt_grftsnt = 0;
+ while (st = g->gt_srctbl) {
+ g->gt_srctbl = st->st_next;
+ k_del_rg(st->st_origin, g);
+ kroutes--;
+ free(st);
+ }
}
} else {
/*
@@ -848,13 +830,13 @@ reset_neighbor_state(vifi, addr)
/*
* Remove any prunes that this router has sent us.
*/
- prev_pt = (struct ptable *)&g->gt_pruntbl;
- for (pt = g->gt_pruntbl; pt; pt = pt->pt_next) {
+ ptnp = &g->gt_pruntbl;
+ while ((pt = *ptnp) != NULL) {
if (pt->pt_vifi == vifi && pt->pt_router == addr) {
- prev_pt->pt_next = pt->pt_next;
+ *ptnp = pt->pt_next;
free(pt);
} else
- prev_pt = pt;
+ ptnp = &pt->pt_next;
}
/*
@@ -924,9 +906,9 @@ del_table_entry(r, mcastgrp, del_flag)
pt = g->gt_pruntbl;
while (pt) {
- prev_pt = pt->pt_next;
- free(pt);
- pt = prev_pt;
+ prev_pt = pt;
+ pt = pt->pt_next;
+ free(prev_pt);
}
g->gt_pruntbl = NULL;
@@ -937,14 +919,14 @@ del_table_entry(r, mcastgrp, del_flag)
else
kernel_table = g->gt_gnext;
- prev_g = g->gt_next;
#ifdef RSRR
/* Send route change notification to reservation protocol. */
rsrr_cache_send(g,0);
rsrr_cache_clean(g);
#endif /* RSRR */
- free(g);
- g = prev_g;
+ prev_g = g;
+ g = g->gt_next;
+ free(prev_g);
}
r->rt_groups = NULL;
}
@@ -968,17 +950,17 @@ del_table_entry(r, mcastgrp, del_flag)
inet_fmt(g->gt_mcastgrp, s2));
}
kroutes--;
- prev_st = st->st_next;
- free(st);
- st = prev_st;
+ prev_st = st;
+ st = st->st_next;
+ free(prev_st);
}
g->gt_srctbl = NULL;
pt = g->gt_pruntbl;
while (pt) {
- prev_pt = pt->pt_next;
- free(pt);
- pt = prev_pt;
+ prev_pt = pt;
+ pt = pt->pt_next;
+ free(prev_pt);
}
g->gt_pruntbl = NULL;
@@ -1018,7 +1000,7 @@ update_table_entry(r)
{
struct gtable *g;
struct ptable *pt, *prev_pt;
- int i;
+ vifi_t i;
for (g = r->rt_groups; g; g = g->gt_next) {
pt = g->gt_pruntbl;
@@ -1282,7 +1264,7 @@ accept_prune(src, dst, p, datalen)
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
@@ -1580,21 +1562,21 @@ free_all_prunes()
while (g) {
s = g->gt_srctbl;
while (s) {
- prev_s = s->st_next;
- free(s);
- s = prev_s;
+ prev_s = s;
+ s = s->st_next;
+ free(prev_s);
}
p = g->gt_pruntbl;
while (p) {
- prev_p = p->pt_next;
- free(p);
- p = prev_p;
+ prev_p = p;
+ p = p->pt_next;
+ free(prev_p);
}
- prev_g = g->gt_next;
- free(g);
- g = prev_g;
+ prev_g = g;
+ g = g->gt_next;
+ free(prev_g);
}
r->rt_groups = NULL;
}
@@ -1605,9 +1587,9 @@ free_all_prunes()
if (g->gt_srctbl)
free(g->gt_srctbl);
- prev_g = g->gt_next;
- free(g);
- g = prev_g;
+ prev_g = g;
+ g = g->gt_next;
+ free(prev_g);
}
kernel_no_route = NULL;
}
@@ -1742,34 +1724,8 @@ age_table_entry()
inet_fmt(gt->gt_mcastgrp, s2),
inet_fmt(pt->pt_router, s3),
pt->pt_vifi);
-
- /*
- * No need to send a graft, any prunes that we sent
- * will expire before any prunes that we have received.
- */
- 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;
- }
- /* modify the kernel entry to forward packets */
- if (!VIFM_ISSET(pt->pt_vifi, gt->gt_grpmems)) {
- VIFM_SET(pt->pt_vifi, gt->gt_grpmems);
- log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
- inet_fmts(r->rt_origin, r->rt_originmask, s1),
- inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems,
- pt->pt_vifi);
-
- prun_add_ttls(gt);
- update_kernel(gt);
-#ifdef RSRR
- /* Send route change notification to reservation
- * protocol.
- */
- rsrr_cache_send(gt,1);
-#endif /* RSRR */
- }
+ expire_prune(pt->pt_vifi, gt);
/* remove the router's prune entry and await new one */
*ptnp = pt->pt_next;
@@ -1780,94 +1736,65 @@ age_table_entry()
}
/*
- * If the cache entry has expired, check for downstream prunes.
- *
- * If there are downstream prunes, refresh the cache entry's timer.
- * Otherwise, check for traffic. If no traffic, delete this
- * entry.
+ * If the cache entry has expired, delete source table entries for
+ * silent sources. If there are no source entries left, and there
+ * are no downstream prunes, then the entry is deleted.
+ * Otherwise, the cache entry's timer is refreshed.
*/
if (gt->gt_timer <= 0) {
- if (gt->gt_pruntbl) {
- if (gt->gt_prsent_timer == -1)
- gt->gt_prsent_timer = 0;
- gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
- gtnptr = &gt->gt_gnext;
- continue;
- }
-
- /*
- * If this entry was pruned, but all downstream prunes
- * have expired, then it is safe to simply delete it.
- * Otherwise, check for traffic before deleting.
- */
- if (gt->gt_prsent_timer == 0) {
- sg_req.grp.s_addr = gt->gt_mcastgrp;
- stnp = &gt->gt_srctbl;
- while ((st = *stnp) != NULL) {
- 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;
- log(LOG_DEBUG, 0,
- "age_table_entry deleting (%s %s)",
+ /* Check for traffic before deleting source entries */
+ sg_req.grp.s_addr = gt->gt_mcastgrp;
+ stnp = &gt->gt_srctbl;
+ while ((st = *stnp) != NULL) {
+ 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;
+ log(LOG_DEBUG, 0, "age_table_entry deleting (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ 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));
- 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 {
- stnp = &st->st_next;
}
+ kroutes--;
+ free(st);
+ } else {
+ st->st_pktcnt = sg_req.pktcnt;
+ stnp = &st->st_next;
}
+ }
- if (gt->gt_srctbl) {
- /* At least one source in the list still has traffic */
- gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
- gtnptr = &gt->gt_gnext;
- continue;
- }
+ /*
+ * 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 is running.
+ */
+ if (gt->gt_pruntbl != NULL || gt->gt_srctbl != NULL ||
+ gt->gt_prsent_timer > 0) {
+ gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ 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;
}
log(LOG_DEBUG, 0, "timeout cache entry (%s, %s)",
inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(gt->gt_mcastgrp, s2));
- /* free all the source entries */
- while ((st = gt->gt_srctbl) != NULL) {
- log(LOG_DEBUG, 0,
- "age_table_entry (P) deleting (%s %s)",
- inet_fmt(st->st_origin, s1),
- inet_fmt(gt->gt_mcastgrp, s2));
- if (k_del_rg(st->st_origin, gt) < 0) {
- log(LOG_WARNING, errno,
- "age_table_entry (P) trying to delete (%s %s)",
- inet_fmt(st->st_origin, s1),
- inet_fmt(gt->gt_mcastgrp, s2));
- }
- kroutes--;
- gt->gt_srctbl = st->st_next;
- free(st);
- }
-
- /* free all the prune list entries */
- while ((pt = gt->gt_pruntbl) != NULL) {
- gt->gt_pruntbl = pt->pt_next;
- free(pt);
- }
-
if (gt->gt_prev)
gt->gt_prev->gt_next = gt->gt_next;
else
@@ -1893,7 +1820,10 @@ age_table_entry()
free((char *)gt);
} else {
if (gt->gt_prsent_timer == -1)
- gt->gt_prsent_timer = 0;
+ if (gt->gt_grpmems == 0)
+ send_prune(gt);
+ else
+ gt->gt_prsent_timer = 0;
gtnptr = &gt->gt_gnext;
}
}
@@ -1928,6 +1858,44 @@ age_table_entry()
}
}
+/*
+ * Modify the kernel to forward packets when one or multiple prunes that
+ * were received on the vif given by vifi, for the group given by gt,
+ * have expired.
+ */
+static void
+expire_prune(vifi, gt)
+ vifi_t vifi;
+ struct gtable *gt;
+{
+ /*
+ * No need to send a graft, any prunes that we sent
+ * will expire before any prunes that we have received.
+ */
+ 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;
+ }
+
+ /* 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);
+ log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems, vifi);
+
+ prun_add_ttls(gt);
+ update_kernel(gt);
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(gt,1);
+#endif /* RSRR */
+ }
+}
+
+
static char *
scaletime(t)
u_long t;
@@ -1978,7 +1946,7 @@ dump_cache(fp2)
register struct gtable *gt;
register struct stable *st;
register struct ptable *pt;
- register int i;
+ register vifi_t i;
register time_t thyme = time(0);
fprintf(fp2,
@@ -2091,21 +2059,6 @@ accept_mtrace(src, dst, group, data, no, datalen)
qry = (struct tr_query *)data;
- if (oqid == qry->tr_qid) {
- /*
- * If the multicast router is a member of the group being
- * queried, and the query is multicasted, then the router can
- * recieve multiple copies of the same query. If we have already
- * replied to this traceroute, just ignore it this time.
- *
- * This is not a total solution, but since if this fails you
- * only get N copies, N <= the number of interfaces on the router,
- * it is not fatal.
- */
- log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
- return;
- }
-
/*
* if it is a packet with all reports filled, drop it
*/
@@ -2136,6 +2089,21 @@ accept_mtrace(src, dst, group, data, no, datalen)
* and if so, whether I should start response back
*/
if (type == QUERY) {
+ if (oqid == qry->tr_qid) {
+ /*
+ * If the multicast router is a member of the group being
+ * queried, and the query is multicasted, then the router can
+ * recieve multiple copies of the same query. If we have already
+ * replied to this traceroute, just ignore it this time.
+ *
+ * This is not a total solution, but since if this fails you
+ * only get N copies, N <= the number of interfaces on the router,
+ * it is not fatal.
+ */
+ log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
+ return;
+ }
+
if (rt == NULL) {
log(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s",
inet_fmt(qry->tr_src, s1));
OpenPOWER on IntegriCloud