All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Cc: davem@davemloft.net, netdev@vger.kernel.org
Subject: [PATCH 32/32] netfilter: nf_tables_netdev: unregister hooks on net_device removal
Date: Mon, 15 Jun 2015 23:26:29 +0200	[thread overview]
Message-ID: <1434403589-24796-33-git-send-email-pablo@netfilter.org> (raw)
In-Reply-To: <1434403589-24796-1-git-send-email-pablo@netfilter.org>

In case the net_device is gone, we have to unregister the hooks and put back
the reference on the net_device object. Once it comes back, register them
again. This also covers the device rename case.

This patch also adds a new flag to indicate that the basechain is disabled, so
their hooks are not registered. This flag is used by the netdev family to
handle the case where the net_device object is gone. Currently this flag is not
exposed to userspace.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netfilter/nf_tables.h |    7 ++++
 net/netfilter/nf_tables_api.c     |   16 ++++++--
 net/netfilter/nf_tables_netdev.c  |   75 +++++++++++++++++++++++++++++++++++++
 3 files changed, 94 insertions(+), 4 deletions(-)

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 09d6f8d..2a24668 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -781,6 +781,7 @@ struct nft_stats {
 };
 
 #define NFT_HOOK_OPS_MAX		2
+#define NFT_BASECHAIN_DISABLED		(1 << 0)
 
 /**
  *	struct nft_base_chain - nf_tables base chain
@@ -798,6 +799,7 @@ struct nft_base_chain {
 	possible_net_t			pnet;
 	const struct nf_chain_type	*type;
 	u8				policy;
+	u8				flags;
 	struct nft_stats __percpu	*stats;
 	struct nft_chain		chain;
 	char 				dev_name[IFNAMSIZ];
@@ -808,6 +810,11 @@ static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chai
 	return container_of(chain, struct nft_base_chain, chain);
 }
 
+int nft_register_basechain(struct nft_base_chain *basechain,
+			   unsigned int hook_nops);
+void nft_unregister_basechain(struct nft_base_chain *basechain,
+			      unsigned int hook_nops);
+
 unsigned int nft_do_chain(struct nft_pktinfo *pkt,
 			  const struct nf_hook_ops *ops);
 
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index c66dc62..cfe6368 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -127,17 +127,25 @@ static void nft_trans_destroy(struct nft_trans *trans)
 	kfree(trans);
 }
 
-static int nft_register_basechain(struct nft_base_chain *basechain,
-				  unsigned int hook_nops)
+int nft_register_basechain(struct nft_base_chain *basechain,
+			   unsigned int hook_nops)
 {
+	if (basechain->flags & NFT_BASECHAIN_DISABLED)
+		return 0;
+
 	return nf_register_hooks(basechain->ops, hook_nops);
 }
+EXPORT_SYMBOL_GPL(nft_register_basechain);
 
-static void nft_unregister_basechain(struct nft_base_chain *basechain,
-				     unsigned int hook_nops)
+void nft_unregister_basechain(struct nft_base_chain *basechain,
+			      unsigned int hook_nops)
 {
+	if (basechain->flags & NFT_BASECHAIN_DISABLED)
+		return;
+
 	nf_unregister_hooks(basechain->ops, hook_nops);
 }
+EXPORT_SYMBOL_GPL(nft_unregister_basechain);
 
 static int nf_tables_register_hooks(const struct nft_table *table,
 				    struct nft_chain *chain,
diff --git a/net/netfilter/nf_tables_netdev.c b/net/netfilter/nf_tables_netdev.c
index 04cb170..2cae4d4 100644
--- a/net/netfilter/nf_tables_netdev.c
+++ b/net/netfilter/nf_tables_netdev.c
@@ -8,6 +8,7 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/netdevice.h>
 #include <net/netfilter/nf_tables.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
@@ -157,6 +158,77 @@ static const struct nf_chain_type nft_filter_chain_netdev = {
 	.hook_mask	= (1 << NF_NETDEV_INGRESS),
 };
 
+static void nft_netdev_event(unsigned long event, struct nft_af_info *afi,
+			     struct net_device *dev, struct nft_table *table,
+			     struct nft_base_chain *basechain)
+{
+	switch (event) {
+	case NETDEV_REGISTER:
+		if (strcmp(basechain->dev_name, dev->name) != 0)
+			return;
+
+		BUG_ON(!(basechain->flags & NFT_BASECHAIN_DISABLED));
+
+		dev_hold(dev);
+		basechain->ops[0].dev = dev;
+		basechain->flags &= ~NFT_BASECHAIN_DISABLED;
+		if (!(table->flags & NFT_TABLE_F_DORMANT))
+			nft_register_basechain(basechain, afi->nops);
+		break;
+	case NETDEV_UNREGISTER:
+		if (strcmp(basechain->dev_name, dev->name) != 0)
+			return;
+
+		BUG_ON(basechain->flags & NFT_BASECHAIN_DISABLED);
+
+		if (!(table->flags & NFT_TABLE_F_DORMANT))
+			nft_unregister_basechain(basechain, afi->nops);
+
+		dev_put(basechain->ops[0].dev);
+		basechain->ops[0].dev = NULL;
+		basechain->flags |= NFT_BASECHAIN_DISABLED;
+		break;
+	case NETDEV_CHANGENAME:
+		if (dev->ifindex != basechain->ops[0].dev->ifindex)
+			return;
+
+		strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
+		break;
+	}
+}
+
+static int nf_tables_netdev_event(struct notifier_block *this,
+				  unsigned long event, void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+	struct nft_af_info *afi;
+	struct nft_table *table;
+	struct nft_chain *chain;
+
+	nfnl_lock(NFNL_SUBSYS_NFTABLES);
+	list_for_each_entry(afi, &dev_net(dev)->nft.af_info, list) {
+		if (afi->family != NFPROTO_NETDEV)
+			continue;
+
+		list_for_each_entry(table, &afi->tables, list) {
+			list_for_each_entry(chain, &table->chains, list) {
+				if (!(chain->flags & NFT_BASE_CHAIN))
+					continue;
+
+				nft_netdev_event(event, afi, dev, table,
+						 nft_base_chain(chain));
+			}
+		}
+	}
+	nfnl_unlock(NFNL_SUBSYS_NFTABLES);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block nf_tables_netdev_notifier = {
+	.notifier_call	= nf_tables_netdev_event,
+};
+
 static int __init nf_tables_netdev_init(void)
 {
 	int ret;
@@ -166,11 +238,14 @@ static int __init nf_tables_netdev_init(void)
 	if (ret < 0)
 		nft_unregister_chain_type(&nft_filter_chain_netdev);
 
+	register_netdevice_notifier(&nf_tables_netdev_notifier);
+
 	return ret;
 }
 
 static void __exit nf_tables_netdev_exit(void)
 {
+	unregister_netdevice_notifier(&nf_tables_netdev_notifier);
 	unregister_pernet_subsys(&nf_tables_netdev_net_ops);
 	nft_unregister_chain_type(&nft_filter_chain_netdev);
 }
-- 
1.7.10.4

  parent reply	other threads:[~2015-06-15 21:21 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-15 21:25 [PATCH 00/32] Netfilter updates for net-next Pablo Neira Ayuso
2015-06-15 21:25 ` [PATCH 01/32] netfilter: conntrack: warn the user if there is a better helper to use Pablo Neira Ayuso
2015-06-15 21:25 ` [PATCH 02/32] netfilter: bridge: refactor clearing BRNF_NF_BRIDGE_PREROUTING Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 03/32] netfilter: bridge: re-order br_nf_pre_routing_finish_ipv6() Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 04/32] netfilter: bridge: detect NAT66 correctly and change MAC address Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 05/32] netfilter: bridge: refactor frag_max_size Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 06/32] netfilter: bridge: rename br_parse_ip_options Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 07/32] netfilter: bridge: re-order check_hbh_len() Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 08/32] netfilter: bridge: forward IPv6 fragmented packets Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 09/32] net: ip_fragment: remove BRIDGE_NETFILTER mtu special handling Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 10/32] netfilter: bridge: restore vlan tag when refragmenting Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 11/32] netfilter: xtables: use percpu rule counters Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 12/32] netfilter: xtables: avoid percpu ruleset duplication Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 13/32] netfilter: ipset: Use MSEC_PER_SEC consistently Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 14/32] netfilter: ipset: Use SET_WITH_*() helpers to test set extensions Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 15/32] netfilter: ipset: Check extensions attributes before getting extensions Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 16/32] netfilter: ipset: Permit CIDR equal to the host address CIDR in IPv6 Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 17/32] netfilter: ipset: Make sure we always return line number on batch Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 18/32] netfilter: ipset: Check CIDR value only when attribute is given Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 19/32] netfilter: ipset: Fix cidr handling for hash:*net* types Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 20/32] netfilter: ipset: Fix parallel resizing and listing of the same set Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 21/32] netfilter: ipset: Make sure listing doesn't grab a set which is just being destroyed Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 22/32] netfilter:ipset Remove rbtree from hash:net,iface Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 23/32] netfilter: ipset: Prepare the ipset core to use RCU at set level Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 24/32] netfilter: ipset: Introduce RCU locking in bitmap:* types Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 25/32] netfilter: ipset: Introduce RCU locking in hash:* types Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 26/32] netfilter: ipset: Introduce RCU locking in list type Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 27/32] netfilter: ipset: Fix coding styles reported by checkpatch.pl Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 28/32] netfilter: Kconfig: get rid of parens around depends on Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 29/32] netfilter: x_tables: remove XT_TABLE_INFO_SZ and a dereference Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 30/32] netfilter: nf_tables: attach net_device to basechain Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 31/32] netfilter: nf_tables: add nft_register_basechain() and nft_unregister_basechain() Pablo Neira Ayuso
2015-06-15 21:26 ` Pablo Neira Ayuso [this message]
2015-06-15 21:41 ` [PATCH 00/32] Netfilter updates for net-next David Miller
2015-06-20 13:11 ` Jakub Kiciński
2015-06-20 18:30   ` Pablo Neira Ayuso

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1434403589-24796-33-git-send-email-pablo@netfilter.org \
    --to=pablo@netfilter.org \
    --cc=davem@davemloft.net \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.