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