aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2016-06-22 07:26:10 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2016-06-24 05:03:28 -0400
commit3183ab8997a477c8d9ad175a1cef70dff77c6dbc (patch)
tree05fc36b7e2fa3b896cc412cdd8f0f1ac796965a3 /net/netfilter
parent8eee54be73f4b938dbf48e95c0dbecb5f19b08ee (diff)
netfilter: conntrack: allow increasing bucket size via sysctl too
No need to restrict this to module parameter. We export a copy of the real hash size -- when user alters the value we allocate the new table, copy entries etc before we update the real size to the requested one. This is also needed because the real size is used by concurrent readers and cannot be changed without synchronizing the conntrack generation seqcnt. We only allow changing this value from the initial net namespace. Tested using http-client-benchmark vs. httpterm with concurrent while true;do echo $RANDOM > /proc/sys/net/netfilter/nf_conntrack_buckets done Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nf_conntrack_core.c41
-rw-r--r--net/netfilter/nf_conntrack_standalone.c36
2 files changed, 59 insertions, 18 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index a459176c3253..e17d5c7faca0 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1595,24 +1595,14 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
1595} 1595}
1596EXPORT_SYMBOL_GPL(nf_ct_alloc_hashtable); 1596EXPORT_SYMBOL_GPL(nf_ct_alloc_hashtable);
1597 1597
1598int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) 1598int nf_conntrack_hash_resize(unsigned int hashsize)
1599{ 1599{
1600 int i, bucket, rc; 1600 int i, bucket;
1601 unsigned int hashsize, old_size; 1601 unsigned int old_size;
1602 struct hlist_nulls_head *hash, *old_hash; 1602 struct hlist_nulls_head *hash, *old_hash;
1603 struct nf_conntrack_tuple_hash *h; 1603 struct nf_conntrack_tuple_hash *h;
1604 struct nf_conn *ct; 1604 struct nf_conn *ct;
1605 1605
1606 if (current->nsproxy->net_ns != &init_net)
1607 return -EOPNOTSUPP;
1608
1609 /* On boot, we can set this without any fancy locking. */
1610 if (!nf_conntrack_htable_size)
1611 return param_set_uint(val, kp);
1612
1613 rc = kstrtouint(val, 0, &hashsize);
1614 if (rc)
1615 return rc;
1616 if (!hashsize) 1606 if (!hashsize)
1617 return -EINVAL; 1607 return -EINVAL;
1618 1608
@@ -1620,6 +1610,12 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
1620 if (!hash) 1610 if (!hash)
1621 return -ENOMEM; 1611 return -ENOMEM;
1622 1612
1613 old_size = nf_conntrack_htable_size;
1614 if (old_size == hashsize) {
1615 nf_ct_free_hashtable(hash, hashsize);
1616 return 0;
1617 }
1618
1623 local_bh_disable(); 1619 local_bh_disable();
1624 nf_conntrack_all_lock(); 1620 nf_conntrack_all_lock();
1625 write_seqcount_begin(&nf_conntrack_generation); 1621 write_seqcount_begin(&nf_conntrack_generation);
@@ -1655,6 +1651,25 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
1655 nf_ct_free_hashtable(old_hash, old_size); 1651 nf_ct_free_hashtable(old_hash, old_size);
1656 return 0; 1652 return 0;
1657} 1653}
1654
1655int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
1656{
1657 unsigned int hashsize;
1658 int rc;
1659
1660 if (current->nsproxy->net_ns != &init_net)
1661 return -EOPNOTSUPP;
1662
1663 /* On boot, we can set this without any fancy locking. */
1664 if (!nf_conntrack_htable_size)
1665 return param_set_uint(val, kp);
1666
1667 rc = kstrtouint(val, 0, &hashsize);
1668 if (rc)
1669 return rc;
1670
1671 return nf_conntrack_hash_resize(hashsize);
1672}
1658EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize); 1673EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize);
1659 1674
1660module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, 1675module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index f87e84ebcec3..a0cc1919f081 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -434,8 +434,29 @@ static void nf_conntrack_standalone_fini_proc(struct net *net)
434 434
435#ifdef CONFIG_SYSCTL 435#ifdef CONFIG_SYSCTL
436/* Log invalid packets of a given protocol */ 436/* Log invalid packets of a given protocol */
437static int log_invalid_proto_min = 0; 437static int log_invalid_proto_min __read_mostly;
438static int log_invalid_proto_max = 255; 438static int log_invalid_proto_max __read_mostly = 255;
439
440/* size the user *wants to set */
441static unsigned int nf_conntrack_htable_size_user __read_mostly;
442
443static int
444nf_conntrack_hash_sysctl(struct ctl_table *table, int write,
445 void __user *buffer, size_t *lenp, loff_t *ppos)
446{
447 int ret;
448
449 ret = proc_dointvec(table, write, buffer, lenp, ppos);
450 if (ret < 0 || !write)
451 return ret;
452
453 /* update ret, we might not be able to satisfy request */
454 ret = nf_conntrack_hash_resize(nf_conntrack_htable_size_user);
455
456 /* update it to the actual value used by conntrack */
457 nf_conntrack_htable_size_user = nf_conntrack_htable_size;
458 return ret;
459}
439 460
440static struct ctl_table_header *nf_ct_netfilter_header; 461static struct ctl_table_header *nf_ct_netfilter_header;
441 462
@@ -456,10 +477,10 @@ static struct ctl_table nf_ct_sysctl_table[] = {
456 }, 477 },
457 { 478 {
458 .procname = "nf_conntrack_buckets", 479 .procname = "nf_conntrack_buckets",
459 .data = &nf_conntrack_htable_size, 480 .data = &nf_conntrack_htable_size_user,
460 .maxlen = sizeof(unsigned int), 481 .maxlen = sizeof(unsigned int),
461 .mode = 0444, 482 .mode = 0644,
462 .proc_handler = proc_dointvec, 483 .proc_handler = nf_conntrack_hash_sysctl,
463 }, 484 },
464 { 485 {
465 .procname = "nf_conntrack_checksum", 486 .procname = "nf_conntrack_checksum",
@@ -517,6 +538,9 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
517 if (net->user_ns != &init_user_ns) 538 if (net->user_ns != &init_user_ns)
518 table[0].procname = NULL; 539 table[0].procname = NULL;
519 540
541 if (!net_eq(&init_net, net))
542 table[2].mode = 0444;
543
520 net->ct.sysctl_header = register_net_sysctl(net, "net/netfilter", table); 544 net->ct.sysctl_header = register_net_sysctl(net, "net/netfilter", table);
521 if (!net->ct.sysctl_header) 545 if (!net->ct.sysctl_header)
522 goto out_unregister_netfilter; 546 goto out_unregister_netfilter;
@@ -606,6 +630,8 @@ static int __init nf_conntrack_standalone_init(void)
606 ret = -ENOMEM; 630 ret = -ENOMEM;
607 goto out_sysctl; 631 goto out_sysctl;
608 } 632 }
633
634 nf_conntrack_htable_size_user = nf_conntrack_htable_size;
609#endif 635#endif
610 636
611 ret = register_pernet_subsys(&nf_conntrack_net_ops); 637 ret = register_pernet_subsys(&nf_conntrack_net_ops);