aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter/core.c
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2017-04-24 15:37:41 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2017-05-01 11:19:12 +0200
commit039b40ee5854dc733cf786fee4a88e240a012115 (patch)
tree49070019cfbd9dd9a86e32e50be465ca3346afcc /net/netfilter/core.c
parentnetfilter: nf_log: don't call synchronize_rcu in nf_log_unset (diff)
downloadlinux-dev-039b40ee5854dc733cf786fee4a88e240a012115.tar.xz
linux-dev-039b40ee5854dc733cf786fee4a88e240a012115.zip
netfilter: nf_queue: only call synchronize_net twice if nf_queue is active
nf_unregister_net_hook(s) can avoid a second call to synchronize_net, provided there is no nfqueue active in that net namespace (which is the common case). This also gets rid of the extra arg to nf_queue_nf_hook_drop(), normally this gets called during netns cleanup so no packets should be queued. For the rare case of base chain being unregistered or module removal while nfqueue is in use the extra hiccup due to the packet drops isn't a big deal. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter/core.c')
-rw-r--r--net/netfilter/core.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index b5d908851cc8..552d606e57ca 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -162,14 +162,17 @@ __nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
{
struct nf_hook_entry *p = __nf_unregister_net_hook(net, reg);
+ unsigned int nfq;
if (!p)
return;
synchronize_net();
- nf_queue_nf_hook_drop(net, p);
+
/* other cpu might still process nfqueue verdict that used reg */
- synchronize_net();
+ nfq = nf_queue_nf_hook_drop(net);
+ if (nfq)
+ synchronize_net();
kfree(p);
}
EXPORT_SYMBOL(nf_unregister_net_hook);
@@ -198,7 +201,7 @@ void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg,
unsigned int hookcount)
{
struct nf_hook_entry *to_free[16];
- unsigned int i, n;
+ unsigned int i, n, nfq;
do {
n = min_t(unsigned int, hookcount, ARRAY_SIZE(to_free));
@@ -208,12 +211,12 @@ void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg,
synchronize_net();
- for (i = 0; i < n; i++) {
- if (to_free[i])
- nf_queue_nf_hook_drop(net, to_free[i]);
- }
-
- synchronize_net();
+ /* need 2nd synchronize_net() if nfqueue is used, skb
+ * can get reinjected right before nf_queue_hook_drop()
+ */
+ nfq = nf_queue_nf_hook_drop(net);
+ if (nfq)
+ synchronize_net();
for (i = 0; i < n; i++)
kfree(to_free[i]);