OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 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; |