diff options
author | Gao feng <gaofeng@cn.fujitsu.com> | 2012-06-21 00:36:41 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-06-27 12:46:00 -0400 |
commit | fa34fff5e69cc56eecf26754c9b57403899ebd0d (patch) | |
tree | 9d6500f577616a9a44081fe271ee94c6d5b566d3 | |
parent | f28997e27a03abc679f13824a0574b09112eea37 (diff) |
netfilter: nf_conntrack: use l4proto->users as refcount for per-net data
Currently, nf_proto_net's l4proto->users meaning is quite confusing
since it depends on the compilation tweaks.
To resolve this, we cleanup this code to regard it as the refcount
for l4proto's per-net data, since there may be two l4protos use the
same per-net data.
Thus, we increment pn->users when nf_conntrack_l4proto_register
successfully, and decrement it for nf_conntrack_l4_unregister case.
The users refcnt is not required form layer 3 protocol trackers.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | net/netfilter/nf_conntrack_proto.c | 76 |
1 files changed, 46 insertions, 30 deletions
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 9d6b6ab193a9..63612e6d7238 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c | |||
@@ -39,16 +39,13 @@ static int | |||
39 | nf_ct_register_sysctl(struct net *net, | 39 | nf_ct_register_sysctl(struct net *net, |
40 | struct ctl_table_header **header, | 40 | struct ctl_table_header **header, |
41 | const char *path, | 41 | const char *path, |
42 | struct ctl_table *table, | 42 | struct ctl_table *table) |
43 | unsigned int *users) | ||
44 | { | 43 | { |
45 | if (*header == NULL) { | 44 | if (*header == NULL) { |
46 | *header = register_net_sysctl(net, path, table); | 45 | *header = register_net_sysctl(net, path, table); |
47 | if (*header == NULL) | 46 | if (*header == NULL) |
48 | return -ENOMEM; | 47 | return -ENOMEM; |
49 | } | 48 | } |
50 | if (users != NULL) | ||
51 | (*users)++; | ||
52 | 49 | ||
53 | return 0; | 50 | return 0; |
54 | } | 51 | } |
@@ -56,9 +53,9 @@ nf_ct_register_sysctl(struct net *net, | |||
56 | static void | 53 | static void |
57 | nf_ct_unregister_sysctl(struct ctl_table_header **header, | 54 | nf_ct_unregister_sysctl(struct ctl_table_header **header, |
58 | struct ctl_table **table, | 55 | struct ctl_table **table, |
59 | unsigned int *users) | 56 | unsigned int users) |
60 | { | 57 | { |
61 | if (users != NULL && --*users > 0) | 58 | if (users > 0) |
62 | return; | 59 | return; |
63 | 60 | ||
64 | unregister_net_sysctl_table(*header); | 61 | unregister_net_sysctl_table(*header); |
@@ -191,8 +188,7 @@ static int nf_ct_l3proto_register_sysctl(struct net *net, | |||
191 | err = nf_ct_register_sysctl(net, | 188 | err = nf_ct_register_sysctl(net, |
192 | &in->ctl_table_header, | 189 | &in->ctl_table_header, |
193 | l3proto->ctl_table_path, | 190 | l3proto->ctl_table_path, |
194 | in->ctl_table, | 191 | in->ctl_table); |
195 | NULL); | ||
196 | if (err < 0) { | 192 | if (err < 0) { |
197 | kfree(in->ctl_table); | 193 | kfree(in->ctl_table); |
198 | in->ctl_table = NULL; | 194 | in->ctl_table = NULL; |
@@ -213,7 +209,7 @@ static void nf_ct_l3proto_unregister_sysctl(struct net *net, | |||
213 | if (in->ctl_table_header != NULL) | 209 | if (in->ctl_table_header != NULL) |
214 | nf_ct_unregister_sysctl(&in->ctl_table_header, | 210 | nf_ct_unregister_sysctl(&in->ctl_table_header, |
215 | &in->ctl_table, | 211 | &in->ctl_table, |
216 | NULL); | 212 | 0); |
217 | #endif | 213 | #endif |
218 | } | 214 | } |
219 | 215 | ||
@@ -329,20 +325,17 @@ static struct nf_proto_net *nf_ct_l4proto_net(struct net *net, | |||
329 | 325 | ||
330 | static | 326 | static |
331 | int nf_ct_l4proto_register_sysctl(struct net *net, | 327 | int nf_ct_l4proto_register_sysctl(struct net *net, |
328 | struct nf_proto_net *pn, | ||
332 | struct nf_conntrack_l4proto *l4proto) | 329 | struct nf_conntrack_l4proto *l4proto) |
333 | { | 330 | { |
334 | int err = 0; | 331 | int err = 0; |
335 | struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto); | ||
336 | if (pn == NULL) | ||
337 | return 0; | ||
338 | 332 | ||
339 | #ifdef CONFIG_SYSCTL | 333 | #ifdef CONFIG_SYSCTL |
340 | if (pn->ctl_table != NULL) { | 334 | if (pn->ctl_table != NULL) { |
341 | err = nf_ct_register_sysctl(net, | 335 | err = nf_ct_register_sysctl(net, |
342 | &pn->ctl_table_header, | 336 | &pn->ctl_table_header, |
343 | "net/netfilter", | 337 | "net/netfilter", |
344 | pn->ctl_table, | 338 | pn->ctl_table); |
345 | &pn->users); | ||
346 | if (err < 0) { | 339 | if (err < 0) { |
347 | if (!pn->users) { | 340 | if (!pn->users) { |
348 | kfree(pn->ctl_table); | 341 | kfree(pn->ctl_table); |
@@ -356,15 +349,14 @@ int nf_ct_l4proto_register_sysctl(struct net *net, | |||
356 | err = nf_ct_register_sysctl(net, | 349 | err = nf_ct_register_sysctl(net, |
357 | &pn->ctl_compat_header, | 350 | &pn->ctl_compat_header, |
358 | "net/ipv4/netfilter", | 351 | "net/ipv4/netfilter", |
359 | pn->ctl_compat_table, | 352 | pn->ctl_compat_table); |
360 | NULL); | ||
361 | if (err == 0) | 353 | if (err == 0) |
362 | goto out; | 354 | goto out; |
363 | 355 | ||
364 | nf_ct_kfree_compat_sysctl_table(pn); | 356 | nf_ct_kfree_compat_sysctl_table(pn); |
365 | nf_ct_unregister_sysctl(&pn->ctl_table_header, | 357 | nf_ct_unregister_sysctl(&pn->ctl_table_header, |
366 | &pn->ctl_table, | 358 | &pn->ctl_table, |
367 | &pn->users); | 359 | pn->users); |
368 | } | 360 | } |
369 | #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ | 361 | #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ |
370 | out: | 362 | out: |
@@ -374,25 +366,21 @@ out: | |||
374 | 366 | ||
375 | static | 367 | static |
376 | void nf_ct_l4proto_unregister_sysctl(struct net *net, | 368 | void nf_ct_l4proto_unregister_sysctl(struct net *net, |
369 | struct nf_proto_net *pn, | ||
377 | struct nf_conntrack_l4proto *l4proto) | 370 | struct nf_conntrack_l4proto *l4proto) |
378 | { | 371 | { |
379 | struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto); | ||
380 | if (pn == NULL) | ||
381 | return; | ||
382 | #ifdef CONFIG_SYSCTL | 372 | #ifdef CONFIG_SYSCTL |
383 | if (pn->ctl_table_header != NULL) | 373 | if (pn->ctl_table_header != NULL) |
384 | nf_ct_unregister_sysctl(&pn->ctl_table_header, | 374 | nf_ct_unregister_sysctl(&pn->ctl_table_header, |
385 | &pn->ctl_table, | 375 | &pn->ctl_table, |
386 | &pn->users); | 376 | pn->users); |
387 | 377 | ||
388 | #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT | 378 | #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT |
389 | if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_header != NULL) | 379 | if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_header != NULL) |
390 | nf_ct_unregister_sysctl(&pn->ctl_compat_header, | 380 | nf_ct_unregister_sysctl(&pn->ctl_compat_header, |
391 | &pn->ctl_compat_table, | 381 | &pn->ctl_compat_table, |
392 | NULL); | 382 | 0); |
393 | #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ | 383 | #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ |
394 | #else | ||
395 | pn->users--; | ||
396 | #endif /* CONFIG_SYSCTL */ | 384 | #endif /* CONFIG_SYSCTL */ |
397 | } | 385 | } |
398 | 386 | ||
@@ -458,23 +446,32 @@ int nf_conntrack_l4proto_register(struct net *net, | |||
458 | struct nf_conntrack_l4proto *l4proto) | 446 | struct nf_conntrack_l4proto *l4proto) |
459 | { | 447 | { |
460 | int ret = 0; | 448 | int ret = 0; |
449 | struct nf_proto_net *pn = NULL; | ||
461 | 450 | ||
462 | if (l4proto->init_net) { | 451 | if (l4proto->init_net) { |
463 | ret = l4proto->init_net(net, l4proto->l3proto); | 452 | ret = l4proto->init_net(net, l4proto->l3proto); |
464 | if (ret < 0) | 453 | if (ret < 0) |
465 | return ret; | 454 | goto out; |
466 | } | 455 | } |
467 | 456 | ||
468 | ret = nf_ct_l4proto_register_sysctl(net, l4proto); | 457 | pn = nf_ct_l4proto_net(net, l4proto); |
458 | if (pn == NULL) | ||
459 | goto out; | ||
460 | |||
461 | ret = nf_ct_l4proto_register_sysctl(net, pn, l4proto); | ||
469 | if (ret < 0) | 462 | if (ret < 0) |
470 | return ret; | 463 | goto out; |
471 | 464 | ||
472 | if (net == &init_net) { | 465 | if (net == &init_net) { |
473 | ret = nf_conntrack_l4proto_register_net(l4proto); | 466 | ret = nf_conntrack_l4proto_register_net(l4proto); |
474 | if (ret < 0) | 467 | if (ret < 0) { |
475 | nf_ct_l4proto_unregister_sysctl(net, l4proto); | 468 | nf_ct_l4proto_unregister_sysctl(net, pn, l4proto); |
469 | goto out; | ||
470 | } | ||
476 | } | 471 | } |
477 | 472 | ||
473 | pn->users++; | ||
474 | out: | ||
478 | return ret; | 475 | return ret; |
479 | } | 476 | } |
480 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register); | 477 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register); |
@@ -499,10 +496,18 @@ nf_conntrack_l4proto_unregister_net(struct nf_conntrack_l4proto *l4proto) | |||
499 | void nf_conntrack_l4proto_unregister(struct net *net, | 496 | void nf_conntrack_l4proto_unregister(struct net *net, |
500 | struct nf_conntrack_l4proto *l4proto) | 497 | struct nf_conntrack_l4proto *l4proto) |
501 | { | 498 | { |
499 | struct nf_proto_net *pn = NULL; | ||
500 | |||
502 | if (net == &init_net) | 501 | if (net == &init_net) |
503 | nf_conntrack_l4proto_unregister_net(l4proto); | 502 | nf_conntrack_l4proto_unregister_net(l4proto); |
504 | 503 | ||
505 | nf_ct_l4proto_unregister_sysctl(net, l4proto); | 504 | pn = nf_ct_l4proto_net(net, l4proto); |
505 | if (pn == NULL) | ||
506 | return; | ||
507 | |||
508 | pn->users--; | ||
509 | nf_ct_l4proto_unregister_sysctl(net, pn, l4proto); | ||
510 | |||
506 | /* Remove all contrack entries for this protocol */ | 511 | /* Remove all contrack entries for this protocol */ |
507 | rtnl_lock(); | 512 | rtnl_lock(); |
508 | nf_ct_iterate_cleanup(net, kill_l4proto, l4proto); | 513 | nf_ct_iterate_cleanup(net, kill_l4proto, l4proto); |
@@ -514,11 +519,15 @@ int nf_conntrack_proto_init(struct net *net) | |||
514 | { | 519 | { |
515 | unsigned int i; | 520 | unsigned int i; |
516 | int err; | 521 | int err; |
522 | struct nf_proto_net *pn = nf_ct_l4proto_net(net, | ||
523 | &nf_conntrack_l4proto_generic); | ||
524 | |||
517 | err = nf_conntrack_l4proto_generic.init_net(net, | 525 | err = nf_conntrack_l4proto_generic.init_net(net, |
518 | nf_conntrack_l4proto_generic.l3proto); | 526 | nf_conntrack_l4proto_generic.l3proto); |
519 | if (err < 0) | 527 | if (err < 0) |
520 | return err; | 528 | return err; |
521 | err = nf_ct_l4proto_register_sysctl(net, | 529 | err = nf_ct_l4proto_register_sysctl(net, |
530 | pn, | ||
522 | &nf_conntrack_l4proto_generic); | 531 | &nf_conntrack_l4proto_generic); |
523 | if (err < 0) | 532 | if (err < 0) |
524 | return err; | 533 | return err; |
@@ -528,13 +537,20 @@ int nf_conntrack_proto_init(struct net *net) | |||
528 | rcu_assign_pointer(nf_ct_l3protos[i], | 537 | rcu_assign_pointer(nf_ct_l3protos[i], |
529 | &nf_conntrack_l3proto_generic); | 538 | &nf_conntrack_l3proto_generic); |
530 | } | 539 | } |
540 | |||
541 | pn->users++; | ||
531 | return 0; | 542 | return 0; |
532 | } | 543 | } |
533 | 544 | ||
534 | void nf_conntrack_proto_fini(struct net *net) | 545 | void nf_conntrack_proto_fini(struct net *net) |
535 | { | 546 | { |
536 | unsigned int i; | 547 | unsigned int i; |
548 | struct nf_proto_net *pn = nf_ct_l4proto_net(net, | ||
549 | &nf_conntrack_l4proto_generic); | ||
550 | |||
551 | pn->users--; | ||
537 | nf_ct_l4proto_unregister_sysctl(net, | 552 | nf_ct_l4proto_unregister_sysctl(net, |
553 | pn, | ||
538 | &nf_conntrack_l4proto_generic); | 554 | &nf_conntrack_l4proto_generic); |
539 | if (net == &init_net) { | 555 | if (net == &init_net) { |
540 | /* free l3proto protocol tables */ | 556 | /* free l3proto protocol tables */ |