aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGao feng <gaofeng@cn.fujitsu.com>2012-06-21 00:36:41 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2012-06-27 12:46:00 -0400
commitfa34fff5e69cc56eecf26754c9b57403899ebd0d (patch)
tree9d6500f577616a9a44081fe271ee94c6d5b566d3
parentf28997e27a03abc679f13824a0574b09112eea37 (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.c76
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
39nf_ct_register_sysctl(struct net *net, 39nf_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,
56static void 53static void
57nf_ct_unregister_sysctl(struct ctl_table_header **header, 54nf_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
330static 326static
331int nf_ct_l4proto_register_sysctl(struct net *net, 327int 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 */
370out: 362out:
@@ -374,25 +366,21 @@ out:
374 366
375static 367static
376void nf_ct_l4proto_unregister_sysctl(struct net *net, 368void 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++;
474out:
478 return ret; 475 return ret;
479} 476}
480EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register); 477EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
@@ -499,10 +496,18 @@ nf_conntrack_l4proto_unregister_net(struct nf_conntrack_l4proto *l4proto)
499void nf_conntrack_l4proto_unregister(struct net *net, 496void 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
534void nf_conntrack_proto_fini(struct net *net) 545void 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 */