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