Patchwork [06/11] netfilter: nf_tables: introduce chain handles and fix chain rename

login
register
mail settings
Submitter Patrick McHardy
Date Dec. 12, 2012, 6:47 p.m.
Message ID <1355338061-5517-7-git-send-email-kaber@trash.net>
Download mbox | patch
Permalink /patch/205623/
State Accepted
Headers show

Comments

Patrick McHardy - Dec. 12, 2012, 6:47 p.m.
From: Patrick McHardy <kaber@trash.net>

Add a chain handle as an alternative way to identify a chain for renames.
The handle is constant, while the name might change.

Kill the NFTA_CHAIN_NEW_NAME attribute since netlink attributes are
supposed to be symetrical. Also fix netlink notification to not send
a DELCHAIN/NEWCHAIN message for renames but a simple NEWCHAIN with
the old handle and the new name.

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 include/linux/netfilter/nf_tables.h |   2 +-
 include/net/netfilter/nf_tables.h   |   2 +
 net/netfilter/nf_tables_api.c       | 100 ++++++++++++++++--------------------
 3 Dateien geändert, 48 Zeilen hinzugefügt(+), 56 Zeilen entfernt(-)

Patch

diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 5a6eefe..7640290 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -75,11 +75,11 @@  enum nft_table_attributes {
 enum nft_chain_attributes {
 	NFTA_CHAIN_UNSPEC,
 	NFTA_CHAIN_TABLE,
+	NFTA_CHAIN_HANDLE,
 	NFTA_CHAIN_NAME,
 	NFTA_CHAIN_HOOK,
 	NFTA_CHAIN_POLICY,
 	NFTA_CHAIN_USE,
-	NFTA_CHAIN_NEW_NAME,
 	NFTA_CHAIN_TYPE,
 	__NFTA_CHAIN_MAX
 };
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index d1a8e9e..e7dc1da 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -346,6 +346,7 @@  enum nft_chain_flags {
  *
  *	@rules: list of rules in the chain
  *	@list: used internally
+ *	@handle: chain handle
  *	@flags: bitmask of enum nft_chain_flags
  *	@use: number of jump references to this chain
  *	@level: length of longest path to this chain
@@ -354,6 +355,7 @@  enum nft_chain_flags {
 struct nft_chain {
 	struct list_head		rules;
 	struct list_head		list;
+	u64				handle;
 	u8				flags;
 	u16				use;
 	u16				level;
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 4b36b0a..bc4eb76 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -118,6 +118,11 @@  static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi,
 	return ERR_PTR(-ENOENT);
 }
 
+static inline u64 nf_tables_alloc_handle(struct nft_table *table)
+{
+	return ++table->hgenerator;
+}
+
 static struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX];
 
 static int __nf_tables_chain_type_lookup(int family, const struct nlattr *nla)
@@ -474,6 +479,19 @@  EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
  * Chains
  */
 
+static struct nft_chain *
+nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
+{
+	struct nft_chain *chain;
+
+	list_for_each_entry(chain, &table->chains, list) {
+		if (chain->handle == handle)
+			return chain;
+	}
+
+	return ERR_PTR(-ENOENT);
+}
+
 static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
 						const struct nlattr *nla)
 {
@@ -491,13 +509,12 @@  static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
 }
 
 static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
+	[NFTA_CHAIN_HANDLE]	= { .type = NLA_U64 },
 	[NFTA_CHAIN_NAME]	= { .type = NLA_STRING,
 				    .len = NFT_CHAIN_MAXNAMELEN - 1 },
 	[NFTA_CHAIN_TABLE]	= { .type = NLA_STRING },
 	[NFTA_CHAIN_HOOK]	= { .type = NLA_NESTED },
 	[NFTA_CHAIN_POLICY]	= { .type = NLA_U32 },
-	[NFTA_CHAIN_NEW_NAME]	= { .type = NLA_STRING,
-				    .len = NFT_CHAIN_MAXNAMELEN - 1 },
 	[NFTA_CHAIN_TYPE]	= { .type = NLA_NUL_STRING },
 };
 
@@ -527,6 +544,8 @@  static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
 
 	if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
 		goto nla_put_failure;
+	if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle)))
+		goto nla_put_failure;
 	if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
 		goto nla_put_failure;
 
@@ -701,58 +720,19 @@  nf_tables_chain_policy(struct nft_base_chain *chain, const struct nlattr *attr)
 	return 0;
 }
 
