diff options
Diffstat (limited to 'net/ipv4/route.c')
| -rw-r--r-- | net/ipv4/route.c | 154 |
1 files changed, 33 insertions, 121 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index cb562fdd9b9a..560acc677ce4 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
| @@ -129,7 +129,6 @@ static int ip_rt_gc_elasticity __read_mostly = 8; | |||
| 129 | static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; | 129 | static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; |
| 130 | static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; | 130 | static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; |
| 131 | static int ip_rt_min_advmss __read_mostly = 256; | 131 | static int ip_rt_min_advmss __read_mostly = 256; |
| 132 | static int ip_rt_secret_interval __read_mostly = 10 * 60 * HZ; | ||
| 133 | static int rt_chain_length_max __read_mostly = 20; | 132 | static int rt_chain_length_max __read_mostly = 20; |
| 134 | 133 | ||
| 135 | static struct delayed_work expires_work; | 134 | static struct delayed_work expires_work; |
| @@ -258,10 +257,9 @@ static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat); | |||
| 258 | (__raw_get_cpu_var(rt_cache_stat).field++) | 257 | (__raw_get_cpu_var(rt_cache_stat).field++) |
| 259 | 258 | ||
| 260 | static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx, | 259 | static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx, |
| 261 | int genid) | 260 | int genid) |
| 262 | { | 261 | { |
| 263 | return jhash_3words((__force u32)(__be32)(daddr), | 262 | return jhash_3words((__force u32)daddr, (__force u32)saddr, |
| 264 | (__force u32)(__be32)(saddr), | ||
| 265 | idx, genid) | 263 | idx, genid) |
| 266 | & rt_hash_mask; | 264 | & rt_hash_mask; |
| 267 | } | 265 | } |
| @@ -378,12 +376,13 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) | |||
| 378 | struct rtable *r = v; | 376 | struct rtable *r = v; |
| 379 | int len; | 377 | int len; |
| 380 | 378 | ||
| 381 | seq_printf(seq, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t" | 379 | seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t" |
| 382 | "%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n", | 380 | "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n", |
| 383 | r->u.dst.dev ? r->u.dst.dev->name : "*", | 381 | r->u.dst.dev ? r->u.dst.dev->name : "*", |
| 384 | (unsigned long)r->rt_dst, (unsigned long)r->rt_gateway, | 382 | (__force u32)r->rt_dst, |
| 383 | (__force u32)r->rt_gateway, | ||
| 385 | r->rt_flags, atomic_read(&r->u.dst.__refcnt), | 384 | r->rt_flags, atomic_read(&r->u.dst.__refcnt), |
| 386 | r->u.dst.__use, 0, (unsigned long)r->rt_src, | 385 | r->u.dst.__use, 0, (__force u32)r->rt_src, |
| 387 | (dst_metric(&r->u.dst, RTAX_ADVMSS) ? | 386 | (dst_metric(&r->u.dst, RTAX_ADVMSS) ? |
| 388 | (int)dst_metric(&r->u.dst, RTAX_ADVMSS) + 40 : 0), | 387 | (int)dst_metric(&r->u.dst, RTAX_ADVMSS) + 40 : 0), |
| 389 | dst_metric(&r->u.dst, RTAX_WINDOW), | 388 | dst_metric(&r->u.dst, RTAX_WINDOW), |
| @@ -685,18 +684,17 @@ static inline bool rt_caching(const struct net *net) | |||
| 685 | static inline bool compare_hash_inputs(const struct flowi *fl1, | 684 | static inline bool compare_hash_inputs(const struct flowi *fl1, |
| 686 | const struct flowi *fl2) | 685 | const struct flowi *fl2) |
| 687 | { | 686 | { |
| 688 | return (__force u32)(((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | | 687 | return ((((__force u32)fl1->nl_u.ip4_u.daddr ^ (__force u32)fl2->nl_u.ip4_u.daddr) | |
| 689 | (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) | | 688 | ((__force u32)fl1->nl_u.ip4_u.saddr ^ (__force u32)fl2->nl_u.ip4_u.saddr) | |
| 690 | (fl1->iif ^ fl2->iif)) == 0); | 689 | (fl1->iif ^ fl2->iif)) == 0); |
| 691 | } | 690 | } |
| 692 | 691 | ||
| 693 | static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) | 692 | static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) |
| 694 | { | 693 | { |
| 695 | return ((__force u32)((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | | 694 | return (((__force u32)fl1->nl_u.ip4_u.daddr ^ (__force u32)fl2->nl_u.ip4_u.daddr) | |
| 696 | (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr)) | | 695 | ((__force u32)fl1->nl_u.ip4_u.saddr ^ (__force u32)fl2->nl_u.ip4_u.saddr) | |
| 697 | (fl1->mark ^ fl2->mark) | | 696 | (fl1->mark ^ fl2->mark) | |
| 698 | (*(u16 *)&fl1->nl_u.ip4_u.tos ^ | 697 | (*(u16 *)&fl1->nl_u.ip4_u.tos ^ *(u16 *)&fl2->nl_u.ip4_u.tos) | |
| 699 | *(u16 *)&fl2->nl_u.ip4_u.tos) | | ||
| 700 | (fl1->oif ^ fl2->oif) | | 698 | (fl1->oif ^ fl2->oif) | |
| 701 | (fl1->iif ^ fl2->iif)) == 0; | 699 | (fl1->iif ^ fl2->iif)) == 0; |
| 702 | } | 700 | } |
| @@ -919,32 +917,11 @@ void rt_cache_flush_batch(void) | |||
| 919 | rt_do_flush(!in_softirq()); | 917 | rt_do_flush(!in_softirq()); |
| 920 | } | 918 | } |
| 921 | 919 | ||
| 922 | /* | ||
| 923 | * We change rt_genid and let gc do the cleanup | ||
| 924 | */ | ||
| 925 | static void rt_secret_rebuild(unsigned long __net) | ||
| 926 | { | ||
| 927 | struct net *net = (struct net *)__net; | ||
| 928 | rt_cache_invalidate(net); | ||
| 929 | mod_timer(&net->ipv4.rt_secret_timer, jiffies + ip_rt_secret_interval); | ||
| 930 | } | ||
| 931 | |||
| 932 | static void rt_secret_rebuild_oneshot(struct net *net) | ||
| 933 | { | ||
| 934 | del_timer_sync(&net->ipv4.rt_secret_timer); | ||
| 935 | rt_cache_invalidate(net); | ||
| 936 | if (ip_rt_secret_interval) | ||
| 937 | mod_timer(&net->ipv4.rt_secret_timer, jiffies + ip_rt_secret_interval); | ||
| 938 | } | ||
| 939 | |||
| 940 | static void rt_emergency_hash_rebuild(struct net *net) | 920 | static void rt_emergency_hash_rebuild(struct net *net) |
| 941 | { | 921 | { |
| 942 | if (net_ratelimit()) { | 922 | if (net_ratelimit()) |
| 943 | printk(KERN_WARNING "Route hash chain too long!\n"); | 923 | printk(KERN_WARNING "Route hash chain too long!\n"); |
| 944 | printk(KERN_WARNING "Adjust your secret_interval!\n"); | 924 | rt_cache_invalidate(net); |
| 945 | } | ||
| 946 | |||
| 947 | rt_secret_rebuild_oneshot(net); | ||
| 948 | } | 925 | } |
| 949 | 926 | ||
| 950 | /* | 927 | /* |
| @@ -2300,8 +2277,8 @@ martian_source: | |||
| 2300 | goto e_inval; | 2277 | goto e_inval; |
| 2301 | } | 2278 | } |
| 2302 | 2279 | ||
| 2303 | int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, | 2280 | int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr, |
| 2304 | u8 tos, struct net_device *dev) | 2281 | u8 tos, struct net_device *dev, bool noref) |
| 2305 | { | 2282 | { |
| 2306 | struct rtable * rth; | 2283 | struct rtable * rth; |
| 2307 | unsigned hash; | 2284 | unsigned hash; |
| @@ -2319,18 +2296,23 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
| 2319 | rcu_read_lock(); | 2296 | rcu_read_lock(); |
| 2320 | for (rth = rcu_dereference(rt_hash_table[hash].chain); rth; | 2297 | for (rth = rcu_dereference(rt_hash_table[hash].chain); rth; |
| 2321 | rth = rcu_dereference(rth->u.dst.rt_next)) { | 2298 | rth = rcu_dereference(rth->u.dst.rt_next)) { |
| 2322 | if (((rth->fl.fl4_dst ^ daddr) | | 2299 | if ((((__force u32)rth->fl.fl4_dst ^ (__force u32)daddr) | |
| 2323 | (rth->fl.fl4_src ^ saddr) | | 2300 | ((__force u32)rth->fl.fl4_src ^ (__force u32)saddr) | |
| 2324 | (rth->fl.iif ^ iif) | | 2301 | (rth->fl.iif ^ iif) | |
| 2325 | rth->fl.oif | | 2302 | rth->fl.oif | |
| 2326 | (rth->fl.fl4_tos ^ tos)) == 0 && | 2303 | (rth->fl.fl4_tos ^ tos)) == 0 && |
| 2327 | rth->fl.mark == skb->mark && | 2304 | rth->fl.mark == skb->mark && |
| 2328 | net_eq(dev_net(rth->u.dst.dev), net) && | 2305 | net_eq(dev_net(rth->u.dst.dev), net) && |
| 2329 | !rt_is_expired(rth)) { | 2306 | !rt_is_expired(rth)) { |
| 2330 | dst_use(&rth->u.dst, jiffies); | 2307 | if (noref) { |
| 2308 | dst_use_noref(&rth->u.dst, jiffies); | ||
| 2309 | skb_dst_set_noref(skb, &rth->u.dst); | ||
| 2310 | } else { | ||
| 2311 | dst_use(&rth->u.dst, jiffies); | ||
| 2312 | skb_dst_set(skb, &rth->u.dst); | ||
| 2313 | } | ||
| 2331 | RT_CACHE_STAT_INC(in_hit); | 2314 | RT_CACHE_STAT_INC(in_hit); |
| 2332 | rcu_read_unlock(); | 2315 | rcu_read_unlock(); |
| 2333 | skb_dst_set(skb, &rth->u.dst); | ||
| 2334 | return 0; | 2316 | return 0; |
| 2335 | } | 2317 | } |
| 2336 | RT_CACHE_STAT_INC(in_hlist_search); | 2318 | RT_CACHE_STAT_INC(in_hlist_search); |
| @@ -2373,6 +2355,7 @@ skip_cache: | |||
| 2373 | } | 2355 | } |
| 2374 | return ip_route_input_slow(skb, daddr, saddr, tos, dev); | 2356 | return ip_route_input_slow(skb, daddr, saddr, tos, dev); |
| 2375 | } | 2357 | } |
| 2358 | EXPORT_SYMBOL(ip_route_input_common); | ||
| 2376 | 2359 | ||
| 2377 | static int __mkroute_output(struct rtable **result, | 2360 | static int __mkroute_output(struct rtable **result, |
| 2378 | struct fib_result *res, | 2361 | struct fib_result *res, |
| @@ -3056,7 +3039,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 3056 | continue; | 3039 | continue; |
| 3057 | if (rt_is_expired(rt)) | 3040 | if (rt_is_expired(rt)) |
| 3058 | continue; | 3041 | continue; |
| 3059 | skb_dst_set(skb, dst_clone(&rt->u.dst)); | 3042 | skb_dst_set_noref(skb, &rt->u.dst); |
| 3060 | if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid, | 3043 | if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid, |
| 3061 | cb->nlh->nlmsg_seq, RTM_NEWROUTE, | 3044 | cb->nlh->nlmsg_seq, RTM_NEWROUTE, |
| 3062 | 1, NLM_F_MULTI) <= 0) { | 3045 | 1, NLM_F_MULTI) <= 0) { |
| @@ -3102,48 +3085,6 @@ static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write, | |||
| 3102 | return -EINVAL; | 3085 | return -EINVAL; |
| 3103 | } | 3086 | } |
| 3104 | 3087 | ||
| 3105 | static void rt_secret_reschedule(int old) | ||
| 3106 | { | ||
| 3107 | struct net *net; | ||
| 3108 | int new = ip_rt_secret_interval; | ||
| 3109 | int diff = new - old; | ||
| 3110 | |||
| 3111 | if (!diff) | ||
| 3112 | return; | ||
| 3113 | |||
| 3114 | rtnl_lock(); | ||
| 3115 | for_each_net(net) { | ||
| 3116 | int deleted = del_timer_sync(&net->ipv4.rt_secret_timer); | ||
| 3117 | long time; | ||
| 3118 | |||
| 3119 | if (!new) | ||
| 3120 | continue; | ||
| 3121 | |||
| 3122 | if (deleted) { | ||
| 3123 | time = net->ipv4.rt_secret_timer.expires - jiffies; | ||
| 3124 | |||
| 3125 | if (time <= 0 || (time += diff) <= 0) | ||
| 3126 | time = 0; | ||
| 3127 | } else | ||
| 3128 | time = new; | ||
| 3129 | |||
| 3130 | mod_timer(&net->ipv4.rt_secret_timer, jiffies + time); | ||
| 3131 | } | ||
| 3132 | rtnl_unlock(); | ||
| 3133 | } | ||
| 3134 | |||
| 3135 | static int ipv4_sysctl_rt_secret_interval(ctl_table *ctl, int write, | ||
| 3136 | void __user *buffer, size_t *lenp, | ||
| 3137 | loff_t *ppos) | ||
| 3138 | { | ||
| 3139 | int old = ip_rt_secret_interval; | ||
| 3140 | int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); | ||
| 3141 | |||
| 3142 | rt_secret_reschedule(old); | ||
| 3143 | |||
| 3144 | return ret; | ||
| 3145 | } | ||
| 3146 | |||
| 3147 | static ctl_table ipv4_route_table[] = { | 3088 | static ctl_table ipv4_route_table[] = { |
| 3148 | { | 3089 | { |
| 3149 | .procname = "gc_thresh", | 3090 | .procname = "gc_thresh", |
| @@ -3252,13 +3193,6 @@ static ctl_table ipv4_route_table[] = { | |||
| 3252 | .mode = 0644, | 3193 | .mode = 0644, |
| 3253 | .proc_handler = proc_dointvec, | 3194 | .proc_handler = proc_dointvec, |
| 3254 | }, | 3195 | }, |
| 3255 | { | ||
| 3256 | .procname = "secret_interval", | ||
| 3257 | .data = &ip_rt_secret_interval, | ||
| 3258 | .maxlen = sizeof(int), | ||
| 3259 | .mode = 0644, | ||
| 3260 | .proc_handler = ipv4_sysctl_rt_secret_interval, | ||
| 3261 | }, | ||
| 3262 | { } | 3196 | { } |
| 3263 | }; | 3197 | }; |
| 3264 | 3198 | ||
| @@ -3337,34 +3271,15 @@ static __net_initdata struct pernet_operations sysctl_route_ops = { | |||
| 3337 | }; | 3271 | }; |
| 3338 | #endif | 3272 | #endif |
| 3339 | 3273 | ||
| 3340 | 3274 | static __net_init int rt_genid_init(struct net *net) | |
| 3341 | static __net_init int rt_secret_timer_init(struct net *net) | ||
| 3342 | { | 3275 | { |
| 3343 | atomic_set(&net->ipv4.rt_genid, | 3276 | get_random_bytes(&net->ipv4.rt_genid, |
| 3344 | (int) ((num_physpages ^ (num_physpages>>8)) ^ | 3277 | sizeof(net->ipv4.rt_genid)); |
| 3345 | (jiffies ^ (jiffies >> 7)))); | ||
| 3346 | |||
| 3347 | net->ipv4.rt_secret_timer.function = rt_secret_rebuild; | ||
| 3348 | net->ipv4.rt_secret_timer.data = (unsigned long)net; | ||
| 3349 | init_timer_deferrable(&net->ipv4.rt_secret_timer); | ||
| 3350 | |||
| 3351 | if (ip_rt_secret_interval) { | ||
| 3352 | net->ipv4.rt_secret_timer.expires = | ||
| 3353 | jiffies + net_random() % ip_rt_secret_interval + | ||
| 3354 | ip_rt_secret_interval; | ||
| 3355 | add_timer(&net->ipv4.rt_secret_timer); | ||
| 3356 | } | ||
| 3357 | return 0; | 3278 | return 0; |
| 3358 | } | 3279 | } |
| 3359 | 3280 | ||
| 3360 | static __net_exit void rt_secret_timer_exit(struct net *net) | 3281 | static __net_initdata struct pernet_operations rt_genid_ops = { |
| 3361 | { | 3282 | .init = rt_genid_init, |
| 3362 | del_timer_sync(&net->ipv4.rt_secret_timer); | ||
| 3363 | } | ||
| 3364 | |||
| 3365 | static __net_initdata struct pernet_operations rt_secret_timer_ops = { | ||
| 3366 | .init = rt_secret_timer_init, | ||
| 3367 | .exit = rt_secret_timer_exit, | ||
| 3368 | }; | 3283 | }; |
| 3369 | 3284 | ||
| 3370 | 3285 | ||
| @@ -3425,9 +3340,6 @@ int __init ip_rt_init(void) | |||
| 3425 | schedule_delayed_work(&expires_work, | 3340 | schedule_delayed_work(&expires_work, |
| 3426 | net_random() % ip_rt_gc_interval + ip_rt_gc_interval); | 3341 | net_random() % ip_rt_gc_interval + ip_rt_gc_interval); |
| 3427 | 3342 | ||
| 3428 | if (register_pernet_subsys(&rt_secret_timer_ops)) | ||
| 3429 | printk(KERN_ERR "Unable to setup rt_secret_timer\n"); | ||
| 3430 | |||
| 3431 | if (ip_rt_proc_init()) | 3343 | if (ip_rt_proc_init()) |
| 3432 | printk(KERN_ERR "Unable to create route proc files\n"); | 3344 | printk(KERN_ERR "Unable to create route proc files\n"); |
| 3433 | #ifdef CONFIG_XFRM | 3345 | #ifdef CONFIG_XFRM |
| @@ -3439,6 +3351,7 @@ int __init ip_rt_init(void) | |||
| 3439 | #ifdef CONFIG_SYSCTL | 3351 | #ifdef CONFIG_SYSCTL |
| 3440 | register_pernet_subsys(&sysctl_route_ops); | 3352 | register_pernet_subsys(&sysctl_route_ops); |
| 3441 | #endif | 3353 | #endif |
| 3354 | register_pernet_subsys(&rt_genid_ops); | ||
| 3442 | return rc; | 3355 | return rc; |
| 3443 | } | 3356 | } |
| 3444 | 3357 | ||
| @@ -3454,5 +3367,4 @@ void __init ip_static_sysctl_init(void) | |||
| 3454 | #endif | 3367 | #endif |
| 3455 | 3368 | ||
| 3456 | EXPORT_SYMBOL(__ip_select_ident); | 3369 | EXPORT_SYMBOL(__ip_select_ident); |
| 3457 | EXPORT_SYMBOL(ip_route_input); | ||
| 3458 | EXPORT_SYMBOL(ip_route_output_key); | 3370 | EXPORT_SYMBOL(ip_route_output_key); |
