1 diff -ur v2.5.50/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
2 --- v2.5.50/linux/include/linux/rtnetlink.h Thu Oct 31 04:03:27 2002
3 +++ linux/include/linux/rtnetlink.h Sun Dec 1 17:04:46 2002
5 #define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
6 #define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
7 #define RTNH_F_ONLINK 4 /* Gateway is forced on link */
8 +#define RTNH_F_SUSPECT 8 /* We don't know the real state */
9 +#define RTNH_F_BADSTATE (RTNH_F_DEAD | RTNH_F_SUSPECT)
11 /* Macros to handle hexthops */
13 diff -ur v2.5.50/linux/include/net/ip_fib.h linux/include/net/ip_fib.h
14 --- v2.5.50/linux/include/net/ip_fib.h Tue Nov 19 00:13:38 2002
15 +++ linux/include/net/ip_fib.h Sun Dec 1 17:04:46 2002
18 static inline void fib_select_default(const struct flowi *flp, struct fib_result *res)
20 - if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
21 + if ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
22 + FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)
23 ip_fib_main_table->tb_select_default(ip_fib_main_table, flp, res);
27 extern int fib_lookup(const struct flowi *flp, struct fib_result *res);
28 extern struct fib_table *__fib_new_table(int id);
29 extern void fib_rule_put(struct fib_rule *r);
30 +extern __inline__ int fib_result_table(struct fib_result *res);
32 static inline struct fib_table *fib_get_table(int id)
34 diff -ur v2.5.50/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
35 --- v2.5.50/linux/net/ipv4/fib_frontend.c Thu Oct 17 03:43:21 2002
36 +++ linux/net/ipv4/fib_frontend.c Sun Dec 1 17:04:46 2002
38 struct fib_table *ip_fib_local_table;
39 struct fib_table *ip_fib_main_table;
41 +#define FIB_RES_TABLE(r) (RT_TABLE_MAIN)
45 #define RT_TABLE_MIN 1
50 +#define FIB_RES_TABLE(r) (fib_result_table(r))
52 #endif /* CONFIG_IP_MULTIPLE_TABLES */
57 struct fib_result res;
59 + unsigned char prefixlen;
60 + unsigned char scope;
66 *spec_dst = FIB_RES_PREFSRC(res);
67 fib_combine_itag(itag, &res);
68 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
69 - if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
71 if (FIB_RES_DEV(res) == dev)
74 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
78 + table = FIB_RES_TABLE(&res);
79 + prefixlen = res.prefixlen;
86 fl.oif = dev->ifindex;
89 if (fib_lookup(&fl, &res) == 0) {
90 - if (res.type == RTN_UNICAST) {
91 + if (res.type == RTN_UNICAST &&
92 + ((table == FIB_RES_TABLE(&res) &&
93 + res.prefixlen >= prefixlen && res.scope >= scope) ||
95 *spec_dst = FIB_RES_PREFSRC(res);
96 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
107 diff -ur v2.5.50/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
108 --- v2.5.50/linux/net/ipv4/fib_hash.c Tue Nov 19 00:13:40 2002
109 +++ linux/net/ipv4/fib_hash.c Sun Dec 1 17:04:46 2002
111 struct fib_info *fn_info;
112 #define FIB_INFO(f) ((f)->fn_info)
118 @@ -312,72 +313,120 @@
122 -static int fn_hash_last_dflt=-1;
124 -static int fib_detect_death(struct fib_info *fi, int order,
125 - struct fib_info **last_resort, int *last_idx)
126 +static int fib_detect_death(struct fib_info *fi, int order, int last_dflt,
127 + struct fib_info **last_resort, int *last_idx,
128 + int *last_nhsel, const struct flowi *flp)
131 - int state = NUD_NONE;
134 + struct fib_nh * nh;
136 + int flag, dead = 1;
138 + /* change_nexthops(fi) { */
139 + for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) {
140 + if (flp->oif && flp->oif != nh->nh_oif)
142 + if (nh->nh_flags & RTNH_F_DEAD)
146 + if (nh->nh_dev->flags & IFF_NOARP) {
152 + if (!nh->nh_gw || nh->nh_scope != RT_SCOPE_LINK)
153 + dst = flp->fl4_dst;
156 + n = neigh_lookup(&arp_tbl, &dst, nh->nh_dev);
158 + state = n->nud_state;
161 + if (state==NUD_REACHABLE ||
162 + ((state&NUD_VALID) && order != last_dflt)) {
166 + if (!(state&NUD_VALID))
170 + if ((state&NUD_VALID) ||
171 + (*last_idx<0 && order >= last_dflt)) {
174 + *last_nhsel = nhsel;
177 - n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev);
179 - state = n->nud_state;
182 - if (state==NUD_REACHABLE)
184 - if ((state&NUD_VALID) && order != fn_hash_last_dflt)
186 - if ((state&NUD_VALID) ||
187 - (*last_idx<0 && order > fn_hash_last_dflt)) {
192 + read_lock_bh(&fib_nhflags_lock);
194 + nh->nh_flags |= RTNH_F_SUSPECT;
196 + nh->nh_flags &= ~RTNH_F_SUSPECT;
197 + read_unlock_bh(&fib_nhflags_lock);
200 + /* } endfor_nexthops(fi) */
206 fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
208 - int order, last_idx;
209 - struct fib_node *f;
210 + int order, last_idx, last_dflt, last_nhsel;
211 + struct fib_node *f, *first_node;
212 struct fib_info *fi = NULL;
213 struct fib_info *last_resort;
214 struct fn_hash *t = (struct fn_hash*)tb->tb_data;
215 - struct fn_zone *fz = t->fn_zones[0];
216 + struct fn_zone *fz = t->fn_zones[res->prefixlen];
222 + k = fz_key(flp->fl4_dst, fz);
230 read_lock(&fib_hash_lock);
231 - for (f = fz->fz_hash[0]; f; f = f->fn_next) {
232 + for (f = fz_chain(k, fz); f; f = f->fn_next) {
233 struct fib_info *next_fi = FIB_INFO(f);
235 - if ((f->fn_state&FN_S_ZOMBIE) ||
236 + if (!fn_key_eq(k, f->fn_key) ||
237 + (f->fn_state&FN_S_ZOMBIE) ||
238 f->fn_scope != res->scope ||
239 +#ifdef CONFIG_IP_ROUTE_TOS
240 + (f->fn_tos && f->fn_tos != flp->fl4_tos) ||
242 f->fn_type != RTN_UNICAST)
245 if (next_fi->fib_priority > res->fi->fib_priority)
247 - if (!next_fi->fib_nh[0].nh_gw || next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
249 f->fn_state |= FN_S_ACCESSED;
252 - if (next_fi != res->fi)
254 - } else if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
256 + last_dflt = f->fn_last_dflt;
259 + if (fi && !fib_detect_death(fi, order, last_dflt,
260 + &last_resort, &last_idx, &last_nhsel, flp)) {
262 fib_info_put(res->fi);
264 atomic_inc(&fi->fib_clntref);
265 - fn_hash_last_dflt = order;
266 + first_node->fn_last_dflt = order;
270 @@ -385,16 +434,25 @@
273 if (order<=0 || fi==NULL) {
274 - fn_hash_last_dflt = -1;
275 + if (fi && fi->fib_nhs > 1 &&
276 + fib_detect_death(fi, order, last_dflt,
277 + &last_resort, &last_idx, &last_nhsel, flp) &&
278 + last_resort == fi) {
279 + read_lock_bh(&fib_nhflags_lock);
280 + fi->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
281 + read_unlock_bh(&fib_nhflags_lock);
283 + if (first_node) first_node->fn_last_dflt = -1;
287 - if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
288 + if (!fib_detect_death(fi, order, last_dflt, &last_resort, &last_idx,
289 + &last_nhsel, flp)) {
291 fib_info_put(res->fi);
293 atomic_inc(&fi->fib_clntref);
294 - fn_hash_last_dflt = order;
295 + first_node->fn_last_dflt = order;
300 res->fi = last_resort;
302 atomic_inc(&last_resort->fib_clntref);
303 + read_lock_bh(&fib_nhflags_lock);
304 + last_resort->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
305 + read_unlock_bh(&fib_nhflags_lock);
306 + first_node->fn_last_dflt = last_idx;
308 - fn_hash_last_dflt = last_idx;
310 read_unlock(&fib_hash_lock);
314 memset(new_f, 0, sizeof(struct fib_node));
316 + new_f->fn_last_dflt = -1;
318 #ifdef CONFIG_IP_ROUTE_TOS
320 diff -ur v2.5.50/linux/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c
321 --- v2.5.50/linux/net/ipv4/fib_rules.c Thu Oct 17 03:43:21 2002
322 +++ linux/net/ipv4/fib_rules.c Sun Dec 1 17:04:46 2002
327 +int fib_result_table(struct fib_result *res)
329 + return res->r->r_table;
332 int fib_lookup(const struct flowi *flp, struct fib_result *res)
337 void fib_select_default(const struct flowi *flp, struct fib_result *res)
339 - if (res->r && res->r->r_action == RTN_UNICAST &&
340 - FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
342 + (res->r->r_action == RTN_UNICAST || res->r->r_action == RTN_NAT) &&
343 + ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
344 + FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)) {
345 struct fib_table *tb;
346 if ((tb = fib_get_table(res->r->r_table)) != NULL)
347 tb->tb_select_default(tb, flp, res);
348 diff -ur v2.5.50/linux/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c
349 --- v2.5.50/linux/net/ipv4/fib_semantics.c Thu Oct 31 04:03:33 2002
350 +++ linux/net/ipv4/fib_semantics.c Sun Dec 1 17:45:35 2002
352 #ifdef CONFIG_NET_CLS_ROUTE
353 nh->nh_tclassid != onh->nh_tclassid ||
355 - ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
356 + ((nh->nh_flags^onh->nh_flags)&~RTNH_F_BADSTATE))
359 } endfor_nexthops(fi);
361 nfi->fib_prefsrc == fi->fib_prefsrc &&
362 nfi->fib_priority == fi->fib_priority &&
363 memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 &&
364 - ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
365 + ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_BADSTATE) == 0 &&
366 (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
369 @@ -953,24 +953,42 @@
370 void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
372 struct fib_info *fi = res->fi;
376 spin_lock_bh(&fib_multipath_lock);
380 + change_nexthops(fi) {
381 + if (flp->oif != nh->nh_oif)
383 + if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
384 + if (nh->nh_power > w) {
389 + } endfor_nexthops(fi);
391 + spin_unlock_bh(&fib_multipath_lock);
399 if (fi->fib_power <= 0) {
401 change_nexthops(fi) {
402 - if (!(nh->nh_flags&RTNH_F_DEAD)) {
403 + if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
404 power += nh->nh_weight;
405 nh->nh_power = nh->nh_weight;
407 } endfor_nexthops(fi);
408 fi->fib_power = power;
410 - spin_unlock_bh(&fib_multipath_lock);
411 - /* Race condition: route has just become dead. */
420 @@ -980,20 +998,37 @@
422 w = jiffies % fi->fib_power;
425 change_nexthops(fi) {
426 - if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
427 + if (!(nh->nh_flags&RTNH_F_BADSTATE) && nh->nh_power) {
428 if ((w -= nh->nh_power) <= 0) {
431 + spin_unlock_bh(&fib_multipath_lock);
437 + } endfor_nexthops(fi);
446 + if (!(nh->nh_flags&RTNH_F_DEAD)) {
447 + if (!flp->oif || flp->oif == nh->nh_oif) {
448 spin_unlock_bh(&fib_multipath_lock);
449 + res->nh_sel = nhsel;
453 } endfor_nexthops(fi);
455 /* Race condition: route has just become dead. */
457 spin_unlock_bh(&fib_multipath_lock);
460 diff -ur v2.5.50/linux/net/ipv4/route.c linux/net/ipv4/route.c
461 --- v2.5.50/linux/net/ipv4/route.c Mon Nov 11 23:43:59 2002
462 +++ linux/net/ipv4/route.c Sun Dec 1 17:04:46 2002
463 @@ -1433,8 +1433,9 @@
464 if (res.type != RTN_UNICAST)
465 goto martian_destination;
467 + fib_select_default(&fl, &res);
468 #ifdef CONFIG_IP_ROUTE_MULTIPATH
469 - if (res.fi->fib_nhs > 1 && fl.oif == 0)
470 + if (res.fi->fib_nhs > 1)
471 fib_select_multipath(&fl, &res);
473 out_dev = in_dev_get(FIB_RES_DEV(res));
474 @@ -1823,7 +1824,7 @@
476 if (fib_lookup(&fl, &res)) {
479 + if (oldflp->oif && dev_out->flags&IFF_UP) {
480 /* Apparently, routing tables are wrong. Assume,
481 that the destination is on link.
483 @@ -1873,13 +1874,12 @@
487 + if (res.type == RTN_UNICAST)
488 + fib_select_default(&fl, &res);
489 #ifdef CONFIG_IP_ROUTE_MULTIPATH
490 - if (res.fi->fib_nhs > 1 && fl.oif == 0)
491 + if (res.fi->fib_nhs > 1)
492 fib_select_multipath(&fl, &res);
495 - if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif)
496 - fib_select_default(&fl, &res);
499 fl.fl4_src = FIB_RES_PREFSRC(res);