[nf-next] src: enable set expiration date for set elements
diff mbox series

Message ID 20190617161424.gc46x7z5nv24m6pz@nevthink
State Changes Requested
Delegated to: Pablo Neira
Headers show
Series
  • [nf-next] src: enable set expiration date for set elements
Related show

Commit Message

Laura Garcia Liebana June 17, 2019, 4:14 p.m. UTC
Currently, the expiration of every element in a set or map
is a read-only parameter generated at kernel side.

This change will permit to set a certain expiration date
per element that will be required, for example, during
stateful replication among several nodes.

This patch handles the NFTA_SET_ELEM_EXPIRATION in order
to configure the expiration parameter per element, or
will use the timeout in the case that the expiration
is not set.

Signed-off-by: Laura Garcia Liebana <nevola@gmail.com>
---
 include/net/netfilter/nf_tables.h |  2 +-
 net/netfilter/nf_tables_api.c     | 26 ++++++++++++++++++++------
 net/netfilter/nft_dynset.c        |  5 ++++-
 3 files changed, 25 insertions(+), 8 deletions(-)

Comments

Pablo Neira Ayuso June 17, 2019, 10:09 p.m. UTC | #1
Hi Laura,

On Mon, Jun 17, 2019 at 06:14:24PM +0200, Laura Garcia Liebana wrote:
[...]
> diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
> index 8394560aa695..df19844e994f 100644
> --- a/net/netfilter/nft_dynset.c
> +++ b/net/netfilter/nft_dynset.c
> @@ -24,6 +24,7 @@ struct nft_dynset {
>  	enum nft_registers		sreg_data:8;
>  	bool				invert;
>  	u64				timeout;
> +	u64				expiration;
>  	struct nft_expr			*expr;
>  	struct nft_set_binding		binding;
>  };
> @@ -51,16 +52,18 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
>  	const struct nft_dynset *priv = nft_expr_priv(expr);
>  	struct nft_set_ext *ext;
>  	u64 timeout;
> +	u64 expiration;
>  	void *elem;
>  
>  	if (!atomic_add_unless(&set->nelems, 1, set->size))
>  		return NULL;
>  
>  	timeout = priv->timeout ? : set->timeout;
> +	expiration = priv->expiration;
>  	elem = nft_set_elem_init(set, &priv->tmpl,
>  				 &regs->data[priv->sreg_key],
>  				 &regs->data[priv->sreg_data],
> -				 timeout, GFP_ATOMIC);
> +				 timeout, expiration, GFP_ATOMIC);
                                          ^^^^^^^^^^

Probably better to replace 'expiration' by 0? priv->expiration is
never used / always set to zero, right?

Thanks!
Laura Garcia Liebana June 18, 2019, 8:36 a.m. UTC | #2
Hi Pablo,

On Tue, Jun 18, 2019 at 12:09 AM Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>
> Hi Laura,
>
> On Mon, Jun 17, 2019 at 06:14:24PM +0200, Laura Garcia Liebana wrote:
> [...]
> > diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
> > index 8394560aa695..df19844e994f 100644
> > --- a/net/netfilter/nft_dynset.c
> > +++ b/net/netfilter/nft_dynset.c
> > @@ -24,6 +24,7 @@ struct nft_dynset {
> >       enum nft_registers              sreg_data:8;
> >       bool                            invert;
> >       u64                             timeout;
> > +     u64                             expiration;
> >       struct nft_expr                 *expr;
> >       struct nft_set_binding          binding;
> >  };
> > @@ -51,16 +52,18 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
> >       const struct nft_dynset *priv = nft_expr_priv(expr);
> >       struct nft_set_ext *ext;
> >       u64 timeout;
> > +     u64 expiration;
> >       void *elem;
> >
> >       if (!atomic_add_unless(&set->nelems, 1, set->size))
> >               return NULL;
> >
> >       timeout = priv->timeout ? : set->timeout;
> > +     expiration = priv->expiration;
> >       elem = nft_set_elem_init(set, &priv->tmpl,
> >                                &regs->data[priv->sreg_key],
> >                                &regs->data[priv->sreg_data],
> > -                              timeout, GFP_ATOMIC);
> > +                              timeout, expiration, GFP_ATOMIC);
>                                           ^^^^^^^^^^
>
> Probably better to replace 'expiration' by 0? priv->expiration is
> never used / always set to zero, right?
>

That's right, in this case could be always set to 0. Will send an v2.

Thank you.

