Commit eaae44d248b151e7257ba551ae589cf343c3fdf6
Exists in
master
and in
7 other branches
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Showing 12 changed files Side-by-side Diff
- include/linux/list_nulls.h
- include/net/netfilter/nf_conntrack.h
- include/net/netfilter/nf_conntrack_ecache.h
- include/net/netfilter/nf_conntrack_extend.h
- include/net/netfilter/nf_conntrack_helper.h
- include/net/netns/conntrack.h
- net/netfilter/nf_conntrack_core.c
- net/netfilter/nf_conntrack_ecache.c
- net/netfilter/nf_conntrack_helper.c
- net/netfilter/nf_conntrack_netlink.c
- net/netfilter/nf_log.c
- net/netfilter/x_tables.c
include/linux/list_nulls.h
... | ... | @@ -56,6 +56,18 @@ |
56 | 56 | return is_a_nulls(h->first); |
57 | 57 | } |
58 | 58 | |
59 | +static inline void hlist_nulls_add_head(struct hlist_nulls_node *n, | |
60 | + struct hlist_nulls_head *h) | |
61 | +{ | |
62 | + struct hlist_nulls_node *first = h->first; | |
63 | + | |
64 | + n->next = first; | |
65 | + n->pprev = &h->first; | |
66 | + h->first = n; | |
67 | + if (!is_a_nulls(first)) | |
68 | + first->pprev = &n->next; | |
69 | +} | |
70 | + | |
59 | 71 | static inline void __hlist_nulls_del(struct hlist_nulls_node *n) |
60 | 72 | { |
61 | 73 | struct hlist_nulls_node *next = n->next; |
... | ... | @@ -63,6 +75,12 @@ |
63 | 75 | *pprev = next; |
64 | 76 | if (!is_a_nulls(next)) |
65 | 77 | next->pprev = pprev; |
78 | +} | |
79 | + | |
80 | +static inline void hlist_nulls_del(struct hlist_nulls_node *n) | |
81 | +{ | |
82 | + __hlist_nulls_del(n); | |
83 | + n->pprev = LIST_POISON2; | |
66 | 84 | } |
67 | 85 | |
68 | 86 | /** |
include/net/netfilter/nf_conntrack.h
... | ... | @@ -201,6 +201,8 @@ |
201 | 201 | __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); |
202 | 202 | |
203 | 203 | extern void nf_conntrack_hash_insert(struct nf_conn *ct); |
204 | +extern void nf_ct_delete_from_lists(struct nf_conn *ct); | |
205 | +extern void nf_ct_insert_dying_list(struct nf_conn *ct); | |
204 | 206 | |
205 | 207 | extern void nf_conntrack_flush_report(struct net *net, u32 pid, int report); |
206 | 208 |
include/net/netfilter/nf_conntrack_ecache.h
... | ... | @@ -6,61 +6,54 @@ |
6 | 6 | #define _NF_CONNTRACK_ECACHE_H |
7 | 7 | #include <net/netfilter/nf_conntrack.h> |
8 | 8 | |
9 | -#include <linux/interrupt.h> | |
10 | 9 | #include <net/net_namespace.h> |
11 | 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 | 16 | enum ip_conntrack_events |
15 | 17 | { |
16 | - /* New conntrack */ | |
17 | - IPCT_NEW_BIT = 0, | |
18 | - IPCT_NEW = (1 << IPCT_NEW_BIT), | |
18 | + IPCT_NEW = 0, /* new conntrack */ | |
19 | + IPCT_RELATED = 1, /* related conntrack */ | |
20 | + IPCT_DESTROY = 2, /* destroyed conntrack */ | |
21 | + IPCT_STATUS = 3, /* status has changed */ | |
22 | + IPCT_PROTOINFO = 4, /* protocol information has changed */ | |
23 | + IPCT_HELPER = 5, /* new helper has been set */ | |
24 | + IPCT_MARK = 6, /* new mark has been set */ | |
25 | + IPCT_NATSEQADJ = 7, /* NAT is doing sequence adjustment */ | |
26 | + IPCT_SECMARK = 8, /* new security mark has been set */ | |
27 | +}; | |
19 | 28 | |
20 | - /* Expected connection */ | |
21 | - IPCT_RELATED_BIT = 1, | |
22 | - IPCT_RELATED = (1 << IPCT_RELATED_BIT), | |
29 | +enum ip_conntrack_expect_events { | |
30 | + IPEXP_NEW = 0, /* new expectation */ | |
31 | +}; | |
23 | 32 | |
24 | - /* Destroyed conntrack */ | |
25 | - IPCT_DESTROY_BIT = 2, | |
26 | - IPCT_DESTROY = (1 << IPCT_DESTROY_BIT), | |
33 | +struct nf_conntrack_ecache { | |
34 | + unsigned long cache; /* bitops want long */ | |
35 | + unsigned long missed; /* missed events */ | |
36 | + u32 pid; /* netlink pid of destroyer */ | |
37 | +}; | |
27 | 38 | |
28 | - /* Status has changed */ | |
29 | - IPCT_STATUS_BIT = 3, | |
30 | - IPCT_STATUS = (1 << IPCT_STATUS_BIT), | |
39 | +static inline struct nf_conntrack_ecache * | |
40 | +nf_ct_ecache_find(const struct nf_conn *ct) | |
41 | +{ | |
42 | + return nf_ct_ext_find(ct, NF_CT_EXT_ECACHE); | |
43 | +} | |
31 | 44 | |
32 | - /* Update of protocol info */ | |
33 | - IPCT_PROTOINFO_BIT = 4, | |
34 | - IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT), | |
45 | +static inline struct nf_conntrack_ecache * | |
46 | +nf_ct_ecache_ext_add(struct nf_conn *ct, gfp_t gfp) | |
47 | +{ | |
48 | + struct net *net = nf_ct_net(ct); | |
35 | 49 | |
36 | - /* New helper for conntrack */ | |
37 | - IPCT_HELPER_BIT = 5, | |
38 | - IPCT_HELPER = (1 << IPCT_HELPER_BIT), | |
50 | + if (!net->ct.sysctl_events) | |
51 | + return NULL; | |
39 | 52 | |
40 | - /* Mark is set */ | |
41 | - IPCT_MARK_BIT = 6, | |
42 | - IPCT_MARK = (1 << IPCT_MARK_BIT), | |
43 | - | |
44 | - /* NAT sequence adjustment */ | |
45 | - IPCT_NATSEQADJ_BIT = 7, | |
46 | - IPCT_NATSEQADJ = (1 << IPCT_NATSEQADJ_BIT), | |
47 | - | |
48 | - /* Secmark is set */ | |
49 | - IPCT_SECMARK_BIT = 8, | |
50 | - IPCT_SECMARK = (1 << IPCT_SECMARK_BIT), | |
53 | + return nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp); | |
51 | 54 | }; |
52 | 55 | |
53 | -enum ip_conntrack_expect_events { | |
54 | - IPEXP_NEW_BIT = 0, | |
55 | - IPEXP_NEW = (1 << IPEXP_NEW_BIT), | |
56 | -}; | |
57 | - | |
58 | 56 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
59 | -struct nf_conntrack_ecache { | |
60 | - struct nf_conn *ct; | |
61 | - unsigned int events; | |
62 | -}; | |
63 | - | |
64 | 57 | /* This structure is passed to event handler */ |
65 | 58 | struct nf_ct_event { |
66 | 59 | struct nf_conn *ct; |
67 | 60 | |
68 | 61 | |
69 | 62 | |
70 | 63 | |
71 | 64 | |
72 | 65 | |
73 | 66 | |
74 | 67 | |
75 | 68 | |
76 | 69 | |
77 | 70 | |
... | ... | @@ -76,53 +69,88 @@ |
76 | 69 | extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb); |
77 | 70 | extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb); |
78 | 71 | |
79 | -extern void nf_ct_deliver_cached_events(const 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); | |
72 | +extern void nf_ct_deliver_cached_events(struct nf_conn *ct); | |
82 | 73 | |
83 | 74 | static inline void |
84 | 75 | nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) |
85 | 76 | { |
86 | - struct net *net = nf_ct_net(ct); | |
87 | - struct nf_conntrack_ecache *ecache; | |
77 | + struct nf_conntrack_ecache *e; | |
88 | 78 | |
89 | - local_bh_disable(); | |
90 | - ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id()); | |
91 | - if (ct != ecache->ct) | |
92 | - __nf_ct_event_cache_init(ct); | |
93 | - ecache->events |= event; | |
94 | - local_bh_enable(); | |
79 | + if (nf_conntrack_event_cb == NULL) | |
80 | + return; | |
81 | + | |
82 | + e = nf_ct_ecache_find(ct); | |
83 | + if (e == NULL) | |
84 | + return; | |
85 | + | |
86 | + set_bit(event, &e->cache); | |
95 | 87 | } |
96 | 88 | |
97 | -static inline void | |
98 | -nf_conntrack_event_report(enum ip_conntrack_events event, | |
99 | - struct nf_conn *ct, | |
100 | - u32 pid, | |
101 | - int report) | |
89 | +static inline int | |
90 | +nf_conntrack_eventmask_report(unsigned int eventmask, | |
91 | + struct nf_conn *ct, | |
92 | + u32 pid, | |
93 | + int report) | |
102 | 94 | { |
95 | + int ret = 0; | |
96 | + struct net *net = nf_ct_net(ct); | |
103 | 97 | struct nf_ct_event_notifier *notify; |
98 | + struct nf_conntrack_ecache *e; | |
104 | 99 | |
105 | 100 | rcu_read_lock(); |
106 | 101 | notify = rcu_dereference(nf_conntrack_event_cb); |
107 | 102 | if (notify == NULL) |
108 | 103 | goto out_unlock; |
109 | 104 | |
105 | + if (!net->ct.sysctl_events) | |
106 | + goto out_unlock; | |
107 | + | |
108 | + e = nf_ct_ecache_find(ct); | |
109 | + if (e == NULL) | |
110 | + goto out_unlock; | |
111 | + | |
110 | 112 | if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) { |
111 | 113 | struct nf_ct_event item = { |
112 | 114 | .ct = ct, |
113 | - .pid = pid, | |
115 | + .pid = e->pid ? e->pid : pid, | |
114 | 116 | .report = report |
115 | 117 | }; |
116 | - notify->fcn(event, &item); | |
118 | + /* This is a resent of a destroy event? If so, skip missed */ | |
119 | + unsigned long missed = e->pid ? 0 : e->missed; | |
120 | + | |
121 | + ret = notify->fcn(eventmask | missed, &item); | |
122 | + if (unlikely(ret < 0 || missed)) { | |
123 | + spin_lock_bh(&ct->lock); | |
124 | + if (ret < 0) { | |
125 | + /* This is a destroy event that has been | |
126 | + * triggered by a process, we store the PID | |
127 | + * to include it in the retransmission. */ | |
128 | + if (eventmask & (1 << IPCT_DESTROY) && | |
129 | + e->pid == 0 && pid != 0) | |
130 | + e->pid = pid; | |
131 | + else | |
132 | + e->missed |= eventmask; | |
133 | + } else | |
134 | + e->missed &= ~missed; | |
135 | + spin_unlock_bh(&ct->lock); | |
136 | + } | |
117 | 137 | } |
118 | 138 | out_unlock: |
119 | 139 | rcu_read_unlock(); |
140 | + return ret; | |
120 | 141 | } |
121 | 142 | |
122 | -static inline void | |
143 | +static inline int | |
144 | +nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct, | |
145 | + u32 pid, int report) | |
146 | +{ | |
147 | + return nf_conntrack_eventmask_report(1 << event, ct, pid, report); | |
148 | +} | |
149 | + | |
150 | +static inline int | |
123 | 151 | nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) |
124 | 152 | { |
125 | - nf_conntrack_event_report(event, ct, 0, 0); | |
153 | + return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); | |
126 | 154 | } |
127 | 155 | |
128 | 156 | struct nf_exp_event { |
... | ... | @@ -145,6 +173,7 @@ |
145 | 173 | u32 pid, |
146 | 174 | int report) |
147 | 175 | { |
176 | + struct net *net = nf_ct_exp_net(exp); | |
148 | 177 | struct nf_exp_event_notifier *notify; |
149 | 178 | |
150 | 179 | rcu_read_lock(); |
151 | 180 | |
... | ... | @@ -152,13 +181,16 @@ |
152 | 181 | if (notify == NULL) |
153 | 182 | goto out_unlock; |
154 | 183 | |
184 | + if (!net->ct.sysctl_events) | |
185 | + goto out_unlock; | |
186 | + | |
155 | 187 | { |
156 | 188 | struct nf_exp_event item = { |
157 | 189 | .exp = exp, |
158 | 190 | .pid = pid, |
159 | 191 | .report = report |
160 | 192 | }; |
161 | - notify->fcn(event, &item); | |
193 | + notify->fcn(1 << event, &item); | |
162 | 194 | } |
163 | 195 | out_unlock: |
164 | 196 | rcu_read_unlock(); |
... | ... | @@ -178,12 +210,16 @@ |
178 | 210 | |
179 | 211 | static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, |
180 | 212 | struct nf_conn *ct) {} |
181 | -static inline void nf_conntrack_event(enum ip_conntrack_events event, | |
182 | - struct nf_conn *ct) {} | |
183 | -static inline void nf_conntrack_event_report(enum ip_conntrack_events event, | |
184 | - struct nf_conn *ct, | |
185 | - u32 pid, | |
186 | - int report) {} | |
213 | +static inline int nf_conntrack_eventmask_report(unsigned int eventmask, | |
214 | + struct nf_conn *ct, | |
215 | + u32 pid, | |
216 | + int report) { return 0; } | |
217 | +static inline int nf_conntrack_event(enum ip_conntrack_events event, | |
218 | + struct nf_conn *ct) { return 0; } | |
219 | +static inline int nf_conntrack_event_report(enum ip_conntrack_events event, | |
220 | + struct nf_conn *ct, | |
221 | + u32 pid, | |
222 | + int report) { return 0; } | |
187 | 223 | static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} |
188 | 224 | static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, |
189 | 225 | struct nf_conntrack_expect *exp) {} |
... | ... | @@ -191,7 +227,6 @@ |
191 | 227 | struct nf_conntrack_expect *exp, |
192 | 228 | u32 pid, |
193 | 229 | int report) {} |
194 | -static inline void nf_ct_event_cache_flush(struct net *net) {} | |
195 | 230 | |
196 | 231 | static inline int nf_conntrack_ecache_init(struct net *net) |
197 | 232 | { |
include/net/netfilter/nf_conntrack_extend.h
... | ... | @@ -8,12 +8,14 @@ |
8 | 8 | NF_CT_EXT_HELPER, |
9 | 9 | NF_CT_EXT_NAT, |
10 | 10 | NF_CT_EXT_ACCT, |
11 | + NF_CT_EXT_ECACHE, | |
11 | 12 | NF_CT_EXT_NUM, |
12 | 13 | }; |
13 | 14 | |
14 | 15 | #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help |
15 | 16 | #define NF_CT_EXT_NAT_TYPE struct nf_conn_nat |
16 | 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 | 20 | /* Extensions: optional stuff which isn't permanently in struct. */ |
19 | 21 | struct nf_ct_ext { |
include/net/netfilter/nf_conntrack_helper.h
... | ... | @@ -50,6 +50,8 @@ |
50 | 50 | |
51 | 51 | extern int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags); |
52 | 52 | |
53 | +extern void nf_ct_helper_destroy(struct nf_conn *ct); | |
54 | + | |
53 | 55 | static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) |
54 | 56 | { |
55 | 57 | return nf_ct_ext_find(ct, NF_CT_EXT_HELPER); |
include/net/netns/conntrack.h
... | ... | @@ -14,16 +14,17 @@ |
14 | 14 | struct hlist_nulls_head *hash; |
15 | 15 | struct hlist_head *expect_hash; |
16 | 16 | struct hlist_nulls_head unconfirmed; |
17 | + struct hlist_nulls_head dying; | |
17 | 18 | struct ip_conntrack_stat *stat; |
18 | -#ifdef CONFIG_NF_CONNTRACK_EVENTS | |
19 | - struct nf_conntrack_ecache *ecache; | |
20 | -#endif | |
19 | + int sysctl_events; | |
20 | + unsigned int sysctl_events_retry_timeout; | |
21 | 21 | int sysctl_acct; |
22 | 22 | int sysctl_checksum; |
23 | 23 | unsigned int sysctl_log_invalid; /* Log invalid packets */ |
24 | 24 | #ifdef CONFIG_SYSCTL |
25 | 25 | struct ctl_table_header *sysctl_header; |
26 | 26 | struct ctl_table_header *acct_sysctl_header; |
27 | + struct ctl_table_header *event_sysctl_header; | |
27 | 28 | #endif |
28 | 29 | int hash_vmalloc; |
29 | 30 | int expect_vmalloc; |
net/netfilter/nf_conntrack_core.c
... | ... | @@ -39,6 +39,7 @@ |
39 | 39 | #include <net/netfilter/nf_conntrack_core.h> |
40 | 40 | #include <net/netfilter/nf_conntrack_extend.h> |
41 | 41 | #include <net/netfilter/nf_conntrack_acct.h> |
42 | +#include <net/netfilter/nf_conntrack_ecache.h> | |
42 | 43 | #include <net/netfilter/nf_nat.h> |
43 | 44 | #include <net/netfilter/nf_nat_core.h> |
44 | 45 | |
... | ... | @@ -182,10 +183,6 @@ |
182 | 183 | NF_CT_ASSERT(atomic_read(&nfct->use) == 0); |
183 | 184 | NF_CT_ASSERT(!timer_pending(&ct->timeout)); |
184 | 185 | |
185 | - if (!test_bit(IPS_DYING_BIT, &ct->status)) | |
186 | - nf_conntrack_event(IPCT_DESTROY, ct); | |
187 | - set_bit(IPS_DYING_BIT, &ct->status); | |
188 | - | |
189 | 186 | /* To make sure we don't get any weird locking issues here: |
190 | 187 | * destroy_conntrack() MUST NOT be called with a write lock |
191 | 188 | * to nf_conntrack_lock!!! -HW */ |
192 | 189 | |
193 | 190 | |
194 | 191 | |
195 | 192 | |
196 | 193 | |
... | ... | @@ -219,30 +216,73 @@ |
219 | 216 | nf_conntrack_free(ct); |
220 | 217 | } |
221 | 218 | |
222 | -static void death_by_timeout(unsigned long ul_conntrack) | |
219 | +void nf_ct_delete_from_lists(struct nf_conn *ct) | |
223 | 220 | { |
224 | - struct nf_conn *ct = (void *)ul_conntrack; | |
225 | 221 | struct net *net = nf_ct_net(ct); |
226 | - struct nf_conn_help *help = nfct_help(ct); | |
227 | - struct nf_conntrack_helper *helper; | |
228 | 222 | |
229 | - if (help) { | |
230 | - rcu_read_lock(); | |
231 | - helper = rcu_dereference(help->helper); | |
232 | - if (helper && helper->destroy) | |
233 | - helper->destroy(ct); | |
234 | - rcu_read_unlock(); | |
235 | - } | |
236 | - | |
223 | + nf_ct_helper_destroy(ct); | |
237 | 224 | spin_lock_bh(&nf_conntrack_lock); |
238 | 225 | /* Inside lock so preempt is disabled on module removal path. |
239 | 226 | * Otherwise we can get spurious warnings. */ |
240 | 227 | NF_CT_STAT_INC(net, delete_list); |
241 | 228 | clean_from_lists(ct); |
242 | 229 | spin_unlock_bh(&nf_conntrack_lock); |
230 | +} | |
231 | +EXPORT_SYMBOL_GPL(nf_ct_delete_from_lists); | |
232 | + | |
233 | +static void death_by_event(unsigned long ul_conntrack) | |
234 | +{ | |
235 | + struct nf_conn *ct = (void *)ul_conntrack; | |
236 | + struct net *net = nf_ct_net(ct); | |
237 | + | |
238 | + if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) { | |
239 | + /* bad luck, let's retry again */ | |
240 | + ct->timeout.expires = jiffies + | |
241 | + (random32() % net->ct.sysctl_events_retry_timeout); | |
242 | + add_timer(&ct->timeout); | |
243 | + return; | |
244 | + } | |
245 | + /* we've got the event delivered, now it's dying */ | |
246 | + set_bit(IPS_DYING_BIT, &ct->status); | |
247 | + spin_lock(&nf_conntrack_lock); | |
248 | + hlist_nulls_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); | |
249 | + spin_unlock(&nf_conntrack_lock); | |
243 | 250 | nf_ct_put(ct); |
244 | 251 | } |
245 | 252 | |
253 | +void nf_ct_insert_dying_list(struct nf_conn *ct) | |
254 | +{ | |
255 | + struct net *net = nf_ct_net(ct); | |
256 | + | |
257 | + /* add this conntrack to the dying list */ | |
258 | + spin_lock_bh(&nf_conntrack_lock); | |
259 | + hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, | |
260 | + &net->ct.dying); | |
261 | + spin_unlock_bh(&nf_conntrack_lock); | |
262 | + /* set a new timer to retry event delivery */ | |
263 | + setup_timer(&ct->timeout, death_by_event, (unsigned long)ct); | |
264 | + ct->timeout.expires = jiffies + | |
265 | + (random32() % net->ct.sysctl_events_retry_timeout); | |
266 | + add_timer(&ct->timeout); | |
267 | +} | |
268 | +EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list); | |
269 | + | |
270 | +static void death_by_timeout(unsigned long ul_conntrack) | |
271 | +{ | |
272 | + struct nf_conn *ct = (void *)ul_conntrack; | |
273 | + | |
274 | + if (!test_bit(IPS_DYING_BIT, &ct->status) && | |
275 | + unlikely(nf_conntrack_event(IPCT_DESTROY, ct) < 0)) { | |
276 | + /* destroy event was not delivered */ | |
277 | + nf_ct_delete_from_lists(ct); | |
278 | + nf_ct_insert_dying_list(ct); | |
279 | + return; | |
280 | + } | |
281 | + set_bit(IPS_DYING_BIT, &ct->status); | |
282 | + nf_ct_delete_from_lists(ct); | |
283 | + nf_ct_put(ct); | |
284 | +} | |
285 | + | |
246 | 286 | /* |
247 | 287 | * Warning : |
248 | 288 | * - Caller must take a reference on returned object |
... | ... | @@ -577,6 +617,7 @@ |
577 | 617 | } |
578 | 618 | |
579 | 619 | nf_ct_acct_ext_add(ct, GFP_ATOMIC); |
620 | + nf_ct_ecache_ext_add(ct, GFP_ATOMIC); | |
580 | 621 | |
581 | 622 | spin_lock_bh(&nf_conntrack_lock); |
582 | 623 | exp = nf_ct_find_expectation(net, tuple); |
... | ... | @@ -807,8 +848,6 @@ |
807 | 848 | NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); |
808 | 849 | NF_CT_ASSERT(skb); |
809 | 850 | |
810 | - spin_lock_bh(&nf_conntrack_lock); | |
811 | - | |
812 | 851 | /* Only update if this is not a fixed timeout */ |
813 | 852 | if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) |
814 | 853 | goto acct; |
... | ... | @@ -822,11 +861,8 @@ |
822 | 861 | /* Only update the timeout if the new timeout is at least |
823 | 862 | HZ jiffies from the old timeout. Need del_timer for race |
824 | 863 | avoidance (may already be dying). */ |
825 | - if (newtime - ct->timeout.expires >= HZ | |
826 | - && del_timer(&ct->timeout)) { | |
827 | - ct->timeout.expires = newtime; | |
828 | - add_timer(&ct->timeout); | |
829 | - } | |
864 | + if (newtime - ct->timeout.expires >= HZ) | |
865 | + mod_timer_pending(&ct->timeout, newtime); | |
830 | 866 | } |
831 | 867 | |
832 | 868 | acct: |
833 | 869 | |
834 | 870 | |
... | ... | @@ -835,13 +871,13 @@ |
835 | 871 | |
836 | 872 | acct = nf_conn_acct_find(ct); |
837 | 873 | if (acct) { |
874 | + spin_lock_bh(&ct->lock); | |
838 | 875 | acct[CTINFO2DIR(ctinfo)].packets++; |
839 | 876 | acct[CTINFO2DIR(ctinfo)].bytes += |
840 | 877 | skb->len - skb_network_offset(skb); |
878 | + spin_unlock_bh(&ct->lock); | |
841 | 879 | } |
842 | 880 | } |
843 | - | |
844 | - spin_unlock_bh(&nf_conntrack_lock); | |
845 | 881 | } |
846 | 882 | EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct); |
847 | 883 | |
848 | 884 | |
849 | 885 | |
850 | 886 | |
... | ... | @@ -853,14 +889,14 @@ |
853 | 889 | if (do_acct) { |
854 | 890 | struct nf_conn_counter *acct; |
855 | 891 | |
856 | - spin_lock_bh(&nf_conntrack_lock); | |
857 | 892 | acct = nf_conn_acct_find(ct); |
858 | 893 | if (acct) { |
894 | + spin_lock_bh(&ct->lock); | |
859 | 895 | acct[CTINFO2DIR(ctinfo)].packets++; |
860 | 896 | acct[CTINFO2DIR(ctinfo)].bytes += |
861 | 897 | skb->len - skb_network_offset(skb); |
898 | + spin_unlock_bh(&ct->lock); | |
862 | 899 | } |
863 | - spin_unlock_bh(&nf_conntrack_lock); | |
864 | 900 | } |
865 | 901 | |
866 | 902 | if (del_timer(&ct->timeout)) { |
... | ... | @@ -994,11 +1030,13 @@ |
994 | 1030 | { |
995 | 1031 | struct __nf_ct_flush_report *fr = (struct __nf_ct_flush_report *)data; |
996 | 1032 | |
997 | - /* get_next_corpse sets the dying bit for us */ | |
998 | - nf_conntrack_event_report(IPCT_DESTROY, | |
999 | - i, | |
1000 | - fr->pid, | |
1001 | - fr->report); | |
1033 | + /* If we fail to deliver the event, death_by_timeout() will retry */ | |
1034 | + if (nf_conntrack_event_report(IPCT_DESTROY, i, | |
1035 | + fr->pid, fr->report) < 0) | |
1036 | + return 1; | |
1037 | + | |
1038 | + /* Avoid the delivery of the destroy event in death_by_timeout(). */ | |
1039 | + set_bit(IPS_DYING_BIT, &i->status); | |
1002 | 1040 | return 1; |
1003 | 1041 | } |
1004 | 1042 | |
... | ... | @@ -1027,6 +1065,21 @@ |
1027 | 1065 | } |
1028 | 1066 | EXPORT_SYMBOL_GPL(nf_conntrack_flush_report); |
1029 | 1067 | |
1068 | +static void nf_ct_release_dying_list(void) | |
1069 | +{ | |
1070 | + struct nf_conntrack_tuple_hash *h; | |
1071 | + struct nf_conn *ct; | |
1072 | + struct hlist_nulls_node *n; | |
1073 | + | |
1074 | + spin_lock_bh(&nf_conntrack_lock); | |
1075 | + hlist_nulls_for_each_entry(h, n, &init_net.ct.dying, hnnode) { | |
1076 | + ct = nf_ct_tuplehash_to_ctrack(h); | |
1077 | + /* never fails to remove them, no listeners at this point */ | |
1078 | + nf_ct_kill(ct); | |
1079 | + } | |
1080 | + spin_unlock_bh(&nf_conntrack_lock); | |
1081 | +} | |
1082 | + | |
1030 | 1083 | static void nf_conntrack_cleanup_init_net(void) |
1031 | 1084 | { |
1032 | 1085 | nf_conntrack_helper_fini(); |
1033 | 1086 | |
... | ... | @@ -1036,10 +1089,9 @@ |
1036 | 1089 | |
1037 | 1090 | static void nf_conntrack_cleanup_net(struct net *net) |
1038 | 1091 | { |
1039 | - nf_ct_event_cache_flush(net); | |
1040 | - nf_conntrack_ecache_fini(net); | |
1041 | 1092 | i_see_dead_people: |
1042 | 1093 | nf_ct_iterate_cleanup(net, kill_all, NULL); |
1094 | + nf_ct_release_dying_list(); | |
1043 | 1095 | if (atomic_read(&net->ct.count) != 0) { |
1044 | 1096 | schedule(); |
1045 | 1097 | goto i_see_dead_people; |
... | ... | @@ -1050,6 +1102,7 @@ |
1050 | 1102 | |
1051 | 1103 | nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, |
1052 | 1104 | nf_conntrack_htable_size); |
1105 | + nf_conntrack_ecache_fini(net); | |
1053 | 1106 | nf_conntrack_acct_fini(net); |
1054 | 1107 | nf_conntrack_expect_fini(net); |
1055 | 1108 | free_percpu(net->ct.stat); |
1056 | 1109 | |
... | ... | @@ -1220,14 +1273,12 @@ |
1220 | 1273 | |
1221 | 1274 | atomic_set(&net->ct.count, 0); |
1222 | 1275 | INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, 0); |
1276 | + INIT_HLIST_NULLS_HEAD(&net->ct.dying, 0); | |
1223 | 1277 | net->ct.stat = alloc_percpu(struct ip_conntrack_stat); |
1224 | 1278 | if (!net->ct.stat) { |
1225 | 1279 | ret = -ENOMEM; |
1226 | 1280 | goto err_stat; |
1227 | 1281 | } |
1228 | - ret = nf_conntrack_ecache_init(net); | |
1229 | - if (ret < 0) | |
1230 | - goto err_ecache; | |
1231 | 1282 | net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, |
1232 | 1283 | &net->ct.hash_vmalloc, 1); |
1233 | 1284 | if (!net->ct.hash) { |
... | ... | @@ -1241,6 +1292,9 @@ |
1241 | 1292 | ret = nf_conntrack_acct_init(net); |
1242 | 1293 | if (ret < 0) |
1243 | 1294 | goto err_acct; |
1295 | + ret = nf_conntrack_ecache_init(net); | |
1296 | + if (ret < 0) | |
1297 | + goto err_ecache; | |
1244 | 1298 | |
1245 | 1299 | /* Set up fake conntrack: |
1246 | 1300 | - to never be deleted, not in any hashes */ |
1247 | 1301 | |
... | ... | @@ -1253,14 +1307,14 @@ |
1253 | 1307 | |
1254 | 1308 | return 0; |
1255 | 1309 | |
1310 | +err_ecache: | |
1311 | + nf_conntrack_acct_fini(net); | |
1256 | 1312 | err_acct: |
1257 | 1313 | nf_conntrack_expect_fini(net); |
1258 | 1314 | err_expect: |
1259 | 1315 | nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, |
1260 | 1316 | nf_conntrack_htable_size); |
1261 | 1317 | err_hash: |
1262 | - nf_conntrack_ecache_fini(net); | |
1263 | -err_ecache: | |
1264 | 1318 | free_percpu(net->ct.stat); |
1265 | 1319 | err_stat: |
1266 | 1320 | return ret; |
net/netfilter/nf_conntrack_ecache.c
... | ... | @@ -21,6 +21,7 @@ |
21 | 21 | |
22 | 22 | #include <net/netfilter/nf_conntrack.h> |
23 | 23 | #include <net/netfilter/nf_conntrack_core.h> |
24 | +#include <net/netfilter/nf_conntrack_extend.h> | |
24 | 25 | |
25 | 26 | static DEFINE_MUTEX(nf_ct_ecache_mutex); |
26 | 27 | |
27 | 28 | |
28 | 29 | |
29 | 30 | |
30 | 31 | |
31 | 32 | |
32 | 33 | |
33 | 34 | |
34 | 35 | |
35 | 36 | |
... | ... | @@ -32,94 +33,51 @@ |
32 | 33 | |
33 | 34 | /* deliver cached events and clear cache entry - must be called with locally |
34 | 35 | * disabled softirqs */ |
35 | -static inline void | |
36 | -__nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) | |
36 | +void nf_ct_deliver_cached_events(struct nf_conn *ct) | |
37 | 37 | { |
38 | + unsigned long events; | |
38 | 39 | struct nf_ct_event_notifier *notify; |
40 | + struct nf_conntrack_ecache *e; | |
39 | 41 | |
40 | 42 | rcu_read_lock(); |
41 | 43 | notify = rcu_dereference(nf_conntrack_event_cb); |
42 | 44 | if (notify == NULL) |
43 | 45 | goto out_unlock; |
44 | 46 | |
45 | - if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) | |
46 | - && ecache->events) { | |
47 | + e = nf_ct_ecache_find(ct); | |
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 | 54 | struct nf_ct_event item = { |
48 | - .ct = ecache->ct, | |
55 | + .ct = ct, | |
49 | 56 | .pid = 0, |
50 | 57 | .report = 0 |
51 | 58 | }; |
59 | + int ret; | |
60 | + /* We make a copy of the missed event cache without taking | |
61 | + * the lock, thus we may send missed events twice. However, | |
62 | + * this does not harm and it happens very rarely. */ | |
63 | + unsigned long missed = e->missed; | |
52 | 64 | |
53 | - notify->fcn(ecache->events, &item); | |
65 | + ret = notify->fcn(events | missed, &item); | |
66 | + if (unlikely(ret < 0 || missed)) { | |
67 | + spin_lock_bh(&ct->lock); | |
68 | + if (ret < 0) | |
69 | + e->missed |= events; | |
70 | + else | |
71 | + e->missed &= ~missed; | |
72 | + spin_unlock_bh(&ct->lock); | |
73 | + } | |
54 | 74 | } |
55 | 75 | |
56 | - ecache->events = 0; | |
57 | - nf_ct_put(ecache->ct); | |
58 | - ecache->ct = NULL; | |
59 | - | |
60 | 76 | out_unlock: |
61 | 77 | rcu_read_unlock(); |
62 | 78 | } |
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 | 79 | EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); |
78 | 80 | |
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 | 81 | int nf_conntrack_register_notifier(struct nf_ct_event_notifier *new) |
124 | 82 | { |
125 | 83 | int ret = 0; |
... | ... | @@ -185,4 +143,119 @@ |
185 | 143 | mutex_unlock(&nf_ct_ecache_mutex); |
186 | 144 | } |
187 | 145 | EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); |
146 | + | |
147 | +#define NF_CT_EVENTS_DEFAULT 1 | |
148 | +static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT; | |
149 | +static int nf_ct_events_retry_timeout __read_mostly = 15*HZ; | |
150 | + | |
151 | +#ifdef CONFIG_SYSCTL | |
152 | +static struct ctl_table event_sysctl_table[] = { | |
153 | + { | |
154 | + .ctl_name = CTL_UNNUMBERED, | |
155 | + .procname = "nf_conntrack_events", | |
156 | + .data = &init_net.ct.sysctl_events, | |
157 | + .maxlen = sizeof(unsigned int), | |
158 | + .mode = 0644, | |
159 | + .proc_handler = proc_dointvec, | |
160 | + }, | |
161 | + { | |
162 | + .ctl_name = CTL_UNNUMBERED, | |
163 | + .procname = "nf_conntrack_events_retry_timeout", | |
164 | + .data = &init_net.ct.sysctl_events_retry_timeout, | |
165 | + .maxlen = sizeof(unsigned int), | |
166 | + .mode = 0644, | |
167 | + .proc_handler = proc_dointvec_jiffies, | |
168 | + }, | |
169 | + {} | |
170 | +}; | |
171 | +#endif /* CONFIG_SYSCTL */ | |
172 | + | |
173 | +static struct nf_ct_ext_type event_extend __read_mostly = { | |
174 | + .len = sizeof(struct nf_conntrack_ecache), | |
175 | + .align = __alignof__(struct nf_conntrack_ecache), | |
176 | + .id = NF_CT_EXT_ECACHE, | |
177 | +}; | |
178 | + | |
179 | +#ifdef CONFIG_SYSCTL | |
180 | +static int nf_conntrack_event_init_sysctl(struct net *net) | |
181 | +{ | |
182 | + struct ctl_table *table; | |
183 | + | |
184 | + table = kmemdup(event_sysctl_table, sizeof(event_sysctl_table), | |
185 | + GFP_KERNEL); | |
186 | + if (!table) | |
187 | + goto out; | |
188 | + | |
189 | + table[0].data = &net->ct.sysctl_events; | |
190 | + table[1].data = &net->ct.sysctl_events_retry_timeout; | |
191 | + | |
192 | + net->ct.event_sysctl_header = | |
193 | + register_net_sysctl_table(net, | |
194 | + nf_net_netfilter_sysctl_path, table); | |
195 | + if (!net->ct.event_sysctl_header) { | |
196 | + printk(KERN_ERR "nf_ct_event: can't register to sysctl.\n"); | |
197 | + goto out_register; | |
198 | + } | |
199 | + return 0; | |
200 | + | |
201 | +out_register: | |
202 | + kfree(table); | |
203 | +out: | |
204 | + return -ENOMEM; | |
205 | +} | |
206 | + | |
207 | +static void nf_conntrack_event_fini_sysctl(struct net *net) | |
208 | +{ | |
209 | + struct ctl_table *table; | |
210 | + | |
211 | + table = net->ct.event_sysctl_header->ctl_table_arg; | |
212 | + unregister_net_sysctl_table(net->ct.event_sysctl_header); | |
213 | + kfree(table); | |
214 | +} | |
215 | +#else | |
216 | +static int nf_conntrack_event_init_sysctl(struct net *net) | |
217 | +{ | |
218 | + return 0; | |
219 | +} | |
220 | + | |
221 | +static void nf_conntrack_event_fini_sysctl(struct net *net) | |
222 | +{ | |
223 | +} | |
224 | +#endif /* CONFIG_SYSCTL */ | |
225 | + | |
226 | +int nf_conntrack_ecache_init(struct net *net) | |
227 | +{ | |
228 | + int ret; | |
229 | + | |
230 | + net->ct.sysctl_events = nf_ct_events; | |
231 | + net->ct.sysctl_events_retry_timeout = nf_ct_events_retry_timeout; | |
232 | + | |
233 | + if (net_eq(net, &init_net)) { | |
234 | + ret = nf_ct_extend_register(&event_extend); | |
235 | + if (ret < 0) { | |
236 | + printk(KERN_ERR "nf_ct_event: Unable to register " | |
237 | + "event extension.\n"); | |
238 | + goto out_extend_register; | |
239 | + } | |
240 | + } | |
241 | + | |
242 | + ret = nf_conntrack_event_init_sysctl(net); | |
243 | + if (ret < 0) | |
244 | + goto out_sysctl; | |
245 | + | |
246 | + return 0; | |
247 | + | |
248 | +out_sysctl: | |
249 | + if (net_eq(net, &init_net)) | |
250 | + nf_ct_extend_unregister(&event_extend); | |
251 | +out_extend_register: | |
252 | + return ret; | |
253 | +} | |
254 | + | |
255 | +void nf_conntrack_ecache_fini(struct net *net) | |
256 | +{ | |
257 | + nf_conntrack_event_fini_sysctl(net); | |
258 | + if (net_eq(net, &init_net)) | |
259 | + nf_ct_extend_unregister(&event_extend); | |
260 | +} |
net/netfilter/nf_conntrack_helper.c
... | ... | @@ -136,6 +136,20 @@ |
136 | 136 | return 0; |
137 | 137 | } |
138 | 138 | |
139 | +void nf_ct_helper_destroy(struct nf_conn *ct) | |
140 | +{ | |
141 | + struct nf_conn_help *help = nfct_help(ct); | |
142 | + struct nf_conntrack_helper *helper; | |
143 | + | |
144 | + if (help) { | |
145 | + rcu_read_lock(); | |
146 | + helper = rcu_dereference(help->helper); | |
147 | + if (helper && helper->destroy) | |
148 | + helper->destroy(ct); | |
149 | + rcu_read_unlock(); | |
150 | + } | |
151 | +} | |
152 | + | |
139 | 153 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) |
140 | 154 | { |
141 | 155 | unsigned int h = helper_hash(&me->tuple); |
net/netfilter/nf_conntrack_netlink.c
... | ... | @@ -463,15 +463,16 @@ |
463 | 463 | struct sk_buff *skb; |
464 | 464 | unsigned int type; |
465 | 465 | unsigned int flags = 0, group; |
466 | + int err; | |
466 | 467 | |
467 | 468 | /* ignore our fake conntrack entry */ |
468 | 469 | if (ct == &nf_conntrack_untracked) |
469 | 470 | return 0; |
470 | 471 | |
471 | - if (events & IPCT_DESTROY) { | |
472 | + if (events & (1 << IPCT_DESTROY)) { | |
472 | 473 | type = IPCTNL_MSG_CT_DELETE; |
473 | 474 | group = NFNLGRP_CONNTRACK_DESTROY; |
474 | - } else if (events & (IPCT_NEW | IPCT_RELATED)) { | |
475 | + } else if (events & ((1 << IPCT_NEW) | (1 << IPCT_RELATED))) { | |
475 | 476 | type = IPCTNL_MSG_CT_NEW; |
476 | 477 | flags = NLM_F_CREATE|NLM_F_EXCL; |
477 | 478 | group = NFNLGRP_CONNTRACK_NEW; |
... | ... | @@ -519,7 +520,7 @@ |
519 | 520 | if (ctnetlink_dump_status(skb, ct) < 0) |
520 | 521 | goto nla_put_failure; |
521 | 522 | |
522 | - if (events & IPCT_DESTROY) { | |
523 | + if (events & (1 << IPCT_DESTROY)) { | |
523 | 524 | if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || |
524 | 525 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) |
525 | 526 | goto nla_put_failure; |
526 | 527 | |
527 | 528 | |
528 | 529 | |
529 | 530 | |
530 | 531 | |
531 | 532 | |
... | ... | @@ -527,38 +528,41 @@ |
527 | 528 | if (ctnetlink_dump_timeout(skb, ct) < 0) |
528 | 529 | goto nla_put_failure; |
529 | 530 | |
530 | - if (events & IPCT_PROTOINFO | |
531 | + if (events & (1 << IPCT_PROTOINFO) | |
531 | 532 | && ctnetlink_dump_protoinfo(skb, ct) < 0) |
532 | 533 | goto nla_put_failure; |
533 | 534 | |
534 | - if ((events & IPCT_HELPER || nfct_help(ct)) | |
535 | + if ((events & (1 << IPCT_HELPER) || nfct_help(ct)) | |
535 | 536 | && ctnetlink_dump_helpinfo(skb, ct) < 0) |
536 | 537 | goto nla_put_failure; |
537 | 538 | |
538 | 539 | #ifdef CONFIG_NF_CONNTRACK_SECMARK |
539 | - if ((events & IPCT_SECMARK || ct->secmark) | |
540 | + if ((events & (1 << IPCT_SECMARK) || ct->secmark) | |
540 | 541 | && ctnetlink_dump_secmark(skb, ct) < 0) |
541 | 542 | goto nla_put_failure; |
542 | 543 | #endif |
543 | 544 | |
544 | - if (events & IPCT_RELATED && | |
545 | + if (events & (1 << IPCT_RELATED) && | |
545 | 546 | ctnetlink_dump_master(skb, ct) < 0) |
546 | 547 | goto nla_put_failure; |
547 | 548 | |
548 | - if (events & IPCT_NATSEQADJ && | |
549 | + if (events & (1 << IPCT_NATSEQADJ) && | |
549 | 550 | ctnetlink_dump_nat_seq_adj(skb, ct) < 0) |
550 | 551 | goto nla_put_failure; |
551 | 552 | } |
552 | 553 | |
553 | 554 | #ifdef CONFIG_NF_CONNTRACK_MARK |
554 | - if ((events & IPCT_MARK || ct->mark) | |
555 | + if ((events & (1 << IPCT_MARK) || ct->mark) | |
555 | 556 | && ctnetlink_dump_mark(skb, ct) < 0) |
556 | 557 | goto nla_put_failure; |
557 | 558 | #endif |
558 | 559 | rcu_read_unlock(); |
559 | 560 | |
560 | 561 | nlmsg_end(skb, nlh); |
561 | - nfnetlink_send(skb, item->pid, group, item->report, GFP_ATOMIC); | |
562 | + err = nfnetlink_send(skb, item->pid, group, item->report, GFP_ATOMIC); | |
563 | + if (err == -ENOBUFS || err == -EAGAIN) | |
564 | + return -ENOBUFS; | |
565 | + | |
562 | 566 | return 0; |
563 | 567 | |
564 | 568 | nla_put_failure: |
... | ... | @@ -798,10 +802,15 @@ |
798 | 802 | } |
799 | 803 | } |
800 | 804 | |
801 | - nf_conntrack_event_report(IPCT_DESTROY, | |
802 | - ct, | |
803 | - NETLINK_CB(skb).pid, | |
804 | - nlmsg_report(nlh)); | |
805 | + if (nf_conntrack_event_report(IPCT_DESTROY, ct, | |
806 | + NETLINK_CB(skb).pid, | |
807 | + nlmsg_report(nlh)) < 0) { | |
808 | + nf_ct_delete_from_lists(ct); | |
809 | + /* we failed to report the event, try later */ | |
810 | + nf_ct_insert_dying_list(ct); | |
811 | + nf_ct_put(ct); | |
812 | + return 0; | |
813 | + } | |
805 | 814 | |
806 | 815 | /* death_by_timeout would report the event again */ |
807 | 816 | set_bit(IPS_DYING_BIT, &ct->status); |
... | ... | @@ -1253,6 +1262,7 @@ |
1253 | 1262 | } |
1254 | 1263 | |
1255 | 1264 | nf_ct_acct_ext_add(ct, GFP_ATOMIC); |
1265 | + nf_ct_ecache_ext_add(ct, GFP_ATOMIC); | |
1256 | 1266 | |
1257 | 1267 | #if defined(CONFIG_NF_CONNTRACK_MARK) |
1258 | 1268 | if (cda[CTA_MARK]) |
... | ... | @@ -1340,13 +1350,13 @@ |
1340 | 1350 | else |
1341 | 1351 | events = IPCT_NEW; |
1342 | 1352 | |
1343 | - nf_conntrack_event_report(IPCT_STATUS | | |
1344 | - IPCT_HELPER | | |
1345 | - IPCT_PROTOINFO | | |
1346 | - IPCT_NATSEQADJ | | |
1347 | - IPCT_MARK | events, | |
1348 | - ct, NETLINK_CB(skb).pid, | |
1349 | - nlmsg_report(nlh)); | |
1353 | + nf_conntrack_eventmask_report((1 << IPCT_STATUS) | | |
1354 | + (1 << IPCT_HELPER) | | |
1355 | + (1 << IPCT_PROTOINFO) | | |
1356 | + (1 << IPCT_NATSEQADJ) | | |
1357 | + (1 << IPCT_MARK) | events, | |
1358 | + ct, NETLINK_CB(skb).pid, | |
1359 | + nlmsg_report(nlh)); | |
1350 | 1360 | nf_ct_put(ct); |
1351 | 1361 | } else |
1352 | 1362 | spin_unlock_bh(&nf_conntrack_lock); |
... | ... | @@ -1365,13 +1375,13 @@ |
1365 | 1375 | if (err == 0) { |
1366 | 1376 | nf_conntrack_get(&ct->ct_general); |
1367 | 1377 | spin_unlock_bh(&nf_conntrack_lock); |
1368 | - nf_conntrack_event_report(IPCT_STATUS | | |
1369 | - IPCT_HELPER | | |
1370 | - IPCT_PROTOINFO | | |
1371 | - IPCT_NATSEQADJ | | |
1372 | - IPCT_MARK, | |
1373 | - ct, NETLINK_CB(skb).pid, | |
1374 | - nlmsg_report(nlh)); | |
1378 | + nf_conntrack_eventmask_report((1 << IPCT_STATUS) | | |
1379 | + (1 << IPCT_HELPER) | | |
1380 | + (1 << IPCT_PROTOINFO) | | |
1381 | + (1 << IPCT_NATSEQADJ) | | |
1382 | + (1 << IPCT_MARK), | |
1383 | + ct, NETLINK_CB(skb).pid, | |
1384 | + nlmsg_report(nlh)); | |
1375 | 1385 | nf_ct_put(ct); |
1376 | 1386 | } else |
1377 | 1387 | spin_unlock_bh(&nf_conntrack_lock); |
... | ... | @@ -1515,7 +1525,7 @@ |
1515 | 1525 | unsigned int type; |
1516 | 1526 | int flags = 0; |
1517 | 1527 | |
1518 | - if (events & IPEXP_NEW) { | |
1528 | + if (events & (1 << IPEXP_NEW)) { | |
1519 | 1529 | type = IPCTNL_MSG_EXP_NEW; |
1520 | 1530 | flags = NLM_F_CREATE|NLM_F_EXCL; |
1521 | 1531 | } else |
net/netfilter/nf_log.c
... | ... | @@ -248,14 +248,14 @@ |
248 | 248 | rcu_assign_pointer(nf_loggers[tindex], logger); |
249 | 249 | mutex_unlock(&nf_log_mutex); |
250 | 250 | } else { |
251 | - rcu_read_lock(); | |
252 | - logger = rcu_dereference(nf_loggers[tindex]); | |
251 | + mutex_lock(&nf_log_mutex); | |
252 | + logger = nf_loggers[tindex]; | |
253 | 253 | if (!logger) |
254 | 254 | table->data = "NONE"; |
255 | 255 | else |
256 | 256 | table->data = logger->name; |
257 | 257 | r = proc_dostring(table, write, filp, buffer, lenp, ppos); |
258 | - rcu_read_unlock(); | |
258 | + mutex_unlock(&nf_log_mutex); | |
259 | 259 | } |
260 | 260 | |
261 | 261 | return r; |
net/netfilter/x_tables.c
... | ... | @@ -364,14 +364,14 @@ |
364 | 364 | * ebt_among is exempt from centralized matchsize checking |
365 | 365 | * because it uses a dynamic-size data set. |
366 | 366 | */ |
367 | - printk("%s_tables: %s match: invalid size %Zu != %u\n", | |
367 | + pr_err("%s_tables: %s match: invalid size %Zu != %u\n", | |
368 | 368 | xt_prefix[par->family], par->match->name, |
369 | 369 | XT_ALIGN(par->match->matchsize), size); |
370 | 370 | return -EINVAL; |
371 | 371 | } |
372 | 372 | if (par->match->table != NULL && |
373 | 373 | strcmp(par->match->table, par->table) != 0) { |
374 | - printk("%s_tables: %s match: only valid in %s table, not %s\n", | |
374 | + pr_err("%s_tables: %s match: only valid in %s table, not %s\n", | |
375 | 375 | xt_prefix[par->family], par->match->name, |
376 | 376 | par->match->table, par->table); |
377 | 377 | return -EINVAL; |
... | ... | @@ -379,7 +379,7 @@ |
379 | 379 | if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) { |
380 | 380 | char used[64], allow[64]; |
381 | 381 | |
382 | - printk("%s_tables: %s match: used from hooks %s, but only " | |
382 | + pr_err("%s_tables: %s match: used from hooks %s, but only " | |
383 | 383 | "valid from %s\n", |
384 | 384 | xt_prefix[par->family], par->match->name, |
385 | 385 | textify_hooks(used, sizeof(used), par->hook_mask), |
... | ... | @@ -387,7 +387,7 @@ |
387 | 387 | return -EINVAL; |
388 | 388 | } |
389 | 389 | if (par->match->proto && (par->match->proto != proto || inv_proto)) { |
390 | - printk("%s_tables: %s match: only valid for protocol %u\n", | |
390 | + pr_err("%s_tables: %s match: only valid for protocol %u\n", | |
391 | 391 | xt_prefix[par->family], par->match->name, |
392 | 392 | par->match->proto); |
393 | 393 | return -EINVAL; |
394 | 394 | |
... | ... | @@ -514,14 +514,14 @@ |
514 | 514 | unsigned int size, u_int8_t proto, bool inv_proto) |
515 | 515 | { |
516 | 516 | if (XT_ALIGN(par->target->targetsize) != size) { |
517 | - printk("%s_tables: %s target: invalid size %Zu != %u\n", | |
517 | + pr_err("%s_tables: %s target: invalid size %Zu != %u\n", | |
518 | 518 | xt_prefix[par->family], par->target->name, |
519 | 519 | XT_ALIGN(par->target->targetsize), size); |
520 | 520 | return -EINVAL; |
521 | 521 | } |
522 | 522 | if (par->target->table != NULL && |
523 | 523 | strcmp(par->target->table, par->table) != 0) { |
524 | - printk("%s_tables: %s target: only valid in %s table, not %s\n", | |
524 | + pr_err("%s_tables: %s target: only valid in %s table, not %s\n", | |
525 | 525 | xt_prefix[par->family], par->target->name, |
526 | 526 | par->target->table, par->table); |
527 | 527 | return -EINVAL; |
... | ... | @@ -529,7 +529,7 @@ |
529 | 529 | if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) { |
530 | 530 | char used[64], allow[64]; |
531 | 531 | |
532 | - printk("%s_tables: %s target: used from hooks %s, but only " | |
532 | + pr_err("%s_tables: %s target: used from hooks %s, but only " | |
533 | 533 | "usable from %s\n", |
534 | 534 | xt_prefix[par->family], par->target->name, |
535 | 535 | textify_hooks(used, sizeof(used), par->hook_mask), |
... | ... | @@ -537,7 +537,7 @@ |
537 | 537 | return -EINVAL; |
538 | 538 | } |
539 | 539 | if (par->target->proto && (par->target->proto != proto || inv_proto)) { |
540 | - printk("%s_tables: %s target: only valid for protocol %u\n", | |
540 | + pr_err("%s_tables: %s target: only valid for protocol %u\n", | |
541 | 541 | xt_prefix[par->family], par->target->name, |
542 | 542 | par->target->proto); |
543 | 543 | return -EINVAL; |