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 
36 EXPORT_SYMBOL(nftnl_flowtable_alloc);
37 struct nftnl_flowtable *nftnl_flowtable_alloc(void)
38 {
39  return calloc(1, sizeof(struct nftnl_flowtable));
40 }
41 
42 EXPORT_SYMBOL(nftnl_flowtable_free);
43 void 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 
54 EXPORT_SYMBOL(nftnl_flowtable_is_set);
55 bool nftnl_flowtable_is_set(const struct nftnl_flowtable *c, uint16_t attr)
56 {
57  return c->flags & (1 << attr);
58 }
59 
60 EXPORT_SYMBOL(nftnl_flowtable_unset);
61 void 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 
90 static 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 
99 EXPORT_SYMBOL(nftnl_flowtable_set_data);
100 int 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 
141 void nftnl_flowtable_set(struct nftnl_flowtable *c, uint16_t attr, const void *data) __visible;
142 void 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 
147 EXPORT_SYMBOL(nftnl_flowtable_set_u32);
148 void 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 
153 EXPORT_SYMBOL(nftnl_flowtable_set_s32);
154 void 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 
159 EXPORT_SYMBOL(nftnl_flowtable_set_str);
160 int 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 
165 EXPORT_SYMBOL(nftnl_flowtable_set_u64);
166 void 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 
171 EXPORT_SYMBOL(nftnl_flowtable_set_array);
172 int 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 
178 EXPORT_SYMBOL(nftnl_flowtable_get_data);
179 const 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 
217 EXPORT_SYMBOL(nftnl_flowtable_get);
218 const 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 
224 EXPORT_SYMBOL(nftnl_flowtable_get_str);
225 const char *nftnl_flowtable_get_str(const struct nftnl_flowtable *c, uint16_t attr)
226 {
227  return nftnl_flowtable_get(c, attr);
228 }
229 
230 EXPORT_SYMBOL(nftnl_flowtable_get_u32);
231 uint32_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 
241 EXPORT_SYMBOL(nftnl_flowtable_get_u64);
242 uint64_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 
252 EXPORT_SYMBOL(nftnl_flowtable_get_s32);
253 int32_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 
263 EXPORT_SYMBOL(nftnl_flowtable_get_array);
264 const 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 
274 EXPORT_SYMBOL(nftnl_flowtable_nlmsg_build_payload);
275 void 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 
317 static 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 
350 static 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 
374 static 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 
401 EXPORT_SYMBOL(nftnl_flowtable_nlmsg_parse);
402 int 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 
451 static 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 
491 EXPORT_SYMBOL(nftnl_flowtable_parse);
492 int 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 
499 EXPORT_SYMBOL(nftnl_flowtable_parse_file);
500 int 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 
508 static 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 
541 static 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 
556 EXPORT_SYMBOL(nftnl_flowtable_snprintf);
557 int 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 
567 static 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 
573 EXPORT_SYMBOL(nftnl_flowtable_fprintf);
574 int 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 
585 EXPORT_SYMBOL(nftnl_flowtable_list_alloc);
586 struct 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 
599 EXPORT_SYMBOL(nftnl_flowtable_list_free);
600 void 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 
611 EXPORT_SYMBOL(nftnl_flowtable_list_is_empty);
612 int nftnl_flowtable_list_is_empty(const struct nftnl_flowtable_list *list)
613 {
614  return list_empty(&list->list);
615 }
616 
617 EXPORT_SYMBOL(nftnl_flowtable_list_add);
618 void nftnl_flowtable_list_add(struct nftnl_flowtable *s,
619  struct nftnl_flowtable_list *list)
620 {
621  list_add(&s->head, &list->list);
622 }
623 
624 EXPORT_SYMBOL(nftnl_flowtable_list_add_tail);
625 void 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 
631 EXPORT_SYMBOL(nftnl_flowtable_list_del);
632 void nftnl_flowtable_list_del(struct nftnl_flowtable *s)
633 {
634  list_del(&s->head);
635 }
636 
637 EXPORT_SYMBOL(nftnl_flowtable_list_foreach);
638 int 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 }