mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
netfilter: nf_tables: honor set timeout and garbage collection updates
Set timeout and garbage collection interval updates are ignored on
updates. Add transaction to update global set element timeout and
garbage collection interval.
Fixes: 96518518cc
("netfilter: add nftables")
Suggested-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
f6594c372a
commit
123b99619c
@ -597,7 +597,9 @@ void *nft_set_catchall_gc(const struct nft_set *set);
|
||||
|
||||
static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
|
||||
{
|
||||
return set->gc_int ? msecs_to_jiffies(set->gc_int) : HZ;
|
||||
u32 gc_int = READ_ONCE(set->gc_int);
|
||||
|
||||
return gc_int ? msecs_to_jiffies(gc_int) : HZ;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1570,6 +1572,9 @@ struct nft_trans_rule {
|
||||
struct nft_trans_set {
|
||||
struct nft_set *set;
|
||||
u32 set_id;
|
||||
u32 gc_int;
|
||||
u64 timeout;
|
||||
bool update;
|
||||
bool bound;
|
||||
};
|
||||
|
||||
@ -1579,6 +1584,12 @@ struct nft_trans_set {
|
||||
(((struct nft_trans_set *)trans->data)->set_id)
|
||||
#define nft_trans_set_bound(trans) \
|
||||
(((struct nft_trans_set *)trans->data)->bound)
|
||||
#define nft_trans_set_update(trans) \
|
||||
(((struct nft_trans_set *)trans->data)->update)
|
||||
#define nft_trans_set_timeout(trans) \
|
||||
(((struct nft_trans_set *)trans->data)->timeout)
|
||||
#define nft_trans_set_gc_int(trans) \
|
||||
(((struct nft_trans_set *)trans->data)->gc_int)
|
||||
|
||||
struct nft_trans_chain {
|
||||
bool update;
|
||||
|
@ -465,8 +465,9 @@ static int nft_delrule_by_chain(struct nft_ctx *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,
|
||||
struct nft_set *set)
|
||||
static int __nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,
|
||||
struct nft_set *set,
|
||||
const struct nft_set_desc *desc)
|
||||
{
|
||||
struct nft_trans *trans;
|
||||
|
||||
@ -474,17 +475,28 @@ static int nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,
|
||||
if (trans == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] != NULL) {
|
||||
if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] && !desc) {
|
||||
nft_trans_set_id(trans) =
|
||||
ntohl(nla_get_be32(ctx->nla[NFTA_SET_ID]));
|
||||
nft_activate_next(ctx->net, set);
|
||||
}
|
||||
nft_trans_set(trans) = set;
|
||||
if (desc) {
|
||||
nft_trans_set_update(trans) = true;
|
||||
nft_trans_set_gc_int(trans) = desc->gc_int;
|
||||
nft_trans_set_timeout(trans) = desc->timeout;
|
||||
}
|
||||
nft_trans_commit_list_add_tail(ctx->net, trans);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,
|
||||
struct nft_set *set)
|
||||
{
|
||||
return __nft_trans_set_add(ctx, msg_type, set, NULL);
|
||||
}
|
||||
|
||||
static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set)
|
||||
{
|
||||
int err;
|
||||
@ -4044,8 +4056,10 @@ static int nf_tables_fill_set_concat(struct sk_buff *skb,
|
||||
static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
|
||||
const struct nft_set *set, u16 event, u16 flags)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
u64 timeout = READ_ONCE(set->timeout);
|
||||
u32 gc_int = READ_ONCE(set->gc_int);
|
||||
u32 portid = ctx->portid;
|
||||
struct nlmsghdr *nlh;
|
||||
struct nlattr *nest;
|
||||
u32 seq = ctx->seq;
|
||||
int i;
|
||||
@ -4081,13 +4095,13 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
|
||||
nla_put_be32(skb, NFTA_SET_OBJ_TYPE, htonl(set->objtype)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (set->timeout &&
|
||||
if (timeout &&
|
||||
nla_put_be64(skb, NFTA_SET_TIMEOUT,
|
||||
nf_jiffies64_to_msecs(set->timeout),
|
||||
nf_jiffies64_to_msecs(timeout),
|
||||
NFTA_SET_PAD))
|
||||
goto nla_put_failure;
|
||||
if (set->gc_int &&
|
||||
nla_put_be32(skb, NFTA_SET_GC_INTERVAL, htonl(set->gc_int)))
|
||||
if (gc_int &&
|
||||
nla_put_be32(skb, NFTA_SET_GC_INTERVAL, htonl(gc_int)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (set->policy != NFT_SET_POL_PERFORMANCE) {
|
||||
@ -4632,7 +4646,10 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
for (i = 0; i < num_exprs; i++)
|
||||
nft_expr_destroy(&ctx, exprs[i]);
|
||||
|
||||
return err;
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return __nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set, &desc);
|
||||
}
|
||||
|
||||
if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
|
||||
@ -6070,7 +6087,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
|
||||
return err;
|
||||
} else if (set->flags & NFT_SET_TIMEOUT &&
|
||||
!(flags & NFT_SET_ELEM_INTERVAL_END)) {
|
||||
timeout = set->timeout;
|
||||
timeout = READ_ONCE(set->timeout);
|
||||
}
|
||||
|
||||
expiration = 0;
|
||||
@ -6171,7 +6188,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
|
||||
if (err < 0)
|
||||
goto err_parse_key_end;
|
||||
|
||||
if (timeout != set->timeout) {
|
||||
if (timeout != READ_ONCE(set->timeout)) {
|
||||
err = nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
|
||||
if (err < 0)
|
||||
goto err_parse_key_end;
|
||||
@ -9093,14 +9110,20 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
|
||||
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
|
||||
break;
|
||||
case NFT_MSG_NEWSET:
|
||||
nft_clear(net, nft_trans_set(trans));
|
||||
/* This avoids hitting -EBUSY when deleting the table
|
||||
* from the transaction.
|
||||
*/
|
||||
if (nft_set_is_anonymous(nft_trans_set(trans)) &&
|
||||
!list_empty(&nft_trans_set(trans)->bindings))
|
||||
trans->ctx.table->use--;
|
||||
if (nft_trans_set_update(trans)) {
|
||||
struct nft_set *set = nft_trans_set(trans);
|
||||
|
||||
WRITE_ONCE(set->timeout, nft_trans_set_timeout(trans));
|
||||
WRITE_ONCE(set->gc_int, nft_trans_set_gc_int(trans));
|
||||
} else {
|
||||
nft_clear(net, nft_trans_set(trans));
|
||||
/* This avoids hitting -EBUSY when deleting the table
|
||||
* from the transaction.
|
||||
*/
|
||||
if (nft_set_is_anonymous(nft_trans_set(trans)) &&
|
||||
!list_empty(&nft_trans_set(trans)->bindings))
|
||||
trans->ctx.table->use--;
|
||||
}
|
||||
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
|
||||
NFT_MSG_NEWSET, GFP_KERNEL);
|
||||
nft_trans_destroy(trans);
|
||||
@ -9322,6 +9345,10 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
|
||||
nft_trans_destroy(trans);
|
||||
break;
|
||||
case NFT_MSG_NEWSET:
|
||||
if (nft_trans_set_update(trans)) {
|
||||
nft_trans_destroy(trans);
|
||||
break;
|
||||
}
|
||||
trans->ctx.table->use--;
|
||||
if (nft_trans_set_bound(trans)) {
|
||||
nft_trans_destroy(trans);
|
||||
|
Loading…
Reference in New Issue
Block a user