diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 137 |
1 files changed, 22 insertions, 115 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index cb562fdd9b9a..dea3f9264250 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 | /* |
@@ -2319,8 +2296,8 @@ 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 && |
@@ -3102,48 +3079,6 @@ static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write, | |||
3102 | return -EINVAL; | 3079 | return -EINVAL; |
3103 | } | 3080 | } |
3104 | 3081 | ||
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[] = { | 3082 | static ctl_table ipv4_route_table[] = { |
3148 | { | 3083 | { |
3149 | .procname = "gc_thresh", | 3084 | .procname = "gc_thresh", |
@@ -3252,13 +3187,6 @@ static ctl_table ipv4_route_table[] = { | |||
3252 | .mode = 0644, | 3187 | .mode = 0644, |
3253 | .proc_handler = proc_dointvec, | 3188 | .proc_handler = proc_dointvec, |
3254 | }, | 3189 | }, |
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 | { } | 3190 | { } |
3263 | }; | 3191 | }; |
3264 | 3192 | ||
@@ -3337,34 +3265,15 @@ static __net_initdata struct pernet_operations sysctl_route_ops = { | |||
3337 | }; | 3265 | }; |
3338 | #endif | 3266 | #endif |
3339 | 3267 | ||
3340 | 3268 | static __net_init int rt_genid_init(struct net *net) | |
3341 | static __net_init int rt_secret_timer_init(struct net *net) | ||
3342 | { | 3269 | { |
3343 | atomic_set(&net->ipv4.rt_genid, | 3270 | get_random_bytes(&net->ipv4.rt_genid, |
3344 | (int) ((num_physpages ^ (num_physpages>>8)) ^ | 3271 | 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; | 3272 | return 0; |
3358 | } | 3273 | } |
3359 | 3274 | ||
3360 | static __net_exit void rt_secret_timer_exit(struct net *net) | 3275 | static __net_initdata struct pernet_operations rt_genid_ops = { |
3361 | { | 3276 | .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 | }; | 3277 | }; |
3369 | 3278 | ||
3370 | 3279 | ||
@@ -3425,9 +3334,6 @@ int __init ip_rt_init(void) | |||
3425 | schedule_delayed_work(&expires_work, | 3334 | schedule_delayed_work(&expires_work, |
3426 | net_random() % ip_rt_gc_interval + ip_rt_gc_interval); | 3335 | net_random() % ip_rt_gc_interval + ip_rt_gc_interval); |
3427 | 3336 | ||
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()) | 3337 | if (ip_rt_proc_init()) |
3432 | printk(KERN_ERR "Unable to create route proc files\n"); | 3338 | printk(KERN_ERR "Unable to create route proc files\n"); |
3433 | #ifdef CONFIG_XFRM | 3339 | #ifdef CONFIG_XFRM |
@@ -3439,6 +3345,7 @@ int __init ip_rt_init(void) | |||
3439 | #ifdef CONFIG_SYSCTL | 3345 | #ifdef CONFIG_SYSCTL |
3440 | register_pernet_subsys(&sysctl_route_ops); | 3346 | register_pernet_subsys(&sysctl_route_ops); |
3441 | #endif | 3347 | #endif |
3348 | register_pernet_subsys(&rt_genid_ops); | ||
3442 | return rc; | 3349 | return rc; |
3443 | } | 3350 | } |
3444 | 3351 | ||