libnftnl 1.2.7
flowtable.c
1#include "internal.h"
2
3#include <time.h>
4#include <endian.h>
5#include <stdint.h>
6#include <stdlib.h>
7#include <limits.h>
8#include <string.h>
9#include <netinet/in.h>
10#include <errno.h>
11#include <inttypes.h>
12
13#include <libmnl/libmnl.h>
14#include <linux/netfilter/nfnetlink.h>
15#include <linux/netfilter/nf_tables.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter_arp.h>
18
19#include <libnftnl/flowtable.h>
20
22 struct list_head head;
23 const char *name;
24 const char *table;
25 int family;
26 uint32_t hooknum;
27 int32_t prio;
28 uint32_t size;
29 const char **dev_array;
30 uint32_t dev_array_len;
31 uint32_t ft_flags;
32 uint32_t use;
33 uint32_t flags;
34 uint64_t handle;
35};
36
37EXPORT_SYMBOL(nftnl_flowtable_alloc);
38struct nftnl_flowtable *nftnl_flowtable_alloc(void)
39{
40 return calloc(1, sizeof(struct nftnl_flowtable));
41}
42
43EXPORT_SYMBOL(nftnl_flowtable_free);
44void nftnl_flowtable_free(const struct nftnl_flowtable *c)
45{
46 int i;
47
48 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
49 xfree(c->name);
50 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
51 xfree(c->table);
52 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
53 for (i = 0; i < c->dev_array_len; i++)
54 xfree(c->dev_array[i]);
55
56 xfree(c->dev_array);
57 }
58 xfree(c);
59}
60
61EXPORT_SYMBOL(nftnl_flowtable_is_set);
62bool nftnl_flowtable_is_set(const struct nftnl_flowtable *c, uint16_t attr)
63{
64 return c->flags & (1 << attr);
65}
66
67EXPORT_SYMBOL(nftnl_flowtable_unset);
68void nftnl_flowtable_unset(struct nftnl_flowtable *c, uint16_t attr)
69{
70 int i;
71
72 if (!(c->flags & (1 << attr)))
73 return;
74
75 switch (attr) {
76 case NFTNL_FLOWTABLE_NAME:
77 xfree(c->name);
78 break;
79 case NFTNL_FLOWTABLE_TABLE:
80 xfree(c->table);
81 break;
82 case NFTNL_FLOWTABLE_HOOKNUM:
83 case NFTNL_FLOWTABLE_PRIO:
84 case NFTNL_FLOWTABLE_USE:
85 case NFTNL_FLOWTABLE_FAMILY:
86 case NFTNL_FLOWTABLE_FLAGS:
87 case NFTNL_FLOWTABLE_HANDLE:
88 break;
89 case NFTNL_FLOWTABLE_DEVICES:
90 for (i = 0; i < c->dev_array_len; i++)
91 xfree(c->dev_array[i]);
92 xfree(c->dev_array);
93 break;
94 default:
95 return;
96 }
97
98 c->flags &= ~(1 << attr);
99}
100
101static uint32_t nftnl_flowtable_validate[NFTNL_FLOWTABLE_MAX + 1] = {
102 [NFTNL_FLOWTABLE_HOOKNUM] = sizeof(uint32_t),
103 [NFTNL_FLOWTABLE_PRIO] = sizeof(int32_t),
104 [NFTNL_FLOWTABLE_FAMILY] = sizeof(uint32_t),
105 [NFTNL_FLOWTABLE_SIZE] = sizeof(uint32_t),
106 [NFTNL_FLOWTABLE_FLAGS] = sizeof(uint32_t),
107 [NFTNL_FLOWTABLE_HANDLE] = sizeof(uint64_t),
108};
109
110EXPORT_SYMBOL(nftnl_flowtable_set_data);
111int nftnl_flowtable_set_data(struct nftnl_flowtable *c, uint16_t attr,
112 const void *data, uint32_t data_len)
113{
114 const char **dev_array;
115 int len = 0, i;
116
117 nftnl_assert_attr_exists(attr, NFTNL_FLOWTABLE_MAX);
118 nftnl_assert_validate(data, nftnl_flowtable_validate, attr, data_len);
119
120 switch(attr) {
121 case NFTNL_FLOWTABLE_NAME:
122 return nftnl_set_str_attr(&c->name, &c->flags,
123 attr, data, data_len);
124 case NFTNL_FLOWTABLE_TABLE:
125 return nftnl_set_str_attr(&c->table, &c->flags,
126 attr, data, data_len);
127 break;
128 case NFTNL_FLOWTABLE_HOOKNUM:
129 memcpy(&c->hooknum, data, sizeof(c->hooknum));
130 break;
131 case NFTNL_FLOWTABLE_PRIO:
132 memcpy(&c->prio, data, sizeof(c->prio));
133 break;
134 case NFTNL_FLOWTABLE_FAMILY:
135 memcpy(&c->family, data, sizeof(c->family));
136 break;
137 case NFTNL_FLOWTABLE_DEVICES:
138 dev_array = (const char **)data;
139 while (dev_array[len] != NULL)
140 len++;
141
142 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
143 for (i = 0; i < c->dev_array_len; i++)
144 xfree(c->dev_array[i]);
145 xfree(c->dev_array);
146 }
147
148 c->dev_array = calloc(len + 1, sizeof(char *));
149 if (!c->dev_array)
150 return -1;
151
152 for (i = 0; i < len; i++)
153 c->dev_array[i] = strdup(dev_array[i]);
154
155 c->dev_array_len = len;
156 break;
157 case NFTNL_FLOWTABLE_SIZE:
158 memcpy(&c->size, data, sizeof(c->size));
159 break;
160 case NFTNL_FLOWTABLE_FLAGS:
161 memcpy(&c->ft_flags, data, sizeof(c->ft_flags));
162 break;
163 case NFTNL_FLOWTABLE_HANDLE:
164 memcpy(&c->handle, data, sizeof(c->handle));
165 break;
166 }
167 c->flags |= (1 << attr);
168 return 0;
169}
170
171void nftnl_flowtable_set(struct nftnl_flowtable *c, uint16_t attr, const void *data) __visible;
172void nftnl_flowtable_set(struct nftnl_flowtable *c, uint16_t attr, const void *data)
173{
174 nftnl_flowtable_set_data(c, attr, data, nftnl_flowtable_validate[attr]);
175}
176
177EXPORT_SYMBOL(nftnl_flowtable_set_u32);
178void nftnl_flowtable_set_u32(struct nftnl_flowtable *c, uint16_t attr, uint32_t data)
179{
180 nftnl_flowtable_set_data(c, attr, &data, sizeof(uint32_t));
181}
182
183EXPORT_SYMBOL(nftnl_flowtable_set_s32);
184void nftnl_flowtable_set_s32(struct nftnl_flowtable *c, uint16_t attr, int32_t data)
185{
186 nftnl_flowtable_set_data(c, attr, &data, sizeof(int32_t));
187}
188
189EXPORT_SYMBOL(nftnl_flowtable_set_str);
190int nftnl_flowtable_set_str(struct nftnl_flowtable *c, uint16_t attr, const char *str)
191{
192 return nftnl_flowtable_set_data(c, attr, str, strlen(str) + 1);
193}
194
195EXPORT_SYMBOL(nftnl_flowtable_set_u64);
196void nftnl_flowtable_set_u64(struct nftnl_flowtable *c, uint16_t attr, uint64_t data)
197{
198 nftnl_flowtable_set_data(c, attr, &data, sizeof(uint64_t));
199}
200
201EXPORT_SYMBOL(nftnl_flowtable_set_array);
202int nftnl_flowtable_set_array(struct nftnl_flowtable *c, uint16_t attr,
203 const char **data)
204{
205 return nftnl_flowtable_set_data(c, attr, data, 0);
206}
207
208EXPORT_SYMBOL(nftnl_flowtable_get_data);
209const void *nftnl_flowtable_get_data(const struct nftnl_flowtable *c,
210 uint16_t attr, uint32_t *data_len)
211{
212 if (!(c->flags & (1 << attr)))
213 return NULL;
214
215 switch(attr) {
216 case NFTNL_FLOWTABLE_NAME:
217 *data_len = strlen(c->name) + 1;
218 return c->name;
219 case NFTNL_FLOWTABLE_TABLE:
220 *data_len = strlen(c->table) + 1;
221 return c->table;
222 case NFTNL_FLOWTABLE_HOOKNUM:
223 *data_len = sizeof(uint32_t);
224 return &c->hooknum;
225 case NFTNL_FLOWTABLE_PRIO:
226 *data_len = sizeof(int32_t);
227 return &c->prio;
228 case NFTNL_FLOWTABLE_FAMILY:
229 *data_len = sizeof(int32_t);
230 return &c->family;
231 case NFTNL_FLOWTABLE_DEVICES:
232 *data_len = 0;
233 return &c->dev_array[0];
234 case NFTNL_FLOWTABLE_SIZE:
235 *data_len = sizeof(int32_t);
236 return &c->size;
237 case NFTNL_FLOWTABLE_FLAGS:
238 *data_len = sizeof(int32_t);
239 return &c->ft_flags;
240 case NFTNL_FLOWTABLE_HANDLE:
241 *data_len = sizeof(uint64_t);
242 return &c->handle;
243 }
244 return NULL;
245}
246
247EXPORT_SYMBOL(nftnl_flowtable_get);
248const void *nftnl_flowtable_get(const struct nftnl_flowtable *c, uint16_t attr)
249{
250 uint32_t data_len;
251 return nftnl_flowtable_get_data(c, attr, &data_len);
252}
253
254EXPORT_SYMBOL(nftnl_flowtable_get_str);
255const char *nftnl_flowtable_get_str(const struct nftnl_flowtable *c, uint16_t attr)
256{
257 return nftnl_flowtable_get(c, attr);
258}
259
260EXPORT_SYMBOL(nftnl_flowtable_get_u32);
261uint32_t nftnl_flowtable_get_u32(const struct nftnl_flowtable *c, uint16_t attr)
262{
263 uint32_t data_len = 0;
264 const uint32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
265
266 nftnl_assert(val, attr, data_len == sizeof(uint32_t));
267
268 return val ? *val : 0;
269}
270
271EXPORT_SYMBOL(nftnl_flowtable_get_u64);
272uint64_t nftnl_flowtable_get_u64(const struct nftnl_flowtable *c, uint16_t attr)
273{
274 uint32_t data_len = 0;
275 const uint64_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
276
277 nftnl_assert(val, attr, data_len == sizeof(uint64_t));
278
279 return val ? *val : 0;
280}
281
282EXPORT_SYMBOL(nftnl_flowtable_get_s32);
283int32_t nftnl_flowtable_get_s32(const struct nftnl_flowtable *c, uint16_t attr)
284{
285 uint32_t data_len = 0;
286 const int32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
287
288 nftnl_assert(val, attr, data_len == sizeof(int32_t));
289
290 return val ? *val : 0;
291}
292
293EXPORT_SYMBOL(nftnl_flowtable_get_array);
294const char *const *nftnl_flowtable_get_array(const struct nftnl_flowtable *c, uint16_t attr)
295{
296 uint32_t data_len;
297 const char * const *val = nftnl_flowtable_get_data(c, attr, &data_len);
298
299 nftnl_assert(val, attr, attr == NFTNL_FLOWTABLE_DEVICES);
300
301 return val;
302}
303
304EXPORT_SYMBOL(nftnl_flowtable_nlmsg_build_payload);
305void nftnl_flowtable_nlmsg_build_payload(struct nlmsghdr *nlh,
306 const struct nftnl_flowtable *c)
307{
308 struct nlattr *nest = NULL;
309 int i;
310
311 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
312 mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, c->table);
313 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
314 mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME, c->name);
315
316 if (c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM) ||
317 c->flags & (1 << NFTNL_FLOWTABLE_PRIO) ||
318 c->flags & (1 << NFTNL_FLOWTABLE_DEVICES))
319 nest = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK);
320
321 if (c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM))
322 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_NUM, htonl(c->hooknum));
323 if (c->flags & (1 << NFTNL_FLOWTABLE_PRIO))
324 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_PRIORITY, htonl(c->prio));
325
326 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
327 struct nlattr *nest_dev;
328
329 nest_dev = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK_DEVS);
330 for (i = 0; i < c->dev_array_len; i++) {
331 mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME,
332 c->dev_array[i]);
333 }
334 mnl_attr_nest_end(nlh, nest_dev);
335 }
336
337 if (nest)
338 mnl_attr_nest_end(nlh, nest);
339
340 if (c->flags & (1 << NFTNL_FLOWTABLE_FLAGS))
341 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_FLAGS, htonl(c->ft_flags));
342 if (c->flags & (1 << NFTNL_FLOWTABLE_USE))
343 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_USE, htonl(c->use));
344 if (c->flags & (1 << NFTNL_FLOWTABLE_HANDLE))
345 mnl_attr_put_u64(nlh, NFTA_FLOWTABLE_HANDLE, htobe64(c->handle));
346}
347
348static int nftnl_flowtable_parse_attr_cb(const struct nlattr *attr, void *data)
349{
350 const struct nlattr **tb = data;
351 int type = mnl_attr_get_type(attr);
352
353 if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_MAX) < 0)
354 return MNL_CB_OK;
355
356 switch(type) {
357 case NFTA_FLOWTABLE_NAME:
358 case NFTA_FLOWTABLE_TABLE:
359 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
360 abi_breakage();
361 break;
362 case NFTA_FLOWTABLE_HOOK:
363 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
364 abi_breakage();
365 break;
366 case NFTA_FLOWTABLE_FLAGS:
367 case NFTA_FLOWTABLE_USE:
368 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
369 abi_breakage();
370 break;
371 case NFTA_FLOWTABLE_HANDLE:
372 if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
373 abi_breakage();
374 break;
375 }
376
377 tb[type] = attr;
378 return MNL_CB_OK;
379}
380
381static int nftnl_flowtable_parse_hook_cb(const struct nlattr *attr, void *data)
382{
383 const struct nlattr **tb = data;
384 int type = mnl_attr_get_type(attr);
385
386 if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_HOOK_MAX) < 0)
387 return MNL_CB_OK;
388
389 switch(type) {
390 case NFTA_FLOWTABLE_HOOK_NUM:
391 case NFTA_FLOWTABLE_HOOK_PRIORITY:
392 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
393 abi_breakage();
394 break;
395 case NFTA_FLOWTABLE_HOOK_DEVS:
396 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
397 abi_breakage();
398 break;
399 }
400
401 tb[type] = attr;
402 return MNL_CB_OK;
403}
404
405static int nftnl_flowtable_parse_devs(struct nlattr *nest,
406 struct nftnl_flowtable *c)
407{
408 const char **dev_array, **tmp;
409 int len = 0, size = 8;
410 struct nlattr *attr;
411
412 dev_array = calloc(8, sizeof(char *));
413 if (!dev_array)
414 return -1;
415
416 mnl_attr_for_each_nested(attr, nest) {
417 if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
418 goto err;
419 dev_array[len++] = strdup(mnl_attr_get_str(attr));
420 if (len >= size) {
421 tmp = realloc(dev_array, size * 2 * sizeof(char *));
422 if (!tmp)
423 goto err;
424
425 size *= 2;
426 memset(&tmp[len], 0, (size - len) * sizeof(char *));
427 dev_array = tmp;
428 }
429 }
430
431 c->dev_array = dev_array;
432 c->dev_array_len = len;
433
434 return 0;
435err:
436 while (len--)
437 xfree(dev_array[len]);
438 xfree(dev_array);
439 return -1;
440}
441
442static int nftnl_flowtable_parse_hook(struct nlattr *attr, struct nftnl_flowtable *c)
443{
444 struct nlattr *tb[NFTA_FLOWTABLE_HOOK_MAX + 1] = {};
445 int ret;
446
447 if (mnl_attr_parse_nested(attr, nftnl_flowtable_parse_hook_cb, tb) < 0)
448 return -1;
449
450 if (tb[NFTA_FLOWTABLE_HOOK_NUM]) {
451 c->hooknum = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_HOOK_NUM]));
452 c->flags |= (1 << NFTNL_FLOWTABLE_HOOKNUM);
453 }
454 if (tb[NFTA_FLOWTABLE_HOOK_PRIORITY]) {
455 c->prio = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_HOOK_PRIORITY]));
456 c->flags |= (1 << NFTNL_FLOWTABLE_PRIO);
457 }
458 if (tb[NFTA_FLOWTABLE_HOOK_DEVS]) {
459 ret = nftnl_flowtable_parse_devs(tb[NFTA_FLOWTABLE_HOOK_DEVS], c);
460 if (ret < 0)
461 return -1;
462 c->flags |= (1 << NFTNL_FLOWTABLE_DEVICES);
463 }
464
465 return 0;
466}
467
468EXPORT_SYMBOL(nftnl_flowtable_nlmsg_parse);
469int nftnl_flowtable_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_flowtable *c)
470{
471 struct nlattr *tb[NFTA_FLOWTABLE_MAX + 1] = {};
472 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
473 int ret = 0;
474
475 if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_flowtable_parse_attr_cb, tb) < 0)
476 return -1;
477
478 if (tb[NFTA_FLOWTABLE_NAME]) {
479 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
480 xfree(c->name);
481 c->name = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_NAME]));
482 if (!c->name)
483 return -1;
484 c->flags |= (1 << NFTNL_FLOWTABLE_NAME);
485 }
486 if (tb[NFTA_FLOWTABLE_TABLE]) {
487 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
488 xfree(c->table);
489 c->table = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_TABLE]));
490 if (!c->table)
491 return -1;
492 c->flags |= (1 << NFTNL_FLOWTABLE_TABLE);
493 }
494 if (tb[NFTA_FLOWTABLE_HOOK]) {
495 ret = nftnl_flowtable_parse_hook(tb[NFTA_FLOWTABLE_HOOK], c);
496 if (ret < 0)
497 return ret;
498 }
499 if (tb[NFTA_FLOWTABLE_FLAGS]) {
500 c->ft_flags = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_FLAGS]));
501 c->flags |= (1 << NFTNL_FLOWTABLE_FLAGS);
502 }
503 if (tb[NFTA_FLOWTABLE_USE]) {
504 c->use = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_USE]));
505 c->flags |= (1 << NFTNL_FLOWTABLE_USE);
506 }
507 if (tb[NFTA_FLOWTABLE_HANDLE]) {
508 c->handle = be64toh(mnl_attr_get_u64(tb[NFTA_FLOWTABLE_HANDLE]));
509 c->flags |= (1 << NFTNL_FLOWTABLE_HANDLE);
510 }
511
512 c->family = nfg->nfgen_family;
513 c->flags |= (1 << NFTNL_FLOWTABLE_FAMILY);
514
515 return ret;
516}
517
518static const char *nftnl_hooknum2str(int family, int hooknum)
519{
520 switch (family) {
521 case NFPROTO_IPV4:
522 case NFPROTO_IPV6:
523 case NFPROTO_INET:
524 case NFPROTO_BRIDGE:
525 switch (hooknum) {
526 case NF_INET_PRE_ROUTING:
527 return "prerouting";
528 case NF_INET_LOCAL_IN:
529 return "input";
530 case NF_INET_FORWARD:
531 return "forward";
532 case NF_INET_LOCAL_OUT:
533 return "output";
534 case NF_INET_POST_ROUTING:
535 return "postrouting";
536 }
537 break;
538 case NFPROTO_ARP:
539 switch (hooknum) {
540 case NF_ARP_IN:
541 return "input";
542 case NF_ARP_OUT:
543 return "output";
544 case NF_ARP_FORWARD:
545 return "forward";
546 }
547 break;
548 case NFPROTO_NETDEV:
549 switch (hooknum) {
550 case NF_NETDEV_INGRESS:
551 return "ingress";
552 }
553 break;
554 }
555 return "unknown";
556}
557
558static inline int nftnl_str2hooknum(int family, const char *hook)
559{
560 int hooknum;
561
562 for (hooknum = 0; hooknum < NF_INET_NUMHOOKS; hooknum++) {
563 if (strcmp(hook, nftnl_hooknum2str(family, hooknum)) == 0)
564 return hooknum;
565 }
566 return -1;
567}
568
569EXPORT_SYMBOL(nftnl_flowtable_parse);
570int nftnl_flowtable_parse(struct nftnl_flowtable *c, enum nftnl_parse_type type,
571 const char *data, struct nftnl_parse_err *err)
572{
573 errno = EOPNOTSUPP;
574 return -1;
575}
576
577EXPORT_SYMBOL(nftnl_flowtable_parse_file);
578int nftnl_flowtable_parse_file(struct nftnl_flowtable *c,
579 enum nftnl_parse_type type,
580 FILE *fp, struct nftnl_parse_err *err)
581{
582 errno = EOPNOTSUPP;
583 return -1;
584}
585
586static int nftnl_flowtable_snprintf_default(char *buf, size_t remain,
587 const struct nftnl_flowtable *c)
588{
589 int ret, offset = 0, i;
590
591 ret = snprintf(buf, remain, "flow table %s %s use %u size %u flags %x",
592 c->table, c->name, c->use, c->size, c->ft_flags);
593 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
594
595 if (c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM)) {
596 ret = snprintf(buf + offset, remain, " hook %s prio %d ",
597 nftnl_hooknum2str(c->family, c->hooknum),
598 c->prio);
599 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
600
601 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
602 ret = snprintf(buf + offset, remain, " dev { ");
603 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
604
605 for (i = 0; i < c->dev_array_len; i++) {
606 ret = snprintf(buf + offset, remain, " %s ",
607 c->dev_array[i]);
608 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
609 }
610 ret = snprintf(buf + offset, remain, " } ");
611 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
612 }
613 }
614
615 return offset;
616}
617
618static int nftnl_flowtable_cmd_snprintf(char *buf, size_t remain,
619 const struct nftnl_flowtable *c,
620 uint32_t cmd, uint32_t type,
621 uint32_t flags)
622{
623 int ret, offset = 0;
624
625 if (type != NFTNL_OUTPUT_DEFAULT)
626 return -1;
627
628 ret = nftnl_flowtable_snprintf_default(buf + offset, remain, c);
629 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
630 return offset;
631}
632
633EXPORT_SYMBOL(nftnl_flowtable_snprintf);
634int nftnl_flowtable_snprintf(char *buf, size_t size, const struct nftnl_flowtable *c,
635 uint32_t type, uint32_t flags)
636{
637 if (size)
638 buf[0] = '\0';
639
640 return nftnl_flowtable_cmd_snprintf(buf, size, c, nftnl_flag2cmd(flags),
641 type, flags);
642}
643
644static int nftnl_flowtable_do_snprintf(char *buf, size_t size, const void *c,
645 uint32_t cmd, uint32_t type, uint32_t flags)
646{
647 return nftnl_flowtable_snprintf(buf, size, c, type, flags);
648}
649
650EXPORT_SYMBOL(nftnl_flowtable_fprintf);
651int nftnl_flowtable_fprintf(FILE *fp, const struct nftnl_flowtable *c,
652 uint32_t type, uint32_t flags)
653{
654 return nftnl_fprintf(fp, c, NFTNL_CMD_UNSPEC, type, flags,
655 nftnl_flowtable_do_snprintf);
656}
657
659 struct list_head list;
660};
661
662EXPORT_SYMBOL(nftnl_flowtable_list_alloc);
663struct nftnl_flowtable_list *nftnl_flowtable_list_alloc(void)
664{
665 struct nftnl_flowtable_list *list;
666
667 list = calloc(1, sizeof(struct nftnl_flowtable_list));
668 if (list == NULL)
669 return NULL;
670
671 INIT_LIST_HEAD(&list->list);
672
673 return list;
674}
675
676EXPORT_SYMBOL(nftnl_flowtable_list_free);
677void nftnl_flowtable_list_free(struct nftnl_flowtable_list *list)
678{
679 struct nftnl_flowtable *s, *tmp;
680
681 list_for_each_entry_safe(s, tmp, &list->list, head) {
682 list_del(&s->head);
683 nftnl_flowtable_free(s);
684 }
685 xfree(list);
686}
687
688EXPORT_SYMBOL(nftnl_flowtable_list_is_empty);
689int nftnl_flowtable_list_is_empty(const struct nftnl_flowtable_list *list)
690{
691 return list_empty(&list->list);
692}
693
694EXPORT_SYMBOL(nftnl_flowtable_list_add);
695void nftnl_flowtable_list_add(struct nftnl_flowtable *s,
696 struct nftnl_flowtable_list *list)
697{
698 list_add(&s->head, &list->list);
699}
700
701EXPORT_SYMBOL(nftnl_flowtable_list_add_tail);
702void nftnl_flowtable_list_add_tail(struct nftnl_flowtable *s,
703 struct nftnl_flowtable_list *list)
704{
705 list_add_tail(&s->head, &list->list);
706}
707
708EXPORT_SYMBOL(nftnl_flowtable_list_del);
709void nftnl_flowtable_list_del(struct nftnl_flowtable *s)
710{
711 list_del(&s->head);
712}
713
714EXPORT_SYMBOL(nftnl_flowtable_list_foreach);
715int nftnl_flowtable_list_foreach(struct nftnl_flowtable_list *flowtable_list,
716 int (*cb)(struct nftnl_flowtable *t, void *data), void *data)
717{
718 struct nftnl_flowtable *cur, *tmp;
719 int ret;
720
721 list_for_each_entry_safe(cur, tmp, &flowtable_list->list, head) {
722 ret = cb(cur, data);
723 if (ret < 0)
724 return ret;
725 }
726 return 0;
727}