Commit 4c5daea9 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

netfilter: nf_tables: consolidate timeout extension for elements



Expiration and timeout are stored in separated set element extensions,
but they are tightly coupled. Consolidate them in a single extension to
simplify and prepare for set element updates.

Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 73d3c04b
Loading
Loading
Loading
Loading
+8 −10
Original line number Diff line number Diff line
@@ -687,7 +687,6 @@ void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set);
 *	@NFT_SET_EXT_DATA: mapping data
 *	@NFT_SET_EXT_FLAGS: element flags
 *	@NFT_SET_EXT_TIMEOUT: element timeout
 *	@NFT_SET_EXT_EXPIRATION: element expiration time
 *	@NFT_SET_EXT_USERDATA: user data associated with the element
 *	@NFT_SET_EXT_EXPRESSIONS: expressions associated with the element
 *	@NFT_SET_EXT_OBJREF: stateful object reference associated with element
@@ -699,7 +698,6 @@ enum nft_set_extensions {
	NFT_SET_EXT_DATA,
	NFT_SET_EXT_FLAGS,
	NFT_SET_EXT_TIMEOUT,
	NFT_SET_EXT_EXPIRATION,
	NFT_SET_EXT_USERDATA,
	NFT_SET_EXT_EXPRESSIONS,
	NFT_SET_EXT_OBJREF,
@@ -811,14 +809,14 @@ static inline u8 *nft_set_ext_flags(const struct nft_set_ext *ext)
	return nft_set_ext(ext, NFT_SET_EXT_FLAGS);
}

static inline u64 *nft_set_ext_timeout(const struct nft_set_ext *ext)
{
	return nft_set_ext(ext, NFT_SET_EXT_TIMEOUT);
}
struct nft_timeout {
	u64	timeout;
	u64	expiration;
};

static inline u64 *nft_set_ext_expiration(const struct nft_set_ext *ext)
static inline struct nft_timeout *nft_set_ext_timeout(const struct nft_set_ext *ext)
{
	return nft_set_ext(ext, NFT_SET_EXT_EXPIRATION);
	return nft_set_ext(ext, NFT_SET_EXT_TIMEOUT);
}

static inline struct nft_userdata *nft_set_ext_userdata(const struct nft_set_ext *ext)
@@ -834,8 +832,8 @@ static inline struct nft_set_elem_expr *nft_set_ext_expr(const struct nft_set_ex
static inline bool __nft_set_elem_expired(const struct nft_set_ext *ext,
					  u64 tstamp)
{
	return nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION) &&
	       time_after_eq64(tstamp, READ_ONCE(*nft_set_ext_expiration(ext)));
	return nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
	       time_after_eq64(tstamp, READ_ONCE(nft_set_ext_timeout(ext)->expiration));
}

static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
+17 −26
Original line number Diff line number Diff line
@@ -5694,12 +5694,8 @@ const struct nft_set_ext_type nft_set_ext_types[] = {
		.align	= __alignof__(u8),
	},
	[NFT_SET_EXT_TIMEOUT]		= {
		.len	= sizeof(u64),
		.align	= __alignof__(u64),
	},
	[NFT_SET_EXT_EXPIRATION]	= {
		.len	= sizeof(u64),
		.align	= __alignof__(u64),
		.len	= sizeof(struct nft_timeout),
		.align	= __alignof__(struct nft_timeout),
	},
	[NFT_SET_EXT_USERDATA]		= {
		.len	= sizeof(struct nft_userdata),
@@ -5818,16 +5814,16 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
		         htonl(*nft_set_ext_flags(ext))))
		goto nla_put_failure;

	if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
	if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT)) {
		u64 expires, now = get_jiffies_64();

		if (nft_set_ext_timeout(ext)->timeout != READ_ONCE(set->timeout) &&
		    nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
			 nf_jiffies64_to_msecs(*nft_set_ext_timeout(ext)),
				 nf_jiffies64_to_msecs(nft_set_ext_timeout(ext)->timeout),
				 NFTA_SET_ELEM_PAD))
			goto nla_put_failure;

	if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
		u64 expires, now = get_jiffies_64();

		expires = READ_ONCE(*nft_set_ext_expiration(ext));
		expires = READ_ONCE(nft_set_ext_timeout(ext)->expiration);
		if (time_before64(now, expires))
			expires -= now;
		else
@@ -6499,13 +6495,14 @@ struct nft_elem_priv *nft_set_elem_init(const struct nft_set *set,
			       nft_set_ext_data(ext), data, set->dlen) < 0)
		goto err_ext_check;

	if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
		*nft_set_ext_expiration(ext) = get_jiffies_64() + expiration;
	if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT)) {
		nft_set_ext_timeout(ext)->timeout = timeout;

		if (expiration == 0)
			*nft_set_ext_expiration(ext) += timeout;
			expiration = timeout;

		nft_set_ext_timeout(ext)->expiration = get_jiffies_64() + expiration;
	}
	if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT))
		*nft_set_ext_timeout(ext) = timeout;

	return elem;

@@ -7019,16 +7016,10 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
	}

	if (timeout > 0) {
		err = nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
		if (err < 0)
			goto err_parse_key_end;

		if (timeout != set->timeout) {
		err = nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
		if (err < 0)
			goto err_parse_key_end;
	}
	}

	if (num_exprs) {
		for (i = 0; i < num_exprs; i++)
+5 −8
Original line number Diff line number Diff line
@@ -94,9 +94,9 @@ void nft_dynset_eval(const struct nft_expr *expr,
	if (set->ops->update(set, &regs->data[priv->sreg_key], nft_dynset_new,
			     expr, regs, &ext)) {
		if (priv->op == NFT_DYNSET_OP_UPDATE &&
		    nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
		    nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT)) {
			timeout = priv->timeout ? : READ_ONCE(set->timeout);
			WRITE_ONCE(*nft_set_ext_expiration(ext), get_jiffies_64() + timeout);
			WRITE_ONCE(nft_set_ext_timeout(ext)->expiration, get_jiffies_64() + timeout);
		}

		nft_set_elem_update_expr(ext, regs, pkt);
@@ -312,12 +312,9 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
	if (priv->num_exprs)
		nft_dynset_ext_add_expr(priv);

	if (set->flags & NFT_SET_TIMEOUT) {
		if (timeout || READ_ONCE(set->timeout)) {
	if (set->flags & NFT_SET_TIMEOUT &&
	    (timeout || READ_ONCE(set->timeout)))
		nft_set_ext_add(&priv->tmpl, NFT_SET_EXT_TIMEOUT);
			nft_set_ext_add(&priv->tmpl, NFT_SET_EXT_EXPIRATION);
		}
	}

	priv->timeout = timeout;