diff options
author | Gao feng <gaofeng@cn.fujitsu.com> | 2012-05-28 17:04:10 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-06-07 08:58:39 -0400 |
commit | 524a53e5ad5f34f64ed34281e8b0eca19437db5b (patch) | |
tree | e6ad5ef71a1fe4b95c3ab5690d5e728513765e5d | |
parent | 2c352f444ccfa966a1aa4fd8e9ee29381c467448 (diff) |
netfilter: nf_conntrack: prepare namespace support for l3 protocol trackers
This patch prepares the namespace support for layer 3 protocol trackers.
Basically, this modifies the following interfaces:
* nf_ct_l3proto_[un]register_sysctl.
* nf_conntrack_l3proto_[un]register.
We add a new nf_ct_l3proto_net is used to get the pernet data of l3proto.
This adds rhe new struct nf_ip_net that is used to store the sysctl header
and l3proto_ipv4,l4proto_tcp(6),l4proto_udp(6),l4proto_icmp(v6) because the
protos such tcp and tcp6 use the same data,so making nf_ip_net as a field
of netns_ct is the easiest way to manager it.
This patch also adds init_net to struct nf_conntrack_l3proto to initial
the layer 3 protocol pernet data.
Acked-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | include/net/netfilter/nf_conntrack_l3proto.h | 9 | ||||
-rw-r--r-- | include/net/netns/conntrack.h | 8 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 6 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 6 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto.c | 92 |
5 files changed, 91 insertions, 30 deletions
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h index 9699c028b74..d6df8c71a7f 100644 --- a/include/net/netfilter/nf_conntrack_l3proto.h +++ b/include/net/netfilter/nf_conntrack_l3proto.h | |||
@@ -69,6 +69,9 @@ struct nf_conntrack_l3proto { | |||
69 | struct ctl_table *ctl_table; | 69 | struct ctl_table *ctl_table; |
70 | #endif /* CONFIG_SYSCTL */ | 70 | #endif /* CONFIG_SYSCTL */ |
71 | 71 | ||
72 | /* Init l3proto pernet data */ | ||
73 | int (*init_net)(struct net *net); | ||
74 | |||
72 | /* Module (if any) which this is connected to. */ | 75 | /* Module (if any) which this is connected to. */ |
73 | struct module *me; | 76 | struct module *me; |
74 | }; | 77 | }; |
@@ -76,8 +79,10 @@ struct nf_conntrack_l3proto { | |||
76 | extern struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX]; | 79 | extern struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX]; |
77 | 80 | ||
78 | /* Protocol registration. */ | 81 | /* Protocol registration. */ |
79 | extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto); | 82 | extern int nf_conntrack_l3proto_register(struct net *net, |
80 | extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto); | 83 | struct nf_conntrack_l3proto *proto); |
84 | extern void nf_conntrack_l3proto_unregister(struct net *net, | ||
85 | struct nf_conntrack_l3proto *proto); | ||
81 | extern struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto); | 86 | extern struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto); |
82 | extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p); | 87 | extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p); |
83 | 88 | ||
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index 1f53038b0d1..b2dbcc5cd81 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h | |||
@@ -20,6 +20,13 @@ struct nf_proto_net { | |||
20 | unsigned int users; | 20 | unsigned int users; |
21 | }; | 21 | }; |
22 | 22 | ||
23 | struct nf_ip_net { | ||
24 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) | ||
25 | struct ctl_table_header *ctl_table_header; | ||
26 | struct ctl_table *ctl_table; | ||
27 | #endif | ||
28 | }; | ||
29 | |||
23 | struct netns_ct { | 30 | struct netns_ct { |
24 | atomic_t count; | 31 | atomic_t count; |
25 | unsigned int expect_count; | 32 | unsigned int expect_count; |
@@ -40,6 +47,7 @@ struct netns_ct { | |||
40 | unsigned int sysctl_log_invalid; /* Log invalid packets */ | 47 | unsigned int sysctl_log_invalid; /* Log invalid packets */ |
41 | int sysctl_auto_assign_helper; | 48 | int sysctl_auto_assign_helper; |
42 | bool auto_assign_helper_warned; | 49 | bool auto_assign_helper_warned; |
50 | struct nf_ip_net nf_ct_proto; | ||
43 | #ifdef CONFIG_SYSCTL | 51 | #ifdef CONFIG_SYSCTL |
44 | struct ctl_table_header *sysctl_header; | 52 | struct ctl_table_header *sysctl_header; |
45 | struct ctl_table_header *acct_sysctl_header; | 53 | struct ctl_table_header *acct_sysctl_header; |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 46ec515db12..0c0fb906c19 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -409,7 +409,7 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) | |||
409 | goto cleanup_udp; | 409 | goto cleanup_udp; |
410 | } | 410 | } |
411 | 411 | ||
412 | ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv4); | 412 | ret = nf_conntrack_l3proto_register(&init_net, &nf_conntrack_l3proto_ipv4); |
413 | if (ret < 0) { | 413 | if (ret < 0) { |
414 | pr_err("nf_conntrack_ipv4: can't register ipv4\n"); | 414 | pr_err("nf_conntrack_ipv4: can't register ipv4\n"); |
415 | goto cleanup_icmp; | 415 | goto cleanup_icmp; |
@@ -432,7 +432,7 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) | |||
432 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); | 432 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); |
433 | #endif | 433 | #endif |
434 | cleanup_ipv4: | 434 | cleanup_ipv4: |
435 | nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); | 435 | nf_conntrack_l3proto_unregister(&init_net, &nf_conntrack_l3proto_ipv4); |
436 | cleanup_icmp: | 436 | cleanup_icmp: |
437 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_icmp); | 437 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_icmp); |
438 | cleanup_udp: | 438 | cleanup_udp: |
@@ -451,7 +451,7 @@ static void __exit nf_conntrack_l3proto_ipv4_fini(void) | |||
451 | nf_conntrack_ipv4_compat_fini(); | 451 | nf_conntrack_ipv4_compat_fini(); |
452 | #endif | 452 | #endif |
453 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); | 453 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); |
454 | nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); | 454 | nf_conntrack_l3proto_unregister(&init_net, &nf_conntrack_l3proto_ipv4); |
455 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_icmp); | 455 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_icmp); |
456 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_udp4); | 456 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_udp4); |
457 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_tcp4); | 457 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_tcp4); |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 51ad9f10442..7334cbfd600 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -358,7 +358,7 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
358 | goto cleanup_udp; | 358 | goto cleanup_udp; |
359 | } | 359 | } |
360 | 360 | ||
361 | ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6); | 361 | ret = nf_conntrack_l3proto_register(&init_net, &nf_conntrack_l3proto_ipv6); |
362 | if (ret < 0) { | 362 | if (ret < 0) { |
363 | pr_err("nf_conntrack_ipv6: can't register ipv6\n"); | 363 | pr_err("nf_conntrack_ipv6: can't register ipv6\n"); |
364 | goto cleanup_icmpv6; | 364 | goto cleanup_icmpv6; |
@@ -374,7 +374,7 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
374 | return ret; | 374 | return ret; |
375 | 375 | ||
376 | cleanup_ipv6: | 376 | cleanup_ipv6: |
377 | nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); | 377 | nf_conntrack_l3proto_unregister(&init_net, &nf_conntrack_l3proto_ipv6); |
378 | cleanup_icmpv6: | 378 | cleanup_icmpv6: |
379 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_icmpv6); | 379 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_icmpv6); |
380 | cleanup_udp: | 380 | cleanup_udp: |
@@ -388,7 +388,7 @@ static void __exit nf_conntrack_l3proto_ipv6_fini(void) | |||
388 | { | 388 | { |
389 | synchronize_net(); | 389 | synchronize_net(); |
390 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); | 390 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); |
391 | nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); | 391 | nf_conntrack_l3proto_unregister(&init_net, &nf_conntrack_l3proto_ipv6); |
392 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_icmpv6); | 392 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_icmpv6); |
393 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_udp6); | 393 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_udp6); |
394 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_tcp6); | 394 | nf_conntrack_l4proto_unregister(&init_net, &nf_conntrack_l4proto_tcp6); |
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 7ee31ac0a12..a8daf0faadb 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c | |||
@@ -168,31 +168,57 @@ static int kill_l4proto(struct nf_conn *i, void *data) | |||
168 | nf_ct_l3num(i) == l4proto->l3proto; | 168 | nf_ct_l3num(i) == l4proto->l3proto; |
169 | } | 169 | } |
170 | 170 | ||
171 | static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) | 171 | static struct nf_ip_net *nf_ct_l3proto_net(struct net *net, |
172 | struct nf_conntrack_l3proto *l3proto) | ||
173 | { | ||
174 | if (l3proto->l3proto == PF_INET) | ||
175 | return &net->ct.nf_ct_proto; | ||
176 | else | ||
177 | return NULL; | ||
178 | } | ||
179 | |||
180 | static int nf_ct_l3proto_register_sysctl(struct net *net, | ||
181 | struct nf_conntrack_l3proto *l3proto) | ||
172 | { | 182 | { |
173 | int err = 0; | 183 | int err = 0; |
184 | struct nf_ip_net *in = nf_ct_l3proto_net(net, l3proto); | ||
185 | /* nf_conntrack_l3proto_ipv6 doesn't support sysctl */ | ||
186 | if (in == NULL) | ||
187 | return 0; | ||
174 | 188 | ||
175 | #ifdef CONFIG_SYSCTL | 189 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) |
176 | if (l3proto->ctl_table != NULL) { | 190 | if (in->ctl_table != NULL) { |
177 | err = nf_ct_register_sysctl(&init_net, | 191 | err = nf_ct_register_sysctl(net, |
178 | &l3proto->ctl_table_header, | 192 | &in->ctl_table_header, |
179 | l3proto->ctl_table_path, | 193 | l3proto->ctl_table_path, |
180 | l3proto->ctl_table, NULL); | 194 | in->ctl_table, |
195 | NULL); | ||
196 | if (err < 0) { | ||
197 | kfree(in->ctl_table); | ||
198 | in->ctl_table = NULL; | ||
199 | } | ||
181 | } | 200 | } |
182 | #endif | 201 | #endif |
183 | return err; | 202 | return err; |
184 | } | 203 | } |
185 | 204 | ||
186 | static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto) | 205 | static void nf_ct_l3proto_unregister_sysctl(struct net *net, |
206 | struct nf_conntrack_l3proto *l3proto) | ||
187 | { | 207 | { |
188 | #ifdef CONFIG_SYSCTL | 208 | struct nf_ip_net *in = nf_ct_l3proto_net(net, l3proto); |
189 | if (l3proto->ctl_table_header != NULL) | 209 | |
190 | nf_ct_unregister_sysctl(&l3proto->ctl_table_header, | 210 | if (in == NULL) |
191 | &l3proto->ctl_table, NULL); | 211 | return; |
212 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) | ||
213 | if (in->ctl_table_header != NULL) | ||
214 | nf_ct_unregister_sysctl(&in->ctl_table_header, | ||
215 | &in->ctl_table, | ||
216 | NULL); | ||
192 | #endif | 217 | #endif |
193 | } | 218 | } |
194 | 219 | ||
195 | int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | 220 | static int |
221 | nf_conntrack_l3proto_register_net(struct nf_conntrack_l3proto *proto) | ||
196 | { | 222 | { |
197 | int ret = 0; | 223 | int ret = 0; |
198 | struct nf_conntrack_l3proto *old; | 224 | struct nf_conntrack_l3proto *old; |
@@ -211,10 +237,6 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | |||
211 | goto out_unlock; | 237 | goto out_unlock; |
212 | } | 238 | } |
213 | 239 | ||
214 | ret = nf_ct_l3proto_register_sysctl(proto); | ||
215 | if (ret < 0) | ||
216 | goto out_unlock; | ||
217 | |||
218 | if (proto->nlattr_tuple_size) | 240 | if (proto->nlattr_tuple_size) |
219 | proto->nla_size = 3 * proto->nlattr_tuple_size(); | 241 | proto->nla_size = 3 * proto->nlattr_tuple_size(); |
220 | 242 | ||
@@ -223,13 +245,32 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | |||
223 | out_unlock: | 245 | out_unlock: |
224 | mutex_unlock(&nf_ct_proto_mutex); | 246 | mutex_unlock(&nf_ct_proto_mutex); |
225 | return ret; | 247 | return ret; |
248 | |||
226 | } | 249 | } |
227 | EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register); | ||
228 | 250 | ||
229 | void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto) | 251 | int nf_conntrack_l3proto_register(struct net *net, |
252 | struct nf_conntrack_l3proto *proto) | ||
230 | { | 253 | { |
231 | struct net *net; | 254 | int ret = 0; |
255 | |||
256 | if (net == &init_net) | ||
257 | ret = nf_conntrack_l3proto_register_net(proto); | ||
232 | 258 | ||
259 | if (ret < 0) | ||
260 | return ret; | ||
261 | |||
262 | if (proto->init_net) { | ||
263 | ret = proto->init_net(net); | ||
264 | if (ret < 0) | ||
265 | return ret; | ||
266 | } | ||
267 | return nf_ct_l3proto_register_sysctl(net, proto); | ||
268 | } | ||
269 | EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register); | ||
270 | |||
271 | static void | ||
272 | nf_conntrack_l3proto_unregister_net(struct nf_conntrack_l3proto *proto) | ||
273 | { | ||
233 | BUG_ON(proto->l3proto >= AF_MAX); | 274 | BUG_ON(proto->l3proto >= AF_MAX); |
234 | 275 | ||
235 | mutex_lock(&nf_ct_proto_mutex); | 276 | mutex_lock(&nf_ct_proto_mutex); |
@@ -238,15 +279,22 @@ void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto) | |||
238 | ) != proto); | 279 | ) != proto); |
239 | rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], | 280 | rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], |
240 | &nf_conntrack_l3proto_generic); | 281 | &nf_conntrack_l3proto_generic); |
241 | nf_ct_l3proto_unregister_sysctl(proto); | ||
242 | mutex_unlock(&nf_ct_proto_mutex); | 282 | mutex_unlock(&nf_ct_proto_mutex); |
243 | 283 | ||
244 | synchronize_rcu(); | 284 | synchronize_rcu(); |
285 | } | ||
286 | |||
287 | void nf_conntrack_l3proto_unregister(struct net *net, | ||
288 | struct nf_conntrack_l3proto *proto) | ||
289 | { | ||
290 | if (net == &init_net) | ||
291 | nf_conntrack_l3proto_unregister_net(proto); | ||
292 | |||
293 | nf_ct_l3proto_unregister_sysctl(net, proto); | ||
245 | 294 | ||
246 | /* Remove all contrack entries for this protocol */ | 295 | /* Remove all contrack entries for this protocol */ |
247 | rtnl_lock(); | 296 | rtnl_lock(); |
248 | for_each_net(net) | 297 | nf_ct_iterate_cleanup(net, kill_l3proto, proto); |
249 | nf_ct_iterate_cleanup(net, kill_l3proto, proto); | ||
250 | rtnl_unlock(); | 298 | rtnl_unlock(); |
251 | } | 299 | } |
252 | EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister); | 300 | EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister); |