Skip to content

Commit c3e1b00

Browse files
kaberummakynes
authored andcommitted
netfilter: nf_tables: add set element timeout support
Add API support for set element timeouts. Elements can have a individual timeout value specified, overriding the sets' default. Two new extension types are used for timeouts - the timeout value and the expiration time. The timeout value only exists if it differs from the default value. Signed-off-by: Patrick McHardy <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 761da29 commit c3e1b00

File tree

3 files changed

+75
-2
lines changed

3 files changed

+75
-2
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,12 +329,16 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
329329
* @NFT_SET_EXT_KEY: element key
330330
* @NFT_SET_EXT_DATA: mapping data
331331
* @NFT_SET_EXT_FLAGS: element flags
332+
* @NFT_SET_EXT_TIMEOUT: element timeout
333+
* @NFT_SET_EXT_EXPIRATION: element expiration time
332334
* @NFT_SET_EXT_NUM: number of extension types
333335
*/
334336
enum nft_set_extensions {
335337
NFT_SET_EXT_KEY,
336338
NFT_SET_EXT_DATA,
337339
NFT_SET_EXT_FLAGS,
340+
NFT_SET_EXT_TIMEOUT,
341+
NFT_SET_EXT_EXPIRATION,
338342
NFT_SET_EXT_NUM
339343
};
340344

@@ -431,6 +435,22 @@ static inline u8 *nft_set_ext_flags(const struct nft_set_ext *ext)
431435
return nft_set_ext(ext, NFT_SET_EXT_FLAGS);
432436
}
433437

438+
static inline u64 *nft_set_ext_timeout(const struct nft_set_ext *ext)
439+
{
440+
return nft_set_ext(ext, NFT_SET_EXT_TIMEOUT);
441+
}
442+
443+
static inline unsigned long *nft_set_ext_expiration(const struct nft_set_ext *ext)
444+
{
445+
return nft_set_ext(ext, NFT_SET_EXT_EXPIRATION);
446+
}
447+
448+
static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
449+
{
450+
return nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION) &&
451+
time_is_before_eq_jiffies(*nft_set_ext_expiration(ext));
452+
}
453+
434454
static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
435455
void *elem)
436456
{

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,12 +290,16 @@ enum nft_set_elem_flags {
290290
* @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data)
291291
* @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes)
292292
* @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
293+
* @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64)
294+
* @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
293295
*/
294296
enum nft_set_elem_attributes {
295297
NFTA_SET_ELEM_UNSPEC,
296298
NFTA_SET_ELEM_KEY,
297299
NFTA_SET_ELEM_DATA,
298300
NFTA_SET_ELEM_FLAGS,
301+
NFTA_SET_ELEM_TIMEOUT,
302+
NFTA_SET_ELEM_EXPIRATION,
299303
__NFTA_SET_ELEM_MAX
300304
};
301305
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)

net/netfilter/nf_tables_api.c

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2863,6 +2863,14 @@ const struct nft_set_ext_type nft_set_ext_types[] = {
28632863
.len = sizeof(u8),
28642864
.align = __alignof__(u8),
28652865
},
2866+
[NFT_SET_EXT_TIMEOUT] = {
2867+
.len = sizeof(u64),
2868+
.align = __alignof__(u64),
2869+
},
2870+
[NFT_SET_EXT_EXPIRATION] = {
2871+
.len = sizeof(unsigned long),
2872+
.align = __alignof__(unsigned long),
2873+
},
28662874
};
28672875
EXPORT_SYMBOL_GPL(nft_set_ext_types);
28682876

@@ -2874,6 +2882,7 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
28742882
[NFTA_SET_ELEM_KEY] = { .type = NLA_NESTED },
28752883
[NFTA_SET_ELEM_DATA] = { .type = NLA_NESTED },
28762884
[NFTA_SET_ELEM_FLAGS] = { .type = NLA_U32 },
2885+
[NFTA_SET_ELEM_TIMEOUT] = { .type = NLA_U64 },
28772886
};
28782887

