Commit f94161c1bbdf7af11729cf106b4452f2432448e0
Committed by
Pablo Neira Ayuso
1 parent
8a454ab95e
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>
Showing 3 changed files with 77 additions and 83 deletions Side-by-side Diff
include/net/netfilter/nf_conntrack_core.h
... | ... | @@ -25,12 +25,16 @@ |
25 | 25 | unsigned int hooknum, |
26 | 26 | struct sk_buff *skb); |
27 | 27 | |
28 | -extern int nf_conntrack_init(struct net *net); | |
29 | -extern void nf_conntrack_cleanup(struct net *net); | |
28 | +extern int nf_conntrack_init_net(struct net *net); | |
29 | +extern void nf_conntrack_cleanup_net(struct net *net); | |
30 | 30 | |
31 | 31 | extern int nf_conntrack_proto_init(struct net *net); |
32 | 32 | extern void nf_conntrack_proto_fini(struct net *net); |
33 | 33 | |
34 | +extern int nf_conntrack_init_start(void); | |
35 | +extern void nf_conntrack_cleanup_start(void); | |
36 | + | |
37 | +extern void nf_conntrack_init_end(void); | |
34 | 38 | extern void nf_conntrack_cleanup_end(void); |
35 | 39 | |
36 | 40 | extern bool |
net/netfilter/nf_conntrack_core.c
... | ... | @@ -1334,8 +1334,14 @@ |
1334 | 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 | 1345 | while (untrack_refs() > 0) |
1340 | 1346 | schedule(); |
1341 | 1347 | |
1342 | 1348 | |
... | ... | @@ -1344,8 +1350,18 @@ |
1344 | 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 | 1365 | i_see_dead_people: |
1350 | 1366 | nf_ct_iterate_cleanup(net, kill_all, NULL); |
1351 | 1367 | nf_ct_release_dying_list(net); |
... | ... | @@ -1355,6 +1371,7 @@ |
1355 | 1371 | } |
1356 | 1372 | |
1357 | 1373 | nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); |
1374 | + nf_conntrack_proto_fini(net); | |
1358 | 1375 | nf_conntrack_labels_fini(net); |
1359 | 1376 | nf_conntrack_helper_fini(net); |
1360 | 1377 | nf_conntrack_timeout_fini(net); |
... | ... | @@ -1367,27 +1384,6 @@ |
1367 | 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 | 1387 | void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) |
1392 | 1388 | { |
1393 | 1389 | struct hlist_nulls_head *hash; |
... | ... | @@ -1478,7 +1474,7 @@ |
1478 | 1474 | } |
1479 | 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 | 1479 | int max_factor = 8; |
1484 | 1480 | int ret, cpu; |
... | ... | @@ -1526,6 +1522,16 @@ |
1526 | 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 | 1536 | * We need to use special "null" values, not used in hash table |
1531 | 1537 | */ |
... | ... | @@ -1533,7 +1539,7 @@ |
1533 | 1539 | #define DYING_NULLS_VAL ((1<<30)+1) |
1534 | 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 | 1544 | int ret; |
1539 | 1545 | |
1540 | 1546 | |
... | ... | @@ -1592,8 +1598,13 @@ |
1592 | 1598 | if (ret < 0) |
1593 | 1599 | goto err_labels; |
1594 | 1600 | |
1601 | + ret = nf_conntrack_proto_init(net); | |
1602 | + if (ret < 0) | |
1603 | + goto err_proto; | |
1595 | 1604 | return 0; |
1596 | 1605 | |
1606 | +err_proto: | |
1607 | + nf_conntrack_labels_fini(net); | |
1597 | 1608 | err_labels: |
1598 | 1609 | nf_conntrack_helper_fini(net); |
1599 | 1610 | err_helper: |
... | ... | @@ -1622,39 +1633,4 @@ |
1622 | 1633 | enum ip_conntrack_dir dir, |
1623 | 1634 | u32 seq); |
1624 | 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 | -} |
net/netfilter/nf_conntrack_standalone.c
... | ... | @@ -472,13 +472,6 @@ |
472 | 472 | { |
473 | 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 | 475 | table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table), |
483 | 476 | GFP_KERNEL); |
484 | 477 | if (!table) |
... | ... | @@ -502,10 +495,6 @@ |
502 | 495 | out_unregister_netfilter: |
503 | 496 | kfree(table); |
504 | 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 | 498 | return -ENOMEM; |
510 | 499 | } |
511 | 500 | |
... | ... | @@ -513,8 +502,6 @@ |
513 | 502 | { |
514 | 503 | struct ctl_table *table; |
515 | 504 | |
516 | - if (net_eq(net, &init_net)) | |
517 | - unregister_net_sysctl_table(nf_ct_netfilter_header); | |
518 | 505 | table = net->ct.sysctl_header->ctl_table_arg; |
519 | 506 | unregister_net_sysctl_table(net->ct.sysctl_header); |
520 | 507 | kfree(table); |
521 | 508 | |
522 | 509 | |
523 | 510 | |
524 | 511 | |
525 | 512 | |
526 | 513 | |
527 | 514 | |
528 | 515 | |
529 | 516 | |
530 | 517 | |
531 | 518 | |
... | ... | @@ -530,51 +517,78 @@ |
530 | 517 | } |
531 | 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 | 522 | int ret; |
536 | 523 | |
537 | - ret = nf_conntrack_init(net); | |
524 | + ret = nf_conntrack_init_net(net); | |
538 | 525 | if (ret < 0) |
539 | 526 | goto out_init; |
527 | + | |
540 | 528 | ret = nf_conntrack_standalone_init_proc(net); |
541 | 529 | if (ret < 0) |
542 | 530 | goto out_proc; |
531 | + | |
543 | 532 | net->ct.sysctl_checksum = 1; |
544 | 533 | net->ct.sysctl_log_invalid = 0; |
545 | 534 | ret = nf_conntrack_standalone_init_sysctl(net); |
546 | 535 | if (ret < 0) |
547 | 536 | goto out_sysctl; |
537 | + | |
548 | 538 | return 0; |
549 | 539 | |
550 | 540 | out_sysctl: |
551 | 541 | nf_conntrack_standalone_fini_proc(net); |
552 | 542 | out_proc: |
553 | - nf_conntrack_cleanup(net); | |
543 | + nf_conntrack_cleanup_net(net); | |
554 | 544 | out_init: |
555 | 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 | 550 | nf_conntrack_standalone_fini_sysctl(net); |
561 | 551 | nf_conntrack_standalone_fini_proc(net); |
562 | - nf_conntrack_cleanup(net); | |
552 | + nf_conntrack_cleanup_net(net); | |
563 | 553 | } |
564 | 554 | |
565 | 555 | static struct pernet_operations nf_conntrack_net_ops = { |
566 | - .init = nf_conntrack_net_init, | |
567 | - .exit = nf_conntrack_net_exit, | |
556 | + .init = nf_conntrack_pernet_init, | |
557 | + .exit = nf_conntrack_pernet_exit, | |
568 | 558 | }; |
569 | 559 | |
570 | 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 | 587 | static void __exit nf_conntrack_standalone_fini(void) |
576 | 588 | { |
589 | + nf_conntrack_cleanup_start(); | |
577 | 590 | unregister_pernet_subsys(&nf_conntrack_net_ops); |
591 | + unregister_net_sysctl_table(nf_ct_netfilter_header); | |
578 | 592 | nf_conntrack_cleanup_end(); |
579 | 593 | } |
580 | 594 |