diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2008-10-08 05:35:09 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2008-10-08 05:35:09 -0400 |
commit | 08f6547d266fdba087f7fa7963fc0610be5b7cd7 (patch) | |
tree | 60e4dbfc5328d581503eb074c2ff0794be40ecd2 /net | |
parent | d716a4dfbbdf0d4731d596a96e5f4b0d892ac168 (diff) |
netfilter: netns nf_conntrack: final netns tweaks
Add init_net checks to not remove kmem_caches twice and so on.
Refactor functions to split code which should be executed only for
init_net into one place.
ip_ct_attach and ip_ct_destroy assignments remain separate, because
they're separate stages in setup and teardown.
NOTE: NOTRACK code is in for-every-net part. It will be made per-netns
after we decidce how to do it correctly.
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.c | 151 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 26 |
2 files changed, 114 insertions, 63 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index bb26460d897c..27de3c7b006e 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -1010,17 +1010,15 @@ void nf_conntrack_flush(struct net *net) | |||
1010 | } | 1010 | } |
1011 | EXPORT_SYMBOL_GPL(nf_conntrack_flush); | 1011 | EXPORT_SYMBOL_GPL(nf_conntrack_flush); |
1012 | 1012 | ||
1013 | /* Mishearing the voices in his head, our hero wonders how he's | 1013 | static void nf_conntrack_cleanup_init_net(void) |
1014 | supposed to kill the mall. */ | ||
1015 | void nf_conntrack_cleanup(struct net *net) | ||
1016 | { | 1014 | { |
1017 | rcu_assign_pointer(ip_ct_attach, NULL); | 1015 | nf_conntrack_helper_fini(); |
1018 | 1016 | nf_conntrack_proto_fini(); | |
1019 | /* This makes sure all current packets have passed through | 1017 | kmem_cache_destroy(nf_conntrack_cachep); |
1020 | netfilter framework. Roll on, two-stage module | 1018 | } |
1021 | delete... */ | ||
1022 | synchronize_net(); | ||
1023 | 1019 | ||
1020 | static void nf_conntrack_cleanup_net(struct net *net) | ||
1021 | { | ||
1024 | nf_ct_event_cache_flush(net); | 1022 | nf_ct_event_cache_flush(net); |
1025 | nf_conntrack_ecache_fini(net); | 1023 | nf_conntrack_ecache_fini(net); |
1026 | i_see_dead_people: | 1024 | i_see_dead_people: |
@@ -1033,17 +1031,31 @@ void nf_conntrack_cleanup(struct net *net) | |||
1033 | while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1) | 1031 | while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1) |
1034 | schedule(); | 1032 | schedule(); |
1035 | 1033 | ||
1036 | rcu_assign_pointer(nf_ct_destroy, NULL); | ||
1037 | |||
1038 | kmem_cache_destroy(nf_conntrack_cachep); | ||
1039 | nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, | 1034 | nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, |
1040 | nf_conntrack_htable_size); | 1035 | nf_conntrack_htable_size); |
1041 | |||
1042 | nf_conntrack_acct_fini(net); | 1036 | nf_conntrack_acct_fini(net); |
1043 | nf_conntrack_expect_fini(net); | 1037 | nf_conntrack_expect_fini(net); |
1044 | free_percpu(net->ct.stat); | 1038 | free_percpu(net->ct.stat); |
1045 | nf_conntrack_helper_fini(); | 1039 | } |
1046 | nf_conntrack_proto_fini(); | 1040 | |
1041 | /* Mishearing the voices in his head, our hero wonders how he's | ||
1042 | supposed to kill the mall. */ | ||
1043 | void nf_conntrack_cleanup(struct net *net) | ||
1044 | { | ||
1045 | if (net_eq(net, &init_net)) | ||
1046 | rcu_assign_pointer(ip_ct_attach, NULL); | ||
1047 | |||
1048 | /* This makes sure all current packets have passed through | ||
1049 | netfilter framework. Roll on, two-stage module | ||
1050 | delete... */ | ||
1051 | synchronize_net(); | ||
1052 | |||
1053 | nf_conntrack_cleanup_net(net); | ||
1054 | |||
1055 | if (net_eq(net, &init_net)) { | ||
1056 | rcu_assign_pointer(nf_ct_destroy, NULL); | ||
1057 | nf_conntrack_cleanup_init_net(); | ||
1058 | } | ||
1047 | } | 1059 | } |
1048 | 1060 | ||
1049 | struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced) | 1061 | struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced) |
@@ -1128,7 +1140,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize); | |||
1128 | module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, | 1140 | module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, |
1129 | &nf_conntrack_htable_size, 0600); | 1141 | &nf_conntrack_htable_size, 0600); |
1130 | 1142 | ||
1131 | int nf_conntrack_init(struct net *net) | 1143 | static int nf_conntrack_init_init_net(void) |
1132 | { | 1144 | { |
1133 | int max_factor = 8; | 1145 | int max_factor = 8; |
1134 | int ret; | 1146 | int ret; |
@@ -1150,21 +1162,6 @@ int nf_conntrack_init(struct net *net) | |||
1150 | * entries. */ | 1162 | * entries. */ |
1151 | max_factor = 4; | 1163 | max_factor = 4; |
1152 | } | 1164 | } |
1153 | atomic_set(&net->ct.count, 0); | ||
1154 | net->ct.stat = alloc_percpu(struct ip_conntrack_stat); | ||
1155 | if (!net->ct.stat) | ||
1156 | goto err_stat; | ||
1157 | ret = nf_conntrack_ecache_init(net); | ||
1158 | if (ret < 0) | ||
1159 | goto err_ecache; | ||
1160 | net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, | ||
1161 | &net->ct.hash_vmalloc); | ||
1162 | if (!net->ct.hash) { | ||
1163 | printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); | ||
1164 | goto err_hash; | ||
1165 | } | ||
1166 | INIT_HLIST_HEAD(&net->ct.unconfirmed); | ||
1167 | |||
1168 | nf_conntrack_max = max_factor * nf_conntrack_htable_size; | 1165 | nf_conntrack_max = max_factor * nf_conntrack_htable_size; |
1169 | 1166 | ||
1170 | printk("nf_conntrack version %s (%u buckets, %d max)\n", | 1167 | printk("nf_conntrack version %s (%u buckets, %d max)\n", |
@@ -1176,28 +1173,55 @@ int nf_conntrack_init(struct net *net) | |||
1176 | 0, 0, NULL); | 1173 | 0, 0, NULL); |
1177 | if (!nf_conntrack_cachep) { | 1174 | if (!nf_conntrack_cachep) { |
1178 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); | 1175 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); |
1179 | goto err_free_hash; | 1176 | ret = -ENOMEM; |
1177 | goto err_cache; | ||
1180 | } | 1178 | } |
1181 | 1179 | ||
1182 | ret = nf_conntrack_proto_init(); | 1180 | ret = nf_conntrack_proto_init(); |
1183 | if (ret < 0) | 1181 | if (ret < 0) |
1184 | goto err_free_conntrack_slab; | 1182 | goto err_proto; |
1185 | |||
1186 | ret = nf_conntrack_expect_init(net); | ||
1187 | if (ret < 0) | ||
1188 | goto out_fini_proto; | ||
1189 | 1183 | ||
1190 | ret = nf_conntrack_helper_init(); | 1184 | ret = nf_conntrack_helper_init(); |
1191 | if (ret < 0) | 1185 | if (ret < 0) |
1192 | goto out_fini_expect; | 1186 | goto err_helper; |
1187 | |||
1188 | return 0; | ||
1189 | |||
1190 | err_helper: | ||
1191 | nf_conntrack_proto_fini(); | ||
1192 | err_proto: | ||
1193 | kmem_cache_destroy(nf_conntrack_cachep); | ||
1194 | err_cache: | ||
1195 | return ret; | ||
1196 | } | ||
1197 | |||
1198 | static int nf_conntrack_init_net(struct net *net) | ||
1199 | { | ||
1200 | int ret; | ||
1193 | 1201 | ||
1202 | atomic_set(&net->ct.count, 0); | ||
1203 | INIT_HLIST_HEAD(&net->ct.unconfirmed); | ||
1204 | net->ct.stat = alloc_percpu(struct ip_conntrack_stat); | ||
1205 | if (!net->ct.stat) { | ||
1206 | ret = -ENOMEM; | ||
1207 | goto err_stat; | ||
1208 | } | ||
1209 | ret = nf_conntrack_ecache_init(net); | ||
1210 | if (ret < 0) | ||
1211 | goto err_ecache; | ||
1212 | net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, | ||
1213 | &net->ct.hash_vmalloc); | ||
1214 | if (!net->ct.hash) { | ||
1215 | ret = -ENOMEM; | ||
1216 | printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); | ||
1217 | goto err_hash; | ||
1218 | } | ||
1219 | ret = nf_conntrack_expect_init(net); | ||
1220 | if (ret < 0) | ||
1221 | goto err_expect; | ||
1194 | ret = nf_conntrack_acct_init(net); | 1222 | ret = nf_conntrack_acct_init(net); |
1195 | if (ret < 0) | 1223 | if (ret < 0) |
1196 | goto out_fini_helper; | 1224 | goto err_acct; |
1197 | |||
1198 | /* For use by REJECT target */ | ||
1199 | rcu_assign_pointer(ip_ct_attach, nf_conntrack_attach); | ||
1200 | rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); | ||
1201 | 1225 | ||
1202 | /* Set up fake conntrack: | 1226 | /* Set up fake conntrack: |
1203 | - to never be deleted, not in any hashes */ | 1227 | - to never be deleted, not in any hashes */ |
@@ -1208,17 +1232,11 @@ int nf_conntrack_init(struct net *net) | |||
1208 | /* - and look it like as a confirmed connection */ | 1232 | /* - and look it like as a confirmed connection */ |
1209 | set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status); | 1233 | set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status); |
1210 | 1234 | ||
1211 | return ret; | 1235 | return 0; |
1212 | 1236 | ||
1213 | out_fini_helper: | 1237 | err_acct: |
1214 | nf_conntrack_helper_fini(); | ||
1215 | out_fini_expect: | ||
1216 | nf_conntrack_expect_fini(net); | 1238 | nf_conntrack_expect_fini(net); |
1217 | out_fini_proto: | 1239 | err_expect: |
1218 | nf_conntrack_proto_fini(); | ||
1219 | err_free_conntrack_slab: | ||
1220 | kmem_cache_destroy(nf_conntrack_cachep); | ||
1221 | err_free_hash: | ||
1222 | nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, | 1240 | nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, |
1223 | nf_conntrack_htable_size); | 1241 | nf_conntrack_htable_size); |
1224 | err_hash: | 1242 | err_hash: |
@@ -1226,5 +1244,32 @@ err_hash: | |||
1226 | err_ecache: | 1244 | err_ecache: |
1227 | free_percpu(net->ct.stat); | 1245 | free_percpu(net->ct.stat); |
1228 | err_stat: | 1246 | err_stat: |
1229 | return -ENOMEM; | 1247 | return ret; |
1248 | } | ||
1249 | |||
1250 | int nf_conntrack_init(struct net *net) | ||
1251 | { | ||
1252 | int ret; | ||
1253 | |||
1254 | if (net_eq(net, &init_net)) { | ||
1255 | ret = nf_conntrack_init_init_net(); | ||
1256 | if (ret < 0) | ||
1257 | goto out_init_net; | ||
1258 | } | ||
1259 | ret = nf_conntrack_init_net(net); | ||
1260 | if (ret < 0) | ||
1261 | goto out_net; | ||
1262 | |||
1263 | if (net_eq(net, &init_net)) { | ||
1264 | /* For use by REJECT target */ | ||
1265 | rcu_assign_pointer(ip_ct_attach, nf_conntrack_attach); | ||
1266 | rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); | ||
1267 | } | ||
1268 | return 0; | ||
1269 | |||
1270 | out_net: | ||
1271 | if (net_eq(net, &init_net)) | ||
1272 | nf_conntrack_cleanup_init_net(); | ||
1273 | out_init_net: | ||
1274 | return ret; | ||
1230 | } | 1275 | } |
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index b7f751171613..37a703bc3b8e 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -563,12 +563,14 @@ int nf_conntrack_expect_init(struct net *net) | |||
563 | { | 563 | { |
564 | int err = -ENOMEM; | 564 | int err = -ENOMEM; |
565 | 565 | ||
566 | if (!nf_ct_expect_hsize) { | 566 | if (net_eq(net, &init_net)) { |
567 | nf_ct_expect_hsize = nf_conntrack_htable_size / 256; | 567 | if (!nf_ct_expect_hsize) { |
568 | if (!nf_ct_expect_hsize) | 568 | nf_ct_expect_hsize = nf_conntrack_htable_size / 256; |
569 | nf_ct_expect_hsize = 1; | 569 | if (!nf_ct_expect_hsize) |
570 | nf_ct_expect_hsize = 1; | ||
571 | } | ||
572 | nf_ct_expect_max = nf_ct_expect_hsize * 4; | ||
570 | } | 573 | } |
571 | nf_ct_expect_max = nf_ct_expect_hsize * 4; | ||
572 | 574 | ||
573 | net->ct.expect_count = 0; | 575 | net->ct.expect_count = 0; |
574 | net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, | 576 | net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, |
@@ -576,11 +578,13 @@ int nf_conntrack_expect_init(struct net *net) | |||
576 | if (net->ct.expect_hash == NULL) | 578 | if (net->ct.expect_hash == NULL) |
577 | goto err1; | 579 | goto err1; |
578 | 580 | ||
579 | nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect", | 581 | if (net_eq(net, &init_net)) { |
582 | nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect", | ||
580 | sizeof(struct nf_conntrack_expect), | 583 | sizeof(struct nf_conntrack_expect), |
581 | 0, 0, NULL); | 584 | 0, 0, NULL); |
582 | if (!nf_ct_expect_cachep) | 585 | if (!nf_ct_expect_cachep) |
583 | goto err2; | 586 | goto err2; |
587 | } | ||
584 | 588 | ||
585 | err = exp_proc_init(net); | 589 | err = exp_proc_init(net); |
586 | if (err < 0) | 590 | if (err < 0) |
@@ -589,7 +593,8 @@ int nf_conntrack_expect_init(struct net *net) | |||
589 | return 0; | 593 | return 0; |
590 | 594 | ||
591 | err3: | 595 | err3: |
592 | kmem_cache_destroy(nf_ct_expect_cachep); | 596 | if (net_eq(net, &init_net)) |
597 | kmem_cache_destroy(nf_ct_expect_cachep); | ||
593 | err2: | 598 | err2: |
594 | nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc, | 599 | nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc, |
595 | nf_ct_expect_hsize); | 600 | nf_ct_expect_hsize); |
@@ -600,7 +605,8 @@ err1: | |||
600 | void nf_conntrack_expect_fini(struct net *net) | 605 | void nf_conntrack_expect_fini(struct net *net) |
601 | { | 606 | { |
602 | exp_proc_remove(net); | 607 | exp_proc_remove(net); |
603 | kmem_cache_destroy(nf_ct_expect_cachep); | 608 | if (net_eq(net, &init_net)) |
609 | kmem_cache_destroy(nf_ct_expect_cachep); | ||
604 | nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc, | 610 | nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc, |
605 | nf_ct_expect_hsize); | 611 | nf_ct_expect_hsize); |
606 | } | 612 | } |