]>
Commit | Line | Data |
---|---|---|
fac10ea7 | 1 | /* |
a5dadd72 | 2 | * Copyright (c) 2008-2012 Patrick McHardy <kaber@trash.net> |
aae836a7 | 3 | * Copyright (c) 2013 Pablo Neira Ayuso <pablo@netfilter.org> |
fac10ea7 PM |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | |
10 | */ | |
11 | ||
b4add075 TH |
12 | #include <nft.h> |
13 | ||
aae836a7 | 14 | #include <string.h> |
aae836a7 PNA |
15 | #include <errno.h> |
16 | #include <libmnl/libmnl.h> | |
cb86c169 ABG |
17 | #include <netinet/in.h> |
18 | #include <arpa/inet.h> | |
bd9f3633 | 19 | #include <inttypes.h> |
aae836a7 | 20 | |
1c2c506d | 21 | #include <libnftnl/table.h> |
be5d9120 | 22 | #include <libnftnl/trace.h> |
1c2c506d PNA |
23 | #include <libnftnl/chain.h> |
24 | #include <libnftnl/expr.h> | |
4d38878b | 25 | #include <libnftnl/object.h> |
1c2c506d | 26 | #include <libnftnl/set.h> |
db0697ce | 27 | #include <libnftnl/flowtable.h> |
61f851be | 28 | #include <libnftnl/udata.h> |
2fa54d8a | 29 | #include <libnftnl/ruleset.h> |
f9563c0f | 30 | #include <libnftnl/common.h> |
6e48df53 | 31 | #include <libnftnl/udata.h> |
f9563c0f | 32 | #include <linux/netfilter/nfnetlink.h> |
fac10ea7 | 33 | #include <linux/netfilter/nf_tables.h> |
cb86c169 | 34 | #include <linux/netfilter.h> |
fac10ea7 PM |
35 | |
36 | #include <nftables.h> | |
6e48df53 | 37 | #include <parser.h> |
fac10ea7 | 38 | #include <netlink.h> |
aae836a7 | 39 | #include <mnl.h> |
fac10ea7 | 40 | #include <expression.h> |
be5d9120 | 41 | #include <statement.h> |
53fc2c7a | 42 | #include <gmputil.h> |
fac10ea7 PM |
43 | #include <utils.h> |
44 | #include <erec.h> | |
be5d9120 | 45 | #include <iface.h> |
fac10ea7 | 46 | |
2dc07bcd | 47 | #define nft_mon_print(monh, ...) nft_print(&monh->ctx->nft->output, __VA_ARGS__) |
2535ba70 | 48 | |
a144995d PM |
49 | const struct input_descriptor indesc_netlink = { |
50 | .name = "netlink", | |
51 | .type = INDESC_NETLINK, | |
52 | }; | |
53 | ||
54 | const struct location netlink_location = { | |
55 | .indesc = &indesc_netlink, | |
56 | }; | |
57 | ||
52f169d3 AB |
58 | void __noreturn __netlink_abi_error(const char *file, int line, |
59 | const char *reason) | |
f9563c0f AB |
60 | { |
61 | fprintf(stderr, "E: Contact urgently your Linux kernel vendor. " | |
52f169d3 | 62 | "Netlink ABI is broken: %s:%d %s\n", file, line, reason); |
5adbd76e | 63 | abort(); |
fac10ea7 PM |
64 | } |
65 | ||
a72315d2 PNA |
66 | int netlink_io_error(struct netlink_ctx *ctx, const struct location *loc, |
67 | const char *fmt, ...) | |
fac10ea7 PM |
68 | { |
69 | struct error_record *erec; | |
70 | va_list ap; | |
71 | ||
72 | if (loc == NULL) | |
a144995d | 73 | loc = &netlink_location; |
fac10ea7 PM |
74 | |
75 | va_start(ap, fmt); | |
76 | erec = erec_vcreate(EREC_ERROR, loc, fmt, ap); | |
77 | va_end(ap); | |
78 | erec_queue(erec, ctx->msgs); | |
79 | return -1; | |
80 | } | |
81 | ||
62812246 PNA |
82 | void __noreturn __netlink_init_error(const char *filename, int line, |
83 | const char *reason) | |
1be55ff3 | 84 | { |
62812246 PNA |
85 | fprintf(stderr, "%s:%d: Unable to initialize Netlink socket: %s\n", |
86 | filename, line, reason); | |
1be55ff3 AB |
87 | exit(NFT_EXIT_NONL); |
88 | } | |
89 | ||
d6f06c30 | 90 | struct nftnl_expr *alloc_nft_expr(const char *name) |
fac10ea7 | 91 | { |
d6f06c30 | 92 | struct nftnl_expr *nle; |
fac10ea7 | 93 | |
d6f06c30 | 94 | nle = nftnl_expr_alloc(name); |
aae836a7 | 95 | if (nle == NULL) |
fac10ea7 | 96 | memory_allocation_error(); |
e7b568e1 | 97 | |
fac10ea7 PM |
98 | return nle; |
99 | } | |
80669876 PNA |
100 | static void netlink_gen_key(const struct expr *expr, |
101 | struct nft_data_linearize *data); | |
039a1494 PNA |
102 | static void __netlink_gen_data(const struct expr *expr, |
103 | struct nft_data_linearize *data, bool expand); | |
66746e7d | 104 | |
b4b234f5 PNA |
105 | struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set, |
106 | const struct expr *expr) | |
ebfd6822 | 107 | { |
8ac2f3b2 | 108 | const struct expr *elem, *data; |
d6f06c30 | 109 | struct nftnl_set_elem *nlse; |
aae836a7 | 110 | struct nft_data_linearize nld; |
6089630f | 111 | struct nftnl_udata_buf *udbuf = NULL; |
419d1968 | 112 | uint32_t flags = 0; |
e6d1d0d6 PNA |
113 | int num_exprs = 0; |
114 | struct stmt *stmt; | |
8ac2f3b2 | 115 | struct expr *key; |
ebfd6822 | 116 | |
d6f06c30 | 117 | nlse = nftnl_set_elem_alloc(); |
ebfd6822 PM |
118 | if (nlse == NULL) |
119 | memory_allocation_error(); | |
120 | ||
52532335 | 121 | data = NULL; |
72931553 | 122 | if (expr->etype == EXPR_MAPPING) { |
52532335 PM |
123 | elem = expr->left; |
124 | if (!(expr->flags & EXPR_F_INTERVAL_END)) | |
125 | data = expr->right; | |
aae836a7 | 126 | } else { |
52532335 PM |
127 | elem = expr; |
128 | } | |
3d6cf7f3 FW |
129 | if (elem->etype != EXPR_SET_ELEM) |
130 | BUG("Unexpected expression type: got %d\n", elem->etype); | |
131 | ||
52532335 PM |
132 | key = elem->key; |
133 | ||
419d1968 PNA |
134 | switch (key->etype) { |
135 | case EXPR_SET_ELEM_CATCHALL: | |
136 | break; | |
137 | default: | |
b0c6deab PNA |
138 | if (set->set_flags & NFT_SET_INTERVAL && |
139 | key->etype == EXPR_CONCAT && key->field_count > 1) { | |
508f3a27 | 140 | key->flags |= EXPR_F_INTERVAL; |
80669876 | 141 | netlink_gen_key(key, &nld); |
508f3a27 PNA |
142 | key->flags &= ~EXPR_F_INTERVAL; |
143 | ||
144 | nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len); | |
145 | ||
419d1968 | 146 | key->flags |= EXPR_F_INTERVAL_END; |
80669876 | 147 | netlink_gen_key(key, &nld); |
419d1968 PNA |
148 | key->flags &= ~EXPR_F_INTERVAL_END; |
149 | ||
150 | nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY_END, | |
151 | &nld.value, nld.len); | |
508f3a27 | 152 | } else { |
80669876 | 153 | netlink_gen_key(key, &nld); |
508f3a27 | 154 | nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len); |
419d1968 PNA |
155 | } |
156 | break; | |
8ac2f3b2 SB |
157 | } |
158 | ||
7b524897 | 159 | if (elem->timeout) |
d6f06c30 | 160 | nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_TIMEOUT, |
947b4fe1 | 161 | elem->timeout); |
24f33c71 LGL |
162 | if (elem->expiration) |
163 | nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_EXPIRATION, | |
164 | elem->expiration); | |
e6d1d0d6 PNA |
165 | list_for_each_entry(stmt, &elem->stmt_list, list) |
166 | num_exprs++; | |
167 | ||
168 | if (num_exprs == 1) { | |
169 | list_for_each_entry(stmt, &elem->stmt_list, list) { | |
170 | nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_EXPR, | |
171 | netlink_gen_stmt_stateful(stmt), 0); | |
172 | } | |
173 | } else if (num_exprs > 1) { | |
174 | list_for_each_entry(stmt, &elem->stmt_list, list) { | |
175 | nftnl_set_elem_add_expr(nlse, | |
176 | netlink_gen_stmt_stateful(stmt)); | |
177 | } | |
178 | } | |
6089630f | 179 | if (elem->comment || expr->elem_flags) { |
61f851be CFG |
180 | udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN); |
181 | if (!udbuf) | |
182 | memory_allocation_error(); | |
6089630f PS |
183 | } |
184 | if (elem->comment) { | |
10da57e3 | 185 | if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_SET_ELEM_COMMENT, |
61f851be CFG |
186 | elem->comment)) |
187 | memory_allocation_error(); | |
6089630f PS |
188 | } |
189 | if (expr->elem_flags) { | |
10da57e3 | 190 | if (!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_ELEM_FLAGS, |
6089630f PS |
191 | expr->elem_flags)) |
192 | memory_allocation_error(); | |
193 | } | |
194 | if (udbuf) { | |
d6f06c30 | 195 | nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_USERDATA, |
61f851be CFG |
196 | nftnl_udata_buf_data(udbuf), |
197 | nftnl_udata_buf_len(udbuf)); | |
198 | nftnl_udata_buf_free(udbuf); | |
199 | } | |
0fd53234 | 200 | if (set_is_datamap(set->set_flags) && data != NULL) { |
66746e7d | 201 | __netlink_gen_data(data, &nld, !(data->flags & EXPR_F_SINGLETON)); |
72931553 | 202 | switch (data->etype) { |
a54d7b05 | 203 | case EXPR_VERDICT: |
d6f06c30 | 204 | nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_VERDICT, |
947b4fe1 | 205 | data->verdict); |
52532335 | 206 | if (data->chain != NULL) |
d6f06c30 | 207 | nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_CHAIN, |
947b4fe1 | 208 | nld.chain, strlen(nld.chain)); |
a54d7b05 | 209 | break; |
6f0d90ec FW |
210 | case EXPR_CONCAT: |
211 | assert(nld.len > 0); | |
212 | /* fallthrough */ | |
a54d7b05 | 213 | case EXPR_VALUE: |
9599d9d2 PNA |
214 | case EXPR_RANGE: |
215 | case EXPR_PREFIX: | |
d6f06c30 | 216 | nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_DATA, |
947b4fe1 | 217 | nld.value, nld.len); |
a54d7b05 PNA |
218 | break; |
219 | default: | |
220 | BUG("unexpected set element expression\n"); | |
221 | break; | |
aae836a7 | 222 | } |
ebfd6822 | 223 | } |
0fd53234 | 224 | if (set_is_objmap(set->set_flags) && data != NULL) { |
deaf962e PNA |
225 | netlink_gen_data(data, &nld); |
226 | nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_OBJREF, | |
227 | nld.value, nld.len); | |
228 | } | |
ebfd6822 | 229 | |
e7b568e1 | 230 | if (expr->flags & EXPR_F_INTERVAL_END) |
419d1968 PNA |
231 | flags |= NFT_SET_ELEM_INTERVAL_END; |
232 | if (key->etype == EXPR_SET_ELEM_CATCHALL) | |
233 | flags |= NFT_SET_ELEM_CATCHALL; | |
234 | ||
235 | if (flags) | |
236 | nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_FLAGS, flags); | |
ebfd6822 PM |
237 | |
238 | return nlse; | |
239 | } | |
240 | ||
aae836a7 PNA |
241 | void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder, |
242 | unsigned int len, struct nft_data_linearize *data) | |
fac10ea7 | 243 | { |
fac10ea7 | 244 | assert(len > 0); |
aae836a7 PNA |
245 | mpz_export_data(data->value, value, byteorder, len); |
246 | data->len = len; | |
fac10ea7 PM |
247 | } |
248 | ||
8ac2f3b2 SB |
249 | static int netlink_export_pad(unsigned char *data, const mpz_t v, |
250 | const struct expr *i) | |
251 | { | |
252 | mpz_export_data(data, v, i->byteorder, | |
253 | div_round_up(i->len, BITS_PER_BYTE)); | |
254 | ||
255 | return netlink_padded_len(i->len) / BITS_PER_BYTE; | |
256 | } | |
257 | ||
9582a075 PNA |
258 | static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i, |
259 | unsigned char *data) | |
8ac2f3b2 | 260 | { |
1017d323 PNA |
261 | struct expr *expr; |
262 | ||
8ac2f3b2 SB |
263 | switch (i->etype) { |
264 | case EXPR_RANGE: | |
508f3a27 | 265 | if (flags & EXPR_F_INTERVAL_END) |
1017d323 PNA |
266 | expr = i->right; |
267 | else | |
268 | expr = i->left; | |
269 | ||
270 | if (expr_basetype(expr)->type == TYPE_INTEGER && | |
271 | expr->byteorder == BYTEORDER_HOST_ENDIAN) | |
272 | mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE); | |
273 | ||
274 | i = expr; | |
8ac2f3b2 SB |
275 | break; |
276 | case EXPR_PREFIX: | |
508f3a27 | 277 | if (flags & EXPR_F_INTERVAL_END) { |
8ac2f3b2 SB |
278 | int count; |
279 | mpz_t v; | |
280 | ||
281 | mpz_init_bitmask(v, i->len - i->prefix_len); | |
806ab081 FW |
282 | |
283 | if (i->byteorder == BYTEORDER_HOST_ENDIAN) | |
284 | mpz_switch_byteorder(v, i->len / BITS_PER_BYTE); | |
285 | ||
8ac2f3b2 SB |
286 | mpz_add(v, i->prefix->value, v); |
287 | count = netlink_export_pad(data, v, i); | |
288 | mpz_clear(v); | |
289 | return count; | |
290 | } | |
291 | return netlink_export_pad(data, i->prefix->value, i); | |
292 | case EXPR_VALUE: | |
508f3a27 PNA |
293 | /* Switch byteorder only once for singleton values when the set |
294 | * contains concatenation of intervals. | |
295 | */ | |
296 | if (!(flags & EXPR_F_INTERVAL)) | |
297 | break; | |
298 | ||
299 | expr = (struct expr *)i; | |
300 | if (expr_basetype(expr)->type == TYPE_INTEGER && | |
301 | expr->byteorder == BYTEORDER_HOST_ENDIAN) | |
302 | mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE); | |
8ac2f3b2 SB |
303 | break; |
304 | default: | |
305 | BUG("invalid expression type '%s' in set", expr_ops(i)->name); | |
306 | } | |
307 | ||
308 | return netlink_export_pad(data, i->value, i); | |
309 | } | |
310 | ||
9582a075 PNA |
311 | static void netlink_gen_concat_key(const struct expr *expr, |
312 | struct nft_data_linearize *nld) | |
53fc2c7a | 313 | { |
8ac2f3b2 | 314 | unsigned int len = expr->len / BITS_PER_BYTE, offset = 0; |
8ac2f3b2 | 315 | unsigned char data[len]; |
53fc2c7a | 316 | const struct expr *i; |
aae836a7 | 317 | |
8ac2f3b2 SB |
318 | memset(data, 0, len); |
319 | ||
320 | list_for_each_entry(i, &expr->expressions, list) | |
9582a075 | 321 | offset += __netlink_gen_concat_key(expr->flags, i, data + offset); |
8ac2f3b2 SB |
322 | |
323 | memcpy(nld->value, data, len); | |
324 | nld->len = len; | |
53fc2c7a PM |
325 | } |
326 | ||
9582a075 PNA |
327 | static int __netlink_gen_concat_data(int end, const struct expr *i, |
328 | unsigned char *data) | |
329 | { | |
330 | switch (i->etype) { | |
331 | case EXPR_RANGE: | |
332 | i = end ? i->right : i->left; | |
333 | break; | |
334 | case EXPR_PREFIX: | |
335 | if (end) { | |
336 | int count; | |
337 | mpz_t v; | |
338 | ||
339 | mpz_init_bitmask(v, i->len - i->prefix_len); | |
340 | mpz_add(v, i->prefix->value, v); | |
341 | count = netlink_export_pad(data, v, i); | |
342 | mpz_clear(v); | |
343 | return count; | |
344 | } | |
345 | return netlink_export_pad(data, i->prefix->value, i); | |
346 | case EXPR_VALUE: | |
347 | break; | |
348 | default: | |
349 | BUG("invalid expression type '%s' in set", expr_ops(i)->name); | |
350 | } | |
351 | ||
352 | return netlink_export_pad(data, i->value, i); | |
353 | } | |
354 | ||
66746e7d PNA |
355 | static void __netlink_gen_concat_expand(const struct expr *expr, |
356 | struct nft_data_linearize *nld) | |
357 | { | |
358 | unsigned int len = div_round_up(expr->len, BITS_PER_BYTE) * 2, offset = 0; | |
359 | unsigned char data[len]; | |
360 | const struct expr *i; | |
361 | ||
362 | memset(data, 0, len); | |
363 | ||
364 | list_for_each_entry(i, &expr->expressions, list) | |
9582a075 PNA |
365 | offset += __netlink_gen_concat_data(false, i, data + offset); |
366 | ||
367 | list_for_each_entry(i, &expr->expressions, list) | |
368 | offset += __netlink_gen_concat_data(true, i, data + offset); | |
369 | ||
370 | memcpy(nld->value, data, len); | |
371 | nld->len = len; | |
372 | } | |
373 | ||
374 | static void __netlink_gen_concat(const struct expr *expr, | |
375 | struct nft_data_linearize *nld) | |
376 | { | |
377 | unsigned int len = expr->len / BITS_PER_BYTE, offset = 0; | |
378 | unsigned char data[len]; | |
379 | const struct expr *i; | |
380 | ||
381 | memset(data, 0, len); | |
66746e7d PNA |
382 | |
383 | list_for_each_entry(i, &expr->expressions, list) | |
9582a075 | 384 | offset += __netlink_gen_concat_data(expr->flags, i, data + offset); |
66746e7d PNA |
385 | |
386 | memcpy(nld->value, data, len); | |
387 | nld->len = len; | |
388 | } | |
389 | ||
390 | static void netlink_gen_concat_data(const struct expr *expr, | |
9582a075 | 391 | struct nft_data_linearize *nld, bool expand) |
66746e7d PNA |
392 | { |
393 | if (expand) | |
394 | __netlink_gen_concat_expand(expr, nld); | |
395 | else | |
396 | __netlink_gen_concat(expr, nld); | |
397 | } | |
398 | ||
aae836a7 PNA |
399 | static void netlink_gen_constant_data(const struct expr *expr, |
400 | struct nft_data_linearize *data) | |
53fc2c7a | 401 | { |
72931553 | 402 | assert(expr->etype == EXPR_VALUE); |
aae836a7 PNA |
403 | netlink_gen_raw_data(expr->value, expr->byteorder, |
404 | div_round_up(expr->len, BITS_PER_BYTE), data); | |
53fc2c7a PM |
405 | } |
406 | ||
c330152b PNA |
407 | static void netlink_gen_chain(const struct expr *expr, |
408 | struct nft_data_linearize *data) | |
53fc2c7a | 409 | { |
f1e8a129 | 410 | char chain[NFT_CHAIN_MAXNAMELEN]; |
fb6d826a | 411 | unsigned int len; |
f1e8a129 | 412 | |
c330152b | 413 | len = expr->chain->len / BITS_PER_BYTE; |
53fc2c7a | 414 | |
c330152b PNA |
415 | if (!len) |
416 | BUG("chain length is 0"); | |
417 | ||
418 | if (len > sizeof(chain)) | |
419 | BUG("chain is too large (%u, %u max)", | |
420 | len, (unsigned int)sizeof(chain)); | |
421 | ||
422 | memset(chain, 0, sizeof(chain)); | |
fb6d826a | 423 | |
c330152b PNA |
424 | mpz_export_data(chain, expr->chain->value, |
425 | BYTEORDER_HOST_ENDIAN, len); | |
426 | snprintf(data->chain, NFT_CHAIN_MAXNAMELEN, "%s", chain); | |
427 | } | |
fb6d826a | 428 | |
c330152b PNA |
429 | static void netlink_gen_verdict(const struct expr *expr, |
430 | struct nft_data_linearize *data) | |
431 | { | |
fb6d826a | 432 | |
c330152b | 433 | data->verdict = expr->verdict; |
fb6d826a | 434 | |
c330152b PNA |
435 | switch (expr->verdict) { |
436 | case NFT_JUMP: | |
437 | case NFT_GOTO: | |
438 | if (expr->chain) | |
439 | netlink_gen_chain(expr, data); | |
440 | else | |
441 | data->chain_id = expr->chain_id; | |
53fc2c7a PM |
442 | break; |
443 | } | |
53fc2c7a PM |
444 | } |
445 | ||
9599d9d2 PNA |
446 | static void netlink_gen_range(const struct expr *expr, |
447 | struct nft_data_linearize *nld) | |
448 | { | |
449 | unsigned int len = div_round_up(expr->left->len, BITS_PER_BYTE) * 2; | |
450 | unsigned char data[len]; | |
451 | unsigned int offset = 0; | |
452 | ||
453 | memset(data, 0, len); | |
454 | offset = netlink_export_pad(data, expr->left->value, expr->left); | |
455 | netlink_export_pad(data + offset, expr->right->value, expr->right); | |
456 | memcpy(nld->value, data, len); | |
457 | nld->len = len; | |
458 | } | |
459 | ||
460 | static void netlink_gen_prefix(const struct expr *expr, | |
461 | struct nft_data_linearize *nld) | |
462 | { | |
463 | unsigned int len = div_round_up(expr->len, BITS_PER_BYTE) * 2; | |
464 | unsigned char data[len]; | |
465 | int offset; | |
466 | mpz_t v; | |
467 | ||
468 | offset = netlink_export_pad(data, expr->prefix->value, expr); | |
469 | mpz_init_bitmask(v, expr->len - expr->prefix_len); | |
470 | mpz_add(v, expr->prefix->value, v); | |
471 | netlink_export_pad(data + offset, v, expr->prefix); | |
472 | mpz_clear(v); | |
473 | ||
474 | memcpy(nld->value, data, len); | |
475 | nld->len = len; | |
476 | } | |
477 | ||
80669876 PNA |
478 | static void netlink_gen_key(const struct expr *expr, |
479 | struct nft_data_linearize *data) | |
480 | { | |
481 | switch (expr->etype) { | |
482 | case EXPR_VALUE: | |
483 | return netlink_gen_constant_data(expr, data); | |
484 | case EXPR_CONCAT: | |
9582a075 | 485 | return netlink_gen_concat_key(expr, data); |
80669876 PNA |
486 | case EXPR_RANGE: |
487 | return netlink_gen_range(expr, data); | |
488 | case EXPR_PREFIX: | |
489 | return netlink_gen_prefix(expr, data); | |
490 | default: | |
491 | BUG("invalid data expression type %s\n", expr_name(expr)); | |
492 | } | |
493 | } | |
494 | ||
039a1494 PNA |
495 | static void __netlink_gen_data(const struct expr *expr, |
496 | struct nft_data_linearize *data, bool expand) | |
53fc2c7a | 497 | { |
72931553 | 498 | switch (expr->etype) { |
53fc2c7a | 499 | case EXPR_VALUE: |
aae836a7 | 500 | return netlink_gen_constant_data(expr, data); |
53fc2c7a | 501 | case EXPR_CONCAT: |
66746e7d | 502 | return netlink_gen_concat_data(expr, data, expand); |
53fc2c7a | 503 | case EXPR_VERDICT: |
aae836a7 | 504 | return netlink_gen_verdict(expr, data); |
9599d9d2 PNA |
505 | case EXPR_RANGE: |
506 | return netlink_gen_range(expr, data); | |
507 | case EXPR_PREFIX: | |
508 | return netlink_gen_prefix(expr, data); | |
53fc2c7a | 509 | default: |
68e76238 | 510 | BUG("invalid data expression type %s\n", expr_name(expr)); |
53fc2c7a PM |
511 | } |
512 | } | |
513 | ||
66746e7d PNA |
514 | void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data) |
515 | { | |
516 | __netlink_gen_data(expr, data, false); | |
517 | } | |
518 | ||
53fc2c7a | 519 | struct expr *netlink_alloc_value(const struct location *loc, |
aae836a7 | 520 | const struct nft_data_delinearize *nld) |
53fc2c7a PM |
521 | { |
522 | return constant_expr_alloc(loc, &invalid_type, BYTEORDER_INVALID, | |
aae836a7 | 523 | nld->len * BITS_PER_BYTE, nld->value); |
53fc2c7a PM |
524 | } |
525 | ||
526 | static struct expr *netlink_alloc_verdict(const struct location *loc, | |
aae836a7 | 527 | const struct nft_data_delinearize *nld) |
53fc2c7a | 528 | { |
f1e8a129 | 529 | struct expr *chain; |
53fc2c7a | 530 | |
aae836a7 | 531 | switch (nld->verdict) { |
53fc2c7a PM |
532 | case NFT_JUMP: |
533 | case NFT_GOTO: | |
f1e8a129 FFM |
534 | chain = constant_expr_alloc(loc, &string_type, |
535 | BYTEORDER_HOST_ENDIAN, | |
142350f1 PNA |
536 | strlen(nld->chain) * BITS_PER_BYTE, |
537 | nld->chain); | |
53fc2c7a PM |
538 | break; |
539 | default: | |
540 | chain = NULL; | |
541 | break; | |
542 | } | |
543 | ||
aae836a7 | 544 | return verdict_expr_alloc(loc, nld->verdict, chain); |
53fc2c7a PM |
545 | } |
546 | ||
547 | struct expr *netlink_alloc_data(const struct location *loc, | |
aae836a7 | 548 | const struct nft_data_delinearize *nld, |
53fc2c7a PM |
549 | enum nft_registers dreg) |
550 | { | |
551 | switch (dreg) { | |
552 | case NFT_REG_VERDICT: | |
553 | return netlink_alloc_verdict(loc, nld); | |
554 | default: | |
555 | return netlink_alloc_value(loc, nld); | |
556 | } | |
557 | } | |
558 | ||
2535ba70 | 559 | void netlink_dump_rule(const struct nftnl_rule *nlr, struct netlink_ctx *ctx) |
fac10ea7 | 560 | { |
2dc07bcd | 561 | FILE *fp = ctx->nft->output.output_fp; |
7c1ccf81 | 562 | |
2dc07bcd | 563 | if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp) |
fac10ea7 | 564 | return; |
fac10ea7 | 565 | |
2535ba70 PS |
566 | nftnl_rule_fprintf(fp, nlr, 0, 0); |
567 | fprintf(fp, "\n"); | |
fac10ea7 PM |
568 | } |
569 | ||
89122493 PS |
570 | void netlink_dump_expr(const struct nftnl_expr *nle, |
571 | FILE *fp, unsigned int debug_mask) | |
fac10ea7 | 572 | { |
6db6ec4d | 573 | if (!(debug_mask & NFT_DEBUG_NETLINK)) |
aae836a7 | 574 | return; |
fac10ea7 | 575 | |
8dee5e43 PS |
576 | nftnl_expr_fprintf(fp, nle, 0, 0); |
577 | fprintf(fp, "\n"); | |
fac10ea7 PM |
578 | } |
579 | ||
2535ba70 | 580 | void netlink_dump_chain(const struct nftnl_chain *nlc, struct netlink_ctx *ctx) |
aae836a7 | 581 | { |
2dc07bcd | 582 | FILE *fp = ctx->nft->output.output_fp; |
aae836a7 | 583 | |
2dc07bcd | 584 | if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp) |
aae836a7 PNA |
585 | return; |
586 | ||
2535ba70 PS |
587 | nftnl_chain_fprintf(fp, nlc, 0, 0); |
588 | fprintf(fp, "\n"); | |
aae836a7 PNA |
589 | } |
590 | ||
702ac2b7 JGG |
591 | static int chain_parse_udata_cb(const struct nftnl_udata *attr, void *data) |
592 | { | |
593 | unsigned char *value = nftnl_udata_get(attr); | |
594 | uint8_t type = nftnl_udata_type(attr); | |
595 | const struct nftnl_udata **tb = data; | |
596 | uint8_t len = nftnl_udata_len(attr); | |
597 | ||
598 | switch (type) { | |
599 | case NFTNL_UDATA_CHAIN_COMMENT: | |
600 | if (value[len - 1] != '\0') | |
601 | return -1; | |
602 | break; | |
603 | default: | |
604 | return 0; | |
605 | } | |
606 | tb[type] = attr; | |
607 | return 0; | |
608 | } | |
609 | ||
8161ea94 PNA |
610 | static int qsort_device_cmp(const void *a, const void *b) |
611 | { | |
612 | const char **x = (const char **)a; | |
613 | const char **y = (const char **)b; | |
614 | ||
615 | return strcmp(*x, *y); | |
616 | } | |
617 | ||
fbcb888b PNA |
618 | struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx, |
619 | const struct nftnl_chain *nlc) | |
fac10ea7 | 620 | { |
702ac2b7 | 621 | const struct nftnl_udata *ud[NFTNL_UDATA_OBJ_MAX + 1] = {}; |
3fdc7541 PNA |
622 | int priority, policy, len = 0, i; |
623 | const char * const *dev_array; | |
fac10ea7 | 624 | struct chain *chain; |
702ac2b7 JGG |
625 | const char *udata; |
626 | uint32_t ulen; | |
7c1ccf81 | 627 | |
4e7b7ddd | 628 | chain = chain_alloc(); |
aae836a7 | 629 | chain->handle.family = |
d6f06c30 | 630 | nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY); |
cf646426 | 631 | chain->handle.table.name = |
d6f06c30 | 632 | xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE)); |
4e7b7ddd PNA |
633 | chain->handle.chain.name = |
634 | xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME)); | |
5db9dc92 | 635 | chain->handle.handle.id = |
d6f06c30 | 636 | nftnl_chain_get_u64(nlc, NFTNL_CHAIN_HANDLE); |
d42bd56c PNA |
637 | if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_FLAGS)) |
638 | chain->flags = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FLAGS); | |
2e27f246 | 639 | |
d6f06c30 PNA |
640 | if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_HOOKNUM) && |
641 | nftnl_chain_is_set(nlc, NFTNL_CHAIN_PRIO) && | |
642 | nftnl_chain_is_set(nlc, NFTNL_CHAIN_TYPE) && | |
643 | nftnl_chain_is_set(nlc, NFTNL_CHAIN_POLICY)) { | |
673d82af | 644 | chain->hook.num = |
d6f06c30 | 645 | nftnl_chain_get_u32(nlc, NFTNL_CHAIN_HOOKNUM); |
673d82af PNA |
646 | chain->hook.name = |
647 | hooknum2str(chain->handle.family, chain->hook.num); | |
627c451b FFM |
648 | priority = nftnl_chain_get_s32(nlc, NFTNL_CHAIN_PRIO); |
649 | chain->priority.expr = | |
650 | constant_expr_alloc(&netlink_location, | |
651 | &integer_type, | |
652 | BYTEORDER_HOST_ENDIAN, | |
653 | sizeof(int) * BITS_PER_BYTE, | |
654 | &priority); | |
50087981 | 655 | chain->type.str = |
d6f06c30 | 656 | xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_TYPE)); |
dba4a9b4 FFM |
657 | policy = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY); |
658 | chain->policy = constant_expr_alloc(&netlink_location, | |
659 | &integer_type, | |
660 | BYTEORDER_HOST_ENDIAN, | |
661 | sizeof(int) * BITS_PER_BYTE, | |
662 | &policy); | |
d6f06c30 PNA |
663 | nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY); |
664 | if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEV)) { | |
90d451ff | 665 | chain->dev_array = xmalloc(sizeof(char *) * 2); |
3fdc7541 PNA |
666 | chain->dev_array_len = 1; |
667 | chain->dev_array[0] = | |
d6f06c30 | 668 | xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_DEV)); |
3fdc7541 PNA |
669 | chain->dev_array[1] = NULL; |
670 | } else if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEVICES)) { | |
671 | dev_array = nftnl_chain_get(nlc, NFTNL_CHAIN_DEVICES); | |
672 | while (dev_array[len]) | |
673 | len++; | |
674 | ||
90d451ff | 675 | chain->dev_array = xmalloc((len + 1)* sizeof(char *)); |
3fdc7541 PNA |
676 | for (i = 0; i < len; i++) |
677 | chain->dev_array[i] = xstrdup(dev_array[i]); | |
678 | ||
679 | chain->dev_array[i] = NULL; | |
680 | chain->dev_array_len = len; | |
6c43069e | 681 | } |
4318642b | 682 | chain->flags |= CHAIN_F_BASECHAIN; |
8161ea94 PNA |
683 | |
684 | if (chain->dev_array_len) { | |
685 | qsort(chain->dev_array, chain->dev_array_len, | |
686 | sizeof(char *), qsort_device_cmp); | |
687 | } | |
2e27f246 | 688 | } |
aae836a7 | 689 | |
702ac2b7 JGG |
690 | if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_USERDATA)) { |
691 | udata = nftnl_chain_get_data(nlc, NFTNL_CHAIN_USERDATA, &ulen); | |
692 | if (nftnl_udata_parse(udata, ulen, chain_parse_udata_cb, ud) < 0) { | |
693 | netlink_io_error(ctx, NULL, "Cannot parse userdata"); | |
04f7af9d | 694 | chain_free(chain); |
702ac2b7 JGG |
695 | return NULL; |
696 | } | |
697 | if (ud[NFTNL_UDATA_CHAIN_COMMENT]) | |
698 | chain->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_CHAIN_COMMENT])); | |
699 | } | |
700 | ||
38756bcd AB |
701 | return chain; |
702 | } | |
703 | ||
c156232a JGG |
704 | static int table_parse_udata_cb(const struct nftnl_udata *attr, void *data) |
705 | { | |
706 | unsigned char *value = nftnl_udata_get(attr); | |
707 | const struct nftnl_udata **tb = data; | |
708 | uint8_t type = nftnl_udata_type(attr); | |
709 | uint8_t len = nftnl_udata_len(attr); | |
710 | ||
711 | switch (type) { | |
712 | case NFTNL_UDATA_TABLE_COMMENT: | |
713 | if (value[len - 1] != '\0') | |
714 | return -1; | |
715 | break; | |
716 | default: | |
717 | return 0; | |
718 | } | |
719 | tb[type] = attr; | |
720 | return 0; | |
721 | } | |
722 | ||
fbcb888b PNA |
723 | struct table *netlink_delinearize_table(struct netlink_ctx *ctx, |
724 | const struct nftnl_table *nlt) | |
aae836a7 | 725 | { |
c156232a | 726 | const struct nftnl_udata *ud[NFTNL_UDATA_TABLE_MAX + 1] = {}; |
aae836a7 | 727 | struct table *table; |
c156232a JGG |
728 | const char *udata; |
729 | uint32_t ulen; | |
aae836a7 | 730 | |
fac10ea7 | 731 | table = table_alloc(); |
947b4fe1 | 732 | table->handle.family = nftnl_table_get_u32(nlt, NFTNL_TABLE_FAMILY); |
cf646426 | 733 | table->handle.table.name = xstrdup(nftnl_table_get_str(nlt, NFTNL_TABLE_NAME)); |
947b4fe1 | 734 | table->flags = nftnl_table_get_u32(nlt, NFTNL_TABLE_FLAGS); |
0f830263 | 735 | table->handle.handle.id = nftnl_table_get_u64(nlt, NFTNL_TABLE_HANDLE); |
6d085b22 | 736 | table->owner = nftnl_table_get_u32(nlt, NFTNL_TABLE_OWNER); |
aae836a7 | 737 | |
c156232a JGG |
738 | if (nftnl_table_is_set(nlt, NFTNL_TABLE_USERDATA)) { |
739 | udata = nftnl_table_get_data(nlt, NFTNL_TABLE_USERDATA, &ulen); | |
740 | if (nftnl_udata_parse(udata, ulen, table_parse_udata_cb, ud) < 0) { | |
741 | netlink_io_error(ctx, NULL, "Cannot parse userdata"); | |
47640634 | 742 | table_free(table); |
c156232a JGG |
743 | return NULL; |
744 | } | |
745 | if (ud[NFTNL_UDATA_TABLE_COMMENT]) | |
746 | table->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_TABLE_COMMENT])); | |
747 | } | |
748 | ||
af657c08 AB |
749 | return table; |
750 | } | |
751 | ||
d6f06c30 | 752 | static int list_table_cb(struct nftnl_table *nlt, void *arg) |
af657c08 AB |
753 | { |
754 | struct netlink_ctx *ctx = arg; | |
dcb0a614 | 755 | struct table *table; |
af657c08 | 756 | |
dcb0a614 PNA |
757 | table = netlink_delinearize_table(ctx, nlt); |
758 | list_add_tail(&table->list, &ctx->list); | |
af657c08 | 759 | |
aae836a7 | 760 | return 0; |
fac10ea7 PM |
761 | } |
762 | ||
a37212f2 PS |
763 | int netlink_list_tables(struct netlink_ctx *ctx, const struct handle *h, |
764 | const struct nft_cache_filter *filter) | |
fac10ea7 | 765 | { |
d6f06c30 | 766 | struct nftnl_table_list *table_cache; |
a37212f2 PS |
767 | uint32_t family = h->family; |
768 | const char *table = NULL; | |
fac10ea7 | 769 | |
a37212f2 PS |
770 | if (filter) { |
771 | family = filter->list.family; | |
772 | table = filter->list.table; | |
773 | } | |
774 | ||
775 | table_cache = mnl_nft_table_dump(ctx, family, table); | |
09f81768 PNA |
776 | if (table_cache == NULL) { |
777 | if (errno == EINTR) | |
778 | return -1; | |
779 | ||
3cfb9e4b | 780 | return -1; |
09f81768 | 781 | } |
fac10ea7 | 782 | |
0f830263 | 783 | ctx->data = h; |
d6f06c30 PNA |
784 | nftnl_table_list_foreach(table_cache, list_table_cb, ctx); |
785 | nftnl_table_list_free(table_cache); | |
fac10ea7 PM |
786 | return 0; |
787 | } | |
788 | ||
d6ed28a3 | 789 | enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype) |
ebfd6822 PM |
790 | { |
791 | switch (dtype->type) { | |
792 | case TYPE_VERDICT: | |
793 | return NFT_DATA_VERDICT; | |
794 | default: | |
795 | return dtype->type; | |
796 | } | |
797 | } | |
798 | ||
343a5170 | 799 | static const struct datatype *dtype_map_from_kernel(enum nft_data_types type) |
ebfd6822 | 800 | { |
8519ab03 TH |
801 | /* The function always returns ownership of a reference. But for |
802 | * &verdict_Type and datatype_lookup(), those are static instances, | |
803 | * we can omit the datatype_get() call. | |
804 | */ | |
ebfd6822 PM |
805 | switch (type) { |
806 | case NFT_DATA_VERDICT: | |
807 | return &verdict_type; | |
808 | default: | |
551d2a09 PM |
809 | if (type & ~TYPE_MASK) |
810 | return concat_type_alloc(type); | |
bb1be655 | 811 | return datatype_lookup((enum datatypes) type); |
ebfd6822 PM |
812 | } |
813 | } | |
814 | ||
2535ba70 | 815 | void netlink_dump_set(const struct nftnl_set *nls, struct netlink_ctx *ctx) |
ebfd6822 | 816 | { |
2dc07bcd | 817 | FILE *fp = ctx->nft->output.output_fp; |
ebfd6822 | 818 | |
2dc07bcd | 819 | if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp) |
aae836a7 | 820 | return; |
ebfd6822 | 821 | |
2535ba70 PS |
822 | nftnl_set_fprintf(fp, nls, 0, 0); |
823 | fprintf(fp, "\n"); | |
ebfd6822 PM |
824 | } |
825 | ||
10bdec0a PNA |
826 | static int set_parse_udata_cb(const struct nftnl_udata *attr, void *data) |
827 | { | |
0864c2d4 | 828 | unsigned char *value = nftnl_udata_get(attr); |
10bdec0a PNA |
829 | const struct nftnl_udata **tb = data; |
830 | uint8_t type = nftnl_udata_type(attr); | |
831 | uint8_t len = nftnl_udata_len(attr); | |
832 | ||
833 | switch (type) { | |
10da57e3 PS |
834 | case NFTNL_UDATA_SET_KEYBYTEORDER: |
835 | case NFTNL_UDATA_SET_DATABYTEORDER: | |
836 | case NFTNL_UDATA_SET_MERGE_ELEMENTS: | |
9599d9d2 | 837 | case NFTNL_UDATA_SET_DATA_INTERVAL: |
10bdec0a PNA |
838 | if (len != sizeof(uint32_t)) |
839 | return -1; | |
840 | break; | |
6e48df53 FW |
841 | case NFTNL_UDATA_SET_KEY_TYPEOF: |
842 | case NFTNL_UDATA_SET_DATA_TYPEOF: | |
843 | if (len < 3) | |
844 | return -1; | |
845 | break; | |
0864c2d4 JGG |
846 | case NFTNL_UDATA_SET_COMMENT: |
847 | if (value[len - 1] != '\0') | |
848 | return -1; | |
849 | break; | |
6e48df53 FW |
850 | default: |
851 | return 0; | |
852 | } | |
853 | tb[type] = attr; | |
854 | return 0; | |
855 | } | |
856 | ||
857 | static int set_key_parse_udata(const struct nftnl_udata *attr, void *data) | |
858 | { | |
859 | const struct nftnl_udata **tb = data; | |
860 | uint8_t type = nftnl_udata_type(attr); | |
861 | uint8_t len = nftnl_udata_len(attr); | |
862 | ||
863 | switch (type) { | |
864 | case NFTNL_UDATA_SET_TYPEOF_EXPR: | |
865 | if (len != sizeof(uint32_t)) | |
866 | return -1; | |
867 | break; | |
868 | case NFTNL_UDATA_SET_TYPEOF_DATA: | |
869 | break; | |
10bdec0a PNA |
870 | default: |
871 | return 0; | |
872 | } | |
873 | tb[type] = attr; | |
874 | return 0; | |
875 | } | |
876 | ||
6e48df53 FW |
877 | static struct expr *set_make_key(const struct nftnl_udata *attr) |
878 | { | |
879 | const struct nftnl_udata *ud[NFTNL_UDATA_SET_TYPEOF_MAX + 1] = {}; | |
880 | const struct expr_ops *ops; | |
881 | enum expr_types etype; | |
882 | struct expr *expr; | |
883 | int err; | |
884 | ||
885 | if (!attr) | |
886 | return NULL; | |
887 | ||
888 | err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr), | |
889 | set_key_parse_udata, ud); | |
890 | if (err < 0) | |
891 | return NULL; | |
892 | ||
893 | if (!ud[NFTNL_UDATA_SET_TYPEOF_EXPR] || | |
894 | !ud[NFTNL_UDATA_SET_TYPEOF_DATA]) | |
895 | return NULL; | |
896 | ||
897 | etype = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_TYPEOF_EXPR]); | |
898 | ops = expr_ops_by_type(etype); | |
899 | ||
900 | expr = ops->parse_udata(ud[NFTNL_UDATA_SET_TYPEOF_DATA]); | |
901 | if (!expr) | |
902 | return NULL; | |
903 | ||
904 | return expr; | |
905 | } | |
906 | ||
ea31855d | 907 | static bool set_udata_key_valid(const struct expr *e, uint32_t len) |
6e48df53 FW |
908 | { |
909 | if (!e) | |
910 | return false; | |
911 | ||
912 | return div_round_up(e->len, BITS_PER_BYTE) == len / BITS_PER_BYTE; | |
913 | } | |
914 | ||
e6d1d0d6 PNA |
915 | struct setelem_parse_ctx { |
916 | struct set *set; | |
917 | struct nft_cache *cache; | |
918 | struct list_head stmt_list; | |
919 | }; | |
920 | ||
921 | static int set_elem_parse_expressions(struct nftnl_expr *e, void *data) | |
922 | { | |
923 | struct setelem_parse_ctx *setelem_parse_ctx = data; | |
924 | struct nft_cache *cache = setelem_parse_ctx->cache; | |
925 | struct set *set = setelem_parse_ctx->set; | |
926 | struct stmt *stmt; | |
927 | ||
928 | stmt = netlink_parse_set_expr(set, cache, e); | |
929 | list_add_tail(&stmt->list, &setelem_parse_ctx->stmt_list); | |
930 | ||
931 | return 0; | |
932 | } | |
933 | ||
fbcb888b PNA |
934 | struct set *netlink_delinearize_set(struct netlink_ctx *ctx, |
935 | const struct nftnl_set *nls) | |
cc1c2620 | 936 | { |
10da57e3 | 937 | const struct nftnl_udata *ud[NFTNL_UDATA_SET_MAX + 1] = {}; |
fb2d2de9 | 938 | enum byteorder keybyteorder = BYTEORDER_INVALID; |
e6ca6739 | 939 | enum byteorder databyteorder = BYTEORDER_INVALID; |
6e48df53 | 940 | struct expr *typeof_expr_key, *typeof_expr_data; |
e6d1d0d6 | 941 | struct setelem_parse_ctx set_parse_ctx; |
8519ab03 TH |
942 | const struct datatype *datatype = NULL; |
943 | const struct datatype *keytype = NULL; | |
944 | const struct datatype *dtype2 = NULL; | |
945 | const struct datatype *dtype = NULL; | |
0864c2d4 | 946 | const char *udata, *comment = NULL; |
343a5170 | 947 | uint32_t flags, key, objtype = 0; |
9599d9d2 | 948 | uint32_t data_interval = 0; |
30f66792 | 949 | bool automerge = false; |
fb2d2de9 PNA |
950 | struct set *set; |
951 | uint32_t ulen; | |
6e48df53 FW |
952 | uint32_t klen; |
953 | ||
954 | typeof_expr_key = NULL; | |
955 | typeof_expr_data = NULL; | |
fb2d2de9 PNA |
956 | |
957 | if (nftnl_set_is_set(nls, NFTNL_SET_USERDATA)) { | |
958 | udata = nftnl_set_get_data(nls, NFTNL_SET_USERDATA, &ulen); | |
959 | if (nftnl_udata_parse(udata, ulen, set_parse_udata_cb, ud) < 0) { | |
960 | netlink_io_error(ctx, NULL, "Cannot parse userdata"); | |
961 | return NULL; | |
962 | } | |
963 | ||
10da57e3 PS |
964 | #define GET_U32_UDATA(var, attr) \ |
965 | if (ud[attr]) \ | |
966 | var = nftnl_udata_get_u32(ud[attr]) | |
967 | ||
968 | GET_U32_UDATA(keybyteorder, NFTNL_UDATA_SET_KEYBYTEORDER); | |
969 | GET_U32_UDATA(databyteorder, NFTNL_UDATA_SET_DATABYTEORDER); | |
970 | GET_U32_UDATA(automerge, NFTNL_UDATA_SET_MERGE_ELEMENTS); | |
9599d9d2 | 971 | GET_U32_UDATA(data_interval, NFTNL_UDATA_SET_DATA_INTERVAL); |
10da57e3 PS |
972 | |
973 | #undef GET_U32_UDATA | |
6e48df53 FW |
974 | typeof_expr_key = set_make_key(ud[NFTNL_UDATA_SET_KEY_TYPEOF]); |
975 | if (ud[NFTNL_UDATA_SET_DATA_TYPEOF]) | |
976 | typeof_expr_data = set_make_key(ud[NFTNL_UDATA_SET_DATA_TYPEOF]); | |
0864c2d4 | 977 | if (ud[NFTNL_UDATA_SET_COMMENT]) |
accd7a34 | 978 | comment = nftnl_udata_get(ud[NFTNL_UDATA_SET_COMMENT]); |
fb2d2de9 | 979 | } |
cc1c2620 | 980 | |
d6f06c30 | 981 | key = nftnl_set_get_u32(nls, NFTNL_SET_KEY_TYPE); |
cc1c2620 AB |
982 | keytype = dtype_map_from_kernel(key); |
983 | if (keytype == NULL) { | |
984 | netlink_io_error(ctx, NULL, "Unknown data type in set key %u", | |
985 | key); | |
986 | return NULL; | |
987 | } | |
988 | ||
d6f06c30 | 989 | flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS); |
0fd53234 | 990 | if (set_is_datamap(flags)) { |
343a5170 FW |
991 | uint32_t data; |
992 | ||
d6f06c30 | 993 | data = nftnl_set_get_u32(nls, NFTNL_SET_DATA_TYPE); |
cc1c2620 AB |
994 | datatype = dtype_map_from_kernel(data); |
995 | if (datatype == NULL) { | |
996 | netlink_io_error(ctx, NULL, | |
997 | "Unknown data type in set key %u", | |
998 | data); | |
8519ab03 TH |
999 | set = NULL; |
1000 | goto out; | |
cc1c2620 | 1001 | } |
343a5170 | 1002 | } |
cc1c2620 | 1003 | |
0fd53234 | 1004 | if (set_is_objmap(flags)) { |
deaf962e | 1005 | objtype = nftnl_set_get_u32(nls, NFTNL_SET_OBJ_TYPE); |
6e48df53 | 1006 | assert(!datatype); |
deaf962e PNA |
1007 | datatype = &string_type; |
1008 | } | |
1009 | ||
cc1c2620 | 1010 | set = set_alloc(&netlink_location); |
d6f06c30 | 1011 | set->handle.family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY); |
cf646426 | 1012 | set->handle.table.name = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_TABLE)); |
12d57b50 | 1013 | set->handle.set.name = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_NAME)); |
30f66792 | 1014 | set->automerge = automerge; |
0864c2d4 | 1015 | if (comment) |
accd7a34 | 1016 | set->comment = xstrdup(comment); |
cc1c2620 | 1017 | |
e6d1d0d6 PNA |
1018 | init_list_head(&set_parse_ctx.stmt_list); |
1019 | ||
6d80e0f1 PNA |
1020 | if (nftnl_set_is_set(nls, NFTNL_SET_EXPR)) { |
1021 | const struct nftnl_expr *nle; | |
e6d1d0d6 | 1022 | struct stmt *stmt; |
6d80e0f1 PNA |
1023 | |
1024 | nle = nftnl_set_get(nls, NFTNL_SET_EXPR); | |
e6d1d0d6 PNA |
1025 | stmt = netlink_parse_set_expr(set, &ctx->nft->cache, nle); |
1026 | list_add_tail(&stmt->list, &set_parse_ctx.stmt_list); | |
1027 | } else if (nftnl_set_is_set(nls, NFTNL_SET_EXPRESSIONS)) { | |
1028 | set_parse_ctx.cache = &ctx->nft->cache; | |
1029 | set_parse_ctx.set = set; | |
1030 | nftnl_set_expr_foreach(nls, set_elem_parse_expressions, | |
1031 | &set_parse_ctx); | |
6d80e0f1 | 1032 | } |
e6d1d0d6 | 1033 | list_splice_tail(&set_parse_ctx.stmt_list, &set->stmt_list); |
6d80e0f1 | 1034 | |
6e48df53 | 1035 | if (datatype) { |
0583bac2 FW |
1036 | uint32_t dlen; |
1037 | ||
8519ab03 | 1038 | dtype2 = set_datatype_alloc(datatype, databyteorder); |
6e48df53 FW |
1039 | klen = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN) * BITS_PER_BYTE; |
1040 | ||
0583bac2 FW |
1041 | dlen = data_interval ? klen / 2 : klen; |
1042 | ||
1043 | if (set_udata_key_valid(typeof_expr_data, dlen)) { | |
1044 | typeof_expr_data->len = klen; | |
6e48df53 FW |
1045 | set->data = typeof_expr_data; |
1046 | } else { | |
1047 | expr_free(typeof_expr_data); | |
1048 | set->data = constant_expr_alloc(&netlink_location, | |
8519ab03 | 1049 | dtype2, |
6e48df53 FW |
1050 | databyteorder, klen, |
1051 | NULL); | |
1052 | ||
1053 | /* Can't use 'typeof' keyword, so discard key too */ | |
1054 | expr_free(typeof_expr_key); | |
1055 | typeof_expr_key = NULL; | |
1056 | } | |
1057 | ||
9599d9d2 PNA |
1058 | if (data_interval) |
1059 | set->data->flags |= EXPR_F_INTERVAL; | |
6e48df53 FW |
1060 | } |
1061 | ||
1062 | dtype = set_datatype_alloc(keytype, keybyteorder); | |
1063 | klen = nftnl_set_get_u32(nls, NFTNL_SET_KEY_LEN) * BITS_PER_BYTE; | |
1064 | ||
ea31855d | 1065 | if (set_udata_key_valid(typeof_expr_key, klen)) { |
6e48df53 FW |
1066 | set->key = typeof_expr_key; |
1067 | set->key_typeof_valid = true; | |
1068 | } else { | |
1069 | expr_free(typeof_expr_key); | |
1070 | set->key = constant_expr_alloc(&netlink_location, dtype, | |
1071 | keybyteorder, klen, | |
1072 | NULL); | |
1073 | } | |
1074 | ||
d6f06c30 | 1075 | set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS); |
f4a34d25 | 1076 | set->handle.handle.id = nftnl_set_get_u64(nls, NFTNL_SET_HANDLE); |
cc1c2620 | 1077 | |
deaf962e PNA |
1078 | set->objtype = objtype; |
1079 | ||
d6f06c30 PNA |
1080 | if (nftnl_set_is_set(nls, NFTNL_SET_TIMEOUT)) |
1081 | set->timeout = nftnl_set_get_u64(nls, NFTNL_SET_TIMEOUT); | |
1082 | if (nftnl_set_is_set(nls, NFTNL_SET_GC_INTERVAL)) | |
1083 | set->gc_int = nftnl_set_get_u32(nls, NFTNL_SET_GC_INTERVAL); | |
38a077f7 | 1084 | |
d6f06c30 PNA |
1085 | if (nftnl_set_is_set(nls, NFTNL_SET_POLICY)) |
1086 | set->policy = nftnl_set_get_u32(nls, NFTNL_SET_POLICY); | |
90a0f8c4 | 1087 | |
d6f06c30 | 1088 | if (nftnl_set_is_set(nls, NFTNL_SET_DESC_SIZE)) |
947b4fe1 | 1089 | set->desc.size = nftnl_set_get_u32(nls, NFTNL_SET_DESC_SIZE); |
90a0f8c4 | 1090 | |
6156ba34 SB |
1091 | if (nftnl_set_is_set(nls, NFTNL_SET_DESC_CONCAT)) { |
1092 | uint32_t len = NFT_REG32_COUNT; | |
1093 | const uint8_t *data; | |
1094 | ||
1095 | data = nftnl_set_get_data(nls, NFTNL_SET_DESC_CONCAT, &len); | |
1096 | if (data) { | |
1097 | memcpy(set->desc.field_len, data, len); | |
1098 | set->desc.field_count = len; | |
1099 | } | |
1100 | } | |
1101 | ||
8519ab03 TH |
1102 | out: |
1103 | datatype_free(datatype); | |
1104 | datatype_free(keytype); | |
1105 | datatype_free(dtype2); | |
1106 | datatype_free(dtype); | |
cc1c2620 AB |
1107 | return set; |
1108 | } | |
1109 | ||
d6ed28a3 | 1110 | void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls) |
ebfd6822 | 1111 | { |
d6f06c30 | 1112 | struct nftnl_set_elem *nlse; |
ebfd6822 | 1113 | const struct expr *expr; |
ebfd6822 | 1114 | |
ebfd6822 | 1115 | list_for_each_entry(expr, &set->expressions, list) { |
deaf962e | 1116 | nlse = alloc_nftnl_setelem(set, expr); |
d6f06c30 | 1117 | nftnl_set_elem_add(nls, nlse); |
ebfd6822 | 1118 | } |
ebfd6822 PM |
1119 | } |
1120 | ||
34f31e74 | 1121 | static bool range_expr_is_prefix(const struct expr *range, uint32_t *prefix_len) |
9599d9d2 | 1122 | { |
34f31e74 PNA |
1123 | const struct expr *right = range->right; |
1124 | const struct expr *left = range->left; | |
1125 | uint32_t len = left->len; | |
9599d9d2 | 1126 | unsigned long n1, n2; |
34f31e74 PNA |
1127 | uint32_t plen; |
1128 | mpz_t bitmask; | |
9599d9d2 | 1129 | |
34f31e74 PNA |
1130 | mpz_init2(bitmask, left->len); |
1131 | mpz_xor(bitmask, left->value, right->value); | |
9599d9d2 | 1132 | |
34f31e74 PNA |
1133 | n1 = mpz_scan0(bitmask, 0); |
1134 | if (n1 == ULONG_MAX) | |
1135 | goto not_a_prefix; | |
9599d9d2 | 1136 | |
34f31e74 PNA |
1137 | n2 = mpz_scan1(bitmask, n1 + 1); |
1138 | if (n2 < len) | |
1139 | goto not_a_prefix; | |
9599d9d2 | 1140 | |
34f31e74 PNA |
1141 | plen = len - n1; |
1142 | ||
1143 | if (mpz_scan1(left->value, 0) < len - plen) | |
1144 | goto not_a_prefix; | |
1145 | ||
1146 | mpz_clear(bitmask); | |
1147 | *prefix_len = plen; | |
1148 | ||
1149 | return true; | |
1150 | ||
1151 | not_a_prefix: | |
1152 | mpz_clear(bitmask); | |
1153 | ||
1154 | return false; | |
9599d9d2 PNA |
1155 | } |
1156 | ||
ee4391d0 | 1157 | struct expr *range_expr_to_prefix(struct expr *range) |
9599d9d2 | 1158 | { |
34f31e74 PNA |
1159 | struct expr *prefix; |
1160 | uint32_t prefix_len; | |
9599d9d2 | 1161 | |
34f31e74 PNA |
1162 | if (range_expr_is_prefix(range, &prefix_len)) { |
1163 | prefix = prefix_expr_alloc(&range->location, | |
1164 | expr_get(range->left), | |
1165 | prefix_len); | |
1166 | expr_free(range); | |
1167 | return prefix; | |
9599d9d2 | 1168 | } |
9599d9d2 PNA |
1169 | |
1170 | return range; | |
1171 | } | |
1172 | ||
66746e7d PNA |
1173 | static struct expr *range_expr_reduce(struct expr *range) |
1174 | { | |
1175 | struct expr *expr; | |
1176 | ||
1177 | if (!mpz_cmp(range->left->value, range->right->value)) { | |
1178 | expr = expr_get(range->left); | |
1179 | expr_free(range); | |
1180 | return expr; | |
1181 | } | |
1182 | ||
1183 | if (range->left->dtype->type != TYPE_IPADDR && | |
1184 | range->left->dtype->type != TYPE_IP6ADDR) | |
1185 | return range; | |
1186 | ||
1187 | return range_expr_to_prefix(range); | |
1188 | } | |
1189 | ||
1190 | static struct expr *netlink_parse_interval_elem(const struct set *set, | |
9599d9d2 PNA |
1191 | struct expr *expr) |
1192 | { | |
1193 | unsigned int len = div_round_up(expr->len, BITS_PER_BYTE); | |
66746e7d | 1194 | const struct datatype *dtype = set->data->dtype; |
9599d9d2 PNA |
1195 | struct expr *range, *left, *right; |
1196 | char data[len]; | |
1197 | ||
1198 | mpz_export_data(data, expr->value, dtype->byteorder, len); | |
1199 | left = constant_expr_alloc(&internal_location, dtype, | |
1200 | dtype->byteorder, | |
1201 | (len / 2) * BITS_PER_BYTE, &data[0]); | |
1202 | right = constant_expr_alloc(&internal_location, dtype, | |
1203 | dtype->byteorder, | |
1204 | (len / 2) * BITS_PER_BYTE, &data[len / 2]); | |
1205 | range = range_expr_alloc(&expr->location, left, right); | |
1206 | expr_free(expr); | |
1207 | ||
ee4391d0 | 1208 | return range_expr_to_prefix(range); |
9599d9d2 PNA |
1209 | } |
1210 | ||
1017d323 | 1211 | static struct expr *concat_elem_expr(const struct set *set, struct expr *key, |
66746e7d PNA |
1212 | const struct datatype *dtype, |
1213 | struct expr *data, int *off) | |
a93bc179 PM |
1214 | { |
1215 | const struct datatype *subtype; | |
c1c223f1 | 1216 | unsigned int sub_length; |
64bb3f43 | 1217 | struct expr *expr; |
66746e7d | 1218 | |
64bb3f43 PNA |
1219 | if (key) { |
1220 | (*off)--; | |
c1c223f1 FW |
1221 | sub_length = round_up(key->len, BITS_PER_BYTE); |
1222 | ||
1223 | expr = constant_expr_splice(data, sub_length); | |
64bb3f43 PNA |
1224 | expr->dtype = datatype_get(key->dtype); |
1225 | expr->byteorder = key->byteorder; | |
1226 | expr->len = key->len; | |
1227 | } else { | |
1228 | subtype = concat_subtype_lookup(dtype->type, --(*off)); | |
c1c223f1 FW |
1229 | sub_length = round_up(subtype->size, BITS_PER_BYTE); |
1230 | expr = constant_expr_splice(data, sub_length); | |
64bb3f43 PNA |
1231 | expr->dtype = subtype; |
1232 | expr->byteorder = subtype->byteorder; | |
1233 | } | |
66746e7d | 1234 | |
1017d323 PNA |
1235 | if (expr_basetype(expr)->type == TYPE_STRING || |
1236 | (!(set->flags & NFT_SET_INTERVAL) && | |
1237 | expr->byteorder == BYTEORDER_HOST_ENDIAN)) | |
66746e7d PNA |
1238 | mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE); |
1239 | ||
1240 | if (expr->dtype->basetype != NULL && | |
1241 | expr->dtype->basetype->type == TYPE_BITMASK) | |
1242 | expr = bitmask_expr_to_binops(expr); | |
1243 | ||
c1c223f1 | 1244 | data->len -= netlink_padding_len(sub_length); |
66746e7d PNA |
1245 | |
1246 | return expr; | |
1247 | } | |
1248 | ||
1249 | static struct expr *netlink_parse_concat_elem_key(const struct set *set, | |
1250 | struct expr *data) | |
1251 | { | |
1252 | const struct datatype *dtype = set->key->dtype; | |
64bb3f43 | 1253 | struct expr *concat, *expr, *n = NULL; |
a93bc179 PM |
1254 | int off = dtype->subtypes; |
1255 | ||
64bb3f43 PNA |
1256 | if (set->key->etype == EXPR_CONCAT) |
1257 | n = list_first_entry(&set->key->expressions, struct expr, list); | |
1258 | ||
a93bc179 PM |
1259 | concat = concat_expr_alloc(&data->location); |
1260 | while (off > 0) { | |
1017d323 | 1261 | expr = concat_elem_expr(set, n, dtype, data, &off); |
66746e7d | 1262 | compound_expr_add(concat, expr); |
64bb3f43 PNA |
1263 | if (set->key->etype == EXPR_CONCAT) |
1264 | n = list_next_entry(n, list); | |
66746e7d PNA |
1265 | } |
1266 | ||
1267 | expr_free(data); | |
1268 | ||
1269 | return concat; | |
1270 | } | |
1271 | ||
1272 | static struct expr *netlink_parse_concat_elem(const struct set *set, | |
1273 | struct expr *data) | |
1274 | { | |
1275 | const struct datatype *dtype = set->data->dtype; | |
1276 | struct expr *concat, *expr, *left, *range; | |
1277 | struct list_head expressions; | |
1278 | int off = dtype->subtypes; | |
1279 | ||
1280 | init_list_head(&expressions); | |
1281 | ||
1282 | concat = concat_expr_alloc(&data->location); | |
1283 | while (off > 0) { | |
1017d323 | 1284 | expr = concat_elem_expr(set, NULL, dtype, data, &off); |
66746e7d PNA |
1285 | list_add_tail(&expr->list, &expressions); |
1286 | } | |
a93bc179 | 1287 | |
66746e7d PNA |
1288 | if (set->data->flags & EXPR_F_INTERVAL) { |
1289 | assert(!list_empty(&expressions)); | |
a93bc179 | 1290 | |
66746e7d | 1291 | off = dtype->subtypes; |
a93bc179 | 1292 | |
66746e7d PNA |
1293 | while (off > 0) { |
1294 | left = list_first_entry(&expressions, struct expr, list); | |
a93bc179 | 1295 | |
1017d323 | 1296 | expr = concat_elem_expr(set, NULL, dtype, data, &off); |
66746e7d PNA |
1297 | list_del(&left->list); |
1298 | ||
1299 | range = range_expr_alloc(&data->location, left, expr); | |
1300 | range = range_expr_reduce(range); | |
1301 | compound_expr_add(concat, range); | |
1302 | } | |
1303 | assert(list_empty(&expressions)); | |
1304 | } else { | |
1305 | list_splice_tail(&expressions, &concat->expressions); | |
a93bc179 | 1306 | } |
66746e7d | 1307 | |
a93bc179 PM |
1308 | expr_free(data); |
1309 | ||
1310 | return concat; | |
1311 | } | |
1312 | ||
6089630f | 1313 | static int set_elem_parse_udata_cb(const struct nftnl_udata *attr, void *data) |
61f851be | 1314 | { |
6089630f | 1315 | const struct nftnl_udata **tb = data; |
61f851be CFG |
1316 | unsigned char *value = nftnl_udata_get(attr); |
1317 | uint8_t type = nftnl_udata_type(attr); | |
1318 | uint8_t len = nftnl_udata_len(attr); | |
61f851be CFG |
1319 | |
1320 | switch (type) { | |
10da57e3 | 1321 | case NFTNL_UDATA_SET_ELEM_COMMENT: |
61f851be CFG |
1322 | if (value[len - 1] != '\0') |
1323 | return -1; | |
1324 | break; | |
10da57e3 | 1325 | case NFTNL_UDATA_SET_ELEM_FLAGS: |
6089630f PS |
1326 | if (len != sizeof(uint32_t)) |
1327 | return -1; | |
1328 | break; | |
61f851be CFG |
1329 | default: |
1330 | return 0; | |
1331 | } | |
1332 | tb[type] = attr; | |
1333 | return 0; | |
1334 | } | |
1335 | ||
6089630f PS |
1336 | static void set_elem_parse_udata(struct nftnl_set_elem *nlse, |
1337 | struct expr *expr) | |
61f851be | 1338 | { |
10da57e3 | 1339 | const struct nftnl_udata *ud[NFTNL_UDATA_SET_ELEM_MAX + 1] = {}; |
6089630f PS |
1340 | const void *data; |
1341 | uint32_t len; | |
61f851be | 1342 | |
6089630f PS |
1343 | data = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_USERDATA, &len); |
1344 | if (nftnl_udata_parse(data, len, set_elem_parse_udata_cb, ud)) | |
1345 | return; | |
61f851be | 1346 | |
10da57e3 | 1347 | if (ud[NFTNL_UDATA_SET_ELEM_COMMENT]) |
6089630f | 1348 | expr->comment = |
10da57e3 PS |
1349 | xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_SET_ELEM_COMMENT])); |
1350 | if (ud[NFTNL_UDATA_SET_ELEM_FLAGS]) | |
1351 | expr->elem_flags = | |
1352 | nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_ELEM_FLAGS]); | |
61f851be CFG |
1353 | } |
1354 | ||
fbcb888b | 1355 | int netlink_delinearize_setelem(struct nftnl_set_elem *nlse, |
fbae6328 | 1356 | struct set *set, struct nft_cache *cache) |
ebfd6822 | 1357 | { |
e6d1d0d6 PNA |
1358 | struct setelem_parse_ctx setelem_parse_ctx = { |
1359 | .set = set, | |
1360 | .cache = cache, | |
1361 | }; | |
aae836a7 | 1362 | struct nft_data_delinearize nld; |
52532335 | 1363 | struct expr *expr, *key, *data; |
aae836a7 | 1364 | uint32_t flags = 0; |
7c1ccf81 | 1365 | |
e6d1d0d6 PNA |
1366 | init_list_head(&setelem_parse_ctx.stmt_list); |
1367 | ||
419d1968 PNA |
1368 | if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY)) |
1369 | nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY, &nld.len); | |
d6f06c30 PNA |
1370 | if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_FLAGS)) |
1371 | flags = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_FLAGS); | |
ebfd6822 | 1372 | |
8ac2f3b2 | 1373 | key_end: |
419d1968 PNA |
1374 | if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY)) { |
1375 | key = netlink_alloc_value(&netlink_location, &nld); | |
1376 | datatype_set(key, set->key->dtype); | |
1377 | key->byteorder = set->key->byteorder; | |
1378 | if (set->key->dtype->subtypes) | |
66746e7d | 1379 | key = netlink_parse_concat_elem_key(set, key); |
419d1968 PNA |
1380 | |
1381 | if (!(set->flags & NFT_SET_INTERVAL) && | |
1382 | key->byteorder == BYTEORDER_HOST_ENDIAN) | |
1383 | mpz_switch_byteorder(key->value, key->len / BITS_PER_BYTE); | |
1384 | ||
1385 | if (key->dtype->basetype != NULL && | |
1386 | key->dtype->basetype->type == TYPE_BITMASK) | |
1387 | key = bitmask_expr_to_binops(key); | |
1388 | } else if (flags & NFT_SET_ELEM_CATCHALL) { | |
1389 | key = set_elem_catchall_expr_alloc(&netlink_location); | |
1390 | datatype_set(key, set->key->dtype); | |
1391 | key->byteorder = set->key->byteorder; | |
1392 | key->len = set->key->len; | |
1393 | } else { | |
1394 | BUG("Unexpected set element with no key\n"); | |
1395 | } | |
ebfd6822 | 1396 | |
52532335 | 1397 | expr = set_elem_expr_alloc(&netlink_location, key); |
f1cc44ed | 1398 | expr->flags |= EXPR_F_KERNEL; |
242965f4 | 1399 | |
d6f06c30 PNA |
1400 | if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT)) |
1401 | expr->timeout = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_TIMEOUT); | |
1402 | if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPIRATION)) | |
1403 | expr->expiration = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_EXPIRATION); | |
6089630f PS |
1404 | if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_USERDATA)) |
1405 | set_elem_parse_udata(nlse, expr); | |
2d74990a | 1406 | if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPR)) { |
3ed5e31f | 1407 | const struct nftnl_expr *nle; |
e6d1d0d6 | 1408 | struct stmt *stmt; |
3ed5e31f | 1409 | |
2d74990a | 1410 | nle = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_EXPR, NULL); |
e6d1d0d6 PNA |
1411 | stmt = netlink_parse_set_expr(set, cache, nle); |
1412 | list_add_tail(&stmt->list, &setelem_parse_ctx.stmt_list); | |
1413 | } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPRESSIONS)) { | |
1414 | nftnl_set_elem_expr_foreach(nlse, set_elem_parse_expressions, | |
1415 | &setelem_parse_ctx); | |
3ed5e31f | 1416 | } |
0693edb9 | 1417 | list_splice_tail_init(&setelem_parse_ctx.stmt_list, &expr->stmt_list); |
e6d1d0d6 | 1418 | |
fbae6328 | 1419 | if (flags & NFT_SET_ELEM_INTERVAL_END) { |
ebfd6822 | 1420 | expr->flags |= EXPR_F_INTERVAL_END; |
fbae6328 PNA |
1421 | if (mpz_cmp_ui(set->key->value, 0) == 0) |
1422 | set->root = true; | |
1423 | } | |
deaf962e | 1424 | |
0fd53234 | 1425 | if (set_is_datamap(set->flags)) { |
d6f06c30 PNA |
1426 | if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_DATA)) { |
1427 | nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_DATA, | |
947b4fe1 | 1428 | &nld.len); |
d6f06c30 PNA |
1429 | } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_CHAIN)) { |
1430 | nld.chain = nftnl_set_elem_get_str(nlse, NFTNL_SET_ELEM_CHAIN); | |
1431 | nld.verdict = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_VERDICT); | |
1432 | } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_VERDICT)) { | |
1433 | nld.verdict = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_VERDICT); | |
aae836a7 PNA |
1434 | } else |
1435 | goto out; | |
1436 | ||
a144995d | 1437 | data = netlink_alloc_data(&netlink_location, &nld, |
343a5170 | 1438 | set->data->dtype->type == TYPE_VERDICT ? |
ebfd6822 | 1439 | NFT_REG_VERDICT : NFT_REG_1); |
343a5170 FW |
1440 | datatype_set(data, set->data->dtype); |
1441 | data->byteorder = set->data->byteorder; | |
6f0d90ec | 1442 | |
66746e7d PNA |
1443 | if (set->data->dtype->subtypes) { |
1444 | data = netlink_parse_concat_elem(set, data); | |
1445 | } else if (set->data->flags & EXPR_F_INTERVAL) | |
1446 | data = netlink_parse_interval_elem(set, data); | |
6f0d90ec | 1447 | |
a54d7b05 PNA |
1448 | if (data->byteorder == BYTEORDER_HOST_ENDIAN) |
1449 | mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE); | |
ebfd6822 | 1450 | |
a144995d | 1451 | expr = mapping_expr_alloc(&netlink_location, expr, data); |
deaf962e | 1452 | } |
0fd53234 | 1453 | if (set_is_objmap(set->flags)) { |
0d2b22cb PNA |
1454 | if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_OBJREF)) { |
1455 | nld.value = nftnl_set_elem_get(nlse, | |
1456 | NFTNL_SET_ELEM_OBJREF, | |
1457 | &nld.len); | |
1458 | } else | |
1459 | goto out; | |
1460 | ||
deaf962e PNA |
1461 | data = netlink_alloc_value(&netlink_location, &nld); |
1462 | data->dtype = &string_type; | |
1463 | data->byteorder = BYTEORDER_HOST_ENDIAN; | |
1464 | mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE); | |
1465 | expr = mapping_expr_alloc(&netlink_location, expr, data); | |
ebfd6822 | 1466 | } |
aae836a7 | 1467 | out: |
ebfd6822 | 1468 | compound_expr_add(set->init, expr); |
8ac2f3b2 SB |
1469 | |
1470 | if (!(flags & NFT_SET_ELEM_INTERVAL_END) && | |
1471 | nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY_END)) { | |
1472 | flags |= NFT_SET_ELEM_INTERVAL_END; | |
1473 | nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY_END, | |
1474 | &nld.len); | |
1475 | goto key_end; | |
1476 | } | |
1477 | ||
aae836a7 | 1478 | return 0; |
ebfd6822 PM |
1479 | } |
1480 | ||
d6f06c30 | 1481 | static int list_setelem_cb(struct nftnl_set_elem *nlse, void *arg) |
3e1c7b67 AB |
1482 | { |
1483 | struct netlink_ctx *ctx = arg; | |
2dc07bcd | 1484 | return netlink_delinearize_setelem(nlse, ctx->set, &ctx->nft->cache); |
3e1c7b67 AB |
1485 | } |
1486 | ||
ca2e6e0d FW |
1487 | static int list_setelem_debug_cb(struct nftnl_set_elem *nlse, void *arg) |
1488 | { | |
1489 | int r; | |
1490 | ||
1491 | r = list_setelem_cb(nlse, arg); | |
1492 | if (r == 0) { | |
1493 | struct netlink_ctx *ctx = arg; | |
1494 | FILE *fp = ctx->nft->output.output_fp; | |
1495 | ||
1496 | fprintf(fp, "\t"); | |
1497 | nftnl_set_elem_fprintf(fp, nlse, 0, 0); | |
1498 | fprintf(fp, "\n"); | |
1499 | } | |
1500 | ||
1501 | return r; | |
1502 | } | |
1503 | ||
1504 | static int list_setelements(struct nftnl_set *s, struct netlink_ctx *ctx) | |
1505 | { | |
1506 | FILE *fp = ctx->nft->output.output_fp; | |
1507 | ||
1508 | if (fp && (ctx->nft->debug_mask & NFT_DEBUG_NETLINK)) { | |
1509 | const char *table, *name; | |
1510 | uint32_t family = nftnl_set_get_u32(s, NFTNL_SET_FAMILY); | |
1511 | ||
1512 | table = nftnl_set_get_str(s, NFTNL_SET_TABLE); | |
1513 | name = nftnl_set_get_str(s, NFTNL_SET_NAME); | |
1514 | ||
1515 | fprintf(fp, "%s %s @%s\n", family2str(family), table, name); | |
1516 | ||
1517 | return nftnl_set_elem_foreach(s, list_setelem_debug_cb, ctx); | |
1518 | } | |
1519 | ||
1520 | return nftnl_set_elem_foreach(s, list_setelem_cb, ctx); | |
1521 | } | |
1522 | ||
760bd167 | 1523 | int netlink_list_setelems(struct netlink_ctx *ctx, const struct handle *h, |
83e0f440 | 1524 | struct set *set, bool reset) |
ebfd6822 | 1525 | { |
d6f06c30 | 1526 | struct nftnl_set *nls; |
ebfd6822 PM |
1527 | int err; |
1528 | ||
d6ed28a3 PNA |
1529 | nls = nftnl_set_alloc(); |
1530 | if (nls == NULL) | |
1531 | memory_allocation_error(); | |
1532 | ||
1533 | nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family); | |
1534 | nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name); | |
1535 | nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name); | |
1536 | if (h->handle.id) | |
1537 | nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id); | |
7c1ccf81 | 1538 | |
83e0f440 | 1539 | err = mnl_nft_setelem_get(ctx, nls, reset); |
09f81768 | 1540 | if (err < 0) { |
d6f06c30 | 1541 | nftnl_set_free(nls); |
09f81768 PNA |
1542 | if (errno == EINTR) |
1543 | return -1; | |
1544 | ||
760bd167 | 1545 | return 0; |
09f81768 | 1546 | } |
ebfd6822 PM |
1547 | |
1548 | ctx->set = set; | |
760bd167 | 1549 | set->init = set_expr_alloc(&internal_location, set); |
ca2e6e0d | 1550 | list_setelements(nls, ctx); |
14ee0a97 | 1551 | |
8ac2f3b2 SB |
1552 | if (set->flags & NFT_SET_INTERVAL && set->desc.field_count > 1) |
1553 | concat_range_aggregate(set->init); | |
1554 | else if (set->flags & NFT_SET_INTERVAL) | |
1555 | interval_map_decompose(set->init); | |
1556 | else | |
14ee0a97 EL |
1557 | list_expr_sort(&ctx->set->init->expressions); |
1558 | ||
d6f06c30 | 1559 | nftnl_set_free(nls); |
ebfd6822 PM |
1560 | ctx->set = NULL; |
1561 | ||
760bd167 | 1562 | return 0; |
ebfd6822 | 1563 | } |
a72315d2 | 1564 | |
a43cc8d5 | 1565 | int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h, |
ac4b25b3 | 1566 | const struct location *loc, struct set *cache_set, |
83e0f440 | 1567 | struct set *set, struct expr *init, bool reset) |
a43cc8d5 PNA |
1568 | { |
1569 | struct nftnl_set *nls, *nls_out = NULL; | |
8ac2f3b2 | 1570 | int err = 0; |
a43cc8d5 | 1571 | |
d6ed28a3 PNA |
1572 | nls = nftnl_set_alloc(); |
1573 | if (nls == NULL) | |
1574 | memory_allocation_error(); | |
1575 | ||
1576 | nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family); | |
1577 | nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name); | |
1578 | nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name); | |
1579 | if (h->handle.id) | |
1580 | nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id); | |
1581 | ||
a43cc8d5 PNA |
1582 | alloc_setelem_cache(init, nls); |
1583 | ||
1584 | netlink_dump_set(nls, ctx); | |
1585 | ||
83e0f440 | 1586 | nls_out = mnl_nft_setelem_get_one(ctx, nls, reset); |
da5f97e3 PNA |
1587 | if (!nls_out) { |
1588 | nftnl_set_free(nls); | |
70cb4bbd | 1589 | return -1; |
da5f97e3 | 1590 | } |
a43cc8d5 PNA |
1591 | |
1592 | ctx->set = set; | |
1593 | set->init = set_expr_alloc(loc, set); | |
ca2e6e0d | 1594 | list_setelements(nls_out, ctx); |
a43cc8d5 | 1595 | |
8ac2f3b2 SB |
1596 | if (set->flags & NFT_SET_INTERVAL && set->desc.field_count > 1) |
1597 | concat_range_aggregate(set->init); | |
1598 | else if (set->flags & NFT_SET_INTERVAL) | |
ac4b25b3 | 1599 | err = get_set_decompose(cache_set, set); |
8ac2f3b2 | 1600 | else |
a43cc8d5 PNA |
1601 | list_expr_sort(&ctx->set->init->expressions); |
1602 | ||
1603 | nftnl_set_free(nls); | |
1604 | nftnl_set_free(nls_out); | |
1605 | ctx->set = NULL; | |
1606 | ||
8ac2f3b2 | 1607 | return err; |
a43cc8d5 PNA |
1608 | } |
1609 | ||
2535ba70 | 1610 | void netlink_dump_obj(struct nftnl_obj *nln, struct netlink_ctx *ctx) |
4d38878b | 1611 | { |
2dc07bcd | 1612 | FILE *fp = ctx->nft->output.output_fp; |
4d38878b | 1613 | |
2dc07bcd | 1614 | if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp) |
4d38878b PNA |
1615 | return; |
1616 | ||
2535ba70 PS |
1617 | nftnl_obj_fprintf(fp, nln, 0, 0); |
1618 | fprintf(fp, "\n"); | |
4d38878b PNA |
1619 | } |
1620 | ||
293c9b11 JGG |
1621 | static int obj_parse_udata_cb(const struct nftnl_udata *attr, void *data) |
1622 | { | |
1623 | unsigned char *value = nftnl_udata_get(attr); | |
1624 | uint8_t type = nftnl_udata_type(attr); | |
1625 | const struct nftnl_udata **tb = data; | |
1626 | uint8_t len = nftnl_udata_len(attr); | |
1627 | ||
1628 | switch (type) { | |
1629 | case NFTNL_UDATA_OBJ_COMMENT: | |
1630 | if (value[len - 1] != '\0') | |
1631 | return -1; | |
1632 | break; | |
1633 | default: | |
1634 | return 0; | |
1635 | } | |
1636 | tb[type] = attr; | |
1637 | return 0; | |
1638 | } | |
1639 | ||
fbcb888b PNA |
1640 | struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx, |
1641 | struct nftnl_obj *nlo) | |
4756d92e | 1642 | { |
293c9b11 JGG |
1643 | const struct nftnl_udata *ud[NFTNL_UDATA_OBJ_MAX + 1] = {}; |
1644 | const char *udata; | |
4756d92e PNA |
1645 | struct obj *obj; |
1646 | uint32_t type; | |
293c9b11 | 1647 | uint32_t ulen; |
4756d92e PNA |
1648 | |
1649 | obj = obj_alloc(&netlink_location); | |
1650 | obj->handle.family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY); | |
cf646426 | 1651 | obj->handle.table.name = |
4756d92e | 1652 | xstrdup(nftnl_obj_get_str(nlo, NFTNL_OBJ_TABLE)); |
b2a76466 | 1653 | obj->handle.obj.name = |
4756d92e | 1654 | xstrdup(nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME)); |
832b2862 HS |
1655 | obj->handle.handle.id = |
1656 | nftnl_obj_get_u64(nlo, NFTNL_OBJ_HANDLE); | |
293c9b11 JGG |
1657 | if (nftnl_obj_is_set(nlo, NFTNL_OBJ_USERDATA)) { |
1658 | udata = nftnl_obj_get_data(nlo, NFTNL_OBJ_USERDATA, &ulen); | |
1659 | if (nftnl_udata_parse(udata, ulen, obj_parse_udata_cb, ud) < 0) { | |
1660 | netlink_io_error(ctx, NULL, "Cannot parse userdata"); | |
97b5d4bb | 1661 | obj_free(obj); |
293c9b11 JGG |
1662 | return NULL; |
1663 | } | |
1664 | if (ud[NFTNL_UDATA_OBJ_COMMENT]) | |
1665 | obj->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_OBJ_COMMENT])); | |
1666 | } | |
4756d92e PNA |
1667 | |
1668 | type = nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE); | |
1669 | switch (type) { | |
1670 | case NFT_OBJECT_COUNTER: | |
1671 | obj->counter.packets = | |
1672 | nftnl_obj_get_u64(nlo, NFTNL_OBJ_CTR_PKTS); | |
1673 | obj->counter.bytes = | |
1674 | nftnl_obj_get_u64(nlo, NFTNL_OBJ_CTR_BYTES); | |
1675 | break; | |
1676 | case NFT_OBJECT_QUOTA: | |
1677 | obj->quota.bytes = | |
1678 | nftnl_obj_get_u64(nlo, NFTNL_OBJ_QUOTA_BYTES); | |
1679 | obj->quota.used = | |
1680 | nftnl_obj_get_u64(nlo, NFTNL_OBJ_QUOTA_CONSUMED); | |
1681 | obj->quota.flags = | |
1682 | nftnl_obj_get_u32(nlo, NFTNL_OBJ_QUOTA_FLAGS); | |
5ca4eb30 | 1683 | break; |
3bc84e5c CG |
1684 | case NFT_OBJECT_SECMARK: |
1685 | snprintf(obj->secmark.ctx, sizeof(obj->secmark.ctx), "%s", | |
1686 | nftnl_obj_get_str(nlo, NFTNL_OBJ_SECMARK_CTX)); | |
1687 | break; | |
5ca4eb30 | 1688 | case NFT_OBJECT_CT_HELPER: |
f63405f9 | 1689 | snprintf(obj->ct_helper.name, sizeof(obj->ct_helper.name), "%s", |
5ca4eb30 | 1690 | nftnl_obj_get_str(nlo, NFTNL_OBJ_CT_HELPER_NAME)); |
f63405f9 FW |
1691 | obj->ct_helper.l3proto = nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_HELPER_L3PROTO); |
1692 | obj->ct_helper.l4proto = nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_HELPER_L4PROTO); | |
5ca4eb30 | 1693 | break; |
c7c94802 | 1694 | case NFT_OBJECT_CT_TIMEOUT: |
7a0e2672 | 1695 | init_list_head(&obj->ct_timeout.timeout_list); |
c7c94802 HS |
1696 | obj->ct_timeout.l3proto = nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_TIMEOUT_L3PROTO); |
1697 | obj->ct_timeout.l4proto = nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_TIMEOUT_L4PROTO); | |
1698 | memcpy(obj->ct_timeout.timeout, | |
1699 | nftnl_obj_get(nlo, NFTNL_OBJ_CT_TIMEOUT_ARRAY), | |
1700 | NFTNL_CTTIMEOUT_ARRAY_MAX * sizeof(uint32_t)); | |
1701 | break; | |
c0697eab PBG |
1702 | case NFT_OBJECT_LIMIT: |
1703 | obj->limit.rate = | |
1704 | nftnl_obj_get_u64(nlo, NFTNL_OBJ_LIMIT_RATE); | |
1705 | obj->limit.unit = | |
1706 | nftnl_obj_get_u64(nlo, NFTNL_OBJ_LIMIT_UNIT); | |
1707 | obj->limit.burst = | |
1708 | nftnl_obj_get_u32(nlo, NFTNL_OBJ_LIMIT_BURST); | |
1709 | obj->limit.type = | |
1710 | nftnl_obj_get_u32(nlo, NFTNL_OBJ_LIMIT_TYPE); | |
1711 | obj->limit.flags = | |
1712 | nftnl_obj_get_u32(nlo, NFTNL_OBJ_LIMIT_FLAGS); | |
1713 | break; | |
1dd08fcf SV |
1714 | case NFT_OBJECT_CT_EXPECT: |
1715 | obj->ct_expect.l3proto = | |
1716 | nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_EXPECT_L3PROTO); | |
1717 | obj->ct_expect.l4proto = | |
1718 | nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_EXPECT_L4PROTO); | |
1719 | obj->ct_expect.dport = | |
1720 | nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_EXPECT_DPORT); | |
1721 | obj->ct_expect.timeout = | |
1722 | nftnl_obj_get_u32(nlo, NFTNL_OBJ_CT_EXPECT_TIMEOUT); | |
1723 | obj->ct_expect.size = | |
1724 | nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_EXPECT_SIZE); | |
1725 | break; | |
f44ab88b FFM |
1726 | case NFT_OBJECT_SYNPROXY: |
1727 | obj->synproxy.mss = | |
1728 | nftnl_obj_get_u16(nlo, NFTNL_OBJ_SYNPROXY_MSS); | |
1729 | obj->synproxy.wscale = | |
1730 | nftnl_obj_get_u8(nlo, NFTNL_OBJ_SYNPROXY_WSCALE); | |
1731 | obj->synproxy.flags = | |
1732 | nftnl_obj_get_u32(nlo, NFTNL_OBJ_SYNPROXY_FLAGS); | |
1733 | break; | |
4756d92e PNA |
1734 | } |
1735 | obj->type = type; | |
1736 | ||
1737 | return obj; | |
1738 | } | |
1739 | ||
15ab9872 PNA |
1740 | void netlink_dump_flowtable(struct nftnl_flowtable *flo, |
1741 | struct netlink_ctx *ctx) | |
92911b36 | 1742 | { |
2dc07bcd | 1743 | FILE *fp = ctx->nft->output.output_fp; |
92911b36 | 1744 | |
2dc07bcd | 1745 | if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp) |
92911b36 PNA |
1746 | return; |
1747 | ||
1748 | nftnl_flowtable_fprintf(fp, flo, 0, 0); | |
1749 | fprintf(fp, "\n"); | |
1750 | } | |
1751 | ||
4756d92e PNA |
1752 | static int list_obj_cb(struct nftnl_obj *nls, void *arg) |
1753 | { | |
1754 | struct netlink_ctx *ctx = arg; | |
1755 | struct obj *obj; | |
1756 | ||
1757 | obj = netlink_delinearize_obj(ctx, nls); | |
1758 | if (obj == NULL) | |
1759 | return -1; | |
1760 | list_add_tail(&obj->list, &ctx->list); | |
1761 | return 0; | |
1762 | } | |
1763 | ||
2daca4fa PNA |
1764 | int netlink_reset_objs(struct netlink_ctx *ctx, const struct cmd *cmd, |
1765 | uint32_t type, bool dump) | |
8ec2e843 | 1766 | { |
2daca4fa | 1767 | const struct handle *h = &cmd->handle; |
8ec2e843 PNA |
1768 | struct nftnl_obj_list *obj_cache; |
1769 | int err; | |
1770 | ||
657fdefc | 1771 | obj_cache = mnl_nft_obj_dump(ctx, h->family, |
b2a76466 | 1772 | h->table.name, h->obj.name, type, dump, true); |
a8ba88c3 PNA |
1773 | if (obj_cache == NULL) |
1774 | return -1; | |
4756d92e PNA |
1775 | |
1776 | err = nftnl_obj_list_foreach(obj_cache, list_obj_cb, ctx); | |
1777 | nftnl_obj_list_free(obj_cache); | |
1778 | return err; | |
1779 | } | |
1780 | ||
1694df2d PS |
1781 | int netlink_reset_rules(struct netlink_ctx *ctx, const struct cmd *cmd, |
1782 | bool dump) | |
1783 | { | |
1784 | const struct handle *h = &cmd->handle; | |
1785 | struct nft_cache_filter f = { | |
1786 | .list.table = h->table.name, | |
1787 | .list.chain = h->chain.name, | |
1788 | .list.rule_handle = h->handle.id, | |
1789 | }; | |
1790 | struct rule *rule, *next, *crule, *cnext; | |
1791 | struct table *table; | |
1792 | struct chain *chain; | |
1793 | int ret; | |
1794 | ||
1795 | ret = rule_cache_dump(ctx, h, &f, dump, true); | |
1796 | ||
1797 | list_for_each_entry_safe(rule, next, &ctx->list, list) { | |
1798 | table = table_cache_find(&ctx->nft->cache.table_cache, | |
1799 | rule->handle.table.name, | |
1800 | rule->handle.family); | |
1801 | if (!table) | |
1802 | continue; | |
1803 | ||
1804 | chain = chain_cache_find(table, rule->handle.chain.name); | |
1805 | if (!chain) | |
1806 | continue; | |
1807 | ||
1808 | list_del(&rule->list); | |
1809 | list_for_each_entry_safe(crule, cnext, &chain->rules, list) { | |
1810 | if (crule->handle.handle.id != rule->handle.handle.id) | |
1811 | continue; | |
1812 | ||
1813 | list_replace(&crule->list, &rule->list); | |
1814 | rule_free(crule); | |
1815 | rule = NULL; | |
1816 | break; | |
1817 | } | |
1818 | if (rule) { | |
1819 | list_add_tail(&rule->list, &chain->rules); | |
1820 | } | |
1821 | } | |
1822 | list_for_each_entry_safe(rule, next, &ctx->list, list) { | |
1823 | list_del(&rule->list); | |
1824 | rule_free(rule); | |
1825 | } | |
1826 | ||
1827 | return ret; | |
1828 | } | |
1829 | ||
560963c4 | 1830 | struct flowtable * |
db0697ce PNA |
1831 | netlink_delinearize_flowtable(struct netlink_ctx *ctx, |
1832 | struct nftnl_flowtable *nlo) | |
1833 | { | |
1834 | struct flowtable *flowtable; | |
71f755e5 | 1835 | const char * const *dev_array; |
627c451b | 1836 | int len = 0, i, priority; |
db0697ce PNA |
1837 | |
1838 | flowtable = flowtable_alloc(&netlink_location); | |
1839 | flowtable->handle.family = | |
1840 | nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FAMILY); | |
cf646426 | 1841 | flowtable->handle.table.name = |
db0697ce | 1842 | xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_TABLE)); |
81c51fc1 | 1843 | flowtable->handle.flowtable.name = |
db0697ce | 1844 | xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_NAME)); |
91487a80 EJ |
1845 | flowtable->handle.handle.id = |
1846 | nftnl_flowtable_get_u64(nlo, NFTNL_FLOWTABLE_HANDLE); | |
8e6cc9f3 FW |
1847 | if (nftnl_flowtable_is_set(nlo, NFTNL_FLOWTABLE_FLAGS)) |
1848 | flowtable->flags = nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FLAGS); | |
71f755e5 FW |
1849 | dev_array = nftnl_flowtable_get(nlo, NFTNL_FLOWTABLE_DEVICES); |
1850 | while (dev_array[len]) | |
db0697ce PNA |
1851 | len++; |
1852 | ||
927d5674 PS |
1853 | if (len) |
1854 | flowtable->dev_array = xmalloc(len * sizeof(char *)); | |
db0697ce PNA |
1855 | for (i = 0; i < len; i++) |
1856 | flowtable->dev_array[i] = xstrdup(dev_array[i]); | |
1857 | ||
1858 | flowtable->dev_array_len = len; | |
1859 | ||
8161ea94 PNA |
1860 | if (flowtable->dev_array_len) { |
1861 | qsort(flowtable->dev_array, flowtable->dev_array_len, | |
1862 | sizeof(char *), qsort_device_cmp); | |
1863 | } | |
1864 | ||
627c451b FFM |
1865 | priority = nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_PRIO); |
1866 | flowtable->priority.expr = | |
1867 | constant_expr_alloc(&netlink_location, | |
1868 | &integer_type, | |
1869 | BYTEORDER_HOST_ENDIAN, | |
1870 | sizeof(int) * | |
1871 | BITS_PER_BYTE, | |
1872 | &priority); | |
673d82af | 1873 | flowtable->hook.num = |
db0697ce | 1874 | nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_HOOKNUM); |
b119428c PNA |
1875 | flowtable->flags = |
1876 | nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FLAGS); | |
db0697ce PNA |
1877 | |
1878 | return flowtable; | |
1879 | } | |
1880 | ||
1881 | static int list_flowtable_cb(struct nftnl_flowtable *nls, void *arg) | |
1882 | { | |
1883 | struct netlink_ctx *ctx = arg; | |
1884 | struct flowtable *flowtable; | |
1885 | ||
1886 | flowtable = netlink_delinearize_flowtable(ctx, nls); | |
1887 | if (flowtable == NULL) | |
1888 | return -1; | |
1889 | list_add_tail(&flowtable->list, &ctx->list); | |
1890 | return 0; | |
1891 | } | |
1892 | ||
d163ba4d | 1893 | int netlink_list_flowtables(struct netlink_ctx *ctx, const struct handle *h) |
db0697ce PNA |
1894 | { |
1895 | struct nftnl_flowtable_list *flowtable_cache; | |
1896 | int err; | |
1897 | ||
cb4b07d0 PS |
1898 | flowtable_cache = mnl_nft_flowtable_dump(ctx, h->family, |
1899 | h->table.name, NULL); | |
db0697ce PNA |
1900 | if (flowtable_cache == NULL) { |
1901 | if (errno == EINTR) | |
1902 | return -1; | |
1903 | ||
1904 | return 0; | |
1905 | } | |
1906 | ||
1907 | err = nftnl_flowtable_list_foreach(flowtable_cache, list_flowtable_cb, ctx); | |
1908 | nftnl_flowtable_list_free(flowtable_cache); | |
1909 | return err; | |
1910 | } | |
1911 | ||
65747284 PS |
1912 | static void trace_print_hdr(const struct nftnl_trace *nlt, |
1913 | struct output_ctx *octx) | |
be5d9120 | 1914 | { |
65747284 PS |
1915 | nft_print(octx, "trace id %08x %s ", |
1916 | nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID), | |
1917 | family2str(nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY))); | |
be5d9120 | 1918 | if (nftnl_trace_is_set(nlt, NFTNL_TRACE_TABLE)) |
65747284 PS |
1919 | nft_print(octx, "%s ", |
1920 | nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE)); | |
be5d9120 | 1921 | if (nftnl_trace_is_set(nlt, NFTNL_TRACE_CHAIN)) |
65747284 PS |
1922 | nft_print(octx, "%s ", |
1923 | nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN)); | |
be5d9120 PM |
1924 | } |
1925 | ||
1926 | static void trace_print_expr(const struct nftnl_trace *nlt, unsigned int attr, | |
35f6cd32 | 1927 | struct expr *lhs, struct output_ctx *octx) |
be5d9120 PM |
1928 | { |
1929 | struct expr *rhs, *rel; | |
1930 | const void *data; | |
1931 | uint32_t len; | |
1932 | ||
1933 | data = nftnl_trace_get_data(nlt, attr, &len); | |
1934 | rhs = constant_expr_alloc(&netlink_location, | |
1935 | lhs->dtype, lhs->byteorder, | |
1936 | len * BITS_PER_BYTE, data); | |
1937 | rel = relational_expr_alloc(&netlink_location, OP_EQ, lhs, rhs); | |
1938 | ||
35f6cd32 | 1939 | expr_print(rel, octx); |
65747284 | 1940 | nft_print(octx, " "); |
be5d9120 PM |
1941 | expr_free(rel); |
1942 | } | |
1943 | ||
35f6cd32 VR |
1944 | static void trace_print_verdict(const struct nftnl_trace *nlt, |
1945 | struct output_ctx *octx) | |
be5d9120 | 1946 | { |
f1e8a129 | 1947 | struct expr *chain_expr = NULL; |
be5d9120 PM |
1948 | const char *chain = NULL; |
1949 | unsigned int verdict; | |
1950 | struct expr *expr; | |
1951 | ||
1952 | verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT); | |
f1e8a129 | 1953 | if (nftnl_trace_is_set(nlt, NFTNL_TRACE_JUMP_TARGET)) { |
be5d9120 | 1954 | chain = xstrdup(nftnl_trace_get_str(nlt, NFTNL_TRACE_JUMP_TARGET)); |
f1e8a129 FFM |
1955 | chain_expr = constant_expr_alloc(&netlink_location, |
1956 | &string_type, | |
1957 | BYTEORDER_HOST_ENDIAN, | |
619327e3 | 1958 | strlen(chain) * BITS_PER_BYTE, |
f1e8a129 FFM |
1959 | chain); |
1960 | } | |
1961 | expr = verdict_expr_alloc(&netlink_location, verdict, chain_expr); | |
be5d9120 | 1962 | |
78ba4ffd FW |
1963 | nft_print(octx, "verdict "); |
1964 | expr_print(expr, octx); | |
1965 | expr_free(expr); | |
1966 | } | |
1967 | ||
1968 | static void trace_print_policy(const struct nftnl_trace *nlt, | |
1969 | struct output_ctx *octx) | |
1970 | { | |
1971 | unsigned int policy; | |
1972 | struct expr *expr; | |
1973 | ||
1974 | policy = nftnl_trace_get_u32(nlt, NFTNL_TRACE_POLICY); | |
1975 | ||
1976 | expr = verdict_expr_alloc(&netlink_location, policy, NULL); | |
1977 | ||
1978 | nft_print(octx, "policy "); | |
35f6cd32 | 1979 | expr_print(expr, octx); |
be5d9120 PM |
1980 | expr_free(expr); |
1981 | } | |
1982 | ||
0bbd101a LR |
1983 | static struct rule *trace_lookup_rule(const struct nftnl_trace *nlt, |
1984 | uint64_t rule_handle, | |
1985 | struct nft_cache *cache) | |
be5d9120 | 1986 | { |
be5d9120 | 1987 | struct chain *chain; |
0bbd101a | 1988 | struct table *table; |
be5d9120 PM |
1989 | struct handle h; |
1990 | ||
1991 | h.family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY); | |
0bbd101a LR |
1992 | h.table.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE); |
1993 | h.chain.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN); | |
be5d9120 | 1994 | |
cf646426 | 1995 | if (!h.table.name) |
0bbd101a | 1996 | return NULL; |
be5d9120 | 1997 | |
5ec5c706 | 1998 | table = table_cache_find(&cache->table_cache, h.table.name, h.family); |
be5d9120 | 1999 | if (!table) |
0bbd101a | 2000 | return NULL; |
be5d9120 | 2001 | |
797b4f34 | 2002 | chain = chain_cache_find(table, h.chain.name); |
be5d9120 | 2003 | if (!chain) |
0bbd101a LR |
2004 | return NULL; |
2005 | ||
2006 | return rule_lookup(chain, rule_handle); | |
2007 | } | |
2008 | ||
2009 | static void trace_print_rule(const struct nftnl_trace *nlt, | |
2010 | struct output_ctx *octx, struct nft_cache *cache) | |
2011 | { | |
2012 | uint64_t rule_handle; | |
2013 | struct rule *rule; | |
be5d9120 PM |
2014 | |
2015 | rule_handle = nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE); | |
0bbd101a | 2016 | rule = trace_lookup_rule(nlt, rule_handle, cache); |
be5d9120 | 2017 | |
65747284 | 2018 | trace_print_hdr(nlt, octx); |
0bbd101a LR |
2019 | |
2020 | if (rule) { | |
2021 | nft_print(octx, "rule "); | |
2022 | rule_print(rule, octx); | |
2023 | } else { | |
2024 | nft_print(octx, "unknown rule handle %" PRIu64, rule_handle); | |
2025 | } | |
2026 | ||
65747284 | 2027 | nft_print(octx, " ("); |
35f6cd32 | 2028 | trace_print_verdict(nlt, octx); |
65747284 | 2029 | nft_print(octx, ")\n"); |
be5d9120 PM |
2030 | } |
2031 | ||
2032 | static void trace_gen_stmts(struct list_head *stmts, | |
2033 | struct proto_ctx *ctx, struct payload_dep_ctx *pctx, | |
2034 | const struct nftnl_trace *nlt, unsigned int attr, | |
2035 | enum proto_bases base) | |
2036 | { | |
2037 | struct list_head unordered = LIST_HEAD_INIT(unordered); | |
2038 | struct list_head list; | |
2039 | struct expr *rel, *lhs, *rhs, *tmp, *nexpr; | |
2040 | struct stmt *stmt; | |
2041 | const struct proto_desc *desc; | |
2042 | const void *hdr; | |
2043 | uint32_t hlen; | |
2044 | unsigned int n; | |
be5d9120 PM |
2045 | |
2046 | if (!nftnl_trace_is_set(nlt, attr)) | |
2047 | return; | |
2048 | hdr = nftnl_trace_get_data(nlt, attr, &hlen); | |
2049 | ||
2050 | lhs = payload_expr_alloc(&netlink_location, NULL, 0); | |
2051 | payload_init_raw(lhs, base, 0, hlen * BITS_PER_BYTE); | |
2052 | rhs = constant_expr_alloc(&netlink_location, | |
2053 | &invalid_type, BYTEORDER_INVALID, | |
2054 | hlen * BITS_PER_BYTE, hdr); | |
2055 | ||
2056 | restart: | |
2057 | init_list_head(&list); | |
2058 | payload_expr_expand(&list, lhs, ctx); | |
2059 | expr_free(lhs); | |
2060 | ||
2061 | desc = NULL; | |
2062 | list_for_each_entry_safe(lhs, nexpr, &list, list) { | |
2063 | if (desc && desc != ctx->protocol[base].desc) { | |
2064 | /* Chained protocols */ | |
2065 | lhs->payload.offset = 0; | |
2066 | if (ctx->protocol[base].desc == NULL) | |
2067 | break; | |
2068 | goto restart; | |
2069 | } | |
2070 | ||
2071 | tmp = constant_expr_splice(rhs, lhs->len); | |
2072 | expr_set_type(tmp, lhs->dtype, lhs->byteorder); | |
2073 | if (tmp->byteorder == BYTEORDER_HOST_ENDIAN) | |
2074 | mpz_switch_byteorder(tmp->value, tmp->len / BITS_PER_BYTE); | |
2075 | ||
2076 | /* Skip unknown and filtered expressions */ | |
2077 | desc = lhs->payload.desc; | |
2078 | if (lhs->dtype == &invalid_type || | |
2079 | desc->checksum_key == payload_hdr_field(lhs) || | |
2080 | desc->format.filter & (1 << payload_hdr_field(lhs))) { | |
2081 | expr_free(lhs); | |
2082 | expr_free(tmp); | |
2083 | continue; | |
2084 | } | |
2085 | ||
2086 | rel = relational_expr_alloc(&lhs->location, OP_EQ, lhs, tmp); | |
2087 | stmt = expr_stmt_alloc(&rel->location, rel); | |
2088 | list_add_tail(&stmt->list, &unordered); | |
2089 | ||
2090 | desc = ctx->protocol[base].desc; | |
a2c55e04 | 2091 | relational_expr_pctx_update(ctx, rel); |
be5d9120 PM |
2092 | } |
2093 | ||
2094 | expr_free(rhs); | |
2095 | ||
2096 | n = 0; | |
2097 | next: | |
2098 | list_for_each_entry(stmt, &unordered, list) { | |
6217dfe0 JS |
2099 | enum proto_bases b = base; |
2100 | ||
be5d9120 PM |
2101 | rel = stmt->expr; |
2102 | lhs = rel->left; | |
2103 | ||
2104 | /* Move statements to result list in defined order */ | |
2105 | desc = lhs->payload.desc; | |
2106 | if (desc->format.order[n] && | |
2107 | desc->format.order[n] != payload_hdr_field(lhs)) | |
2108 | continue; | |
2109 | ||
2110 | list_move_tail(&stmt->list, stmts); | |
2111 | n++; | |
2112 | ||
6217dfe0 JS |
2113 | if (payload_is_stacked(desc, rel)) |
2114 | b--; | |
be5d9120 | 2115 | |
70d05dc5 JS |
2116 | /* Don't strip 'icmp type' from payload dump. */ |
2117 | if (pctx->icmp_type == 0) | |
2118 | payload_dependency_kill(pctx, lhs, ctx->family); | |
2119 | if (lhs->flags & EXPR_F_PROTOCOL) | |
6217dfe0 | 2120 | payload_dependency_store(pctx, stmt, b); |
be5d9120 PM |
2121 | |
2122 | goto next; | |
2123 | } | |
2124 | } | |
2125 | ||
35f6cd32 VR |
2126 | static void trace_print_packet(const struct nftnl_trace *nlt, |
2127 | struct output_ctx *octx) | |
be5d9120 PM |
2128 | { |
2129 | struct list_head stmts = LIST_HEAD_INIT(stmts); | |
9604b087 | 2130 | const struct proto_desc *ll_desc; |
be5d9120 PM |
2131 | struct payload_dep_ctx pctx = {}; |
2132 | struct proto_ctx ctx; | |
2133 | uint16_t dev_type; | |
2134 | uint32_t nfproto; | |
2135 | struct stmt *stmt, *next; | |
2136 | ||
65747284 | 2137 | trace_print_hdr(nlt, octx); |
be5d9120 | 2138 | |
65747284 | 2139 | nft_print(octx, "packet: "); |
be5d9120 PM |
2140 | if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF)) |
2141 | trace_print_expr(nlt, NFTNL_TRACE_IIF, | |
2142 | meta_expr_alloc(&netlink_location, | |
35f6cd32 | 2143 | NFT_META_IIF), octx); |
be5d9120 PM |
2144 | if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF)) |
2145 | trace_print_expr(nlt, NFTNL_TRACE_OIF, | |
2146 | meta_expr_alloc(&netlink_location, | |
35f6cd32 | 2147 | NFT_META_OIF), octx); |
be5d9120 | 2148 | |
75b096c0 | 2149 | proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY), 0, false); |
9604b087 FW |
2150 | ll_desc = ctx.protocol[PROTO_BASE_LL_HDR].desc; |
2151 | if ((ll_desc == &proto_inet || ll_desc == &proto_netdev) && | |
be5d9120 PM |
2152 | nftnl_trace_is_set(nlt, NFTNL_TRACE_NFPROTO)) { |
2153 | nfproto = nftnl_trace_get_u32(nlt, NFTNL_TRACE_NFPROTO); | |
9604b087 | 2154 | |
be5d9120 PM |
2155 | proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &netlink_location, NULL); |
2156 | proto_ctx_update(&ctx, PROTO_BASE_NETWORK_HDR, &netlink_location, | |
9604b087 | 2157 | proto_find_upper(ll_desc, nfproto)); |
be5d9120 PM |
2158 | } |
2159 | if (ctx.protocol[PROTO_BASE_LL_HDR].desc == NULL && | |
2160 | nftnl_trace_is_set(nlt, NFTNL_TRACE_IIFTYPE)) { | |
2161 | dev_type = nftnl_trace_get_u16(nlt, NFTNL_TRACE_IIFTYPE); | |
2162 | proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &netlink_location, | |
2163 | proto_dev_desc(dev_type)); | |
2164 | } | |
2165 | ||
2166 | trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_LL_HEADER, | |
2167 | PROTO_BASE_LL_HDR); | |
2168 | trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_NETWORK_HEADER, | |
2169 | PROTO_BASE_NETWORK_HDR); | |
2170 | trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_TRANSPORT_HEADER, | |
2171 | PROTO_BASE_TRANSPORT_HDR); | |
2172 | ||
2173 | list_for_each_entry_safe(stmt, next, &stmts, list) { | |
35f6cd32 | 2174 | stmt_print(stmt, octx); |
65747284 | 2175 | nft_print(octx, " "); |
be5d9120 PM |
2176 | stmt_free(stmt); |
2177 | } | |
65747284 | 2178 | nft_print(octx, "\n"); |
be5d9120 PM |
2179 | } |
2180 | ||
fbcb888b PNA |
2181 | int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type, |
2182 | struct netlink_mon_handler *monh) | |
be5d9120 PM |
2183 | { |
2184 | struct nftnl_trace *nlt; | |
2185 | ||
2186 | assert(type == NFT_MSG_TRACE); | |
2187 | ||
2188 | nlt = nftnl_trace_alloc(); | |
2189 | if (!nlt) | |
2190 | memory_allocation_error(); | |
2191 | ||
2192 | if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0) | |
2193 | netlink_abi_error(); | |
2194 | ||
871fb4ea FW |
2195 | if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) || |
2196 | nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER)) | |
2197 | trace_print_packet(nlt, &monh->ctx->nft->output); | |
2198 | ||
be5d9120 PM |
2199 | switch (nftnl_trace_get_u32(nlt, NFTNL_TRACE_TYPE)) { |
2200 | case NFT_TRACETYPE_RULE: | |
be5d9120 | 2201 | if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE)) |
2dc07bcd PNA |
2202 | trace_print_rule(nlt, &monh->ctx->nft->output, |
2203 | &monh->ctx->nft->cache); | |
be5d9120 PM |
2204 | break; |
2205 | case NFT_TRACETYPE_POLICY: | |
2dc07bcd | 2206 | trace_print_hdr(nlt, &monh->ctx->nft->output); |
78ba4ffd FW |
2207 | |
2208 | if (nftnl_trace_is_set(nlt, NFTNL_TRACE_POLICY)) { | |
2dc07bcd | 2209 | trace_print_policy(nlt, &monh->ctx->nft->output); |
78ba4ffd FW |
2210 | nft_mon_print(monh, " "); |
2211 | } | |
2212 | ||
2213 | if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK)) | |
2214 | trace_print_expr(nlt, NFTNL_TRACE_MARK, | |
2215 | meta_expr_alloc(&netlink_location, | |
2216 | NFT_META_MARK), | |
2dc07bcd | 2217 | &monh->ctx->nft->output); |
78ba4ffd FW |
2218 | nft_mon_print(monh, "\n"); |
2219 | break; | |
be5d9120 | 2220 | case NFT_TRACETYPE_RETURN: |
2dc07bcd | 2221 | trace_print_hdr(nlt, &monh->ctx->nft->output); |
be5d9120 PM |
2222 | |
2223 | if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT)) { | |
2dc07bcd | 2224 | trace_print_verdict(nlt, &monh->ctx->nft->output); |
65747284 | 2225 | nft_mon_print(monh, " "); |
be5d9120 PM |
2226 | } |
2227 | ||
2228 | if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK)) | |
2229 | trace_print_expr(nlt, NFTNL_TRACE_MARK, | |
2230 | meta_expr_alloc(&netlink_location, | |
35f6cd32 | 2231 | NFT_META_MARK), |
2dc07bcd | 2232 | &monh->ctx->nft->output); |
65747284 | 2233 | nft_mon_print(monh, "\n"); |
be5d9120 PM |
2234 | break; |
2235 | } | |
2236 | ||
2237 | nftnl_trace_free(nlt); | |
2238 | return MNL_CB_OK; | |
2239 | } |