aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netfilter/nf_conntrack_ecache.h130
-rw-r--r--include/net/netfilter/nf_conntrack_extend.h2
-rw-r--r--include/net/netns/conntrack.h5
-rw-r--r--net/netfilter/nf_conntrack_core.c15
-rw-r--r--net/netfilter/nf_conntrack_ecache.c185
-rw-r--r--net/netfilter/nf_conntrack_netlink.c49
6 files changed, 223 insertions, 163 deletions
diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h
index 1afb907e015a..e7ae297ba383 100644
--- a/include/net/netfilter/nf_conntrack_ecache.h
+++ b/include/net/netfilter/nf_conntrack_ecache.h
@@ -6,61 +6,52 @@
6#define _NF_CONNTRACK_ECACHE_H 6#define _NF_CONNTRACK_ECACHE_H
7#include <net/netfilter/nf_conntrack.h> 7#include <net/netfilter/nf_conntrack.h>
8 8
9#include <linux/interrupt.h>
10#include <net/net_namespace.h> 9#include <net/net_namespace.h>
11#include <net/netfilter/nf_conntrack_expect.h> 10#include <net/netfilter/nf_conntrack_expect.h>
11#include <linux/netfilter/nf_conntrack_common.h>
12#include <linux/netfilter/nf_conntrack_tuple_common.h>
13#include <net/netfilter/nf_conntrack_extend.h>
12 14
13/* Connection tracking event bits */ 15/* Connection tracking event types */
14enum ip_conntrack_events 16enum ip_conntrack_events
15{ 17{
16 /* New conntrack */ 18 IPCT_NEW = 0, /* new conntrack */
17 IPCT_NEW_BIT = 0, 19 IPCT_RELATED = 1, /* related conntrack */
18 IPCT_NEW = (1 << IPCT_NEW_BIT), 20 IPCT_DESTROY = 2, /* destroyed conntrack */
19 21 IPCT_STATUS = 3, /* status has changed */
20 /* Expected connection */ 22 IPCT_PROTOINFO = 4, /* protocol information has changed */
21 IPCT_RELATED_BIT = 1, 23 IPCT_HELPER = 5, /* new helper has been set */
22 IPCT_RELATED = (1 << IPCT_RELATED_BIT), 24 IPCT_MARK = 6, /* new mark has been set */
23 25 IPCT_NATSEQADJ = 7, /* NAT is doing sequence adjustment */
24 /* Destroyed conntrack */ 26 IPCT_SECMARK = 8, /* new security mark has been set */
25 IPCT_DESTROY_BIT = 2, 27};
26 IPCT_DESTROY = (1 << IPCT_DESTROY_BIT),
27
28 /* Status has changed */
29 IPCT_STATUS_BIT = 3,
30 IPCT_STATUS = (1 << IPCT_STATUS_BIT),
31 28
32 /* Update of protocol info */ 29enum ip_conntrack_expect_events {
33 IPCT_PROTOINFO_BIT = 4, 30 IPEXP_NEW = 0, /* new expectation */
34 IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT), 31};
35 32
36 /* New helper for conntrack */ 33struct nf_conntrack_ecache {
37 IPCT_HELPER_BIT = 5, 34 unsigned long cache; /* bitops want long */
38 IPCT_HELPER = (1 << IPCT_HELPER_BIT), 35};
39 36
40 /* Mark is set */ 37static inline struct nf_conntrack_ecache *
41 IPCT_MARK_BIT = 6, 38nf_ct_ecache_find(const struct nf_conn *ct)
42 IPCT_MARK = (1 << IPCT_MARK_BIT), 39{
40 return nf_ct_ext_find(ct, NF_CT_EXT_ECACHE);
41}
43 42
44 /* NAT sequence adjustment */ 43static inline struct nf_conntrack_ecache *
45 IPCT_NATSEQADJ_BIT = 7, 44nf_ct_ecache_ext_add(struct nf_conn *ct, gfp_t gfp)
46 IPCT_NATSEQADJ = (1 << IPCT_NATSEQADJ_BIT), 45{
46 struct net *net = nf_ct_net(ct);
47 47
48 /* Secmark is set */ 48 if (!net->ct.sysctl_events)
49 IPCT_SECMARK_BIT = 8, 49 return NULL;
50 IPCT_SECMARK = (1 << IPCT_SECMARK_BIT),
51};
52 50
53enum ip_conntrack_expect_events { 51 return nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
54 IPEXP_NEW_BIT = 0,
55 IPEXP_NEW = (1 << IPEXP_NEW_BIT),
56}; 52};
57 53
58#ifdef CONFIG_NF_CONNTRACK_EVENTS 54#ifdef CONFIG_NF_CONNTRACK_EVENTS
59struct nf_conntrack_ecache {
60 struct nf_conn *ct;
61 unsigned int events;
62};
63
64/* This structure is passed to event handler */ 55/* This structure is passed to event handler */
65struct nf_ct_event { 56struct nf_ct_event {
66 struct nf_conn *ct; 57 struct nf_conn *ct;
@@ -76,30 +67,30 @@ extern struct nf_ct_event_notifier *nf_conntrack_event_cb;
76extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb); 67extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb);
77extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb); 68extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb);
78 69
79extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); 70extern void nf_ct_deliver_cached_events(struct nf_conn *ct);
80extern void __nf_ct_event_cache_init(struct nf_conn *ct);
81extern void nf_ct_event_cache_flush(struct net *net);
82 71
83static inline void 72static inline void
84nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) 73nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
85{ 74{
86 struct net *net = nf_ct_net(ct); 75 struct nf_conntrack_ecache *e;
87 struct nf_conntrack_ecache *ecache; 76
88 77 if (nf_conntrack_event_cb == NULL)
89 local_bh_disable(); 78 return;
90 ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id()); 79
91 if (ct != ecache->ct) 80 e = nf_ct_ecache_find(ct);
92 __nf_ct_event_cache_init(ct); 81 if (e == NULL)
93 ecache->events |= event; 82 return;
94 local_bh_enable(); 83
84 set_bit(event, &e->cache);
95} 85}
96 86
97static inline void 87static inline void
98nf_conntrack_event_report(enum ip_conntrack_events event, 88nf_conntrack_eventmask_report(unsigned int eventmask,
99 struct nf_conn *ct, 89 struct nf_conn *ct,
100 u32 pid, 90 u32 pid,
101 int report) 91 int report)
102{ 92{
93 struct net *net = nf_ct_net(ct);
103 struct nf_ct_event_notifier *notify; 94 struct nf_ct_event_notifier *notify;
104 95
105 rcu_read_lock(); 96 rcu_read_lock();
@@ -107,22 +98,32 @@ nf_conntrack_event_report(enum ip_conntrack_events event,
107 if (notify == NULL) 98 if (notify == NULL)
108 goto out_unlock; 99 goto out_unlock;
109 100
101 if (!net->ct.sysctl_events)
102 goto out_unlock;
103
110 if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) { 104 if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) {
111 struct nf_ct_event item = { 105 struct nf_ct_event item = {
112 .ct = ct, 106 .ct = ct,
113 .pid = pid, 107 .pid = pid,
114 .report = report 108 .report = report
115 }; 109 };
116 notify->fcn(event, &item); 110 notify->fcn(eventmask, &item);
117 } 111 }
118out_unlock: 112out_unlock:
119 rcu_read_unlock(); 113 rcu_read_unlock();
120} 114}
121 115
122static inline void 116static inline void
117nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct,
118 u32 pid, int report)
119{
120 nf_conntrack_eventmask_report(1 << event, ct, pid, report);
121}
122
123static inline void
123nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) 124nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct)
124{ 125{
125 nf_conntrack_event_report(event, ct, 0, 0); 126 nf_conntrack_eventmask_report(1 << event, ct, 0, 0);
126} 127}
127 128
128struct nf_exp_event { 129struct nf_exp_event {
@@ -145,6 +146,7 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
145 u32 pid, 146 u32 pid,
146 int report) 147 int report)
147{ 148{
149 struct net *net = nf_ct_exp_net(exp);
148 struct nf_exp_event_notifier *notify; 150 struct nf_exp_event_notifier *notify;
149 151
150 rcu_read_lock(); 152 rcu_read_lock();
@@ -152,13 +154,16 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
152 if (notify == NULL) 154 if (notify == NULL)
153 goto out_unlock; 155 goto out_unlock;
154 156
157 if (!net->ct.sysctl_events)
158 goto out_unlock;
159
155 { 160 {
156 struct nf_exp_event item = { 161 struct nf_exp_event item = {
157 .exp = exp, 162 .exp = exp,
158 .pid = pid, 163 .pid = pid,
159 .report = report 164 .report = report
160 }; 165 };
161 notify->fcn(event, &item); 166 notify->fcn(1 << event, &item);
162 } 167 }
163out_unlock: 168out_unlock:
164 rcu_read_unlock(); 169 rcu_read_unlock();
@@ -178,6 +183,10 @@ extern void nf_conntrack_ecache_fini(struct net *net);
178 183
179static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, 184static inline void nf_conntrack_event_cache(enum ip_conntrack_events event,
180 struct nf_conn *ct) {} 185 struct nf_conn *ct) {}
186static inline void nf_conntrack_eventmask_report(unsigned int eventmask,
187 struct nf_conn *ct,
188 u32 pid,
189 int report) {}
181static inline void nf_conntrack_event(enum ip_conntrack_events event, 190static inline void nf_conntrack_event(enum ip_conntrack_events event,
182 struct nf_conn *ct) {} 191 struct nf_conn *ct) {}
183static inline void nf_conntrack_event_report(enum ip_conntrack_events event, 192static inline void nf_conntrack_event_report(enum ip_conntrack_events event,
@@ -191,7 +200,6 @@ static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e,
191 struct nf_conntrack_expect *exp, 200 struct nf_conntrack_expect *exp,
192 u32 pid, 201 u32 pid,
193 int report) {} 202 int report) {}
194static inline void nf_ct_event_cache_flush(struct net *net) {}
195 203
196static inline int nf_conntrack_ecache_init(struct net *net) 204static inline int nf_conntrack_ecache_init(struct net *net)
197{ 205{
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index da8ee52613a5..7f8fc5d123c5 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -8,12 +8,14 @@ enum nf_ct_ext_id
8 NF_CT_EXT_HELPER, 8 NF_CT_EXT_HELPER,
9 NF_CT_EXT_NAT, 9 NF_CT_EXT_NAT,
10 NF_CT_EXT_ACCT, 10 NF_CT_EXT_ACCT,
11 NF_CT_EXT_ECACHE,
11 NF_CT_EXT_NUM, 12 NF_CT_EXT_NUM,
12}; 13};
13 14
14#define NF_CT_EXT_HELPER_TYPE struct nf_conn_help 15#define NF_CT_EXT_HELPER_TYPE struct nf_conn_help
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
18#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache
17 19
18/* Extensions: optional stuff which isn't permanently in struct. */ 20/* Extensions: optional stuff which isn't permanently in struct. */
19struct nf_ct_ext { 21struct nf_ct_ext {
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index 9dc58402bc09..505a51cd8c63 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -15,15 +15,14 @@ struct netns_ct {
15 struct hlist_head *expect_hash; 15 struct hlist_head *expect_hash;
16 struct hlist_nulls_head unconfirmed; 16 struct hlist_nulls_head unconfirmed;
17 struct ip_conntrack_stat *stat; 17 struct ip_conntrack_stat *stat;
18#ifdef CONFIG_NF_CONNTRACK_EVENTS 18 int sysctl_events;
19 struct nf_conntrack_ecache *ecache;
20#endif
21 int sysctl_acct; 19 int sysctl_acct;
22 int sysctl_checksum; 20 int sysctl_checksum;
23 unsigned int sysctl_log_invalid; /* Log invalid packets */ 21 unsigned int sysctl_log_invalid; /* Log invalid packets */
24#ifdef CONFIG_SYSCTL 22#ifdef CONFIG_SYSCTL
25 struct ctl_table_header *sysctl_header; 23 struct ctl_table_header *sysctl_header;
26 struct ctl_table_header *acct_sysctl_header; 24 struct ctl_table_header *acct_sysctl_header;
25 struct ctl_table_header *event_sysctl_header;
27#endif 26#endif
28 int hash_vmalloc; 27 int hash_vmalloc;
29 int expect_vmalloc; 28 int expect_vmalloc;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index d8dffe7ab509..bcacbb5373c3 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -39,6 +39,7 @@
39#include <net/netfilter/nf_conntrack_core.h> 39#include <net/netfilter/nf_conntrack_core.h>
40#include <net/netfilter/nf_conntrack_extend.h> 40#include <net/netfilter/nf_conntrack_extend.h>
41#include <net/netfilter/nf_conntrack_acct.h> 41#include <net/netfilter/nf_conntrack_acct.h>
42#include <net/netfilter/nf_conntrack_ecache.h>
42#include <net/netfilter/nf_nat.h> 43#include <net/netfilter/nf_nat.h>
43#include <net/netfilter/nf_nat_core.h> 44#include <net/netfilter/nf_nat_core.h>
44 45
@@ -577,6 +578,7 @@ init_conntrack(struct net *net,
577 } 578 }
578 579
579 nf_ct_acct_ext_add(ct, GFP_ATOMIC); 580 nf_ct_acct_ext_add(ct, GFP_ATOMIC);
581 nf_ct_ecache_ext_add(ct, GFP_ATOMIC);
580 582
581 spin_lock_bh(&nf_conntrack_lock); 583 spin_lock_bh(&nf_conntrack_lock);
582 exp = nf_ct_find_expectation(net, tuple); 584 exp = nf_ct_find_expectation(net, tuple);
@@ -1031,8 +1033,6 @@ static void nf_conntrack_cleanup_init_net(void)
1031 1033
1032static void nf_conntrack_cleanup_net(struct net *net) 1034static void nf_conntrack_cleanup_net(struct net *net)
1033{ 1035{
1034 nf_ct_event_cache_flush(net);
1035 nf_conntrack_ecache_fini(net);
1036 i_see_dead_people: 1036 i_see_dead_people:
1037 nf_ct_iterate_cleanup(net, kill_all, NULL); 1037 nf_ct_iterate_cleanup(net, kill_all, NULL);
1038 if (atomic_read(&net->ct.count) != 0) { 1038 if (atomic_read(&net->ct.count) != 0) {
@@ -1045,6 +1045,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
1045 1045
1046 nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, 1046 nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc,
1047 nf_conntrack_htable_size); 1047 nf_conntrack_htable_size);
1048 nf_conntrack_ecache_fini(net);
1048 nf_conntrack_acct_fini(net); 1049 nf_conntrack_acct_fini(net);
1049 nf_conntrack_expect_fini(net); 1050 nf_conntrack_expect_fini(net);
1050 free_percpu(net->ct.stat); 1051 free_percpu(net->ct.stat);
@@ -1220,9 +1221,6 @@ static int nf_conntrack_init_net(struct net *net)
1220 ret = -ENOMEM; 1221 ret = -ENOMEM;
1221 goto err_stat; 1222 goto err_stat;
1222 } 1223 }
1223 ret = nf_conntrack_ecache_init(net);
1224 if (ret < 0)
1225 goto err_ecache;
1226 net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, 1224 net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size,
1227 &net->ct.hash_vmalloc, 1); 1225 &net->ct.hash_vmalloc, 1);
1228 if (!net->ct.hash) { 1226 if (!net->ct.hash) {
@@ -1236,6 +1234,9 @@ static int nf_conntrack_init_net(struct net *net)
1236 ret = nf_conntrack_acct_init(net); 1234 ret = nf_conntrack_acct_init(net);
1237 if (ret < 0) 1235 if (ret < 0)
1238 goto err_acct; 1236 goto err_acct;
1237 ret = nf_conntrack_ecache_init(net);
1238 if (ret < 0)
1239 goto err_ecache;
1239 1240
1240 /* Set up fake conntrack: 1241 /* Set up fake conntrack:
1241 - to never be deleted, not in any hashes */ 1242 - to never be deleted, not in any hashes */
@@ -1248,14 +1249,14 @@ static int nf_conntrack_init_net(struct net *net)
1248 1249
1249 return 0; 1250 return 0;
1250 1251
1252err_ecache:
1253 nf_conntrack_acct_fini(net);
1251err_acct: 1254err_acct:
1252 nf_conntrack_expect_fini(net); 1255 nf_conntrack_expect_fini(net);
1253err_expect: 1256err_expect:
1254 nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, 1257 nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc,
1255 nf_conntrack_htable_size); 1258 nf_conntrack_htable_size);
1256err_hash: 1259err_hash:
1257 nf_conntrack_ecache_fini(net);
1258err_ecache:
1259 free_percpu(net->ct.stat); 1260 free_percpu(net->ct.stat);
1260err_stat: 1261err_stat:
1261 return ret; 1262 return ret;
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c
index 5516b3e64b43..683281b78047 100644
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -21,6 +21,7 @@
21 21
22#include <net/netfilter/nf_conntrack.h> 22#include <net/netfilter/nf_conntrack.h>
23#include <net/netfilter/nf_conntrack_core.h> 23#include <net/netfilter/nf_conntrack_core.h>
24#include <net/netfilter/nf_conntrack_extend.h>
24 25
25static DEFINE_MUTEX(nf_ct_ecache_mutex); 26static DEFINE_MUTEX(nf_ct_ecache_mutex);
26 27
@@ -32,94 +33,38 @@ EXPORT_SYMBOL_GPL(nf_expect_event_cb);
32 33
33/* deliver cached events and clear cache entry - must be called with locally 34/* deliver cached events and clear cache entry - must be called with locally
34 * disabled softirqs */ 35 * disabled softirqs */
35static inline void 36void nf_ct_deliver_cached_events(struct nf_conn *ct)
36__nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache)
37{ 37{
38 unsigned long events;
38 struct nf_ct_event_notifier *notify; 39 struct nf_ct_event_notifier *notify;
40 struct nf_conntrack_ecache *e;
39 41
40 rcu_read_lock(); 42 rcu_read_lock();
41 notify = rcu_dereference(nf_conntrack_event_cb); 43 notify = rcu_dereference(nf_conntrack_event_cb);
42 if (notify == NULL) 44 if (notify == NULL)
43 goto out_unlock; 45 goto out_unlock;
44 46
45 if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) 47 e = nf_ct_ecache_find(ct);
46 && ecache->events) { 48 if (e == NULL)
49 goto out_unlock;
50
51 events = xchg(&e->cache, 0);
52
53 if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct) && events) {
47 struct nf_ct_event item = { 54 struct nf_ct_event item = {
48 .ct = ecache->ct, 55 .ct = ct,
49 .pid = 0, 56 .pid = 0,
50 .report = 0 57 .report = 0
51 }; 58 };
52 59
53 notify->fcn(ecache->events, &item); 60 notify->fcn(events, &item);
54 } 61 }
55 62
56 ecache->events = 0;
57 nf_ct_put(ecache->ct);
58 ecache->ct = NULL;
59
60out_unlock: 63out_unlock:
61 rcu_read_unlock(); 64 rcu_read_unlock();
62} 65}
63
64/* Deliver all cached events for a particular conntrack. This is called
65 * by code prior to async packet handling for freeing the skb */
66void nf_ct_deliver_cached_events(const struct nf_conn *ct)
67{
68 struct net *net = nf_ct_net(ct);
69 struct nf_conntrack_ecache *ecache;
70
71 local_bh_disable();
72 ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id());
73 if (ecache->ct == ct)
74 __nf_ct_deliver_cached_events(ecache);
75 local_bh_enable();
76}
77EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); 66EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events);
78 67
79/* Deliver cached events for old pending events, if current conntrack != old */
80void __nf_ct_event_cache_init(struct nf_conn *ct)
81{
82 struct net *net = nf_ct_net(ct);
83 struct nf_conntrack_ecache *ecache;
84
85 /* take care of delivering potentially old events */
86 ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id());
87 BUG_ON(ecache->ct == ct);
88 if (ecache->ct)
89 __nf_ct_deliver_cached_events(ecache);
90 /* initialize for this conntrack/packet */
91 ecache->ct = ct;
92 nf_conntrack_get(&ct->ct_general);
93}
94EXPORT_SYMBOL_GPL(__nf_ct_event_cache_init);
95
96/* flush the event cache - touches other CPU's data and must not be called
97 * while packets are still passing through the code */
98void nf_ct_event_cache_flush(struct net *net)
99{
100 struct nf_conntrack_ecache *ecache;
101 int cpu;
102
103 for_each_possible_cpu(cpu) {
104 ecache = per_cpu_ptr(net->ct.ecache, cpu);
105 if (ecache->ct)
106 nf_ct_put(ecache->ct);
107 }
108}
109
110int nf_conntrack_ecache_init(struct net *net)
111{
112 net->ct.ecache = alloc_percpu(struct nf_conntrack_ecache);
113 if (!net->ct.ecache)
114 return -ENOMEM;
115 return 0;
116}
117
118void nf_conntrack_ecache_fini(struct net *net)
119{
120 free_percpu(net->ct.ecache);
121}
122
123int nf_conntrack_register_notifier(struct nf_ct_event_notifier *new) 68int nf_conntrack_register_notifier(struct nf_ct_event_notifier *new)
124{ 69{
125 int ret = 0; 70 int ret = 0;
@@ -185,3 +130,107 @@ void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *new)
185 mutex_unlock(&nf_ct_ecache_mutex); 130 mutex_unlock(&nf_ct_ecache_mutex);
186} 131}
187EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); 132EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier);
133
134#define NF_CT_EVENTS_DEFAULT 1
135static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT;
136
137#ifdef CONFIG_SYSCTL
138static struct ctl_table event_sysctl_table[] = {
139 {
140 .ctl_name = CTL_UNNUMBERED,
141 .procname = "nf_conntrack_events",
142 .data = &init_net.ct.sysctl_events,
143 .maxlen = sizeof(unsigned int),
144 .mode = 0644,
145 .proc_handler = proc_dointvec,
146 },
147 {}
148};
149#endif /* CONFIG_SYSCTL */
150
151static struct nf_ct_ext_type event_extend __read_mostly = {
152 .len = sizeof(struct nf_conntrack_ecache),
153 .align = __alignof__(struct nf_conntrack_ecache),
154 .id = NF_CT_EXT_ECACHE,
155};
156
157#ifdef CONFIG_SYSCTL
158static int nf_conntrack_event_init_sysctl(struct net *net)
159{
160 struct ctl_table *table;
161
162 table = kmemdup(event_sysctl_table, sizeof(event_sysctl_table),
163 GFP_KERNEL);
164 if (!table)
165 goto out;
166
167 table[0].data = &net->ct.sysctl_events;
168
169 net->ct.event_sysctl_header =
170 register_net_sysctl_table(net,
171 nf_net_netfilter_sysctl_path, table);
172 if (!net->ct.event_sysctl_header) {
173 printk(KERN_ERR "nf_ct_event: can't register to sysctl.\n");
174 goto out_register;
175 }
176 return 0;
177
178out_register:
179 kfree(table);
180out:
181 return -ENOMEM;
182}
183
184static void nf_conntrack_event_fini_sysctl(struct net *net)
185{
186 struct ctl_table *table;
187
188 table = net->ct.event_sysctl_header->ctl_table_arg;
189 unregister_net_sysctl_table(net->ct.event_sysctl_header);
190 kfree(table);
191}
192#else
193static int nf_conntrack_event_init_sysctl(struct net *net)
194{
195 return 0;
196}
197
198static void nf_conntrack_event_fini_sysctl(struct net *net)
199{
200}
201#endif /* CONFIG_SYSCTL */
202
203int nf_conntrack_ecache_init(struct net *net)
204{
205 int ret;
206
207 net->ct.sysctl_events = nf_ct_events;
208
209 if (net_eq(net, &init_net)) {
210 ret = nf_ct_extend_register(&event_extend);
211 if (ret < 0) {
212 printk(KERN_ERR "nf_ct_event: Unable to register "
213 "event extension.\n");
214 goto out_extend_register;
215 }
216 }
217
218 ret = nf_conntrack_event_init_sysctl(net);
219 if (ret < 0)
220 goto out_sysctl;
221
222 return 0;
223
224out_sysctl:
225 if (net_eq(net, &init_net))
226 nf_ct_extend_unregister(&event_extend);
227out_extend_register:
228 return ret;
229}
230
231void nf_conntrack_ecache_fini(struct net *net)
232{
233 nf_conntrack_event_fini_sysctl(net);
234 if (net_eq(net, &init_net))
235 nf_ct_extend_unregister(&event_extend);
236}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 4e503ada5728..19706eff1647 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -468,10 +468,10 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
468 if (ct == &nf_conntrack_untracked) 468 if (ct == &nf_conntrack_untracked)
469 return 0; 469 return 0;
470 470
471 if (events & IPCT_DESTROY) { 471 if (events & (1 << IPCT_DESTROY)) {
472 type = IPCTNL_MSG_CT_DELETE; 472 type = IPCTNL_MSG_CT_DELETE;
473 group = NFNLGRP_CONNTRACK_DESTROY; 473 group = NFNLGRP_CONNTRACK_DESTROY;
474 } else if (events & (IPCT_NEW | IPCT_RELATED)) { 474 } else if (events & ((1 << IPCT_NEW) | (1 << IPCT_RELATED))) {
475 type = IPCTNL_MSG_CT_NEW; 475 type = IPCTNL_MSG_CT_NEW;
476 flags = NLM_F_CREATE|NLM_F_EXCL; 476 flags = NLM_F_CREATE|NLM_F_EXCL;
477 group = NFNLGRP_CONNTRACK_NEW; 477 group = NFNLGRP_CONNTRACK_NEW;
@@ -519,7 +519,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
519 if (ctnetlink_dump_status(skb, ct) < 0) 519 if (ctnetlink_dump_status(skb, ct) < 0)
520 goto nla_put_failure; 520 goto nla_put_failure;
521 521
522 if (events & IPCT_DESTROY) { 522 if (events & (1 << IPCT_DESTROY)) {
523 if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || 523 if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
524 ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) 524 ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
525 goto nla_put_failure; 525 goto nla_put_failure;
@@ -527,31 +527,31 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
527 if (ctnetlink_dump_timeout(skb, ct) < 0) 527 if (ctnetlink_dump_timeout(skb, ct) < 0)
528 goto nla_put_failure; 528 goto nla_put_failure;
529 529
530 if (events & IPCT_PROTOINFO 530 if (events & (1 << IPCT_PROTOINFO)
531 && ctnetlink_dump_protoinfo(skb, ct) < 0) 531 && ctnetlink_dump_protoinfo(skb, ct) < 0)
532 goto nla_put_failure; 532 goto nla_put_failure;
533 533
534 if ((events & IPCT_HELPER || nfct_help(ct)) 534 if ((events & (1 << IPCT_HELPER) || nfct_help(ct))
535 && ctnetlink_dump_helpinfo(skb, ct) < 0) 535 && ctnetlink_dump_helpinfo(skb, ct) < 0)
536 goto nla_put_failure; 536 goto nla_put_failure;
537 537
538#ifdef CONFIG_NF_CONNTRACK_SECMARK 538#ifdef CONFIG_NF_CONNTRACK_SECMARK
539 if ((events & IPCT_SECMARK || ct->secmark) 539 if ((events & (1 << IPCT_SECMARK) || ct->secmark)
540 && ctnetlink_dump_secmark(skb, ct) < 0) 540 && ctnetlink_dump_secmark(skb, ct) < 0)
541 goto nla_put_failure; 541 goto nla_put_failure;
542#endif 542#endif
543 543
544 if (events & IPCT_RELATED && 544 if (events & (1 << IPCT_RELATED) &&
545 ctnetlink_dump_master(skb, ct) < 0) 545 ctnetlink_dump_master(skb, ct) < 0)
546 goto nla_put_failure; 546 goto nla_put_failure;
547 547
548 if (events & IPCT_NATSEQADJ && 548 if (events & (1 << IPCT_NATSEQADJ) &&
549 ctnetlink_dump_nat_seq_adj(skb, ct) < 0) 549 ctnetlink_dump_nat_seq_adj(skb, ct) < 0)
550 goto nla_put_failure; 550 goto nla_put_failure;
551 } 551 }
552 552
553#ifdef CONFIG_NF_CONNTRACK_MARK 553#ifdef CONFIG_NF_CONNTRACK_MARK
554 if ((events & IPCT_MARK || ct->mark) 554 if ((events & (1 << IPCT_MARK) || ct->mark)
555 && ctnetlink_dump_mark(skb, ct) < 0) 555 && ctnetlink_dump_mark(skb, ct) < 0)
556 goto nla_put_failure; 556 goto nla_put_failure;
557#endif 557#endif
@@ -1253,6 +1253,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1253 } 1253 }
1254 1254
1255 nf_ct_acct_ext_add(ct, GFP_ATOMIC); 1255 nf_ct_acct_ext_add(ct, GFP_ATOMIC);
1256 nf_ct_ecache_ext_add(ct, GFP_ATOMIC);
1256 1257
1257#if defined(CONFIG_NF_CONNTRACK_MARK) 1258#if defined(CONFIG_NF_CONNTRACK_MARK)
1258 if (cda[CTA_MARK]) 1259 if (cda[CTA_MARK])
@@ -1340,13 +1341,13 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1340 else 1341 else
1341 events = IPCT_NEW; 1342 events = IPCT_NEW;
1342 1343
1343 nf_conntrack_event_report(IPCT_STATUS | 1344 nf_conntrack_eventmask_report((1 << IPCT_STATUS) |
1344 IPCT_HELPER | 1345 (1 << IPCT_HELPER) |
1345 IPCT_PROTOINFO | 1346 (1 << IPCT_PROTOINFO) |
1346 IPCT_NATSEQADJ | 1347 (1 << IPCT_NATSEQADJ) |
1347 IPCT_MARK | events, 1348 (1 << IPCT_MARK) | events,
1348 ct, NETLINK_CB(skb).pid, 1349 ct, NETLINK_CB(skb).pid,
1349 nlmsg_report(nlh)); 1350 nlmsg_report(nlh));
1350 nf_ct_put(ct); 1351 nf_ct_put(ct);
1351 } else 1352 } else
1352 spin_unlock_bh(&nf_conntrack_lock); 1353 spin_unlock_bh(&nf_conntrack_lock);
@@ -1365,13 +1366,13 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1365 if (err == 0) { 1366 if (err == 0) {
1366 nf_conntrack_get(&ct->ct_general); 1367 nf_conntrack_get(&ct->ct_general);
1367 spin_unlock_bh(&nf_conntrack_lock); 1368 spin_unlock_bh(&nf_conntrack_lock);
1368 nf_conntrack_event_report(IPCT_STATUS | 1369 nf_conntrack_eventmask_report((1 << IPCT_STATUS) |
1369 IPCT_HELPER | 1370 (1 << IPCT_HELPER) |
1370 IPCT_PROTOINFO | 1371 (1 << IPCT_PROTOINFO) |
1371 IPCT_NATSEQADJ | 1372 (1 << IPCT_NATSEQADJ) |
1372 IPCT_MARK, 1373 (1 << IPCT_MARK),
1373 ct, NETLINK_CB(skb).pid, 1374 ct, NETLINK_CB(skb).pid,
1374 nlmsg_report(nlh)); 1375 nlmsg_report(nlh));
1375 nf_ct_put(ct); 1376 nf_ct_put(ct);
1376 } else 1377 } else
1377 spin_unlock_bh(&nf_conntrack_lock); 1378 spin_unlock_bh(&nf_conntrack_lock);
@@ -1515,7 +1516,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
1515 unsigned int type; 1516 unsigned int type;
1516 int flags = 0; 1517 int flags = 0;
1517 1518
1518 if (events & IPEXP_NEW) { 1519 if (events & (1 << IPEXP_NEW)) {
1519 type = IPCTNL_MSG_EXP_NEW; 1520 type = IPCTNL_MSG_EXP_NEW;
1520 flags = NLM_F_CREATE|NLM_F_EXCL; 1521 flags = NLM_F_CREATE|NLM_F_EXCL;
1521 } else 1522 } else