Skip to content

Commit 563125a

Browse files
committed
netfilter: nftables: generalize set extension to support for several expressions
This patch replaces NFT_SET_EXPR by NFT_SET_EXT_EXPRESSIONS. This new extension allows to attach several expressions to one set element (not only one single expression as NFT_SET_EXPR provides). This patch prepares for support for several expressions per set element in the netlink userspace API. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 92b211a commit 563125a

File tree

4 files changed

+196
-55
lines changed

4 files changed

+196
-55
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,20 @@ struct nft_set_type {
421421
};
422422
#define to_set_type(o) container_of(o, struct nft_set_type, ops)
423423

424+
struct nft_set_elem_expr {
425+
u8 size;
426+
unsigned char data[]
427+
__attribute__((aligned(__alignof__(struct nft_expr))));
428+
};
429+
430+
#define nft_setelem_expr_at(__elem_expr, __offset) \
431+
((struct nft_expr *)&__elem_expr->data[__offset])
432+
433+
#define nft_setelem_expr_foreach(__expr, __elem_expr, __size) \
434+
for (__expr = nft_setelem_expr_at(__elem_expr, 0), __size = 0; \
435+
__size < (__elem_expr)->size; \
436+
__size += (__expr)->ops->size, __expr = ((void *)(__expr)) + (__expr)->ops->size)
437+
424438
#define NFT_SET_EXPR_MAX 2
425439

426440
/**
@@ -547,7 +561,7 @@ void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set);
547561
* @NFT_SET_EXT_TIMEOUT: element timeout
548562
* @NFT_SET_EXT_EXPIRATION: element expiration time
549563
* @NFT_SET_EXT_USERDATA: user data associated with the element
550-
* @NFT_SET_EXT_EXPR: expression assiociated with the element
564+
* @NFT_SET_EXT_EXPRESSIONS: expressions assiciated with the element
551565
* @NFT_SET_EXT_OBJREF: stateful object reference associated with element
552566
* @NFT_SET_EXT_NUM: number of extension types
553567
*/
@@ -559,7 +573,7 @@ enum nft_set_extensions {
559573
NFT_SET_EXT_TIMEOUT,
560574
NFT_SET_EXT_EXPIRATION,
561575
NFT_SET_EXT_USERDATA,
562-
NFT_SET_EXT_EXPR,
576+
NFT_SET_EXT_EXPRESSIONS,
563577
NFT_SET_EXT_OBJREF,
564578
NFT_SET_EXT_NUM
565579
};
@@ -677,9 +691,9 @@ static inline struct nft_userdata *nft_set_ext_userdata(const struct nft_set_ext
677691
return nft_set_ext(ext, NFT_SET_EXT_USERDATA);
678692
}
679693

680-
static inline struct nft_expr *nft_set_ext_expr(const struct nft_set_ext *ext)
694+
static inline struct nft_set_elem_expr *nft_set_ext_expr(const struct nft_set_ext *ext)
681695
{
682-
return nft_set_ext(ext, NFT_SET_EXT_EXPR);
696+
return nft_set_ext(ext, NFT_SET_EXT_EXPRESSIONS);
683697
}
684698

685699
static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
@@ -909,11 +923,17 @@ static inline void nft_set_elem_update_expr(const struct nft_set_ext *ext,
909923
struct nft_regs *regs,
910924
const struct nft_pktinfo *pkt)
911925
{
926+
struct nft_set_elem_expr *elem_expr;
912927
struct nft_expr *expr;
913-
914-
if (__nft_set_ext_exists(ext, NFT_SET_EXT_EXPR)) {
915-
expr = nft_set_ext_expr(ext);
916-
expr->ops->eval(expr, regs, pkt);
928+
u32 size;
929+
930+
if (__nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS)) {
931+
elem_expr = nft_set_ext_expr(ext);
932+
nft_setelem_expr_foreach(expr, elem_expr, size) {
933+
expr->ops->eval(expr, regs, pkt);
934+
if (regs->verdict.code == NFT_BREAK)
935+
return;
936+
}
917937
}
918938
}
919939

net/netfilter/nf_tables_api.c

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4496,8 +4496,8 @@ const struct nft_set_ext_type nft_set_ext_types[] = {
44964496
[NFT_SET_EXT_DATA] = {
44974497
.align = __alignof__(u32),
44984498
},
4499-
[NFT_SET_EXT_EXPR] = {
4500-
.align = __alignof__(struct nft_expr),
4499+
[NFT_SET_EXT_EXPRESSIONS] = {
4500+
.align = __alignof__(struct nft_set_elem_expr),
45014501
},
45024502
[NFT_SET_EXT_OBJREF] = {
45034503
.len = sizeof(struct nft_object *),
@@ -4573,6 +4573,29 @@ static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
45734573
return 0;
45744574
}
45754575

4576+
static int nft_set_elem_expr_dump(struct sk_buff *skb,
4577+
const struct nft_set *set,
4578+
const struct nft_set_ext *ext)
4579+
{
4580+
struct nft_set_elem_expr *elem_expr;
4581+
u32 size, num_exprs = 0;
4582+
struct nft_expr *expr;
4583+
4584+
elem_expr = nft_set_ext_expr(ext);
4585+
nft_setelem_expr_foreach(expr, elem_expr, size)
4586+
num_exprs++;
4587+
4588+
if (num_exprs == 1) {
4589+
expr = nft_setelem_expr_at(elem_expr, 0);
4590+
if (nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, expr) < 0)
4591+
return -1;
4592+
4593+
return 0;
4594+
}
4595+
4596+
return 0;
4597+
}
4598+
45764599
static int nf_tables_fill_setelem(struct sk_buff *skb,
45774600
const struct nft_set *set,
45784601
const struct nft_set_elem *elem)
@@ -4600,8 +4623,8 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
46004623
set->dlen) < 0)
46014624
goto nla_put_failure;
46024625

