Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alexey Dobriyan and committed by
Patrick McHardy
08f6547d d716a4df

+114 -63
+98 -53
net/netfilter/nf_conntrack_core.c
··· 1010 1010 } 1011 1011 EXPORT_SYMBOL_GPL(nf_conntrack_flush); 1012 1012 1013 - /* Mishearing the voices in his head, our hero wonders how he's 1014 - supposed to kill the mall. */ 1015 - void nf_conntrack_cleanup(struct net *net) 1013 + static void nf_conntrack_cleanup_init_net(void) 1016 1014 { 1017 - rcu_assign_pointer(ip_ct_attach, NULL); 1015 + nf_conntrack_helper_fini(); 1016 + nf_conntrack_proto_fini(); 1017 + kmem_cache_destroy(nf_conntrack_cachep); 1018 + } 1018 1019 1019 - /* This makes sure all current packets have passed through 1020 - netfilter framework. Roll on, two-stage module 1021 - delete... */ 1022 - synchronize_net(); 1023 - 1020 + static void nf_conntrack_cleanup_net(struct net *net) 1021 + { 1024 1022 nf_ct_event_cache_flush(net); 1025 1023 nf_conntrack_ecache_fini(net); 1026 1024 i_see_dead_people: ··· 1031 1033 while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1) 1032 1034 schedule(); 1033 1035 1034 - rcu_assign_pointer(nf_ct_destroy, NULL); 1035 - 1036 - kmem_cache_destroy(nf_conntrack_cachep); 1037 1036 nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, 1038 1037 nf_conntrack_htable_size); 1039 - 1040 1038 nf_conntrack_acct_fini(net); 1041 1039 nf_conntrack_expect_fini(net); 1042 1040 free_percpu(net->ct.stat); 1043 - nf_conntrack_helper_fini(); 1044 - nf_conntrack_proto_fini(); 1041 + } 1042 + 1043 + /* Mishearing the voices in his head, our hero wonders how he's 1044 + supposed to kill the mall. */ 1045 + void nf_conntrack_cleanup(struct net *net) 1046 + { 1047 + if (net_eq(net, &init_net)) 1048 + rcu_assign_pointer(ip_ct_attach, NULL); 1049 + 1050 + /* This makes sure all current packets have passed through 1051 + netfilter framework. Roll on, two-stage module 1052 + delete... */ 1053 + synchronize_net(); 1054 + 1055 + nf_conntrack_cleanup_net(net); 1056 + 1057 + if (net_eq(net, &init_net)) { 1058 + rcu_assign_pointer(nf_ct_destroy, NULL); 1059 + nf_conntrack_cleanup_init_net(); 1060 + } 1045 1061 } 1046 1062 1047 1063 struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced) ··· 1140 1128 module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, 1141 1129 &nf_conntrack_htable_size, 0600); 1142 1130 1143 - int nf_conntrack_init(struct net *net) 1131 + static int nf_conntrack_init_init_net(void) 1144 1132 { 1145 1133 int max_factor = 8; 1146 1134 int ret; ··· 1162 1150 * entries. */ 1163 1151 max_factor = 4; 1164 1152 } 1165 - atomic_set(&net->ct.count, 0); 1166 - net->ct.stat = alloc_percpu(struct ip_conntrack_stat); 1167 - if (!net->ct.stat) 1168 - goto err_stat; 1169 - ret = nf_conntrack_ecache_init(net); 1170 - if (ret < 0) 1171 - goto err_ecache; 1172 - net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, 1173 - &net->ct.hash_vmalloc); 1174 - if (!net->ct.hash) { 1175 - printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); 1176 - goto err_hash; 1177 - } 1178 - INIT_HLIST_HEAD(&net->ct.unconfirmed); 1179 - 1180 1153 nf_conntrack_max = max_factor * nf_conntrack_htable_size; 1181 1154 1182 1155 printk("nf_conntrack version %s (%u buckets, %d max)\n", ··· 1173 1176 0, 0, NULL); 1174 1177 if (!nf_conntrack_cachep) { 1175 1178 printk(KERN_ERR "Unable to create nf_conn slab cache\n"); 1176 - goto err_free_hash; 1179 + ret = -ENOMEM; 1180 + goto err_cache; 1177 1181 } 1178 1182 1179 1183 ret = nf_conntrack_proto_init(); 1180 1184 if (ret < 0) 1181 - goto err_free_conntrack_slab; 1182 - 1183 - ret = nf_conntrack_expect_init(net); 1184 - if (ret < 0) 1185 - goto out_fini_proto; 1185 + goto err_proto; 1186 1186 1187 1187 ret = nf_conntrack_helper_init(); 1188 1188 if (ret < 0) 1189 - goto out_fini_expect; 1189 + goto err_helper; 1190 1190 1191 + return 0; 1192 + 1193 + err_helper: 1194 + nf_conntrack_proto_fini(); 1195 + err_proto: 1196 + kmem_cache_destroy(nf_conntrack_cachep); 1197 + err_cache: 1198 + return ret; 1199 + } 1200 + 1201 + static int nf_conntrack_init_net(struct net *net) 1202 + { 1203 + int ret; 1204 + 1205 + atomic_set(&net->ct.count, 0); 1206 + INIT_HLIST_HEAD(&net->ct.unconfirmed); 1207 + net->ct.stat = alloc_percpu(struct ip_conntrack_stat); 1208 + if (!net->ct.stat) { 1209 + ret = -ENOMEM; 1210 + goto err_stat; 1211 + } 1212 + ret = nf_conntrack_ecache_init(net); 1213 + if (ret < 0) 1214 + goto err_ecache; 1215 + net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, 1216 + &net->ct.hash_vmalloc); 1217 + if (!net->ct.hash) { 1218 + ret = -ENOMEM; 1219 + printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); 1220 + goto err_hash; 1221 + } 1222 + ret = nf_conntrack_expect_init(net); 1223 + if (ret < 0) 1224 + goto err_expect; 1191 1225 ret = nf_conntrack_acct_init(net); 1192 1226 if (ret < 0) 1193 - goto out_fini_helper; 1194 - 1195 - /* For use by REJECT target */ 1196 - rcu_assign_pointer(ip_ct_attach, nf_conntrack_attach); 1197 - rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); 1227 + goto err_acct; 1198 1228 1199 1229 /* Set up fake conntrack: 1200 1230 - to never be deleted, not in any hashes */ ··· 1232 1208 /* - and look it like as a confirmed connection */ 1233 1209 set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status); 1234 1210 1235 - return ret; 1211 + return 0; 1236 1212 1237 - out_fini_helper: 1238 - nf_conntrack_helper_fini(); 1239 - out_fini_expect: 1213 + err_acct: 1240 1214 nf_conntrack_expect_fini(net); 1241 - out_fini_proto: 1242 - nf_conntrack_proto_fini(); 1243 - err_free_conntrack_slab: 1244 - kmem_cache_destroy(nf_conntrack_cachep); 1245 - err_free_hash: 1215 + err_expect: 1246 1216 nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, 1247 1217 nf_conntrack_htable_size); 1248 1218 err_hash: ··· 1244 1226 err_ecache: 1245 1227 free_percpu(net->ct.stat); 1246 1228 err_stat: 1247 - return -ENOMEM; 1229 + return ret; 1230 + } 1231 + 1232 + int nf_conntrack_init(struct net *net) 1233 + { 1234 + int ret; 1235 + 1236 + if (net_eq(net, &init_net)) { 1237 + ret = nf_conntrack_init_init_net(); 1238 + if (ret < 0) 1239 + goto out_init_net; 1240 + } 1241 + ret = nf_conntrack_init_net(net); 1242 + if (ret < 0) 1243 + goto out_net; 1244 + 1245 + if (net_eq(net, &init_net)) { 1246 + /* For use by REJECT target */ 1247 + rcu_assign_pointer(ip_ct_attach, nf_conntrack_attach); 1248 + rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); 1249 + } 1250 + return 0; 1251 + 1252 + out_net: 1253 + if (net_eq(net, &init_net)) 1254 + nf_conntrack_cleanup_init_net(); 1255 + out_init_net: 1256 + return ret; 1248 1257 }
+16 -10
net/netfilter/nf_conntrack_expect.c
··· 563 563 { 564 564 int err = -ENOMEM; 565 565 566 - if (!nf_ct_expect_hsize) { 567 - nf_ct_expect_hsize = nf_conntrack_htable_size / 256; 568 - if (!nf_ct_expect_hsize) 569 - nf_ct_expect_hsize = 1; 566 + if (net_eq(net, &init_net)) { 567 + if (!nf_ct_expect_hsize) { 568 + nf_ct_expect_hsize = nf_conntrack_htable_size / 256; 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 575 net->ct.expect_count = 0; 574 576 net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, ··· 578 576 if (net->ct.expect_hash == NULL) 579 577 goto err1; 580 578 581 - nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect", 579 + if (net_eq(net, &init_net)) { 580 + nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect", 582 581 sizeof(struct nf_conntrack_expect), 583 582 0, 0, NULL); 584 - if (!nf_ct_expect_cachep) 585 - goto err2; 583 + if (!nf_ct_expect_cachep) 584 + goto err2; 585 + } 586 586 587 587 err = exp_proc_init(net); 588 588 if (err < 0) ··· 593 589 return 0; 594 590 595 591 err3: 596 - kmem_cache_destroy(nf_ct_expect_cachep); 592 + if (net_eq(net, &init_net)) 593 + kmem_cache_destroy(nf_ct_expect_cachep); 597 594 err2: 598 595 nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc, 599 596 nf_ct_expect_hsize); ··· 605 600 void nf_conntrack_expect_fini(struct net *net) 606 601 { 607 602 exp_proc_remove(net); 608 - kmem_cache_destroy(nf_ct_expect_cachep); 603 + if (net_eq(net, &init_net)) 604 + kmem_cache_destroy(nf_ct_expect_cachep); 609 605 nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc, 610 606 nf_ct_expect_hsize); 611 607 }