]> git.pld-linux.org Git - packages/kernel.git/blob - routes-2.6.19-12.diff
- xen update to 3.0.4
[packages/kernel.git] / routes-2.6.19-12.diff
1 diff -urp v2.6.19/linux/include/linux/netfilter_ipv4/ip_nat.h linux/include/linux/netfilter_ipv4/ip_nat.h
2 --- v2.6.19/linux/include/linux/netfilter_ipv4/ip_nat.h 2006-12-01 00:26:11.000000000 +0200
3 +++ linux/include/linux/netfilter_ipv4/ip_nat.h 2006-12-02 23:55:43.000000000 +0200
4 @@ -63,6 +63,13 @@ struct ip_nat_info
5  
6  struct ip_conntrack;
7  
8 +/* Call input routing for SNAT-ed traffic */
9 +extern unsigned int ip_nat_route_input(unsigned int hooknum,
10 +                                      struct sk_buff **pskb,
11 +                                      const struct net_device *in,
12 +                                      const struct net_device *out,
13 +                                      int (*okfn)(struct sk_buff *));
14 +
15  /* Set up the info structure to map into this range. */
16  extern unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack,
17                                       const struct ip_nat_range *range,
18 diff -urp v2.6.19/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
19 --- v2.6.19/linux/include/linux/rtnetlink.h     2006-12-01 00:26:11.000000000 +0200
20 +++ linux/include/linux/rtnetlink.h     2006-12-02 23:54:59.000000000 +0200
21 @@ -293,6 +293,8 @@ struct rtnexthop
22  #define RTNH_F_DEAD            1       /* Nexthop is dead (used by multipath)  */
23  #define RTNH_F_PERVASIVE       2       /* Do recursive gateway lookup  */
24  #define RTNH_F_ONLINK          4       /* Gateway is forced on link    */
25 +#define RTNH_F_SUSPECT         8       /* We don't know the real state */
26 +#define RTNH_F_BADSTATE                (RTNH_F_DEAD | RTNH_F_SUSPECT)
27  
28  /* Macros to handle hexthops */
29  
30 diff -urp v2.6.19/linux/include/net/flow.h linux/include/net/flow.h
31 --- v2.6.19/linux/include/net/flow.h    2006-12-01 00:26:11.000000000 +0200
32 +++ linux/include/net/flow.h    2006-12-03 00:04:49.000000000 +0200
33 @@ -19,6 +19,8 @@ struct flowi {
34                         __be32                  daddr;
35                         __be32                  saddr;
36                         __u32                   fwmark;
37 +                       __be32                  lsrc;
38 +                       __be32                  gw;
39                         __u8                    tos;
40                         __u8                    scope;
41                 } ip4_u;
42 @@ -48,6 +50,8 @@ struct flowi {
43  #define fl4_dst                nl_u.ip4_u.daddr
44  #define fl4_src                nl_u.ip4_u.saddr
45  #define fl4_fwmark     nl_u.ip4_u.fwmark
46 +#define fl4_lsrc       nl_u.ip4_u.lsrc
47 +#define fl4_gw         nl_u.ip4_u.gw
48  #define fl4_tos                nl_u.ip4_u.tos
49  #define fl4_scope      nl_u.ip4_u.scope
50  
51 diff -urp v2.6.19/linux/include/net/ip_fib.h linux/include/net/ip_fib.h
52 --- v2.6.19/linux/include/net/ip_fib.h  2006-12-01 00:26:11.000000000 +0200
53 +++ linux/include/net/ip_fib.h  2006-12-02 23:54:59.000000000 +0200
54 @@ -196,7 +196,8 @@ static inline int fib_lookup(const struc
55  
56  static inline void fib_select_default(const struct flowi *flp, struct fib_result *res)
57  {
58 -       if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
59 +       if ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
60 +           FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)
61                 ip_fib_main_table->tb_select_default(ip_fib_main_table, flp, res);
62  }
63  
64 @@ -209,6 +210,7 @@ extern int fib_lookup(struct flowi *flp,
65  extern struct fib_table *fib_new_table(u32 id);
66  extern struct fib_table *fib_get_table(u32 id);
67  extern void fib_select_default(const struct flowi *flp, struct fib_result *res);
68 +extern int fib_result_table(struct fib_result *res);
69  
70  #endif /* CONFIG_IP_MULTIPLE_TABLES */
71  
72 @@ -284,4 +286,6 @@ extern int  fib_proc_init(void);
73  extern void fib_proc_exit(void);
74  #endif
75  
76 +extern rwlock_t fib_nhflags_lock;
77 +
78  #endif  /* _NET_FIB_H */
79 diff -urp v2.6.19/linux/include/net/route.h linux/include/net/route.h
80 --- v2.6.19/linux/include/net/route.h   2006-12-01 00:26:11.000000000 +0200
81 +++ linux/include/net/route.h   2006-12-02 23:57:13.000000000 +0200
82 @@ -117,6 +117,7 @@ extern int          __ip_route_output_key(struct
83  extern int             ip_route_output_key(struct rtable **, struct flowi *flp);
84  extern int             ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
85  extern int             ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin);
86 +extern int             ip_route_input_lookup(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin, __be32 lsrc);
87  extern unsigned short  ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
88  extern void            ip_rt_send_redirect(struct sk_buff *skb);
89  
90 diff -urp v2.6.19/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
91 --- v2.6.19/linux/net/ipv4/fib_frontend.c       2006-12-01 00:26:11.000000000 +0200
92 +++ linux/net/ipv4/fib_frontend.c       2006-12-02 23:54:59.000000000 +0200
93 @@ -58,8 +58,12 @@ struct fib_table *ip_fib_main_table;
94  #define FIB_TABLE_HASHSZ 1
95  static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
96  
97 +#define FIB_RES_TABLE(r) (RT_TABLE_MAIN)
98 +
99  #else
100  
101 +#define FIB_RES_TABLE(r) (fib_result_table(r))
102 +
103  #define FIB_TABLE_HASHSZ 256
104  static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
105  
106 @@ -190,6 +194,9 @@ int fib_validate_source(__be32 src, __be
107                                         .tos = tos } },
108                             .iif = oif };
109         struct fib_result res;
110 +       int table;
111 +       unsigned char prefixlen;
112 +       unsigned char scope;
113         int no_addr, rpf;
114         int ret;
115  
116 @@ -211,31 +218,35 @@ int fib_validate_source(__be32 src, __be
117                 goto e_inval_res;
118         *spec_dst = FIB_RES_PREFSRC(res);
119         fib_combine_itag(itag, &res);
120 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
121 -       if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
122 -#else
123         if (FIB_RES_DEV(res) == dev)
124 -#endif
125         {
126                 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
127                 fib_res_put(&res);
128                 return ret;
129         }
130 +       table = FIB_RES_TABLE(&res);
131 +       prefixlen = res.prefixlen;
132 +       scope = res.scope;
133         fib_res_put(&res);
134         if (no_addr)
135                 goto last_resort;
136 -       if (rpf)
137 -               goto e_inval;
138         fl.oif = dev->ifindex;
139  
140         ret = 0;
141         if (fib_lookup(&fl, &res) == 0) {
142 -               if (res.type == RTN_UNICAST) {
143 +               if (res.type == RTN_UNICAST &&
144 +                   ((table == FIB_RES_TABLE(&res) &&
145 +                     res.prefixlen >= prefixlen && res.scope >= scope) ||
146 +                    !rpf)) {
147                         *spec_dst = FIB_RES_PREFSRC(res);
148                         ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
149 +                       fib_res_put(&res);
150 +                       return ret;
151                 }
152                 fib_res_put(&res);
153         }
154 +       if (rpf)
155 +               goto e_inval;
156         return ret;
157  
158  last_resort:
159 @@ -836,9 +847,7 @@ static int fib_inetaddr_event(struct not
160         switch (event) {
161         case NETDEV_UP:
162                 fib_add_ifaddr(ifa);
163 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
164                 fib_sync_up(ifa->ifa_dev->dev);
165 -#endif
166                 rt_cache_flush(-1);
167                 break;
168         case NETDEV_DOWN:
169 @@ -874,9 +883,7 @@ static int fib_netdev_event(struct notif
170                 for_ifa(in_dev) {
171                         fib_add_ifaddr(ifa);
172                 } endfor_ifa(in_dev);
173 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
174                 fib_sync_up(dev);
175 -#endif
176                 rt_cache_flush(-1);
177                 break;
178         case NETDEV_DOWN:
179 diff -urp v2.6.19/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
180 --- v2.6.19/linux/net/ipv4/fib_hash.c   2006-12-01 00:26:11.000000000 +0200
181 +++ linux/net/ipv4/fib_hash.c   2006-12-02 23:54:59.000000000 +0200
182 @@ -275,30 +275,38 @@ out:
183         return err;
184  }
185  
186 -static int fn_hash_last_dflt=-1;
187 -
188  static void
189  fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
190  {
191 -       int order, last_idx;
192 +       int order, last_idx, last_dflt, last_nhsel;
193 +       struct fib_alias *first_fa = NULL;
194 +       struct hlist_head *head;
195         struct hlist_node *node;
196         struct fib_node *f;
197         struct fib_info *fi = NULL;
198         struct fib_info *last_resort;
199         struct fn_hash *t = (struct fn_hash*)tb->tb_data;
200 -       struct fn_zone *fz = t->fn_zones[0];
201 +       struct fn_zone *fz = t->fn_zones[res->prefixlen];
202 +       __be32 k;
203  
204         if (fz == NULL)
205                 return;
206  
207 +       k = fz_key(flp->fl4_dst, fz);
208 +       last_dflt = -2;
209 +       last_nhsel = 0;
210         last_idx = -1;
211         last_resort = NULL;
212         order = -1;
213  
214         read_lock(&fib_hash_lock);
215 -       hlist_for_each_entry(f, node, &fz->fz_hash[0], fn_hash) {
216 +       head = &fz->fz_hash[fn_hash(k, fz)];
217 +       hlist_for_each_entry(f, node, head, fn_hash) {
218                 struct fib_alias *fa;
219  
220 +               if (f->fn_key != k)
221 +                       continue;
222 +
223                 list_for_each_entry(fa, &f->fn_alias, fa_list) {
224                         struct fib_info *next_fi = fa->fa_info;
225  
226 @@ -306,41 +314,52 @@ fn_hash_select_default(struct fib_table 
227                             fa->fa_type != RTN_UNICAST)
228                                 continue;
229  
230 +                       if (fa->fa_tos &&
231 +                           fa->fa_tos != flp->fl4_tos)
232 +                               continue;
233                         if (next_fi->fib_priority > res->fi->fib_priority)
234                                 break;
235 -                       if (!next_fi->fib_nh[0].nh_gw ||
236 -                           next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
237 -                               continue;
238                         fa->fa_state |= FA_S_ACCESSED;
239  
240 -                       if (fi == NULL) {
241 -                               if (next_fi != res->fi)
242 -                                       break;
243 -                       } else if (!fib_detect_death(fi, order, &last_resort,
244 -                                                    &last_idx, &fn_hash_last_dflt)) {
245 +                       if (!first_fa) {
246 +                               last_dflt = fa->fa_last_dflt;
247 +                               first_fa = fa;
248 +                       }
249 +                       if (fi && !fib_detect_death(fi, order, &last_resort,
250 +                               &last_idx, &last_dflt, &last_nhsel, flp)) {
251                                 if (res->fi)
252                                         fib_info_put(res->fi);
253                                 res->fi = fi;
254                                 atomic_inc(&fi->fib_clntref);
255 -                               fn_hash_last_dflt = order;
256 +                               first_fa->fa_last_dflt = order;
257                                 goto out;
258                         }
259                         fi = next_fi;
260                         order++;
261                 }
262 +               break;
263         }
264  
265         if (order <= 0 || fi == NULL) {
266 -               fn_hash_last_dflt = -1;
267 +               if (fi && fi->fib_nhs > 1 &&
268 +                   fib_detect_death(fi, order, &last_resort, &last_idx,
269 +                       &last_dflt, &last_nhsel, flp) &&
270 +                   last_resort == fi) {
271 +                       read_lock_bh(&fib_nhflags_lock);
272 +                       fi->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
273 +                       read_unlock_bh(&fib_nhflags_lock);
274 +               }
275 +               if (first_fa) first_fa->fa_last_dflt = -1;
276                 goto out;
277         }
278  
279 -       if (!fib_detect_death(fi, order, &last_resort, &last_idx, &fn_hash_last_dflt)) {
280 +       if (!fib_detect_death(fi, order, &last_resort, &last_idx,
281 +                             &last_dflt, &last_nhsel, flp)) {
282                 if (res->fi)
283                         fib_info_put(res->fi);
284                 res->fi = fi;
285                 atomic_inc(&fi->fib_clntref);
286 -               fn_hash_last_dflt = order;
287 +               first_fa->fa_last_dflt = order;
288                 goto out;
289         }
290  
291 @@ -350,8 +369,11 @@ fn_hash_select_default(struct fib_table 
292                 res->fi = last_resort;
293                 if (last_resort)
294                         atomic_inc(&last_resort->fib_clntref);
295 +               read_lock_bh(&fib_nhflags_lock);
296 +               last_resort->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
297 +               read_unlock_bh(&fib_nhflags_lock);
298 +               first_fa->fa_last_dflt = last_idx;
299         }
300 -       fn_hash_last_dflt = last_idx;
301  out:
302         read_unlock(&fib_hash_lock);
303  }
304 @@ -447,6 +469,7 @@ static int fn_hash_insert(struct fib_tab
305                         write_lock_bh(&fib_hash_lock);
306                         fi_drop = fa->fa_info;
307                         fa->fa_info = fi;
308 +                       fa->fa_last_dflt = -1;
309                         fa->fa_type = cfg->fc_type;
310                         fa->fa_scope = cfg->fc_scope;
311                         state = fa->fa_state;
312 @@ -506,6 +529,7 @@ static int fn_hash_insert(struct fib_tab
313         new_fa->fa_type = cfg->fc_type;
314         new_fa->fa_scope = cfg->fc_scope;
315         new_fa->fa_state = 0;
316 +       new_fa->fa_last_dflt = -1;
317  
318         /*
319          * Insert new entry to the list.
320 diff -urp v2.6.19/linux/net/ipv4/fib_lookup.h linux/net/ipv4/fib_lookup.h
321 --- v2.6.19/linux/net/ipv4/fib_lookup.h 2006-12-01 00:26:11.000000000 +0200
322 +++ linux/net/ipv4/fib_lookup.h 2006-12-02 23:54:59.000000000 +0200
323 @@ -9,6 +9,7 @@ struct fib_alias {
324         struct list_head        fa_list;
325         struct rcu_head rcu;
326         struct fib_info         *fa_info;
327 +       int                     fa_last_dflt;
328         u8                      fa_tos;
329         u8                      fa_type;
330         u8                      fa_scope;
331 @@ -35,6 +36,7 @@ extern struct fib_alias *fib_find_alias(
332                                         u8 tos, u32 prio);
333  extern int fib_detect_death(struct fib_info *fi, int order,
334                             struct fib_info **last_resort,
335 -                           int *last_idx, int *dflt);
336 +                           int *last_idx, int *dflt, int *last_nhsel,
337 +                           const struct flowi *flp);
338  
339  #endif /* _FIB_LOOKUP_H */
340 diff -urp v2.6.19/linux/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c
341 --- v2.6.19/linux/net/ipv4/fib_rules.c  2006-12-01 00:26:11.000000000 +0200
342 +++ linux/net/ipv4/fib_rules.c  2006-12-02 23:54:59.000000000 +0200
343 @@ -89,6 +89,11 @@ u32 fib_rules_tclass(struct fib_result *
344  }
345  #endif
346  
347 +int fib_result_table(struct fib_result *res)
348 +{
349 +       return res->r->table;
350 +}
351 +
352  int fib_lookup(struct flowi *flp, struct fib_result *res)
353  {
354         struct fib_lookup_arg arg = {
355 @@ -140,7 +145,8 @@ errout:
356  void fib_select_default(const struct flowi *flp, struct fib_result *res)
357  {
358         if (res->r && res->r->action == FR_ACT_TO_TBL &&
359 -           FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
360 +           ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
361 +            FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)) {
362                 struct fib_table *tb;
363                 if ((tb = fib_get_table(res->r->table)) != NULL)
364                         tb->tb_select_default(tb, flp, res);
365 diff -urp v2.6.19/linux/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c
366 --- v2.6.19/linux/net/ipv4/fib_semantics.c      2006-12-01 00:26:11.000000000 +0200
367 +++ linux/net/ipv4/fib_semantics.c      2006-12-02 23:55:43.000000000 +0200
368 @@ -55,6 +55,7 @@ static struct hlist_head *fib_info_hash;
369  static struct hlist_head *fib_info_laddrhash;
370  static unsigned int fib_hash_size;
371  static unsigned int fib_info_cnt;
372 +rwlock_t fib_nhflags_lock = RW_LOCK_UNLOCKED;
373  
374  #define DEVINDEX_HASHBITS 8
375  #define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS)
376 @@ -190,7 +191,7 @@ static __inline__ int nh_comp(const stru
377  #ifdef CONFIG_NET_CLS_ROUTE
378                     nh->nh_tclassid != onh->nh_tclassid ||
379  #endif
380 -                   ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
381 +                   ((nh->nh_flags^onh->nh_flags)&~RTNH_F_BADSTATE))
382                         return -1;
383                 onh++;
384         } endfor_nexthops(fi);
385 @@ -227,7 +228,7 @@ static struct fib_info *fib_find_info(co
386                     nfi->fib_priority == fi->fib_priority &&
387                     memcmp(nfi->fib_metrics, fi->fib_metrics,
388                            sizeof(fi->fib_metrics)) == 0 &&
389 -                   ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
390 +                   ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_BADSTATE) == 0 &&
391                     (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
392                         return fi;
393         }
394 @@ -319,26 +320,70 @@ struct fib_alias *fib_find_alias(struct 
395  }
396  
397  int fib_detect_death(struct fib_info *fi, int order,
398 -                    struct fib_info **last_resort, int *last_idx, int *dflt)
399 +                    struct fib_info **last_resort, int *last_idx, int *dflt,
400 +                    int *last_nhsel, const struct flowi *flp)
401  {
402         struct neighbour *n;
403 -       int state = NUD_NONE;
404 +       int nhsel;
405 +       int state;
406 +       struct fib_nh * nh;
407 +       __be32 dst;
408 +       int flag, dead = 1;
409 +
410 +       /* change_nexthops(fi) { */
411 +       for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) {
412 +               if (flp->oif && flp->oif != nh->nh_oif)
413 +                       continue;
414 +               if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw && nh->nh_gw &&
415 +                   nh->nh_scope == RT_SCOPE_LINK)
416 +                       continue;
417 +               if (nh->nh_flags & RTNH_F_DEAD)
418 +                       continue;
419  
420 -       n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev);
421 -       if (n) {
422 -               state = n->nud_state;
423 -               neigh_release(n);
424 -       }
425 -       if (state==NUD_REACHABLE)
426 -               return 0;
427 -       if ((state&NUD_VALID) && order != *dflt)
428 -               return 0;
429 -       if ((state&NUD_VALID) ||
430 -           (*last_idx<0 && order > *dflt)) {
431 -               *last_resort = fi;
432 -               *last_idx = order;
433 +               flag = 0;
434 +               if (nh->nh_dev->flags & IFF_NOARP) {
435 +                       dead = 0;
436 +                       goto setfl;
437 +               }
438 +
439 +               dst = nh->nh_gw;
440 +               if (!nh->nh_gw || nh->nh_scope != RT_SCOPE_LINK)
441 +                       dst = flp->fl4_dst;
442 +
443 +               state = NUD_NONE;
444 +               n = neigh_lookup(&arp_tbl, &dst, nh->nh_dev);
445 +               if (n) {
446 +                       state = n->nud_state;
447 +                       neigh_release(n);
448 +               }
449 +               if (state==NUD_REACHABLE ||
450 +                       ((state&NUD_VALID) && order != *dflt)) {
451 +                       dead = 0;
452 +                       goto setfl;
453 +               }
454 +               if (!(state&NUD_VALID))
455 +                       flag = 1;
456 +               if (!dead)
457 +                       goto setfl;
458 +               if ((state&NUD_VALID) ||
459 +                   (*last_idx<0 && order >= *dflt)) {
460 +                       *last_resort = fi;
461 +                       *last_idx = order;
462 +                       *last_nhsel = nhsel;
463 +               }
464 +
465 +               setfl:
466 +
467 +               read_lock_bh(&fib_nhflags_lock);
468 +               if (flag)
469 +                       nh->nh_flags |= RTNH_F_SUSPECT;
470 +               else
471 +                       nh->nh_flags &= ~RTNH_F_SUSPECT;
472 +               read_unlock_bh(&fib_nhflags_lock);
473         }
474 -       return 1;
475 +       /* } endfor_nexthops(fi) */
476 +
477 +       return dead;
478  }
479  
480  #ifdef CONFIG_IP_ROUTE_MULTIPATH
481 @@ -508,8 +553,11 @@ static int fib_check_nh(struct fib_confi
482                                 return -EINVAL;
483                         if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
484                                 return -ENODEV;
485 -                       if (!(dev->flags&IFF_UP))
486 -                               return -ENETDOWN;
487 +                       if (!(dev->flags&IFF_UP)) {
488 +                               if (fi->fib_protocol != RTPROT_STATIC)
489 +                                       return -ENETDOWN;
490 +                               nh->nh_flags |= RTNH_F_DEAD;
491 +                       }
492                         nh->nh_dev = dev;
493                         dev_hold(dev);
494                         nh->nh_scope = RT_SCOPE_LINK;
495 @@ -529,24 +577,48 @@ static int fib_check_nh(struct fib_confi
496                         /* It is not necessary, but requires a bit of thinking */
497                         if (fl.fl4_scope < RT_SCOPE_LINK)
498                                 fl.fl4_scope = RT_SCOPE_LINK;
499 -                       if ((err = fib_lookup(&fl, &res)) != 0)
500 -                               return err;
501 +                       err = fib_lookup(&fl, &res);
502                 }
503 -               err = -EINVAL;
504 -               if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
505 -                       goto out;
506 -               nh->nh_scope = res.scope;
507 -               nh->nh_oif = FIB_RES_OIF(res);
508 -               if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
509 -                       goto out;
510 -               dev_hold(nh->nh_dev);
511 -               err = -ENETDOWN;
512 -               if (!(nh->nh_dev->flags & IFF_UP))
513 -                       goto out;
514 -               err = 0;
515 +               if (err) {
516 +                       struct in_device *in_dev;
517 +
518 +                       if (err != -ENETUNREACH ||
519 +                           fi->fib_protocol != RTPROT_STATIC)
520 +                               return err;
521 +
522 +                       in_dev = inetdev_by_index(nh->nh_oif);
523 +                       if (in_dev == NULL ||
524 +                           in_dev->dev->flags & IFF_UP) {
525 +                               if (in_dev)
526 +                                       in_dev_put(in_dev);
527 +                               return err;
528 +                       }
529 +                       nh->nh_flags |= RTNH_F_DEAD;
530 +                       nh->nh_scope = RT_SCOPE_LINK;
531 +                       nh->nh_dev = in_dev->dev;
532 +                       dev_hold(nh->nh_dev);
533 +                       in_dev_put(in_dev);
534 +               } else {
535 +                       err = -EINVAL;
536 +                       if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
537 +                               goto out;
538 +                       nh->nh_scope = res.scope;
539 +                       nh->nh_oif = FIB_RES_OIF(res);
540 +                       if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
541 +                               goto out;
542 +                       dev_hold(nh->nh_dev);
543 +                       if (!(nh->nh_dev->flags & IFF_UP)) {
544 +                               if (fi->fib_protocol != RTPROT_STATIC) {
545 +                                       err = -ENETDOWN;
546 +                                       goto out;
547 +                               }
548 +                               nh->nh_flags |= RTNH_F_DEAD;
549 +                       }
550 +                       err = 0;
551  out:
552 -               fib_res_put(&res);
553 -               return err;
554 +                       fib_res_put(&res);
555 +                       return err;
556 +               }
557         } else {
558                 struct in_device *in_dev;
559  
560 @@ -557,8 +629,11 @@ out:
561                 if (in_dev == NULL)
562                         return -ENODEV;
563                 if (!(in_dev->dev->flags&IFF_UP)) {
564 -                       in_dev_put(in_dev);
565 -                       return -ENETDOWN;
566 +                       if (fi->fib_protocol != RTPROT_STATIC) {
567 +                               in_dev_put(in_dev);
568 +                               return -ENETDOWN;
569 +                       }
570 +                       nh->nh_flags |= RTNH_F_DEAD;
571                 }
572                 nh->nh_dev = in_dev->dev;
573                 dev_hold(nh->nh_dev);
574 @@ -881,8 +956,12 @@ int fib_semantic_match(struct list_head 
575                                 for_nexthops(fi) {
576                                         if (nh->nh_flags&RTNH_F_DEAD)
577                                                 continue;
578 -                                       if (!flp->oif || flp->oif == nh->nh_oif)
579 -                                               break;
580 +                                       if (flp->oif && flp->oif != nh->nh_oif)
581 +                                               continue;
582 +                                       if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw &&
583 +                                           nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
584 +                                               continue;
585 +                                       break;
586                                 }
587  #ifdef CONFIG_IP_ROUTE_MULTIPATH
588                                 if (nhsel < fi->fib_nhs) {
589 @@ -1056,18 +1135,29 @@ int fib_sync_down(__be32 local, struct n
590                         prev_fi = fi;
591                         dead = 0;
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_rtnl(nh->nh_dev) == NULL ||
602 +                                           nh->nh_dev->flags&IFF_UP)
603 +                                               dead++;
604 +                               } else if (nh->nh_dev == dev &&
605 +                                          nh->nh_scope != scope) {
606 +                                       write_lock_bh(&fib_nhflags_lock);
607  #ifdef CONFIG_IP_ROUTE_MULTIPATH
608 -                                       spin_lock_bh(&fib_multipath_lock);
609 +                                       spin_lock(&fib_multipath_lock);
610 +                                       nh->nh_flags |= RTNH_F_DEAD;
611                                         fi->fib_power -= nh->nh_power;
612                                         nh->nh_power = 0;
613 -                                       spin_unlock_bh(&fib_multipath_lock);
614 +                                       spin_unlock(&fib_multipath_lock);
615 +#else
616 +                                       nh->nh_flags |= RTNH_F_DEAD;
617  #endif
618 -                                       dead++;
619 +                                       write_unlock_bh(&fib_nhflags_lock);
620 +                                       if (fi->fib_protocol!=RTPROT_STATIC ||
621 +                                           force ||
622 +                                           __in_dev_get_rtnl(dev) == NULL)
623 +                                               dead++;
624                                 }
625  #ifdef CONFIG_IP_ROUTE_MULTIPATH
626                                 if (force > 1 && nh->nh_dev == dev) {
627 @@ -1086,11 +1176,8 @@ int fib_sync_down(__be32 local, struct n
628         return ret;
629  }
630  
631 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
632 -
633  /*
634 -   Dead device goes up. We wake up dead nexthops.
635 -   It takes sense only on multipath routes.
636 +   Dead device goes up or new address is added. We wake up dead nexthops.
637   */
638  
639  int fib_sync_up(struct net_device *dev)
640 @@ -1100,8 +1187,10 @@ int fib_sync_up(struct net_device *dev)
641         struct hlist_head *head;
642         struct hlist_node *node;
643         struct fib_nh *nh;
644 -       int ret;
645 +       struct fib_result res;
646 +       int ret, rep;
647  
648 +repeat:
649         if (!(dev->flags&IFF_UP))
650                 return 0;
651  
652 @@ -1109,6 +1198,7 @@ int fib_sync_up(struct net_device *dev)
653         hash = fib_devindex_hashfn(dev->ifindex);
654         head = &fib_info_devhash[hash];
655         ret = 0;
656 +       rep = 0;
657  
658         hlist_for_each_entry(nh, node, head, nh_hash) {
659                 struct fib_info *fi = nh->nh_parent;
660 @@ -1121,19 +1211,37 @@ int fib_sync_up(struct net_device *dev)
661                 prev_fi = fi;
662                 alive = 0;
663                 change_nexthops(fi) {
664 -                       if (!(nh->nh_flags&RTNH_F_DEAD)) {
665 -                               alive++;
666 +                       if (!(nh->nh_flags&RTNH_F_DEAD))
667                                 continue;
668 -                       }
669                         if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
670                                 continue;
671                         if (nh->nh_dev != dev || !__in_dev_get_rtnl(dev))
672                                 continue;
673 +                       if (nh->nh_gw && fi->fib_protocol == RTPROT_STATIC) {
674 +                               struct flowi fl = {
675 +                                       .nl_u = { .ip4_u =
676 +                                                 { .daddr = nh->nh_gw,
677 +                                                   .scope = nh->nh_scope } },
678 +                                       .oif =  nh->nh_oif,
679 +                               };
680 +                               if (fib_lookup(&fl, &res) != 0)
681 +                                       continue;
682 +                               if (res.type != RTN_UNICAST &&
683 +                                   res.type != RTN_LOCAL) {
684 +                                       fib_res_put(&res);
685 +                                       continue;
686 +                               }
687 +                               nh->nh_scope = res.scope;
688 +                               fib_res_put(&res);
689 +                               rep = 1;
690 +                       }
691                         alive++;
692 +#ifdef CONFIG_IP_ROUTE_MULTIPATH
693                         spin_lock_bh(&fib_multipath_lock);
694                         nh->nh_power = 0;
695                         nh->nh_flags &= ~RTNH_F_DEAD;
696                         spin_unlock_bh(&fib_multipath_lock);
697 +#endif
698                 } endfor_nexthops(fi)
699  
700                 if (alive > 0) {
701 @@ -1141,10 +1249,14 @@ int fib_sync_up(struct net_device *dev)
702                         ret++;
703                 }
704         }
705 +       if (rep)
706 +               goto repeat;
707  
708         return ret;
709  }
710  
711 +#ifdef CONFIG_IP_ROUTE_MULTIPATH
712 +
713  /*
714     The algorithm is suboptimal, but it provides really
715     fair weighted route distribution.
716 @@ -1153,24 +1265,45 @@ int fib_sync_up(struct net_device *dev)
717  void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
718  {
719         struct fib_info *fi = res->fi;
720 -       int w;
721 +       int w, alive;
722  
723         spin_lock_bh(&fib_multipath_lock);
724 +       if (flp->oif) {
725 +               int sel = -1;
726 +               w = -1;
727 +               change_nexthops(fi) {
728 +                       if (flp->oif != nh->nh_oif)
729 +                               continue;
730 +                       if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw &&
731 +                           nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
732 +                               continue;
733 +                       if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
734 +                               if (nh->nh_power > w) {
735 +                                       w = nh->nh_power;
736 +                                       sel = nhsel;
737 +                               }
738 +                       }
739 +               } endfor_nexthops(fi);
740 +               if (sel >= 0) {
741 +                       spin_unlock_bh(&fib_multipath_lock);
742 +                       res->nh_sel = sel;
743 +                       return;
744 +               }
745 +               goto last_resort;
746 +       }
747 +
748 +repeat:
749         if (fi->fib_power <= 0) {
750                 int power = 0;
751                 change_nexthops(fi) {
752 -                       if (!(nh->nh_flags&RTNH_F_DEAD)) {
753 +                       if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
754                                 power += nh->nh_weight;
755                                 nh->nh_power = nh->nh_weight;
756                         }
757                 } endfor_nexthops(fi);
758                 fi->fib_power = power;
759 -               if (power <= 0) {
760 -                       spin_unlock_bh(&fib_multipath_lock);
761 -                       /* Race condition: route has just become dead. */
762 -                       res->nh_sel = 0;
763 -                       return;
764 -               }
765 +               if (power <= 0)
766 +                       goto last_resort;
767         }
768  
769  
770 @@ -1180,20 +1313,40 @@ void fib_select_multipath(const struct f
771  
772         w = jiffies % fi->fib_power;
773  
774 +       alive = 0;
775         change_nexthops(fi) {
776 -               if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
777 +               if (!(nh->nh_flags&RTNH_F_BADSTATE) && nh->nh_power) {
778                         if ((w -= nh->nh_power) <= 0) {
779                                 nh->nh_power--;
780                                 fi->fib_power--;
781 -                               res->nh_sel = nhsel;
782                                 spin_unlock_bh(&fib_multipath_lock);
783 +                               res->nh_sel = nhsel;
784                                 return;
785                         }
786 +                       alive = 1;
787 +               }
788 +       } endfor_nexthops(fi);
789 +       if (alive) {
790 +               fi->fib_power = 0;
791 +               goto repeat;
792 +       }
793 +
794 +last_resort:
795 +
796 +       for_nexthops(fi) {
797 +               if (!(nh->nh_flags&RTNH_F_DEAD)) {
798 +                       if (flp->oif && flp->oif != nh->nh_oif)
799 +                               continue;
800 +                       if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw &&
801 +                           nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
802 +                               continue;
803 +                       spin_unlock_bh(&fib_multipath_lock);
804 +                       res->nh_sel = nhsel;
805 +                       return;
806                 }
807         } endfor_nexthops(fi);
808  
809         /* Race condition: route has just become dead. */
810 -       res->nh_sel = 0;
811         spin_unlock_bh(&fib_multipath_lock);
812  }
813  #endif
814 diff -urp v2.6.19/linux/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c
815 --- v2.6.19/linux/net/ipv4/netfilter/ip_nat_core.c      2006-12-01 00:26:11.000000000 +0200
816 +++ linux/net/ipv4/netfilter/ip_nat_core.c      2006-12-03 00:02:47.000000000 +0200
817 @@ -573,6 +573,53 @@ EXPORT_SYMBOL_GPL(ip_nat_port_nfattr_to_
818  EXPORT_SYMBOL_GPL(ip_nat_port_range_to_nfattr);
819  #endif
820  
821 +unsigned int
822 +ip_nat_route_input(unsigned int hooknum,
823 +               struct sk_buff **pskb,
824 +               const struct net_device *in,
825 +               const struct net_device *out,
826 +               int (*okfn)(struct sk_buff *))
827 +{
828 +       struct sk_buff *skb = *pskb;
829 +       struct iphdr *iph;
830 +       struct ip_conntrack *conn;
831 +       enum ip_conntrack_info ctinfo;
832 +       enum ip_conntrack_dir dir;
833 +       unsigned long statusbit;
834 +       __be32 saddr;
835 +
836 +       if (!(conn = ip_conntrack_get(skb, &ctinfo)))
837 +               return NF_ACCEPT;
838 +
839 +       if (!(conn->status & IPS_NAT_DONE_MASK))
840 +               return NF_ACCEPT;
841 +       dir = CTINFO2DIR(ctinfo);
842 +       statusbit = IPS_SRC_NAT;
843 +       if (dir == IP_CT_DIR_REPLY)
844 +               statusbit ^= IPS_NAT_MASK;
845 +       if (!(conn->status & statusbit))
846 +               return NF_ACCEPT;
847 +
848 +       if (skb->dst)
849 +               return NF_ACCEPT;
850 +
851 +       if (skb->len < sizeof(struct iphdr))
852 +               return NF_ACCEPT;
853 +
854 +       /* use daddr in other direction as masquerade address (lsrc) */
855 +       iph = skb->nh.iph;
856 +       saddr = conn->tuplehash[!dir].tuple.dst.ip;
857 +       if (saddr == iph->saddr)
858 +               return NF_ACCEPT;
859 +
860 +       if (ip_route_input_lookup(skb, iph->daddr, iph->saddr, iph->tos,
861 +           skb->dev, saddr))
862 +               return NF_DROP;
863 +
864 +       return NF_ACCEPT;
865 +}
866 +EXPORT_SYMBOL_GPL(ip_nat_route_input);
867 +
868  static int __init ip_nat_init(void)
869  {
870         size_t i;
871 diff -urp v2.6.19/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c
872 --- v2.6.19/linux/net/ipv4/netfilter/ip_nat_standalone.c        2006-12-01 00:26:12.000000000 +0200
873 +++ linux/net/ipv4/netfilter/ip_nat_standalone.c        2006-12-02 23:55:43.000000000 +0200
874 @@ -301,6 +301,14 @@ static struct nf_hook_ops ip_nat_ops[] =
875                 .hooknum        = NF_IP_PRE_ROUTING,
876                 .priority       = NF_IP_PRI_NAT_DST,
877         },
878 +       /* Before routing, route before mangling */
879 +       {
880 +               .hook           = ip_nat_route_input,
881 +               .owner          = THIS_MODULE,
882 +               .pf             = PF_INET,
883 +               .hooknum        = NF_IP_PRE_ROUTING,
884 +               .priority       = NF_IP_PRI_LAST-1,
885 +       },
886         /* After packet filtering, change source */
887         {
888                 .hook           = ip_nat_out,
889 diff -urp v2.6.19/linux/net/ipv4/netfilter/ipt_MASQUERADE.c linux/net/ipv4/netfilter/ipt_MASQUERADE.c
890 --- v2.6.19/linux/net/ipv4/netfilter/ipt_MASQUERADE.c   2006-12-01 00:26:12.000000000 +0200
891 +++ linux/net/ipv4/netfilter/ipt_MASQUERADE.c   2006-12-02 23:55:43.000000000 +0200
892 @@ -85,13 +85,31 @@ masquerade_target(struct sk_buff **pskb,
893                 return NF_ACCEPT;
894  
895         mr = targinfo;
896 -       rt = (struct rtable *)(*pskb)->dst;
897 -       newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
898 -       if (!newsrc) {
899 -               printk("MASQUERADE: %s ate my IP address\n", out->name);
900 -               return NF_DROP;
901 +
902 +       {
903 +               struct flowi fl = { .nl_u = { .ip4_u =
904 +                                             { .daddr = (*pskb)->nh.iph->daddr,
905 +                                               .tos = (RT_TOS((*pskb)->nh.iph->tos) |
906 +                                                       RTO_CONN),
907 +                                               .gw = ((struct rtable *) (*pskb)->dst)->rt_gateway,
908 +#ifdef CONFIG_IP_ROUTE_FWMARK
909 +                                               .fwmark = (*pskb)->nfmark
910 +#endif
911 +                                             } },
912 +                                   .oif = out->ifindex };
913 +               if (ip_route_output_key(&rt, &fl) != 0) {
914 +                       /* Funky routing can do this. */
915 +                       if (net_ratelimit())
916 +                               printk("MASQUERADE:"
917 +                                      " No route: Rusty's brain broke!\n");
918 +                       return NF_DROP;
919 +               }
920         }
921  
922 +       newsrc = rt->rt_src;
923 +       DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc));
924 +       ip_rt_put(rt);
925 +
926         write_lock_bh(&masq_lock);
927         ct->nat.masq_index = out->ifindex;
928         write_unlock_bh(&masq_lock);
929 diff -urp v2.6.19/linux/net/ipv4/route.c linux/net/ipv4/route.c
930 --- v2.6.19/linux/net/ipv4/route.c      2006-12-01 00:26:12.000000000 +0200
931 +++ linux/net/ipv4/route.c      2006-12-02 23:59:58.000000000 +0200
932 @@ -1211,6 +1211,7 @@ void ip_rt_redirect(__be32 old_gw, __be3
933  
934                                 /* Gateway is different ... */
935                                 rt->rt_gateway          = new_gw;
936 +                               if (rt->fl.fl4_gw) rt->fl.fl4_gw = new_gw;
937  
938                                 /* Redirect received -> path was valid */
939                                 dst_confirm(&rth->u.dst);
940 @@ -1647,6 +1648,7 @@ static int ip_route_input_mc(struct sk_b
941         rth->fl.fl4_fwmark= skb->nfmark;
942  #endif
943         rth->fl.fl4_src = saddr;
944 +       rth->fl.fl4_lsrc = 0;
945         rth->rt_src     = saddr;
946  #ifdef CONFIG_NET_CLS_ROUTE
947         rth->u.dst.tclassid = itag;
948 @@ -1657,6 +1659,7 @@ static int ip_route_input_mc(struct sk_b
949         dev_hold(rth->u.dst.dev);
950         rth->idev       = in_dev_get(rth->u.dst.dev);
951         rth->fl.oif     = 0;
952 +       rth->fl.fl4_gw  = 0;
953         rth->rt_gateway = daddr;
954         rth->rt_spec_dst= spec_dst;
955         rth->rt_type    = RTN_MULTICAST;
956 @@ -1721,7 +1724,7 @@ static inline int __mkroute_input(struct
957                                   struct fib_result* res, 
958                                   struct in_device *in_dev, 
959                                   __be32 daddr, __be32 saddr, u32 tos,
960 -                                 struct rtable **result) 
961 +                                 __be32 lsrc, struct rtable **result) 
962  {
963  
964         struct rtable *rth;
965 @@ -1755,6 +1758,7 @@ static inline int __mkroute_input(struct
966                 flags |= RTCF_DIRECTSRC;
967  
968         if (out_dev == in_dev && err && !(flags & (RTCF_NAT | RTCF_MASQ)) &&
969 +           !lsrc &&
970             (IN_DEV_SHARED_MEDIA(out_dev) ||
971              inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
972                 flags |= RTCF_DOREDIRECT;
973 @@ -1794,6 +1798,7 @@ static inline int __mkroute_input(struct
974  #endif
975         rth->fl.fl4_src = saddr;
976         rth->rt_src     = saddr;
977 +       rth->fl.fl4_lsrc        = lsrc;
978         rth->rt_gateway = daddr;
979         rth->rt_iif     =
980                 rth->fl.iif     = in_dev->dev->ifindex;
981 @@ -1801,6 +1806,7 @@ static inline int __mkroute_input(struct
982         dev_hold(rth->u.dst.dev);
983         rth->idev       = in_dev_get(rth->u.dst.dev);
984         rth->fl.oif     = 0;
985 +       rth->fl.fl4_gw  = 0;
986         rth->rt_spec_dst= spec_dst;
987  
988         rth->u.dst.input = ip_forward;
989 @@ -1822,19 +1828,20 @@ static inline int ip_mkroute_input_def(s
990                                        struct fib_result* res, 
991                                        const struct flowi *fl,
992                                        struct in_device *in_dev,
993 -                                      __be32 daddr, __be32 saddr, u32 tos)
994 +                                      __be32 daddr, __be32 saddr, u32 tos, __be32 lsrc)
995  {
996         struct rtable* rth = NULL;
997         int err;
998         unsigned hash;
999  
1000 +       fib_select_default(fl, res);
1001  #ifdef CONFIG_IP_ROUTE_MULTIPATH
1002 -       if (res->fi && res->fi->fib_nhs > 1 && fl->oif == 0)
1003 +       if (res->fi && res->fi->fib_nhs > 1)
1004                 fib_select_multipath(fl, res);
1005  #endif
1006  
1007         /* create a routing cache entry */
1008 -       err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);
1009 +       err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, lsrc, &rth);
1010         if (err)
1011                 return err;
1012  
1013 @@ -1847,7 +1854,7 @@ static inline int ip_mkroute_input(struc
1014                                    struct fib_result* res, 
1015                                    const struct flowi *fl,
1016                                    struct in_device *in_dev,
1017 -                                  __be32 daddr, __be32 saddr, u32 tos)
1018 +                                  __be32 daddr, __be32 saddr, u32 tos, __be32 lsrc)
1019  {
1020  #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
1021         struct rtable* rth = NULL, *rtres;
1022 @@ -1863,7 +1870,7 @@ static inline int ip_mkroute_input(struc
1023         /* distinguish between multipath and singlepath */
1024         if (hopcount < 2)
1025                 return ip_mkroute_input_def(skb, res, fl, in_dev, daddr,
1026 -                                           saddr, tos);
1027 +                                           saddr, tos, 0);
1028         
1029         /* add all alternatives to the routing cache */
1030         for (hop = 0; hop < hopcount; hop++) {
1031 @@ -1875,7 +1882,7 @@ static inline int ip_mkroute_input(struc
1032  
1033                 /* create a routing cache entry */
1034                 err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos,
1035 -                                     &rth);
1036 +                                     0, &rth);
1037                 if (err)
1038                         return err;
1039  
1040 @@ -1895,7 +1902,7 @@ static inline int ip_mkroute_input(struc
1041         skb->dst = &rtres->u.dst;
1042         return err;
1043  #else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED  */
1044 -       return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos);
1045 +       return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos, lsrc);
1046  #endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED  */
1047  }
1048  
1049 @@ -1911,20 +1918,20 @@ static inline int ip_mkroute_input(struc
1050   */
1051  
1052  static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1053 -                              u8 tos, struct net_device *dev)
1054 +                              u8 tos, struct net_device *dev, __be32 lsrc)
1055  {
1056         struct fib_result res;
1057         struct in_device *in_dev = in_dev_get(dev);
1058         struct flowi fl = { .nl_u = { .ip4_u =
1059                                       { .daddr = daddr,
1060 -                                       .saddr = saddr,
1061 +                                       .saddr = lsrc? : saddr,
1062                                         .tos = tos,
1063                                         .scope = RT_SCOPE_UNIVERSE,
1064  #ifdef CONFIG_IP_ROUTE_FWMARK
1065                                         .fwmark = skb->nfmark
1066  #endif
1067                                       } },
1068 -                           .iif = dev->ifindex };
1069 +                           .iif = lsrc? loopback_dev.ifindex : dev->ifindex };
1070         unsigned        flags = 0;
1071         u32             itag = 0;
1072         struct rtable * rth;
1073 @@ -1957,6 +1964,12 @@ static int ip_route_input_slow(struct sk
1074         if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr))
1075                 goto martian_destination;
1076  
1077 +       if (lsrc) {
1078 +               if (MULTICAST(lsrc) || BADCLASS(lsrc) ||
1079 +                   ZERONET(lsrc) || LOOPBACK(lsrc))
1080 +                       goto e_inval;
1081 +       }
1082 +
1083         /*
1084          *      Now we are ready to route packet.
1085          */
1086 @@ -1966,6 +1979,10 @@ static int ip_route_input_slow(struct sk
1087                 goto no_route;
1088         }
1089         free_res = 1;
1090 +       if (lsrc && res.type != RTN_UNICAST && res.type != RTN_NAT)
1091 +               goto e_inval;
1092 +       fl.iif = dev->ifindex;
1093 +       fl.fl4_src = saddr;
1094  
1095         RT_CACHE_STAT_INC(in_slow_tot);
1096  
1097 @@ -1990,7 +2007,7 @@ static int ip_route_input_slow(struct sk
1098         if (res.type != RTN_UNICAST)
1099                 goto martian_destination;
1100  
1101 -       err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
1102 +       err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos, lsrc);
1103         if (err == -ENOBUFS)
1104                 goto e_nobufs;
1105         if (err == -EINVAL)
1106 @@ -2005,6 +2022,8 @@ out:      return err;
1107  brd_input:
1108         if (skb->protocol != htons(ETH_P_IP))
1109                 goto e_inval;
1110 +       if (lsrc)
1111 +               goto e_inval;
1112  
1113         if (ZERONET(saddr))
1114                 spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
1115 @@ -2047,6 +2066,7 @@ local_input:
1116         rth->u.dst.dev  = &loopback_dev;
1117         dev_hold(rth->u.dst.dev);
1118         rth->idev       = in_dev_get(rth->u.dst.dev);
1119 +       rth->fl.fl4_gw  = 0;
1120         rth->rt_gateway = daddr;
1121         rth->rt_spec_dst= spec_dst;
1122         rth->u.dst.input= ip_local_deliver;
1123 @@ -2096,8 +2116,9 @@ martian_source:
1124         goto e_inval;
1125  }
1126  
1127 -int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1128 -                  u8 tos, struct net_device *dev)
1129 +static inline int
1130 +ip_route_input_cached(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1131 +                  u8 tos, struct net_device *dev, __be32 lsrc)
1132  {
1133         struct rtable * rth;
1134         unsigned        hash;
1135 @@ -2112,6 +2133,7 @@ int ip_route_input(struct sk_buff *skb, 
1136                 if (rth->fl.fl4_dst == daddr &&
1137                     rth->fl.fl4_src == saddr &&
1138                     rth->fl.iif == iif &&
1139 +                   rth->fl.fl4_lsrc == lsrc &&
1140                     rth->fl.oif == 0 &&
1141  #ifdef CONFIG_IP_ROUTE_FWMARK
1142                     rth->fl.fl4_fwmark == skb->nfmark &&
1143 @@ -2160,7 +2182,19 @@ int ip_route_input(struct sk_buff *skb, 
1144                 rcu_read_unlock();
1145                 return -EINVAL;
1146         }
1147 -       return ip_route_input_slow(skb, daddr, saddr, tos, dev);
1148 +       return ip_route_input_slow(skb, daddr, saddr, tos, dev, lsrc);
1149 +}
1150 +
1151 +int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1152 +                  u8 tos, struct net_device *dev)
1153 +{
1154 +       return ip_route_input_cached(skb, daddr, saddr, tos, dev, 0);
1155 +}
1156 +
1157 +int ip_route_input_lookup(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1158 +                         u8 tos, struct net_device *dev, __be32 lsrc)
1159 +{
1160 +       return ip_route_input_cached(skb, daddr, saddr, tos, dev, lsrc);
1161  }
1162  
1163  static inline int __mkroute_output(struct rtable **result,
1164 @@ -2239,6 +2273,7 @@ static inline int __mkroute_output(struc
1165         rth->fl.fl4_tos = tos;
1166         rth->fl.fl4_src = oldflp->fl4_src;
1167         rth->fl.oif     = oldflp->oif;
1168 +       rth->fl.fl4_gw  = oldflp->fl4_gw;
1169  #ifdef CONFIG_IP_ROUTE_FWMARK
1170         rth->fl.fl4_fwmark= oldflp->fl4_fwmark;
1171  #endif
1172 @@ -2381,6 +2416,7 @@ static int ip_route_output_slow(struct r
1173         struct flowi fl = { .nl_u = { .ip4_u =
1174                                       { .daddr = oldflp->fl4_dst,
1175                                         .saddr = oldflp->fl4_src,
1176 +                                       .gw = oldflp->fl4_gw,
1177                                         .tos = tos & IPTOS_RT_MASK,
1178                                         .scope = ((tos & RTO_ONLINK) ?
1179                                                   RT_SCOPE_LINK :
1180 @@ -2486,6 +2522,7 @@ static int ip_route_output_slow(struct r
1181                 dev_out = &loopback_dev;
1182                 dev_hold(dev_out);
1183                 fl.oif = loopback_dev.ifindex;
1184 +               fl.fl4_gw = 0;
1185                 res.type = RTN_LOCAL;
1186                 flags |= RTCF_LOCAL;
1187                 goto make_route;
1188 @@ -2493,7 +2530,7 @@ static int ip_route_output_slow(struct r
1189  
1190         if (fib_lookup(&fl, &res)) {
1191                 res.fi = NULL;
1192 -               if (oldflp->oif) {
1193 +               if (oldflp->oif && dev_out->flags & IFF_UP) {
1194                         /* Apparently, routing tables are wrong. Assume,
1195                            that the destination is on link.
1196  
1197 @@ -2533,6 +2570,7 @@ static int ip_route_output_slow(struct r
1198                 dev_out = &loopback_dev;
1199                 dev_hold(dev_out);
1200                 fl.oif = dev_out->ifindex;
1201 +               fl.fl4_gw = 0;
1202                 if (res.fi)
1203                         fib_info_put(res.fi);
1204                 res.fi = NULL;
1205 @@ -2540,13 +2578,12 @@ static int ip_route_output_slow(struct r
1206                 goto make_route;
1207         }
1208  
1209 +       if (res.type == RTN_UNICAST)
1210 +               fib_select_default(&fl, &res);
1211  #ifdef CONFIG_IP_ROUTE_MULTIPATH
1212 -       if (res.fi->fib_nhs > 1 && fl.oif == 0)
1213 +       if (res.fi->fib_nhs > 1)
1214                 fib_select_multipath(&fl, &res);
1215 -       else
1216  #endif
1217 -       if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif)
1218 -               fib_select_default(&fl, &res);
1219  
1220         if (!fl.fl4_src)
1221                 fl.fl4_src = FIB_RES_PREFSRC(res);
1222 @@ -2583,6 +2620,7 @@ int __ip_route_output_key(struct rtable 
1223                     rth->fl.fl4_src == flp->fl4_src &&
1224                     rth->fl.iif == 0 &&
1225                     rth->fl.oif == flp->oif &&
1226 +                   rth->fl.fl4_gw == flp->fl4_gw &&
1227  #ifdef CONFIG_IP_ROUTE_FWMARK
1228                     rth->fl.fl4_fwmark == flp->fl4_fwmark &&
1229  #endif
1230 @@ -3221,3 +3259,4 @@ int __init ip_rt_init(void)
1231  EXPORT_SYMBOL(__ip_select_ident);
1232  EXPORT_SYMBOL(ip_route_input);
1233  EXPORT_SYMBOL(ip_route_output_key);
1234 +EXPORT_SYMBOL(ip_route_input_lookup);
This page took 0.120992 seconds and 3 git commands to generate.