diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-06-09 08:43:38 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2010-06-09 08:43:38 -0400 |
commit | b3c5163fe0193a74016dba1bb22491e0d1e9aaa4 (patch) | |
tree | fc52d035b431969c034a1033e1c70803dd9ef219 | |
parent | 5bfddbd46a95c978f4d3c992339cbdf4f4b790a3 (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.h | 5 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 36 |
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 */ |
264 | DECLARE_PER_CPU(struct nf_conn, nf_conntrack_untracked); | ||
264 | static inline struct nf_conn *nf_ct_untracked_get(void) | 265 | static 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 | } |
270 | extern void nf_ct_untracked_status_or(unsigned long bits); | 269 | extern 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); | |||
62 | unsigned int nf_conntrack_max __read_mostly; | 62 | unsigned int nf_conntrack_max __read_mostly; |
63 | EXPORT_SYMBOL_GPL(nf_conntrack_max); | 63 | EXPORT_SYMBOL_GPL(nf_conntrack_max); |
64 | 64 | ||
65 | struct nf_conn nf_conntrack_untracked; | 65 | DEFINE_PER_CPU(struct nf_conn, nf_conntrack_untracked); |
66 | EXPORT_SYMBOL_GPL(nf_conntrack_untracked); | 66 | EXPORT_PER_CPU_SYMBOL(nf_conntrack_untracked); |
67 | 67 | ||
68 | static int nf_conntrack_hash_rnd_initted; | 68 | static int nf_conntrack_hash_rnd_initted; |
69 | static unsigned int nf_conntrack_hash_rnd; | 69 | static 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 | ||
1186 | static 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 | |||
1186 | static void nf_conntrack_cleanup_init_net(void) | 1198 | static 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 | ||
1324 | void nf_ct_untracked_status_or(unsigned long bits) | 1335 | void 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 | } |
1328 | EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or); | 1342 | EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or); |
1329 | 1343 | ||
1330 | static int nf_conntrack_init_init_net(void) | 1344 | static 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; |