aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r--net/ipv4/route.c137
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;
129static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; 129static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ;
130static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; 130static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20;
131static int ip_rt_min_advmss __read_mostly = 256; 131static int ip_rt_min_advmss __read_mostly = 256;
132static int ip_rt_secret_interval __read_mostly = 10 * 60 * HZ;
133static int rt_chain_length_max __read_mostly = 20; 132static int rt_chain_length_max __read_mostly = 20;
134 133
135static struct delayed_work expires_work; 134static 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
260static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx, 259static 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)
685static inline bool compare_hash_inputs(const struct flowi *fl1, 684static 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
693static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) 692static 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 */
925static 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
932static 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
940static void rt_emergency_hash_rebuild(struct net *net) 920static 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
3105static 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
3135static 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
3147static ctl_table ipv4_route_table[] = { 3082static 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 3268static __net_init int rt_genid_init(struct net *net)
3341static __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
3360static __net_exit void rt_secret_timer_exit(struct net *net) 3275static __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
3365static __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