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

netfilter: conntrack: use a single expectation table for all namespaces

We already include netns address in the hash and compare the netns pointers
during lookup, so even if namespaces have overlapping addresses entries
will be spread across the expectation table.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
0a93aaed a9a083c3

+25 -33
+1
include/net/netfilter/nf_conntrack_expect.h
··· 10 10 11 11 extern unsigned int nf_ct_expect_hsize; 12 12 extern unsigned int nf_ct_expect_max; 13 + extern struct hlist_head *nf_ct_expect_hash; 13 14 14 15 struct nf_conntrack_expect { 15 16 /* Conntrack expectation list member */
-1
include/net/netns/conntrack.h
··· 94 94 int sysctl_checksum; 95 95 96 96 struct kmem_cache *nf_conntrack_cachep; 97 - struct hlist_head *expect_hash; 98 97 struct ct_pcpu __percpu *pcpu_lists; 99 98 struct ip_conntrack_stat __percpu *stat; 100 99 struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb;
+2 -4
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
··· 236 236 237 237 static struct hlist_node *ct_expect_get_first(struct seq_file *seq) 238 238 { 239 - struct net *net = seq_file_net(seq); 240 239 struct ct_expect_iter_state *st = seq->private; 241 240 struct hlist_node *n; 242 241 243 242 for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { 244 243 n = rcu_dereference( 245 - hlist_first_rcu(&net->ct.expect_hash[st->bucket])); 244 + hlist_first_rcu(&nf_ct_expect_hash[st->bucket])); 246 245 if (n) 247 246 return n; 248 247 } ··· 251 252 static struct hlist_node *ct_expect_get_next(struct seq_file *seq, 252 253 struct hlist_node *head) 253 254 { 254 - struct net *net = seq_file_net(seq); 255 255 struct ct_expect_iter_state *st = seq->private; 256 256 257 257 head = rcu_dereference(hlist_next_rcu(head)); ··· 258 260 if (++st->bucket >= nf_ct_expect_hsize) 259 261 return NULL; 260 262 head = rcu_dereference( 261 - hlist_first_rcu(&net->ct.expect_hash[st->bucket])); 263 + hlist_first_rcu(&nf_ct_expect_hash[st->bucket])); 262 264 } 263 265 return head; 264 266 }
+18 -24
net/netfilter/nf_conntrack_expect.c
··· 36 36 unsigned int nf_ct_expect_hsize __read_mostly; 37 37 EXPORT_SYMBOL_GPL(nf_ct_expect_hsize); 38 38 39 + struct hlist_head *nf_ct_expect_hash __read_mostly; 40 + EXPORT_SYMBOL_GPL(nf_ct_expect_hash); 41 + 39 42 unsigned int nf_ct_expect_max __read_mostly; 40 43 41 44 static struct kmem_cache *nf_ct_expect_cachep __read_mostly; ··· 115 112 return NULL; 116 113 117 114 h = nf_ct_expect_dst_hash(net, tuple); 118 - hlist_for_each_entry_rcu(i, &net->ct.expect_hash[h], hnode) { 115 + hlist_for_each_entry_rcu(i, &nf_ct_expect_hash[h], hnode) { 119 116 if (nf_ct_exp_equal(tuple, i, zone, net)) 120 117 return i; 121 118 } ··· 155 152 return NULL; 156 153 157 154 h = nf_ct_expect_dst_hash(net, tuple); 158 - hlist_for_each_entry(i, &net->ct.expect_hash[h], hnode) { 155 + hlist_for_each_entry(i, &nf_ct_expect_hash[h], hnode) { 159 156 if (!(i->flags & NF_CT_EXPECT_INACTIVE) && 160 157 nf_ct_exp_equal(tuple, i, zone, net)) { 161 158 exp = i; ··· 366 363 hlist_add_head(&exp->lnode, &master_help->expectations); 367 364 master_help->expecting[exp->class]++; 368 365 369 - hlist_add_head_rcu(&exp->hnode, &net->ct.expect_hash[h]); 366 + hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]); 370 367 net->ct.expect_count++; 371 368 372 369 setup_timer(&exp->timeout, nf_ct_expectation_timed_out, ··· 418 415 goto out; 419 416 } 420 417 h = nf_ct_expect_dst_hash(net, &expect->tuple); 421 - hlist_for_each_entry_safe(i, next, &net->ct.expect_hash[h], hnode) { 418 + hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) { 422 419 if (expect_matches(i, expect)) { 423 420 if (del_timer(&i->timeout)) { 424 421 nf_ct_unlink_expect(i); ··· 484 481 485 482 static struct hlist_node *ct_expect_get_first(struct seq_file *seq) 486 483 { 487 - struct net *net = seq_file_net(seq); 488 484 struct ct_expect_iter_state *st = seq->private; 489 485 struct hlist_node *n; 490 486 491 487 for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { 492 - n = rcu_dereference(hlist_first_rcu(&net->ct.expect_hash[st->bucket])); 488 + n = rcu_dereference(hlist_first_rcu(&nf_ct_expect_hash[st->bucket])); 493 489 if (n) 494 490 return n; 495 491 } ··· 498 496 static struct hlist_node *ct_expect_get_next(struct seq_file *seq, 499 497 struct hlist_node *head) 500 498 { 501 - struct net *net = seq_file_net(seq); 502 499 struct ct_expect_iter_state *st = seq->private; 503 500 504 501 head = rcu_dereference(hlist_next_rcu(head)); 505 502 while (head == NULL) { 506 503 if (++st->bucket >= nf_ct_expect_hsize) 507 504 return NULL; 508 - head = rcu_dereference(hlist_first_rcu(&net->ct.expect_hash[st->bucket])); 505 + head = rcu_dereference(hlist_first_rcu(&nf_ct_expect_hash[st->bucket])); 509 506 } 510 507 return head; 511 508 } ··· 637 636 638 637 int nf_conntrack_expect_pernet_init(struct net *net) 639 638 { 640 - int err = -ENOMEM; 641 - 642 639 net->ct.expect_count = 0; 643 - net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, 0); 644 - if (net->ct.expect_hash == NULL) 645 - goto err1; 646 - 647 - err = exp_proc_init(net); 648 - if (err < 0) 649 - goto err2; 650 - 651 - return 0; 652 - err2: 653 - nf_ct_free_hashtable(net->ct.expect_hash, nf_ct_expect_hsize); 654 - err1: 655 - return err; 640 + return exp_proc_init(net); 656 641 } 657 642 658 643 void nf_conntrack_expect_pernet_fini(struct net *net) 659 644 { 660 645 exp_proc_remove(net); 661 - nf_ct_free_hashtable(net->ct.expect_hash, nf_ct_expect_hsize); 662 646 } 663 647 664 648 int nf_conntrack_expect_init(void) ··· 659 673 0, 0, NULL); 660 674 if (!nf_ct_expect_cachep) 661 675 return -ENOMEM; 676 + 677 + nf_ct_expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, 0); 678 + if (!nf_ct_expect_hash) { 679 + kmem_cache_destroy(nf_ct_expect_cachep); 680 + return -ENOMEM; 681 + } 682 + 662 683 return 0; 663 684 } 664 685 ··· 673 680 { 674 681 rcu_barrier(); /* Wait for call_rcu() before destroy */ 675 682 kmem_cache_destroy(nf_ct_expect_cachep); 683 + nf_ct_free_hashtable(nf_ct_expect_hash, nf_ct_expect_hsize); 676 684 }
+1 -1
net/netfilter/nf_conntrack_helper.c
··· 400 400 spin_lock_bh(&nf_conntrack_expect_lock); 401 401 for (i = 0; i < nf_ct_expect_hsize; i++) { 402 402 hlist_for_each_entry_safe(exp, next, 403 - &net->ct.expect_hash[i], hnode) { 403 + &nf_ct_expect_hash[i], hnode) { 404 404 struct nf_conn_help *help = nfct_help(exp->master); 405 405 if ((rcu_dereference_protected( 406 406 help->helper,
+3 -3
net/netfilter/nf_conntrack_netlink.c
··· 2632 2632 last = (struct nf_conntrack_expect *)cb->args[1]; 2633 2633 for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) { 2634 2634 restart: 2635 - hlist_for_each_entry(exp, &net->ct.expect_hash[cb->args[0]], 2635 + hlist_for_each_entry(exp, &nf_ct_expect_hash[cb->args[0]], 2636 2636 hnode) { 2637 2637 if (l3proto && exp->tuple.src.l3num != l3proto) 2638 2638 continue; ··· 2890 2890 spin_lock_bh(&nf_conntrack_expect_lock); 2891 2891 for (i = 0; i < nf_ct_expect_hsize; i++) { 2892 2892 hlist_for_each_entry_safe(exp, next, 2893 - &net->ct.expect_hash[i], 2893 + &nf_ct_expect_hash[i], 2894 2894 hnode) { 2895 2895 2896 2896 if (!net_eq(nf_ct_exp_net(exp), net)) ··· 2912 2912 spin_lock_bh(&nf_conntrack_expect_lock); 2913 2913 for (i = 0; i < nf_ct_expect_hsize; i++) { 2914 2914 hlist_for_each_entry_safe(exp, next, 2915 - &net->ct.expect_hash[i], 2915 + &nf_ct_expect_hash[i], 2916 2916 hnode) { 2917 2917 2918 2918 if (!net_eq(nf_ct_exp_net(exp), net))