aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2010-02-15 12:13:33 -0500
committerPatrick McHardy <kaber@trash.net>2010-02-15 12:13:33 -0500
commit5d0aa2ccd4699a01cfdf14886191c249d7b45a01 (patch)
tree6ea81b5eede26bd6a04bcc3cd79770c334139381
parent8fea97ec1772bbf553d89187340ef624d548e115 (diff)
netfilter: nf_conntrack: add support for "conntrack zones"
Normally, each connection needs a unique identity. Conntrack zones allow to specify a numerical zone using the CT target, connections in different zones can use the same identity. Example: iptables -t raw -A PREROUTING -i veth0 -j CT --zone 1 iptables -t raw -A OUTPUT -o veth1 -j CT --zone 1 Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--include/linux/netfilter/xt_CT.h2
-rw-r--r--include/net/ip.h3
-rw-r--r--include/net/ipv6.h3
-rw-r--r--include/net/netfilter/nf_conntrack.h5
-rw-r--r--include/net/netfilter/nf_conntrack_core.h3
-rw-r--r--include/net/netfilter/nf_conntrack_expect.h9
-rw-r--r--include/net/netfilter/nf_conntrack_extend.h2
-rw-r--r--include/net/netfilter/nf_conntrack_zones.h23
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c3
-rw-r--r--net/ipv4/netfilter/nf_conntrack_proto_icmp.c8
-rw-r--r--net/ipv4/netfilter/nf_defrag_ipv4.c12
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c24
-rw-r--r--net/ipv4/netfilter/nf_nat_pptp.c3
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c12
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c8
-rw-r--r--net/netfilter/Kconfig13
-rw-r--r--net/netfilter/nf_conntrack_core.c109
-rw-r--r--net/netfilter/nf_conntrack_expect.c21
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c3
-rw-r--r--net/netfilter/nf_conntrack_netlink.c20
-rw-r--r--net/netfilter/nf_conntrack_pptp.c14
-rw-r--r--net/netfilter/nf_conntrack_sip.c3
-rw-r--r--net/netfilter/nf_conntrack_standalone.c6
-rw-r--r--net/netfilter/xt_CT.c8
-rw-r--r--net/netfilter/xt_connlimit.c4
25 files changed, 236 insertions, 85 deletions
diff --git a/include/linux/netfilter/xt_CT.h b/include/linux/netfilter/xt_CT.h
index 7fd0effe1316..1b564106891d 100644
--- a/include/linux/netfilter/xt_CT.h
+++ b/include/linux/netfilter/xt_CT.h
@@ -5,7 +5,7 @@
5 5
6struct xt_ct_target_info { 6struct xt_ct_target_info {
7 u_int16_t flags; 7 u_int16_t flags;
8 u_int16_t __unused; 8 u_int16_t zone;
9 u_int32_t ct_events; 9 u_int32_t ct_events;
10 u_int32_t exp_events; 10 u_int32_t exp_events;
11 char helper[16]; 11 char helper[16];
diff --git a/include/net/ip.h b/include/net/ip.h
index fb63371c07a8..7bc47873e3fc 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -352,8 +352,11 @@ enum ip_defrag_users {
352 IP_DEFRAG_LOCAL_DELIVER, 352 IP_DEFRAG_LOCAL_DELIVER,
353 IP_DEFRAG_CALL_RA_CHAIN, 353 IP_DEFRAG_CALL_RA_CHAIN,
354 IP_DEFRAG_CONNTRACK_IN, 354 IP_DEFRAG_CONNTRACK_IN,
355 __IP_DEFRAG_CONNTRACK_IN_END = IP_DEFRAG_CONNTRACK_IN + USHORT_MAX,
355 IP_DEFRAG_CONNTRACK_OUT, 356 IP_DEFRAG_CONNTRACK_OUT,
357 __IP_DEFRAG_CONNTRACK_OUT_END = IP_DEFRAG_CONNTRACK_OUT + USHORT_MAX,
356 IP_DEFRAG_CONNTRACK_BRIDGE_IN, 358 IP_DEFRAG_CONNTRACK_BRIDGE_IN,
359 __IP_DEFRAG_CONNTRACK_BRIDGE_IN = IP_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX,
357 IP_DEFRAG_VS_IN, 360 IP_DEFRAG_VS_IN,
358 IP_DEFRAG_VS_OUT, 361 IP_DEFRAG_VS_OUT,
359 IP_DEFRAG_VS_FWD 362 IP_DEFRAG_VS_FWD
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 299bbf5adfb6..639ec53ea081 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -355,8 +355,11 @@ struct inet_frag_queue;
355enum ip6_defrag_users { 355enum ip6_defrag_users {
356 IP6_DEFRAG_LOCAL_DELIVER, 356 IP6_DEFRAG_LOCAL_DELIVER,
357 IP6_DEFRAG_CONNTRACK_IN, 357 IP6_DEFRAG_CONNTRACK_IN,
358 __IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHORT_MAX,
358 IP6_DEFRAG_CONNTRACK_OUT, 359 IP6_DEFRAG_CONNTRACK_OUT,
360 __IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHORT_MAX,
359 IP6_DEFRAG_CONNTRACK_BRIDGE_IN, 361 IP6_DEFRAG_CONNTRACK_BRIDGE_IN,
362 __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX,
360}; 363};
361 364
362struct ip6_create_arg { 365struct ip6_create_arg {
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 5b7d8835523f..bde095f7e845 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -198,7 +198,8 @@ extern void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int null
198extern void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size); 198extern void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size);
199 199
200extern struct nf_conntrack_tuple_hash * 200extern struct nf_conntrack_tuple_hash *
201__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); 201__nf_conntrack_find(struct net *net, u16 zone,
202 const struct nf_conntrack_tuple *tuple);
202 203
203extern void nf_conntrack_hash_insert(struct nf_conn *ct); 204extern void nf_conntrack_hash_insert(struct nf_conn *ct);
204extern void nf_ct_delete_from_lists(struct nf_conn *ct); 205extern void nf_ct_delete_from_lists(struct nf_conn *ct);
@@ -267,7 +268,7 @@ extern void
267nf_ct_iterate_cleanup(struct net *net, int (*iter)(struct nf_conn *i, void *data), void *data); 268nf_ct_iterate_cleanup(struct net *net, int (*iter)(struct nf_conn *i, void *data), void *data);
268extern void nf_conntrack_free(struct nf_conn *ct); 269extern void nf_conntrack_free(struct nf_conn *ct);
269extern struct nf_conn * 270extern struct nf_conn *
270nf_conntrack_alloc(struct net *net, 271nf_conntrack_alloc(struct net *net, u16 zone,
271 const struct nf_conntrack_tuple *orig, 272 const struct nf_conntrack_tuple *orig,
272 const struct nf_conntrack_tuple *repl, 273 const struct nf_conntrack_tuple *repl,
273 gfp_t gfp); 274 gfp_t gfp);
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index 5a449b44ba33..dffde8e6920e 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -49,7 +49,8 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
49 49
50/* Find a connection corresponding to a tuple. */ 50/* Find a connection corresponding to a tuple. */
51extern struct nf_conntrack_tuple_hash * 51extern struct nf_conntrack_tuple_hash *
52nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple); 52nf_conntrack_find_get(struct net *net, u16 zone,
53 const struct nf_conntrack_tuple *tuple);
53 54
54extern int __nf_conntrack_confirm(struct sk_buff *skb); 55extern int __nf_conntrack_confirm(struct sk_buff *skb);
55 56
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index 4b47ec19ef39..11e815084fcf 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -74,13 +74,16 @@ int nf_conntrack_expect_init(struct net *net);
74void nf_conntrack_expect_fini(struct net *net); 74void nf_conntrack_expect_fini(struct net *net);
75 75
76struct nf_conntrack_expect * 76struct nf_conntrack_expect *
77__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple); 77__nf_ct_expect_find(struct net *net, u16 zone,
78 const struct nf_conntrack_tuple *tuple);
78 79
79struct nf_conntrack_expect * 80struct nf_conntrack_expect *
80nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple); 81nf_ct_expect_find_get(struct net *net, u16 zone,
82 const struct nf_conntrack_tuple *tuple);
81 83
82struct nf_conntrack_expect * 84struct nf_conntrack_expect *
83nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple); 85nf_ct_find_expectation(struct net *net, u16 zone,
86 const struct nf_conntrack_tuple *tuple);
84 87
85void nf_ct_unlink_expect(struct nf_conntrack_expect *exp); 88void nf_ct_unlink_expect(struct nf_conntrack_expect *exp);
86void nf_ct_remove_expectations(struct nf_conn *ct); 89void nf_ct_remove_expectations(struct nf_conn *ct);
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index e192dc17c583..2d2a1f9a61d8 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -8,6 +8,7 @@ enum nf_ct_ext_id {
8 NF_CT_EXT_NAT, 8 NF_CT_EXT_NAT,
9 NF_CT_EXT_ACCT, 9 NF_CT_EXT_ACCT,
10 NF_CT_EXT_ECACHE, 10 NF_CT_EXT_ECACHE,
11 NF_CT_EXT_ZONE,
11 NF_CT_EXT_NUM, 12 NF_CT_EXT_NUM,
12}; 13};
13 14
@@ -15,6 +16,7 @@ enum nf_ct_ext_id {
15#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat 16#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat
16#define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter 17#define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter
17#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache 18#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache
19#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone
18 20
19/* Extensions: optional stuff which isn't permanently in struct. */ 21/* Extensions: optional stuff which isn't permanently in struct. */
20struct nf_ct_ext { 22struct nf_ct_ext {
diff --git a/include/net/netfilter/nf_conntrack_zones.h b/include/net/netfilter/nf_conntrack_zones.h
new file mode 100644
index 000000000000..0bbb2bd51e89
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_zones.h
@@ -0,0 +1,23 @@
1#ifndef _NF_CONNTRACK_ZONES_H
2#define _NF_CONNTRACK_ZONES_H
3
4#include <net/netfilter/nf_conntrack_extend.h>
5
6#define NF_CT_DEFAULT_ZONE 0
7
8struct nf_conntrack_zone {
9 u16 id;
10};
11
12static inline u16 nf_ct_zone(const struct nf_conn *ct)
13{
14#ifdef CONFIG_NF_CONNTRACK_ZONES
15 struct nf_conntrack_zone *nf_ct_zone;
16 nf_ct_zone = nf_ct_ext_find(ct, NF_CT_EXT_ZONE);
17 if (nf_ct_zone)
18 return nf_ct_zone->id;
19#endif
20 return NF_CT_DEFAULT_ZONE;
21}
22
23#endif /* _NF_CONNTRACK_ZONES_H */
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index d1ea38a7c490..2bb1f87051c4 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -22,6 +22,7 @@
22#include <net/netfilter/nf_conntrack_helper.h> 22#include <net/netfilter/nf_conntrack_helper.h>
23#include <net/netfilter/nf_conntrack_l4proto.h> 23#include <net/netfilter/nf_conntrack_l4proto.h>
24#include <net/netfilter/nf_conntrack_l3proto.h> 24#include <net/netfilter/nf_conntrack_l3proto.h>
25#include <net/netfilter/nf_conntrack_zones.h>
25#include <net/netfilter/nf_conntrack_core.h> 26#include <net/netfilter/nf_conntrack_core.h>
26#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> 27#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
27#include <net/netfilter/nf_nat_helper.h> 28#include <net/netfilter/nf_nat_helper.h>
@@ -266,7 +267,7 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
266 return -EINVAL; 267 return -EINVAL;
267 } 268 }
268 269
269 h = nf_conntrack_find_get(sock_net(sk), &tuple); 270 h = nf_conntrack_find_get(sock_net(sk), NF_CT_DEFAULT_ZONE, &tuple);
270 if (h) { 271 if (h) {
271 struct sockaddr_in sin; 272 struct sockaddr_in sin;
272 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); 273 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 327826a968a8..7404bde95994 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -18,6 +18,7 @@
18#include <net/netfilter/nf_conntrack_tuple.h> 18#include <net/netfilter/nf_conntrack_tuple.h>
19#include <net/netfilter/nf_conntrack_l4proto.h> 19#include <net/netfilter/nf_conntrack_l4proto.h>
20#include <net/netfilter/nf_conntrack_core.h> 20#include <net/netfilter/nf_conntrack_core.h>
21#include <net/netfilter/nf_conntrack_zones.h>
21#include <net/netfilter/nf_log.h> 22#include <net/netfilter/nf_log.h>
22 23
23static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ; 24static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ;
@@ -114,13 +115,14 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb,
114 115
115/* Returns conntrack if it dealt with ICMP, and filled in skb fields */ 116/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
116static int 117static int
117icmp_error_message(struct net *net, struct sk_buff *skb, 118icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
118 enum ip_conntrack_info *ctinfo, 119 enum ip_conntrack_info *ctinfo,
119 unsigned int hooknum) 120 unsigned int hooknum)
120{ 121{
121 struct nf_conntrack_tuple innertuple, origtuple; 122 struct nf_conntrack_tuple innertuple, origtuple;
122 const struct nf_conntrack_l4proto *innerproto; 123 const struct nf_conntrack_l4proto *innerproto;
123 const struct nf_conntrack_tuple_hash *h; 124 const struct nf_conntrack_tuple_hash *h;
125 u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
124 126
125 NF_CT_ASSERT(skb->nfct == NULL); 127 NF_CT_ASSERT(skb->nfct == NULL);
126 128
@@ -146,7 +148,7 @@ icmp_error_message(struct net *net, struct sk_buff *skb,
146 148
147 *ctinfo = IP_CT_RELATED; 149 *ctinfo = IP_CT_RELATED;
148 150
149 h = nf_conntrack_find_get(net, &innertuple); 151 h = nf_conntrack_find_get(net, zone, &innertuple);
150 if (!h) { 152 if (!h) {
151 pr_debug("icmp_error_message: no match\n"); 153 pr_debug("icmp_error_message: no match\n");
152 return -NF_ACCEPT; 154 return -NF_ACCEPT;
@@ -209,7 +211,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl,
209 icmph->type != ICMP_REDIRECT) 211 icmph->type != ICMP_REDIRECT)
210 return NF_ACCEPT; 212 return NF_ACCEPT;
211 213
212 return icmp_error_message(net, skb, ctinfo, hooknum); 214 return icmp_error_message(net, tmpl, skb, ctinfo, hooknum);
213} 215}
214 216
215#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 217#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index f6f46686cbc0..d498a704d456 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -16,6 +16,7 @@
16 16
17#include <linux/netfilter_bridge.h> 17#include <linux/netfilter_bridge.h>
18#include <linux/netfilter_ipv4.h> 18#include <linux/netfilter_ipv4.h>
19#include <net/netfilter/nf_conntrack_zones.h>
19#include <net/netfilter/ipv4/nf_defrag_ipv4.h> 20#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
20#include <net/netfilter/nf_conntrack.h> 21#include <net/netfilter/nf_conntrack.h>
21 22
@@ -39,15 +40,20 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
39static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum, 40static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum,
40 struct sk_buff *skb) 41 struct sk_buff *skb)
41{ 42{
43 u16 zone = NF_CT_DEFAULT_ZONE;
44
45 if (skb->nfct)
46 zone = nf_ct_zone((struct nf_conn *)skb->nfct);
47
42#ifdef CONFIG_BRIDGE_NETFILTER 48#ifdef CONFIG_BRIDGE_NETFILTER
43 if (skb->nf_bridge && 49 if (skb->nf_bridge &&
44 skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) 50 skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
45 return IP_DEFRAG_CONNTRACK_BRIDGE_IN; 51 return IP_DEFRAG_CONNTRACK_BRIDGE_IN + zone;
46#endif 52#endif
47 if (hooknum == NF_INET_PRE_ROUTING) 53 if (hooknum == NF_INET_PRE_ROUTING)
48 return IP_DEFRAG_CONNTRACK_IN; 54 return IP_DEFRAG_CONNTRACK_IN + zone;
49 else 55 else
50 return IP_DEFRAG_CONNTRACK_OUT; 56 return IP_DEFRAG_CONNTRACK_OUT + zone;
51} 57}
52 58
53static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, 59static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 26066a2327ad..4595281c2863 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -30,6 +30,7 @@
30#include <net/netfilter/nf_conntrack_helper.h> 30#include <net/netfilter/nf_conntrack_helper.h>
31#include <net/netfilter/nf_conntrack_l3proto.h> 31#include <net/netfilter/nf_conntrack_l3proto.h>
32#include <net/netfilter/nf_conntrack_l4proto.h> 32#include <net/netfilter/nf_conntrack_l4proto.h>
33#include <net/netfilter/nf_conntrack_zones.h>
33 34
34static DEFINE_SPINLOCK(nf_nat_lock); 35static DEFINE_SPINLOCK(nf_nat_lock);
35 36
@@ -69,13 +70,14 @@ EXPORT_SYMBOL_GPL(nf_nat_proto_put);
69 70
70/* We keep an extra hash for each conntrack, for fast searching. */ 71/* We keep an extra hash for each conntrack, for fast searching. */
71static inline unsigned int 72static inline unsigned int
72hash_by_src(const struct net *net, const struct nf_conntrack_tuple *tuple) 73hash_by_src(const struct net *net, u16 zone,
74 const struct nf_conntrack_tuple *tuple)
73{ 75{
74 unsigned int hash; 76 unsigned int hash;
75 77
76 /* Original src, to ensure we map it consistently if poss. */ 78 /* Original src, to ensure we map it consistently if poss. */
77 hash = jhash_3words((__force u32)tuple->src.u3.ip, 79 hash = jhash_3words((__force u32)tuple->src.u3.ip,
78 (__force u32)tuple->src.u.all, 80 (__force u32)tuple->src.u.all ^ zone,
79 tuple->dst.protonum, 0); 81 tuple->dst.protonum, 0);
80 return ((u64)hash * net->ipv4.nat_htable_size) >> 32; 82 return ((u64)hash * net->ipv4.nat_htable_size) >> 32;
81} 83}
@@ -139,12 +141,12 @@ same_src(const struct nf_conn *ct,
139 141
140/* Only called for SRC manip */ 142/* Only called for SRC manip */
141static int 143static int
142find_appropriate_src(struct net *net, 144find_appropriate_src(struct net *net, u16 zone,
143 const struct nf_conntrack_tuple *tuple, 145 const struct nf_conntrack_tuple *tuple,
144 struct nf_conntrack_tuple *result, 146 struct nf_conntrack_tuple *result,
145 const struct nf_nat_range *range) 147 const struct nf_nat_range *range)
146{ 148{
147 unsigned int h = hash_by_src(net, tuple); 149 unsigned int h = hash_by_src(net, zone, tuple);
148 const struct nf_conn_nat *nat; 150 const struct nf_conn_nat *nat;
149 const struct nf_conn *ct; 151 const struct nf_conn *ct;
150 const struct hlist_node *n; 152 const struct hlist_node *n;
@@ -152,7 +154,7 @@ find_appropriate_src(struct net *net,
152 rcu_read_lock(); 154 rcu_read_lock();
153 hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) { 155 hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) {
154 ct = nat->ct; 156 ct = nat->ct;
155 if (same_src(ct, tuple)) { 157 if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) {
156 /* Copy source part from reply tuple. */ 158 /* Copy source part from reply tuple. */
157 nf_ct_invert_tuplepr(result, 159 nf_ct_invert_tuplepr(result,
158 &ct->tuplehash[IP_CT_DIR_REPLY].tuple); 160 &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
@@ -175,7 +177,7 @@ find_appropriate_src(struct net *net,
175 the ip with the lowest src-ip/dst-ip/proto usage. 177 the ip with the lowest src-ip/dst-ip/proto usage.
176*/ 178*/
177static void 179static void
178find_best_ips_proto(struct nf_conntrack_tuple *tuple, 180find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple,
179 const struct nf_nat_range *range, 181 const struct nf_nat_range *range,
180 const struct nf_conn *ct, 182 const struct nf_conn *ct,
181 enum nf_nat_manip_type maniptype) 183 enum nf_nat_manip_type maniptype)
@@ -209,7 +211,7 @@ find_best_ips_proto(struct nf_conntrack_tuple *tuple,
209 maxip = ntohl(range->max_ip); 211 maxip = ntohl(range->max_ip);
210 j = jhash_2words((__force u32)tuple->src.u3.ip, 212 j = jhash_2words((__force u32)tuple->src.u3.ip,
211 range->flags & IP_NAT_RANGE_PERSISTENT ? 213 range->flags & IP_NAT_RANGE_PERSISTENT ?
212 0 : (__force u32)tuple->dst.u3.ip, 0); 214 0 : (__force u32)tuple->dst.u3.ip ^ zone, 0);
213 j = ((u64)j * (maxip - minip + 1)) >> 32; 215 j = ((u64)j * (maxip - minip + 1)) >> 32;
214 *var_ipp = htonl(minip + j); 216 *var_ipp = htonl(minip + j);
215} 217}
@@ -229,6 +231,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
229{ 231{
230 struct net *net = nf_ct_net(ct); 232 struct net *net = nf_ct_net(ct);
231 const struct nf_nat_protocol *proto; 233 const struct nf_nat_protocol *proto;
234 u16 zone = nf_ct_zone(ct);
232 235
233 /* 1) If this srcip/proto/src-proto-part is currently mapped, 236 /* 1) If this srcip/proto/src-proto-part is currently mapped,
234 and that same mapping gives a unique tuple within the given 237 and that same mapping gives a unique tuple within the given
@@ -239,7 +242,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
239 manips not an issue. */ 242 manips not an issue. */
240 if (maniptype == IP_NAT_MANIP_SRC && 243 if (maniptype == IP_NAT_MANIP_SRC &&
241 !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) { 244 !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) {
242 if (find_appropriate_src(net, orig_tuple, tuple, range)) { 245 if (find_appropriate_src(net, zone, orig_tuple, tuple, range)) {
243 pr_debug("get_unique_tuple: Found current src map\n"); 246 pr_debug("get_unique_tuple: Found current src map\n");
244 if (!nf_nat_used_tuple(tuple, ct)) 247 if (!nf_nat_used_tuple(tuple, ct))
245 return; 248 return;
@@ -249,7 +252,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
249 /* 2) Select the least-used IP/proto combination in the given 252 /* 2) Select the least-used IP/proto combination in the given
250 range. */ 253 range. */
251 *tuple = *orig_tuple; 254 *tuple = *orig_tuple;
252 find_best_ips_proto(tuple, range, ct, maniptype); 255 find_best_ips_proto(zone, tuple, range, ct, maniptype);
253 256
254 /* 3) The per-protocol part of the manip is made to map into 257 /* 3) The per-protocol part of the manip is made to map into
255 the range to make a unique tuple. */ 258 the range to make a unique tuple. */
@@ -327,7 +330,8 @@ nf_nat_setup_info(struct nf_conn *ct,
327 if (have_to_hash) { 330 if (have_to_hash) {
328 unsigned int srchash; 331 unsigned int srchash;
329 332
330 srchash = hash_by_src(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 333 srchash = hash_by_src(net, nf_ct_zone(ct),
334 &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
331 spin_lock_bh(&nf_nat_lock); 335 spin_lock_bh(&nf_nat_lock);
332 /* nf_conntrack_alter_reply might re-allocate exntension aera */ 336 /* nf_conntrack_alter_reply might re-allocate exntension aera */
333 nat = nfct_nat(ct); 337 nat = nfct_nat(ct);
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index 9eb171056c63..4c060038d29f 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -25,6 +25,7 @@
25#include <net/netfilter/nf_nat_rule.h> 25#include <net/netfilter/nf_nat_rule.h>
26#include <net/netfilter/nf_conntrack_helper.h> 26#include <net/netfilter/nf_conntrack_helper.h>
27#include <net/netfilter/nf_conntrack_expect.h> 27#include <net/netfilter/nf_conntrack_expect.h>
28#include <net/netfilter/nf_conntrack_zones.h>
28#include <linux/netfilter/nf_conntrack_proto_gre.h> 29#include <linux/netfilter/nf_conntrack_proto_gre.h>
29#include <linux/netfilter/nf_conntrack_pptp.h> 30#include <linux/netfilter/nf_conntrack_pptp.h>
30 31
@@ -74,7 +75,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
74 75
75 pr_debug("trying to unexpect other dir: "); 76 pr_debug("trying to unexpect other dir: ");
76 nf_ct_dump_tuple_ip(&t); 77 nf_ct_dump_tuple_ip(&t);
77 other_exp = nf_ct_expect_find_get(net, &t); 78 other_exp = nf_ct_expect_find_get(net, nf_ct_zone(ct), &t);
78 if (other_exp) { 79 if (other_exp) {
79 nf_ct_unexpect_related(other_exp); 80 nf_ct_unexpect_related(other_exp);
80 nf_ct_expect_put(other_exp); 81 nf_ct_expect_put(other_exp);
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 55ce22e5de49..996c3f41fecd 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -27,6 +27,7 @@
27#include <net/netfilter/nf_conntrack_l4proto.h> 27#include <net/netfilter/nf_conntrack_l4proto.h>
28#include <net/netfilter/nf_conntrack_l3proto.h> 28#include <net/netfilter/nf_conntrack_l3proto.h>
29#include <net/netfilter/nf_conntrack_core.h> 29#include <net/netfilter/nf_conntrack_core.h>
30#include <net/netfilter/nf_conntrack_zones.h>
30#include <net/netfilter/ipv6/nf_conntrack_ipv6.h> 31#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
31#include <net/netfilter/nf_log.h> 32#include <net/netfilter/nf_log.h>
32 33
@@ -191,15 +192,20 @@ out:
191static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, 192static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
192 struct sk_buff *skb) 193 struct sk_buff *skb)
193{ 194{
195 u16 zone = NF_CT_DEFAULT_ZONE;
196
197 if (skb->nfct)
198 zone = nf_ct_zone((struct nf_conn *)skb->nfct);
199
194#ifdef CONFIG_BRIDGE_NETFILTER 200#ifdef CONFIG_BRIDGE_NETFILTER
195 if (skb->nf_bridge && 201 if (skb->nf_bridge &&
196 skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) 202 skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
197 return IP6_DEFRAG_CONNTRACK_BRIDGE_IN; 203 return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone;
198#endif 204#endif
199 if (hooknum == NF_INET_PRE_ROUTING) 205 if (hooknum == NF_INET_PRE_ROUTING)
200 return IP6_DEFRAG_CONNTRACK_IN; 206 return IP6_DEFRAG_CONNTRACK_IN + zone;
201 else 207 else
202 return IP6_DEFRAG_CONNTRACK_OUT; 208 return IP6_DEFRAG_CONNTRACK_OUT + zone;
203 209
204} 210}
205 211
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index d772dc21857f..9be81776415e 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -23,6 +23,7 @@
23#include <net/netfilter/nf_conntrack_tuple.h> 23#include <net/netfilter/nf_conntrack_tuple.h>
24#include <net/netfilter/nf_conntrack_l4proto.h> 24#include <net/netfilter/nf_conntrack_l4proto.h>
25#include <net/netfilter/nf_conntrack_core.h> 25#include <net/netfilter/nf_conntrack_core.h>
26#include <net/netfilter/nf_conntrack_zones.h>
26#include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> 27#include <net/netfilter/ipv6/nf_conntrack_icmpv6.h>
27#include <net/netfilter/nf_log.h> 28#include <net/netfilter/nf_log.h>
28 29
@@ -128,7 +129,7 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb,
128} 129}
129 130
130static int 131static int
131icmpv6_error_message(struct net *net, 132icmpv6_error_message(struct net *net, struct nf_conn *tmpl,
132 struct sk_buff *skb, 133 struct sk_buff *skb,
133 unsigned int icmp6off, 134 unsigned int icmp6off,
134 enum ip_conntrack_info *ctinfo, 135 enum ip_conntrack_info *ctinfo,
@@ -137,6 +138,7 @@ icmpv6_error_message(struct net *net,
137 struct nf_conntrack_tuple intuple, origtuple; 138 struct nf_conntrack_tuple intuple, origtuple;
138 const struct nf_conntrack_tuple_hash *h; 139 const struct nf_conntrack_tuple_hash *h;
139 const struct nf_conntrack_l4proto *inproto; 140 const struct nf_conntrack_l4proto *inproto;
141 u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
140 142
141 NF_CT_ASSERT(skb->nfct == NULL); 143 NF_CT_ASSERT(skb->nfct == NULL);
142 144
@@ -163,7 +165,7 @@ icmpv6_error_message(struct net *net,
163 165
164 *ctinfo = IP_CT_RELATED; 166 *ctinfo = IP_CT_RELATED;
165 167
166 h = nf_conntrack_find_get(net, &intuple); 168 h = nf_conntrack_find_get(net, zone, &intuple);
167 if (!h) { 169 if (!h) {
168 pr_debug("icmpv6_error: no match\n"); 170 pr_debug("icmpv6_error: no match\n");
169 return -NF_ACCEPT; 171 return -NF_ACCEPT;
@@ -216,7 +218,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl,
216 if (icmp6h->icmp6_type >= 128) 218 if (icmp6h->icmp6_type >= 128)
217 return NF_ACCEPT; 219 return NF_ACCEPT;
218 220
219 return icmpv6_error_message(net, skb, dataoff, ctinfo, hooknum); 221 return icmpv6_error_message(net, tmpl, skb, dataoff, ctinfo, hooknum);
220} 222}
221 223
222#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 224#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 4469d45261f4..18d77b5c351a 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -83,6 +83,19 @@ config NF_CONNTRACK_SECMARK
83 83
84 If unsure, say 'N'. 84 If unsure, say 'N'.
85 85
86config NF_CONNTRACK_ZONES
87 bool 'Connection tracking zones'
88 depends on NETFILTER_ADVANCED
89 depends on NETFILTER_XT_TARGET_CT
90 help
91 This option enables support for connection tracking zones.
92 Normally, each connection needs to have a unique system wide
93 identity. Connection tracking zones allow to have multiple
94 connections using the same identity, as long as they are
95 contained in different zones.
96
97 If unsure, say `N'.
98
86config NF_CONNTRACK_EVENTS 99config NF_CONNTRACK_EVENTS
87 bool "Connection tracking events" 100 bool "Connection tracking events"
88 depends on NETFILTER_ADVANCED 101 depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 65351ed5d815..0c9bbe93cc16 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -42,6 +42,7 @@
42#include <net/netfilter/nf_conntrack_extend.h> 42#include <net/netfilter/nf_conntrack_extend.h>
43#include <net/netfilter/nf_conntrack_acct.h> 43#include <net/netfilter/nf_conntrack_acct.h>
44#include <net/netfilter/nf_conntrack_ecache.h> 44#include <net/netfilter/nf_conntrack_ecache.h>
45#include <net/netfilter/nf_conntrack_zones.h>
45#include <net/netfilter/nf_nat.h> 46#include <net/netfilter/nf_nat.h>
46#include <net/netfilter/nf_nat_core.h> 47#include <net/netfilter/nf_nat_core.h>
47 48
@@ -68,7 +69,7 @@ static int nf_conntrack_hash_rnd_initted;
68static unsigned int nf_conntrack_hash_rnd; 69static unsigned int nf_conntrack_hash_rnd;
69 70
70static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple, 71static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple,
71 unsigned int size, unsigned int rnd) 72 u16 zone, unsigned int size, unsigned int rnd)
72{ 73{
73 unsigned int n; 74 unsigned int n;
74 u_int32_t h; 75 u_int32_t h;
@@ -79,16 +80,16 @@ static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple,
79 */ 80 */
80 n = (sizeof(tuple->src) + sizeof(tuple->dst.u3)) / sizeof(u32); 81 n = (sizeof(tuple->src) + sizeof(tuple->dst.u3)) / sizeof(u32);
81 h = jhash2((u32 *)tuple, n, 82 h = jhash2((u32 *)tuple, n,
82 rnd ^ (((__force __u16)tuple->dst.u.all << 16) | 83 zone ^ rnd ^ (((__force __u16)tuple->dst.u.all << 16) |
83 tuple->dst.protonum)); 84 tuple->dst.protonum));
84 85
85 return ((u64)h * size) >> 32; 86 return ((u64)h * size) >> 32;
86} 87}
87 88
88static inline u_int32_t hash_conntrack(const struct net *net, 89static inline u_int32_t hash_conntrack(const struct net *net, u16 zone,
89 const struct nf_conntrack_tuple *tuple) 90 const struct nf_conntrack_tuple *tuple)
90{ 91{
91 return __hash_conntrack(tuple, net->ct.htable_size, 92 return __hash_conntrack(tuple, zone, net->ct.htable_size,
92 nf_conntrack_hash_rnd); 93 nf_conntrack_hash_rnd);
93} 94}
94 95
@@ -292,11 +293,12 @@ static void death_by_timeout(unsigned long ul_conntrack)
292 * - Caller must lock nf_conntrack_lock before calling this function 293 * - Caller must lock nf_conntrack_lock before calling this function
293 */ 294 */
294struct nf_conntrack_tuple_hash * 295struct nf_conntrack_tuple_hash *
295__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple) 296__nf_conntrack_find(struct net *net, u16 zone,
297 const struct nf_conntrack_tuple *tuple)
296{ 298{
297 struct nf_conntrack_tuple_hash *h; 299 struct nf_conntrack_tuple_hash *h;
298 struct hlist_nulls_node *n; 300 struct hlist_nulls_node *n;
299 unsigned int hash = hash_conntrack(net, tuple); 301 unsigned int hash = hash_conntrack(net, zone, tuple);
300 302
301 /* Disable BHs the entire time since we normally need to disable them 303 /* Disable BHs the entire time since we normally need to disable them
302 * at least once for the stats anyway. 304 * at least once for the stats anyway.
@@ -304,7 +306,8 @@ __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple)
304 local_bh_disable(); 306 local_bh_disable();
305begin: 307begin:
306 hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { 308 hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) {
307 if (nf_ct_tuple_equal(tuple, &h->tuple)) { 309 if (nf_ct_tuple_equal(tuple, &h->tuple) &&
310 nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) {
308 NF_CT_STAT_INC(net, found); 311 NF_CT_STAT_INC(net, found);
309 local_bh_enable(); 312 local_bh_enable();
310 return h; 313 return h;
@@ -326,21 +329,23 @@ EXPORT_SYMBOL_GPL(__nf_conntrack_find);
326 329
327/* Find a connection corresponding to a tuple. */ 330/* Find a connection corresponding to a tuple. */
328struct nf_conntrack_tuple_hash * 331struct nf_conntrack_tuple_hash *
329nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple) 332nf_conntrack_find_get(struct net *net, u16 zone,
333 const struct nf_conntrack_tuple *tuple)
330{ 334{
331 struct nf_conntrack_tuple_hash *h; 335 struct nf_conntrack_tuple_hash *h;
332 struct nf_conn *ct; 336 struct nf_conn *ct;
333 337
334 rcu_read_lock(); 338 rcu_read_lock();
335begin: 339begin:
336 h = __nf_conntrack_find(net, tuple); 340 h = __nf_conntrack_find(net, zone, tuple);
337 if (h) { 341 if (h) {
338 ct = nf_ct_tuplehash_to_ctrack(h); 342 ct = nf_ct_tuplehash_to_ctrack(h);
339 if (unlikely(nf_ct_is_dying(ct) || 343 if (unlikely(nf_ct_is_dying(ct) ||
340 !atomic_inc_not_zero(&ct->ct_general.use))) 344 !atomic_inc_not_zero(&ct->ct_general.use)))
341 h = NULL; 345 h = NULL;
342 else { 346 else {
343 if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple))) { 347 if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple) ||
348 nf_ct_zone(ct) != zone)) {
344 nf_ct_put(ct); 349 nf_ct_put(ct);
345 goto begin; 350 goto begin;
346 } 351 }
@@ -368,9 +373,11 @@ void nf_conntrack_hash_insert(struct nf_conn *ct)
368{ 373{
369 struct net *net = nf_ct_net(ct); 374 struct net *net = nf_ct_net(ct);
370 unsigned int hash, repl_hash; 375 unsigned int hash, repl_hash;
376 u16 zone;
371 377
372 hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 378 zone = nf_ct_zone(ct);
373 repl_hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); 379 hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
380 repl_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
374 381
375 __nf_conntrack_hash_insert(ct, hash, repl_hash); 382 __nf_conntrack_hash_insert(ct, hash, repl_hash);
376} 383}
@@ -387,6 +394,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
387 struct hlist_nulls_node *n; 394 struct hlist_nulls_node *n;
388 enum ip_conntrack_info ctinfo; 395 enum ip_conntrack_info ctinfo;
389 struct net *net; 396 struct net *net;
397 u16 zone;
390 398
391 ct = nf_ct_get(skb, &ctinfo); 399 ct = nf_ct_get(skb, &ctinfo);
392 net = nf_ct_net(ct); 400 net = nf_ct_net(ct);
@@ -398,8 +406,9 @@ __nf_conntrack_confirm(struct sk_buff *skb)
398 if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) 406 if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
399 return NF_ACCEPT; 407 return NF_ACCEPT;
400 408
401 hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 409 zone = nf_ct_zone(ct);
402 repl_hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); 410 hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
411 repl_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
403 412
404 /* We're not in hash table, and we refuse to set up related 413 /* We're not in hash table, and we refuse to set up related
405 connections for unconfirmed conns. But packet copies and 414 connections for unconfirmed conns. But packet copies and
@@ -418,11 +427,13 @@ __nf_conntrack_confirm(struct sk_buff *skb)
418 not in the hash. If there is, we lost race. */ 427 not in the hash. If there is, we lost race. */
419 hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode) 428 hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode)
420 if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, 429 if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
421 &h->tuple)) 430 &h->tuple) &&
431 zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
422 goto out; 432 goto out;
423 hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode) 433 hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode)
424 if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, 434 if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
425 &h->tuple)) 435 &h->tuple) &&
436 zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
426 goto out; 437 goto out;
427 438
428 /* Remove from unconfirmed list */ 439 /* Remove from unconfirmed list */
@@ -469,15 +480,19 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple,
469 struct net *net = nf_ct_net(ignored_conntrack); 480 struct net *net = nf_ct_net(ignored_conntrack);
470 struct nf_conntrack_tuple_hash *h; 481 struct nf_conntrack_tuple_hash *h;
471 struct hlist_nulls_node *n; 482 struct hlist_nulls_node *n;
472 unsigned int hash = hash_conntrack(net, tuple); 483 struct nf_conn *ct;
484 u16 zone = nf_ct_zone(ignored_conntrack);
485 unsigned int hash = hash_conntrack(net, zone, tuple);
473 486
474 /* Disable BHs the entire time since we need to disable them at 487 /* Disable BHs the entire time since we need to disable them at
475 * least once for the stats anyway. 488 * least once for the stats anyway.
476 */ 489 */
477 rcu_read_lock_bh(); 490 rcu_read_lock_bh();
478 hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { 491 hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) {
479 if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack && 492 ct = nf_ct_tuplehash_to_ctrack(h);
480 nf_ct_tuple_equal(tuple, &h->tuple)) { 493 if (ct != ignored_conntrack &&
494 nf_ct_tuple_equal(tuple, &h->tuple) &&
495 nf_ct_zone(ct) == zone) {
481 NF_CT_STAT_INC(net, found); 496 NF_CT_STAT_INC(net, found);
482 rcu_read_unlock_bh(); 497 rcu_read_unlock_bh();
483 return 1; 498 return 1;
@@ -540,7 +555,7 @@ static noinline int early_drop(struct net *net, unsigned int hash)
540 return dropped; 555 return dropped;
541} 556}
542 557
543struct nf_conn *nf_conntrack_alloc(struct net *net, 558struct nf_conn *nf_conntrack_alloc(struct net *net, u16 zone,
544 const struct nf_conntrack_tuple *orig, 559 const struct nf_conntrack_tuple *orig,
545 const struct nf_conntrack_tuple *repl, 560 const struct nf_conntrack_tuple *repl,
546 gfp_t gfp) 561 gfp_t gfp)
@@ -558,7 +573,7 @@ struct nf_conn *nf_conntrack_alloc(struct net *net,
558 573
559 if (nf_conntrack_max && 574 if (nf_conntrack_max &&
560 unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) { 575 unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) {
561 unsigned int hash = hash_conntrack(net, orig); 576 unsigned int hash = hash_conntrack(net, zone, orig);
562 if (!early_drop(net, hash)) { 577 if (!early_drop(net, hash)) {
563 atomic_dec(&net->ct.count); 578 atomic_dec(&net->ct.count);
564 if (net_ratelimit()) 579 if (net_ratelimit())
@@ -595,13 +610,28 @@ struct nf_conn *nf_conntrack_alloc(struct net *net,
595#ifdef CONFIG_NET_NS 610#ifdef CONFIG_NET_NS
596 ct->ct_net = net; 611 ct->ct_net = net;
597#endif 612#endif
598 613#ifdef CONFIG_NF_CONNTRACK_ZONES
614 if (zone) {
615 struct nf_conntrack_zone *nf_ct_zone;
616
617 nf_ct_zone = nf_ct_ext_add(ct, NF_CT_EXT_ZONE, GFP_ATOMIC);
618 if (!nf_ct_zone)
619 goto out_free;
620 nf_ct_zone->id = zone;
621 }
622#endif
599 /* 623 /*
600 * changes to lookup keys must be done before setting refcnt to 1 624 * changes to lookup keys must be done before setting refcnt to 1
601 */ 625 */
602 smp_wmb(); 626 smp_wmb();
603 atomic_set(&ct->ct_general.use, 1); 627 atomic_set(&ct->ct_general.use, 1);
604 return ct; 628 return ct;
629
630#ifdef CONFIG_NF_CONNTRACK_ZONES
631out_free:
632 kmem_cache_free(net->ct.nf_conntrack_cachep, ct);
633 return ERR_PTR(-ENOMEM);
634#endif
605} 635}
606EXPORT_SYMBOL_GPL(nf_conntrack_alloc); 636EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
607 637
@@ -631,13 +661,14 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
631 struct nf_conntrack_tuple repl_tuple; 661 struct nf_conntrack_tuple repl_tuple;
632 struct nf_conntrack_ecache *ecache; 662 struct nf_conntrack_ecache *ecache;
633 struct nf_conntrack_expect *exp; 663 struct nf_conntrack_expect *exp;
664 u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
634 665
635 if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) { 666 if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) {
636 pr_debug("Can't invert tuple.\n"); 667 pr_debug("Can't invert tuple.\n");
637 return NULL; 668 return NULL;
638 } 669 }
639 670
640 ct = nf_conntrack_alloc(net, tuple, &repl_tuple, GFP_ATOMIC); 671 ct = nf_conntrack_alloc(net, zone, tuple, &repl_tuple, GFP_ATOMIC);
641 if (IS_ERR(ct)) { 672 if (IS_ERR(ct)) {
642 pr_debug("Can't allocate conntrack.\n"); 673 pr_debug("Can't allocate conntrack.\n");
643 return (struct nf_conntrack_tuple_hash *)ct; 674 return (struct nf_conntrack_tuple_hash *)ct;
@@ -657,7 +688,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
657 GFP_ATOMIC); 688 GFP_ATOMIC);
658 689
659 spin_lock_bh(&nf_conntrack_lock); 690 spin_lock_bh(&nf_conntrack_lock);
660 exp = nf_ct_find_expectation(net, tuple); 691 exp = nf_ct_find_expectation(net, zone, tuple);
661 if (exp) { 692 if (exp) {
662 pr_debug("conntrack: expectation arrives ct=%p exp=%p\n", 693 pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
663 ct, exp); 694 ct, exp);
@@ -713,6 +744,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
713 struct nf_conntrack_tuple tuple; 744 struct nf_conntrack_tuple tuple;
714 struct nf_conntrack_tuple_hash *h; 745 struct nf_conntrack_tuple_hash *h;
715 struct nf_conn *ct; 746 struct nf_conn *ct;
747 u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
716 748
717 if (!nf_ct_get_tuple(skb, skb_network_offset(skb), 749 if (!nf_ct_get_tuple(skb, skb_network_offset(skb),
718 dataoff, l3num, protonum, &tuple, l3proto, 750 dataoff, l3num, protonum, &tuple, l3proto,
@@ -722,7 +754,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
722 } 754 }
723 755
724 /* look for tuple match */ 756 /* look for tuple match */
725 h = nf_conntrack_find_get(net, &tuple); 757 h = nf_conntrack_find_get(net, zone, &tuple);
726 if (!h) { 758 if (!h) {
727 h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, 759 h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
728 skb, dataoff); 760 skb, dataoff);
@@ -958,6 +990,14 @@ bool __nf_ct_kill_acct(struct nf_conn *ct,
958} 990}
959EXPORT_SYMBOL_GPL(__nf_ct_kill_acct); 991EXPORT_SYMBOL_GPL(__nf_ct_kill_acct);
960 992
993#ifdef CONFIG_NF_CONNTRACK_ZONES
994static struct nf_ct_ext_type nf_ct_zone_extend __read_mostly = {
995 .len = sizeof(struct nf_conntrack_zone),
996 .align = __alignof__(struct nf_conntrack_zone),
997 .id = NF_CT_EXT_ZONE,
998};
999#endif
1000
961#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 1001#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
962 1002
963#include <linux/netfilter/nfnetlink.h> 1003#include <linux/netfilter/nfnetlink.h>
@@ -1139,6 +1179,9 @@ static void nf_conntrack_cleanup_init_net(void)
1139 1179
1140 nf_conntrack_helper_fini(); 1180 nf_conntrack_helper_fini();
1141 nf_conntrack_proto_fini(); 1181 nf_conntrack_proto_fini();
1182#ifdef CONFIG_NF_CONNTRACK_ZONES
1183 nf_ct_extend_unregister(&nf_ct_zone_extend);
1184#endif
1142} 1185}
1143 1186
1144static void nf_conntrack_cleanup_net(struct net *net) 1187static void nf_conntrack_cleanup_net(struct net *net)
@@ -1214,6 +1257,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
1214 unsigned int hashsize, old_size; 1257 unsigned int hashsize, old_size;
1215 struct hlist_nulls_head *hash, *old_hash; 1258 struct hlist_nulls_head *hash, *old_hash;
1216 struct nf_conntrack_tuple_hash *h; 1259 struct nf_conntrack_tuple_hash *h;
1260 struct nf_conn *ct;
1217 1261
1218 if (current->nsproxy->net_ns != &init_net) 1262 if (current->nsproxy->net_ns != &init_net)
1219 return -EOPNOTSUPP; 1263 return -EOPNOTSUPP;
@@ -1240,8 +1284,10 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
1240 while (!hlist_nulls_empty(&init_net.ct.hash[i])) { 1284 while (!hlist_nulls_empty(&init_net.ct.hash[i])) {
1241 h = hlist_nulls_entry(init_net.ct.hash[i].first, 1285 h = hlist_nulls_entry(init_net.ct.hash[i].first,
1242 struct nf_conntrack_tuple_hash, hnnode); 1286 struct nf_conntrack_tuple_hash, hnnode);
1287 ct = nf_ct_tuplehash_to_ctrack(h);
1243 hlist_nulls_del_rcu(&h->hnnode); 1288 hlist_nulls_del_rcu(&h->hnnode);
1244 bucket = __hash_conntrack(&h->tuple, hashsize, 1289 bucket = __hash_conntrack(&h->tuple, nf_ct_zone(ct),
1290 hashsize,
1245 nf_conntrack_hash_rnd); 1291 nf_conntrack_hash_rnd);
1246 hlist_nulls_add_head_rcu(&h->hnnode, &hash[bucket]); 1292 hlist_nulls_add_head_rcu(&h->hnnode, &hash[bucket]);
1247 } 1293 }
@@ -1299,6 +1345,11 @@ static int nf_conntrack_init_init_net(void)
1299 if (ret < 0) 1345 if (ret < 0)
1300 goto err_helper; 1346 goto err_helper;
1301 1347
1348#ifdef CONFIG_NF_CONNTRACK_ZONES
1349 ret = nf_ct_extend_register(&nf_ct_zone_extend);
1350 if (ret < 0)
1351 goto err_extend;
1352#endif
1302 /* Set up fake conntrack: to never be deleted, not in any hashes */ 1353 /* Set up fake conntrack: to never be deleted, not in any hashes */
1303#ifdef CONFIG_NET_NS 1354#ifdef CONFIG_NET_NS
1304 nf_conntrack_untracked.ct_net = &init_net; 1355 nf_conntrack_untracked.ct_net = &init_net;
@@ -1309,6 +1360,10 @@ static int nf_conntrack_init_init_net(void)
1309 1360
1310 return 0; 1361 return 0;
1311 1362
1363#ifdef CONFIG_NF_CONNTRACK_ZONES
1364err_extend:
1365 nf_conntrack_helper_fini();
1366#endif
1312err_helper: 1367err_helper:
1313 nf_conntrack_proto_fini(); 1368 nf_conntrack_proto_fini();
1314err_proto: 1369err_proto:
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 6182fb1b55de..acb29ccaa41f 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -27,6 +27,7 @@
27#include <net/netfilter/nf_conntrack_expect.h> 27#include <net/netfilter/nf_conntrack_expect.h>
28#include <net/netfilter/nf_conntrack_helper.h> 28#include <net/netfilter/nf_conntrack_helper.h>
29#include <net/netfilter/nf_conntrack_tuple.h> 29#include <net/netfilter/nf_conntrack_tuple.h>
30#include <net/netfilter/nf_conntrack_zones.h>
30 31
31unsigned int nf_ct_expect_hsize __read_mostly; 32unsigned int nf_ct_expect_hsize __read_mostly;
32EXPORT_SYMBOL_GPL(nf_ct_expect_hsize); 33EXPORT_SYMBOL_GPL(nf_ct_expect_hsize);
@@ -84,7 +85,8 @@ static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple
84} 85}
85 86
86struct nf_conntrack_expect * 87struct nf_conntrack_expect *
87__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple) 88__nf_ct_expect_find(struct net *net, u16 zone,
89 const struct nf_conntrack_tuple *tuple)
88{ 90{
89 struct nf_conntrack_expect *i; 91 struct nf_conntrack_expect *i;
90 struct hlist_node *n; 92 struct hlist_node *n;
@@ -95,7 +97,8 @@ __nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple)
95 97
96 h = nf_ct_expect_dst_hash(tuple); 98 h = nf_ct_expect_dst_hash(tuple);
97 hlist_for_each_entry_rcu(i, n, &net->ct.expect_hash[h], hnode) { 99 hlist_for_each_entry_rcu(i, n, &net->ct.expect_hash[h], hnode) {
98 if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) 100 if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
101 nf_ct_zone(i->master) == zone)
99 return i; 102 return i;
100 } 103 }
101 return NULL; 104 return NULL;
@@ -104,12 +107,13 @@ EXPORT_SYMBOL_GPL(__nf_ct_expect_find);
104 107
105/* Just find a expectation corresponding to a tuple. */ 108/* Just find a expectation corresponding to a tuple. */
106struct nf_conntrack_expect * 109struct nf_conntrack_expect *
107nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple) 110nf_ct_expect_find_get(struct net *net, u16 zone,
111 const struct nf_conntrack_tuple *tuple)
108{ 112{
109 struct nf_conntrack_expect *i; 113 struct nf_conntrack_expect *i;
110 114
111 rcu_read_lock(); 115 rcu_read_lock();
112 i = __nf_ct_expect_find(net, tuple); 116 i = __nf_ct_expect_find(net, zone, tuple);
113 if (i && !atomic_inc_not_zero(&i->use)) 117 if (i && !atomic_inc_not_zero(&i->use))
114 i = NULL; 118 i = NULL;
115 rcu_read_unlock(); 119 rcu_read_unlock();
@@ -121,7 +125,8 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_find_get);
121/* If an expectation for this connection is found, it gets delete from 125/* If an expectation for this connection is found, it gets delete from
122 * global list then returned. */ 126 * global list then returned. */
123struct nf_conntrack_expect * 127struct nf_conntrack_expect *
124nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple) 128nf_ct_find_expectation(struct net *net, u16 zone,
129 const struct nf_conntrack_tuple *tuple)
125{ 130{
126 struct nf_conntrack_expect *i, *exp = NULL; 131 struct nf_conntrack_expect *i, *exp = NULL;
127 struct hlist_node *n; 132 struct hlist_node *n;
@@ -133,7 +138,8 @@ nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple)
133 h = nf_ct_expect_dst_hash(tuple); 138 h = nf_ct_expect_dst_hash(tuple);
134 hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) { 139 hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) {
135 if (!(i->flags & NF_CT_EXPECT_INACTIVE) && 140 if (!(i->flags & NF_CT_EXPECT_INACTIVE) &&
136 nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) { 141 nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
142 nf_ct_zone(i->master) == zone) {
137 exp = i; 143 exp = i;
138 break; 144 break;
139 } 145 }
@@ -204,7 +210,8 @@ static inline int expect_matches(const struct nf_conntrack_expect *a,
204{ 210{
205 return a->master == b->master && a->class == b->class && 211 return a->master == b->master && a->class == b->class &&
206 nf_ct_tuple_equal(&a->tuple, &b->tuple) && 212 nf_ct_tuple_equal(&a->tuple, &b->tuple) &&
207 nf_ct_tuple_mask_equal(&a->mask, &b->mask); 213 nf_ct_tuple_mask_equal(&a->mask, &b->mask) &&
214 nf_ct_zone(a->master) == nf_ct_zone(b->master);
208} 215}
209 216
210/* Generally a bad idea to call this: could have matched already. */ 217/* Generally a bad idea to call this: could have matched already. */
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 66369490230e..a1c8dd917e12 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -29,6 +29,7 @@
29#include <net/netfilter/nf_conntrack_expect.h> 29#include <net/netfilter/nf_conntrack_expect.h>
30#include <net/netfilter/nf_conntrack_ecache.h> 30#include <net/netfilter/nf_conntrack_ecache.h>
31#include <net/netfilter/nf_conntrack_helper.h> 31#include <net/netfilter/nf_conntrack_helper.h>
32#include <net/netfilter/nf_conntrack_zones.h>
32#include <linux/netfilter/nf_conntrack_h323.h> 33#include <linux/netfilter/nf_conntrack_h323.h>
33 34
34/* Parameters */ 35/* Parameters */
@@ -1216,7 +1217,7 @@ static struct nf_conntrack_expect *find_expect(struct nf_conn *ct,
1216 tuple.dst.u.tcp.port = port; 1217 tuple.dst.u.tcp.port = port;
1217 tuple.dst.protonum = IPPROTO_TCP; 1218 tuple.dst.protonum = IPPROTO_TCP;
1218 1219
1219 exp = __nf_ct_expect_find(net, &tuple); 1220 exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
1220 if (exp && exp->master == ct) 1221 if (exp && exp->master == ct)
1221 return exp; 1222 return exp;
1222 return NULL; 1223 return NULL;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index db35edac307b..51089cfe1167 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -811,7 +811,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
811 if (err < 0) 811 if (err < 0)
812 return err; 812 return err;
813 813
814 h = nf_conntrack_find_get(net, &tuple); 814 h = nf_conntrack_find_get(net, 0, &tuple);
815 if (!h) 815 if (!h)
816 return -ENOENT; 816 return -ENOENT;
817 817
@@ -872,7 +872,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
872 if (err < 0) 872 if (err < 0)
873 return err; 873 return err;
874 874
875 h = nf_conntrack_find_get(net, &tuple); 875 h = nf_conntrack_find_get(net, 0, &tuple);
876 if (!h) 876 if (!h)
877 return -ENOENT; 877 return -ENOENT;
878 878
@@ -1221,7 +1221,7 @@ ctnetlink_create_conntrack(struct net *net,
1221 int err = -EINVAL; 1221 int err = -EINVAL;
1222 struct nf_conntrack_helper *helper; 1222 struct nf_conntrack_helper *helper;
1223 1223
1224 ct = nf_conntrack_alloc(net, otuple, rtuple, GFP_ATOMIC); 1224 ct = nf_conntrack_alloc(net, 0, otuple, rtuple, GFP_ATOMIC);
1225 if (IS_ERR(ct)) 1225 if (IS_ERR(ct))
1226 return ERR_PTR(-ENOMEM); 1226 return ERR_PTR(-ENOMEM);
1227 1227
@@ -1325,7 +1325,7 @@ ctnetlink_create_conntrack(struct net *net,
1325 if (err < 0) 1325 if (err < 0)
1326 goto err2; 1326 goto err2;
1327 1327
1328 master_h = nf_conntrack_find_get(net, &master); 1328 master_h = nf_conntrack_find_get(net, 0, &master);
1329 if (master_h == NULL) { 1329 if (master_h == NULL) {
1330 err = -ENOENT; 1330 err = -ENOENT;
1331 goto err2; 1331 goto err2;
@@ -1374,9 +1374,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1374 1374
1375 spin_lock_bh(&nf_conntrack_lock); 1375 spin_lock_bh(&nf_conntrack_lock);
1376 if (cda[CTA_TUPLE_ORIG]) 1376 if (cda[CTA_TUPLE_ORIG])
1377 h = __nf_conntrack_find(net, &otuple); 1377 h = __nf_conntrack_find(net, 0, &otuple);
1378 else if (cda[CTA_TUPLE_REPLY]) 1378 else if (cda[CTA_TUPLE_REPLY])
1379 h = __nf_conntrack_find(net, &rtuple); 1379 h = __nf_conntrack_find(net, 0, &rtuple);
1380 1380
1381 if (h == NULL) { 1381 if (h == NULL) {
1382 err = -ENOENT; 1382 err = -ENOENT;
@@ -1714,7 +1714,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
1714 if (err < 0) 1714 if (err < 0)
1715 return err; 1715 return err;
1716 1716
1717 exp = nf_ct_expect_find_get(net, &tuple); 1717 exp = nf_ct_expect_find_get(net, 0, &tuple);
1718 if (!exp) 1718 if (!exp)
1719 return -ENOENT; 1719 return -ENOENT;
1720 1720
@@ -1770,7 +1770,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
1770 return err; 1770 return err;
1771 1771
1772 /* bump usage count to 2 */ 1772 /* bump usage count to 2 */
1773 exp = nf_ct_expect_find_get(net, &tuple); 1773 exp = nf_ct_expect_find_get(net, 0, &tuple);
1774 if (!exp) 1774 if (!exp)
1775 return -ENOENT; 1775 return -ENOENT;
1776 1776
@@ -1855,7 +1855,7 @@ ctnetlink_create_expect(struct net *net, const struct nlattr * const cda[],
1855 return err; 1855 return err;
1856 1856
1857 /* Look for master conntrack of this expectation */ 1857 /* Look for master conntrack of this expectation */
1858 h = nf_conntrack_find_get(net, &master_tuple); 1858 h = nf_conntrack_find_get(net, 0, &master_tuple);
1859 if (!h) 1859 if (!h)
1860 return -ENOENT; 1860 return -ENOENT;
1861 ct = nf_ct_tuplehash_to_ctrack(h); 1861 ct = nf_ct_tuplehash_to_ctrack(h);
@@ -1912,7 +1912,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
1912 return err; 1912 return err;
1913 1913
1914 spin_lock_bh(&nf_conntrack_lock); 1914 spin_lock_bh(&nf_conntrack_lock);
1915 exp = __nf_ct_expect_find(net, &tuple); 1915 exp = __nf_ct_expect_find(net, 0, &tuple);
1916 1916
1917 if (!exp) { 1917 if (!exp) {
1918 spin_unlock_bh(&nf_conntrack_lock); 1918 spin_unlock_bh(&nf_conntrack_lock);
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 3807ac7faf4c..088944824e13 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -28,6 +28,7 @@
28#include <net/netfilter/nf_conntrack.h> 28#include <net/netfilter/nf_conntrack.h>
29#include <net/netfilter/nf_conntrack_core.h> 29#include <net/netfilter/nf_conntrack_core.h>
30#include <net/netfilter/nf_conntrack_helper.h> 30#include <net/netfilter/nf_conntrack_helper.h>
31#include <net/netfilter/nf_conntrack_zones.h>
31#include <linux/netfilter/nf_conntrack_proto_gre.h> 32#include <linux/netfilter/nf_conntrack_proto_gre.h>
32#include <linux/netfilter/nf_conntrack_pptp.h> 33#include <linux/netfilter/nf_conntrack_pptp.h>
33 34
@@ -123,7 +124,7 @@ static void pptp_expectfn(struct nf_conn *ct,
123 pr_debug("trying to unexpect other dir: "); 124 pr_debug("trying to unexpect other dir: ");
124 nf_ct_dump_tuple(&inv_t); 125 nf_ct_dump_tuple(&inv_t);
125 126
126 exp_other = nf_ct_expect_find_get(net, &inv_t); 127 exp_other = nf_ct_expect_find_get(net, nf_ct_zone(ct), &inv_t);
127 if (exp_other) { 128 if (exp_other) {
128 /* delete other expectation. */ 129 /* delete other expectation. */
129 pr_debug("found\n"); 130 pr_debug("found\n");
@@ -136,17 +137,18 @@ static void pptp_expectfn(struct nf_conn *ct,
136 rcu_read_unlock(); 137 rcu_read_unlock();
137} 138}
138 139
139static int destroy_sibling_or_exp(struct net *net, 140static int destroy_sibling_or_exp(struct net *net, struct nf_conn *ct,
140 const struct nf_conntrack_tuple *t) 141 const struct nf_conntrack_tuple *t)
141{ 142{
142 const struct nf_conntrack_tuple_hash *h; 143 const struct nf_conntrack_tuple_hash *h;
143 struct nf_conntrack_expect *exp; 144 struct nf_conntrack_expect *exp;
144 struct nf_conn *sibling; 145 struct nf_conn *sibling;
146 u16 zone = nf_ct_zone(ct);
145 147
146 pr_debug("trying to timeout ct or exp for tuple "); 148 pr_debug("trying to timeout ct or exp for tuple ");
147 nf_ct_dump_tuple(t); 149 nf_ct_dump_tuple(t);
148 150
149 h = nf_conntrack_find_get(net, t); 151 h = nf_conntrack_find_get(net, zone, t);
150 if (h) { 152 if (h) {
151 sibling = nf_ct_tuplehash_to_ctrack(h); 153 sibling = nf_ct_tuplehash_to_ctrack(h);
152 pr_debug("setting timeout of conntrack %p to 0\n", sibling); 154 pr_debug("setting timeout of conntrack %p to 0\n", sibling);
@@ -157,7 +159,7 @@ static int destroy_sibling_or_exp(struct net *net,
157 nf_ct_put(sibling); 159 nf_ct_put(sibling);
158 return 1; 160 return 1;
159 } else { 161 } else {
160 exp = nf_ct_expect_find_get(net, t); 162 exp = nf_ct_expect_find_get(net, zone, t);
161 if (exp) { 163 if (exp) {
162 pr_debug("unexpect_related of expect %p\n", exp); 164 pr_debug("unexpect_related of expect %p\n", exp);
163 nf_ct_unexpect_related(exp); 165 nf_ct_unexpect_related(exp);
@@ -182,7 +184,7 @@ static void pptp_destroy_siblings(struct nf_conn *ct)
182 t.dst.protonum = IPPROTO_GRE; 184 t.dst.protonum = IPPROTO_GRE;
183 t.src.u.gre.key = help->help.ct_pptp_info.pns_call_id; 185 t.src.u.gre.key = help->help.ct_pptp_info.pns_call_id;
184 t.dst.u.gre.key = help->help.ct_pptp_info.pac_call_id; 186 t.dst.u.gre.key = help->help.ct_pptp_info.pac_call_id;
185 if (!destroy_sibling_or_exp(net, &t)) 187 if (!destroy_sibling_or_exp(net, ct, &t))
186 pr_debug("failed to timeout original pns->pac ct/exp\n"); 188 pr_debug("failed to timeout original pns->pac ct/exp\n");
187 189
188 /* try reply (pac->pns) tuple */ 190 /* try reply (pac->pns) tuple */
@@ -190,7 +192,7 @@ static void pptp_destroy_siblings(struct nf_conn *ct)
190 t.dst.protonum = IPPROTO_GRE; 192 t.dst.protonum = IPPROTO_GRE;
191 t.src.u.gre.key = help->help.ct_pptp_info.pac_call_id; 193 t.src.u.gre.key = help->help.ct_pptp_info.pac_call_id;
192 t.dst.u.gre.key = help->help.ct_pptp_info.pns_call_id; 194 t.dst.u.gre.key = help->help.ct_pptp_info.pns_call_id;
193 if (!destroy_sibling_or_exp(net, &t)) 195 if (!destroy_sibling_or_exp(net, ct, &t))
194 pr_debug("failed to timeout reply pac->pns ct/exp\n"); 196 pr_debug("failed to timeout reply pac->pns ct/exp\n");
195} 197}
196 198
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index fbe8ff5a420a..8dd75d90efc0 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -23,6 +23,7 @@
23#include <net/netfilter/nf_conntrack_core.h> 23#include <net/netfilter/nf_conntrack_core.h>
24#include <net/netfilter/nf_conntrack_expect.h> 24#include <net/netfilter/nf_conntrack_expect.h>
25#include <net/netfilter/nf_conntrack_helper.h> 25#include <net/netfilter/nf_conntrack_helper.h>
26#include <net/netfilter/nf_conntrack_zones.h>
26#include <linux/netfilter/nf_conntrack_sip.h> 27#include <linux/netfilter/nf_conntrack_sip.h>
27 28
28MODULE_LICENSE("GPL"); 29MODULE_LICENSE("GPL");
@@ -836,7 +837,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int dataoff,
836 837
837 rcu_read_lock(); 838 rcu_read_lock();
838 do { 839 do {
839 exp = __nf_ct_expect_find(net, &tuple); 840 exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
840 841
841 if (!exp || exp->master == ct || 842 if (!exp || exp->master == ct ||
842 nfct_help(exp->master)->helper != nfct_help(ct)->helper || 843 nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index e310f1561bb2..24a42efe62ef 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -26,6 +26,7 @@
26#include <net/netfilter/nf_conntrack_expect.h> 26#include <net/netfilter/nf_conntrack_expect.h>
27#include <net/netfilter/nf_conntrack_helper.h> 27#include <net/netfilter/nf_conntrack_helper.h>
28#include <net/netfilter/nf_conntrack_acct.h> 28#include <net/netfilter/nf_conntrack_acct.h>
29#include <net/netfilter/nf_conntrack_zones.h>
29 30
30MODULE_LICENSE("GPL"); 31MODULE_LICENSE("GPL");
31 32
@@ -171,6 +172,11 @@ static int ct_seq_show(struct seq_file *s, void *v)
171 goto release; 172 goto release;
172#endif 173#endif
173 174
175#ifdef CONFIG_NF_CONNTRACK_ZONES
176 if (seq_printf(s, "zone=%u ", nf_ct_zone(ct)))
177 goto release;
178#endif
179
174 if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) 180 if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use)))
175 goto release; 181 goto release;
176 182
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index 8183a054256f..61c50fa84703 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -16,6 +16,7 @@
16#include <net/netfilter/nf_conntrack.h> 16#include <net/netfilter/nf_conntrack.h>
17#include <net/netfilter/nf_conntrack_helper.h> 17#include <net/netfilter/nf_conntrack_helper.h>
18#include <net/netfilter/nf_conntrack_ecache.h> 18#include <net/netfilter/nf_conntrack_ecache.h>
19#include <net/netfilter/nf_conntrack_zones.h>
19 20
20static unsigned int xt_ct_target(struct sk_buff *skb, 21static unsigned int xt_ct_target(struct sk_buff *skb,
21 const struct xt_target_param *par) 22 const struct xt_target_param *par)
@@ -69,11 +70,16 @@ static bool xt_ct_tg_check(const struct xt_tgchk_param *par)
69 goto out; 70 goto out;
70 } 71 }
71 72
73#ifndef CONFIG_NF_CONNTRACK_ZONES
74 if (info->zone)
75 goto err1;
76#endif
77
72 if (nf_ct_l3proto_try_module_get(par->family) < 0) 78 if (nf_ct_l3proto_try_module_get(par->family) < 0)
73 goto err1; 79 goto err1;
74 80
75 memset(&t, 0, sizeof(t)); 81 memset(&t, 0, sizeof(t));
76 ct = nf_conntrack_alloc(par->net, &t, &t, GFP_KERNEL); 82 ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
77 if (IS_ERR(ct)) 83 if (IS_ERR(ct))
78 goto err2; 84 goto err2;
79 85
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c
index 0d9d18ea2b09..26997ce90e48 100644
--- a/net/netfilter/xt_connlimit.c
+++ b/net/netfilter/xt_connlimit.c
@@ -28,6 +28,7 @@
28#include <net/netfilter/nf_conntrack.h> 28#include <net/netfilter/nf_conntrack.h>
29#include <net/netfilter/nf_conntrack_core.h> 29#include <net/netfilter/nf_conntrack_core.h>
30#include <net/netfilter/nf_conntrack_tuple.h> 30#include <net/netfilter/nf_conntrack_tuple.h>
31#include <net/netfilter/nf_conntrack_zones.h>
31 32
32/* we will save the tuples of all connections we care about */ 33/* we will save the tuples of all connections we care about */
33struct xt_connlimit_conn { 34struct xt_connlimit_conn {
@@ -114,7 +115,8 @@ static int count_them(struct net *net,
114 115
115 /* check the saved connections */ 116 /* check the saved connections */
116 list_for_each_entry_safe(conn, tmp, hash, list) { 117 list_for_each_entry_safe(conn, tmp, hash, list) {
117 found = nf_conntrack_find_get(net, &conn->tuple); 118 found = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE,
119 &conn->tuple);
118 found_ct = NULL; 120 found_ct = NULL;
119 121
120 if (found != NULL) 122 if (found != NULL)