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;
23 struct nft_expr
*expr
;
24 struct nft_set_binding binding
;
27 static int nft_expr_clone(struct nft_expr
*dst
, struct nft_expr
*src
)
31 if (src
->ops
->clone
) {
33 err
= src
->ops
->clone(dst
, src
);
37 memcpy(dst
, src
, src
->ops
->size
);
40 __module_get(src
->ops
->type
->owner
);
44 static void *nft_dynset_new(struct nft_set
*set
, const struct nft_expr
*expr
,
45 struct nft_regs
*regs
)
47 const struct nft_dynset
*priv
= nft_expr_priv(expr
);
48 struct nft_set_ext
*ext
;
52 if (!atomic_add_unless(&set
->nelems
, 1, set
->size
))
55 timeout
= priv
->timeout
? : set
->timeout
;
56 elem
= nft_set_elem_init(set
, &priv
->tmpl
,
57 ®s
->data
[priv
->sreg_key
],
58 ®s
->data
[priv
->sreg_data
],
59 timeout
, 0, GFP_ATOMIC
);
63 ext
= nft_set_elem_ext(set
, elem
);
64 if (priv
->expr
!= NULL
&&
65 nft_expr_clone(nft_set_ext_expr(ext
), priv
->expr
) < 0)
71 nft_set_elem_destroy(set
, elem
, false);
74 atomic_dec(&set
->nelems
);
78 void nft_dynset_eval(const struct nft_expr
*expr
,
79 struct nft_regs
*regs
, const struct nft_pktinfo
*pkt
)
81 const struct nft_dynset
*priv
= nft_expr_priv(expr
);
82 struct nft_set
*set
= priv
->set
;
83 const struct nft_set_ext
*ext
;
84 const struct nft_expr
*sexpr
;
87 if (priv
->op
== NFT_DYNSET_OP_DELETE
) {
88 set
->ops
->delete(set
, ®s
->data
[priv
->sreg_key
]);
92 if (set
->ops
->update(set
, ®s
->data
[priv
->sreg_key
], nft_dynset_new
,
95 if (nft_set_ext_exists(ext
, NFT_SET_EXT_EXPR
))
96 sexpr
= nft_set_ext_expr(ext
);
98 if (priv
->op
== NFT_DYNSET_OP_UPDATE
&&
99 nft_set_ext_exists(ext
, NFT_SET_EXT_EXPIRATION
)) {
100 timeout
= priv
->timeout
? : set
->timeout
;
101 *nft_set_ext_expiration(ext
) = get_jiffies_64() + timeout
;
105 sexpr
->ops
->eval(sexpr
, regs
, pkt
);
108 regs
->verdict
.code
= NFT_BREAK
;
113 regs
->verdict
.code
= NFT_BREAK
;
116 static const struct nla_policy nft_dynset_policy
[NFTA_DYNSET_MAX
+ 1] = {
117 [NFTA_DYNSET_SET_NAME
] = { .type
= NLA_STRING
,
118 .len
= NFT_SET_MAXNAMELEN
- 1 },
119 [NFTA_DYNSET_SET_ID
] = { .type
= NLA_U32
},
120 [NFTA_DYNSET_OP
] = { .type
= NLA_U32
},
121 [NFTA_DYNSET_SREG_KEY
] = { .type
= NLA_U32
},
122 [NFTA_DYNSET_SREG_DATA
] = { .type
= NLA_U32
},
123 [NFTA_DYNSET_TIMEOUT
] = { .type
= NLA_U64
},
124 [NFTA_DYNSET_EXPR
] = { .type
= NLA_NESTED
},
125 [NFTA_DYNSET_FLAGS
] = { .type
= NLA_U32
},
128 static int nft_dynset_init(const struct nft_ctx
*ctx
,
129 const struct nft_expr
*expr
,
130 const struct nlattr
* const tb
[])
132 struct nft_dynset
*priv
= nft_expr_priv(expr
);
133 u8 genmask
= nft_genmask_next(ctx
->net
);
138 lockdep_assert_held(&ctx
->net
->nft
.commit_mutex
);
140 if (tb
[NFTA_DYNSET_SET_NAME
] == NULL
||
141 tb
[NFTA_DYNSET_OP
] == NULL
||
142 tb
[NFTA_DYNSET_SREG_KEY
] == NULL
)
145 if (tb
[NFTA_DYNSET_FLAGS
]) {
146 u32 flags
= ntohl(nla_get_be32(tb
[NFTA_DYNSET_FLAGS
]));
148 if (flags
& ~NFT_DYNSET_F_INV
)
150 if (flags
& NFT_DYNSET_F_INV
)
154 set
= nft_set_lookup_global(ctx
->net
, ctx
->table
,
155 tb
[NFTA_DYNSET_SET_NAME
],
156 tb
[NFTA_DYNSET_SET_ID
], genmask
);
160 if (set
->ops
->update
== NULL
)
163 if (set
->flags
& NFT_SET_CONSTANT
)
166 priv
->op
= ntohl(nla_get_be32(tb
[NFTA_DYNSET_OP
]));
168 case NFT_DYNSET_OP_ADD
:
169 case NFT_DYNSET_OP_DELETE
:
171 case NFT_DYNSET_OP_UPDATE
:
172 if (!(set
->flags
& NFT_SET_TIMEOUT
))
180 if (tb
[NFTA_DYNSET_TIMEOUT
] != NULL
) {
181 if (!(set
->flags
& NFT_SET_TIMEOUT
))
183 timeout
= msecs_to_jiffies(be64_to_cpu(nla_get_be64(
184 tb
[NFTA_DYNSET_TIMEOUT
])));
187 priv
->sreg_key
= nft_parse_register(tb
[NFTA_DYNSET_SREG_KEY
]);
188 err
= nft_validate_register_load(priv
->sreg_key
, set
->klen
);
192 if (tb
[NFTA_DYNSET_SREG_DATA
] != NULL
) {
193 if (!(set
->flags
& NFT_SET_MAP
))
195 if (set
->dtype
== NFT_DATA_VERDICT
)
198 priv
->sreg_data
= nft_parse_register(tb
[NFTA_DYNSET_SREG_DATA
]);
199 err
= nft_validate_register_load(priv
->sreg_data
, set
->dlen
);
202 } else if (set
->flags
& NFT_SET_MAP
)
205 if (tb
[NFTA_DYNSET_EXPR
] != NULL
) {
206 if (!(set
->flags
& NFT_SET_EVAL
))
209 priv
->expr
= nft_expr_init(ctx
, tb
[NFTA_DYNSET_EXPR
]);
210 if (IS_ERR(priv
->expr
))
211 return PTR_ERR(priv
->expr
);
214 if (!(priv
->expr
->ops
->type
->flags
& NFT_EXPR_STATEFUL
))
217 if (priv
->expr
->ops
->type
->flags
& NFT_EXPR_GC
) {
218 if (set
->flags
& NFT_SET_TIMEOUT
)
220 if (!set
->ops
->gc_init
)
222 set
->ops
->gc_init(set
);
226 nft_set_ext_prepare(&priv
->tmpl
);
227 nft_set_ext_add_length(&priv
->tmpl
, NFT_SET_EXT_KEY
, set
->klen
);
228 if (set
->flags
& NFT_SET_MAP
)
229 nft_set_ext_add_length(&priv
->tmpl
, NFT_SET_EXT_DATA
, set
->dlen
);
230 if (priv
->expr
!= NULL
)
231 nft_set_ext_add_length(&priv
->tmpl
, NFT_SET_EXT_EXPR
,
232 priv
->expr
->ops
->size
);
233 if (set
->flags
& NFT_SET_TIMEOUT
) {
234 if (timeout
|| set
->timeout
)
235 nft_set_ext_add(&priv
->tmpl
, NFT_SET_EXT_EXPIRATION
);
238 priv
->timeout
= timeout
;
240 err
= nf_tables_bind_set(ctx
, set
, &priv
->binding
);
251 if (priv
->expr
!= NULL
)
252 nft_expr_destroy(ctx
, priv
->expr
);
256 static void nft_dynset_deactivate(const struct nft_ctx
*ctx
,
257 const struct nft_expr
*expr
,
258 enum nft_trans_phase phase
)
260 struct nft_dynset
*priv
= nft_expr_priv(expr
);
262 nf_tables_deactivate_set(ctx
, priv
->set
, &priv
->binding
, phase
);
265 static void nft_dynset_activate(const struct nft_ctx
*ctx
,
266 const struct nft_expr
*expr
)
268 struct nft_dynset
*priv
= nft_expr_priv(expr
);
273 static void nft_dynset_destroy(const struct nft_ctx
*ctx
,
274 const struct nft_expr
*expr
)
276 struct nft_dynset
*priv
= nft_expr_priv(expr
);
278 if (priv
->expr
!= NULL
)
279 nft_expr_destroy(ctx
, priv
->expr
);
281 nf_tables_destroy_set(ctx
, priv
->set
);
284 static int nft_dynset_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
286 const struct nft_dynset
*priv
= nft_expr_priv(expr
);
287 u32 flags
= priv
->invert
? NFT_DYNSET_F_INV
: 0;
289 if (nft_dump_register(skb
, NFTA_DYNSET_SREG_KEY
, priv
->sreg_key
))
290 goto nla_put_failure
;
291 if (priv
->set
->flags
& NFT_SET_MAP
&&
292 nft_dump_register(skb
, NFTA_DYNSET_SREG_DATA
, priv
->sreg_data
))
293 goto nla_put_failure
;
294 if (nla_put_be32(skb
, NFTA_DYNSET_OP
, htonl(priv
->op
)))
295 goto nla_put_failure
;
296 if (nla_put_string(skb
, NFTA_DYNSET_SET_NAME
, priv
->set
->name
))
297 goto nla_put_failure
;
298 if (nla_put_be64(skb
, NFTA_DYNSET_TIMEOUT
,
299 cpu_to_be64(jiffies_to_msecs(priv
->timeout
)),
301 goto nla_put_failure
;
302 if (priv
->expr
&& nft_expr_dump(skb
, NFTA_DYNSET_EXPR
, priv
->expr
))
303 goto nla_put_failure
;
304 if (nla_put_be32(skb
, NFTA_DYNSET_FLAGS
, htonl(flags
)))
305 goto nla_put_failure
;
312 static const struct nft_expr_ops nft_dynset_ops
= {
313 .type
= &nft_dynset_type
,
314 .size
= NFT_EXPR_SIZE(sizeof(struct nft_dynset
)),
315 .eval
= nft_dynset_eval
,
316 .init
= nft_dynset_init
,
317 .destroy
= nft_dynset_destroy
,
318 .activate
= nft_dynset_activate
,
319 .deactivate
= nft_dynset_deactivate
,
320 .dump
= nft_dynset_dump
,
323 struct nft_expr_type nft_dynset_type __read_mostly
= {
325 .ops
= &nft_dynset_ops
,
326 .policy
= nft_dynset_policy
,
327 .maxattr
= NFTA_DYNSET_MAX
,
328 .owner
= THIS_MODULE
,