Patch
diff mbox series

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 5b8624ae4a27..9e8493aad49d 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -636,7 +636,7 @@  static inline struct nft_object **nft_set_ext_obj(const struct nft_set_ext *ext)
 void *nft_set_elem_init(const struct nft_set *set,
 			const struct nft_set_ext_tmpl *tmpl,
 			const u32 *key, const u32 *data,
-			u64 timeout, gfp_t gfp);
+			u64 timeout, u64 expiration, gfp_t gfp);
 void nft_set_elem_destroy(const struct nft_set *set, void *elem,
 			  bool destroy_expr);
 
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index d444405211c5..412bb85e9d29 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -3873,6 +3873,7 @@  static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
 	[NFTA_SET_ELEM_DATA]		= { .type = NLA_NESTED },
 	[NFTA_SET_ELEM_FLAGS]		= { .type = NLA_U32 },
 	[NFTA_SET_ELEM_TIMEOUT]		= { .type = NLA_U64 },
+	[NFTA_SET_ELEM_EXPIRATION]	= { .type = NLA_U64 },
 	[NFTA_SET_ELEM_USERDATA]	= { .type = NLA_BINARY,
 					    .len = NFT_USERDATA_MAXLEN },
 	[NFTA_SET_ELEM_EXPR]		= { .type = NLA_NESTED },
@@ -4326,7 +4327,7 @@  static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx,
 void *nft_set_elem_init(const struct nft_set *set,
 			const struct nft_set_ext_tmpl *tmpl,
 			const u32 *key, const u32 *data,
-			u64 timeout, gfp_t gfp)
+			u64 timeout, u64 expiration, gfp_t gfp)
 {
 	struct nft_set_ext *ext;
 	void *elem;
@@ -4341,9 +4342,11 @@  void *nft_set_elem_init(const struct nft_set *set,
 	memcpy(nft_set_ext_key(ext), key, set->klen);
 	if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
 		memcpy(nft_set_ext_data(ext), data, set->dlen);
-	if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION))
-		*nft_set_ext_expiration(ext) =
-			get_jiffies_64() + timeout;
+	if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
+		*nft_set_ext_expiration(ext) = get_jiffies_64() + expiration;
+		if (expiration == 0)
+			*nft_set_ext_expiration(ext) += timeout;
+	}
 	if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT))
 		*nft_set_ext_timeout(ext) = timeout;
 
@@ -4408,6 +4411,7 @@  static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
 	struct nft_trans *trans;
 	u32 flags = 0;
 	u64 timeout;
+	u64 expiration;
 	u8 ulen;
 	int err;
 
@@ -4451,6 +4455,16 @@  static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
 		timeout = set->timeout;
 	}
 
+	expiration = 0;
+	if (nla[NFTA_SET_ELEM_EXPIRATION] != NULL) {
+		if (!(set->flags & NFT_SET_TIMEOUT))
+			return -EINVAL;
+		err = nf_msecs_to_jiffies64(nla[NFTA_SET_ELEM_EXPIRATION],
+					    &expiration);
+		if (err)
+			return err;
+	}
+
 	err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &d1,
 			    nla[NFTA_SET_ELEM_KEY]);
 	if (err < 0)
@@ -4533,7 +4547,7 @@  static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
 
 	err = -ENOMEM;
 	elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, data.data,
-				      timeout, GFP_KERNEL);
+				      timeout, expiration, GFP_KERNEL);
 	if (elem.priv == NULL)
 		goto err3;
 
@@ -4735,7 +4749,7 @@  static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
 
 	err = -ENOMEM;
 	elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, NULL, 0,
-				      GFP_KERNEL);
+				      0, GFP_KERNEL);
 	if (elem.priv == NULL)
 		goto err2;
 
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index 8394560aa695..df19844e994f 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -24,6 +24,7 @@  struct nft_dynset {
 	enum nft_registers		sreg_data:8;
 	bool				invert;
 	u64				timeout;
+	u64				expiration;
 	struct nft_expr			*expr;
 	struct nft_set_binding		binding;
 };
@@ -51,16 +52,18 @@  static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
 	const struct nft_dynset *priv = nft_expr_priv(expr);
 	struct nft_set_ext *ext;
 	u64 timeout;
+	u64 expiration;
 	void *elem;
 
 	if (!atomic_add_unless(&set->nelems, 1, set->size))
 		return NULL;
 
 	timeout = priv->timeout ? : set->timeout;
+	expiration = priv->expiration;
 	elem = nft_set_elem_init(set, &priv->tmpl,
 				 &regs->data[priv->sreg_key],
 				 &regs->data[priv->sreg_data],
-				 timeout, GFP_ATOMIC);
+				 timeout, expiration, GFP_ATOMIC);
 	if (elem == NULL)
 		goto err1;