1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2015 Patrick McHardy <kaber@trash.net>
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/init.h>
9 #include <linux/netlink.h>
10 #include <linux/netfilter.h>
11 #include <linux/netfilter/nf_tables.h>
12 #include <net/netfilter/nf_tables.h>
13 #include <net/netfilter/nf_tables_core.h>
17 struct nft_set_ext_tmpl tmpl
;
18 enum nft_dynset_ops op
:8;
19 enum nft_registers sreg_key
:8;
20 enum nft_registers sreg_data
:8;
25 struct nft_expr
*expr_array
[NFT_SET_EXPR_MAX
];
26 struct nft_set_binding binding
;
29 static int nft_dynset_expr_setup(const struct nft_dynset
*priv
,
30 const struct nft_set_ext
*ext
)
32 struct nft_set_elem_expr
*elem_expr
= nft_set_ext_expr(ext
);
33 struct nft_expr
*expr
;
36 for (i
= 0; i
< priv
->num_exprs
; i
++) {
37 expr
= nft_setelem_expr_at(elem_expr
, elem_expr
->size
);
38 if (nft_expr_clone(expr
, priv
->expr_array
[i
]) < 0)
41 elem_expr
->size
+= priv
->expr_array
[i
]->ops
->size
;
47 static void *nft_dynset_new(struct nft_set
*set
, const struct nft_expr
*expr
,
48 struct nft_regs
*regs
)
50 const struct nft_dynset
*priv
= nft_expr_priv(expr
);
51 struct nft_set_ext
*ext
;
55 if (!atomic_add_unless(&set
->nelems
, 1, set
->size
))
58 timeout
= priv
->timeout
? : set
->timeout
;
59 elem
= nft_set_elem_init(set
, &priv
->tmpl
,
60 ®s
->data
[priv
->sreg_key
], NULL
,
61 ®s
->data
[priv
->sreg_data
],
62 timeout
, 0, GFP_ATOMIC
);
66 ext
= nft_set_elem_ext(set
, elem
);
67 if (priv
->num_exprs
&& nft_dynset_expr_setup(priv
, ext
) < 0)
73 nft_set_elem_destroy(set
, elem
, false);
76 atomic_dec(&set
->nelems
);
80 void nft_dynset_eval(const struct nft_expr
*expr
,
81 struct nft_regs
*regs
, const struct nft_pktinfo
*pkt
)
83 const struct nft_dynset
*priv
= nft_expr_priv(expr
);
84 struct nft_set
*set
= priv
->set
;
85 const struct nft_set_ext
*ext
;
88 if (priv
->op
== NFT_DYNSET_OP_DELETE
) {
89 set
->ops
->delete(set
, ®s
->data
[priv
->sreg_key
]);
93 if (set
->ops
->update(set
, ®s
->data
[priv
->sreg_key
], nft_dynset_new
,
95 if (priv
->op
== NFT_DYNSET_OP_UPDATE
&&
96 nft_set_ext_exists(ext
, NFT_SET_EXT_EXPIRATION
)) {
97 timeout
= priv
->timeout
? : set
->timeout
;
98 *nft_set_ext_expiration(ext
) = get_jiffies_64() + timeout
;
101 nft_set_elem_update_expr(ext
, regs
, pkt
);
104 regs
->verdict
.code
= NFT_BREAK
;
109 regs
->verdict
.code
= NFT_BREAK
;
112 static void nft_dynset_ext_add_expr(struct nft_dynset
*priv
)
117 for (i
= 0; i
< priv
->num_exprs
; i
++)
118 size
+= priv
->expr_array
[i
]->ops
->size
;
120 nft_set_ext_add_length(&priv
->tmpl
, NFT_SET_EXT_EXPRESSIONS
,
121 sizeof(struct nft_set_elem_expr
) + size
);
124 static struct nft_expr
*
125 nft_dynset_expr_alloc(const struct nft_ctx
*ctx
, const struct nft_set
*set
,
126 const struct nlattr
*attr
, int pos
)
128 struct nft_expr
*expr
;
131 expr
= nft_set_elem_expr_alloc(ctx
, set
, attr
);
135 if (set
->exprs
[pos
] && set
->exprs
[pos
]->ops
!= expr
->ops
) {
137 goto err_dynset_expr
;
143 nft_expr_destroy(ctx
, expr
);
147 static const struct nla_policy nft_dynset_policy
[NFTA_DYNSET_MAX
+ 1] = {
148 [NFTA_DYNSET_SET_NAME
] = { .type
= NLA_STRING
,
149 .len
= NFT_SET_MAXNAMELEN
- 1 },
150 [NFTA_DYNSET_SET_ID
] = { .type
= NLA_U32
},
151 [NFTA_DYNSET_OP
] = { .type
= NLA_U32
},
152 [NFTA_DYNSET_SREG_KEY
] = { .type
= NLA_U32
},
153 [NFTA_DYNSET_SREG_DATA
] = { .type
= NLA_U32
},
154 [NFTA_DYNSET_TIMEOUT
] = { .type
= NLA_U64
},
155 [NFTA_DYNSET_EXPR
] = { .type
= NLA_NESTED
},
156 [NFTA_DYNSET_FLAGS
] = { .type
= NLA_U32
},
157 [NFTA_DYNSET_EXPRESSIONS
] = { .type
= NLA_NESTED
},
160 static int nft_dynset_init(const struct nft_ctx
*ctx
,
161 const struct nft_expr
*expr
,
162 const struct nlattr
* const tb
[])
164 struct nft_dynset
*priv
= nft_expr_priv(expr
);
165 u8 genmask
= nft_genmask_next(ctx
->net
);
170 lockdep_assert_held(&ctx
->net
->nft
.commit_mutex
);
172 if (tb
[NFTA_DYNSET_SET_NAME
] == NULL
||
173 tb
[NFTA_DYNSET_OP
] == NULL
||
174 tb
[NFTA_DYNSET_SREG_KEY
] == NULL
)
177 if (tb
[NFTA_DYNSET_FLAGS
]) {
178 u32 flags
= ntohl(nla_get_be32(tb
[NFTA_DYNSET_FLAGS
]));
179 if (flags
& ~(NFT_DYNSET_F_INV
| NFT_DYNSET_F_EXPR
))
181 if (flags
& NFT_DYNSET_F_INV
)
183 if (flags
& NFT_DYNSET_F_EXPR
)
187 set
= nft_set_lookup_global(ctx
->net
, ctx
->table
,
188 tb
[NFTA_DYNSET_SET_NAME
],
189 tb
[NFTA_DYNSET_SET_ID
], genmask
);
193 if (set
->ops
->update
== NULL
)
196 if (set
->flags
& NFT_SET_CONSTANT
)
199 priv
->op
= ntohl(nla_get_be32(tb
[NFTA_DYNSET_OP
]));
201 case NFT_DYNSET_OP_ADD
:
202 case NFT_DYNSET_OP_DELETE
:
204 case NFT_DYNSET_OP_UPDATE
:
205 if (!(set
->flags
& NFT_SET_TIMEOUT
))
213 if (tb
[NFTA_DYNSET_TIMEOUT
] != NULL
) {
214 if (!(set
->flags
& NFT_SET_TIMEOUT
))
217 err
= nf_msecs_to_jiffies64(tb
[NFTA_DYNSET_TIMEOUT
], &timeout
);
222 priv
->sreg_key
= nft_parse_register(tb
[NFTA_DYNSET_SREG_KEY
]);
223 err
= nft_validate_register_load(priv
->sreg_key
, set
->klen
);
227 if (tb
[NFTA_DYNSET_SREG_DATA
] != NULL
) {
228 if (!(set
->flags
& NFT_SET_MAP
))
230 if (set
->dtype
== NFT_DATA_VERDICT
)
233 priv
->sreg_data
= nft_parse_register(tb
[NFTA_DYNSET_SREG_DATA
]);
234 err
= nft_validate_register_load(priv
->sreg_data
, set
->dlen
);
237 } else if (set
->flags
& NFT_SET_MAP
)
240 if ((tb
[NFTA_DYNSET_EXPR
] || tb
[NFTA_DYNSET_EXPRESSIONS
]) &&
241 !(set
->flags
& NFT_SET_EVAL
))
244 if (tb
[NFTA_DYNSET_EXPR
]) {
245 struct nft_expr
*dynset_expr
;
247 dynset_expr
= nft_dynset_expr_alloc(ctx
, set
,
248 tb
[NFTA_DYNSET_EXPR
], 0);
249 if (IS_ERR(dynset_expr
))
250 return PTR_ERR(dynset_expr
);
253 priv
->expr_array
[0] = dynset_expr
;
255 if (set
->num_exprs
> 1 ||
256 (set
->num_exprs
== 1 &&
257 dynset_expr
->ops
!= set
->exprs
[0]->ops
)) {
261 } else if (tb
[NFTA_DYNSET_EXPRESSIONS
]) {
262 struct nft_expr
*dynset_expr
;
270 nla_for_each_nested(tmp
, tb
[NFTA_DYNSET_EXPRESSIONS
], left
) {
271 if (i
== NFT_SET_EXPR_MAX
) {
275 if (nla_type(tmp
) != NFTA_LIST_ELEM
) {
279 dynset_expr
= nft_dynset_expr_alloc(ctx
, set
, tmp
, i
);
280 if (IS_ERR(dynset_expr
)) {
281 err
= PTR_ERR(dynset_expr
);
284 priv
->expr_array
[i
] = dynset_expr
;
287 if (set
->num_exprs
&&
288 dynset_expr
->ops
!= set
->exprs
[i
]->ops
) {
294 if (set
->num_exprs
&& set
->num_exprs
!= i
) {
300 nft_set_ext_prepare(&priv
->tmpl
);
301 nft_set_ext_add_length(&priv
->tmpl
, NFT_SET_EXT_KEY
, set
->klen
);
302 if (set
->flags
& NFT_SET_MAP
)
303 nft_set_ext_add_length(&priv
->tmpl
, NFT_SET_EXT_DATA
, set
->dlen
);
306 nft_dynset_ext_add_expr(priv
);
308 if (set
->flags
& NFT_SET_TIMEOUT
) {
309 if (timeout
|| set
->timeout
)
310 nft_set_ext_add(&priv
->tmpl
, NFT_SET_EXT_EXPIRATION
);
313 priv
->timeout
= timeout
;
315 err
= nf_tables_bind_set(ctx
, set
, &priv
->binding
);
326 for (i
= 0; i
< priv
->num_exprs
; i
++)
327 nft_expr_destroy(ctx
, priv
->expr_array
[i
]);
331 static void nft_dynset_deactivate(const struct nft_ctx
*ctx
,
332 const struct nft_expr
*expr
,
333 enum nft_trans_phase phase
)
335 struct nft_dynset
*priv
= nft_expr_priv(expr
);
337 nf_tables_deactivate_set(ctx
, priv
->set
, &priv
->binding
, phase
);
340 static void nft_dynset_activate(const struct nft_ctx
*ctx
,
341 const struct nft_expr
*expr
)
343 struct nft_dynset
*priv
= nft_expr_priv(expr
);
348 static void nft_dynset_destroy(const struct nft_ctx
*ctx
,
349 const struct nft_expr
*expr
)
351 struct nft_dynset
*priv
= nft_expr_priv(expr
);
354 for (i
= 0; i
< priv
->num_exprs
; i
++)
355 nft_expr_destroy(ctx
, priv
->expr_array
[i
]);
357 nf_tables_destroy_set(ctx
, priv
->set
);
360 static int nft_dynset_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
362 const struct nft_dynset
*priv
= nft_expr_priv(expr
);
363 u32 flags
= priv
->invert
? NFT_DYNSET_F_INV
: 0;
366 if (nft_dump_register(skb
, NFTA_DYNSET_SREG_KEY
, priv
->sreg_key
))
367 goto nla_put_failure
;
368 if (priv
->set
->flags
& NFT_SET_MAP
&&
369 nft_dump_register(skb
, NFTA_DYNSET_SREG_DATA
, priv
->sreg_data
))
370 goto nla_put_failure
;
371 if (nla_put_be32(skb
, NFTA_DYNSET_OP
, htonl(priv
->op
)))
372 goto nla_put_failure
;
373 if (nla_put_string(skb
, NFTA_DYNSET_SET_NAME
, priv
->set
->name
))
374 goto nla_put_failure
;
375 if (nla_put_be64(skb
, NFTA_DYNSET_TIMEOUT
,
376 nf_jiffies64_to_msecs(priv
->timeout
),
378 goto nla_put_failure
;
379 if (priv
->num_exprs
== 1) {
380 if (nft_expr_dump(skb
, NFTA_DYNSET_EXPR
, priv
->expr_array
[0]))
381 goto nla_put_failure
;
382 } else if (priv
->num_exprs
> 1) {
385 nest
= nla_nest_start_noflag(skb
, NFTA_DYNSET_EXPRESSIONS
);
387 goto nla_put_failure
;
389 for (i
= 0; i
< priv
->num_exprs
; i
++) {
390 if (nft_expr_dump(skb
, NFTA_LIST_ELEM
,
391 priv
->expr_array
[i
]))
392 goto nla_put_failure
;
394 nla_nest_end(skb
, nest
);
396 if (nla_put_be32(skb
, NFTA_DYNSET_FLAGS
, htonl(flags
)))
397 goto nla_put_failure
;
404 static const struct nft_expr_ops nft_dynset_ops
= {
405 .type
= &nft_dynset_type
,
406 .size
= NFT_EXPR_SIZE(sizeof(struct nft_dynset
)),
407 .eval
= nft_dynset_eval
,
408 .init
= nft_dynset_init
,
409 .destroy
= nft_dynset_destroy
,
410 .activate
= nft_dynset_activate
,
411 .deactivate
= nft_dynset_deactivate
,
412 .dump
= nft_dynset_dump
,
415 struct nft_expr_type nft_dynset_type __read_mostly
= {
417 .ops
= &nft_dynset_ops
,
418 .policy
= nft_dynset_policy
,
419 .maxattr
= NFTA_DYNSET_MAX
,
420 .owner
= THIS_MODULE
,