-static int nf_tables_mvchain(struct sk_buff *skb, const struct nlmsghdr *nlh,
-			     struct nft_table *table,
-			     struct nft_chain *chain,
-			     const struct nlattr * const nla[])
-{
-	const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-	int family = nfmsg->nfgen_family;
-	struct nft_chain *new_chain;
-	struct nft_chain old_chain;
-
-	if (!nla[NFTA_CHAIN_NEW_NAME])
-		return -EINVAL;
-
-	if (chain->flags & NFT_BASE_CHAIN)
-		return -EOPNOTSUPP;
-
-	new_chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NEW_NAME]);
-	if (IS_ERR(new_chain)) {
-		if (PTR_ERR(new_chain) != -ENOENT)
-			return PTR_ERR(new_chain);
-		new_chain = NULL;
-	}
-
-	if (new_chain != NULL)
-		return -EEXIST;
-
-	new_chain = chain;
-
-	nla_strlcpy(old_chain.name,
-		    nla[NFTA_CHAIN_NAME], NFT_CHAIN_MAXNAMELEN);
-	nla_strlcpy(new_chain->name,
-		    nla[NFTA_CHAIN_NEW_NAME], NFT_CHAIN_MAXNAMELEN);
-
-	nf_tables_chain_notify(skb, nlh, table, &old_chain, NFT_MSG_DELCHAIN,
-			       family);
-	nf_tables_chain_notify(skb, nlh, table, new_chain, NFT_MSG_NEWCHAIN,
-			       family);
-	return 0;
-}
-
 static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
 			      const struct nlmsghdr *nlh,
 			      const struct nlattr * const nla[])
 {
 	const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-	const struct nlattr *name;
+	const struct nlattr * uninitialized_var(name);
 	const struct nft_af_info *afi;
 	struct nft_table *table;
 	struct nft_chain *chain;
 	struct nft_base_chain *basechain = NULL;
 	struct nlattr *ha[NFTA_HOOK_MAX + 1];
 	int family = nfmsg->nfgen_family;
+	u64 handle = 0;
 	int err;
 	bool create;
 
@@ -766,28 +746,42 @@  static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
 	if (IS_ERR(table))
 		return PTR_ERR(table);
 
-	name = nla[NFTA_CHAIN_NAME];
-	chain = nf_tables_chain_lookup(table, name);
-	if (IS_ERR(chain)) {
-		if (PTR_ERR(chain) != -ENOENT)
+	chain = NULL;
+	if (nla[NFTA_CHAIN_HANDLE]) {
+		handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
+		chain = nf_tables_chain_lookup_byhandle(table, handle);
+		if (IS_ERR(chain))
 			return PTR_ERR(chain);
-		chain = NULL;
+	} else {
+		name = nla[NFTA_CHAIN_NAME];
+		chain = nf_tables_chain_lookup(table, name);
+		if (IS_ERR(chain)) {
+			if (PTR_ERR(chain) != -ENOENT)
+				return PTR_ERR(chain);
+			chain = NULL;
+		}
 	}
 
 	if (chain != NULL) {
 		if (nlh->nlmsg_flags & NLM_F_EXCL)
 			return -EEXIST;
 		if (nlh->nlmsg_flags & NLM_F_REPLACE)
-			return nf_tables_mvchain(skb, nlh, table, chain, nla);
+			return -EOPNOTSUPP;
 
 		if (nla[NFTA_CHAIN_POLICY]) {
 			if (!(chain->flags & NFT_BASE_CHAIN))
 				return -EOPNOTSUPP;
+
 			err = nf_tables_chain_policy(nft_base_chain(chain),
 						     nla[NFTA_CHAIN_POLICY]);
 			if (err < 0)
 				return err;
 		}
+
+		if (nla[NFTA_CHAIN_HANDLE] && nla[NFTA_CHAIN_NAME])
+			nla_strlcpy(chain->name, nla[NFTA_CHAIN_NAME],
+				    NFT_CHAIN_MAXNAMELEN);
+
 		goto notify;
 	}
 
@@ -856,6 +850,7 @@  static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
 	}
 
 	INIT_LIST_HEAD(&chain->rules);
+	chain->handle = nf_tables_alloc_handle(table);
 	nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
 
 	list_add_tail(&chain->list, &table->chains);
@@ -1122,11 +1117,6 @@  static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
 	return __nf_tables_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
 }
 
-static inline u64 nf_tables_rule_alloc_handle(struct nft_table *table)
-{
-	return ++table->hgenerator;
-}
-
 static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
 	[NFTA_RULE_TABLE]	= { .type = NLA_STRING },
 	[NFTA_RULE_CHAIN]	= { .type = NLA_STRING,
@@ -1389,7 +1379,7 @@  static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 				return 0;
 		}
 	} else
-		handle = nf_tables_rule_alloc_handle(table);
+		handle = nf_tables_alloc_handle(table);
 
 	if (handle == 0)
 		return -EINVAL;