As commented in defined in sys/net/route.c, rt_fixchange() has a bad

effect, which would cause unnecessary route deletion:

 * Unfortunately, this has the obnoxious
 * property of also triggering for insertion /above/ a pre-existing network
 * route and clones.  Sigh.  This may be fixed some day.

The effect has been even worse, because recent versions of route.c set
the parent rtentry for cloned routes from an interface-direct route.
For example, suppose that we have an interface "ne0" that has an IPv4
subnet "10.0.0.0/24".  Then we may have a cloned route like 10.0.0.1
on the interface, whose parent route is 10.0.0.0/24 (to the interface
ne0).  Now, when we add the default route (i.e. 0.0.0.0/0),
rt_fixchange() will remove the cloned route 10.0.0.1.  The (bad) effect
also prevents rt_setgate from configuring rt_gwroute, which would not
be an intended behavior.

As suggested in the comments to rt_fixchange(), we need stricter check
in the function, to prevent unintentional route deletion.

This fix also solve the "IPV6 panic?" problem in nd6_timer().

Submitted by:	JINMEI Tatuya <jinmei@isl.rdc.toshiba.co.jp>
MFC after:	4 days
This commit is contained in:
Hajimu UMEMOTO 2001-07-25 19:31:43 +00:00
parent 81dd89bf46
commit 9a70151652

View File

@ -726,9 +726,7 @@ rt_fixdelete(rn, vp)
* network route and (cloned) host routes. For this reason, a simple check
* of rt->rt_parent is insufficient; each candidate route must be tested
* against the (mask, value) of the new route (passed as before in vp)
* to see if the new route matches it. Unfortunately, this has the obnoxious
* property of also triggering for insertion /above/ a pre-existing network
* route and clones. Sigh. This may be fixed some day.
* to see if the new route matches it.
*
* XXX - it may be possible to do fixdelete() for changes and reserve this
* routine just for adds. I'm not sure why I thought it was necessary to do
@ -747,8 +745,8 @@ rt_fixchange(rn, vp)
struct rtfc_arg *ap = vp;
struct rtentry *rt0 = ap->rt0;
struct radix_node_head *rnh = ap->rnh;
u_char *xk1, *xm1, *xk2;
int i, len;
u_char *xk1, *xm1, *xk2, *xmp;
int i, len, mlen;
#ifdef DEBUG
if (rtfcdebug)
@ -782,6 +780,28 @@ rt_fixchange(rn, vp)
xm1 = (u_char *)rt_mask(rt0);
xk2 = (u_char *)rt_key(rt);
/* avoid applying a less specific route */
xmp = (u_char *)rt_mask(rt->rt_parent);
mlen = ((struct sockaddr *)rt_key(rt->rt_parent))->sa_len;
if (mlen > ((struct sockaddr *)rt_key(rt0))->sa_len) {
#ifdef DEBUG
if (rtfcdebug)
printf("rt_fixchange: inserting a less "
"specific route\n");
#endif
return 0;
}
for (i = rnh->rnh_treetop->rn_offset; i < mlen; i++) {
if ((xmp[i] & ~(xmp[i] ^ xm1[i])) != xmp[i]) {
#ifdef DEBUG
if (rtfcdebug)
printf("rt_fixchange: inserting a less "
"specific route\n");
#endif
return 0;
}
}
for (i = rnh->rnh_treetop->rn_offset; i < len; i++) {
if ((xk2[i] & xm1[i]) != xk1[i]) {
#ifdef DEBUG