[nf-next RFC] netfilter: nf_tables: Feature ifname-based hook registration

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Require user space to set a flag upon flowtable or netdev-family chain
creation explicitly relaxing the hook registration when it comes to
non-existent interfaces. For the sake of simplicity, just restore error
condition if a given hook does not find an interface to bind to, leave
everyting else in place. Therefore:

- A wildcard interface spec is accepted as long as at least a single
  interface matches.
- Dynamic unregistering and re-registering of vanishing/re-appearing
  interfaces is still happening.

Note that this flag is persistent, i.e. included in ruleset dumps. This
effectively makes it "updatable": User space may create a "name-based"
flowtable for a non-existent interface, then update the flowtable to
drop the flag. What should happen then? Right now this is simply
accepted, even though the flowtable still does not bind to an interface.

Signed-off-by: Phil Sutter <phil@xxxxxx>
---
 include/uapi/linux/netfilter/nf_tables.h |  9 +++++++--
 net/netfilter/nf_tables_api.c            | 15 ++++++++++++---
 2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 792836149eca..d08c7fbde1d1 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -219,10 +219,12 @@ enum nft_chain_flags {
 	NFT_CHAIN_BASE		= (1 << 0),
 	NFT_CHAIN_HW_OFFLOAD	= (1 << 1),
 	NFT_CHAIN_BINDING	= (1 << 2),
+	NFT_CHAIN_NAME_BASED	= (1 << 3),
 };
 #define NFT_CHAIN_FLAGS		(NFT_CHAIN_BASE		| \
 				 NFT_CHAIN_HW_OFFLOAD	| \
-				 NFT_CHAIN_BINDING)
+				 NFT_CHAIN_BINDING	| \
+				 NFT_CHAIN_NAME_BASED)
 
 /**
  * enum nft_chain_attributes - nf_tables chain netlink attributes
@@ -1699,12 +1701,15 @@ enum nft_object_attributes {
  *
  * @NFT_FLOWTABLE_HW_OFFLOAD: flowtable hardware offload is enabled
  * @NFT_FLOWTABLE_COUNTER: enable flow counters
+ * @NFT_FLOWTABLE_NAME_BASED: relax interface hooks
  */
 enum nft_flowtable_flags {
 	NFT_FLOWTABLE_HW_OFFLOAD	= 0x1,
 	NFT_FLOWTABLE_COUNTER		= 0x2,
+	NFT_FLOWTABLE_NAME_BASED	= 0x4,
 	NFT_FLOWTABLE_MASK		= (NFT_FLOWTABLE_HW_OFFLOAD |
-					   NFT_FLOWTABLE_COUNTER)
+					   NFT_FLOWTABLE_COUNTER |
+					   NFT_FLOWTABLE_NAME_BASED)
 };
 
 /**
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 8fcc6393be38..5ae736715eec 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -2374,7 +2374,8 @@ static struct nft_hook *nft_hook_list_find(struct list_head *hook_list,
 static int nf_tables_parse_netdev_hooks(struct net *net,
 					const struct nlattr *attr,
 					struct list_head *hook_list,
-					struct netlink_ext_ack *extack)
+					struct netlink_ext_ack *extack,
+					bool relaxed)
 {
 	struct nft_hook *hook, *next;
 	const struct nlattr *tmp;
@@ -2392,6 +2393,12 @@ static int nf_tables_parse_netdev_hooks(struct net *net,
 			err = PTR_ERR(hook);
 			goto err_hook;
 		}
+		if (!relaxed && list_empty(&hook->ops_list)) {
+			NL_SET_BAD_ATTR(extack, tmp);
+			nft_netdev_hook_free(hook);
+			err = -ENOENT;
+			goto err_hook;
+		}
 		if (nft_hook_list_find(hook_list, hook)) {
 			NL_SET_BAD_ATTR(extack, tmp);
 			nft_netdev_hook_free(hook);
@@ -2441,7 +2448,8 @@ static int nft_chain_parse_netdev(struct net *net, struct nlattr *tb[],
 		list_add_tail(&hook->list, hook_list);
 	} else if (tb[NFTA_HOOK_DEVS]) {
 		err = nf_tables_parse_netdev_hooks(net, tb[NFTA_HOOK_DEVS],
-						   hook_list, extack);
+						   hook_list, extack,
+						   flags & NFT_CHAIN_NAME_BASED);
 		if (err < 0)
 			return err;
 
@@ -8847,6 +8855,7 @@ static int nft_flowtable_parse_hook(const struct nft_ctx *ctx,
 				    struct nft_flowtable *flowtable,
 				    struct netlink_ext_ack *extack, bool add)
 {
+	bool relaxed = flowtable->data.flags & NFT_FLOWTABLE_NAME_BASED;
 	struct nlattr *tb[NFTA_FLOWTABLE_HOOK_MAX + 1];
 	struct nf_hook_ops *ops;
 	struct nft_hook *hook;
@@ -8897,7 +8906,7 @@ static int nft_flowtable_parse_hook(const struct nft_ctx *ctx,
 		err = nf_tables_parse_netdev_hooks(ctx->net,
 						   tb[NFTA_FLOWTABLE_HOOK_DEVS],
 						   &flowtable_hook->list,
-						   extack);
+						   extack, relaxed);
 		if (err < 0)
 			return err;
 	}
-- 
2.49.0





[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux