diff options
author | peter <peter@FreeBSD.org> | 1996-01-06 21:10:30 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1996-01-06 21:10:30 +0000 |
commit | d4c03f31b99ac4bd269582b4d2fee704364a2c1e (patch) | |
tree | f1d0a40a2a6e33e9f309cdfe59bfbb0d9a7d4628 /usr.sbin/mrouted/prune.c | |
parent | a8e9d6a2eaa9df5881201d40c5c05c6154333fef (diff) | |
download | FreeBSD-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.c | 354 |
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_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_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_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_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_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_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)); |