aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/route.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-12-23 17:13:56 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-23 17:13:56 -0500
commitabb434cb0539fb355c1c921f8fd761efbbac3462 (patch)
tree24a7d99ec161f8fd4dc9ff03c9c4cc93be883ce6 /net/ipv4/route.c
parent2494654d4890316e7340fb8b3458daad0474a1b9 (diff)
parent6350323ad8def2ac00d77cdee3b79c9b9fba75c4 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts: net/bluetooth/l2cap_core.c Just two overlapping changes, one added an initialization of a local variable, and another change added a new local variable. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r--net/ipv4/route.c112
1 files changed, 110 insertions, 2 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index f30112f7559a..bcacf54e5418 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -91,6 +91,7 @@
91#include <linux/rcupdate.h> 91#include <linux/rcupdate.h>
92#include <linux/times.h> 92#include <linux/times.h>
93#include <linux/slab.h> 93#include <linux/slab.h>
94#include <linux/prefetch.h>
94#include <net/dst.h> 95#include <net/dst.h>
95#include <net/net_namespace.h> 96#include <net/net_namespace.h>
96#include <net/protocol.h> 97#include <net/protocol.h>
@@ -119,6 +120,7 @@
119 120
120static int ip_rt_max_size; 121static int ip_rt_max_size;
121static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; 122static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT;
123static int ip_rt_gc_interval __read_mostly = 60 * HZ;
122static int ip_rt_gc_min_interval __read_mostly = HZ / 2; 124static int ip_rt_gc_min_interval __read_mostly = HZ / 2;
123static int ip_rt_redirect_number __read_mostly = 9; 125static int ip_rt_redirect_number __read_mostly = 9;
124static int ip_rt_redirect_load __read_mostly = HZ / 50; 126static int ip_rt_redirect_load __read_mostly = HZ / 50;
@@ -132,6 +134,9 @@ static int ip_rt_min_advmss __read_mostly = 256;
132static int rt_chain_length_max __read_mostly = 20; 134static int rt_chain_length_max __read_mostly = 20;
133static int redirect_genid; 135static int redirect_genid;
134 136
137static struct delayed_work expires_work;
138static unsigned long expires_ljiffies;
139
135/* 140/*
136 * Interface to generic destination cache. 141 * Interface to generic destination cache.
137 */ 142 */
@@ -829,6 +834,97 @@ static int has_noalias(const struct rtable *head, const struct rtable *rth)
829 return ONE; 834 return ONE;
830} 835}
831 836
837static void rt_check_expire(void)
838{
839 static unsigned int rover;
840 unsigned int i = rover, goal;
841 struct rtable *rth;
842 struct rtable __rcu **rthp;
843 unsigned long samples = 0;
844 unsigned long sum = 0, sum2 = 0;
845 unsigned long delta;
846 u64 mult;
847
848 delta = jiffies - expires_ljiffies;
849 expires_ljiffies = jiffies;
850 mult = ((u64)delta) << rt_hash_log;
851 if (ip_rt_gc_timeout > 1)
852 do_div(mult, ip_rt_gc_timeout);
853 goal = (unsigned int)mult;
854 if (goal > rt_hash_mask)
855 goal = rt_hash_mask + 1;
856 for (; goal > 0; goal--) {
857 unsigned long tmo = ip_rt_gc_timeout;
858 unsigned long length;
859
860 i = (i + 1) & rt_hash_mask;
861 rthp = &rt_hash_table[i].chain;
862
863 if (need_resched())
864 cond_resched();
865
866 samples++;
867
868 if (rcu_dereference_raw(*rthp) == NULL)
869 continue;
870 length = 0;
871 spin_lock_bh(rt_hash_lock_addr(i));
872 while ((rth = rcu_dereference_protected(*rthp,
873 lockdep_is_held(rt_hash_lock_addr(i)))) != NULL) {
874 prefetch(rth->dst.rt_next);
875 if (rt_is_expired(rth)) {
876 *rthp = rth->dst.rt_next;
877 rt_free(rth);
878 continue;
879 }
880 if (rth->dst.expires) {
881 /* Entry is expired even if it is in use */
882 if (time_before_eq(jiffies, rth->dst.expires)) {
883nofree:
884 tmo >>= 1;
885 rthp = &rth->dst.rt_next;
886 /*
887 * We only count entries on
888 * a chain with equal hash inputs once
889 * so that entries for different QOS
890 * levels, and other non-hash input
891 * attributes don't unfairly skew
892 * the length computation
893 */
894 length += has_noalias(rt_hash_table[i].chain, rth);
895 continue;
896 }
897 } else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout))
898 goto nofree;
899
900 /* Cleanup aged off entries. */
901 *rthp = rth->dst.rt_next;
902 rt_free(rth);
903 }
904 spin_unlock_bh(rt_hash_lock_addr(i));
905 sum += length;
906 sum2 += length*length;
907 }
908 if (samples) {
909 unsigned long avg = sum / samples;
910 unsigned long sd = int_sqrt(sum2 / samples - avg*avg);
911 rt_chain_length_max = max_t(unsigned long,
912 ip_rt_gc_elasticity,
913 (avg + 4*sd) >> FRACT_BITS);
914 }
915 rover = i;
916}
917
918/*
919 * rt_worker_func() is run in process context.
920 * we call rt_check_expire() to scan part of the hash table
921 */
922static void rt_worker_func(struct work_struct *work)
923{
924 rt_check_expire();
925 schedule_delayed_work(&expires_work, ip_rt_gc_interval);
926}
927
832/* 928/*
833 * Perturbation of rt_genid by a small quantity [1..256] 929 * Perturbation of rt_genid by a small quantity [1..256]
834 * Using 8 bits of shuffling ensure we can call rt_cache_invalidate() 930 * Using 8 bits of shuffling ensure we can call rt_cache_invalidate()
@@ -1265,7 +1361,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
1265{ 1361{
1266 struct rtable *rt = (struct rtable *) dst; 1362 struct rtable *rt = (struct rtable *) dst;
1267 1363
1268 if (rt) { 1364 if (rt && !(rt->dst.flags & DST_NOPEER)) {
1269 if (rt->peer == NULL) 1365 if (rt->peer == NULL)
1270 rt_bind_peer(rt, rt->rt_dst, 1); 1366 rt_bind_peer(rt, rt->rt_dst, 1);
1271 1367
@@ -1276,7 +1372,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
1276 iph->id = htons(inet_getid(rt->peer, more)); 1372 iph->id = htons(inet_getid(rt->peer, more));
1277 return; 1373 return;
1278 } 1374 }
1279 } else 1375 } else if (!rt)
1280 printk(KERN_DEBUG "rt_bind_peer(0) @%p\n", 1376 printk(KERN_DEBUG "rt_bind_peer(0) @%p\n",
1281 __builtin_return_address(0)); 1377 __builtin_return_address(0));
1282 1378
@@ -3173,6 +3269,13 @@ static ctl_table ipv4_route_table[] = {
3173 .proc_handler = proc_dointvec_jiffies, 3269 .proc_handler = proc_dointvec_jiffies,
3174 }, 3270 },
3175 { 3271 {
3272 .procname = "gc_interval",
3273 .data = &ip_rt_gc_interval,
3274 .maxlen = sizeof(int),
3275 .mode = 0644,
3276 .proc_handler = proc_dointvec_jiffies,
3277 },
3278 {
3176 .procname = "redirect_load", 3279 .procname = "redirect_load",
3177 .data = &ip_rt_redirect_load, 3280 .data = &ip_rt_redirect_load,
3178 .maxlen = sizeof(int), 3281 .maxlen = sizeof(int),
@@ -3382,6 +3485,11 @@ int __init ip_rt_init(void)
3382 devinet_init(); 3485 devinet_init();
3383 ip_fib_init(); 3486 ip_fib_init();
3384 3487
3488 INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func);
3489 expires_ljiffies = jiffies;
3490 schedule_delayed_work(&expires_work,
3491 net_random() % ip_rt_gc_interval + ip_rt_gc_interval);
3492
3385 if (ip_rt_proc_init()) 3493 if (ip_rt_proc_init())
3386 printk(KERN_ERR "Unable to create route proc files\n"); 3494 printk(KERN_ERR "Unable to create route proc files\n");
3387#ifdef CONFIG_XFRM 3495#ifdef CONFIG_XFRM