]> git.pld-linux.org Git - packages/kernel.git/blob - kernel-routes.patch
- drop apparmor bcond (apparmor is in mainline)
[packages/kernel.git] / kernel-routes.patch
1 diff -urp v2.6.35/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
2 --- v2.6.35/linux/include/linux/rtnetlink.h     2010-08-02 09:37:48.000000000 +0300
3 +++ linux/include/linux/rtnetlink.h     2010-08-03 00:24:10.000000000 +0300
4 @@ -311,6 +311,8 @@ struct rtnexthop {
5  #define RTNH_F_DEAD            1       /* Nexthop is dead (used by multipath)  */
6  #define RTNH_F_PERVASIVE       2       /* Do recursive gateway lookup  */
7  #define RTNH_F_ONLINK          4       /* Gateway is forced on link    */
8 +#define RTNH_F_SUSPECT         8       /* We don't know the real state */
9 +#define RTNH_F_BADSTATE                (RTNH_F_DEAD | RTNH_F_SUSPECT)
10  
11  /* Macros to handle hexthops */
12  
13 diff -urp v2.6.35/linux/include/net/flow.h linux/include/net/flow.h
14 --- v2.6.35/linux/include/net/flow.h    2010-08-02 09:37:48.000000000 +0300
15 +++ linux/include/net/flow.h    2010-08-03 00:24:45.000000000 +0300
16 @@ -19,6 +19,8 @@ struct flowi {
17                 struct {
18                         __be32                  daddr;
19                         __be32                  saddr;
20 +                       __be32                  lsrc;
21 +                       __be32                  gw;
22                         __u8                    tos;
23                         __u8                    scope;
24                 } ip4_u;
25 @@ -43,6 +45,8 @@ struct flowi {
26  #define fl6_flowlabel  nl_u.ip6_u.flowlabel
27  #define fl4_dst                nl_u.ip4_u.daddr
28  #define fl4_src                nl_u.ip4_u.saddr
29 +#define fl4_lsrc       nl_u.ip4_u.lsrc
30 +#define fl4_gw         nl_u.ip4_u.gw
31  #define fl4_tos                nl_u.ip4_u.tos
32  #define fl4_scope      nl_u.ip4_u.scope
33  
34 diff -urp v2.6.35/linux/include/net/ip_fib.h linux/include/net/ip_fib.h
35 --- v2.6.35/linux/include/net/ip_fib.h  2010-02-25 09:01:36.000000000 +0200
36 +++ linux/include/net/ip_fib.h  2010-08-03 00:24:10.000000000 +0300
37 @@ -207,6 +207,8 @@ extern int fib_lookup(struct net *n, str
38  extern struct fib_table *fib_new_table(struct net *net, u32 id);
39  extern struct fib_table *fib_get_table(struct net *net, u32 id);
40  
41 +extern int fib_result_table(struct fib_result *res);
42 +
43  #endif /* CONFIG_IP_MULTIPLE_TABLES */
44  
45  /* Exported by fib_frontend.c */
46 @@ -277,4 +279,6 @@ static inline void fib_proc_exit(struct 
47  }
48  #endif
49  
50 +extern rwlock_t fib_nhflags_lock;
51 +
52  #endif  /* _NET_FIB_H */
53 diff -urp v2.6.35/linux/include/net/netfilter/nf_nat.h linux/include/net/netfilter/nf_nat.h
54 --- v2.6.35/linux/include/net/netfilter/nf_nat.h        2010-02-25 09:01:36.000000000 +0200
55 +++ linux/include/net/netfilter/nf_nat.h        2010-08-03 00:24:45.000000000 +0300
56 @@ -73,6 +73,13 @@ struct nf_conn_nat {
57  #endif
58  };
59  
60 +/* Call input routing for SNAT-ed traffic */
61 +extern unsigned int ip_nat_route_input(unsigned int hooknum,
62 +                                      struct sk_buff *skb,
63 +                                      const struct net_device *in,
64 +                                      const struct net_device *out,
65 +                                      int (*okfn)(struct sk_buff *));
66 +
67  /* Set up the info structure to map into this range. */
68  extern unsigned int nf_nat_setup_info(struct nf_conn *ct,
69                                       const struct nf_nat_range *range,
70 diff -urp v2.6.35/linux/include/net/route.h linux/include/net/route.h
71 --- v2.6.35/linux/include/net/route.h   2010-08-02 09:37:48.000000000 +0300
72 +++ linux/include/net/route.h   2010-08-03 00:26:00.000000000 +0300
73 @@ -128,6 +128,7 @@ static inline int ip_route_input_noref(s
74         return ip_route_input_common(skb, dst, src, tos, devin, true);
75  }
76  
77 +extern int             ip_route_input_lookup(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin, __be32 lsrc);
78  extern unsigned short  ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu, struct net_device *dev);
79  extern void            ip_rt_send_redirect(struct sk_buff *skb);
80  
81 diff -urp v2.6.35/linux/net/bridge/br_netfilter.c linux/net/bridge/br_netfilter.c
82 --- v2.6.35/linux/net/bridge/br_netfilter.c     2010-08-02 09:37:49.000000000 +0300
83 +++ linux/net/bridge/br_netfilter.c     2010-08-03 00:24:45.000000000 +0300
84 @@ -334,6 +334,9 @@ static int br_nf_pre_routing_finish(stru
85         struct rtable *rt;
86         int err;
87  
88 +       /* Old skb->dst is not expected, it is lost in all cases */
89 +       skb_dst_drop(skb);
90 +
91         if (nf_bridge->mask & BRNF_PKT_TYPE) {
92                 skb->pkt_type = PACKET_OTHERHOST;
93                 nf_bridge->mask ^= BRNF_PKT_TYPE;
94 diff -urp v2.6.35/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
95 --- v2.6.35/linux/net/ipv4/fib_frontend.c       2010-05-17 10:49:01.000000000 +0300
96 +++ linux/net/ipv4/fib_frontend.c       2010-08-03 00:24:10.000000000 +0300
97 @@ -47,6 +47,8 @@
98  
99  #ifndef CONFIG_IP_MULTIPLE_TABLES
100  
101 +#define FIB_RES_TABLE(r) (RT_TABLE_MAIN)
102 +
103  static int __net_init fib4_rules_init(struct net *net)
104  {
105         struct fib_table *local_table, *main_table;
106 @@ -71,6 +73,8 @@ fail:
107  }
108  #else
109  
110 +#define FIB_RES_TABLE(r) (fib_result_table(r))
111 +
112  struct fib_table *fib_new_table(struct net *net, u32 id)
113  {
114         struct fib_table *tb;
115 @@ -125,7 +129,8 @@ void fib_select_default(struct net *net,
116         table = res->r->table;
117  #endif
118         tb = fib_get_table(net, table);
119 -       if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
120 +       if ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
121 +           FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)
122                 fib_table_select_default(tb, flp, res);
123  }
124  
125 @@ -242,6 +247,9 @@ int fib_validate_source(__be32 src, __be
126                             .iif = oif };
127  
128         struct fib_result res;
129 +       int table;
130 +       unsigned char prefixlen;
131 +       unsigned char scope;
132         int no_addr, rpf, accept_local;
133         int ret;
134         struct net *net;
135 @@ -270,31 +278,35 @@ int fib_validate_source(__be32 src, __be
136         }
137         *spec_dst = FIB_RES_PREFSRC(res);
138         fib_combine_itag(itag, &res);
139 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
140 -       if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
141 -#else
142         if (FIB_RES_DEV(res) == dev)
143 -#endif
144         {
145                 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
146                 fib_res_put(&res);
147                 return ret;
148         }
149 +       table = FIB_RES_TABLE(&res);
150 +       prefixlen = res.prefixlen;
151 +       scope = res.scope;
152         fib_res_put(&res);
153         if (no_addr)
154                 goto last_resort;
155 -       if (rpf == 1)
156 -               goto e_inval;
157         fl.oif = dev->ifindex;
158  
159         ret = 0;
160         if (fib_lookup(net, &fl, &res) == 0) {
161 -               if (res.type == RTN_UNICAST) {
162 +               if (res.type == RTN_UNICAST &&
163 +                   ((table == FIB_RES_TABLE(&res) &&
164 +                     res.prefixlen >= prefixlen && res.scope >= scope) ||
165 +                    !rpf)) {
166                         *spec_dst = FIB_RES_PREFSRC(res);
167                         ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
168 +                       fib_res_put(&res);
169 +                       return ret;
170                 }
171                 fib_res_put(&res);
172         }
173 +       if (rpf == 1)
174 +               goto e_inval;
175         return ret;
176  
177  last_resort:
178 @@ -917,9 +929,7 @@ static int fib_inetaddr_event(struct not
179         switch (event) {
180         case NETDEV_UP:
181                 fib_add_ifaddr(ifa);
182 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
183                 fib_sync_up(dev);
184 -#endif
185                 rt_cache_flush(dev_net(dev), -1);
186                 break;
187         case NETDEV_DOWN:
188 @@ -955,9 +965,7 @@ static int fib_netdev_event(struct notif
189                 for_ifa(in_dev) {
190                         fib_add_ifaddr(ifa);
191                 } endfor_ifa(in_dev);
192 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
193                 fib_sync_up(dev);
194 -#endif
195                 rt_cache_flush(dev_net(dev), -1);
196                 break;
197         case NETDEV_DOWN:
198 diff -urp v2.6.35/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
199 --- v2.6.35/linux/net/ipv4/fib_hash.c   2010-05-17 10:49:01.000000000 +0300
200 +++ linux/net/ipv4/fib_hash.c   2010-08-03 00:24:10.000000000 +0300
201 @@ -278,25 +278,35 @@ out:
202  void fib_table_select_default(struct fib_table *tb,
203                               const struct flowi *flp, struct fib_result *res)
204  {
205 -       int order, last_idx;
206 +       int order, last_idx, last_dflt, last_nhsel;
207 +       struct fib_alias *first_fa = NULL;
208 +       struct hlist_head *head;
209         struct hlist_node *node;
210         struct fib_node *f;
211         struct fib_info *fi = NULL;
212         struct fib_info *last_resort;
213         struct fn_hash *t = (struct fn_hash *)tb->tb_data;
214 -       struct fn_zone *fz = t->fn_zones[0];
215 +       struct fn_zone *fz = t->fn_zones[res->prefixlen];
216 +       __be32 k;
217  
218         if (fz == NULL)
219                 return;
220  
221 +       k = fz_key(flp->fl4_dst, fz);
222 +       last_dflt = -2;
223 +       last_nhsel = 0;
224         last_idx = -1;
225         last_resort = NULL;
226         order = -1;
227  
228         read_lock(&fib_hash_lock);
229 -       hlist_for_each_entry(f, node, &fz->fz_hash[0], fn_hash) {
230 +       head = &fz->fz_hash[fn_hash(k, fz)];
231 +       hlist_for_each_entry(f, node, head, fn_hash) {
232                 struct fib_alias *fa;
233  
234 +               if (f->fn_key != k)
235 +                       continue;
236 +
237                 list_for_each_entry(fa, &f->fn_alias, fa_list) {
238                         struct fib_info *next_fi = fa->fa_info;
239  
240 @@ -304,42 +314,56 @@ void fib_table_select_default(struct fib
241                             fa->fa_type != RTN_UNICAST)
242                                 continue;
243  
244 +                       if (fa->fa_tos &&
245 +                           fa->fa_tos != flp->fl4_tos)
246 +                               continue;
247                         if (next_fi->fib_priority > res->fi->fib_priority)
248                                 break;
249 -                       if (!next_fi->fib_nh[0].nh_gw ||
250 -                           next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
251 -                               continue;
252                         fa->fa_state |= FA_S_ACCESSED;
253  
254 -                       if (fi == NULL) {
255 -                               if (next_fi != res->fi)
256 -                                       break;
257 -                       } else if (!fib_detect_death(fi, order, &last_resort,
258 -                                               &last_idx, tb->tb_default)) {
259 +                       if (!first_fa) {
260 +                               last_dflt = fa->fa_last_dflt;
261 +                               first_fa = fa;
262 +                       }
263 +                       if (fi && !fib_detect_death(fi, order, &last_resort,
264 +                               &last_idx, &last_dflt, &last_nhsel, flp)) {
265                                 fib_result_assign(res, fi);
266 -                               tb->tb_default = order;
267 +                               first_fa->fa_last_dflt = order;
268                                 goto out;
269                         }
270                         fi = next_fi;
271                         order++;
272                 }
273 +               break;
274         }
275  
276         if (order <= 0 || fi == NULL) {
277 -               tb->tb_default = -1;
278 +               if (fi && fi->fib_nhs > 1 &&
279 +                   fib_detect_death(fi, order, &last_resort, &last_idx,
280 +                       &last_dflt, &last_nhsel, flp) &&
281 +                   last_resort == fi) {
282 +                       read_lock_bh(&fib_nhflags_lock);
283 +                       fi->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
284 +                       read_unlock_bh(&fib_nhflags_lock);
285 +               }
286 +               if (first_fa) first_fa->fa_last_dflt = -1;
287                 goto out;
288         }
289  
290         if (!fib_detect_death(fi, order, &last_resort, &last_idx,
291 -                               tb->tb_default)) {
292 +                             &last_dflt, &last_nhsel, flp)) {
293                 fib_result_assign(res, fi);
294 -               tb->tb_default = order;
295 +               first_fa->fa_last_dflt = order;
296                 goto out;
297         }
298  
299 -       if (last_idx >= 0)
300 +       if (last_idx >= 0) {
301                 fib_result_assign(res, last_resort);
302 -       tb->tb_default = last_idx;
303 +               read_lock_bh(&fib_nhflags_lock);
304 +               last_resort->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
305 +               read_unlock_bh(&fib_nhflags_lock);
306 +               first_fa->fa_last_dflt = last_idx;
307 +       }
308  out:
309         read_unlock(&fib_hash_lock);
310  }
311 @@ -463,6 +487,7 @@ int fib_table_insert(struct fib_table *t
312                         write_lock_bh(&fib_hash_lock);
313                         fi_drop = fa->fa_info;
314                         fa->fa_info = fi;
315 +                       fa->fa_last_dflt = -1;
316                         fa->fa_type = cfg->fc_type;
317                         fa->fa_scope = cfg->fc_scope;
318                         state = fa->fa_state;
319 @@ -517,6 +542,7 @@ int fib_table_insert(struct fib_table *t
320         new_fa->fa_type = cfg->fc_type;
321         new_fa->fa_scope = cfg->fc_scope;
322         new_fa->fa_state = 0;
323 +       new_fa->fa_last_dflt = -1;
324  
325         /*
326          * Insert new entry to the list.
327 diff -urp v2.6.35/linux/net/ipv4/fib_lookup.h linux/net/ipv4/fib_lookup.h
328 --- v2.6.35/linux/net/ipv4/fib_lookup.h 2009-09-11 10:27:17.000000000 +0300
329 +++ linux/net/ipv4/fib_lookup.h 2010-08-03 00:24:10.000000000 +0300
330 @@ -8,6 +8,7 @@
331  struct fib_alias {
332         struct list_head        fa_list;
333         struct fib_info         *fa_info;
334 +       int                     fa_last_dflt;
335         u8                      fa_tos;
336         u8                      fa_type;
337         u8                      fa_scope;
338 @@ -37,7 +38,8 @@ extern struct fib_alias *fib_find_alias(
339                                         u8 tos, u32 prio);
340  extern int fib_detect_death(struct fib_info *fi, int order,
341                             struct fib_info **last_resort,
342 -                           int *last_idx, int dflt);
343 +                           int *last_idx, int *dflt, int *last_nhsel,
344 +                           const struct flowi *flp);
345  
346  static inline void fib_result_assign(struct fib_result *res,
347                                      struct fib_info *fi)
348 diff -urp v2.6.35/linux/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c
349 --- v2.6.35/linux/net/ipv4/fib_rules.c  2010-08-02 09:37:49.000000000 +0300
350 +++ linux/net/ipv4/fib_rules.c  2010-08-03 00:24:10.000000000 +0300
351 @@ -54,6 +54,11 @@ u32 fib_rules_tclass(struct fib_result *
352  }
353  #endif
354  
355 +int fib_result_table(struct fib_result *res)
356 +{
357 +       return res->r->table;
358 +}
359 +
360  int fib_lookup(struct net *net, struct flowi *flp, struct fib_result *res)
361  {
362         struct fib_lookup_arg arg = {
363 diff -urp v2.6.35/linux/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c
364 --- v2.6.35/linux/net/ipv4/fib_semantics.c      2010-05-17 10:49:01.000000000 +0300
365 +++ linux/net/ipv4/fib_semantics.c      2010-08-03 00:24:45.000000000 +0300
366 @@ -51,6 +51,7 @@ static struct hlist_head *fib_info_hash;
367  static struct hlist_head *fib_info_laddrhash;
368  static unsigned int fib_hash_size;
369  static unsigned int fib_info_cnt;
370 +rwlock_t fib_nhflags_lock = RW_LOCK_UNLOCKED;
371  
372  #define DEVINDEX_HASHBITS 8
373  #define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS)
374 @@ -187,7 +188,7 @@ static __inline__ int nh_comp(const stru
375  #ifdef CONFIG_NET_CLS_ROUTE
376                     nh->nh_tclassid != onh->nh_tclassid ||
377  #endif
378 -                   ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
379 +                   ((nh->nh_flags^onh->nh_flags)&~RTNH_F_BADSTATE))
380                         return -1;
381                 onh++;
382         } endfor_nexthops(fi);
383 @@ -238,7 +239,7 @@ static struct fib_info *fib_find_info(co
384                     nfi->fib_priority == fi->fib_priority &&
385                     memcmp(nfi->fib_metrics, fi->fib_metrics,
386                            sizeof(fi->fib_metrics)) == 0 &&
387 -                   ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
388 +                   ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_BADSTATE) == 0 &&
389                     (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
390                         return fi;
391         }
392 @@ -350,26 +351,70 @@ struct fib_alias *fib_find_alias(struct 
393  }
394  
395  int fib_detect_death(struct fib_info *fi, int order,
396 -                    struct fib_info **last_resort, int *last_idx, int dflt)
397 +                    struct fib_info **last_resort, int *last_idx, int *dflt,
398 +                    int *last_nhsel, const struct flowi *flp)
399  {
400         struct neighbour *n;
401 -       int state = NUD_NONE;
402 +       int nhsel;
403 +       int state;
404 +       struct fib_nh * nh;
405 +       __be32 dst;
406 +       int flag, dead = 1;
407 +
408 +       /* change_nexthops(fi) { */
409 +       for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) {
410 +               if (flp->oif && flp->oif != nh->nh_oif)
411 +                       continue;
412 +               if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw && nh->nh_gw &&
413 +                   nh->nh_scope == RT_SCOPE_LINK)
414 +                       continue;
415 +               if (nh->nh_flags & RTNH_F_DEAD)
416 +                       continue;
417  
418 -       n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev);
419 -       if (n) {
420 -               state = n->nud_state;
421 -               neigh_release(n);
422 -       }
423 -       if (state == NUD_REACHABLE)
424 -               return 0;
425 -       if ((state&NUD_VALID) && order != dflt)
426 -               return 0;
427 -       if ((state&NUD_VALID) ||
428 -           (*last_idx<0 && order > dflt)) {
429 -               *last_resort = fi;
430 -               *last_idx = order;
431 +               flag = 0;
432 +               if (nh->nh_dev->flags & IFF_NOARP) {
433 +                       dead = 0;
434 +                       goto setfl;
435 +               }
436 +
437 +               dst = nh->nh_gw;
438 +               if (!nh->nh_gw || nh->nh_scope != RT_SCOPE_LINK)
439 +                       dst = flp->fl4_dst;
440 +
441 +               state = NUD_NONE;
442 +               n = neigh_lookup(&arp_tbl, &dst, nh->nh_dev);
443 +               if (n) {
444 +                       state = n->nud_state;
445 +                       neigh_release(n);
446 +               }
447 +               if (state==NUD_REACHABLE ||
448 +                       ((state&NUD_VALID) && order != *dflt)) {
449 +                       dead = 0;
450 +                       goto setfl;
451 +               }
452 +               if (!(state&NUD_VALID))
453 +                       flag = 1;
454 +               if (!dead)
455 +                       goto setfl;
456 +               if ((state&NUD_VALID) ||
457 +                   (*last_idx<0 && order >= *dflt)) {
458 +                       *last_resort = fi;
459 +                       *last_idx = order;
460 +                       *last_nhsel = nhsel;
461 +               }
462 +
463 +               setfl:
464 +
465 +               read_lock_bh(&fib_nhflags_lock);
466 +               if (flag)
467 +                       nh->nh_flags |= RTNH_F_SUSPECT;
468 +               else
469 +                       nh->nh_flags &= ~RTNH_F_SUSPECT;
470 +               read_unlock_bh(&fib_nhflags_lock);
471         }
472 -       return 1;
473 +       /* } endfor_nexthops(fi) */
474 +
475 +       return dead;
476  }
477  
478  #ifdef CONFIG_IP_ROUTE_MULTIPATH
479 @@ -538,8 +583,11 @@ static int fib_check_nh(struct fib_confi
480                                 return -EINVAL;
481                         if ((dev = __dev_get_by_index(net, nh->nh_oif)) == NULL)
482                                 return -ENODEV;
483 -                       if (!(dev->flags&IFF_UP))
484 -                               return -ENETDOWN;
485 +                       if (!(dev->flags&IFF_UP)) {
486 +                               if (fi->fib_protocol != RTPROT_STATIC)
487 +                                       return -ENETDOWN;
488 +                               nh->nh_flags |= RTNH_F_DEAD;
489 +                       }
490                         nh->nh_dev = dev;
491                         dev_hold(dev);
492                         nh->nh_scope = RT_SCOPE_LINK;
493 @@ -559,24 +607,48 @@ static int fib_check_nh(struct fib_confi
494                         /* It is not necessary, but requires a bit of thinking */
495                         if (fl.fl4_scope < RT_SCOPE_LINK)
496                                 fl.fl4_scope = RT_SCOPE_LINK;
497 -                       if ((err = fib_lookup(net, &fl, &res)) != 0)
498 -                               return err;
499 +                       err = fib_lookup(net, &fl, &res);
500                 }
501 -               err = -EINVAL;
502 -               if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
503 -                       goto out;
504 -               nh->nh_scope = res.scope;
505 -               nh->nh_oif = FIB_RES_OIF(res);
506 -               if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
507 -                       goto out;
508 -               dev_hold(nh->nh_dev);
509 -               err = -ENETDOWN;
510 -               if (!(nh->nh_dev->flags & IFF_UP))
511 -                       goto out;
512 -               err = 0;
513 +               if (err) {
514 +                       struct in_device *in_dev;
515 +
516 +                       if (err != -ENETUNREACH ||
517 +                           fi->fib_protocol != RTPROT_STATIC)
518 +                               return err;
519 +
520 +                       in_dev = inetdev_by_index(net, nh->nh_oif);
521 +                       if (in_dev == NULL ||
522 +                           in_dev->dev->flags & IFF_UP) {
523 +                               if (in_dev)
524 +                                       in_dev_put(in_dev);
525 +                               return err;
526 +                       }
527 +                       nh->nh_flags |= RTNH_F_DEAD;
528 +                       nh->nh_scope = RT_SCOPE_LINK;
529 +                       nh->nh_dev = in_dev->dev;
530 +                       dev_hold(nh->nh_dev);
531 +                       in_dev_put(in_dev);
532 +               } else {
533 +                       err = -EINVAL;
534 +                       if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
535 +                               goto out;
536 +                       nh->nh_scope = res.scope;
537 +                       nh->nh_oif = FIB_RES_OIF(res);
538 +                       if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
539 +                               goto out;
540 +                       dev_hold(nh->nh_dev);
541 +                       if (!(nh->nh_dev->flags & IFF_UP)) {
542 +                               if (fi->fib_protocol != RTPROT_STATIC) {
543 +                                       err = -ENETDOWN;
544 +                                       goto out;
545 +                               }
546 +                               nh->nh_flags |= RTNH_F_DEAD;
547 +                       }
548 +                       err = 0;
549  out:
550 -               fib_res_put(&res);
551 -               return err;
552 +                       fib_res_put(&res);
553 +                       return err;
554 +               }
555         } else {
556                 struct in_device *in_dev;
557  
558 @@ -587,8 +659,11 @@ out:
559                 if (in_dev == NULL)
560                         return -ENODEV;
561                 if (!(in_dev->dev->flags&IFF_UP)) {
562 -                       in_dev_put(in_dev);
563 -                       return -ENETDOWN;
564 +                       if (fi->fib_protocol != RTPROT_STATIC) {
565 +                               in_dev_put(in_dev);
566 +                               return -ENETDOWN;
567 +                       }
568 +                       nh->nh_flags |= RTNH_F_DEAD;
569                 }
570                 nh->nh_dev = in_dev->dev;
571                 dev_hold(nh->nh_dev);
572 @@ -897,8 +972,12 @@ int fib_semantic_match(struct list_head 
573                                 for_nexthops(fi) {
574                                         if (nh->nh_flags&RTNH_F_DEAD)
575                                                 continue;
576 -                                       if (!flp->oif || flp->oif == nh->nh_oif)
577 -                                               break;
578 +                                       if (flp->oif && flp->oif != nh->nh_oif)
579 +                                               continue;
580 +                                       if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw &&
581 +                                           nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
582 +                                               continue;
583 +                                       break;
584                                 }
585  #ifdef CONFIG_IP_ROUTE_MULTIPATH
586                                 if (nhsel < fi->fib_nhs) {
587 @@ -1078,18 +1157,29 @@ int fib_sync_down_dev(struct net_device 
588                 prev_fi = fi;
589                 dead = 0;
590                 change_nexthops(fi) {
591 -                       if (nexthop_nh->nh_flags&RTNH_F_DEAD)
592 -                               dead++;
593 -                       else if (nexthop_nh->nh_dev == dev &&
594 -                                nexthop_nh->nh_scope != scope) {
595 -                               nexthop_nh->nh_flags |= RTNH_F_DEAD;
596 +                       if (nexthop_nh->nh_flags&RTNH_F_DEAD) {
597 +                               if (fi->fib_protocol!=RTPROT_STATIC ||
598 +                                   nexthop_nh->nh_dev == NULL ||
599 +                                   __in_dev_get_rtnl(nexthop_nh->nh_dev) == NULL ||
600 +                                   nexthop_nh->nh_dev->flags&IFF_UP)
601 +                                       dead++;
602 +                       } else if (nexthop_nh->nh_dev == dev &&
603 +                                  nexthop_nh->nh_scope != scope) {
604 +                               write_lock_bh(&fib_nhflags_lock);
605  #ifdef CONFIG_IP_ROUTE_MULTIPATH
606 -                               spin_lock_bh(&fib_multipath_lock);
607 +                               spin_lock(&fib_multipath_lock);
608 +                               nexthop_nh->nh_flags |= RTNH_F_DEAD;
609                                 fi->fib_power -= nexthop_nh->nh_power;
610                                 nexthop_nh->nh_power = 0;
611 -                               spin_unlock_bh(&fib_multipath_lock);
612 +                               spin_unlock(&fib_multipath_lock);
613 +#else
614 +                               nexthop_nh->nh_flags |= RTNH_F_DEAD;
615  #endif
616 -                               dead++;
617 +                               write_unlock_bh(&fib_nhflags_lock);
618 +                               if (fi->fib_protocol!=RTPROT_STATIC ||
619 +                                   force ||
620 +                                   __in_dev_get_rtnl(dev) == NULL)
621 +                                       dead++;
622                         }
623  #ifdef CONFIG_IP_ROUTE_MULTIPATH
624                         if (force > 1 && nexthop_nh->nh_dev == dev) {
625 @@ -1107,11 +1197,8 @@ int fib_sync_down_dev(struct net_device 
626         return ret;
627  }
628  
629 -#ifdef CONFIG_IP_ROUTE_MULTIPATH
630 -
631  /*
632 -   Dead device goes up. We wake up dead nexthops.
633 -   It takes sense only on multipath routes.
634 +   Dead device goes up or new address is added. We wake up dead nexthops.
635   */
636  
637  int fib_sync_up(struct net_device *dev)
638 @@ -1121,8 +1208,10 @@ int fib_sync_up(struct net_device *dev)
639         struct hlist_head *head;
640         struct hlist_node *node;
641         struct fib_nh *nh;
642 -       int ret;
643 +       struct fib_result res;
644 +       int ret, rep;
645  
646 +repeat:
647         if (!(dev->flags&IFF_UP))
648                 return 0;
649  
650 @@ -1130,6 +1219,7 @@ int fib_sync_up(struct net_device *dev)
651         hash = fib_devindex_hashfn(dev->ifindex);
652         head = &fib_info_devhash[hash];
653         ret = 0;
654 +       rep = 0;
655  
656         hlist_for_each_entry(nh, node, head, nh_hash) {
657                 struct fib_info *fi = nh->nh_parent;
658 @@ -1142,21 +1232,41 @@ int fib_sync_up(struct net_device *dev)
659                 prev_fi = fi;
660                 alive = 0;
661                 change_nexthops(fi) {
662 -                       if (!(nexthop_nh->nh_flags&RTNH_F_DEAD)) {
663 -                               alive++;
664 +                       if (!(nexthop_nh->nh_flags&RTNH_F_DEAD))
665                                 continue;
666 -                       }
667                         if (nexthop_nh->nh_dev == NULL ||
668                             !(nexthop_nh->nh_dev->flags&IFF_UP))
669                                 continue;
670                         if (nexthop_nh->nh_dev != dev ||
671                             !__in_dev_get_rtnl(dev))
672                                 continue;
673 +                       if (nexthop_nh->nh_gw && fi->fib_protocol == RTPROT_STATIC) {
674 +                               struct flowi fl = {
675 +                                       .nl_u = { .ip4_u =
676 +                                                 { .daddr = nexthop_nh->nh_gw,
677 +                                                   .scope = nexthop_nh->nh_scope } },
678 +                                       .oif =  nexthop_nh->nh_oif,
679 +                               };
680 +                               if (fib_lookup(dev_net(dev), &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 +                               nexthop_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                         nexthop_nh->nh_power = 0;
695 +#endif
696                         nexthop_nh->nh_flags &= ~RTNH_F_DEAD;
697 +#ifdef CONFIG_IP_ROUTE_MULTIPATH
698                         spin_unlock_bh(&fib_multipath_lock);
699 +#endif
700                 } endfor_nexthops(fi)
701  
702                 if (alive > 0) {
703 @@ -1164,10 +1274,14 @@ int fib_sync_up(struct net_device *dev)
704                         ret++;
705                 }
706         }
707 +       if (rep)
708 +               goto repeat;
709  
710         return ret;
711  }
712  
713 +#ifdef CONFIG_IP_ROUTE_MULTIPATH
714 +
715  /*
716     The algorithm is suboptimal, but it provides really
717     fair weighted route distribution.
718 @@ -1176,24 +1290,45 @@ int fib_sync_up(struct net_device *dev)
719  void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
720  {
721         struct fib_info *fi = res->fi;
722 -       int w;
723 +       int w, alive;
724  
725         spin_lock_bh(&fib_multipath_lock);
726 +       if (flp->oif) {
727 +               int sel = -1;
728 +               w = -1;
729 +               change_nexthops(fi) {
730 +                       if (flp->oif != nexthop_nh->nh_oif)
731 +                               continue;
732 +                       if (flp->fl4_gw && flp->fl4_gw != nexthop_nh->nh_gw &&
733 +                           nexthop_nh->nh_gw && nexthop_nh->nh_scope == RT_SCOPE_LINK)
734 +                               continue;
735 +                       if (!(nexthop_nh->nh_flags&RTNH_F_BADSTATE)) {
736 +                               if (nexthop_nh->nh_power > w) {
737 +                                       w = nexthop_nh->nh_power;
738 +                                       sel = nhsel;
739 +                               }
740 +                       }
741 +               } endfor_nexthops(fi);
742 +               if (sel >= 0) {
743 +                       spin_unlock_bh(&fib_multipath_lock);
744 +                       res->nh_sel = sel;
745 +                       return;
746 +               }
747 +               goto last_resort;
748 +       }
749 +
750 +repeat:
751         if (fi->fib_power <= 0) {
752                 int power = 0;
753                 change_nexthops(fi) {
754 -                       if (!(nexthop_nh->nh_flags&RTNH_F_DEAD)) {
755 +                       if (!(nexthop_nh->nh_flags&RTNH_F_BADSTATE)) {
756                                 power += nexthop_nh->nh_weight;
757                                 nexthop_nh->nh_power = nexthop_nh->nh_weight;
758                         }
759                 } endfor_nexthops(fi);
760                 fi->fib_power = power;
761 -               if (power <= 0) {
762 -                       spin_unlock_bh(&fib_multipath_lock);
763 -                       /* Race condition: route has just become dead. */
764 -                       res->nh_sel = 0;
765 -                       return;
766 -               }
767 +               if (power <= 0)
768 +                       goto last_resort;
769         }
770  
771  
772 @@ -1203,21 +1338,41 @@ void fib_select_multipath(const struct f
773  
774         w = jiffies % fi->fib_power;
775  
776 +       alive = 0;
777         change_nexthops(fi) {
778 -               if (!(nexthop_nh->nh_flags&RTNH_F_DEAD) &&
779 +               if (!(nexthop_nh->nh_flags&RTNH_F_BADSTATE) &&
780                     nexthop_nh->nh_power) {
781                         if ((w -= nexthop_nh->nh_power) <= 0) {
782                                 nexthop_nh->nh_power--;
783                                 fi->fib_power--;
784 -                               res->nh_sel = nhsel;
785                                 spin_unlock_bh(&fib_multipath_lock);
786 +                               res->nh_sel = nhsel;
787                                 return;
788                         }
789 +                       alive = 1;
790 +               }
791 +       } endfor_nexthops(fi);
792 +       if (alive) {
793 +               fi->fib_power = 0;
794 +               goto repeat;
795 +       }
796 +
797 +last_resort:
798 +
799 +       for_nexthops(fi) {
800 +               if (!(nh->nh_flags&RTNH_F_DEAD)) {
801 +                       if (flp->oif && flp->oif != nh->nh_oif)
802 +                               continue;
803 +                       if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw &&
804 +                           nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
805 +                               continue;
806 +                       spin_unlock_bh(&fib_multipath_lock);
807 +                       res->nh_sel = nhsel;
808 +                       return;
809                 }
810         } endfor_nexthops(fi);
811  
812         /* Race condition: route has just become dead. */
813 -       res->nh_sel = 0;
814         spin_unlock_bh(&fib_multipath_lock);
815  }
816  #endif
817 diff -urp v2.6.35/linux/net/ipv4/fib_trie.c linux/net/ipv4/fib_trie.c
818 --- v2.6.35/linux/net/ipv4/fib_trie.c   2010-08-02 09:37:49.000000000 +0300
819 +++ linux/net/ipv4/fib_trie.c   2010-08-03 00:24:10.000000000 +0300
820 @@ -1275,6 +1275,7 @@ int fib_table_insert(struct fib_table *t
821                         fi_drop = fa->fa_info;
822                         new_fa->fa_tos = fa->fa_tos;
823                         new_fa->fa_info = fi;
824 +                       new_fa->fa_last_dflt = -1;
825                         new_fa->fa_type = cfg->fc_type;
826                         new_fa->fa_scope = cfg->fc_scope;
827                         state = fa->fa_state;
828 @@ -1315,6 +1316,7 @@ int fib_table_insert(struct fib_table *t
829         new_fa->fa_type = cfg->fc_type;
830         new_fa->fa_scope = cfg->fc_scope;
831         new_fa->fa_state = 0;
832 +       new_fa->fa_last_dflt = -1;
833         /*
834          * Insert new entry to the list.
835          */
836 @@ -1815,24 +1817,31 @@ void fib_table_select_default(struct fib
837                               struct fib_result *res)
838  {
839         struct trie *t = (struct trie *) tb->tb_data;
840 -       int order, last_idx;
841 +       int order, last_idx, last_dflt, last_nhsel;
842 +       struct fib_alias *first_fa = NULL;
843         struct fib_info *fi = NULL;
844         struct fib_info *last_resort;
845         struct fib_alias *fa = NULL;
846         struct list_head *fa_head;
847         struct leaf *l;
848 +       u32 key, mask;
849  
850 +       last_dflt = -2;
851 +       last_nhsel = 0;
852         last_idx = -1;
853         last_resort = NULL;
854         order = -1;
855  
856 +       mask = inet_make_mask(res->prefixlen);
857 +       key = ntohl(flp->fl4_dst & mask);
858 +
859         rcu_read_lock();
860  
861 -       l = fib_find_node(t, 0);
862 +       l = fib_find_node(t, key);
863         if (!l)
864                 goto out;
865  
866 -       fa_head = get_fa_head(l, 0);
867 +       fa_head = get_fa_head(l, res->prefixlen);
868         if (!fa_head)
869                 goto out;
870  
871 @@ -1846,39 +1855,52 @@ void fib_table_select_default(struct fib
872                     fa->fa_type != RTN_UNICAST)
873                         continue;
874  
875 +               if (fa->fa_tos &&
876 +                   fa->fa_tos != flp->fl4_tos)
877 +                       continue;
878                 if (next_fi->fib_priority > res->fi->fib_priority)
879                         break;
880 -               if (!next_fi->fib_nh[0].nh_gw ||
881 -                   next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
882 -                       continue;
883                 fa->fa_state |= FA_S_ACCESSED;
884  
885 -               if (fi == NULL) {
886 -                       if (next_fi != res->fi)
887 -                               break;
888 -               } else if (!fib_detect_death(fi, order, &last_resort,
889 -                                            &last_idx, tb->tb_default)) {
890 +               if (!first_fa) {
891 +                       last_dflt = fa->fa_last_dflt;
892 +                       first_fa = fa;
893 +               }
894 +               if (fi && !fib_detect_death(fi, order, &last_resort,
895 +                   &last_idx, &last_dflt, &last_nhsel, flp)) {
896                         fib_result_assign(res, fi);
897 -                       tb->tb_default = order;
898 +                       first_fa->fa_last_dflt = order;
899                         goto out;
900                 }
901                 fi = next_fi;
902                 order++;
903         }
904         if (order <= 0 || fi == NULL) {
905 -               tb->tb_default = -1;
906 +               if (fi && fi->fib_nhs > 1 &&
907 +                   fib_detect_death(fi, order, &last_resort, &last_idx,
908 +                                    &last_dflt, &last_nhsel, flp) &&
909 +                   last_resort == fi) {
910 +                       read_lock_bh(&fib_nhflags_lock);
911 +                       fi->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
912 +                       read_unlock_bh(&fib_nhflags_lock);
913 +               }
914 +               if (first_fa) first_fa->fa_last_dflt = -1;
915                 goto out;
916         }
917  
918         if (!fib_detect_death(fi, order, &last_resort, &last_idx,
919 -                               tb->tb_default)) {
920 +                               &last_dflt, &last_nhsel, flp)) {
921                 fib_result_assign(res, fi);
922 -               tb->tb_default = order;
923 +               first_fa->fa_last_dflt = order;
924                 goto out;
925         }
926 -       if (last_idx >= 0)
927 +       if (last_idx >= 0) {
928                 fib_result_assign(res, last_resort);
929 -       tb->tb_default = last_idx;
930 +               read_lock_bh(&fib_nhflags_lock);
931 +               last_resort->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
932 +               read_unlock_bh(&fib_nhflags_lock);
933 +               first_fa->fa_last_dflt = last_idx;
934 +       }
935  out:
936         rcu_read_unlock();
937  }
938 diff -urp v2.6.35/linux/net/ipv4/netfilter/ipt_MASQUERADE.c linux/net/ipv4/netfilter/ipt_MASQUERADE.c
939 --- v2.6.35/linux/net/ipv4/netfilter/ipt_MASQUERADE.c   2010-08-02 09:37:49.000000000 +0300
940 +++ linux/net/ipv4/netfilter/ipt_MASQUERADE.c   2010-08-03 00:26:47.000000000 +0300
941 @@ -51,7 +51,7 @@ masquerade_tg(struct sk_buff *skb, const
942         enum ip_conntrack_info ctinfo;
943         struct nf_nat_range newrange;
944         const struct nf_nat_multi_range_compat *mr;
945 -       const struct rtable *rt;
946 +       struct rtable *rt;
947         __be32 newsrc;
948  
949         NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);
950 @@ -69,13 +69,29 @@ masquerade_tg(struct sk_buff *skb, const
951                 return NF_ACCEPT;
952  
953         mr = par->targinfo;
954 -       rt = skb_rtable(skb);
955 -       newsrc = inet_select_addr(par->out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
956 -       if (!newsrc) {
957 -               pr_info("%s ate my IP address\n", par->out->name);
958 -               return NF_DROP;
959 +
960 +       {
961 +               struct flowi fl = { .nl_u = { .ip4_u =
962 +                                             { .daddr = ip_hdr(skb)->daddr,
963 +                                               .tos = (RT_TOS(ip_hdr(skb)->tos) |
964 +                                                       RTO_CONN),
965 +                                               .gw = skb_rtable(skb)->rt_gateway,
966 +                                             } },
967 +                                   .mark = skb->mark,
968 +                                   .oif = par->out->ifindex };
969 +               if (ip_route_output_key(dev_net(par->out), &rt, &fl) != 0) {
970 +                       /* Funky routing can do this. */
971 +                       if (net_ratelimit())
972 +                               pr_info("%s:"
973 +                                      " No route: Rusty's brain broke!\n",
974 +                                      par->out->name);
975 +                       return NF_DROP;
976 +               }
977         }
978  
979 +       newsrc = rt->rt_src;
980 +       ip_rt_put(rt);
981 +
982         nat->masq_index = par->out->ifindex;
983  
984         /* Transfer from original range. */
985 diff -urp v2.6.35/linux/net/ipv4/netfilter/nf_nat_core.c linux/net/ipv4/netfilter/nf_nat_core.c
986 --- v2.6.35/linux/net/ipv4/netfilter/nf_nat_core.c      2010-05-17 10:49:01.000000000 +0300
987 +++ linux/net/ipv4/netfilter/nf_nat_core.c      2010-08-03 00:24:45.000000000 +0300
988 @@ -715,6 +715,52 @@ static struct pernet_operations nf_nat_n
989         .exit = nf_nat_net_exit,
990  };
991  
992 +unsigned int
993 +ip_nat_route_input(unsigned int hooknum,
994 +               struct sk_buff *skb,
995 +               const struct net_device *in,
996 +               const struct net_device *out,
997 +               int (*okfn)(struct sk_buff *))
998 +{
999 +       struct iphdr *iph;
1000 +       struct nf_conn *conn;
1001 +       enum ip_conntrack_info ctinfo;
1002 +       enum ip_conntrack_dir dir;
1003 +       unsigned long statusbit;
1004 +       __be32 saddr;
1005 +
1006 +       if (!(conn = nf_ct_get(skb, &ctinfo)))
1007 +               return NF_ACCEPT;
1008 +
1009 +       if (!(conn->status & IPS_NAT_DONE_MASK))
1010 +               return NF_ACCEPT;
1011 +       dir = CTINFO2DIR(ctinfo);
1012 +       statusbit = IPS_SRC_NAT;
1013 +       if (dir == IP_CT_DIR_REPLY)
1014 +               statusbit ^= IPS_NAT_MASK;
1015 +       if (!(conn->status & statusbit))
1016 +               return NF_ACCEPT;
1017 +
1018 +       if (skb_dst(skb))
1019 +               return NF_ACCEPT;
1020 +
1021 +       if (skb->len < sizeof(struct iphdr))
1022 +               return NF_ACCEPT;
1023 +
1024 +       /* use daddr in other direction as masquerade address (lsrc) */
1025 +       iph = ip_hdr(skb);
1026 +       saddr = conn->tuplehash[!dir].tuple.dst.u3.ip;
1027 +       if (saddr == iph->saddr)
1028 +               return NF_ACCEPT;
1029 +
1030 +       if (ip_route_input_lookup(skb, iph->daddr, iph->saddr, iph->tos,
1031 +           skb->dev, saddr))
1032 +               return NF_DROP;
1033 +
1034 +       return NF_ACCEPT;
1035 +}
1036 +EXPORT_SYMBOL_GPL(ip_nat_route_input);
1037 +
1038  static int __init nf_nat_init(void)
1039  {
1040         size_t i;
1041 diff -urp v2.6.35/linux/net/ipv4/netfilter/nf_nat_standalone.c linux/net/ipv4/netfilter/nf_nat_standalone.c
1042 --- v2.6.35/linux/net/ipv4/netfilter/nf_nat_standalone.c        2010-08-02 09:37:49.000000000 +0300
1043 +++ linux/net/ipv4/netfilter/nf_nat_standalone.c        2010-08-03 00:24:45.000000000 +0300
1044 @@ -255,6 +255,14 @@ static struct nf_hook_ops nf_nat_ops[] _
1045                 .hooknum        = NF_INET_PRE_ROUTING,
1046                 .priority       = NF_IP_PRI_NAT_DST,
1047         },
1048 +       /* Before routing, route before mangling */
1049 +       {
1050 +               .hook           = ip_nat_route_input,
1051 +               .owner          = THIS_MODULE,
1052 +               .pf             = NFPROTO_IPV4,
1053 +               .hooknum        = NF_INET_PRE_ROUTING,
1054 +               .priority       = NF_IP_PRI_LAST-1,
1055 +       },
1056         /* After packet filtering, change source */
1057         {
1058                 .hook           = nf_nat_out,
1059 diff -urp v2.6.35/linux/net/ipv4/route.c linux/net/ipv4/route.c
1060 --- v2.6.35/linux/net/ipv4/route.c      2010-08-02 09:37:49.000000000 +0300
1061 +++ linux/net/ipv4/route.c      2010-08-03 00:32:04.000000000 +0300
1062 @@ -694,6 +694,8 @@ static inline int compare_keys(struct fl
1063         return (((__force u32)fl1->nl_u.ip4_u.daddr ^ (__force u32)fl2->nl_u.ip4_u.daddr) |
1064                 ((__force u32)fl1->nl_u.ip4_u.saddr ^ (__force u32)fl2->nl_u.ip4_u.saddr) |
1065                 (fl1->mark ^ fl2->mark) |
1066 +               ((__force u32)fl1->nl_u.ip4_u.lsrc ^ (__force u32)fl2->nl_u.ip4_u.lsrc) |
1067 +               ((__force u32)fl1->nl_u.ip4_u.gw ^ (__force u32)fl2->nl_u.ip4_u.gw) |
1068                 (*(u16 *)&fl1->nl_u.ip4_u.tos ^ *(u16 *)&fl2->nl_u.ip4_u.tos) |
1069                 (fl1->oif ^ fl2->oif) |
1070                 (fl1->iif ^ fl2->iif)) == 0;
1071 @@ -1437,6 +1439,7 @@ void ip_rt_redirect(__be32 old_gw, __be3
1072  
1073                                 /* Gateway is different ... */
1074                                 rt->rt_gateway          = new_gw;
1075 +                               if (rt->fl.fl4_gw) rt->fl.fl4_gw = new_gw;
1076  
1077                                 /* Redirect received -> path was valid */
1078                                 dst_confirm(&rth->u.dst);
1079 @@ -1886,6 +1889,7 @@ static int ip_route_input_mc(struct sk_b
1080         rth->fl.fl4_tos = tos;
1081         rth->fl.mark    = skb->mark;
1082         rth->fl.fl4_src = saddr;
1083 +       rth->fl.fl4_lsrc = 0;
1084         rth->rt_src     = saddr;
1085  #ifdef CONFIG_NET_CLS_ROUTE
1086         rth->u.dst.tclassid = itag;
1087 @@ -1896,6 +1900,7 @@ static int ip_route_input_mc(struct sk_b
1088         dev_hold(rth->u.dst.dev);
1089         rth->idev       = in_dev_get(rth->u.dst.dev);
1090         rth->fl.oif     = 0;
1091 +       rth->fl.fl4_gw  = 0;
1092         rth->rt_gateway = daddr;
1093         rth->rt_spec_dst= spec_dst;
1094         rth->rt_genid   = rt_genid(dev_net(dev));
1095 @@ -1960,7 +1965,7 @@ static int __mkroute_input(struct sk_buf
1096                            struct fib_result *res,
1097                            struct in_device *in_dev,
1098                            __be32 daddr, __be32 saddr, u32 tos,
1099 -                          struct rtable **result)
1100 +                          __be32 lsrc, struct rtable **result)
1101  {
1102  
1103         struct rtable *rth;
1104 @@ -1994,6 +1999,7 @@ static int __mkroute_input(struct sk_buf
1105                 flags |= RTCF_DIRECTSRC;
1106  
1107         if (out_dev == in_dev && err &&
1108 +           !lsrc &&
1109             (IN_DEV_SHARED_MEDIA(out_dev) ||
1110              inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
1111                 flags |= RTCF_DOREDIRECT;
1112 @@ -2032,6 +2038,7 @@ static int __mkroute_input(struct sk_buf
1113         rth->fl.mark    = skb->mark;
1114         rth->fl.fl4_src = saddr;
1115         rth->rt_src     = saddr;
1116 +       rth->fl.fl4_lsrc        = lsrc;
1117         rth->rt_gateway = daddr;
1118         rth->rt_iif     =
1119                 rth->fl.iif     = in_dev->dev->ifindex;
1120 @@ -2039,6 +2046,7 @@ static int __mkroute_input(struct sk_buf
1121         dev_hold(rth->u.dst.dev);
1122         rth->idev       = in_dev_get(rth->u.dst.dev);
1123         rth->fl.oif     = 0;
1124 +       rth->fl.fl4_gw  = 0;
1125         rth->rt_spec_dst= spec_dst;
1126  
1127         rth->u.dst.obsolete = -1;
1128 @@ -2060,21 +2068,23 @@ static int __mkroute_input(struct sk_buf
1129  
1130  static int ip_mkroute_input(struct sk_buff *skb,
1131                             struct fib_result *res,
1132 +                           struct net *net,
1133                             const struct flowi *fl,
1134                             struct in_device *in_dev,
1135 -                           __be32 daddr, __be32 saddr, u32 tos)
1136 +                           __be32 daddr, __be32 saddr, u32 tos, __be32 lsrc)
1137  {
1138         struct rtable* rth = NULL;
1139         int err;
1140         unsigned hash;
1141  
1142 +       fib_select_default(net, fl, res);
1143  #ifdef CONFIG_IP_ROUTE_MULTIPATH
1144 -       if (res->fi && res->fi->fib_nhs > 1 && fl->oif == 0)
1145 +       if (res->fi && res->fi->fib_nhs > 1)
1146                 fib_select_multipath(fl, res);
1147  #endif
1148  
1149         /* create a routing cache entry */
1150 -       err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);
1151 +       err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, lsrc, &rth);
1152         if (err)
1153                 return err;
1154  
1155 @@ -2095,18 +2105,19 @@ static int ip_mkroute_input(struct sk_bu
1156   */
1157  
1158  static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1159 -                              u8 tos, struct net_device *dev)
1160 +                              u8 tos, struct net_device *dev, __be32 lsrc)
1161  {
1162         struct fib_result res;
1163         struct in_device *in_dev = in_dev_get(dev);
1164         struct flowi fl = { .nl_u = { .ip4_u =
1165                                       { .daddr = daddr,
1166 -                                       .saddr = saddr,
1167 +                                       .saddr = lsrc? : saddr,
1168                                         .tos = tos,
1169                                         .scope = RT_SCOPE_UNIVERSE,
1170                                       } },
1171                             .mark = skb->mark,
1172 -                           .iif = dev->ifindex };
1173 +                           .iif = lsrc?
1174 +                               dev_net(dev)->loopback_dev->ifindex : dev->ifindex };
1175         unsigned        flags = 0;
1176         u32             itag = 0;
1177         struct rtable * rth;
1178 @@ -2142,6 +2153,12 @@ static int ip_route_input_slow(struct sk
1179             ipv4_is_loopback(daddr))
1180                 goto martian_destination;
1181  
1182 +       if (lsrc) {
1183 +               if (ipv4_is_multicast(lsrc) || ipv4_is_lbcast(lsrc) ||
1184 +                   ipv4_is_zeronet(lsrc) || ipv4_is_loopback(lsrc))
1185 +                       goto e_inval;
1186 +       }
1187 +
1188         /*
1189          *      Now we are ready to route packet.
1190          */
1191 @@ -2151,6 +2168,8 @@ static int ip_route_input_slow(struct sk
1192                 goto no_route;
1193         }
1194         free_res = 1;
1195 +       fl.iif = dev->ifindex;
1196 +       fl.fl4_src = saddr;
1197  
1198         RT_CACHE_STAT_INC(in_slow_tot);
1199  
1200 @@ -2175,7 +2194,7 @@ static int ip_route_input_slow(struct sk
1201         if (res.type != RTN_UNICAST)
1202                 goto martian_destination;
1203  
1204 -       err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
1205 +       err = ip_mkroute_input(skb, &res, net, &fl, in_dev, daddr, saddr, tos, lsrc);
1206  done:
1207         in_dev_put(in_dev);
1208         if (free_res)
1209 @@ -2185,6 +2204,8 @@ out:      return err;
1210  brd_input:
1211         if (skb->protocol != htons(ETH_P_IP))
1212                 goto e_inval;
1213 +       if (lsrc)
1214 +               goto e_inval;
1215  
1216         if (ipv4_is_zeronet(saddr))
1217                 spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
1218 @@ -2227,6 +2248,7 @@ local_input:
1219         rth->u.dst.dev  = net->loopback_dev;
1220         dev_hold(rth->u.dst.dev);
1221         rth->idev       = in_dev_get(rth->u.dst.dev);
1222 +       rth->fl.fl4_gw  = 0;
1223         rth->rt_gateway = daddr;
1224         rth->rt_spec_dst= spec_dst;
1225         rth->u.dst.input= ip_local_deliver;
1226 @@ -2277,8 +2299,9 @@ martian_source:
1227         goto e_inval;
1228  }
1229  
1230 -int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1231 -                          u8 tos, struct net_device *dev, bool noref)
1232 +int ip_route_input_cached(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1233 +                          u8 tos, struct net_device *dev, bool noref,
1234 +                          __be32 lsrc)
1235  {
1236         struct rtable * rth;
1237         unsigned        hash;
1238 @@ -2299,6 +2322,7 @@ int ip_route_input_common(struct sk_buff
1239                 if ((((__force u32)rth->fl.fl4_dst ^ (__force u32)daddr) |
1240                      ((__force u32)rth->fl.fl4_src ^ (__force u32)saddr) |
1241                      (rth->fl.iif ^ iif) |
1242 +                    (rth->fl.fl4_lsrc ^ lsrc) |
1243                      rth->fl.oif |
1244                      (rth->fl.fl4_tos ^ tos)) == 0 &&
1245                     rth->fl.mark == skb->mark &&
1246 @@ -2353,10 +2377,22 @@ skip_cache:
1247                 rcu_read_unlock();
1248                 return -EINVAL;
1249         }
1250 -       return ip_route_input_slow(skb, daddr, saddr, tos, dev);
1251 +       return ip_route_input_slow(skb, daddr, saddr, tos, dev, lsrc);
1252 +}
1253 +
1254 +int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1255 +                  u8 tos, struct net_device *dev, bool noref)
1256 +{
1257 +       return ip_route_input_cached(skb, daddr, saddr, tos, dev, noref, 0);
1258  }
1259  EXPORT_SYMBOL(ip_route_input_common);
1260  
1261 +int ip_route_input_lookup(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1262 +                         u8 tos, struct net_device *dev, __be32 lsrc)
1263 +{
1264 +       return ip_route_input_cached(skb, daddr, saddr, tos, dev, true, lsrc);
1265 +}
1266 +
1267  static int __mkroute_output(struct rtable **result,
1268                             struct fib_result *res,
1269                             const struct flowi *fl,
1270 @@ -2426,6 +2462,7 @@ static int __mkroute_output(struct rtabl
1271         rth->fl.fl4_tos = tos;
1272         rth->fl.fl4_src = oldflp->fl4_src;
1273         rth->fl.oif     = oldflp->oif;
1274 +       rth->fl.fl4_gw  = oldflp->fl4_gw;
1275         rth->fl.mark    = oldflp->mark;
1276         rth->rt_dst     = fl->fl4_dst;
1277         rth->rt_src     = fl->fl4_src;
1278 @@ -2508,6 +2545,7 @@ static int ip_route_output_slow(struct n
1279         struct flowi fl = { .nl_u = { .ip4_u =
1280                                       { .daddr = oldflp->fl4_dst,
1281                                         .saddr = oldflp->fl4_src,
1282 +                                       .gw = oldflp->fl4_gw,
1283                                         .tos = tos & IPTOS_RT_MASK,
1284                                         .scope = ((tos & RTO_ONLINK) ?
1285                                                   RT_SCOPE_LINK :
1286 @@ -2619,6 +2657,7 @@ static int ip_route_output_slow(struct n
1287                 dev_out = net->loopback_dev;
1288                 dev_hold(dev_out);
1289                 fl.oif = net->loopback_dev->ifindex;
1290 +               fl.fl4_gw = 0;
1291                 res.type = RTN_LOCAL;
1292                 flags |= RTCF_LOCAL;
1293                 goto make_route;
1294 @@ -2626,7 +2665,7 @@ static int ip_route_output_slow(struct n
1295  
1296         if (fib_lookup(net, &fl, &res)) {
1297                 res.fi = NULL;
1298 -               if (oldflp->oif) {
1299 +               if (oldflp->oif && dev_out->flags & IFF_UP) {
1300                         /* Apparently, routing tables are wrong. Assume,
1301                            that the destination is on link.
1302  
1303 @@ -2666,6 +2705,7 @@ static int ip_route_output_slow(struct n
1304                 dev_out = net->loopback_dev;
1305                 dev_hold(dev_out);
1306                 fl.oif = dev_out->ifindex;
1307 +               fl.fl4_gw = 0;
1308                 if (res.fi)
1309                         fib_info_put(res.fi);
1310                 res.fi = NULL;
1311 @@ -2673,13 +2713,12 @@ static int ip_route_output_slow(struct n
1312                 goto make_route;
1313         }
1314  
1315 +       if (res.type == RTN_UNICAST)
1316 +               fib_select_default(net, &fl, &res);
1317  #ifdef CONFIG_IP_ROUTE_MULTIPATH
1318 -       if (res.fi->fib_nhs > 1 && fl.oif == 0)
1319 +       if (res.fi->fib_nhs > 1)
1320                 fib_select_multipath(&fl, &res);
1321 -       else
1322  #endif
1323 -       if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif)
1324 -               fib_select_default(net, &fl, &res);
1325  
1326         if (!fl.fl4_src)
1327                 fl.fl4_src = FIB_RES_PREFSRC(res);
1328 @@ -2720,6 +2759,7 @@ int __ip_route_output_key(struct net *ne
1329                     rth->fl.fl4_src == flp->fl4_src &&
1330                     rth->fl.iif == 0 &&
1331                     rth->fl.oif == flp->oif &&
1332 +                   rth->fl.fl4_gw == flp->fl4_gw &&
1333                     rth->fl.mark == flp->mark &&
1334                     !((rth->fl.fl4_tos ^ flp->fl4_tos) &
1335                             (IPTOS_RT_MASK | RTO_ONLINK)) &&
1336 @@ -3368,3 +3408,4 @@ void __init ip_static_sysctl_init(void)
1337  
1338  EXPORT_SYMBOL(__ip_select_ident);
1339  EXPORT_SYMBOL(ip_route_output_key);
1340 +EXPORT_SYMBOL(ip_route_input_lookup);
This page took 0.118579 seconds and 3 git commands to generate.