aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2014-07-24 10:50:35 -0400
committerDavid S. Miller <davem@davemloft.net>2014-07-28 01:34:36 -0400
commite3a57d18b06179d68fcf7a0a06ad844493c65e06 (patch)
tree8a7dcc0a88235136f76a3deb8818c439abb8a944
parent3fd588eb90bfbba17091381006ecafe29c45db4a (diff)
inet: frag: remove periodic secret rebuild timer
merge functionality into the eviction workqueue. Instead of rebuilding every n seconds, take advantage of the upper hash chain length limit. If we hit it, mark table for rebuild and schedule workqueue. To prevent frequent rebuilds when we're completely overloaded, don't rebuild more than once every 5 seconds. ipfrag_secret_interval sysctl is now obsolete and has been marked as deprecated, it still can be changed so scripts won't be broken but it won't have any effect. A comment is left above each unused secret_timer variable to avoid confusion. Joint work with Nikolay Aleksandrov. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/ip-sysctl.txt10
-rw-r--r--include/net/inet_frag.h4
-rw-r--r--net/ieee802154/reassembly.c5
-rw-r--r--net/ipv4/inet_fragment.c43
-rw-r--r--net/ipv4/ip_fragment.c5
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c1
-rw-r--r--net/ipv6/reassembly.c5
7 files changed, 40 insertions, 33 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 625c8dda4be7..e8c304e37831 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -111,11 +111,6 @@ ipfrag_low_thresh - INTEGER
111ipfrag_time - INTEGER 111ipfrag_time - INTEGER
112 Time in seconds to keep an IP fragment in memory. 112 Time in seconds to keep an IP fragment in memory.
113 113
114ipfrag_secret_interval - INTEGER
115 Regeneration interval (in seconds) of the hash secret (or lifetime
116 for the hash secret) for IP fragments.
117 Default: 600
118
119ipfrag_max_dist - INTEGER 114ipfrag_max_dist - INTEGER
120 ipfrag_max_dist is a non-negative integer value which defines the 115 ipfrag_max_dist is a non-negative integer value which defines the
121 maximum "disorder" which is allowed among fragments which share a 116 maximum "disorder" which is allowed among fragments which share a
@@ -1164,11 +1159,6 @@ ip6frag_low_thresh - INTEGER
1164ip6frag_time - INTEGER 1159ip6frag_time - INTEGER
1165 Time in seconds to keep an IPv6 fragment in memory. 1160 Time in seconds to keep an IPv6 fragment in memory.
1166 1161
1167ip6frag_secret_interval - INTEGER
1168 Regeneration interval (in seconds) of the hash secret (or lifetime
1169 for the hash secret) for IPv6 fragments.
1170 Default: 600
1171
1172conf/default/*: 1162conf/default/*:
1173 Change the interface-specific default settings. 1163 Change the interface-specific default settings.
1174 1164
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 90d21ea62c59..d9cc5bb64854 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -58,11 +58,11 @@ struct inet_frags {
58 * Its primarily a rebuild protection rwlock. 58 * Its primarily a rebuild protection rwlock.
59 */ 59 */
60 rwlock_t lock ____cacheline_aligned_in_smp; 60 rwlock_t lock ____cacheline_aligned_in_smp;
61 int secret_interval;
62 struct timer_list secret_timer;
63 61
64 struct work_struct frags_work; 62 struct work_struct frags_work;
65 unsigned int next_bucket; 63 unsigned int next_bucket;
64 unsigned long last_rebuild_jiffies;
65 bool rebuild;
66 66
67 /* The first call to hashfn is responsible to initialize 67 /* The first call to hashfn is responsible to initialize
68 * rnd. This is best done with net_get_random_once. 68 * rnd. This is best done with net_get_random_once.
diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c
index b4bc7a50eccf..20d219682d84 100644
--- a/net/ieee802154/reassembly.c
+++ b/net/ieee802154/reassembly.c
@@ -419,10 +419,12 @@ static struct ctl_table lowpan_frags_ns_ctl_table[] = {
419 { } 419 { }
420}; 420};
421 421
422/* secret interval has been deprecated */
423static int lowpan_frags_secret_interval_unused;
422static struct ctl_table lowpan_frags_ctl_table[] = { 424static struct ctl_table lowpan_frags_ctl_table[] = {
423 { 425 {
424 .procname = "6lowpanfrag_secret_interval", 426 .procname = "6lowpanfrag_secret_interval",
425 .data = &lowpan_frags.secret_interval, 427 .data = &lowpan_frags_secret_interval_unused,
426 .maxlen = sizeof(int), 428 .maxlen = sizeof(int),
427 .mode = 0644, 429 .mode = 0644,
428 .proc_handler = proc_dointvec_jiffies, 430 .proc_handler = proc_dointvec_jiffies,
@@ -562,7 +564,6 @@ int __init lowpan_net_frag_init(void)
562 lowpan_frags.qsize = sizeof(struct frag_queue); 564 lowpan_frags.qsize = sizeof(struct frag_queue);
563 lowpan_frags.match = lowpan_frag_match; 565 lowpan_frags.match = lowpan_frag_match;
564 lowpan_frags.frag_expire = lowpan_frag_expire; 566 lowpan_frags.frag_expire = lowpan_frag_expire;
565 lowpan_frags.secret_interval = 10 * 60 * HZ;
566 inet_frags_init(&lowpan_frags); 567 inet_frags_init(&lowpan_frags);
567 568
568 return ret; 569 return ret;
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 198a5ed7a815..58d4c38534f6 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -28,6 +28,9 @@
28#define INETFRAGS_EVICT_BUCKETS 128 28#define INETFRAGS_EVICT_BUCKETS 128
29#define INETFRAGS_EVICT_MAX 512 29#define INETFRAGS_EVICT_MAX 512
30 30
31/* don't rebuild inetfrag table with new secret more often than this */
32#define INETFRAGS_MIN_REBUILD_INTERVAL (5 * HZ)
33
31/* Given the OR values of all fragments, apply RFC 3168 5.3 requirements 34/* Given the OR values of all fragments, apply RFC 3168 5.3 requirements
32 * Value : 0xff if frame should be dropped. 35 * Value : 0xff if frame should be dropped.
33 * 0 or INET_ECN_CE value, to be ORed in to final iph->tos field 36 * 0 or INET_ECN_CE value, to be ORed in to final iph->tos field
@@ -55,16 +58,24 @@ inet_frag_hashfn(const struct inet_frags *f, const struct inet_frag_queue *q)
55 return f->hashfn(q) & (INETFRAGS_HASHSZ - 1); 58 return f->hashfn(q) & (INETFRAGS_HASHSZ - 1);
56} 59}
57 60
58static void inet_frag_secret_rebuild(unsigned long dummy) 61static bool inet_frag_may_rebuild(struct inet_frags *f)
62{
63 return time_after(jiffies,
64 f->last_rebuild_jiffies + INETFRAGS_MIN_REBUILD_INTERVAL);
65}
66
67static void inet_frag_secret_rebuild(struct inet_frags *f)
59{ 68{
60 struct inet_frags *f = (struct inet_frags *)dummy;
61 unsigned long now = jiffies;
62 int i; 69 int i;
63 70
64 /* Per bucket lock NOT needed here, due to write lock protection */ 71 /* Per bucket lock NOT needed here, due to write lock protection */
65 write_lock(&f->lock); 72 write_lock_bh(&f->lock);
73
74 if (!inet_frag_may_rebuild(f))
75 goto out;
66 76
67 get_random_bytes(&f->rnd, sizeof(u32)); 77 get_random_bytes(&f->rnd, sizeof(u32));
78
68 for (i = 0; i < INETFRAGS_HASHSZ; i++) { 79 for (i = 0; i < INETFRAGS_HASHSZ; i++) {
69 struct inet_frag_bucket *hb; 80 struct inet_frag_bucket *hb;
70 struct inet_frag_queue *q; 81 struct inet_frag_queue *q;
@@ -85,9 +96,11 @@ static void inet_frag_secret_rebuild(unsigned long dummy)
85 } 96 }
86 } 97 }
87 } 98 }
88 write_unlock(&f->lock);
89 99
90 mod_timer(&f->secret_timer, now + f->secret_interval); 100 f->rebuild = false;
101 f->last_rebuild_jiffies = jiffies;
102out:
103 write_unlock_bh(&f->lock);
91} 104}
92 105
93static bool inet_fragq_should_evict(const struct inet_frag_queue *q) 106static bool inet_fragq_should_evict(const struct inet_frag_queue *q)
@@ -162,6 +175,8 @@ static void inet_frag_worker(struct work_struct *work)
162 f->next_bucket = i; 175 f->next_bucket = i;
163 176
164 read_unlock_bh(&f->lock); 177 read_unlock_bh(&f->lock);
178 if (f->rebuild && inet_frag_may_rebuild(f))
179 inet_frag_secret_rebuild(f);
165} 180}
166 181
167static void inet_frag_schedule_worker(struct inet_frags *f) 182static void inet_frag_schedule_worker(struct inet_frags *f)
@@ -183,11 +198,7 @@ void inet_frags_init(struct inet_frags *f)
183 INIT_HLIST_HEAD(&hb->chain); 198 INIT_HLIST_HEAD(&hb->chain);
184 } 199 }
185 rwlock_init(&f->lock); 200 rwlock_init(&f->lock);
186 201 f->last_rebuild_jiffies = 0;
187 setup_timer(&f->secret_timer, inet_frag_secret_rebuild,
188 (unsigned long)f);
189 f->secret_timer.expires = jiffies + f->secret_interval;
190 add_timer(&f->secret_timer);
191} 202}
192EXPORT_SYMBOL(inet_frags_init); 203EXPORT_SYMBOL(inet_frags_init);
193 204
@@ -199,7 +210,6 @@ EXPORT_SYMBOL(inet_frags_init_net);
199 210
200void inet_frags_fini(struct inet_frags *f) 211void inet_frags_fini(struct inet_frags *f)
201{ 212{
202 del_timer(&f->secret_timer);
203 cancel_work_sync(&f->frags_work); 213 cancel_work_sync(&f->frags_work);
204} 214}
205EXPORT_SYMBOL(inet_frags_fini); 215EXPORT_SYMBOL(inet_frags_fini);
@@ -399,8 +409,13 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
399 409
400 if (depth <= INETFRAGS_MAXDEPTH) 410 if (depth <= INETFRAGS_MAXDEPTH)
401 return inet_frag_create(nf, f, key); 411 return inet_frag_create(nf, f, key);
402 else 412
403 return ERR_PTR(-ENOBUFS); 413 if (inet_frag_may_rebuild(f)) {
414 f->rebuild = true;
415 inet_frag_schedule_worker(f);
416 }
417
418 return ERR_PTR(-ENOBUFS);
404} 419}
405EXPORT_SYMBOL(inet_frag_find); 420EXPORT_SYMBOL(inet_frag_find);
406 421
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 8fbeee495037..44e591a7e03f 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -720,10 +720,12 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = {
720 { } 720 { }
721}; 721};
722 722
723/* secret interval has been deprecated */
724static int ip4_frags_secret_interval_unused;
723static struct ctl_table ip4_frags_ctl_table[] = { 725static struct ctl_table ip4_frags_ctl_table[] = {
724 { 726 {
725 .procname = "ipfrag_secret_interval", 727 .procname = "ipfrag_secret_interval",
726 .data = &ip4_frags.secret_interval, 728 .data = &ip4_frags_secret_interval_unused,
727 .maxlen = sizeof(int), 729 .maxlen = sizeof(int),
728 .mode = 0644, 730 .mode = 0644,
729 .proc_handler = proc_dointvec_jiffies, 731 .proc_handler = proc_dointvec_jiffies,
@@ -853,6 +855,5 @@ void __init ipfrag_init(void)
853 ip4_frags.qsize = sizeof(struct ipq); 855 ip4_frags.qsize = sizeof(struct ipq);
854 ip4_frags.match = ip4_frag_match; 856 ip4_frags.match = ip4_frag_match;
855 ip4_frags.frag_expire = ip_expire; 857 ip4_frags.frag_expire = ip_expire;
856 ip4_frags.secret_interval = 10 * 60 * HZ;
857 inet_frags_init(&ip4_frags); 858 inet_frags_init(&ip4_frags);
858} 859}
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index fb0f72a0ff31..3b3ef9774cc2 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -669,7 +669,6 @@ int nf_ct_frag6_init(void)
669 nf_frags.qsize = sizeof(struct frag_queue); 669 nf_frags.qsize = sizeof(struct frag_queue);
670 nf_frags.match = ip6_frag_match; 670 nf_frags.match = ip6_frag_match;
671 nf_frags.frag_expire = nf_ct_frag6_expire; 671 nf_frags.frag_expire = nf_ct_frag6_expire;
672 nf_frags.secret_interval = 10 * 60 * HZ;
673 inet_frags_init(&nf_frags); 672 inet_frags_init(&nf_frags);
674 673
675 ret = register_pernet_subsys(&nf_ct_net_ops); 674 ret = register_pernet_subsys(&nf_ct_net_ops);
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index af85551682c2..987fea46b915 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -604,10 +604,12 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = {
604 { } 604 { }
605}; 605};
606 606
607/* secret interval has been deprecated */
608static int ip6_frags_secret_interval_unused;
607static struct ctl_table ip6_frags_ctl_table[] = { 609static struct ctl_table ip6_frags_ctl_table[] = {
608 { 610 {
609 .procname = "ip6frag_secret_interval", 611 .procname = "ip6frag_secret_interval",
610 .data = &ip6_frags.secret_interval, 612 .data = &ip6_frags_secret_interval_unused,
611 .maxlen = sizeof(int), 613 .maxlen = sizeof(int),
612 .mode = 0644, 614 .mode = 0644,
613 .proc_handler = proc_dointvec_jiffies, 615 .proc_handler = proc_dointvec_jiffies,
@@ -737,7 +739,6 @@ int __init ipv6_frag_init(void)
737 ip6_frags.qsize = sizeof(struct frag_queue); 739 ip6_frags.qsize = sizeof(struct frag_queue);
738 ip6_frags.match = ip6_frag_match; 740 ip6_frags.match = ip6_frag_match;
739 ip6_frags.frag_expire = ip6_frag_expire; 741 ip6_frags.frag_expire = ip6_frag_expire;
740 ip6_frags.secret_interval = 10 * 60 * HZ;
741 inet_frags_init(&ip6_frags); 742 inet_frags_init(&ip6_frags);
742out: 743out:
743 return ret; 744 return ret;