diff options
-rw-r--r-- | include/net/netfilter/nf_conntrack_ecache.h | 130 | ||||
-rw-r--r-- | include/net/netfilter/nf_conntrack_extend.h | 2 | ||||
-rw-r--r-- | include/net/netns/conntrack.h | 5 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 15 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_ecache.c | 185 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 49 |
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 */ |
14 | enum ip_conntrack_events | 16 | enum 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 */ | 29 | enum 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 */ | 33 | struct 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 */ | 37 | static inline struct nf_conntrack_ecache * |
41 | IPCT_MARK_BIT = 6, | 38 | nf_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 */ | 43 | static inline struct nf_conntrack_ecache * |
45 | IPCT_NATSEQADJ_BIT = 7, | 44 | nf_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 | ||
53 | enum 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 |
59 | struct 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 */ |
65 | struct nf_ct_event { | 56 | struct 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; | |||
76 | extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb); | 67 | extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb); |
77 | extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb); | 68 | extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb); |
78 | 69 | ||
79 | extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); | 70 | extern void nf_ct_deliver_cached_events(struct nf_conn *ct); |
80 | extern void __nf_ct_event_cache_init(struct nf_conn *ct); | ||
81 | extern void nf_ct_event_cache_flush(struct net *net); | ||
82 | 71 | ||
83 | static inline void | 72 | static inline void |
84 | nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) | 73 | nf_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 | ||
97 | static inline void | 87 | static inline void |
98 | nf_conntrack_event_report(enum ip_conntrack_events event, | 88 | nf_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 | } |
118 | out_unlock: | 112 | out_unlock: |
119 | rcu_read_unlock(); | 113 | rcu_read_unlock(); |
120 | } | 114 | } |
121 | 115 | ||
122 | static inline void | 116 | static inline void |
117 | nf_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 | |||
123 | static inline void | ||
123 | nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) | 124 | nf_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 | ||
128 | struct nf_exp_event { | 129 | struct 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 | } |
163 | out_unlock: | 168 | out_unlock: |
164 | rcu_read_unlock(); | 169 | rcu_read_unlock(); |
@@ -178,6 +183,10 @@ extern void nf_conntrack_ecache_fini(struct net *net); | |||
178 | 183 | ||
179 | static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, | 184 | static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, |
180 | struct nf_conn *ct) {} | 185 | struct nf_conn *ct) {} |
186 | static inline void nf_conntrack_eventmask_report(unsigned int eventmask, | ||
187 | struct nf_conn *ct, | ||
188 | u32 pid, | ||
189 | int report) {} | ||
181 | static inline void nf_conntrack_event(enum ip_conntrack_events event, | 190 | static inline void nf_conntrack_event(enum ip_conntrack_events event, |
182 | struct nf_conn *ct) {} | 191 | struct nf_conn *ct) {} |
183 | static inline void nf_conntrack_event_report(enum ip_conntrack_events event, | 192 | static 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) {} |
194 | static inline void nf_ct_event_cache_flush(struct net *net) {} | ||
195 | 203 | ||
196 | static inline int nf_conntrack_ecache_init(struct net *net) | 204 | static 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. */ |
19 | struct nf_ct_ext { | 21 | struct 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 | ||
1032 | static void nf_conntrack_cleanup_net(struct net *net) | 1034 | static 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 | ||
1252 | err_ecache: | ||
1253 | nf_conntrack_acct_fini(net); | ||
1251 | err_acct: | 1254 | err_acct: |
1252 | nf_conntrack_expect_fini(net); | 1255 | nf_conntrack_expect_fini(net); |
1253 | err_expect: | 1256 | err_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); |
1256 | err_hash: | 1259 | err_hash: |
1257 | nf_conntrack_ecache_fini(net); | ||
1258 | err_ecache: | ||
1259 | free_percpu(net->ct.stat); | 1260 | free_percpu(net->ct.stat); |
1260 | err_stat: | 1261 | err_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 | ||
25 | static DEFINE_MUTEX(nf_ct_ecache_mutex); | 26 | static 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 */ |
35 | static inline void | 36 | void 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 | |||
60 | out_unlock: | 63 | out_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 */ | ||
66 | void 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 | } | ||
77 | EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); | 66 | EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); |
78 | 67 | ||
79 | /* Deliver cached events for old pending events, if current conntrack != old */ | ||
80 | void __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 | } | ||
94 | EXPORT_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 */ | ||
98 | void 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 | |||
110 | int 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 | |||
118 | void nf_conntrack_ecache_fini(struct net *net) | ||
119 | { | ||
120 | free_percpu(net->ct.ecache); | ||
121 | } | ||
122 | |||
123 | int nf_conntrack_register_notifier(struct nf_ct_event_notifier *new) | 68 | int 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 | } |
187 | EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); | 132 | EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); |
133 | |||
134 | #define NF_CT_EVENTS_DEFAULT 1 | ||
135 | static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT; | ||
136 | |||
137 | #ifdef CONFIG_SYSCTL | ||
138 | static 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 | |||
151 | static 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 | ||
158 | static 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 | |||
178 | out_register: | ||
179 | kfree(table); | ||
180 | out: | ||
181 | return -ENOMEM; | ||
182 | } | ||
183 | |||
184 | static 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 | ||
193 | static int nf_conntrack_event_init_sysctl(struct net *net) | ||
194 | { | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static void nf_conntrack_event_fini_sysctl(struct net *net) | ||
199 | { | ||
200 | } | ||
201 | #endif /* CONFIG_SYSCTL */ | ||
202 | |||
203 | int 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 | |||
224 | out_sysctl: | ||
225 | if (net_eq(net, &init_net)) | ||
226 | nf_ct_extend_unregister(&event_extend); | ||
227 | out_extend_register: | ||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | void 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 |