28792888
static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
@@ -2935,6 +2944,25 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
29352944
htonl(*nft_set_ext_flags(ext))))
29362945
goto nla_put_failure;
29372946

2947+
if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
2948+
nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
2949+
cpu_to_be64(*nft_set_ext_timeout(ext))))
2950+
goto nla_put_failure;
2951+
2952+
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
2953+
unsigned long expires, now = jiffies;
2954+
2955+
expires = *nft_set_ext_expiration(ext);
2956+
if (time_before(now, expires))
2957+
expires -= now;
2958+
else
2959+
expires = 0;
2960+
2961+
if (nla_put_be64(skb, NFTA_SET_ELEM_EXPIRATION,
2962+
cpu_to_be64(jiffies_to_msecs(expires))))
2963+
goto nla_put_failure;
2964+
}
2965+
29382966
nla_nest_end(skb, nest);
29392967
return 0;
29402968

@@ -3158,7 +3186,7 @@ static void *nft_set_elem_init(const struct nft_set *set,
31583186
const struct nft_set_ext_tmpl *tmpl,
31593187
const struct nft_data *key,
31603188
const struct nft_data *data,
3161-
gfp_t gfp)
3189+
u64 timeout, gfp_t gfp)
31623190
{
31633191
struct nft_set_ext *ext;
31643192
void *elem;
@@ -3173,6 +3201,11 @@ static void *nft_set_elem_init(const struct nft_set *set,
31733201
memcpy(nft_set_ext_key(ext), key, set->klen);
31743202
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
31753203
memcpy(nft_set_ext_data(ext), data, set->dlen);
3204+
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION))
3205+
*nft_set_ext_expiration(ext) =
3206+
jiffies + msecs_to_jiffies(timeout);
3207+
if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT))
3208+
*nft_set_ext_timeout(ext) = timeout;
31763209

31773210
return elem;
31783211
}
@@ -3201,6 +3234,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
32013234
struct nft_data data;
32023235
enum nft_registers dreg;
32033236
struct nft_trans *trans;
3237+
u64 timeout;
32043238
u32 flags;
32053239
int err;
32063240

@@ -3241,6 +3275,15 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
32413275
return -EINVAL;
32423276
}
32433277

3278+
timeout = 0;
3279+
if (nla[NFTA_SET_ELEM_TIMEOUT] != NULL) {
3280+
if (!(set->flags & NFT_SET_TIMEOUT))
3281+
return -EINVAL;
3282+
timeout = be64_to_cpu(nla_get_be64(nla[NFTA_SET_ELEM_TIMEOUT]));
3283+
} else if (set->flags & NFT_SET_TIMEOUT) {
3284+
timeout = set->timeout;
3285+
}
3286+
32443287
err = nft_data_init(ctx, &elem.key, &d1, nla[NFTA_SET_ELEM_KEY]);
32453288
if (err < 0)
32463289
goto err1;
@@ -3249,6 +3292,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
32493292
goto err2;
32503293

32513294
nft_set_ext_add(&tmpl, NFT_SET_EXT_KEY);
3295+
if (timeout > 0) {
3296+
nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
3297+
if (timeout != set->timeout)
3298+
nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
3299+
}
32523300

32533301
if (nla[NFTA_SET_ELEM_DATA] != NULL) {
32543302
err = nft_data_init(ctx, &data, &d2, nla[NFTA_SET_ELEM_DATA]);
@@ -3277,7 +3325,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
32773325
}
32783326

32793327
err = -ENOMEM;
3280-
elem.priv = nft_set_elem_init(set, &tmpl, &elem.key, &data, GFP_KERNEL);
3328+
elem.priv = nft_set_elem_init(set, &tmpl, &elem.key, &data,
3329+
timeout, GFP_KERNEL);
32813330
if (elem.priv == NULL)
32823331
goto err3;
32833332

0 commit comments

Comments
 (0)