0d15f9235b82961677ca32afc426f4d770ee9aa2
[openwrt/openwrt.git] / package / libs / libnftnl / patches / 100-src-add-flowtable-support.patch
1 From: Pablo Neira Ayuso <pablo@netfilter.org>
2 Date: Wed, 29 Nov 2017 13:07:02 +0100
3 Subject: [PATCH] src: add flowtable support
4
5 This patch allows you to add, delete and list flowtable through the
6 existing netlink interface.
7
8 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
9 ---
10 create mode 100644 examples/nft-flowtable-add.c
11 create mode 100644 examples/nft-flowtable-del.c
12 create mode 100644 examples/nft-flowtable-get.c
13 create mode 100644 include/libnftnl/flowtable.h
14 create mode 100644 src/flowtable.c
15
16 --- a/examples/Makefile.am
17 +++ b/examples/Makefile.am
18 @@ -25,6 +25,9 @@ check_PROGRAMS = nft-table-add \
19 nft-obj-add \
20 nft-obj-get \
21 nft-obj-del \
22 + nft-flowtable-add \
23 + nft-flowtable-del \
24 + nft-flowtable-get \
25 nft-ruleset-get \
26 nft-ruleset-parse-file \
27 nft-compat-get
28 @@ -104,6 +107,15 @@ nft_obj_del_LDADD = ../src/libnftnl.la $
29 nft_obj_get_SOURCES = nft-obj-get.c
30 nft_obj_get_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS}
31
32 +nft_flowtable_add_SOURCES = nft-flowtable-add.c
33 +nft_flowtable_add_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS}
34 +
35 +nft_flowtable_del_SOURCES = nft-flowtable-del.c
36 +nft_flowtable_del_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS}
37 +
38 +nft_flowtable_get_SOURCES = nft-flowtable-get.c
39 +nft_flowtable_get_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS}
40 +
41 nft_ruleset_get_SOURCES = nft-ruleset-get.c
42 nft_ruleset_get_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS}
43
44 --- /dev/null
45 +++ b/examples/nft-flowtable-add.c
46 @@ -0,0 +1,136 @@
47 +#include <stdlib.h>
48 +#include <time.h>
49 +#include <string.h>
50 +#include <netinet/in.h>
51 +
52 +#include <linux/netfilter.h>
53 +#include <linux/netfilter/nf_tables.h>
54 +
55 +#include <libmnl/libmnl.h>
56 +#include <libnftnl/flowtable.h>
57 +
58 +static struct nftnl_flowtable *flowtable_add_parse(int argc, char *argv[])
59 +{
60 + const char *dev_array[] = { "eth0", "tap0", NULL };
61 + struct nftnl_flowtable *t;
62 + int hooknum = 0;
63 +
64 + if (strcmp(argv[4], "ingress") == 0)
65 + hooknum = NF_NETDEV_INGRESS;
66 + else {
67 + fprintf(stderr, "Unknown hook: %s\n", argv[4]);
68 + return NULL;
69 + }
70 +
71 + t = nftnl_flowtable_alloc();
72 + if (t == NULL) {
73 + perror("OOM");
74 + return NULL;
75 + }
76 + nftnl_flowtable_set(t, NFTNL_FLOWTABLE_TABLE, argv[2]);
77 + nftnl_flowtable_set(t, NFTNL_FLOWTABLE_NAME, argv[3]);
78 + if (argc == 6) {
79 + nftnl_flowtable_set_u32(t, NFTNL_FLOWTABLE_HOOKNUM, hooknum);
80 + nftnl_flowtable_set_u32(t, NFTNL_FLOWTABLE_PRIO, atoi(argv[5]));
81 + }
82 + nftnl_flowtable_set_array(t, NFTNL_FLOWTABLE_DEVICES, dev_array);
83 +
84 + return t;
85 +}
86 +
87 +int main(int argc, char *argv[])
88 +{
89 + struct mnl_socket *nl;
90 + char buf[MNL_SOCKET_BUFFER_SIZE];
91 + struct nlmsghdr *nlh;
92 + uint32_t portid, seq, flowtable_seq;
93 + int ret, family;
94 + struct nftnl_flowtable *t;
95 + struct mnl_nlmsg_batch *batch;
96 + int batching;
97 +
98 + if (argc != 6) {
99 + fprintf(stderr, "Usage: %s <family> <table> <name> <hook> <prio>\n",
100 + argv[0]);
101 + exit(EXIT_FAILURE);
102 + }
103 +
104 + if (strcmp(argv[1], "ip") == 0)
105 + family = NFPROTO_IPV4;
106 + else if (strcmp(argv[1], "ip6") == 0)
107 + family = NFPROTO_IPV6;
108 + else if (strcmp(argv[1], "bridge") == 0)
109 + family = NFPROTO_BRIDGE;
110 + else if (strcmp(argv[1], "arp") == 0)
111 + family = NFPROTO_ARP;
112 + else {
113 + fprintf(stderr, "Unknown family: ip, ip6, bridge, arp\n");
114 + exit(EXIT_FAILURE);
115 + }
116 +
117 + t = flowtable_add_parse(argc, argv);
118 + if (t == NULL)
119 + exit(EXIT_FAILURE);
120 +
121 + batching = nftnl_batch_is_supported();
122 + if (batching < 0) {
123 + perror("cannot talk to nfnetlink");
124 + exit(EXIT_FAILURE);
125 + }
126 +
127 + seq = time(NULL);
128 + batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
129 +
130 + if (batching) {
131 + nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
132 + mnl_nlmsg_batch_next(batch);
133 + }
134 +
135 + flowtable_seq = seq;
136 + nlh = nftnl_flowtable_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
137 + NFT_MSG_NEWFLOWTABLE, family,
138 + NLM_F_CREATE|NLM_F_ACK, seq++);
139 + nftnl_flowtable_nlmsg_build_payload(nlh, t);
140 + nftnl_flowtable_free(t);
141 + mnl_nlmsg_batch_next(batch);
142 +
143 + if (batching) {
144 + nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
145 + mnl_nlmsg_batch_next(batch);
146 + }
147 +
148 + nl = mnl_socket_open(NETLINK_NETFILTER);
149 + if (nl == NULL) {
150 + perror("mnl_socket_open");
151 + exit(EXIT_FAILURE);
152 + }
153 +
154 + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
155 + perror("mnl_socket_bind");
156 + exit(EXIT_FAILURE);
157 + }
158 + portid = mnl_socket_get_portid(nl);
159 +
160 + if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
161 + mnl_nlmsg_batch_size(batch)) < 0) {
162 + perror("mnl_socket_send");
163 + exit(EXIT_FAILURE);
164 + }
165 +
166 + mnl_nlmsg_batch_stop(batch);
167 +
168 + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
169 + while (ret > 0) {
170 + ret = mnl_cb_run(buf, ret, flowtable_seq, portid, NULL, NULL);
171 + if (ret <= 0)
172 + break;
173 + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
174 + }
175 + if (ret == -1) {
176 + perror("error");
177 + exit(EXIT_FAILURE);
178 + }
179 + mnl_socket_close(nl);
180 +
181 + return EXIT_SUCCESS;
182 +}
183 --- /dev/null
184 +++ b/examples/nft-flowtable-del.c
185 @@ -0,0 +1,122 @@
186 +#include <stdlib.h>
187 +#include <time.h>
188 +#include <string.h>
189 +#include <netinet/in.h>
190 +
191 +#include <linux/netfilter.h>
192 +#include <linux/netfilter/nf_tables.h>
193 +
194 +#include <libmnl/libmnl.h>
195 +#include <libnftnl/flowtable.h>
196 +
197 +static struct nftnl_flowtable *flowtable_del_parse(int argc, char *argv[])
198 +{
199 + struct nftnl_flowtable *t;
200 +
201 + t = nftnl_flowtable_alloc();
202 + if (t == NULL) {
203 + perror("OOM");
204 + return NULL;
205 + }
206 +
207 + nftnl_flowtable_set(t, NFTNL_FLOWTABLE_TABLE, argv[2]);
208 + nftnl_flowtable_set(t, NFTNL_FLOWTABLE_NAME, argv[3]);
209 +
210 + return t;
211 +}
212 +
213 +int main(int argc, char *argv[])
214 +{
215 + struct mnl_socket *nl;
216 + struct mnl_nlmsg_batch *batch;
217 + char buf[MNL_SOCKET_BUFFER_SIZE];
218 + struct nlmsghdr *nlh;
219 + uint32_t portid, seq, flowtable_seq;
220 + struct nftnl_flowtable *t;
221 + int ret, family, batching;
222 +
223 + if (argc != 4) {
224 + fprintf(stderr, "Usage: %s <family> <table> <flowtable>\n",
225 + argv[0]);
226 + exit(EXIT_FAILURE);
227 + }
228 +
229 + if (strcmp(argv[1], "ip") == 0)
230 + family = NFPROTO_IPV4;
231 + else if (strcmp(argv[1], "ip6") == 0)
232 + family = NFPROTO_IPV6;
233 + else if (strcmp(argv[1], "bridge") == 0)
234 + family = NFPROTO_BRIDGE;
235 + else if (strcmp(argv[1], "arp") == 0)
236 + family = NFPROTO_ARP;
237 + else {
238 + fprintf(stderr, "Unknown family: ip, ip6, bridge, arp\n");
239 + exit(EXIT_FAILURE);
240 + }
241 +
242 + t = flowtable_del_parse(argc, argv);
243 + if (t == NULL)
244 + exit(EXIT_FAILURE);
245 +
246 + batching = nftnl_batch_is_supported();
247 + if (batching < 0) {
248 + perror("cannot talk to nfnetlink");
249 + exit(EXIT_FAILURE);
250 + }
251 +
252 + seq = time(NULL);
253 + batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
254 +
255 + if (batching) {
256 + nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
257 + mnl_nlmsg_batch_next(batch);
258 + }
259 +
260 + flowtable_seq = seq;
261 + nlh = nftnl_flowtable_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
262 + NFT_MSG_DELFLOWTABLE, family,
263 + NLM_F_ACK, seq++);
264 + nftnl_flowtable_nlmsg_build_payload(nlh, t);
265 + nftnl_flowtable_free(t);
266 + mnl_nlmsg_batch_next(batch);
267 +
268 + if (batching) {
269 + nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
270 + mnl_nlmsg_batch_next(batch);
271 + }
272 +
273 + nl = mnl_socket_open(NETLINK_NETFILTER);
274 + if (nl == NULL) {
275 + perror("mnl_socket_open");
276 + exit(EXIT_FAILURE);
277 + }
278 +
279 + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
280 + perror("mnl_socket_bind");
281 + exit(EXIT_FAILURE);
282 + }
283 + portid = mnl_socket_get_portid(nl);
284 +
285 + if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
286 + mnl_nlmsg_batch_size(batch)) < 0) {
287 + perror("mnl_socket_send");
288 + exit(EXIT_FAILURE);
289 + }
290 +
291 + mnl_nlmsg_batch_stop(batch);
292 +
293 + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
294 + while (ret > 0) {
295 + ret = mnl_cb_run(buf, ret, flowtable_seq, portid, NULL, NULL);
296 + if (ret <= 0)
297 + break;
298 + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
299 + }
300 + if (ret == -1) {
301 + perror("error");
302 + exit(EXIT_FAILURE);
303 + }
304 + mnl_socket_close(nl);
305 +
306 + return EXIT_SUCCESS;
307 +}
308 --- /dev/null
309 +++ b/examples/nft-flowtable-get.c
310 @@ -0,0 +1,121 @@
311 +#include <stdlib.h>
312 +#include <time.h>
313 +#include <string.h>
314 +#include <netinet/in.h>
315 +
316 +#include <linux/netfilter.h>
317 +#include <linux/netfilter/nf_tables.h>
318 +
319 +#include <libmnl/libmnl.h>
320 +#include <libnftnl/flowtable.h>
321 +
322 +static int table_cb(const struct nlmsghdr *nlh, void *data)
323 +{
324 + struct nftnl_flowtable *t;
325 + char buf[4096];
326 + uint32_t *type = data;
327 +
328 + t = nftnl_flowtable_alloc();
329 + if (t == NULL) {
330 + perror("OOM");
331 + goto err;
332 + }
333 +
334 + if (nftnl_flowtable_nlmsg_parse(nlh, t) < 0) {
335 + perror("nftnl_flowtable_nlmsg_parse");
336 + goto err_free;
337 + }
338 +
339 + nftnl_flowtable_snprintf(buf, sizeof(buf), t, *type, 0);
340 + printf("%s\n", buf);
341 +
342 +err_free:
343 + nftnl_flowtable_free(t);
344 +err:
345 + return MNL_CB_OK;
346 +}
347 +
348 +int main(int argc, char *argv[])
349 +{
350 + struct mnl_socket *nl;
351 + char buf[MNL_SOCKET_BUFFER_SIZE];
352 + struct nlmsghdr *nlh;
353 + uint32_t portid, seq, type = NFTNL_OUTPUT_DEFAULT;
354 + struct nftnl_flowtable *t = NULL;
355 + int ret, family;
356 +
357 + seq = time(NULL);
358 +
359 + if (argc < 2 || argc > 5) {
360 + fprintf(stderr, "Usage: %s <family> [<table> <flowtable>] [json]\n",
361 + argv[0]);
362 + exit(EXIT_FAILURE);
363 + }
364 +
365 + if (strcmp(argv[1], "ip") == 0)
366 + family = NFPROTO_IPV4;
367 + else if (strcmp(argv[1], "ip6") == 0)
368 + family = NFPROTO_IPV6;
369 + else if (strcmp(argv[1], "bridge") == 0)
370 + family = NFPROTO_BRIDGE;
371 + else if (strcmp(argv[1], "arp") == 0)
372 + family = NFPROTO_ARP;
373 + else if (strcmp(argv[1], "unspec") == 0)
374 + family = NFPROTO_UNSPEC;
375 + else {
376 + fprintf(stderr, "Unknown family: ip, ip6, bridge, arp, unspec\n");
377 + exit(EXIT_FAILURE);
378 + }
379 +
380 + if (argc >= 4) {
381 + t = nftnl_flowtable_alloc();
382 + if (t == NULL) {
383 + perror("OOM");
384 + exit(EXIT_FAILURE);
385 + }
386 + nlh = nftnl_flowtable_nlmsg_build_hdr(buf, NFT_MSG_GETFLOWTABLE, family,
387 + NLM_F_ACK, seq);
388 + nftnl_flowtable_set(t, NFTNL_FLOWTABLE_TABLE, argv[2]);
389 + nftnl_flowtable_set(t, NFTNL_FLOWTABLE_NAME, argv[3]);
390 + nftnl_flowtable_nlmsg_build_payload(nlh, t);
391 + nftnl_flowtable_free(t);
392 + } else if (argc >= 2) {
393 + nlh = nftnl_flowtable_nlmsg_build_hdr(buf, NFT_MSG_GETFLOWTABLE, family,
394 + NLM_F_DUMP, seq);
395 + }
396 +
397 + if (strcmp(argv[argc-1], "json") == 0)
398 + type = NFTNL_OUTPUT_JSON;
399 +
400 + nl = mnl_socket_open(NETLINK_NETFILTER);
401 + if (nl == NULL) {
402 + perror("mnl_socket_open");
403 + exit(EXIT_FAILURE);
404 + }
405 +
406 + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
407 + perror("mnl_socket_bind");
408 + exit(EXIT_FAILURE);
409 + }
410 + portid = mnl_socket_get_portid(nl);
411 +
412 + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
413 + perror("mnl_socket_send");
414 + exit(EXIT_FAILURE);
415 + }
416 +
417 + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
418 + while (ret > 0) {
419 + ret = mnl_cb_run(buf, ret, seq, portid, table_cb, &type);
420 + if (ret <= 0)
421 + break;
422 + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
423 + }
424 + if (ret == -1) {
425 + perror("error");
426 + exit(EXIT_FAILURE);
427 + }
428 + mnl_socket_close(nl);
429 +
430 + return EXIT_SUCCESS;
431 +}
432 --- a/include/libnftnl/Makefile.am
433 +++ b/include/libnftnl/Makefile.am
434 @@ -6,6 +6,7 @@ pkginclude_HEADERS = batch.h \
435 rule.h \
436 expr.h \
437 set.h \
438 + flowtable.h \
439 ruleset.h \
440 common.h \
441 udata.h \
442 --- /dev/null
443 +++ b/include/libnftnl/flowtable.h
444 @@ -0,0 +1,81 @@
445 +#ifndef _LIBNFTNL_FLOWTABLE_H_
446 +#define _LIBNFTNL_FLOWTABLE_H_
447 +
448 +#include <stdio.h>
449 +#include <stdint.h>
450 +#include <stdbool.h>
451 +#include <sys/types.h>
452 +
453 +#include <libnftnl/common.h>
454 +
455 +#ifdef __cplusplus
456 +extern "C" {
457 +#endif
458 +
459 +struct nftnl_flowtable;
460 +
461 +struct nftnl_flowtable *nftnl_flowtable_alloc(void);
462 +void nftnl_flowtable_free(const struct nftnl_flowtable *);
463 +
464 +enum nftnl_flowtable_attr {
465 + NFTNL_FLOWTABLE_NAME = 0,
466 + NFTNL_FLOWTABLE_FAMILY,
467 + NFTNL_FLOWTABLE_TABLE,
468 + NFTNL_FLOWTABLE_HOOKNUM,
469 + NFTNL_FLOWTABLE_PRIO = 4,
470 + NFTNL_FLOWTABLE_USE,
471 + NFTNL_FLOWTABLE_DEVICES,
472 + __NFTNL_FLOWTABLE_MAX
473 +};
474 +#define NFTNL_FLOWTABLE_MAX (__NFTNL_FLOWTABLE_MAX - 1)
475 +
476 +bool nftnl_flowtable_is_set(const struct nftnl_flowtable *c, uint16_t attr);
477 +void nftnl_flowtable_unset(struct nftnl_flowtable *c, uint16_t attr);
478 +void nftnl_flowtable_set(struct nftnl_flowtable *t, uint16_t attr, const void *data);
479 +int nftnl_flowtable_set_data(struct nftnl_flowtable *t, uint16_t attr,
480 + const void *data, uint32_t data_len);
481 +void nftnl_flowtable_set_u32(struct nftnl_flowtable *t, uint16_t attr, uint32_t data);
482 +void nftnl_flowtable_set_s32(struct nftnl_flowtable *t, uint16_t attr, int32_t data);
483 +int nftnl_flowtable_set_str(struct nftnl_flowtable *t, uint16_t attr, const char *str);
484 +void nftnl_flowtable_set_array(struct nftnl_flowtable *t, uint16_t attr, const char **data);
485 +
486 +const void *nftnl_flowtable_get(const struct nftnl_flowtable *c, uint16_t attr);
487 +const void *nftnl_flowtable_get_data(const struct nftnl_flowtable *c, uint16_t attr,
488 + uint32_t *data_len);
489 +const char *nftnl_flowtable_get_str(const struct nftnl_flowtable *c, uint16_t attr);
490 +uint32_t nftnl_flowtable_get_u32(const struct nftnl_flowtable *c, uint16_t attr);
491 +int32_t nftnl_flowtable_get_s32(const struct nftnl_flowtable *c, uint16_t attr);
492 +const char **nftnl_flowtable_get_array(const struct nftnl_flowtable *t, uint16_t attr);
493 +
494 +struct nlmsghdr;
495 +
496 +void nftnl_flowtable_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_flowtable *t);
497 +
498 +int nftnl_flowtable_parse(struct nftnl_flowtable *c, enum nftnl_parse_type type,
499 + const char *data, struct nftnl_parse_err *err);
500 +int nftnl_flowtable_parse_file(struct nftnl_flowtable *c, enum nftnl_parse_type type,
501 + FILE *fp, struct nftnl_parse_err *err);
502 +int nftnl_flowtable_snprintf(char *buf, size_t size, const struct nftnl_flowtable *t, uint32_t type, uint32_t flags);
503 +int nftnl_flowtable_fprintf(FILE *fp, const struct nftnl_flowtable *c, uint32_t type, uint32_t flags);
504 +
505 +#define nftnl_flowtable_nlmsg_build_hdr nftnl_nlmsg_build_hdr
506 +int nftnl_flowtable_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_flowtable *t);
507 +
508 +struct nftnl_flowtable_list;
509 +
510 +struct nftnl_flowtable_list *nftnl_flowtable_list_alloc(void);
511 +void nftnl_flowtable_list_free(struct nftnl_flowtable_list *list);
512 +int nftnl_flowtable_list_is_empty(const struct nftnl_flowtable_list *list);
513 +void nftnl_flowtable_list_add(struct nftnl_flowtable *s,
514 + struct nftnl_flowtable_list *list);
515 +void nftnl_flowtable_list_add_tail(struct nftnl_flowtable *s,
516 + struct nftnl_flowtable_list *list);
517 +void nftnl_flowtable_list_del(struct nftnl_flowtable *s);
518 +int nftnl_flowtable_list_foreach(struct nftnl_flowtable_list *flowtable_list,
519 + int (*cb)(struct nftnl_flowtable *t, void *data), void *data);
520 +
521 +#ifdef __cplusplus
522 +} /* extern "C" */
523 +#endif
524 +
525 +#endif /* _LIBNFTNL_FLOWTABLE_H_ */
526 --- a/include/linux/netfilter/nf_tables.h
527 +++ b/include/linux/netfilter/nf_tables.h
528 @@ -90,6 +90,9 @@ enum nft_verdicts {
529 * @NFT_MSG_GETOBJ: get a stateful object (enum nft_obj_attributes)
530 * @NFT_MSG_DELOBJ: delete a stateful object (enum nft_obj_attributes)
531 * @NFT_MSG_GETOBJ_RESET: get and reset a stateful object (enum nft_obj_attributes)
532 + * @NFT_MSG_NEWFLOWTABLE: add new flow table (enum nft_flowtable_attributes)
533 + * @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
534 + * @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
535 */
536 enum nf_tables_msg_types {
537 NFT_MSG_NEWTABLE,
538 @@ -114,6 +117,9 @@ enum nf_tables_msg_types {
539 NFT_MSG_GETOBJ,
540 NFT_MSG_DELOBJ,
541 NFT_MSG_GETOBJ_RESET,
542 + NFT_MSG_NEWFLOWTABLE,
543 + NFT_MSG_GETFLOWTABLE,
544 + NFT_MSG_DELFLOWTABLE,
545 NFT_MSG_MAX,
546 };
547
548 @@ -1303,6 +1309,53 @@ enum nft_object_attributes {
549 #define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1)
550
551 /**
552 + * enum nft_flowtable_attributes - nf_tables flow table netlink attributes
553 + *
554 + * @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
555 + * @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
556 + * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
557 + * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
558 + */
559 +enum nft_flowtable_attributes {
560 + NFTA_FLOWTABLE_UNSPEC,
561 + NFTA_FLOWTABLE_TABLE,
562 + NFTA_FLOWTABLE_NAME,
563 + NFTA_FLOWTABLE_HOOK,
564 + NFTA_FLOWTABLE_USE,
565 + __NFTA_FLOWTABLE_MAX
566 +};
567 +#define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
568 +
569 +/**
570 + * enum nft_flowtable_hook_attributes - nf_tables flow table hook netlink attributes
571 + *
572 + * @NFTA_FLOWTABLE_HOOK_NUM: netfilter hook number (NLA_U32)
573 + * @NFTA_FLOWTABLE_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
574 + * @NFTA_FLOWTABLE_HOOK_DEVS: input devices this flow table is bound to (NLA_NESTED)
575 + */
576 +enum nft_flowtable_hook_attributes {
577 + NFTA_FLOWTABLE_HOOK_UNSPEC,
578 + NFTA_FLOWTABLE_HOOK_NUM,
579 + NFTA_FLOWTABLE_HOOK_PRIORITY,
580 + NFTA_FLOWTABLE_HOOK_DEVS,
581 + __NFTA_FLOWTABLE_HOOK_MAX
582 +};
583 +#define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1)
584 +
585 +/**
586 + * enum nft_device_attributes - nf_tables device netlink attributes
587 + *
588 + * @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
589 + */
590 +enum nft_devices_attributes {
591 + NFTA_DEVICE_UNSPEC,
592 + NFTA_DEVICE_NAME,
593 + __NFTA_DEVICE_MAX
594 +};
595 +#define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
596 +
597 +
598 +/**
599 * enum nft_trace_attributes - nf_tables trace netlink attributes
600 *
601 * @NFTA_TRACE_TABLE: name of the table (NLA_STRING)
602 --- a/src/Makefile.am
603 +++ b/src/Makefile.am
604 @@ -8,6 +8,7 @@ libnftnl_la_LDFLAGS = -Wl,--version-scri
605 libnftnl_la_SOURCES = utils.c \
606 batch.c \
607 buffer.c \
608 + flowtable.c \
609 common.c \
610 gen.c \
611 table.c \
612 --- /dev/null
613 +++ b/src/flowtable.c
614 @@ -0,0 +1,793 @@
615 +#include "internal.h"
616 +
617 +#include <time.h>
618 +#include <endian.h>
619 +#include <stdint.h>
620 +#include <stdlib.h>
621 +#include <limits.h>
622 +#include <string.h>
623 +#include <netinet/in.h>
624 +#include <errno.h>
625 +#include <inttypes.h>
626 +
627 +#include <libmnl/libmnl.h>
628 +#include <linux/netfilter/nfnetlink.h>
629 +#include <linux/netfilter/nf_tables.h>
630 +#include <linux/netfilter.h>
631 +#include <linux/netfilter_arp.h>
632 +
633 +#include <libnftnl/flowtable.h>
634 +#include <buffer.h>
635 +
636 +struct nftnl_flowtable {
637 + struct list_head head;
638 + const char *name;
639 + const char *table;
640 + int family;
641 + uint32_t hooknum;
642 + int32_t prio;
643 + const char **dev_array;
644 + uint32_t dev_array_len;
645 + uint32_t use;
646 + uint32_t flags;
647 +};
648 +
649 +struct nftnl_flowtable *nftnl_flowtable_alloc(void)
650 +{
651 + return calloc(1, sizeof(struct nftnl_flowtable));
652 +}
653 +EXPORT_SYMBOL(nftnl_flowtable_alloc);
654 +
655 +void nftnl_flowtable_free(const struct nftnl_flowtable *c)
656 +{
657 + int i;
658 +
659 + if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
660 + xfree(c->name);
661 + if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
662 + xfree(c->table);
663 + if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
664 + for (i = 0; i < c->dev_array_len; i++)
665 + xfree(c->dev_array[i]);
666 +
667 + xfree(c->dev_array);
668 + }
669 + xfree(c);
670 +}
671 +EXPORT_SYMBOL(nftnl_flowtable_free);
672 +
673 +bool nftnl_flowtable_is_set(const struct nftnl_flowtable *c, uint16_t attr)
674 +{
675 + return c->flags & (1 << attr);
676 +}
677 +EXPORT_SYMBOL(nftnl_flowtable_is_set);
678 +
679 +void nftnl_flowtable_unset(struct nftnl_flowtable *c, uint16_t attr)
680 +{
681 + int i;
682 +
683 + if (!(c->flags & (1 << attr)))
684 + return;
685 +
686 + switch (attr) {
687 + case NFTNL_FLOWTABLE_NAME:
688 + xfree(c->name);
689 + break;
690 + case NFTNL_FLOWTABLE_TABLE:
691 + xfree(c->table);
692 + break;
693 + case NFTNL_FLOWTABLE_HOOKNUM:
694 + case NFTNL_FLOWTABLE_PRIO:
695 + case NFTNL_FLOWTABLE_USE:
696 + case NFTNL_FLOWTABLE_FAMILY:
697 + break;
698 + case NFTNL_FLOWTABLE_DEVICES:
699 + for (i = 0; i < c->dev_array_len; i++) {
700 + xfree(c->dev_array[i]);
701 + xfree(c->dev_array);
702 + }
703 + break;
704 + default:
705 + return;
706 + }
707 +
708 + c->flags &= ~(1 << attr);
709 +}
710 +EXPORT_SYMBOL(nftnl_flowtable_unset);
711 +
712 +static uint32_t nftnl_flowtable_validate[NFTNL_FLOWTABLE_MAX + 1] = {
713 + [NFTNL_FLOWTABLE_HOOKNUM] = sizeof(uint32_t),
714 + [NFTNL_FLOWTABLE_PRIO] = sizeof(int32_t),
715 + [NFTNL_FLOWTABLE_FAMILY] = sizeof(uint32_t),
716 +};
717 +
718 +int nftnl_flowtable_set_data(struct nftnl_flowtable *c, uint16_t attr,
719 + const void *data, uint32_t data_len)
720 +{
721 + const char **dev_array;
722 + int len = 0, i;
723 +
724 + nftnl_assert_attr_exists(attr, NFTNL_FLOWTABLE_MAX);
725 + nftnl_assert_validate(data, nftnl_flowtable_validate, attr, data_len);
726 +
727 + switch(attr) {
728 + case NFTNL_FLOWTABLE_NAME:
729 + if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
730 + xfree(c->name);
731 +
732 + c->name = strdup(data);
733 + if (!c->name)
734 + return -1;
735 + break;
736 + case NFTNL_FLOWTABLE_TABLE:
737 + if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
738 + xfree(c->table);
739 +
740 + c->table = strdup(data);
741 + if (!c->table)
742 + return -1;
743 + break;
744 + case NFTNL_FLOWTABLE_HOOKNUM:
745 + memcpy(&c->hooknum, data, sizeof(c->hooknum));
746 + break;
747 + case NFTNL_FLOWTABLE_PRIO:
748 + memcpy(&c->prio, data, sizeof(c->prio));
749 + break;
750 + case NFTNL_FLOWTABLE_FAMILY:
751 + memcpy(&c->family, data, sizeof(c->family));
752 + break;
753 + case NFTNL_FLOWTABLE_DEVICES:
754 + dev_array = (const char **)data;
755 + while (dev_array[len] != NULL)
756 + len++;
757 +
758 + if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
759 + for (i = 0; i < c->dev_array_len; i++) {
760 + xfree(c->dev_array[i]);
761 + xfree(c->dev_array);
762 + }
763 + }
764 +
765 + c->dev_array = calloc(len + 1, sizeof(char *));
766 + if (!c->dev_array)
767 + return -1;
768 +
769 + for (i = 0; i < len; i++)
770 + c->dev_array[i] = strdup(dev_array[i]);
771 +
772 + c->dev_array_len = len;
773 + break;
774 + }
775 + c->flags |= (1 << attr);
776 + return 0;
777 +}
778 +EXPORT_SYMBOL(nftnl_flowtable_set_data);
779 +
780 +void nftnl_flowtable_set(struct nftnl_flowtable *c, uint16_t attr, const void *data)
781 +{
782 + nftnl_flowtable_set_data(c, attr, data, nftnl_flowtable_validate[attr]);
783 +}
784 +EXPORT_SYMBOL(nftnl_flowtable_set);
785 +
786 +void nftnl_flowtable_set_array(struct nftnl_flowtable *c, uint16_t attr, const char **data)
787 +{
788 + nftnl_flowtable_set_data(c, attr, &data[0], nftnl_flowtable_validate[attr]);
789 +}
790 +EXPORT_SYMBOL(nftnl_flowtable_set_array);
791 +
792 +void nftnl_flowtable_set_u32(struct nftnl_flowtable *c, uint16_t attr, uint32_t data)
793 +{
794 + nftnl_flowtable_set_data(c, attr, &data, sizeof(uint32_t));
795 +}
796 +EXPORT_SYMBOL(nftnl_flowtable_set_u32);
797 +
798 +void nftnl_flowtable_set_s32(struct nftnl_flowtable *c, uint16_t attr, int32_t data)
799 +{
800 + nftnl_flowtable_set_data(c, attr, &data, sizeof(int32_t));
801 +}
802 +EXPORT_SYMBOL(nftnl_flowtable_set_s32);
803 +
804 +int nftnl_flowtable_set_str(struct nftnl_flowtable *c, uint16_t attr, const char *str)
805 +{
806 + return nftnl_flowtable_set_data(c, attr, str, strlen(str) + 1);
807 +}
808 +EXPORT_SYMBOL(nftnl_flowtable_set_str);
809 +
810 +const void *nftnl_flowtable_get_data(const struct nftnl_flowtable *c,
811 + uint16_t attr, uint32_t *data_len)
812 +{
813 + if (!(c->flags & (1 << attr)))
814 + return NULL;
815 +
816 + switch(attr) {
817 + case NFTNL_FLOWTABLE_NAME:
818 + *data_len = strlen(c->name) + 1;
819 + return c->name;
820 + case NFTNL_FLOWTABLE_TABLE:
821 + *data_len = strlen(c->table) + 1;
822 + return c->table;
823 + case NFTNL_FLOWTABLE_HOOKNUM:
824 + *data_len = sizeof(uint32_t);
825 + return &c->hooknum;
826 + case NFTNL_FLOWTABLE_PRIO:
827 + *data_len = sizeof(int32_t);
828 + return &c->prio;
829 + case NFTNL_FLOWTABLE_FAMILY:
830 + *data_len = sizeof(int32_t);
831 + return &c->family;
832 + case NFTNL_FLOWTABLE_DEVICES:
833 + return &c->dev_array[0];
834 + }
835 + return NULL;
836 +}
837 +EXPORT_SYMBOL(nftnl_flowtable_get_data);
838 +
839 +const void *nftnl_flowtable_get(const struct nftnl_flowtable *c, uint16_t attr)
840 +{
841 + uint32_t data_len;
842 + return nftnl_flowtable_get_data(c, attr, &data_len);
843 +}
844 +EXPORT_SYMBOL(nftnl_flowtable_get);
845 +
846 +const char *nftnl_flowtable_get_str(const struct nftnl_flowtable *c, uint16_t attr)
847 +{
848 + return nftnl_flowtable_get(c, attr);
849 +}
850 +EXPORT_SYMBOL(nftnl_flowtable_get_str);
851 +
852 +uint32_t nftnl_flowtable_get_u32(const struct nftnl_flowtable *c, uint16_t attr)
853 +{
854 + uint32_t data_len;
855 + const uint32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
856 +
857 + nftnl_assert(val, attr, data_len == sizeof(uint32_t));
858 +
859 + return val ? *val : 0;
860 +}
861 +EXPORT_SYMBOL(nftnl_flowtable_get_u32);
862 +
863 +int32_t nftnl_flowtable_get_s32(const struct nftnl_flowtable *c, uint16_t attr)
864 +{
865 + uint32_t data_len;
866 + const int32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
867 +
868 + nftnl_assert(val, attr, data_len == sizeof(int32_t));
869 +
870 + return val ? *val : 0;
871 +}
872 +EXPORT_SYMBOL(nftnl_flowtable_get_s32);
873 +
874 +const char **nftnl_flowtable_get_array(const struct nftnl_flowtable *c, uint16_t attr)
875 +{
876 + return (const char **)nftnl_flowtable_get(c, attr);
877 +}
878 +EXPORT_SYMBOL(nftnl_flowtable_get_array);
879 +
880 +void nftnl_flowtable_nlmsg_build_payload(struct nlmsghdr *nlh,
881 + const struct nftnl_flowtable *c)
882 +{
883 + int i;
884 +
885 + if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
886 + mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, c->table);
887 + if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
888 + mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME, c->name);
889 + if ((c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM)) &&
890 + (c->flags & (1 << NFTNL_FLOWTABLE_PRIO))) {
891 + struct nlattr *nest;
892 +
893 + nest = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK);
894 + mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_NUM, htonl(c->hooknum));
895 + mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_PRIORITY, htonl(c->prio));
896 + if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
897 + struct nlattr *nest_dev;
898 +
899 + nest_dev = mnl_attr_nest_start(nlh,
900 + NFTA_FLOWTABLE_HOOK_DEVS);
901 + for (i = 0; i < c->dev_array_len; i++)
902 + mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME,
903 + c->dev_array[i]);
904 + mnl_attr_nest_end(nlh, nest_dev);
905 + }
906 + mnl_attr_nest_end(nlh, nest);
907 + }
908 + if (c->flags & (1 << NFTNL_FLOWTABLE_USE))
909 + mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_USE, htonl(c->use));
910 +}
911 +EXPORT_SYMBOL(nftnl_flowtable_nlmsg_build_payload);
912 +
913 +static int nftnl_flowtable_parse_attr_cb(const struct nlattr *attr, void *data)
914 +{
915 + const struct nlattr **tb = data;
916 + int type = mnl_attr_get_type(attr);
917 +
918 + if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_MAX) < 0)
919 + return MNL_CB_OK;
920 +
921 + switch(type) {
922 + case NFTA_FLOWTABLE_NAME:
923 + case NFTA_FLOWTABLE_TABLE:
924 + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
925 + abi_breakage();
926 + break;
927 + case NFTA_FLOWTABLE_HOOK:
928 + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
929 + abi_breakage();
930 + break;
931 + case NFTA_FLOWTABLE_USE:
932 + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
933 + abi_breakage();
934 + break;
935 + }
936 +
937 + tb[type] = attr;
938 + return MNL_CB_OK;
939 +}
940 +
941 +static int nftnl_flowtable_parse_hook_cb(const struct nlattr *attr, void *data)
942 +{
943 + const struct nlattr **tb = data;
944 + int type = mnl_attr_get_type(attr);
945 +
946 + if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_HOOK_MAX) < 0)
947 + return MNL_CB_OK;
948 +
949 + switch(type) {
950 + case NFTA_FLOWTABLE_HOOK_NUM:
951 + case NFTA_FLOWTABLE_HOOK_PRIORITY:
952 + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
953 + abi_breakage();
954 + break;
955 + case NFTA_FLOWTABLE_HOOK_DEVS:
956 + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
957 + abi_breakage();
958 + break;
959 + }
960 +
961 + tb[type] = attr;
962 + return MNL_CB_OK;
963 +}
964 +
965 +static int nftnl_flowtable_parse_devs(struct nlattr *nest,
966 + struct nftnl_flowtable *c)
967 +{
968 + struct nlattr *attr;
969 + char *dev_array[8];
970 + int len = 0, i;
971 +
972 + mnl_attr_for_each_nested(attr, nest) {
973 + if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
974 + return -1;
975 + dev_array[len++] = strdup(mnl_attr_get_str(attr));
976 + if (len >= 8)
977 + break;
978 + }
979 +
980 + if (!len)
981 + return -1;
982 +
983 + c->dev_array = calloc(len + 1, sizeof(char *));
984 + if (!c->dev_array)
985 + return -1;
986 +
987 + c->dev_array_len = len;
988 +
989 + for (i = 0; i < len; i++)
990 + c->dev_array[i] = strdup(dev_array[i]);
991 +
992 + return 0;
993 +}
994 +
995 +static int nftnl_flowtable_parse_hook(struct nlattr *attr, struct nftnl_flowtable *c)
996 +{
997 + struct nlattr *tb[NFTA_FLOWTABLE_HOOK_MAX + 1] = {};
998 + int ret;
999 +
1000 + if (mnl_attr_parse_nested(attr, nftnl_flowtable_parse_hook_cb, tb) < 0)
1001 + return -1;
1002 +
1003 + if (tb[NFTA_FLOWTABLE_HOOK_NUM]) {
1004 + c->hooknum = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_HOOK_NUM]));
1005 + c->flags |= (1 << NFTNL_FLOWTABLE_HOOKNUM);
1006 + }
1007 + if (tb[NFTA_FLOWTABLE_HOOK_PRIORITY]) {
1008 + c->prio = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_HOOK_PRIORITY]));
1009 + c->flags |= (1 << NFTNL_FLOWTABLE_PRIO);
1010 + }
1011 + if (tb[NFTA_FLOWTABLE_HOOK_DEVS]) {
1012 + ret = nftnl_flowtable_parse_devs(tb[NFTA_FLOWTABLE_HOOK_DEVS], c);
1013 + if (ret < 0)
1014 + return -1;
1015 + c->flags |= (1 << NFTNL_FLOWTABLE_DEVICES);
1016 + }
1017 +
1018 + return 0;
1019 +}
1020 +
1021 +int nftnl_flowtable_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_flowtable *c)
1022 +{
1023 + struct nlattr *tb[NFTA_FLOWTABLE_MAX + 1] = {};
1024 + struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
1025 + int ret = 0;
1026 +
1027 + if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_flowtable_parse_attr_cb, tb) < 0)
1028 + return -1;
1029 +
1030 + if (tb[NFTA_FLOWTABLE_NAME]) {
1031 + if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
1032 + xfree(c->name);
1033 + c->name = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_NAME]));
1034 + if (!c->name)
1035 + return -1;
1036 + c->flags |= (1 << NFTNL_FLOWTABLE_NAME);
1037 + }
1038 + if (tb[NFTA_FLOWTABLE_TABLE]) {
1039 + if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
1040 + xfree(c->table);
1041 + c->table = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_TABLE]));
1042 + if (!c->table)
1043 + return -1;
1044 + c->flags |= (1 << NFTNL_FLOWTABLE_TABLE);
1045 + }
1046 + if (tb[NFTA_FLOWTABLE_HOOK]) {
1047 + ret = nftnl_flowtable_parse_hook(tb[NFTA_FLOWTABLE_HOOK], c);
1048 + if (ret < 0)
1049 + return ret;
1050 + }
1051 + if (tb[NFTA_FLOWTABLE_USE]) {
1052 + c->use = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_USE]));
1053 + c->flags |= (1 << NFTNL_FLOWTABLE_USE);
1054 + }
1055 +
1056 + c->family = nfg->nfgen_family;
1057 + c->flags |= (1 << NFTNL_FLOWTABLE_FAMILY);
1058 +
1059 + return ret;
1060 +}
1061 +EXPORT_SYMBOL(nftnl_flowtable_nlmsg_parse);
1062 +
1063 +static const char *nftnl_hooknum2str(int family, int hooknum)
1064 +{
1065 + switch (family) {
1066 + case NFPROTO_IPV4:
1067 + case NFPROTO_IPV6:
1068 + case NFPROTO_INET:
1069 + case NFPROTO_BRIDGE:
1070 + switch (hooknum) {
1071 + case NF_INET_PRE_ROUTING:
1072 + return "prerouting";
1073 + case NF_INET_LOCAL_IN:
1074 + return "input";
1075 + case NF_INET_FORWARD:
1076 + return "forward";
1077 + case NF_INET_LOCAL_OUT:
1078 + return "output";
1079 + case NF_INET_POST_ROUTING:
1080 + return "postrouting";
1081 + }
1082 + break;
1083 + case NFPROTO_ARP:
1084 + switch (hooknum) {
1085 + case NF_ARP_IN:
1086 + return "input";
1087 + case NF_ARP_OUT:
1088 + return "output";
1089 + case NF_ARP_FORWARD:
1090 + return "forward";
1091 + }
1092 + break;
1093 + case NFPROTO_NETDEV:
1094 + switch (hooknum) {
1095 + case NF_NETDEV_INGRESS:
1096 + return "ingress";
1097 + }
1098 + break;
1099 + }
1100 + return "unknown";
1101 +}
1102 +
1103 +static inline int nftnl_str2hooknum(int family, const char *hook)
1104 +{
1105 + int hooknum;
1106 +
1107 + for (hooknum = 0; hooknum < NF_INET_NUMHOOKS; hooknum++) {
1108 + if (strcmp(hook, nftnl_hooknum2str(family, hooknum)) == 0)
1109 + return hooknum;
1110 + }
1111 + return -1;
1112 +}
1113 +
1114 +#ifdef JSON_PARSING
1115 +static int nftnl_jansson_parse_flowtable(struct nftnl_flowtable *c,
1116 + json_t *tree,
1117 + struct nftnl_parse_err *err)
1118 +{
1119 + const char *name, *table, *hooknum_str;
1120 + int32_t family, prio, hooknum;
1121 + json_t *root;
1122 +
1123 + root = nftnl_jansson_get_node(tree, "flowtable", err);
1124 + if (root == NULL)
1125 + return -1;
1126 +
1127 + name = nftnl_jansson_parse_str(root, "name", err);
1128 + if (name != NULL)
1129 + nftnl_flowtable_set_str(c, NFTNL_FLOWTABLE_NAME, name);
1130 +
1131 + if (nftnl_jansson_parse_family(root, &family, err) == 0)
1132 + nftnl_flowtable_set_u32(c, NFTNL_FLOWTABLE_FAMILY, family);
1133 +
1134 + table = nftnl_jansson_parse_str(root, "table", err);
1135 +
1136 + if (table != NULL)
1137 + nftnl_flowtable_set_str(c, NFTNL_FLOWTABLE_TABLE, table);
1138 +
1139 + if (nftnl_jansson_node_exist(root, "hooknum")) {
1140 + if (nftnl_jansson_parse_val(root, "prio", NFTNL_TYPE_S32,
1141 + &prio, err) == 0)
1142 + nftnl_flowtable_set_s32(c, NFTNL_FLOWTABLE_PRIO, prio);
1143 +
1144 + hooknum_str = nftnl_jansson_parse_str(root, "hooknum", err);
1145 + if (hooknum_str != NULL) {
1146 + hooknum = nftnl_str2hooknum(c->family, hooknum_str);
1147 + if (hooknum == -1)
1148 + return -1;
1149 + nftnl_flowtable_set_u32(c, NFTNL_FLOWTABLE_HOOKNUM,
1150 + hooknum);
1151 + }
1152 + }
1153 +
1154 + return 0;
1155 +}
1156 +#endif
1157 +
1158 +static int nftnl_flowtable_json_parse(struct nftnl_flowtable *c,
1159 + const void *json,
1160 + struct nftnl_parse_err *err,
1161 + enum nftnl_parse_input input)
1162 +{
1163 +#ifdef JSON_PARSING
1164 + json_t *tree;
1165 + json_error_t error;
1166 + int ret;
1167 +
1168 + tree = nftnl_jansson_create_root(json, &error, err, input);
1169 + if (tree == NULL)
1170 + return -1;
1171 +
1172 + ret = nftnl_jansson_parse_flowtable(c, tree, err);
1173 +
1174 + nftnl_jansson_free_root(tree);
1175 +
1176 + return ret;
1177 +#else
1178 + errno = EOPNOTSUPP;
1179 + return -1;
1180 +#endif
1181 +}
1182 +
1183 +static int nftnl_flowtable_do_parse(struct nftnl_flowtable *c,
1184 + enum nftnl_parse_type type,
1185 + const void *data,
1186 + struct nftnl_parse_err *err,
1187 + enum nftnl_parse_input input)
1188 +{
1189 + int ret;
1190 + struct nftnl_parse_err perr = {};
1191 +
1192 + switch (type) {
1193 + case NFTNL_PARSE_JSON:
1194 + ret = nftnl_flowtable_json_parse(c, data, &perr, input);
1195 + break;
1196 + case NFTNL_PARSE_XML:
1197 + default:
1198 + ret = -1;
1199 + errno = EOPNOTSUPP;
1200 + break;
1201 + }
1202 +
1203 + if (err != NULL)
1204 + *err = perr;
1205 +
1206 + return ret;
1207 +}
1208 +
1209 +int nftnl_flowtable_parse(struct nftnl_flowtable *c, enum nftnl_parse_type type,
1210 + const char *data, struct nftnl_parse_err *err)
1211 +{
1212 + return nftnl_flowtable_do_parse(c, type, data, err, NFTNL_PARSE_BUFFER);
1213 +}
1214 +EXPORT_SYMBOL(nftnl_flowtable_parse);
1215 +
1216 +int nftnl_flowtable_parse_file(struct nftnl_flowtable *c,
1217 + enum nftnl_parse_type type,
1218 + FILE *fp, struct nftnl_parse_err *err)
1219 +{
1220 + return nftnl_flowtable_do_parse(c, type, fp, err, NFTNL_PARSE_FILE);
1221 +}
1222 +EXPORT_SYMBOL(nftnl_flowtable_parse_file);
1223 +
1224 +static int nftnl_flowtable_export(char *buf, size_t size,
1225 + const struct nftnl_flowtable *c, int type)
1226 +{
1227 + NFTNL_BUF_INIT(b, buf, size);
1228 +
1229 + nftnl_buf_open(&b, type, CHAIN);
1230 + if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
1231 + nftnl_buf_str(&b, type, c->name, NAME);
1232 + if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
1233 + nftnl_buf_str(&b, type, c->table, TABLE);
1234 + if (c->flags & (1 << NFTNL_FLOWTABLE_FAMILY))
1235 + nftnl_buf_str(&b, type, nftnl_family2str(c->family), FAMILY);
1236 + if (c->flags & (1 << NFTNL_FLOWTABLE_USE))
1237 + nftnl_buf_u32(&b, type, c->use, USE);
1238 + if (c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM)) {
1239 + if (c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM))
1240 + nftnl_buf_str(&b, type, nftnl_hooknum2str(c->family,
1241 + c->hooknum), HOOKNUM);
1242 + if (c->flags & (1 << NFTNL_FLOWTABLE_PRIO))
1243 + nftnl_buf_s32(&b, type, c->prio, PRIO);
1244 + }
1245 +
1246 + nftnl_buf_close(&b, type, CHAIN);
1247 +
1248 + return nftnl_buf_done(&b);
1249 +}
1250 +
1251 +static int nftnl_flowtable_snprintf_default(char *buf, size_t size,
1252 + const struct nftnl_flowtable *c)
1253 +{
1254 + int ret, remain = size, offset = 0, i;
1255 +
1256 + ret = snprintf(buf, remain, "flow table %s %s use %u",
1257 + c->table, c->name, c->use);
1258 + SNPRINTF_BUFFER_SIZE(ret, remain, offset);
1259 +
1260 + if (c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM)) {
1261 + ret = snprintf(buf + offset, remain, " hook %s prio %d",
1262 + nftnl_hooknum2str(c->family, c->hooknum),
1263 + c->prio);
1264 + SNPRINTF_BUFFER_SIZE(ret, remain, offset);
1265 +
1266 + if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
1267 + ret = snprintf(buf + offset, remain, " dev { ");
1268 + SNPRINTF_BUFFER_SIZE(ret, remain, offset);
1269 +
1270 + for (i = 0; i < c->dev_array_len; i++) {
1271 + ret = snprintf(buf + offset, remain, " %s ",
1272 + c->dev_array[i]);
1273 + SNPRINTF_BUFFER_SIZE(ret, remain, offset);
1274 + }
1275 + ret = snprintf(buf + offset, remain, " } ");
1276 + SNPRINTF_BUFFER_SIZE(ret, remain, offset);
1277 + }
1278 + }
1279 +
1280 + return offset;
1281 +}
1282 +
1283 +static int nftnl_flowtable_cmd_snprintf(char *buf, size_t size,
1284 + const struct nftnl_flowtable *c,
1285 + uint32_t cmd, uint32_t type,
1286 + uint32_t flags)
1287 +{
1288 + int ret, remain = size, offset = 0;
1289 +
1290 + ret = nftnl_cmd_header_snprintf(buf + offset, remain, cmd, type, flags);
1291 + SNPRINTF_BUFFER_SIZE(ret, remain, offset);
1292 +
1293 + switch (type) {
1294 + case NFTNL_OUTPUT_DEFAULT:
1295 + ret = nftnl_flowtable_snprintf_default(buf + offset, remain, c);
1296 + break;
1297 + case NFTNL_OUTPUT_XML:
1298 + case NFTNL_OUTPUT_JSON:
1299 + ret = nftnl_flowtable_export(buf + offset, remain, c, type);
1300 + break;
1301 + default:
1302 + return -1;
1303 + }
1304 +
1305 + SNPRINTF_BUFFER_SIZE(ret, remain, offset);
1306 +
1307 + ret = nftnl_cmd_footer_snprintf(buf + offset, remain, cmd, type, flags);
1308 + SNPRINTF_BUFFER_SIZE(ret, remain, offset);
1309 +
1310 + return offset;
1311 +}
1312 +
1313 +int nftnl_flowtable_snprintf(char *buf, size_t size, const struct nftnl_flowtable *c,
1314 + uint32_t type, uint32_t flags)
1315 +{
1316 + if (size)
1317 + buf[0] = '\0';
1318 +
1319 + return nftnl_flowtable_cmd_snprintf(buf, size, c, nftnl_flag2cmd(flags),
1320 + type, flags);
1321 +}
1322 +EXPORT_SYMBOL(nftnl_flowtable_snprintf);
1323 +
1324 +static int nftnl_flowtable_do_snprintf(char *buf, size_t size, const void *c,
1325 + uint32_t cmd, uint32_t type, uint32_t flags)
1326 +{
1327 + return nftnl_flowtable_snprintf(buf, size, c, type, flags);
1328 +}
1329 +
1330 +int nftnl_flowtable_fprintf(FILE *fp, const struct nftnl_flowtable *c,
1331 + uint32_t type, uint32_t flags)
1332 +{
1333 + return nftnl_fprintf(fp, c, NFTNL_CMD_UNSPEC, type, flags,
1334 + nftnl_flowtable_do_snprintf);
1335 +}
1336 +EXPORT_SYMBOL(nftnl_flowtable_fprintf);
1337 +
1338 +struct nftnl_flowtable_list {
1339 + struct list_head list;
1340 +};
1341 +
1342 +struct nftnl_flowtable_list *nftnl_flowtable_list_alloc(void)
1343 +{
1344 + struct nftnl_flowtable_list *list;
1345 +
1346 + list = calloc(1, sizeof(struct nftnl_flowtable_list));
1347 + if (list == NULL)
1348 + return NULL;
1349 +
1350 + INIT_LIST_HEAD(&list->list);
1351 +
1352 + return list;
1353 +}
1354 +EXPORT_SYMBOL(nftnl_flowtable_list_alloc);
1355 +
1356 +void nftnl_flowtable_list_free(struct nftnl_flowtable_list *list)
1357 +{
1358 + struct nftnl_flowtable *s, *tmp;
1359 +
1360 + list_for_each_entry_safe(s, tmp, &list->list, head) {
1361 + list_del(&s->head);
1362 + nftnl_flowtable_free(s);
1363 + }
1364 + xfree(list);
1365 +}
1366 +EXPORT_SYMBOL(nftnl_flowtable_list_free);
1367 +
1368 +int nftnl_flowtable_list_is_empty(const struct nftnl_flowtable_list *list)
1369 +{
1370 + return list_empty(&list->list);
1371 +}
1372 +EXPORT_SYMBOL(nftnl_flowtable_list_is_empty);
1373 +
1374 +void nftnl_flowtable_list_add(struct nftnl_flowtable *s,
1375 + struct nftnl_flowtable_list *list)
1376 +{
1377 + list_add(&s->head, &list->list);
1378 +}
1379 +EXPORT_SYMBOL(nftnl_flowtable_list_add);
1380 +
1381 +void nftnl_flowtable_list_add_tail(struct nftnl_flowtable *s,
1382 + struct nftnl_flowtable_list *list)
1383 +{
1384 + list_add_tail(&s->head, &list->list);
1385 +}
1386 +EXPORT_SYMBOL(nftnl_flowtable_list_add_tail);
1387 +
1388 +void nftnl_flowtable_list_del(struct nftnl_flowtable *s)
1389 +{
1390 + list_del(&s->head);
1391 +}
1392 +EXPORT_SYMBOL(nftnl_flowtable_list_del);
1393 +
1394 +int nftnl_flowtable_list_foreach(struct nftnl_flowtable_list *flowtable_list,
1395 + int (*cb)(struct nftnl_flowtable *t, void *data), void *data)
1396 +{
1397 + struct nftnl_flowtable *cur, *tmp;
1398 + int ret;
1399 +
1400 + list_for_each_entry_safe(cur, tmp, &flowtable_list->list, head) {
1401 + ret = cb(cur, data);
1402 + if (ret < 0)
1403 + return ret;
1404 + }
1405 + return 0;
1406 +}
1407 +EXPORT_SYMBOL(nftnl_flowtable_list_foreach);
1408 --- a/src/libnftnl.map
1409 +++ b/src/libnftnl.map
1410 @@ -311,3 +311,34 @@ local: *;
1411 LIBNFTNL_6 {
1412 nftnl_expr_fprintf;
1413 } LIBNFTNL_5;
1414 +
1415 +LIBNFTNL_7 {
1416 + nftnl_flowtable_alloc;
1417 + nftnl_flowtable_free;
1418 + nftnl_flowtable_is_set;
1419 + nftnl_flowtable_unset;
1420 + nftnl_flowtable_set;
1421 + nftnl_flowtable_set_u32;
1422 + nftnl_flowtable_set_s32;
1423 + nftnl_flowtable_set_array;
1424 + nftnl_flowtable_set_str;
1425 + nftnl_flowtable_get;
1426 + nftnl_flowtable_get_u32;
1427 + nftnl_flowtable_get_s32;
1428 + nftnl_flowtable_get_array;
1429 + nftnl_flowtable_get_str;
1430 + nftnl_flowtable_parse;
1431 + nftnl_flowtable_parse_file;
1432 + nftnl_flowtable_snprintf;
1433 + nftnl_flowtable_fprintf;
1434 + nftnl_flowtable_nlmsg_build_payload;
1435 + nftnl_flowtable_nlmsg_parse;
1436 + nftnl_flowtable_list_alloc;
1437 + nftnl_flowtable_list_free;
1438 + nftnl_flowtable_list_is_empty;
1439 + nftnl_flowtable_list_add;
1440 + nftnl_flowtable_list_add_tail;
1441 + nftnl_flowtable_list_del;
1442 + nftnl_flowtable_list_foreach;
1443 +
1444 +} LIBNFTNL_6;