提交 dd4cbef7 编写于 作者: P Pablo Neira Ayuso

netfilter: nf_tables: get rid of pernet families

Now that we have a single table list for each netns, we can get rid of
one pointer per family and the global afinfo list, thus, shrinking
struct netns for nftables that now becomes 64 bytes smaller.

And call __nft_release_afinfo() from __net_exit path accordingly to
release netnamespace objects on removal.
Signed-off-by: NPablo Neira Ayuso <pablo@netfilter.org>
上级 36596dad
...@@ -979,8 +979,8 @@ struct nft_af_info { ...@@ -979,8 +979,8 @@ struct nft_af_info {
struct module *owner; struct module *owner;
}; };
int nft_register_afinfo(struct net *, struct nft_af_info *); int nft_register_afinfo(struct nft_af_info *);
void nft_unregister_afinfo(struct net *, struct nft_af_info *); void nft_unregister_afinfo(struct nft_af_info *);
int nft_register_chain_type(const struct nf_chain_type *); int nft_register_chain_type(const struct nf_chain_type *);
void nft_unregister_chain_type(const struct nf_chain_type *); void nft_unregister_chain_type(const struct nf_chain_type *);
......
...@@ -7,15 +7,8 @@ ...@@ -7,15 +7,8 @@
struct nft_af_info; struct nft_af_info;
struct netns_nftables { struct netns_nftables {
struct list_head af_info;
struct list_head tables; struct list_head tables;
struct list_head commit_list; struct list_head commit_list;
struct nft_af_info *ipv4;
struct nft_af_info *ipv6;
struct nft_af_info *inet;
struct nft_af_info *arp;
struct nft_af_info *bridge;
struct nft_af_info *netdev;
unsigned int base_seq; unsigned int base_seq;
u8 gencursor; u8 gencursor;
}; };
......
...@@ -47,34 +47,6 @@ static struct nft_af_info nft_af_bridge __read_mostly = { ...@@ -47,34 +47,6 @@ static struct nft_af_info nft_af_bridge __read_mostly = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int nf_tables_bridge_init_net(struct net *net)
{
net->nft.bridge = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
if (net->nft.bridge == NULL)
return -ENOMEM;
memcpy(net->nft.bridge, &nft_af_bridge, sizeof(nft_af_bridge));
if (nft_register_afinfo(net, net->nft.bridge) < 0)
goto err;
return 0;
err:
kfree(net->nft.bridge);
return -ENOMEM;
}
static void nf_tables_bridge_exit_net(struct net *net)
{
nft_unregister_afinfo(net, net->nft.bridge);
kfree(net->nft.bridge);
}
static struct pernet_operations nf_tables_bridge_net_ops = {
.init = nf_tables_bridge_init_net,
.exit = nf_tables_bridge_exit_net,
};
static const struct nf_chain_type filter_bridge = { static const struct nf_chain_type filter_bridge = {
.name = "filter", .name = "filter",
.type = NFT_CHAIN_T_DEFAULT, .type = NFT_CHAIN_T_DEFAULT,
...@@ -98,17 +70,17 @@ static int __init nf_tables_bridge_init(void) ...@@ -98,17 +70,17 @@ static int __init nf_tables_bridge_init(void)
{ {
int ret; int ret;
ret = nft_register_chain_type(&filter_bridge); ret = nft_register_afinfo(&nft_af_bridge);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = register_pernet_subsys(&nf_tables_bridge_net_ops); ret = nft_register_chain_type(&filter_bridge);
if (ret < 0) if (ret < 0)
goto err_register_subsys; goto err_register_chain;
return ret; return ret;
err_register_subsys: err_register_chain:
nft_unregister_chain_type(&filter_bridge); nft_unregister_chain_type(&filter_bridge);
return ret; return ret;
...@@ -116,8 +88,8 @@ static int __init nf_tables_bridge_init(void) ...@@ -116,8 +88,8 @@ static int __init nf_tables_bridge_init(void)
static void __exit nf_tables_bridge_exit(void) static void __exit nf_tables_bridge_exit(void)
{ {
unregister_pernet_subsys(&nf_tables_bridge_net_ops);
nft_unregister_chain_type(&filter_bridge); nft_unregister_chain_type(&filter_bridge);
nft_unregister_afinfo(&nft_af_bridge);
} }
module_init(nf_tables_bridge_init); module_init(nf_tables_bridge_init);
......
...@@ -32,34 +32,6 @@ static struct nft_af_info nft_af_arp __read_mostly = { ...@@ -32,34 +32,6 @@ static struct nft_af_info nft_af_arp __read_mostly = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int nf_tables_arp_init_net(struct net *net)
{
net->nft.arp = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
if (net->nft.arp== NULL)
return -ENOMEM;
memcpy(net->nft.arp, &nft_af_arp, sizeof(nft_af_arp));
if (nft_register_afinfo(net, net->nft.arp) < 0)
goto err;
return 0;
err:
kfree(net->nft.arp);
return -ENOMEM;
}
static void nf_tables_arp_exit_net(struct net *net)
{
nft_unregister_afinfo(net, net->nft.arp);
kfree(net->nft.arp);
}
static struct pernet_operations nf_tables_arp_net_ops = {
.init = nf_tables_arp_init_net,
.exit = nf_tables_arp_exit_net,
};
static const struct nf_chain_type filter_arp = { static const struct nf_chain_type filter_arp = {
.name = "filter", .name = "filter",
.type = NFT_CHAIN_T_DEFAULT, .type = NFT_CHAIN_T_DEFAULT,
...@@ -77,21 +49,26 @@ static int __init nf_tables_arp_init(void) ...@@ -77,21 +49,26 @@ static int __init nf_tables_arp_init(void)
{ {
int ret; int ret;
ret = nft_register_chain_type(&filter_arp); ret = nft_register_afinfo(&nft_af_arp);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = register_pernet_subsys(&nf_tables_arp_net_ops); ret = nft_register_chain_type(&filter_arp);
if (ret < 0) if (ret < 0)
nft_unregister_chain_type(&filter_arp); goto err_register_chain;
return 0;
err_register_chain:
nft_unregister_chain_type(&filter_arp);
return ret; return ret;
} }
static void __exit nf_tables_arp_exit(void) static void __exit nf_tables_arp_exit(void)
{ {
unregister_pernet_subsys(&nf_tables_arp_net_ops);
nft_unregister_chain_type(&filter_arp); nft_unregister_chain_type(&filter_arp);
nft_unregister_afinfo(&nft_af_arp);
} }
module_init(nf_tables_arp_init); module_init(nf_tables_arp_init);
......
...@@ -35,34 +35,6 @@ static struct nft_af_info nft_af_ipv4 __read_mostly = { ...@@ -35,34 +35,6 @@ static struct nft_af_info nft_af_ipv4 __read_mostly = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int nf_tables_ipv4_init_net(struct net *net)
{
net->nft.ipv4 = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
if (net->nft.ipv4 == NULL)
return -ENOMEM;
memcpy(net->nft.ipv4, &nft_af_ipv4, sizeof(nft_af_ipv4));
if (nft_register_afinfo(net, net->nft.ipv4) < 0)
goto err;
return 0;
err:
kfree(net->nft.ipv4);
return -ENOMEM;
}
static void nf_tables_ipv4_exit_net(struct net *net)
{
nft_unregister_afinfo(net, net->nft.ipv4);
kfree(net->nft.ipv4);
}
static struct pernet_operations nf_tables_ipv4_net_ops = {
.init = nf_tables_ipv4_init_net,
.exit = nf_tables_ipv4_exit_net,
};
static const struct nf_chain_type filter_ipv4 = { static const struct nf_chain_type filter_ipv4 = {
.name = "filter", .name = "filter",
.type = NFT_CHAIN_T_DEFAULT, .type = NFT_CHAIN_T_DEFAULT,
...@@ -86,21 +58,25 @@ static int __init nf_tables_ipv4_init(void) ...@@ -86,21 +58,25 @@ static int __init nf_tables_ipv4_init(void)
{ {
int ret; int ret;
ret = nft_register_chain_type(&filter_ipv4); ret = nft_register_afinfo(&nft_af_ipv4);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = register_pernet_subsys(&nf_tables_ipv4_net_ops); ret = nft_register_chain_type(&filter_ipv4);
if (ret < 0) if (ret < 0)
nft_unregister_chain_type(&filter_ipv4); goto err_register_chain;
return 0;
err_register_chain:
nft_unregister_afinfo(&nft_af_ipv4);
return ret; return ret;
} }
static void __exit nf_tables_ipv4_exit(void) static void __exit nf_tables_ipv4_exit(void)
{ {
unregister_pernet_subsys(&nf_tables_ipv4_net_ops);
nft_unregister_chain_type(&filter_ipv4); nft_unregister_chain_type(&filter_ipv4);
nft_unregister_afinfo(&nft_af_ipv4);
} }
module_init(nf_tables_ipv4_init); module_init(nf_tables_ipv4_init);
......
...@@ -33,34 +33,6 @@ static struct nft_af_info nft_af_ipv6 __read_mostly = { ...@@ -33,34 +33,6 @@ static struct nft_af_info nft_af_ipv6 __read_mostly = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int nf_tables_ipv6_init_net(struct net *net)
{
net->nft.ipv6 = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
if (net->nft.ipv6 == NULL)
return -ENOMEM;
memcpy(net->nft.ipv6, &nft_af_ipv6, sizeof(nft_af_ipv6));
if (nft_register_afinfo(net, net->nft.ipv6) < 0)
goto err;
return 0;
err:
kfree(net->nft.ipv6);
return -ENOMEM;
}
static void nf_tables_ipv6_exit_net(struct net *net)
{
nft_unregister_afinfo(net, net->nft.ipv6);
kfree(net->nft.ipv6);
}
static struct pernet_operations nf_tables_ipv6_net_ops = {
.init = nf_tables_ipv6_init_net,
.exit = nf_tables_ipv6_exit_net,
};
static const struct nf_chain_type filter_ipv6 = { static const struct nf_chain_type filter_ipv6 = {
.name = "filter", .name = "filter",
.type = NFT_CHAIN_T_DEFAULT, .type = NFT_CHAIN_T_DEFAULT,
...@@ -84,20 +56,24 @@ static int __init nf_tables_ipv6_init(void) ...@@ -84,20 +56,24 @@ static int __init nf_tables_ipv6_init(void)
{ {
int ret; int ret;
ret = nft_register_chain_type(&filter_ipv6); ret = nft_register_afinfo(&nft_af_ipv6);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = register_pernet_subsys(&nf_tables_ipv6_net_ops); ret = nft_register_chain_type(&filter_ipv6);
if (ret < 0) if (ret < 0)
nft_unregister_chain_type(&filter_ipv6); goto err_register_chain;
return 0;
err_register_chain:
nft_unregister_afinfo(&nft_af_ipv6);
return ret; return ret;
} }
static void __exit nf_tables_ipv6_exit(void) static void __exit nf_tables_ipv6_exit(void)
{ {
unregister_pernet_subsys(&nf_tables_ipv6_net_ops); nft_unregister_afinfo(&nft_af_ipv6);
nft_unregister_chain_type(&filter_ipv6); nft_unregister_chain_type(&filter_ipv6);
} }
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
static LIST_HEAD(nf_tables_expressions); static LIST_HEAD(nf_tables_expressions);
static LIST_HEAD(nf_tables_objects); static LIST_HEAD(nf_tables_objects);
static LIST_HEAD(nf_tables_flowtables); static LIST_HEAD(nf_tables_flowtables);
static LIST_HEAD(nf_tables_af_info);
/** /**
* nft_register_afinfo - register nf_tables address family info * nft_register_afinfo - register nf_tables address family info
...@@ -35,17 +36,15 @@ static LIST_HEAD(nf_tables_flowtables); ...@@ -35,17 +36,15 @@ static LIST_HEAD(nf_tables_flowtables);
* Register the address family for use with nf_tables. Returns zero on * Register the address family for use with nf_tables. Returns zero on
* success or a negative errno code otherwise. * success or a negative errno code otherwise.
*/ */
int nft_register_afinfo(struct net *net, struct nft_af_info *afi) int nft_register_afinfo(struct nft_af_info *afi)
{ {
nfnl_lock(NFNL_SUBSYS_NFTABLES); nfnl_lock(NFNL_SUBSYS_NFTABLES);
list_add_tail_rcu(&afi->list, &net->nft.af_info); list_add_tail_rcu(&afi->list, &nf_tables_af_info);
nfnl_unlock(NFNL_SUBSYS_NFTABLES); nfnl_unlock(NFNL_SUBSYS_NFTABLES);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(nft_register_afinfo); EXPORT_SYMBOL_GPL(nft_register_afinfo);
static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi);
/** /**
* nft_unregister_afinfo - unregister nf_tables address family info * nft_unregister_afinfo - unregister nf_tables address family info
* *
...@@ -53,10 +52,9 @@ static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi); ...@@ -53,10 +52,9 @@ static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi);
* *
* Unregister the address family for use with nf_tables. * Unregister the address family for use with nf_tables.
*/ */
void nft_unregister_afinfo(struct net *net, struct nft_af_info *afi) void nft_unregister_afinfo(struct nft_af_info *afi)
{ {
nfnl_lock(NFNL_SUBSYS_NFTABLES); nfnl_lock(NFNL_SUBSYS_NFTABLES);
__nft_release_afinfo(net, afi);
list_del_rcu(&afi->list); list_del_rcu(&afi->list);
nfnl_unlock(NFNL_SUBSYS_NFTABLES); nfnl_unlock(NFNL_SUBSYS_NFTABLES);
} }
...@@ -66,7 +64,7 @@ static struct nft_af_info *nft_afinfo_lookup(struct net *net, int family) ...@@ -66,7 +64,7 @@ static struct nft_af_info *nft_afinfo_lookup(struct net *net, int family)
{ {
struct nft_af_info *afi; struct nft_af_info *afi;
list_for_each_entry(afi, &net->nft.af_info, list) { list_for_each_entry(afi, &nf_tables_af_info, list) {
if (afi->family == family) if (afi->family == family)
return afi; return afi;
} }
...@@ -5042,15 +5040,12 @@ void nft_flow_table_iterate(struct net *net, ...@@ -5042,15 +5040,12 @@ void nft_flow_table_iterate(struct net *net,
void *data) void *data)
{ {
struct nft_flowtable *flowtable; struct nft_flowtable *flowtable;
const struct nft_af_info *afi;
const struct nft_table *table; const struct nft_table *table;
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(afi, &net->nft.af_info, list) { list_for_each_entry_rcu(table, &net->nft.tables, list) {
list_for_each_entry_rcu(table, &net->nft.tables, list) { list_for_each_entry_rcu(flowtable, &table->flowtables, list) {
list_for_each_entry_rcu(flowtable, &table->flowtables, list) { iter(&flowtable->data, data);
iter(&flowtable->data, data);
}
} }
} }
rcu_read_unlock(); rcu_read_unlock();
...@@ -6533,21 +6528,6 @@ int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data, ...@@ -6533,21 +6528,6 @@ int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
} }
EXPORT_SYMBOL_GPL(nft_data_dump); EXPORT_SYMBOL_GPL(nft_data_dump);
static int __net_init nf_tables_init_net(struct net *net)
{
INIT_LIST_HEAD(&net->nft.af_info);
INIT_LIST_HEAD(&net->nft.tables);
INIT_LIST_HEAD(&net->nft.commit_list);
net->nft.base_seq = 1;
return 0;
}
static void __net_exit nf_tables_exit_net(struct net *net)
{
WARN_ON_ONCE(!list_empty(&net->nft.af_info));
WARN_ON_ONCE(!list_empty(&net->nft.commit_list));
}
int __nft_release_basechain(struct nft_ctx *ctx) int __nft_release_basechain(struct nft_ctx *ctx)
{ {
struct nft_rule *rule, *nr; struct nft_rule *rule, *nr;
...@@ -6568,8 +6548,7 @@ int __nft_release_basechain(struct nft_ctx *ctx) ...@@ -6568,8 +6548,7 @@ int __nft_release_basechain(struct nft_ctx *ctx)
} }
EXPORT_SYMBOL_GPL(__nft_release_basechain); EXPORT_SYMBOL_GPL(__nft_release_basechain);
/* Called by nft_unregister_afinfo() from __net_exit path, nfnl_lock is held. */ static void __nft_release_afinfo(struct net *net)
static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
{ {
struct nft_flowtable *flowtable, *nf; struct nft_flowtable *flowtable, *nf;
struct nft_table *table, *nt; struct nft_table *table, *nt;
...@@ -6579,10 +6558,11 @@ static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi) ...@@ -6579,10 +6558,11 @@ static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
struct nft_set *set, *ns; struct nft_set *set, *ns;
struct nft_ctx ctx = { struct nft_ctx ctx = {
.net = net, .net = net,
.family = afi->family,
}; };
list_for_each_entry_safe(table, nt, &net->nft.tables, list) { list_for_each_entry_safe(table, nt, &net->nft.tables, list) {
ctx.family = table->afi->family;
list_for_each_entry(chain, &table->chains, list) list_for_each_entry(chain, &table->chains, list)
nf_tables_unregister_hook(net, table, chain); nf_tables_unregister_hook(net, table, chain);
list_for_each_entry(flowtable, &table->flowtables, list) list_for_each_entry(flowtable, &table->flowtables, list)
...@@ -6623,6 +6603,21 @@ static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi) ...@@ -6623,6 +6603,21 @@ static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
} }
} }
static int __net_init nf_tables_init_net(struct net *net)
{
INIT_LIST_HEAD(&net->nft.tables);
INIT_LIST_HEAD(&net->nft.commit_list);
net->nft.base_seq = 1;
return 0;
}
static void __net_exit nf_tables_exit_net(struct net *net)
{
__nft_release_afinfo(net);
WARN_ON_ONCE(!list_empty(&net->nft.tables));
WARN_ON_ONCE(!list_empty(&net->nft.commit_list));
}
static struct pernet_operations nf_tables_net_ops = { static struct pernet_operations nf_tables_net_ops = {
.init = nf_tables_init_net, .init = nf_tables_init_net,
.exit = nf_tables_exit_net, .exit = nf_tables_exit_net,
......
...@@ -43,34 +43,6 @@ static struct nft_af_info nft_af_inet __read_mostly = { ...@@ -43,34 +43,6 @@ static struct nft_af_info nft_af_inet __read_mostly = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int __net_init nf_tables_inet_init_net(struct net *net)
{
net->nft.inet = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
if (net->nft.inet == NULL)
return -ENOMEM;
memcpy(net->nft.inet, &nft_af_inet, sizeof(nft_af_inet));
if (nft_register_afinfo(net, net->nft.inet) < 0)
goto err;
return 0;
err:
kfree(net->nft.inet);
return -ENOMEM;
}
static void __net_exit nf_tables_inet_exit_net(struct net *net)
{
nft_unregister_afinfo(net, net->nft.inet);
kfree(net->nft.inet);
}
static struct pernet_operations nf_tables_inet_net_ops = {
.init = nf_tables_inet_init_net,
.exit = nf_tables_inet_exit_net,
};
static const struct nf_chain_type filter_inet = { static const struct nf_chain_type filter_inet = {
.name = "filter", .name = "filter",
.type = NFT_CHAIN_T_DEFAULT, .type = NFT_CHAIN_T_DEFAULT,
...@@ -94,21 +66,24 @@ static int __init nf_tables_inet_init(void) ...@@ -94,21 +66,24 @@ static int __init nf_tables_inet_init(void)
{ {
int ret; int ret;
ret = nft_register_chain_type(&filter_inet); if (nft_register_afinfo(&nft_af_inet) < 0)
if (ret < 0)
return ret; return ret;
ret = register_pernet_subsys(&nf_tables_inet_net_ops); ret = nft_register_chain_type(&filter_inet);
if (ret < 0) if (ret < 0)
nft_unregister_chain_type(&filter_inet); goto err_register_chain;
return ret;
err_register_chain:
nft_unregister_afinfo(&nft_af_inet);
return ret; return ret;
} }
static void __exit nf_tables_inet_exit(void) static void __exit nf_tables_inet_exit(void)
{ {
unregister_pernet_subsys(&nf_tables_inet_net_ops);
nft_unregister_chain_type(&filter_inet); nft_unregister_chain_type(&filter_inet);
nft_unregister_afinfo(&nft_af_inet);
} }
module_init(nf_tables_inet_init); module_init(nf_tables_inet_init);
......
...@@ -43,34 +43,6 @@ static struct nft_af_info nft_af_netdev __read_mostly = { ...@@ -43,34 +43,6 @@ static struct nft_af_info nft_af_netdev __read_mostly = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int nf_tables_netdev_init_net(struct net *net)
{
net->nft.netdev = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
if (net->nft.netdev == NULL)
return -ENOMEM;
memcpy(net->nft.netdev, &nft_af_netdev, sizeof(nft_af_netdev));
if (nft_register_afinfo(net, net->nft.netdev) < 0)
goto err;
return 0;
err:
kfree(net->nft.netdev);
return -ENOMEM;
}
static void nf_tables_netdev_exit_net(struct net *net)
{
nft_unregister_afinfo(net, net->nft.netdev);
kfree(net->nft.netdev);
}
static struct pernet_operations nf_tables_netdev_net_ops = {
.init = nf_tables_netdev_init_net,
.exit = nf_tables_netdev_exit_net,
};
static const struct nf_chain_type nft_filter_chain_netdev = { static const struct nf_chain_type nft_filter_chain_netdev = {
.name = "filter", .name = "filter",
.type = NFT_CHAIN_T_DEFAULT, .type = NFT_CHAIN_T_DEFAULT,
...@@ -145,32 +117,32 @@ static int __init nf_tables_netdev_init(void) ...@@ -145,32 +117,32 @@ static int __init nf_tables_netdev_init(void)
{ {
int ret; int ret;
ret = nft_register_chain_type(&nft_filter_chain_netdev); if (nft_register_afinfo(&nft_af_netdev) < 0)
if (ret)
return ret; return ret;
ret = register_pernet_subsys(&nf_tables_netdev_net_ops); ret = nft_register_chain_type(&nft_filter_chain_netdev);
if (ret) if (ret)
goto err1; goto err_register_chain_type;
ret = register_netdevice_notifier(&nf_tables_netdev_notifier); ret = register_netdevice_notifier(&nf_tables_netdev_notifier);
if (ret) if (ret)
goto err2; goto err_register_netdevice_notifier;
return 0; return 0;
err2: err_register_netdevice_notifier:
unregister_pernet_subsys(&nf_tables_netdev_net_ops);
err1:
nft_unregister_chain_type(&nft_filter_chain_netdev); nft_unregister_chain_type(&nft_filter_chain_netdev);
err_register_chain_type:
nft_unregister_afinfo(&nft_af_netdev);
return ret; return ret;
} }
static void __exit nf_tables_netdev_exit(void) static void __exit nf_tables_netdev_exit(void)
{ {
unregister_netdevice_notifier(&nf_tables_netdev_notifier); unregister_netdevice_notifier(&nf_tables_netdev_notifier);
unregister_pernet_subsys(&nf_tables_netdev_net_ops);
nft_unregister_chain_type(&nft_filter_chain_netdev); nft_unregister_chain_type(&nft_filter_chain_netdev);
nft_unregister_afinfo(&nft_af_netdev);
} }
module_init(nf_tables_netdev_init); module_init(nf_tables_netdev_init);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册