--- v2.4.16/linux/net/ipv4/fib_semantics.c Tue Oct 17 20:43:14 2000 +++ linux/net/ipv4/fib_semantics.c Thu Dec 13 23:26:28 2001 @@ -378,11 +378,25 @@ if (key.scope < RT_SCOPE_LINK) key.scope = RT_SCOPE_LINK; - if ((err = fib_lookup(&key, &res)) != 0) - return err; - nh->nh_scope = res.scope; - nh->nh_oif = FIB_RES_OIF(res); - nh->nh_dev = FIB_RES_DEV(res); + err = fib_lookup(&key, &res); + if (err) { + if (err == -ENETUNREACH && + fi->fib_protocol == RTPROT_STATIC) { + struct net_device *dev; + + dev = __dev_get_by_index(nh->nh_oif); + if (dev == NULL || dev->flags & IFF_UP || + inet_addr_type(nh->nh_gw) == RTN_LOCAL) + return err; + nh->nh_flags |= RTNH_F_DEAD; + nh->nh_scope = RT_SCOPE_LINK; + nh->nh_dev = dev; + } else return err; + } else { + nh->nh_scope = res.scope; + nh->nh_oif = FIB_RES_OIF(res); + nh->nh_dev = FIB_RES_DEV(res); + } if (nh->nh_dev) atomic_inc(&nh->nh_dev->refcnt); fib_res_put(&res); @@ -396,8 +410,11 @@ if (in_dev == NULL) return -ENODEV; if (!(in_dev->dev->flags&IFF_UP)) { - in_dev_put(in_dev); - return -ENETDOWN; + if (fi->fib_protocol != RTPROT_STATIC) { + in_dev_put(in_dev); + return -ENETDOWN; + } + nh->nh_flags |= RTNH_F_DEAD; } nh->nh_dev = in_dev->dev; atomic_inc(&nh->nh_dev->refcnt); @@ -581,6 +598,10 @@ #ifdef CONFIG_IP_ROUTE_NAT case RTN_NAT: FIB_RES_RESET(*res); + if (FIB_RES_NH(*res).nh_flags & RTNH_F_DEAD) { + res->fi = NULL; + return 1; + } atomic_inc(&fi->fib_clntref); return 0; #endif @@ -867,16 +888,28 @@ int dead = 0; change_nexthops(fi) { - if (nh->nh_flags&RTNH_F_DEAD) - dead++; - else if (nh->nh_dev == dev && + if (nh->nh_flags&RTNH_F_DEAD) { + if (fi->fib_protocol!=RTPROT_STATIC || + nh->nh_dev == NULL || + !__in_dev_get(nh->nh_dev) || + nh->nh_dev->flags&IFF_UP) + dead++; + } else if (nh->nh_dev == dev && nh->nh_scope != scope) { nh->nh_flags |= RTNH_F_DEAD; #ifdef CONFIG_IP_ROUTE_MULTIPATH fi->fib_power -= nh->nh_power; nh->nh_power = 0; #endif - dead++; + if (fi->fib_protocol!=RTPROT_STATIC || + force || + __in_dev_get(dev) == NULL) + dead++; + } + if (nh->nh_flags&RTNH_F_DEAD && force && + nh->nh_dev == dev) { + dev_put(nh->nh_dev); + nh->nh_dev = NULL; } } endfor_nexthops(fi) if (dead == fi->fib_nhs) { @@ -888,34 +921,50 @@ return ret; } -#ifdef CONFIG_IP_ROUTE_MULTIPATH - /* Dead device goes up. We wake up dead nexthops. - It takes sense only on multipath routes. */ int fib_sync_up(struct net_device *dev) { - int ret = 0; + struct rt_key key; + struct fib_result res; + int ret, rep; +repeat: if (!(dev->flags&IFF_UP)) return 0; + ret = 0; + rep = 0; for_fib_info() { int alive = 0; change_nexthops(fi) { - if (!(nh->nh_flags&RTNH_F_DEAD)) { - alive++; + if (!(nh->nh_flags&RTNH_F_DEAD)) continue; - } if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP)) continue; if (nh->nh_dev != dev || __in_dev_get(dev) == NULL) continue; + if (nh->nh_gw && fi->fib_protocol == RTPROT_STATIC) { + memset(&key, 0, sizeof(key)); + key.dst = nh->nh_gw; + key.oif = nh->nh_oif; + key.scope = nh->nh_scope; + if (fib_lookup(&key, &res) != 0) + continue; + if (res.type != RTN_UNICAST) { + fib_res_put(&res); + continue; + } + fib_res_put(&res); + rep = 1; + } alive++; +#ifdef CONFIG_IP_ROUTE_MULTIPATH nh->nh_power = 0; +#endif nh->nh_flags &= ~RTNH_F_DEAD; } endfor_nexthops(fi) @@ -924,8 +973,12 @@ ret++; } } endfor_fib_info(); + if (rep) + goto repeat; return ret; } + +#ifdef CONFIG_IP_ROUTE_MULTIPATH /* The algorithm is suboptimal, but it provides really --- v2.4.16/linux/net/ipv4/fib_frontend.c Tue Nov 13 01:26:34 2001 +++ linux/net/ipv4/fib_frontend.c Thu Dec 13 23:16:57 2001 @@ -583,6 +583,8 @@ switch (event) { case NETDEV_UP: fib_add_ifaddr(ifa); + if (ifa->ifa_dev && ifa->ifa_dev->dev) + fib_sync_up(ifa->ifa_dev->dev); rt_cache_flush(-1); break; case NETDEV_DOWN: @@ -613,9 +615,7 @@ for_ifa(in_dev) { fib_add_ifaddr(ifa); } endfor_ifa(in_dev); -#ifdef CONFIG_IP_ROUTE_MULTIPATH fib_sync_up(dev); -#endif rt_cache_flush(-1); break; case NETDEV_DOWN: