aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorAlexey Dobriyan <adobriyan@gmail.com>2008-10-08 11:35:07 +0200
committerPatrick McHardy <kaber@trash.net>2008-10-08 11:35:07 +0200
commit6058fa6bb96a5b6145cba10c5171f09c2783ca69 (patch)
tree634c499aa2ce0a76133d5543eaebcdc73a58f4da /net
parenta71996fccce4b2086a26036aa3c915365ca36926 (diff)
netfilter: netns nf_conntrack: per-netns event cache
Heh, last minute proof-reading of this patch made me think, that this is actually unneeded, simply because "ct" pointers will be different for different conntracks in different netns, just like they are different in one netns. Not so sure anymore. [Patrick: pointers will be different, flushing can only be done while inactive though and thus it needs to be per netns] Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nf_conntrack_core.c12
-rw-r--r--net/netfilter/nf_conntrack_ecache.c26
2 files changed, 28 insertions, 10 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 01f59c57730..b55944e5e4e 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1023,7 +1023,8 @@ void nf_conntrack_cleanup(struct net *net)
delete... */
synchronize_net();
- nf_ct_event_cache_flush();
+ nf_ct_event_cache_flush(net);
+ nf_conntrack_ecache_fini(net);
i_see_dead_people:
nf_conntrack_flush(net);
if (atomic_read(&net->ct.count) != 0) {
@@ -1151,11 +1152,14 @@ int nf_conntrack_init(struct net *net)
max_factor = 4;
}
atomic_set(&net->ct.count, 0);
+ ret = nf_conntrack_ecache_init(net);
+ if (ret < 0)
+ goto err_ecache;
net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size,
&net->ct.hash_vmalloc);
if (!net->ct.hash) {
printk(KERN_ERR "Unable to create nf_conntrack_hash\n");
- goto err_out;
+ goto err_hash;
}
INIT_HLIST_HEAD(&net->ct.unconfirmed);
@@ -1215,6 +1219,8 @@ err_free_conntrack_slab:
err_free_hash:
nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc,
nf_conntrack_htable_size);
-err_out:
+err_hash:
+ nf_conntrack_ecache_fini(net);
+err_ecache:
return -ENOMEM;
}
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c
index 83c41ac3505..a5f5e2e65d1 100644
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -29,9 +29,6 @@ EXPORT_SYMBOL_GPL(nf_conntrack_chain);
ATOMIC_NOTIFIER_HEAD(nf_ct_expect_chain);
EXPORT_SYMBOL_GPL(nf_ct_expect_chain);
-DEFINE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache);
-EXPORT_PER_CPU_SYMBOL_GPL(nf_conntrack_ecache);
-
/* deliver cached events and clear cache entry - must be called with locally
* disabled softirqs */
static inline void
@@ -51,10 +48,11 @@ __nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache)
* by code prior to async packet handling for freeing the skb */
void nf_ct_deliver_cached_events(const struct nf_conn *ct)
{
+ struct net *net = nf_ct_net(ct);
struct nf_conntrack_ecache *ecache;
local_bh_disable();
- ecache = &__get_cpu_var(nf_conntrack_ecache);
+ ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id());
if (ecache->ct == ct)
__nf_ct_deliver_cached_events(ecache);
local_bh_enable();
@@ -64,10 +62,11 @@ EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events);
/* Deliver cached events for old pending events, if current conntrack != old */
void __nf_ct_event_cache_init(struct nf_conn *ct)
{
+ struct net *net = nf_ct_net(ct);
struct nf_conntrack_ecache *ecache;
/* take care of delivering potentially old events */
- ecache = &__get_cpu_var(nf_conntrack_ecache);
+ ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id());
BUG_ON(ecache->ct == ct);
if (ecache->ct)
__nf_ct_deliver_cached_events(ecache);
@@ -79,18 +78,31 @@ EXPORT_SYMBOL_GPL(__nf_ct_event_cache_init);
/* flush the event cache - touches other CPU's data and must not be called
* while packets are still passing through the code */
-void nf_ct_event_cache_flush(void)
+void nf_ct_event_cache_flush(struct net *net)
{
struct nf_conntrack_ecache *ecache;
int cpu;
for_each_possible_cpu(cpu) {
- ecache = &per_cpu(nf_conntrack_ecache, cpu);
+ ecache = per_cpu_ptr(net->ct.ecache, cpu);
if (ecache->ct)
nf_ct_put(ecache->ct);
}
}
+int nf_conntrack_ecache_init(struct net *net)
+{
+ net->ct.ecache = alloc_percpu(struct nf_conntrack_ecache);
+ if (!net->ct.ecache)
+ return -ENOMEM;
+ return 0;
+}
+
+void nf_conntrack_ecache_fini(struct net *net)
+{
+ free_percpu(net->ct.ecache);
+}
+
int nf_conntrack_register_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&nf_conntrack_chain, nb);