7b4e48f72093d8f6f953847475ce8666e6440b23
[openwrt.git] / target / linux / generic-2.4 / patches / 700-multiple_default_gateways.patch
1 Index: linux-2.4.35.4/include/linux/netfilter_ipv4/ip_nat.h
2 ===================================================================
3 --- linux-2.4.35.4.orig/include/linux/netfilter_ipv4/ip_nat.h 2007-12-15 05:19:36.574505299 +0100
4 +++ linux-2.4.35.4/include/linux/netfilter_ipv4/ip_nat.h 2007-12-15 05:20:13.092586349 +0100
5 @@ -121,5 +121,13 @@
6 extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
7 u_int32_t newval,
8 u_int16_t oldcheck);
9 +
10 +/* Call input routing for SNAT-ed traffic */
11 +extern unsigned int ip_nat_route_input(unsigned int hooknum,
12 + struct sk_buff **pskb,
13 + const struct net_device *in,
14 + const struct net_device *out,
15 + int (*okfn)(struct sk_buff *));
16 +
17 #endif /*__KERNEL__*/
18 #endif
19 Index: linux-2.4.35.4/include/linux/rtnetlink.h
20 ===================================================================
21 --- linux-2.4.35.4.orig/include/linux/rtnetlink.h 2007-12-15 05:19:36.582505757 +0100
22 +++ linux-2.4.35.4/include/linux/rtnetlink.h 2007-12-15 05:20:13.092586349 +0100
23 @@ -234,6 +234,8 @@
24 #define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
25 #define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
26 #define RTNH_F_ONLINK 4 /* Gateway is forced on link */
27 +#define RTNH_F_SUSPECT 8 /* We don't know the real state */
28 +#define RTNH_F_BADSTATE (RTNH_F_DEAD | RTNH_F_SUSPECT)
29
30 /* Macros to handle hexthops */
31
32 Index: linux-2.4.35.4/include/net/ip_fib.h
33 ===================================================================
34 --- linux-2.4.35.4.orig/include/net/ip_fib.h 2007-12-15 05:19:36.590506213 +0100
35 +++ linux-2.4.35.4/include/net/ip_fib.h 2007-12-15 05:20:13.100586801 +0100
36 @@ -162,7 +162,8 @@
37
38 static inline void fib_select_default(const struct rt_key *key, struct fib_result *res)
39 {
40 - if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
41 + if ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
42 + FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)
43 main_table->tb_select_default(main_table, key, res);
44 }
45
46 @@ -174,6 +175,7 @@
47 extern int fib_lookup(const struct rt_key *key, struct fib_result *res);
48 extern struct fib_table *__fib_new_table(int id);
49 extern void fib_rule_put(struct fib_rule *r);
50 +extern int fib_result_table(struct fib_result *res);
51
52 static inline struct fib_table *fib_get_table(int id)
53 {
54 @@ -275,5 +277,6 @@
55 #endif
56 }
57
58 +extern rwlock_t fib_nhflags_lock;
59
60 #endif /* _NET_FIB_H */
61 Index: linux-2.4.35.4/include/net/route.h
62 ===================================================================
63 --- linux-2.4.35.4.orig/include/net/route.h 2007-12-15 05:19:36.598506668 +0100
64 +++ linux-2.4.35.4/include/net/route.h 2007-12-15 05:20:13.104587030 +0100
65 @@ -49,6 +49,8 @@
66 {
67 __u32 dst;
68 __u32 src;
69 + __u32 lsrc;
70 + __u32 gw;
71 int iif;
72 int oif;
73 #ifdef CONFIG_IP_ROUTE_FWMARK
74 @@ -128,6 +130,7 @@
75 extern void rt_cache_flush(int how);
76 extern int ip_route_output_key(struct rtable **, const struct rt_key *key);
77 extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
78 +extern int ip_route_input_lookup(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin, u32 lsrc);
79 extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
80 extern void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu);
81 extern void ip_rt_send_redirect(struct sk_buff *skb);
82 @@ -148,6 +151,15 @@
83 }
84
85
86 +static inline int
87 +ip_route_output_lookup(struct rtable **rp,
88 + u32 daddr, u32 saddr, u32 tos, int oif, u32 gw)
89 +{
90 + struct rt_key key = { dst:daddr, src:saddr, gw:gw, oif:oif, tos:tos };
91 +
92 + return ip_route_output_key(rp, &key);
93 +}
94 +
95 static inline void ip_rt_put(struct rtable * rt)
96 {
97 if (rt)
98 Index: linux-2.4.35.4/net/ipv4/fib_frontend.c
99 ===================================================================
100 --- linux-2.4.35.4.orig/net/ipv4/fib_frontend.c 2007-12-15 05:19:36.606507123 +0100
101 +++ linux-2.4.35.4/net/ipv4/fib_frontend.c 2007-12-15 05:20:13.108587259 +0100
102 @@ -54,6 +54,8 @@
103 struct fib_table *local_table;
104 struct fib_table *main_table;
105
106 +#define FIB_RES_TABLE(r) (RT_TABLE_MAIN)
107 +
108 #else
109
110 #define RT_TABLE_MIN 1
111 @@ -71,6 +73,7 @@
112 return tb;
113 }
114
115 +#define FIB_RES_TABLE(r) (fib_result_table(r))
116
117 #endif /* CONFIG_IP_MULTIPLE_TABLES */
118
119 @@ -209,6 +212,9 @@
120 struct in_device *in_dev;
121 struct rt_key key;
122 struct fib_result res;
123 + int table;
124 + unsigned char prefixlen;
125 + unsigned char scope;
126 int no_addr, rpf;
127 int ret;
128
129 @@ -216,6 +222,7 @@
130 key.src = dst;
131 key.tos = tos;
132 key.oif = 0;
133 + key.gw = 0;
134 key.iif = oif;
135 key.scope = RT_SCOPE_UNIVERSE;
136
137 @@ -237,31 +244,35 @@
138 goto e_inval_res;
139 *spec_dst = FIB_RES_PREFSRC(res);
140 fib_combine_itag(itag, &res);
141 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
142 - if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
143 -#else
144 if (FIB_RES_DEV(res) == dev)
145 -#endif
146 {
147 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
148 fib_res_put(&res);
149 return ret;
150 }
151 + table = FIB_RES_TABLE(&res);
152 + prefixlen = res.prefixlen;
153 + scope = res.scope;
154 fib_res_put(&res);
155 if (no_addr)
156 goto last_resort;
157 - if (rpf)
158 - goto e_inval;
159 key.oif = dev->ifindex;
160
161 ret = 0;
162 if (fib_lookup(&key, &res) == 0) {
163 - if (res.type == RTN_UNICAST) {
164 + if (res.type == RTN_UNICAST &&
165 + ((table == FIB_RES_TABLE(&res) &&
166 + res.prefixlen >= prefixlen && res.scope >= scope) ||
167 + !rpf)) {
168 *spec_dst = FIB_RES_PREFSRC(res);
169 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
170 + fib_res_put(&res);
171 + return ret;
172 }
173 fib_res_put(&res);
174 }
175 + if (rpf)
176 + goto e_inval;
177 return ret;
178
179 last_resort:
180 @@ -579,9 +590,7 @@
181 switch (event) {
182 case NETDEV_UP:
183 fib_add_ifaddr(ifa);
184 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
185 fib_sync_up(ifa->ifa_dev->dev);
186 -#endif
187 rt_cache_flush(-1);
188 break;
189 case NETDEV_DOWN:
190 @@ -617,9 +626,7 @@
191 for_ifa(in_dev) {
192 fib_add_ifaddr(ifa);
193 } endfor_ifa(in_dev);
194 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
195 fib_sync_up(dev);
196 -#endif
197 rt_cache_flush(-1);
198 break;
199 case NETDEV_DOWN:
200 Index: linux-2.4.35.4/net/ipv4/fib_hash.c
201 ===================================================================
202 --- linux-2.4.35.4.orig/net/ipv4/fib_hash.c 2007-12-15 05:19:36.614507579 +0100
203 +++ linux-2.4.35.4/net/ipv4/fib_hash.c 2007-12-15 05:20:13.108587259 +0100
204 @@ -71,6 +71,7 @@
205 struct fib_info *fn_info;
206 #define FIB_INFO(f) ((f)->fn_info)
207 fn_key_t fn_key;
208 + int fn_last_dflt;
209 u8 fn_tos;
210 u8 fn_type;
211 u8 fn_scope;
212 @@ -336,72 +337,123 @@
213 return err;
214 }
215
216 -static int fn_hash_last_dflt=-1;
217 -
218 -static int fib_detect_death(struct fib_info *fi, int order,
219 - struct fib_info **last_resort, int *last_idx)
220 +static int fib_detect_death(struct fib_info *fi, int order, int last_dflt,
221 + struct fib_info **last_resort, int *last_idx,
222 + int *last_nhsel, const struct rt_key *key)
223 {
224 struct neighbour *n;
225 - int state = NUD_NONE;
226 + int nhsel;
227 + int state;
228 + struct fib_nh * nh;
229 + u32 dst;
230 + int flag, dead = 1;
231 +
232 + /* change_nexthops(fi) { */
233 + for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) {
234 + if (key->oif && key->oif != nh->nh_oif)
235 + continue;
236 + if (key->gw && key->gw != nh->nh_gw && nh->nh_gw &&
237 + nh->nh_scope == RT_SCOPE_LINK)
238 + continue;
239 + if (nh->nh_flags & RTNH_F_DEAD)
240 + continue;
241
242 - n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev);
243 - if (n) {
244 - state = n->nud_state;
245 - neigh_release(n);
246 + flag = 0;
247 + if (nh->nh_dev->flags & IFF_NOARP) {
248 + dead = 0;
249 + goto setfl;
250 + }
251 +
252 + dst = nh->nh_gw;
253 + if (!nh->nh_gw || nh->nh_scope != RT_SCOPE_LINK)
254 + dst = key->dst;
255 +
256 + state = NUD_NONE;
257 + n = neigh_lookup(&arp_tbl, &dst, nh->nh_dev);
258 + if (n) {
259 + state = n->nud_state;
260 + neigh_release(n);
261 + }
262 + if (state==NUD_REACHABLE ||
263 + ((state&NUD_VALID) && order != last_dflt)) {
264 + dead = 0;
265 + goto setfl;
266 + }
267 + if (!(state&NUD_VALID))
268 + flag = 1;
269 + if (!dead)
270 + goto setfl;
271 + if ((state&NUD_VALID) ||
272 + (*last_idx<0 && order >= last_dflt)) {
273 + *last_resort = fi;
274 + *last_idx = order;
275 + *last_nhsel = nhsel;
276 + }
277 +
278 + setfl:
279 +
280 + read_lock_bh(&fib_nhflags_lock);
281 + if (flag)
282 + nh->nh_flags |= RTNH_F_SUSPECT;
283 + else
284 + nh->nh_flags &= ~RTNH_F_SUSPECT;
285 + read_unlock_bh(&fib_nhflags_lock);
286 }
287 - if (state==NUD_REACHABLE)
288 - return 0;
289 - if ((state&NUD_VALID) && order != fn_hash_last_dflt)
290 - return 0;
291 - if ((state&NUD_VALID) ||
292 - (*last_idx<0 && order > fn_hash_last_dflt)) {
293 - *last_resort = fi;
294 - *last_idx = order;
295 - }
296 - return 1;
297 + /* } endfor_nexthops(fi) */
298 +
299 + return dead;
300 }
301
302 static void
303 fn_hash_select_default(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)
304 {
305 - int order, last_idx;
306 - struct fib_node *f;
307 + int order, last_idx, last_dflt, last_nhsel;
308 + struct fib_node *f, *first_node;
309 struct fib_info *fi = NULL;
310 struct fib_info *last_resort;
311 struct fn_hash *t = (struct fn_hash*)tb->tb_data;
312 - struct fn_zone *fz = t->fn_zones[0];
313 + struct fn_zone *fz = t->fn_zones[res->prefixlen];
314 + fn_key_t k;
315
316 if (fz == NULL)
317 return;
318
319 + k = fz_key(key->dst, fz);
320 + last_dflt = -2;
321 + first_node = NULL;
322 last_idx = -1;
323 last_resort = NULL;
324 + last_nhsel = 0;
325 order = -1;
326
327 read_lock(&fib_hash_lock);
328 - for (f = fz->fz_hash[0]; f; f = f->fn_next) {
329 + for (f = fz_chain(k, fz); f; f = f->fn_next) {
330 struct fib_info *next_fi = FIB_INFO(f);
331
332 - if ((f->fn_state&FN_S_ZOMBIE) ||
333 + if (!fn_key_eq(k, f->fn_key) ||
334 + (f->fn_state&FN_S_ZOMBIE) ||
335 f->fn_scope != res->scope ||
336 +#ifdef CONFIG_IP_ROUTE_TOS
337 + (f->fn_tos && f->fn_tos != key->tos) ||
338 +#endif
339 f->fn_type != RTN_UNICAST)
340 continue;
341
342 if (next_fi->fib_priority > res->fi->fib_priority)
343 break;
344 - if (!next_fi->fib_nh[0].nh_gw || next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
345 - continue;
346 f->fn_state |= FN_S_ACCESSED;
347
348 - if (fi == NULL) {
349 - if (next_fi != res->fi)
350 - break;
351 - } else if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
352 + if (!first_node) {
353 + last_dflt = f->fn_last_dflt;
354 + first_node = f;
355 + }
356 + if (fi && !fib_detect_death(fi, order, last_dflt,
357 + &last_resort, &last_idx, &last_nhsel, key)) {
358 if (res->fi)
359 fib_info_put(res->fi);
360 res->fi = fi;
361 atomic_inc(&fi->fib_clntref);
362 - fn_hash_last_dflt = order;
363 + first_node->fn_last_dflt = order;
364 goto out;
365 }
366 fi = next_fi;
367 @@ -409,16 +461,25 @@
368 }
369
370 if (order<=0 || fi==NULL) {
371 - fn_hash_last_dflt = -1;
372 + if (fi && fi->fib_nhs > 1 &&
373 + fib_detect_death(fi, order, last_dflt,
374 + &last_resort, &last_idx, &last_nhsel, key) &&
375 + last_resort == fi) {
376 + read_lock_bh(&fib_nhflags_lock);
377 + fi->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
378 + read_unlock_bh(&fib_nhflags_lock);
379 + }
380 + if (first_node) first_node->fn_last_dflt = -1;
381 goto out;
382 }
383
384 - if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
385 + if (!fib_detect_death(fi, order, last_dflt, &last_resort, &last_idx,
386 + &last_nhsel, key)) {
387 if (res->fi)
388 fib_info_put(res->fi);
389 res->fi = fi;
390 atomic_inc(&fi->fib_clntref);
391 - fn_hash_last_dflt = order;
392 + first_node->fn_last_dflt = order;
393 goto out;
394 }
395
396 @@ -428,8 +489,11 @@
397 res->fi = last_resort;
398 if (last_resort)
399 atomic_inc(&last_resort->fib_clntref);
400 + read_lock_bh(&fib_nhflags_lock);
401 + last_resort->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
402 + read_unlock_bh(&fib_nhflags_lock);
403 + first_node->fn_last_dflt = last_idx;
404 }
405 - fn_hash_last_dflt = last_idx;
406 out:
407 read_unlock(&fib_hash_lock);
408 }
409 @@ -589,6 +653,7 @@
410
411 memset(new_f, 0, sizeof(struct fib_node));
412
413 + new_f->fn_last_dflt = -1;
414 new_f->fn_key = key;
415 #ifdef CONFIG_IP_ROUTE_TOS
416 new_f->fn_tos = tos;
417 Index: linux-2.4.35.4/net/ipv4/fib_rules.c
418 ===================================================================
419 --- linux-2.4.35.4.orig/net/ipv4/fib_rules.c 2007-12-15 05:19:36.618507808 +0100
420 +++ linux-2.4.35.4/net/ipv4/fib_rules.c 2007-12-15 05:20:13.108587259 +0100
421 @@ -307,6 +307,11 @@
422 }
423 }
424
425 +int fib_result_table(struct fib_result *res)
426 +{
427 + return res->r->r_table;
428 +}
429 +
430 int fib_lookup(const struct rt_key *key, struct fib_result *res)
431 {
432 int err;
433 @@ -371,8 +376,10 @@
434
435 void fib_select_default(const struct rt_key *key, struct fib_result *res)
436 {
437 - if (res->r && res->r->r_action == RTN_UNICAST &&
438 - FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
439 + if (res->r &&
440 + (res->r->r_action == RTN_UNICAST || res->r->r_action == RTN_NAT) &&
441 + ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
442 + FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)) {
443 struct fib_table *tb;
444 if ((tb = fib_get_table(res->r->r_table)) != NULL)
445 tb->tb_select_default(tb, key, res);
446 Index: linux-2.4.35.4/net/ipv4/fib_semantics.c
447 ===================================================================
448 --- linux-2.4.35.4.orig/net/ipv4/fib_semantics.c 2007-12-15 05:19:36.626508263 +0100
449 +++ linux-2.4.35.4/net/ipv4/fib_semantics.c 2007-12-15 05:20:13.112587489 +0100
450 @@ -48,6 +48,7 @@
451 static struct fib_info *fib_info_list;
452 static rwlock_t fib_info_lock = RW_LOCK_UNLOCKED;
453 int fib_info_cnt;
454 +rwlock_t fib_nhflags_lock = RW_LOCK_UNLOCKED;
455
456 #define for_fib_info() { struct fib_info *fi; \
457 for (fi = fib_info_list; fi; fi = fi->fib_next)
458 @@ -150,7 +151,7 @@
459 #ifdef CONFIG_NET_CLS_ROUTE
460 nh->nh_tclassid != onh->nh_tclassid ||
461 #endif
462 - ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
463 + ((nh->nh_flags^onh->nh_flags)&~RTNH_F_BADSTATE))
464 return -1;
465 onh++;
466 } endfor_nexthops(fi);
467 @@ -166,7 +167,7 @@
468 nfi->fib_prefsrc == fi->fib_prefsrc &&
469 nfi->fib_priority == fi->fib_priority &&
470 memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 &&
471 - ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
472 + ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_BADSTATE) == 0 &&
473 (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
474 return fi;
475 } endfor_fib_info();
476 @@ -365,8 +366,11 @@
477 return -EINVAL;
478 if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
479 return -ENODEV;
480 - if (!(dev->flags&IFF_UP))
481 - return -ENETDOWN;
482 + if (!(dev->flags&IFF_UP)) {
483 + if (fi->fib_protocol != RTPROT_STATIC)
484 + return -ENETDOWN;
485 + nh->nh_flags |= RTNH_F_DEAD;
486 + }
487 nh->nh_dev = dev;
488 dev_hold(dev);
489 nh->nh_scope = RT_SCOPE_LINK;
490 @@ -380,23 +384,48 @@
491 /* It is not necessary, but requires a bit of thinking */
492 if (key.scope < RT_SCOPE_LINK)
493 key.scope = RT_SCOPE_LINK;
494 - if ((err = fib_lookup(&key, &res)) != 0)
495 - return err;
496 - err = -EINVAL;
497 - if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
498 - goto out;
499 - nh->nh_scope = res.scope;
500 - nh->nh_oif = FIB_RES_OIF(res);
501 - if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
502 - goto out;
503 - dev_hold(nh->nh_dev);
504 - err = -ENETDOWN;
505 - if (!(nh->nh_dev->flags & IFF_UP))
506 - goto out;
507 - err = 0;
508 +
509 + err = fib_lookup(&key, &res);
510 + if (err) {
511 + struct in_device *in_dev;
512 +
513 + if (err != -ENETUNREACH ||
514 + fi->fib_protocol != RTPROT_STATIC)
515 + return err;
516 +
517 + in_dev = inetdev_by_index(nh->nh_oif);
518 + if (in_dev == NULL ||
519 + in_dev->dev->flags & IFF_UP) {
520 + if (in_dev)
521 + in_dev_put(in_dev);
522 + return err;
523 + }
524 + nh->nh_flags |= RTNH_F_DEAD;
525 + nh->nh_scope = RT_SCOPE_LINK;
526 + nh->nh_dev = in_dev->dev;
527 + dev_hold(nh->nh_dev);
528 + in_dev_put(in_dev);
529 + } else {
530 + err = -EINVAL;
531 + if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
532 + goto out;
533 + nh->nh_scope = res.scope;
534 + nh->nh_oif = FIB_RES_OIF(res);
535 + if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
536 + goto out;
537 + dev_hold(nh->nh_dev);
538 + if (!(nh->nh_dev->flags & IFF_UP)) {
539 + if (fi->fib_protocol != RTPROT_STATIC) {
540 + err = -ENETDOWN;
541 + goto out;
542 + }
543 + nh->nh_flags |= RTNH_F_DEAD;
544 + }
545 + err = 0;
546 out:
547 - fib_res_put(&res);
548 - return err;
549 + fib_res_put(&res);
550 + return err;
551 + }
552 } else {
553 struct in_device *in_dev;
554
555 @@ -407,8 +436,11 @@
556 if (in_dev == NULL)
557 return -ENODEV;
558 if (!(in_dev->dev->flags&IFF_UP)) {
559 - in_dev_put(in_dev);
560 - return -ENETDOWN;
561 + if (fi->fib_protocol != RTPROT_STATIC) {
562 + in_dev_put(in_dev);
563 + return -ENETDOWN;
564 + }
565 + nh->nh_flags |= RTNH_F_DEAD;
566 }
567 nh->nh_dev = in_dev->dev;
568 dev_hold(nh->nh_dev);
569 @@ -606,8 +638,12 @@
570 for_nexthops(fi) {
571 if (nh->nh_flags&RTNH_F_DEAD)
572 continue;
573 - if (!key->oif || key->oif == nh->nh_oif)
574 - break;
575 + if (key->oif && key->oif != nh->nh_oif)
576 + continue;
577 + if (key->gw && key->gw != nh->nh_gw &&
578 + nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
579 + continue;
580 + break;
581 }
582 #ifdef CONFIG_IP_ROUTE_MULTIPATH
583 if (nhsel < fi->fib_nhs) {
584 @@ -873,22 +909,35 @@
585 if (local && fi->fib_prefsrc == local) {
586 fi->fib_flags |= RTNH_F_DEAD;
587 ret++;
588 - } else if (dev && fi->fib_nhs) {
589 + } else if (fi->fib_nhs) {
590 int dead = 0;
591
592 change_nexthops(fi) {
593 - if (nh->nh_flags&RTNH_F_DEAD)
594 - dead++;
595 - else if (nh->nh_dev == dev &&
596 - nh->nh_scope != scope) {
597 - nh->nh_flags |= RTNH_F_DEAD;
598 + if (nh->nh_flags&RTNH_F_DEAD) {
599 + if (fi->fib_protocol!=RTPROT_STATIC ||
600 + nh->nh_dev == NULL ||
601 + !__in_dev_get(nh->nh_dev) ||
602 + nh->nh_dev->flags&IFF_UP)
603 + dead++;
604 + } else if ((nh->nh_dev == dev && dev &&
605 + nh->nh_scope != scope) ||
606 + (local == nh->nh_gw && local &&
607 + nh->nh_oif)) {
608 + write_lock_bh(&fib_nhflags_lock);
609 #ifdef CONFIG_IP_ROUTE_MULTIPATH
610 - spin_lock_bh(&fib_multipath_lock);
611 + spin_lock(&fib_multipath_lock);
612 + nh->nh_flags |= RTNH_F_DEAD;
613 fi->fib_power -= nh->nh_power;
614 nh->nh_power = 0;
615 - spin_unlock_bh(&fib_multipath_lock);
616 + spin_unlock(&fib_multipath_lock);
617 +#else
618 + nh->nh_flags |= RTNH_F_DEAD;
619 #endif
620 - dead++;
621 + write_unlock_bh(&fib_nhflags_lock);
622 + if (fi->fib_protocol!=RTPROT_STATIC ||
623 + force ||
624 + (dev && __in_dev_get(dev) == NULL))
625 + dead++;
626 }
627 #ifdef CONFIG_IP_ROUTE_MULTIPATH
628 if (force > 1 && nh->nh_dev == dev) {
629 @@ -906,37 +955,55 @@
630 return ret;
631 }
632
633 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
634 -
635 /*
636 - Dead device goes up. We wake up dead nexthops.
637 - It takes sense only on multipath routes.
638 + Dead device goes up or new address is added. We wake up dead nexthops.
639 */
640
641 int fib_sync_up(struct net_device *dev)
642 {
643 - int ret = 0;
644 + struct rt_key key;
645 + struct fib_result res;
646 + int ret, rep;
647
648 +repeat:
649 if (!(dev->flags&IFF_UP))
650 return 0;
651
652 + ret = 0;
653 + rep = 0;
654 for_fib_info() {
655 int alive = 0;
656
657 change_nexthops(fi) {
658 - if (!(nh->nh_flags&RTNH_F_DEAD)) {
659 - alive++;
660 + if (!(nh->nh_flags&RTNH_F_DEAD))
661 continue;
662 - }
663 if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
664 continue;
665 if (nh->nh_dev != dev || __in_dev_get(dev) == NULL)
666 continue;
667 + if (nh->nh_gw && fi->fib_protocol == RTPROT_STATIC) {
668 + memset(&key, 0, sizeof(key));
669 + key.dst = nh->nh_gw;
670 + key.oif = nh->nh_oif;
671 + key.scope = nh->nh_scope;
672 + if (fib_lookup(&key, &res) != 0)
673 + continue;
674 + if (res.type != RTN_UNICAST &&
675 + res.type != RTN_LOCAL) {
676 + fib_res_put(&res);
677 + continue;
678 + }
679 + nh->nh_scope = res.scope;
680 + fib_res_put(&res);
681 + rep = 1;
682 + }
683 alive++;
684 +#ifdef CONFIG_IP_ROUTE_MULTIPATH
685 spin_lock_bh(&fib_multipath_lock);
686 nh->nh_power = 0;
687 nh->nh_flags &= ~RTNH_F_DEAD;
688 spin_unlock_bh(&fib_multipath_lock);
689 +#endif
690 } endfor_nexthops(fi)
691
692 if (alive > 0) {
693 @@ -944,9 +1011,13 @@
694 ret++;
695 }
696 } endfor_fib_info();
697 + if (rep)
698 + goto repeat;
699 return ret;
700 }
701
702 +#ifdef CONFIG_IP_ROUTE_MULTIPATH
703 +
704 /*
705 The algorithm is suboptimal, but it provides really
706 fair weighted route distribution.
707 @@ -955,24 +1026,45 @@
708 void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
709 {
710 struct fib_info *fi = res->fi;
711 - int w;
712 + int w, alive;
713
714 spin_lock_bh(&fib_multipath_lock);
715 + if (key->oif) {
716 + int sel = -1;
717 + w = -1;
718 + change_nexthops(fi) {
719 + if (key->oif != nh->nh_oif)
720 + continue;
721 + if (key->gw && key->gw != nh->nh_gw &&
722 + nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
723 + continue;
724 + if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
725 + if (nh->nh_power > w) {
726 + w = nh->nh_power;
727 + sel = nhsel;
728 + }
729 + }
730 + } endfor_nexthops(fi);
731 + if (sel >= 0) {
732 + spin_unlock_bh(&fib_multipath_lock);
733 + res->nh_sel = sel;
734 + return;
735 + }
736 + goto last_resort;
737 + }
738 +
739 +repeat:
740 if (fi->fib_power <= 0) {
741 int power = 0;
742 change_nexthops(fi) {
743 - if (!(nh->nh_flags&RTNH_F_DEAD)) {
744 + if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
745 power += nh->nh_weight;
746 nh->nh_power = nh->nh_weight;
747 }
748 } endfor_nexthops(fi);
749 fi->fib_power = power;
750 - if (power <= 0) {
751 - spin_unlock_bh(&fib_multipath_lock);
752 - /* Race condition: route has just become dead. */
753 - res->nh_sel = 0;
754 - return;
755 - }
756 + if (power <= 0)
757 + goto last_resort;
758 }
759
760
761 @@ -982,20 +1074,40 @@
762
763 w = jiffies % fi->fib_power;
764
765 + alive = 0;
766 change_nexthops(fi) {
767 - if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
768 + if (!(nh->nh_flags&RTNH_F_BADSTATE) && nh->nh_power) {
769 if ((w -= nh->nh_power) <= 0) {
770 nh->nh_power--;
771 fi->fib_power--;
772 - res->nh_sel = nhsel;
773 spin_unlock_bh(&fib_multipath_lock);
774 + res->nh_sel = nhsel;
775 return;
776 }
777 + alive = 1;
778 + }
779 + } endfor_nexthops(fi);
780 + if (alive) {
781 + fi->fib_power = 0;
782 + goto repeat;
783 + }
784 +
785 +last_resort:
786 +
787 + for_nexthops(fi) {
788 + if (!(nh->nh_flags&RTNH_F_DEAD)) {
789 + if (key->oif && key->oif != nh->nh_oif)
790 + continue;
791 + if (key->gw && key->gw != nh->nh_gw &&
792 + nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
793 + continue;
794 + spin_unlock_bh(&fib_multipath_lock);
795 + res->nh_sel = nhsel;
796 + return;
797 }
798 } endfor_nexthops(fi);
799
800 /* Race condition: route has just become dead. */
801 - res->nh_sel = 0;
802 spin_unlock_bh(&fib_multipath_lock);
803 }
804 #endif
805 Index: linux-2.4.35.4/net/ipv4/ip_nat_dumb.c
806 ===================================================================
807 --- linux-2.4.35.4.orig/net/ipv4/ip_nat_dumb.c 2007-12-15 05:19:36.634508719 +0100
808 +++ linux-2.4.35.4/net/ipv4/ip_nat_dumb.c 2007-12-15 05:20:13.112587489 +0100
809 @@ -124,6 +124,7 @@
810 key.dst = ciph->saddr;
811 key.iif = skb->dev->ifindex;
812 key.oif = 0;
813 + key.gw = 0;
814 #ifdef CONFIG_IP_ROUTE_TOS
815 key.tos = RT_TOS(ciph->tos);
816 #endif
817 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_fw_compat_masq.c
818 ===================================================================
819 --- linux-2.4.35.4.orig/net/ipv4/netfilter/ip_fw_compat_masq.c 2007-12-15 05:19:36.642509177 +0100
820 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_fw_compat_masq.c 2007-12-15 05:20:13.112587489 +0100
821 @@ -41,6 +41,10 @@
822 enum ip_conntrack_info ctinfo;
823 struct ip_conntrack *ct;
824 unsigned int ret;
825 + struct rtable *rt, *skb_rt;
826 + struct net_device *skb_dev;
827 + __u32 saddr;
828 + int new;
829
830 /* Sorry, only ICMP, TCP and UDP. */
831 if (iph->protocol != IPPROTO_ICMP
832 @@ -64,22 +68,28 @@
833 }
834
835 info = &ct->nat.info;
836 + iph = (*pskb)->nh.iph;
837 + saddr = iph->saddr;
838 + new = 0;
839
840 WRITE_LOCK(&ip_nat_lock);
841 /* Setup the masquerade, if not already */
842 if (!info->initialized) {
843 u_int32_t newsrc;
844 - struct rtable *rt;
845 struct ip_nat_multi_range range;
846
847 + skb_rt = (struct rtable *) (*pskb)->dst;
848 + skb_dev = skb_rt->u.dst.dev;
849 /* Pass 0 instead of saddr, since it's going to be changed
850 anyway. */
851 - if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) {
852 + if (ip_route_output_lookup(&rt, iph->daddr, 0, RT_TOS(iph->tos),
853 + skb_dev? skb_dev->ifindex : 0,
854 + skb_dev? skb_rt->rt_gateway : 0) != 0) {
855 + WRITE_UNLOCK(&ip_nat_lock);
856 DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
857 return NF_DROP;
858 }
859 - newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
860 - RT_SCOPE_UNIVERSE);
861 + newsrc = rt->rt_src;
862 ip_rt_put(rt);
863 range = ((struct ip_nat_multi_range)
864 { 1,
865 @@ -92,11 +102,31 @@
866 WRITE_UNLOCK(&ip_nat_lock);
867 return ret;
868 }
869 + new = 1;
870 } else
871 DEBUGP("Masquerading already done on this conn.\n");
872 WRITE_UNLOCK(&ip_nat_lock);
873
874 - return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
875 + ret = do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
876 + if (ret != NF_ACCEPT || saddr == (*pskb)->nh.iph->saddr || new)
877 + return ret;
878 +
879 + iph = (*pskb)->nh.iph;
880 + if (ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), 0) != 0)
881 + return NF_DROP;
882 +
883 + skb_rt = (struct rtable *) (*pskb)->dst;
884 + skb_dev = skb_rt->u.dst.dev;
885 + if (skb_dev != rt->u.dst.dev || rt->rt_gateway != skb_rt->rt_gateway) {
886 + if (skb_dev != rt->u.dst.dev) {
887 + /* TODO: check the new mtu and reply FRAG_NEEDED */
888 + }
889 + dst_release((*pskb)->dst);
890 + (*pskb)->dst = &rt->u.dst;
891 + } else {
892 + ip_rt_put(rt);
893 + }
894 + return NF_ACCEPT;
895 }
896
897 void
898 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_nat_core.c
899 ===================================================================
900 --- linux-2.4.35.4.orig/net/ipv4/netfilter/ip_nat_core.c 2007-12-15 05:20:06.404205198 +0100
901 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_nat_core.c 2007-12-15 05:20:13.112587489 +0100
902 @@ -994,6 +994,60 @@
903 return NF_ACCEPT;
904 }
905
906 +unsigned int
907 +ip_nat_route_input(unsigned int hooknum,
908 + struct sk_buff **pskb,
909 + const struct net_device *in,
910 + const struct net_device *out,
911 + int (*okfn)(struct sk_buff *))
912 +{
913 + struct sk_buff *skb = *pskb;
914 + struct iphdr *iph;
915 + struct ip_conntrack *ct;
916 + enum ip_conntrack_info ctinfo;
917 + struct ip_nat_info *info;
918 + enum ip_conntrack_dir dir;
919 + __u32 saddr;
920 + int i;
921 +
922 + if (!(ct = ip_conntrack_get(skb, &ctinfo)))
923 + return NF_ACCEPT;
924 +
925 + info = &ct->nat.info;
926 + if (!info->initialized)
927 + return NF_ACCEPT;
928 +
929 + if (skb->dst)
930 + return NF_ACCEPT;
931 +
932 + if (skb->len < sizeof(struct iphdr))
933 + return NF_ACCEPT;
934 +
935 + iph = skb->nh.iph;
936 + saddr = iph->saddr;
937 + hooknum = NF_IP_POST_ROUTING;
938 + dir = CTINFO2DIR(ctinfo);
939 +
940 + READ_LOCK(&ip_nat_lock);
941 + for (i = 0; i < info->num_manips; i++) {
942 + if (info->manips[i].direction == dir
943 + && info->manips[i].hooknum == hooknum
944 + && info->manips[i].maniptype == IP_NAT_MANIP_SRC) {
945 + saddr = info->manips[i].manip.ip;
946 + }
947 + }
948 + READ_UNLOCK(&ip_nat_lock);
949 +
950 + if (saddr == iph->saddr)
951 + return NF_ACCEPT;
952 +
953 + if (ip_route_input_lookup(skb, iph->daddr, iph->saddr, iph->tos,
954 + skb->dev, saddr))
955 + return NF_DROP;
956 +
957 + return NF_ACCEPT;
958 +}
959 +
960 int __init ip_nat_init(void)
961 {
962 size_t i;
963 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_nat_standalone.c
964 ===================================================================
965 --- linux-2.4.35.4.orig/net/ipv4/netfilter/ip_nat_standalone.c 2007-12-15 05:19:36.654509858 +0100
966 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_nat_standalone.c 2007-12-15 05:20:13.112587489 +0100
967 @@ -245,6 +245,9 @@
968 /* Before packet filtering, change destination */
969 static struct nf_hook_ops ip_nat_in_ops
970 = { { NULL, NULL }, ip_nat_in, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST };
971 +/* Before routing, route before mangling */
972 +static struct nf_hook_ops ip_nat_inr_ops
973 += { { NULL, NULL }, ip_nat_route_input, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_LAST-1 };
974 /* After packet filtering, change source */
975 static struct nf_hook_ops ip_nat_out_ops
976 = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC};
977 @@ -313,10 +316,15 @@
978 printk("ip_nat_init: can't register in hook.\n");
979 goto cleanup_nat;
980 }
981 + ret = nf_register_hook(&ip_nat_inr_ops);
982 + if (ret < 0) {
983 + printk("ip_nat_init: can't register inr hook.\n");
984 + goto cleanup_inops;
985 + }
986 ret = nf_register_hook(&ip_nat_out_ops);
987 if (ret < 0) {
988 printk("ip_nat_init: can't register out hook.\n");
989 - goto cleanup_inops;
990 + goto cleanup_inrops;
991 }
992 ret = nf_register_hook(&ip_nat_local_out_ops);
993 if (ret < 0) {
994 @@ -336,6 +344,8 @@
995 nf_unregister_hook(&ip_nat_local_out_ops);
996 cleanup_outops:
997 nf_unregister_hook(&ip_nat_out_ops);
998 + cleanup_inrops:
999 + nf_unregister_hook(&ip_nat_inr_ops);
1000 cleanup_inops:
1001 nf_unregister_hook(&ip_nat_in_ops);
1002 cleanup_nat:
1003 Index: linux-2.4.35.4/net/ipv4/netfilter/ipt_MASQUERADE.c
1004 ===================================================================
1005 --- linux-2.4.35.4.orig/net/ipv4/netfilter/ipt_MASQUERADE.c 2007-12-15 05:19:36.662510316 +0100
1006 +++ linux-2.4.35.4/net/ipv4/netfilter/ipt_MASQUERADE.c 2007-12-15 05:20:13.116587715 +0100
1007 @@ -87,7 +87,8 @@
1008 key.dst = (*pskb)->nh.iph->daddr;
1009 key.src = 0; /* Unknown: that's what we're trying to establish */
1010 key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN;
1011 - key.oif = 0;
1012 + key.oif = out->ifindex;
1013 + key.gw = ((struct rtable *) (*pskb)->dst)->rt_gateway;
1014 #ifdef CONFIG_IP_ROUTE_FWMARK
1015 key.fwmark = (*pskb)->nfmark;
1016 #endif
1017 @@ -98,13 +99,6 @@
1018 " No route: Rusty's brain broke!\n");
1019 return NF_DROP;
1020 }
1021 - if (rt->u.dst.dev != out) {
1022 - if (net_ratelimit())
1023 - printk("MASQUERADE:"
1024 - " Route sent us somewhere else.\n");
1025 - ip_rt_put(rt);
1026 - return NF_DROP;
1027 - }
1028
1029 newsrc = rt->rt_src;
1030 DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc));
1031 Index: linux-2.4.35.4/net/ipv4/route.c
1032 ===================================================================
1033 --- linux-2.4.35.4.orig/net/ipv4/route.c 2007-12-15 05:19:36.670510772 +0100
1034 +++ linux-2.4.35.4/net/ipv4/route.c 2007-12-15 05:20:13.116587715 +0100
1035 @@ -919,6 +919,7 @@
1036
1037 /* Gateway is different ... */
1038 rt->rt_gateway = new_gw;
1039 + if (rt->key.gw) rt->key.gw = new_gw;
1040
1041 /* Redirect received -> path was valid */
1042 dst_confirm(&rth->u.dst);
1043 @@ -1343,6 +1344,7 @@
1044 rth->key.fwmark = skb->nfmark;
1045 #endif
1046 rth->key.src = saddr;
1047 + rth->key.lsrc = 0;
1048 rth->rt_src = saddr;
1049 #ifdef CONFIG_IP_ROUTE_NAT
1050 rth->rt_dst_map = daddr;
1051 @@ -1356,6 +1358,7 @@
1052 rth->u.dst.dev = &loopback_dev;
1053 dev_hold(rth->u.dst.dev);
1054 rth->key.oif = 0;
1055 + rth->key.gw = 0;
1056 rth->rt_gateway = daddr;
1057 rth->rt_spec_dst= spec_dst;
1058 rth->rt_type = RTN_MULTICAST;
1059 @@ -1395,7 +1398,7 @@
1060 */
1061
1062 int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
1063 - u8 tos, struct net_device *dev)
1064 + u8 tos, struct net_device *dev, u32 lsrc)
1065 {
1066 struct rt_key key;
1067 struct fib_result res;
1068 @@ -1415,16 +1418,17 @@
1069 goto out;
1070
1071 key.dst = daddr;
1072 - key.src = saddr;
1073 + key.src = lsrc? : saddr;
1074 key.tos = tos;
1075 #ifdef CONFIG_IP_ROUTE_FWMARK
1076 key.fwmark = skb->nfmark;
1077 #endif
1078 - key.iif = dev->ifindex;
1079 + key.iif = lsrc? loopback_dev.ifindex : dev->ifindex;
1080 key.oif = 0;
1081 + key.gw = 0;
1082 key.scope = RT_SCOPE_UNIVERSE;
1083
1084 - hash = rt_hash_code(daddr, saddr ^ (key.iif << 5), tos);
1085 + hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos);
1086
1087 /* Check for the most weird martians, which can be not detected
1088 by fib_lookup.
1089 @@ -1445,6 +1449,12 @@
1090 if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr))
1091 goto martian_destination;
1092
1093 + if (lsrc) {
1094 + if (MULTICAST(lsrc) || BADCLASS(lsrc) ||
1095 + ZERONET(lsrc) || LOOPBACK(lsrc))
1096 + goto e_inval;
1097 + }
1098 +
1099 /*
1100 * Now we are ready to route packet.
1101 */
1102 @@ -1454,6 +1464,10 @@
1103 goto no_route;
1104 }
1105 free_res = 1;
1106 + if (lsrc && res.type != RTN_UNICAST && res.type != RTN_NAT)
1107 + goto e_inval;
1108 + key.iif = dev->ifindex;
1109 + key.src = saddr;
1110
1111 rt_cache_stat[smp_processor_id()].in_slow_tot++;
1112
1113 @@ -1464,7 +1478,7 @@
1114
1115 if (1) {
1116 u32 src_map = saddr;
1117 - if (res.r)
1118 + if (res.r && !lsrc)
1119 src_map = fib_rules_policy(saddr, &res, &flags);
1120
1121 if (res.type == RTN_NAT) {
1122 @@ -1503,8 +1517,9 @@
1123 if (res.type != RTN_UNICAST)
1124 goto martian_destination;
1125
1126 + fib_select_default(&key, &res);
1127 #ifdef CONFIG_IP_ROUTE_MULTIPATH
1128 - if (res.fi->fib_nhs > 1 && key.oif == 0)
1129 + if (res.fi->fib_nhs > 1)
1130 fib_select_multipath(&key, &res);
1131 #endif
1132 out_dev = in_dev_get(FIB_RES_DEV(res));
1133 @@ -1524,6 +1539,7 @@
1134 flags |= RTCF_DIRECTSRC;
1135
1136 if (out_dev == in_dev && err && !(flags & (RTCF_NAT | RTCF_MASQ)) &&
1137 + !lsrc &&
1138 (IN_DEV_SHARED_MEDIA(out_dev) ||
1139 inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res))))
1140 flags |= RTCF_DOREDIRECT;
1141 @@ -1550,6 +1566,7 @@
1142 #endif
1143 rth->key.src = saddr;
1144 rth->rt_src = saddr;
1145 + rth->key.lsrc = lsrc;
1146 rth->rt_gateway = daddr;
1147 #ifdef CONFIG_IP_ROUTE_NAT
1148 rth->rt_src_map = key.src;
1149 @@ -1562,6 +1579,7 @@
1150 rth->u.dst.dev = out_dev->dev;
1151 dev_hold(rth->u.dst.dev);
1152 rth->key.oif = 0;
1153 + rth->key.gw = 0;
1154 rth->rt_spec_dst= spec_dst;
1155
1156 rth->u.dst.input = ip_forward;
1157 @@ -1572,7 +1590,8 @@
1158 rth->rt_flags = flags;
1159
1160 #ifdef CONFIG_NET_FASTROUTE
1161 - if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT))) {
1162 + if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT)) &&
1163 + !lsrc) {
1164 struct net_device *odev = rth->u.dst.dev;
1165 if (odev != dev &&
1166 dev->accept_fastpath &&
1167 @@ -1595,6 +1614,8 @@
1168 brd_input:
1169 if (skb->protocol != htons(ETH_P_IP))
1170 goto e_inval;
1171 + if (lsrc)
1172 + goto e_inval;
1173
1174 if (ZERONET(saddr))
1175 spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
1176 @@ -1627,6 +1648,7 @@
1177 #endif
1178 rth->key.src = saddr;
1179 rth->rt_src = saddr;
1180 + rth->key.lsrc = 0;
1181 #ifdef CONFIG_IP_ROUTE_NAT
1182 rth->rt_dst_map = key.dst;
1183 rth->rt_src_map = key.src;
1184 @@ -1639,6 +1661,7 @@
1185 rth->u.dst.dev = &loopback_dev;
1186 dev_hold(rth->u.dst.dev);
1187 rth->key.oif = 0;
1188 + rth->key.gw = 0;
1189 rth->rt_gateway = daddr;
1190 rth->rt_spec_dst= spec_dst;
1191 rth->u.dst.input= ip_local_deliver;
1192 @@ -1704,8 +1727,9 @@
1193 goto e_inval;
1194 }
1195
1196 -int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
1197 - u8 tos, struct net_device *dev)
1198 +static inline int
1199 +ip_route_input_cached(struct sk_buff *skb, u32 daddr, u32 saddr,
1200 + u8 tos, struct net_device *dev, u32 lsrc)
1201 {
1202 struct rtable * rth;
1203 unsigned hash;
1204 @@ -1719,6 +1743,7 @@
1205 if (rth->key.dst == daddr &&
1206 rth->key.src == saddr &&
1207 rth->key.iif == iif &&
1208 + rth->key.lsrc == lsrc &&
1209 rth->key.oif == 0 &&
1210 #ifdef CONFIG_IP_ROUTE_FWMARK
1211 rth->key.fwmark == skb->nfmark &&
1212 @@ -1766,9 +1791,21 @@
1213 read_unlock(&inetdev_lock);
1214 return -EINVAL;
1215 }
1216 - return ip_route_input_slow(skb, daddr, saddr, tos, dev);
1217 + return ip_route_input_slow(skb, daddr, saddr, tos, dev, lsrc);
1218 +}
1219 +
1220 +int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
1221 + u8 tos, struct net_device *dev)
1222 +{
1223 + return ip_route_input_cached(skb, daddr, saddr, tos, dev, 0);
1224 }
1225
1226 +int ip_route_input_lookup(struct sk_buff *skb, u32 daddr, u32 saddr,
1227 + u8 tos, struct net_device *dev, u32 lsrc)
1228 +{
1229 + return ip_route_input_cached(skb, daddr, saddr, tos, dev, lsrc);
1230 +}
1231 +
1232 /*
1233 * Major route resolver routine.
1234 */
1235 @@ -1791,6 +1828,7 @@
1236 key.tos = tos & IPTOS_RT_MASK;
1237 key.iif = loopback_dev.ifindex;
1238 key.oif = oldkey->oif;
1239 + key.gw = oldkey->gw;
1240 #ifdef CONFIG_IP_ROUTE_FWMARK
1241 key.fwmark = oldkey->fwmark;
1242 #endif
1243 @@ -1880,6 +1918,7 @@
1244 dev_out = &loopback_dev;
1245 dev_hold(dev_out);
1246 key.oif = loopback_dev.ifindex;
1247 + key.gw = 0;
1248 res.type = RTN_LOCAL;
1249 flags |= RTCF_LOCAL;
1250 goto make_route;
1251 @@ -1887,7 +1926,7 @@
1252
1253 if (fib_lookup(&key, &res)) {
1254 res.fi = NULL;
1255 - if (oldkey->oif) {
1256 + if (oldkey->oif && dev_out->flags&IFF_UP) {
1257 /* Apparently, routing tables are wrong. Assume,
1258 that the destination is on link.
1259
1260 @@ -1930,6 +1969,7 @@
1261 dev_out = &loopback_dev;
1262 dev_hold(dev_out);
1263 key.oif = dev_out->ifindex;
1264 + key.gw = 0;
1265 if (res.fi)
1266 fib_info_put(res.fi);
1267 res.fi = NULL;
1268 @@ -1937,13 +1977,12 @@
1269 goto make_route;
1270 }
1271
1272 + if (res.type == RTN_UNICAST)
1273 + fib_select_default(&key, &res);
1274 #ifdef CONFIG_IP_ROUTE_MULTIPATH
1275 - if (res.fi->fib_nhs > 1 && key.oif == 0)
1276 + if (res.fi->fib_nhs > 1)
1277 fib_select_multipath(&key, &res);
1278 - else
1279 #endif
1280 - if (!res.prefixlen && res.type == RTN_UNICAST && !key.oif)
1281 - fib_select_default(&key, &res);
1282
1283 if (!key.src)
1284 key.src = FIB_RES_PREFSRC(res);
1285 @@ -2001,7 +2040,9 @@
1286 rth->key.tos = tos;
1287 rth->key.src = oldkey->src;
1288 rth->key.iif = 0;
1289 + rth->key.lsrc = 0;
1290 rth->key.oif = oldkey->oif;
1291 + rth->key.gw = oldkey->gw;
1292 #ifdef CONFIG_IP_ROUTE_FWMARK
1293 rth->key.fwmark = oldkey->fwmark;
1294 #endif
1295 @@ -2080,6 +2121,7 @@
1296 rth->key.src == key->src &&
1297 rth->key.iif == 0 &&
1298 rth->key.oif == key->oif &&
1299 + rth->key.gw == key->gw &&
1300 #ifdef CONFIG_IP_ROUTE_FWMARK
1301 rth->key.fwmark == key->fwmark &&
1302 #endif
1303 Index: linux-2.4.35.4/net/netsyms.c
1304 ===================================================================
1305 --- linux-2.4.35.4.orig/net/netsyms.c 2007-12-15 05:19:36.678511227 +0100
1306 +++ linux-2.4.35.4/net/netsyms.c 2007-12-15 05:20:13.120587941 +0100
1307 @@ -260,6 +260,7 @@
1308 EXPORT_SYMBOL(inet_unregister_protosw);
1309 EXPORT_SYMBOL(ip_route_output_key);
1310 EXPORT_SYMBOL(ip_route_input);
1311 +EXPORT_SYMBOL(ip_route_input_lookup);
1312 EXPORT_SYMBOL(icmp_send);
1313 EXPORT_SYMBOL(icmp_statistics);
1314 EXPORT_SYMBOL(icmp_err_convert);
This page took 0.092016 seconds and 3 git commands to generate.