4603-
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPR) &&
4604-
nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, nft_set_ext_expr(ext)) < 0)
4626+
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS) &&
4627+
nft_set_elem_expr_dump(skb, set, ext))
46054628
goto nla_put_failure;
46064629

46074630
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) &&
@@ -5096,8 +5119,8 @@ void *nft_set_elem_init(const struct nft_set *set,
50965119
return elem;
50975120
}
50985121

5099-
static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
5100-
struct nft_expr *expr)
5122+
static void __nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
5123+
struct nft_expr *expr)
51015124
{
51025125
if (expr->ops->destroy_clone) {
51035126
expr->ops->destroy_clone(ctx, expr);
@@ -5107,6 +5130,16 @@ static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
51075130
}
51085131
}
51095132

5133+
static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
5134+
struct nft_set_elem_expr *elem_expr)
5135+
{
5136+
struct nft_expr *expr;
5137+
u32 size;
5138+
5139+
nft_setelem_expr_foreach(expr, elem_expr, size)
5140+
__nft_set_elem_expr_destroy(ctx, expr);
5141+
}
5142+
51105143
void nft_set_elem_destroy(const struct nft_set *set, void *elem,
51115144
bool destroy_expr)
51125145
{
@@ -5119,7 +5152,7 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
51195152
nft_data_release(nft_set_ext_key(ext), NFT_DATA_VALUE);
51205153
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
51215154
nft_data_release(nft_set_ext_data(ext), set->dtype);
5122-
if (destroy_expr && nft_set_ext_exists(ext, NFT_SET_EXT_EXPR))
5155+
if (destroy_expr && nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
51235156
nft_set_elem_expr_destroy(&ctx, nft_set_ext_expr(ext));
51245157

51255158
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
@@ -5136,7 +5169,7 @@ static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
51365169
{
51375170
struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
51385171

5139-
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPR))
5172+
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
51405173
nft_set_elem_expr_destroy(ctx, nft_set_ext_expr(ext));
51415174

51425175
kfree(elem);
@@ -5171,6 +5204,18 @@ static int nft_set_elem_expr_clone(const struct nft_ctx *ctx,
51715204
return -ENOMEM;
51725205
}
51735206

5207+
static void nft_set_elem_expr_setup(const struct nft_set_ext *ext, int i,
5208+
struct nft_expr *expr_array[])
5209+
{
5210+
struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext);
5211+
struct nft_expr *expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
5212+
5213+
memcpy(expr, expr_array[i], expr_array[i]->ops->size);
5214+
elem_expr->size += expr_array[i]->ops->size;
5215+
kfree(expr_array[i]);
5216+
expr_array[i] = NULL;
5217+
}
5218+
51745219
static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
51755220
const struct nlattr *attr, u32 nlmsg_flags)
51765221
{
@@ -5186,11 +5231,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
51865231
struct nft_data_desc desc;
51875232
enum nft_registers dreg;
51885233
struct nft_trans *trans;
5189-
u32 flags = 0;
5234+
u32 flags = 0, size = 0;
51905235
u64 timeout;
51915236
u64 expiration;
5192-
u8 ulen;
51935237
int err, i;
5238+
u8 ulen;
51945239

51955240
err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr,
51965241
nft_set_elem_policy, NULL);
@@ -5293,9 +5338,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
52935338
nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
52945339
}
52955340

5296-
if (set->num_exprs == 1)
5297-
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_EXPR,
5298-
expr_array[0]->ops->size);
5341+
if (set->num_exprs) {
5342+
for (i = 0; i < set->num_exprs; i++)
5343+
size += expr_array[i]->ops->size;
5344+
5345+
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_EXPRESSIONS,
5346+
sizeof(struct nft_set_elem_expr) +
5347+
size);
5348+
}
52995349

53005350
if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
53015351
if (!(set->flags & NFT_SET_OBJECT)) {
@@ -5377,13 +5427,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
53775427
*nft_set_ext_obj(ext) = obj;
53785428
obj->use++;
53795429
}
5380-
if (set->num_exprs == 1) {
5381-
struct nft_expr *expr = expr_array[0];
5382-
5383-
memcpy(nft_set_ext_expr(ext), expr, expr->ops->size);
5384-
kfree(expr);
5385-
expr_array[0] = NULL;
5386-
}
5430+
for (i = 0; i < set->num_exprs; i++)
5431+
nft_set_elem_expr_setup(ext, i, expr_array);
53875432

53885433
trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
53895434
if (trans == NULL)

0 commit comments

Comments
 (0)