|
|
|
|
@@ -736,7 +736,8 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
|
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
|
|
if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
|
|
|
|
|
nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
|
|
|
|
|
nla_put_be32(skb, NFTA_TABLE_FLAGS,
|
|
|
|
|
htonl(table->flags & NFT_TABLE_F_MASK)) ||
|
|
|
|
|
nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)) ||
|
|
|
|
|
nla_put_be64(skb, NFTA_TABLE_HANDLE, cpu_to_be64(table->handle),
|
|
|
|
|
NFTA_TABLE_PAD))
|
|
|
|
|
@@ -947,20 +948,22 @@ err_register_hooks:
|
|
|
|
|
|
|
|
|
|
static void nf_tables_table_disable(struct net *net, struct nft_table *table)
|
|
|
|
|
{
|
|
|
|
|
table->flags &= ~NFT_TABLE_F_DORMANT;
|
|
|
|
|
nft_table_disable(net, table, 0);
|
|
|
|
|
table->flags |= NFT_TABLE_F_DORMANT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
NFT_TABLE_STATE_UNCHANGED = 0,
|
|
|
|
|
NFT_TABLE_STATE_DORMANT,
|
|
|
|
|
NFT_TABLE_STATE_WAKEUP
|
|
|
|
|
};
|
|
|
|
|
#define __NFT_TABLE_F_INTERNAL (NFT_TABLE_F_MASK + 1)
|
|
|
|
|
#define __NFT_TABLE_F_WAS_DORMANT (__NFT_TABLE_F_INTERNAL << 0)
|
|
|
|
|
#define __NFT_TABLE_F_WAS_AWAKEN (__NFT_TABLE_F_INTERNAL << 1)
|
|
|
|
|
#define __NFT_TABLE_F_UPDATE (__NFT_TABLE_F_WAS_DORMANT | \
|
|
|
|
|
__NFT_TABLE_F_WAS_AWAKEN)
|
|
|
|
|
|
|
|
|
|
static int nf_tables_updtable(struct nft_ctx *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct nft_trans *trans;
|
|
|
|
|
u32 flags;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (!ctx->nla[NFTA_TABLE_FLAGS])
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -985,21 +988,27 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
|
|
|
|
|
|
|
|
|
|
if ((flags & NFT_TABLE_F_DORMANT) &&
|
|
|
|
|
!(ctx->table->flags & NFT_TABLE_F_DORMANT)) {
|
|
|
|
|
nft_trans_table_state(trans) = NFT_TABLE_STATE_DORMANT;
|
|
|
|
|
ctx->table->flags |= NFT_TABLE_F_DORMANT;
|
|
|
|
|
if (!(ctx->table->flags & __NFT_TABLE_F_UPDATE))
|
|
|
|
|
ctx->table->flags |= __NFT_TABLE_F_WAS_AWAKEN;
|
|
|
|
|
} else if (!(flags & NFT_TABLE_F_DORMANT) &&
|
|
|
|
|
ctx->table->flags & NFT_TABLE_F_DORMANT) {
|
|
|
|
|
ret = nf_tables_table_enable(ctx->net, ctx->table);
|
|
|
|
|
if (ret >= 0)
|
|
|
|
|
nft_trans_table_state(trans) = NFT_TABLE_STATE_WAKEUP;
|
|
|
|
|
}
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
goto err;
|
|
|
|
|
ctx->table->flags &= ~NFT_TABLE_F_DORMANT;
|
|
|
|
|
if (!(ctx->table->flags & __NFT_TABLE_F_UPDATE)) {
|
|
|
|
|
ret = nf_tables_table_enable(ctx->net, ctx->table);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
goto err_register_hooks;
|
|
|
|
|
|
|
|
|
|
ctx->table->flags |= __NFT_TABLE_F_WAS_DORMANT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nft_trans_table_flags(trans) = flags;
|
|
|
|
|
nft_trans_table_update(trans) = true;
|
|
|
|
|
nft_trans_commit_list_add_tail(ctx->net, trans);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
err:
|
|
|
|
|
|
|
|
|
|
err_register_hooks:
|
|
|
|
|
nft_trans_destroy(trans);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
@@ -1905,7 +1914,7 @@ static int nft_chain_parse_netdev(struct net *net,
|
|
|
|
|
static int nft_chain_parse_hook(struct net *net,
|
|
|
|
|
const struct nlattr * const nla[],
|
|
|
|
|
struct nft_chain_hook *hook, u8 family,
|
|
|
|
|
bool autoload)
|
|
|
|
|
struct netlink_ext_ack *extack, bool autoload)
|
|
|
|
|
{
|
|
|
|
|
struct nftables_pernet *nft_net = nft_pernet(net);
|
|
|
|
|
struct nlattr *ha[NFTA_HOOK_MAX + 1];
|
|
|
|
|
@@ -1935,8 +1944,10 @@ static int nft_chain_parse_hook(struct net *net,
|
|
|
|
|
if (nla[NFTA_CHAIN_TYPE]) {
|
|
|
|
|
type = nf_tables_chain_type_lookup(net, nla[NFTA_CHAIN_TYPE],
|
|
|
|
|
family, autoload);
|
|
|
|
|
if (IS_ERR(type))
|
|
|
|
|
if (IS_ERR(type)) {
|
|
|
|
|
NL_SET_BAD_ATTR(extack, nla[NFTA_CHAIN_TYPE]);
|
|
|
|
|
return PTR_ERR(type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (hook->num >= NFT_MAX_HOOKS || !(type->hook_mask & (1 << hook->num)))
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
@@ -1945,8 +1956,11 @@ static int nft_chain_parse_hook(struct net *net,
|
|
|
|
|
hook->priority <= NF_IP_PRI_CONNTRACK)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
if (!try_module_get(type->owner))
|
|
|
|
|
if (!try_module_get(type->owner)) {
|
|
|
|
|
if (nla[NFTA_CHAIN_TYPE])
|
|
|
|
|
NL_SET_BAD_ATTR(extack, nla[NFTA_CHAIN_TYPE]);
|
|
|
|
|
return -ENOENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hook->type = type;
|
|
|
|
|
|
|
|
|
|
@@ -2057,7 +2071,8 @@ static int nft_chain_add(struct nft_table *table, struct nft_chain *chain)
|
|
|
|
|
static u64 chain_id;
|
|
|
|
|
|
|
|
|
|
static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
|
|
|
|
|
u8 policy, u32 flags)
|
|
|
|
|
u8 policy, u32 flags,
|
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
|
{
|
|
|
|
|
const struct nlattr * const *nla = ctx->nla;
|
|
|
|
|
struct nft_table *table = ctx->table;
|
|
|
|
|
@@ -2079,7 +2094,8 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
|
|
|
|
|
if (flags & NFT_CHAIN_BINDING)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
err = nft_chain_parse_hook(net, nla, &hook, family, true);
|
|
|
|
|
err = nft_chain_parse_hook(net, nla, &hook, family, extack,
|
|
|
|
|
true);
|
|
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
@@ -2234,7 +2250,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
|
|
|
|
|
return -EEXIST;
|
|
|
|
|
}
|
|
|
|
|
err = nft_chain_parse_hook(ctx->net, nla, &hook, ctx->family,
|
|
|
|
|
false);
|
|
|
|
|
extack, false);
|
|
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
@@ -2447,7 +2463,7 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
|
|
|
|
|
extack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nf_tables_addchain(&ctx, family, genmask, policy, flags);
|
|
|
|
|
return nf_tables_addchain(&ctx, family, genmask, policy, flags, extack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
|
|
|
|
|
@@ -3328,8 +3344,10 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
|
|
|
|
|
if (n == NFT_RULE_MAXEXPRS)
|
|
|
|
|
goto err1;
|
|
|
|
|
err = nf_tables_expr_parse(&ctx, tmp, &expr_info[n]);
|
|
|
|
|
if (err < 0)
|
|
|
|
|
if (err < 0) {
|
|
|
|
|
NL_SET_BAD_ATTR(extack, tmp);
|
|
|
|
|
goto err1;
|
|
|
|
|
}
|
|
|
|
|
size += expr_info[n].ops->size;
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
@@ -8547,10 +8565,14 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
|
|
|
|
|
switch (trans->msg_type) {
|
|
|
|
|
case NFT_MSG_NEWTABLE:
|
|
|
|
|
if (nft_trans_table_update(trans)) {
|
|
|
|
|
if (nft_trans_table_state(trans) == NFT_TABLE_STATE_DORMANT)
|
|
|
|
|
if (!(trans->ctx.table->flags & __NFT_TABLE_F_UPDATE)) {
|
|
|
|
|
nft_trans_destroy(trans);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (trans->ctx.table->flags & NFT_TABLE_F_DORMANT)
|
|
|
|
|
nf_tables_table_disable(net, trans->ctx.table);
|
|
|
|
|
|
|
|
|
|
trans->ctx.table->flags = nft_trans_table_flags(trans);
|
|
|
|
|
trans->ctx.table->flags &= ~__NFT_TABLE_F_UPDATE;
|
|
|
|
|
} else {
|
|
|
|
|
nft_clear(net, trans->ctx.table);
|
|
|
|
|
}
|
|
|
|
|
@@ -8768,9 +8790,17 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
|
|
|
|
|
switch (trans->msg_type) {
|
|
|
|
|
case NFT_MSG_NEWTABLE:
|
|
|
|
|
if (nft_trans_table_update(trans)) {
|
|
|
|
|
if (nft_trans_table_state(trans) == NFT_TABLE_STATE_WAKEUP)
|
|
|
|
|
if (!(trans->ctx.table->flags & __NFT_TABLE_F_UPDATE)) {
|
|
|
|
|
nft_trans_destroy(trans);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (trans->ctx.table->flags & __NFT_TABLE_F_WAS_DORMANT) {
|
|
|
|
|
nf_tables_table_disable(net, trans->ctx.table);
|
|
|
|
|
|
|
|
|
|
trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
|
|
|
|
|
} else if (trans->ctx.table->flags & __NFT_TABLE_F_WAS_AWAKEN) {
|
|
|
|
|
trans->ctx.table->flags &= ~NFT_TABLE_F_DORMANT;
|
|
|
|
|
}
|
|
|
|
|
trans->ctx.table->flags &= ~__NFT_TABLE_F_UPDATE;
|
|
|
|
|
nft_trans_destroy(trans);
|
|
|
|
|
} else {
|
|
|
|
|
list_del_rcu(&trans->ctx.table->list);
|
|
|
|
|
|