]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/netfilter/nf_conntrack_core.c
netfilter: netns nf_conntrack: per-netns conntrack count
[karo-tx-linux.git] / net / netfilter / nf_conntrack_core.c
index 9d1830da8e84b86286c793cf8f58f98f10f793ce..8299b3490e77e591b8c690de79d7e162814e35f4 100644 (file)
 DEFINE_SPINLOCK(nf_conntrack_lock);
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
 
-/* nf_conntrack_standalone needs this */
-atomic_t nf_conntrack_count = ATOMIC_INIT(0);
-EXPORT_SYMBOL_GPL(nf_conntrack_count);
-
 unsigned int nf_conntrack_htable_size __read_mostly;
 EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
 
@@ -464,7 +460,8 @@ static noinline int early_drop(unsigned int hash)
        return dropped;
 }
 
-struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
+struct nf_conn *nf_conntrack_alloc(struct net *net,
+                                  const struct nf_conntrack_tuple *orig,
                                   const struct nf_conntrack_tuple *repl,
                                   gfp_t gfp)
 {
@@ -476,13 +473,13 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
        }
 
        /* We don't want any race condition at early drop stage */
-       atomic_inc(&nf_conntrack_count);
+       atomic_inc(&net->ct.count);
 
        if (nf_conntrack_max &&
-           unlikely(atomic_read(&nf_conntrack_count) > nf_conntrack_max)) {
+           unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) {
                unsigned int hash = hash_conntrack(orig);
                if (!early_drop(hash)) {
-                       atomic_dec(&nf_conntrack_count);
+                       atomic_dec(&net->ct.count);
                        if (net_ratelimit())
                                printk(KERN_WARNING
                                       "nf_conntrack: table full, dropping"
@@ -494,7 +491,7 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
        ct = kmem_cache_zalloc(nf_conntrack_cachep, gfp);
        if (ct == NULL) {
                pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n");
-               atomic_dec(&nf_conntrack_count);
+               atomic_dec(&net->ct.count);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -503,6 +500,9 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
        ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
        /* Don't set timer yet: wait for confirmation */
        setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct);
+#ifdef CONFIG_NET_NS
+       ct->ct_net = net;
+#endif
        INIT_RCU_HEAD(&ct->rcu);
 
        return ct;
@@ -512,10 +512,11 @@ EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
 static void nf_conntrack_free_rcu(struct rcu_head *head)
 {
        struct nf_conn *ct = container_of(head, struct nf_conn, rcu);
+       struct net *net = nf_ct_net(ct);
 
        nf_ct_ext_free(ct);
        kmem_cache_free(nf_conntrack_cachep, ct);
-       atomic_dec(&nf_conntrack_count);
+       atomic_dec(&net->ct.count);
 }
 
 void nf_conntrack_free(struct nf_conn *ct)
@@ -528,7 +529,8 @@ EXPORT_SYMBOL_GPL(nf_conntrack_free);
 /* Allocate a new conntrack: we return -ENOMEM if classification
    failed due to stress.  Otherwise it really is unclassifiable. */
 static struct nf_conntrack_tuple_hash *
-init_conntrack(const struct nf_conntrack_tuple *tuple,
+init_conntrack(struct net *net,
+              const struct nf_conntrack_tuple *tuple,
               struct nf_conntrack_l3proto *l3proto,
               struct nf_conntrack_l4proto *l4proto,
               struct sk_buff *skb,
@@ -544,7 +546,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
                return NULL;
        }
 
-       ct = nf_conntrack_alloc(tuple, &repl_tuple, GFP_ATOMIC);
+       ct = nf_conntrack_alloc(net, tuple, &repl_tuple, GFP_ATOMIC);
        if (ct == NULL || IS_ERR(ct)) {
                pr_debug("Can't allocate conntrack.\n");
                return (struct nf_conntrack_tuple_hash *)ct;
@@ -631,7 +633,8 @@ resolve_normal_ct(struct sk_buff *skb,
        /* look for tuple match */
        h = nf_conntrack_find_get(&tuple);
        if (!h) {
-               h = init_conntrack(&tuple, l3proto, l4proto, skb, dataoff);
+               h = init_conntrack(&init_net, &tuple, l3proto, l4proto, skb,
+                                  dataoff);
                if (!h)
                        return NULL;
                if (IS_ERR(h))
@@ -665,7 +668,7 @@ resolve_normal_ct(struct sk_buff *skb,
 }
 
 unsigned int
-nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff *skb)
+nf_conntrack_in(u_int8_t pf, unsigned int hooknum, struct sk_buff *skb)
 {
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
@@ -683,7 +686,7 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff *skb)
        }
 
        /* rcu_read_lock()ed by nf_hook_slow */
-       l3proto = __nf_ct_l3proto_find((u_int16_t)pf);
+       l3proto = __nf_ct_l3proto_find(pf);
        ret = l3proto->get_l4proto(skb, skb_network_offset(skb),
                                   &dataoff, &protonum);
        if (ret <= 0) {
@@ -693,7 +696,7 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff *skb)
                return -ret;
        }
 
-       l4proto = __nf_ct_l4proto_find((u_int16_t)pf, protonum);
+       l4proto = __nf_ct_l4proto_find(pf, protonum);
 
        /* It may be an special packet, error, unclean...
         * inverse of the return code tells to the netfilter
@@ -1006,7 +1009,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_flush);
 
 /* Mishearing the voices in his head, our hero wonders how he's
    supposed to kill the mall. */
-void nf_conntrack_cleanup(void)
+void nf_conntrack_cleanup(struct net *net)
 {
        rcu_assign_pointer(ip_ct_attach, NULL);
 
@@ -1018,7 +1021,7 @@ void nf_conntrack_cleanup(void)
        nf_ct_event_cache_flush();
  i_see_dead_people:
        nf_conntrack_flush();
-       if (atomic_read(&nf_conntrack_count) != 0) {
+       if (atomic_read(&net->ct.count) != 0) {
                schedule();
                goto i_see_dead_people;
        }
@@ -1120,7 +1123,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize);
 module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
                  &nf_conntrack_htable_size, 0600);
 
-int __init nf_conntrack_init(void)
+int nf_conntrack_init(struct net *net)
 {
        int max_factor = 8;
        int ret;
@@ -1142,6 +1145,7 @@ int __init nf_conntrack_init(void)
                 * entries. */
                max_factor = 4;
        }
+       atomic_set(&net->ct.count, 0);
        nf_conntrack_hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size,
                                                  &nf_conntrack_vmalloc);
        if (!nf_conntrack_hash) {
@@ -1185,6 +1189,9 @@ int __init nf_conntrack_init(void)
 
        /* Set up fake conntrack:
            - to never be deleted, not in any hashes */
+#ifdef CONFIG_NET_NS
+       nf_conntrack_untracked.ct_net = &init_net;
+#endif
        atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
        /*  - and look it like as a confirmed connection */
        set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status);