Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[linux-2.6-microblaze.git] / net / netfilter / nf_conntrack_standalone.c
index c026c47..958a145 100644 (file)
@@ -48,6 +48,8 @@ EXPORT_SYMBOL_GPL(print_tuple);
 
 struct ct_iter_state {
        struct seq_net_private p;
+       struct hlist_nulls_head *hash;
+       unsigned int htable_size;
        unsigned int bucket;
        u_int64_t time_now;
 };
@@ -58,9 +60,10 @@ static struct hlist_nulls_node *ct_get_first(struct seq_file *seq)
        struct hlist_nulls_node *n;
 
        for (st->bucket = 0;
-            st->bucket < nf_conntrack_htable_size;
+            st->bucket < st->htable_size;
             st->bucket++) {
-               n = rcu_dereference(hlist_nulls_first_rcu(&nf_conntrack_hash[st->bucket]));
+               n = rcu_dereference(
+                       hlist_nulls_first_rcu(&st->hash[st->bucket]));
                if (!is_a_nulls(n))
                        return n;
        }
@@ -75,12 +78,11 @@ static struct hlist_nulls_node *ct_get_next(struct seq_file *seq,
        head = rcu_dereference(hlist_nulls_next_rcu(head));
        while (is_a_nulls(head)) {
                if (likely(get_nulls_value(head) == st->bucket)) {
-                       if (++st->bucket >= nf_conntrack_htable_size)
+                       if (++st->bucket >= st->htable_size)
                                return NULL;
                }
                head = rcu_dereference(
-                               hlist_nulls_first_rcu(
-                                       &nf_conntrack_hash[st->bucket]));
+                       hlist_nulls_first_rcu(&st->hash[st->bucket]));
        }
        return head;
 }
@@ -102,6 +104,8 @@ static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
 
        st->time_now = ktime_get_real_ns();
        rcu_read_lock();
+
+       nf_conntrack_get_ht(&st->hash, &st->htable_size);
        return ct_get_idx(seq, *pos);
 }
 
@@ -434,8 +438,29 @@ static void nf_conntrack_standalone_fini_proc(struct net *net)
 
 #ifdef CONFIG_SYSCTL
 /* Log invalid packets of a given protocol */
-static int log_invalid_proto_min = 0;
-static int log_invalid_proto_max = 255;
+static int log_invalid_proto_min __read_mostly;
+static int log_invalid_proto_max __read_mostly = 255;
+
+/* size the user *wants to set */
+static unsigned int nf_conntrack_htable_size_user __read_mostly;
+
+static int
+nf_conntrack_hash_sysctl(struct ctl_table *table, int write,
+                        void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int ret;
+
+       ret = proc_dointvec(table, write, buffer, lenp, ppos);
+       if (ret < 0 || !write)
+               return ret;
+
+       /* update ret, we might not be able to satisfy request */
+       ret = nf_conntrack_hash_resize(nf_conntrack_htable_size_user);
+
+       /* update it to the actual value used by conntrack */
+       nf_conntrack_htable_size_user = nf_conntrack_htable_size;
+       return ret;
+}
 
 static struct ctl_table_header *nf_ct_netfilter_header;
 
@@ -456,10 +481,10 @@ static struct ctl_table nf_ct_sysctl_table[] = {
        },
        {
                .procname       = "nf_conntrack_buckets",
-               .data           = &nf_conntrack_htable_size,
+               .data           = &nf_conntrack_htable_size_user,
                .maxlen         = sizeof(unsigned int),
-               .mode           = 0444,
-               .proc_handler   = proc_dointvec,
+               .mode           = 0644,
+               .proc_handler   = nf_conntrack_hash_sysctl,
        },
        {
                .procname       = "nf_conntrack_checksum",
@@ -515,6 +540,9 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
        if (net->user_ns != &init_user_ns)
                table[0].procname = NULL;
 
+       if (!net_eq(&init_net, net))
+               table[2].mode = 0444;
+
        net->ct.sysctl_header = register_net_sysctl(net, "net/netfilter", table);
        if (!net->ct.sysctl_header)
                goto out_unregister_netfilter;
@@ -604,6 +632,8 @@ static int __init nf_conntrack_standalone_init(void)
                ret = -ENOMEM;
                goto out_sysctl;
        }
+
+       nf_conntrack_htable_size_user = nf_conntrack_htable_size;
 #endif
 
        ret = register_pernet_subsys(&nf_conntrack_net_ops);