@@ -69,6 +69,7 @@ enum nft_chain_attributes {
NFTA_CHAIN_HOOK,
NFTA_CHAIN_POLICY,
NFTA_CHAIN_USE,
+ NFTA_CHAIN_NEW_NAME,
__NFTA_CHAIN_MAX
};
#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
@@ -484,6 +484,8 @@ static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
[NFTA_CHAIN_HOOK] = { .type = NLA_NESTED },
[NFTA_CHAIN_POLICY] = { .type = NLA_U32 },
[NFTA_CHAIN_USE] = { .type = NLA_U32 },
+ [NFTA_CHAIN_NEW_NAME] = { .type = NLA_STRING,
+ .len = NFT_CHAIN_MAXNAMELEN - 1 },
};
static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
@@ -678,6 +680,47 @@ nf_tables_chain_policy(struct nft_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_CHAIN_BUILTIN ||
+ 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[])
@@ -715,7 +758,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
if (nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST;
if (nlh->nlmsg_flags & NLM_F_REPLACE)
- return -EOPNOTSUPP;
+ return nf_tables_mvchain(skb, nlh, table, chain, nla);
if ((chain->flags & NFT_BASE_CHAIN) && nla[NFTA_CHAIN_POLICY]) {
return nf_tables_chain_policy(chain,
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com> --- include/linux/netfilter/nf_tables.h | 1 + net/netfilter/nf_tables_api.c | 45 ++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-)