patch-2.4.19 linux-2.4.19/net/ipv4/fib_semantics.c
Next file: linux-2.4.19/net/ipv4/icmp.c
Previous file: linux-2.4.19/net/ipv4/fib_frontend.c
Back to the patch index
Back to the overall index
- Lines: 120
- Date:
Fri Aug 2 17:39:46 2002
- Orig file:
linux-2.4.18/net/ipv4/fib_semantics.c
- Orig date:
Mon Feb 25 11:38:14 2002
diff -urN linux-2.4.18/net/ipv4/fib_semantics.c linux-2.4.19/net/ipv4/fib_semantics.c
@@ -56,6 +56,8 @@
#ifdef CONFIG_IP_ROUTE_MULTIPATH
+static spinlock_t fib_multipath_lock = SPIN_LOCK_UNLOCKED;
+
#define for_nexthops(fi) { int nhsel; const struct fib_nh * nh; \
for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
@@ -183,6 +185,7 @@
continue;
for_nexthops(fi) {
if (nh->nh_dev == dev && nh->nh_gw == gw &&
+ nh->nh_scope == RT_SCOPE_LINK &&
!(nh->nh_flags&RTNH_F_DEAD)) {
read_unlock(&fib_info_lock);
return 0;
@@ -377,15 +380,23 @@
/* It is not necessary, but requires a bit of thinking */
if (key.scope < RT_SCOPE_LINK)
key.scope = RT_SCOPE_LINK;
-
if ((err = fib_lookup(&key, &res)) != 0)
return err;
+ err = -EINVAL;
+ if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
+ goto out;
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);
+ if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
+ goto out;
+ atomic_inc(&nh->nh_dev->refcnt);
+ err = -ENETDOWN;
+ if (!(nh->nh_dev->flags & IFF_UP))
+ goto out;
+ err = 0;
+out:
fib_res_put(&res);
+ return err;
} else {
struct in_device *in_dev;
@@ -869,11 +880,19 @@
nh->nh_scope != scope) {
nh->nh_flags |= RTNH_F_DEAD;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ spin_lock_bh(&fib_multipath_lock);
fi->fib_power -= nh->nh_power;
nh->nh_power = 0;
+ spin_unlock_bh(&fib_multipath_lock);
#endif
dead++;
}
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (force > 1 && nh->nh_dev == dev) {
+ dead = fi->fib_nhs;
+ break;
+ }
+#endif
} endfor_nexthops(fi)
if (dead == fi->fib_nhs) {
fi->fib_flags |= RTNH_F_DEAD;
@@ -911,8 +930,10 @@
if (nh->nh_dev != dev || __in_dev_get(dev) == NULL)
continue;
alive++;
+ spin_lock_bh(&fib_multipath_lock);
nh->nh_power = 0;
nh->nh_flags &= ~RTNH_F_DEAD;
+ spin_unlock_bh(&fib_multipath_lock);
} endfor_nexthops(fi)
if (alive > 0) {
@@ -933,6 +954,7 @@
struct fib_info *fi = res->fi;
int w;
+ spin_lock_bh(&fib_multipath_lock);
if (fi->fib_power <= 0) {
int power = 0;
change_nexthops(fi) {
@@ -942,12 +964,12 @@
}
} endfor_nexthops(fi);
fi->fib_power = power;
-#if 1
if (power <= 0) {
- printk(KERN_CRIT "impossible 777\n");
+ spin_unlock_bh(&fib_multipath_lock);
+ /* Race condition: route has just become dead. */
+ res->nh_sel = 0;
return;
}
-#endif
}
@@ -963,15 +985,15 @@
nh->nh_power--;
fi->fib_power--;
res->nh_sel = nhsel;
+ spin_unlock_bh(&fib_multipath_lock);
return;
}
}
} endfor_nexthops(fi);
-#if 1
- printk(KERN_CRIT "impossible 888\n");
-#endif
- return;
+ /* Race condition: route has just become dead. */
+ res->nh_sel = 0;
+ spin_unlock_bh(&fib_multipath_lock);
}
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)