diff options
author | Gao feng <gaofeng@cn.fujitsu.com> | 2013-01-21 17:10:24 -0500 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-01-23 06:53:35 -0500 |
commit | f94161c1bbdf7af11729cf106b4452f2432448e0 (patch) | |
tree | c1f76b19cf4daf088421e0f75fd0fff6371c4a9c /net/netfilter | |
parent | 8a454ab95e5ccbffd04363e9c028f60739bc3fa4 (diff) |
netfilter: nf_conntrack: move initialization out of pernet operations
nf_conntrack initialization and cleanup codes happens in pernet
operations function. This task should be done in module_init/exit.
We can't use init_net to identify if it's the right time to initialize
or cleanup since we cannot make assumption on the order netns are
created/destroyed.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 96 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_standalone.c | 56 |
2 files changed, 71 insertions, 81 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 85aa4b7149c5..fb3e514c461e 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -1334,8 +1334,14 @@ static int untrack_refs(void) | |||
1334 | return cnt; | 1334 | return cnt; |
1335 | } | 1335 | } |
1336 | 1336 | ||
1337 | static void nf_conntrack_cleanup_init_net(void) | 1337 | void nf_conntrack_cleanup_start(void) |
1338 | { | 1338 | { |
1339 | RCU_INIT_POINTER(ip_ct_attach, NULL); | ||
1340 | } | ||
1341 | |||
1342 | void nf_conntrack_cleanup_end(void) | ||
1343 | { | ||
1344 | RCU_INIT_POINTER(nf_ct_destroy, NULL); | ||
1339 | while (untrack_refs() > 0) | 1345 | while (untrack_refs() > 0) |
1340 | schedule(); | 1346 | schedule(); |
1341 | 1347 | ||
@@ -1344,8 +1350,18 @@ static void nf_conntrack_cleanup_init_net(void) | |||
1344 | #endif | 1350 | #endif |
1345 | } | 1351 | } |
1346 | 1352 | ||
1347 | static void nf_conntrack_cleanup_net(struct net *net) | 1353 | /* |
1354 | * Mishearing the voices in his head, our hero wonders how he's | ||
1355 | * supposed to kill the mall. | ||
1356 | */ | ||
1357 | void nf_conntrack_cleanup_net(struct net *net) | ||
1348 | { | 1358 | { |
1359 | /* | ||
1360 | * This makes sure all current packets have passed through | ||
1361 | * netfilter framework. Roll on, two-stage module | ||
1362 | * delete... | ||
1363 | */ | ||
1364 | synchronize_net(); | ||
1349 | i_see_dead_people: | 1365 | i_see_dead_people: |
1350 | nf_ct_iterate_cleanup(net, kill_all, NULL); | 1366 | nf_ct_iterate_cleanup(net, kill_all, NULL); |
1351 | nf_ct_release_dying_list(net); | 1367 | nf_ct_release_dying_list(net); |
@@ -1355,6 +1371,7 @@ static void nf_conntrack_cleanup_net(struct net *net) | |||
1355 | } | 1371 | } |
1356 | 1372 | ||
1357 | nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); | 1373 | nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); |
1374 | nf_conntrack_proto_fini(net); | ||
1358 | nf_conntrack_labels_fini(net); | 1375 | nf_conntrack_labels_fini(net); |
1359 | nf_conntrack_helper_fini(net); | 1376 | nf_conntrack_helper_fini(net); |
1360 | nf_conntrack_timeout_fini(net); | 1377 | nf_conntrack_timeout_fini(net); |
@@ -1367,27 +1384,6 @@ static void nf_conntrack_cleanup_net(struct net *net) | |||
1367 | free_percpu(net->ct.stat); | 1384 | free_percpu(net->ct.stat); |
1368 | } | 1385 | } |
1369 | 1386 | ||
1370 | /* Mishearing the voices in his head, our hero wonders how he's | ||
1371 | supposed to kill the mall. */ | ||
1372 | void nf_conntrack_cleanup(struct net *net) | ||
1373 | { | ||
1374 | if (net_eq(net, &init_net)) | ||
1375 | RCU_INIT_POINTER(ip_ct_attach, NULL); | ||
1376 | |||
1377 | /* This makes sure all current packets have passed through | ||
1378 | netfilter framework. Roll on, two-stage module | ||
1379 | delete... */ | ||
1380 | synchronize_net(); | ||
1381 | nf_conntrack_proto_fini(net); | ||
1382 | nf_conntrack_cleanup_net(net); | ||
1383 | } | ||
1384 | |||
1385 | void nf_conntrack_cleanup_end(void) | ||
1386 | { | ||
1387 | RCU_INIT_POINTER(nf_ct_destroy, NULL); | ||
1388 | nf_conntrack_cleanup_init_net(); | ||
1389 | } | ||
1390 | |||
1391 | void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) | 1387 | void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) |
1392 | { | 1388 | { |
1393 | struct hlist_nulls_head *hash; | 1389 | struct hlist_nulls_head *hash; |
@@ -1478,7 +1474,7 @@ void nf_ct_untracked_status_or(unsigned long bits) | |||
1478 | } | 1474 | } |
1479 | EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or); | 1475 | EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or); |
1480 | 1476 | ||
1481 | static int nf_conntrack_init_init_net(void) | 1477 | int nf_conntrack_init_start(void) |
1482 | { | 1478 | { |
1483 | int max_factor = 8; | 1479 | int max_factor = 8; |
1484 | int ret, cpu; | 1480 | int ret, cpu; |
@@ -1526,6 +1522,16 @@ err_extend: | |||
1526 | return ret; | 1522 | return ret; |
1527 | } | 1523 | } |
1528 | 1524 | ||
1525 | void nf_conntrack_init_end(void) | ||
1526 | { | ||
1527 | /* For use by REJECT target */ | ||
1528 | RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach); | ||
1529 | RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack); | ||
1530 | |||
1531 | /* Howto get NAT offsets */ | ||
1532 | RCU_INIT_POINTER(nf_ct_nat_offset, NULL); | ||
1533 | } | ||
1534 | |||
1529 | /* | 1535 | /* |
1530 | * We need to use special "null" values, not used in hash table | 1536 | * We need to use special "null" values, not used in hash table |
1531 | */ | 1537 | */ |
@@ -1533,7 +1539,7 @@ err_extend: | |||
1533 | #define DYING_NULLS_VAL ((1<<30)+1) | 1539 | #define DYING_NULLS_VAL ((1<<30)+1) |
1534 | #define TEMPLATE_NULLS_VAL ((1<<30)+2) | 1540 | #define TEMPLATE_NULLS_VAL ((1<<30)+2) |
1535 | 1541 | ||
1536 | static int nf_conntrack_init_net(struct net *net) | 1542 | int nf_conntrack_init_net(struct net *net) |
1537 | { | 1543 | { |
1538 | int ret; | 1544 | int ret; |
1539 | 1545 | ||
@@ -1592,8 +1598,13 @@ static int nf_conntrack_init_net(struct net *net) | |||
1592 | if (ret < 0) | 1598 | if (ret < 0) |
1593 | goto err_labels; | 1599 | goto err_labels; |
1594 | 1600 | ||
1601 | ret = nf_conntrack_proto_init(net); | ||
1602 | if (ret < 0) | ||
1603 | goto err_proto; | ||
1595 | return 0; | 1604 | return 0; |
1596 | 1605 | ||
1606 | err_proto: | ||
1607 | nf_conntrack_labels_fini(net); | ||
1597 | err_labels: | 1608 | err_labels: |
1598 | nf_conntrack_helper_fini(net); | 1609 | nf_conntrack_helper_fini(net); |
1599 | err_helper: | 1610 | err_helper: |
@@ -1622,38 +1633,3 @@ s16 (*nf_ct_nat_offset)(const struct nf_conn *ct, | |||
1622 | enum ip_conntrack_dir dir, | 1633 | enum ip_conntrack_dir dir, |
1623 | u32 seq); | 1634 | u32 seq); |
1624 | EXPORT_SYMBOL_GPL(nf_ct_nat_offset); | 1635 | EXPORT_SYMBOL_GPL(nf_ct_nat_offset); |
1625 | |||
1626 | int nf_conntrack_init(struct net *net) | ||
1627 | { | ||
1628 | int ret; | ||
1629 | |||
1630 | if (net_eq(net, &init_net)) { | ||
1631 | ret = nf_conntrack_init_init_net(); | ||
1632 | if (ret < 0) | ||
1633 | goto out_init_net; | ||
1634 | } | ||
1635 | ret = nf_conntrack_proto_init(net); | ||
1636 | if (ret < 0) | ||
1637 | goto out_proto; | ||
1638 | ret = nf_conntrack_init_net(net); | ||
1639 | if (ret < 0) | ||
1640 | goto out_net; | ||
1641 | |||
1642 | if (net_eq(net, &init_net)) { | ||
1643 | /* For use by REJECT target */ | ||
1644 | RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach); | ||
1645 | RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack); | ||
1646 | |||
1647 | /* Howto get NAT offsets */ | ||
1648 | RCU_INIT_POINTER(nf_ct_nat_offset, NULL); | ||
1649 | } | ||
1650 | return 0; | ||
1651 | |||
1652 | out_net: | ||
1653 | nf_conntrack_proto_fini(net); | ||
1654 | out_proto: | ||
1655 | if (net_eq(net, &init_net)) | ||
1656 | nf_conntrack_cleanup_init_net(); | ||
1657 | out_init_net: | ||
1658 | return ret; | ||
1659 | } | ||
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index e7185c684816..725bf04a2fb9 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c | |||
@@ -472,13 +472,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net) | |||
472 | { | 472 | { |
473 | struct ctl_table *table; | 473 | struct ctl_table *table; |
474 | 474 | ||
475 | if (net_eq(net, &init_net)) { | ||
476 | nf_ct_netfilter_header = | ||
477 | register_net_sysctl(&init_net, "net", nf_ct_netfilter_table); | ||
478 | if (!nf_ct_netfilter_header) | ||
479 | goto out; | ||
480 | } | ||
481 | |||
482 | table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table), | 475 | table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table), |
483 | GFP_KERNEL); | 476 | GFP_KERNEL); |
484 | if (!table) | 477 | if (!table) |
@@ -502,10 +495,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net) | |||
502 | out_unregister_netfilter: | 495 | out_unregister_netfilter: |
503 | kfree(table); | 496 | kfree(table); |
504 | out_kmemdup: | 497 | out_kmemdup: |
505 | if (net_eq(net, &init_net)) | ||
506 | unregister_net_sysctl_table(nf_ct_netfilter_header); | ||
507 | out: | ||
508 | printk(KERN_ERR "nf_conntrack: can't register to sysctl.\n"); | ||
509 | return -ENOMEM; | 498 | return -ENOMEM; |
510 | } | 499 | } |
511 | 500 | ||
@@ -513,8 +502,6 @@ static void nf_conntrack_standalone_fini_sysctl(struct net *net) | |||
513 | { | 502 | { |
514 | struct ctl_table *table; | 503 | struct ctl_table *table; |
515 | 504 | ||
516 | if (net_eq(net, &init_net)) | ||
517 | unregister_net_sysctl_table(nf_ct_netfilter_header); | ||
518 | table = net->ct.sysctl_header->ctl_table_arg; | 505 | table = net->ct.sysctl_header->ctl_table_arg; |
519 | unregister_net_sysctl_table(net->ct.sysctl_header); | 506 | unregister_net_sysctl_table(net->ct.sysctl_header); |
520 | kfree(table); | 507 | kfree(table); |
@@ -530,51 +517,78 @@ static void nf_conntrack_standalone_fini_sysctl(struct net *net) | |||
530 | } | 517 | } |
531 | #endif /* CONFIG_SYSCTL */ | 518 | #endif /* CONFIG_SYSCTL */ |
532 | 519 | ||
533 | static int nf_conntrack_net_init(struct net *net) | 520 | static int nf_conntrack_pernet_init(struct net *net) |
534 | { | 521 | { |
535 | int ret; | 522 | int ret; |
536 | 523 | ||
537 | ret = nf_conntrack_init(net); | 524 | ret = nf_conntrack_init_net(net); |
538 | if (ret < 0) | 525 | if (ret < 0) |
539 | goto out_init; | 526 | goto out_init; |
527 | |||
540 | ret = nf_conntrack_standalone_init_proc(net); | 528 | ret = nf_conntrack_standalone_init_proc(net); |
541 | if (ret < 0) | 529 | if (ret < 0) |
542 | goto out_proc; | 530 | goto out_proc; |
531 | |||
543 | net->ct.sysctl_checksum = 1; | 532 | net->ct.sysctl_checksum = 1; |
544 | net->ct.sysctl_log_invalid = 0; | 533 | net->ct.sysctl_log_invalid = 0; |
545 | ret = nf_conntrack_standalone_init_sysctl(net); | 534 | ret = nf_conntrack_standalone_init_sysctl(net); |
546 | if (ret < 0) | 535 | if (ret < 0) |
547 | goto out_sysctl; | 536 | goto out_sysctl; |
537 | |||
548 | return 0; | 538 | return 0; |
549 | 539 | ||
550 | out_sysctl: | 540 | out_sysctl: |
551 | nf_conntrack_standalone_fini_proc(net); | 541 | nf_conntrack_standalone_fini_proc(net); |
552 | out_proc: | 542 | out_proc: |
553 | nf_conntrack_cleanup(net); | 543 | nf_conntrack_cleanup_net(net); |
554 | out_init: | 544 | out_init: |
555 | return ret; | 545 | return ret; |
556 | } | 546 | } |
557 | 547 | ||
558 | static void nf_conntrack_net_exit(struct net *net) | 548 | static void nf_conntrack_pernet_exit(struct net *net) |
559 | { | 549 | { |
560 | nf_conntrack_standalone_fini_sysctl(net); | 550 | nf_conntrack_standalone_fini_sysctl(net); |
561 | nf_conntrack_standalone_fini_proc(net); | 551 | nf_conntrack_standalone_fini_proc(net); |
562 | nf_conntrack_cleanup(net); | 552 | nf_conntrack_cleanup_net(net); |
563 | } | 553 | } |
564 | 554 | ||
565 | static struct pernet_operations nf_conntrack_net_ops = { | 555 | static struct pernet_operations nf_conntrack_net_ops = { |
566 | .init = nf_conntrack_net_init, | 556 | .init = nf_conntrack_pernet_init, |
567 | .exit = nf_conntrack_net_exit, | 557 | .exit = nf_conntrack_pernet_exit, |
568 | }; | 558 | }; |
569 | 559 | ||
570 | static int __init nf_conntrack_standalone_init(void) | 560 | static int __init nf_conntrack_standalone_init(void) |
571 | { | 561 | { |
572 | return register_pernet_subsys(&nf_conntrack_net_ops); | 562 | int ret = nf_conntrack_init_start(); |
563 | if (ret < 0) | ||
564 | goto out_start; | ||
565 | |||
566 | nf_ct_netfilter_header = | ||
567 | register_net_sysctl(&init_net, "net", nf_ct_netfilter_table); | ||
568 | if (!nf_ct_netfilter_header) | ||
569 | goto out_sysctl; | ||
570 | |||
571 | ret = register_pernet_subsys(&nf_conntrack_net_ops); | ||
572 | if (ret < 0) | ||
573 | goto out_pernet; | ||
574 | |||
575 | nf_conntrack_init_end(); | ||
576 | return 0; | ||
577 | |||
578 | out_pernet: | ||
579 | unregister_net_sysctl_table(nf_ct_netfilter_header); | ||
580 | out_sysctl: | ||
581 | pr_err("nf_conntrack: can't register to sysctl.\n"); | ||
582 | nf_conntrack_cleanup_end(); | ||
583 | out_start: | ||
584 | return ret; | ||
573 | } | 585 | } |
574 | 586 | ||
575 | static void __exit nf_conntrack_standalone_fini(void) | 587 | static void __exit nf_conntrack_standalone_fini(void) |
576 | { | 588 | { |
589 | nf_conntrack_cleanup_start(); | ||
577 | unregister_pernet_subsys(&nf_conntrack_net_ops); | 590 | unregister_pernet_subsys(&nf_conntrack_net_ops); |
591 | unregister_net_sysctl_table(nf_ct_netfilter_header); | ||
578 | nf_conntrack_cleanup_end(); | 592 | nf_conntrack_cleanup_end(); |
579 | } | 593 | } |
580 | 594 | ||