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