aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-06-09 08:43:38 -0400
committerPatrick McHardy <kaber@trash.net>2010-06-09 08:43:38 -0400
commitb3c5163fe0193a74016dba1bb22491e0d1e9aaa4 (patch)
treefc52d035b431969c034a1033e1c70803dd9ef219
parent5bfddbd46a95c978f4d3c992339cbdf4f4b790a3 (diff)
netfilter: nf_conntrack: per_cpu untracking
NOTRACK makes all cpus share a cache line on nf_conntrack_untracked twice per packet, slowing down performance. This patch converts it to a per_cpu variable. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--include/net/netfilter/nf_conntrack.h5
-rw-r--r--net/netfilter/nf_conntrack_core.c36
2 files changed, 28 insertions, 13 deletions
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 3bc38c70bbbe..84a4b6fec99d 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -261,11 +261,10 @@ extern s16 (*nf_ct_nat_offset)(const struct nf_conn *ct,
261 u32 seq); 261 u32 seq);
262 262
263/* Fake conntrack entry for untracked connections */ 263/* Fake conntrack entry for untracked connections */
264DECLARE_PER_CPU(struct nf_conn, nf_conntrack_untracked);
264static inline struct nf_conn *nf_ct_untracked_get(void) 265static inline struct nf_conn *nf_ct_untracked_get(void)
265{ 266{
266 extern struct nf_conn nf_conntrack_untracked; 267 return &__raw_get_cpu_var(nf_conntrack_untracked);
267
268 return &nf_conntrack_untracked;
269} 268}
270extern void nf_ct_untracked_status_or(unsigned long bits); 269extern void nf_ct_untracked_status_or(unsigned long bits);
271 270
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 6c1da212380d..9c661413b826 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -62,8 +62,8 @@ EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
62unsigned int nf_conntrack_max __read_mostly; 62unsigned int nf_conntrack_max __read_mostly;
63EXPORT_SYMBOL_GPL(nf_conntrack_max); 63EXPORT_SYMBOL_GPL(nf_conntrack_max);
64 64
65struct nf_conn nf_conntrack_untracked; 65DEFINE_PER_CPU(struct nf_conn, nf_conntrack_untracked);
66EXPORT_SYMBOL_GPL(nf_conntrack_untracked); 66EXPORT_PER_CPU_SYMBOL(nf_conntrack_untracked);
67 67
68static int nf_conntrack_hash_rnd_initted; 68static int nf_conntrack_hash_rnd_initted;
69static unsigned int nf_conntrack_hash_rnd; 69static unsigned int nf_conntrack_hash_rnd;
@@ -1183,10 +1183,21 @@ static void nf_ct_release_dying_list(struct net *net)
1183 spin_unlock_bh(&nf_conntrack_lock); 1183 spin_unlock_bh(&nf_conntrack_lock);
1184} 1184}
1185 1185
1186static int untrack_refs(void)
1187{
1188 int cnt = 0, cpu;
1189
1190 for_each_possible_cpu(cpu) {
1191 struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu);
1192
1193 cnt += atomic_read(&ct->ct_general.use) - 1;
1194 }
1195 return cnt;
1196}
1197
1186static void nf_conntrack_cleanup_init_net(void) 1198static void nf_conntrack_cleanup_init_net(void)
1187{ 1199{
1188 /* wait until all references to nf_conntrack_untracked are dropped */ 1200 while (untrack_refs() > 0)
1189 while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1)
1190 schedule(); 1201 schedule();
1191 1202
1192 nf_conntrack_helper_fini(); 1203 nf_conntrack_helper_fini();
@@ -1323,14 +1334,17 @@ module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
1323 1334
1324void nf_ct_untracked_status_or(unsigned long bits) 1335void nf_ct_untracked_status_or(unsigned long bits)
1325{ 1336{
1326 nf_conntrack_untracked.status |= bits; 1337 int cpu;
1338
1339 for_each_possible_cpu(cpu)
1340 per_cpu(nf_conntrack_untracked, cpu).status |= bits;
1327} 1341}
1328EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or); 1342EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or);
1329 1343
1330static int nf_conntrack_init_init_net(void) 1344static int nf_conntrack_init_init_net(void)
1331{ 1345{
1332 int max_factor = 8; 1346 int max_factor = 8;
1333 int ret; 1347 int ret, cpu;
1334 1348
1335 /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB 1349 /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
1336 * machine has 512 buckets. >= 1GB machines have 16384 buckets. */ 1350 * machine has 512 buckets. >= 1GB machines have 16384 buckets. */
@@ -1369,10 +1383,12 @@ static int nf_conntrack_init_init_net(void)
1369 goto err_extend; 1383 goto err_extend;
1370#endif 1384#endif
1371 /* Set up fake conntrack: to never be deleted, not in any hashes */ 1385 /* Set up fake conntrack: to never be deleted, not in any hashes */
1372#ifdef CONFIG_NET_NS 1386 for_each_possible_cpu(cpu) {
1373 nf_conntrack_untracked.ct_net = &init_net; 1387 struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu);
1374#endif 1388
1375 atomic_set(&nf_conntrack_untracked.ct_general.use, 1); 1389 write_pnet(&ct->ct_net, &init_net);
1390 atomic_set(&ct->ct_general.use, 1);
1391 }
1376 /* - and look it like as a confirmed connection */ 1392 /* - and look it like as a confirmed connection */
1377 nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED); 1393 nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED);
1378 return 0; 1394 return 0;