libnftnl  1.3.1
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  nftnl_attr_put_ifname(nlh, 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 (nftnl_parse_str_attr(tb[NFTA_FLOWTABLE_NAME],
412  NFTNL_FLOWTABLE_NAME,
413  &c->name, &c->flags) < 0)
414  return -1;
415  if (nftnl_parse_str_attr(tb[NFTA_FLOWTABLE_TABLE],
416  NFTNL_FLOWTABLE_TABLE,
417  &c->table, &c->flags) < 0)
418  return -1;
419  if (tb[NFTA_FLOWTABLE_HOOK]) {
420  ret = nftnl_flowtable_parse_hook(tb[NFTA_FLOWTABLE_HOOK], c);
421  if (ret < 0)
422  return ret;
423  }
424  if (tb[NFTA_FLOWTABLE_FLAGS]) {
425  c->ft_flags = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_FLAGS]));
426  c->flags |= (1 << NFTNL_FLOWTABLE_FLAGS);
427  }
428  if (tb[NFTA_FLOWTABLE_USE]) {
429  c->use = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_USE]));
430  c->flags |= (1 << NFTNL_FLOWTABLE_USE);
431  }
432  if (tb[NFTA_FLOWTABLE_HANDLE]) {
433  c->handle = be64toh(mnl_attr_get_u64(tb[NFTA_FLOWTABLE_HANDLE]));
434  c->flags |= (1 << NFTNL_FLOWTABLE_HANDLE);
435  }
436 
437  c->family = nfg->nfgen_family;
438  c->flags |= (1 << NFTNL_FLOWTABLE_FAMILY);
439 
440  return ret;
441 }
442 
443 static const char *nftnl_hooknum2str(int family, int hooknum)
444 {
445  switch (family) {
446  case NFPROTO_IPV4:
447  case NFPROTO_IPV6:
448  case NFPROTO_INET:
449  case NFPROTO_BRIDGE:
450  switch (hooknum) {
451  case NF_INET_PRE_ROUTING:
452  return "prerouting";
453  case NF_INET_LOCAL_IN:
454  return "input";
455  case NF_INET_FORWARD:
456  return "forward";
457  case NF_INET_LOCAL_OUT:
458  return "output";
459  case NF_INET_POST_ROUTING:
460  return "postrouting";
461  }
462  break;
463  case NFPROTO_ARP:
464  switch (hooknum) {
465  case NF_ARP_IN:
466  return "input";
467  case NF_ARP_OUT:
468  return "output";
469  case NF_ARP_FORWARD:
470  return "forward";
471  }
472  break;
473  case NFPROTO_NETDEV:
474  switch (hooknum) {
475  case NF_NETDEV_INGRESS:
476  return "ingress";
477  }
478  break;
479  }
480  return "unknown";
481 }
482 
483 EXPORT_SYMBOL(nftnl_flowtable_parse);
484 int nftnl_flowtable_parse(struct nftnl_flowtable *c, enum nftnl_parse_type type,
485  const char *data, struct nftnl_parse_err *err)
486 {
487  errno = EOPNOTSUPP;
488  return -1;
489 }
490 
491 EXPORT_SYMBOL(nftnl_flowtable_parse_file);
492 int nftnl_flowtable_parse_file(struct nftnl_flowtable *c,
493  enum nftnl_parse_type type,
494  FILE *fp, struct nftnl_parse_err *err)
495 {
496  errno = EOPNOTSUPP;
497  return -1;
498 }
499 
500 static int nftnl_flowtable_snprintf_default(char *buf, size_t remain,
501  const struct nftnl_flowtable *c)
502 {
503  int ret, offset = 0, i;
504  const char *dev;
505 
506  ret = snprintf(buf, remain, "flow table %s %s use %u size %u flags %x",
507  c->table, c->name, c->use, c->size, c->ft_flags);
508  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
509 
510  if (c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM)) {
511  ret = snprintf(buf + offset, remain, " hook %s prio %d ",
512  nftnl_hooknum2str(c->family, c->hooknum),
513  c->prio);
514  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
515 
516  if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
517  ret = snprintf(buf + offset, remain, " dev { ");
518  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
519 
520  nftnl_str_array_foreach(dev, &c->dev_array, i) {
521  ret = snprintf(buf + offset, remain, " %s ",
522  dev);
523  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
524  }
525  ret = snprintf(buf + offset, remain, " } ");
526  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
527  }
528  }
529 
530  return offset;
531 }
532 
533 static int nftnl_flowtable_cmd_snprintf(char *buf, size_t remain,
534  const struct nftnl_flowtable *c,
535  uint32_t cmd, uint32_t type,
536  uint32_t flags)
537 {
538  int ret, offset = 0;
539 
540  if (type != NFTNL_OUTPUT_DEFAULT)
541  return -1;
542 
543  ret = nftnl_flowtable_snprintf_default(buf + offset, remain, c);
544  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
545  return offset;
546 }
547 
548 EXPORT_SYMBOL(nftnl_flowtable_snprintf);
549 int nftnl_flowtable_snprintf(char *buf, size_t size, const struct nftnl_flowtable *c,
550  uint32_t type, uint32_t flags)
551 {
552  if (size)
553  buf[0] = '\0';
554 
555  return nftnl_flowtable_cmd_snprintf(buf, size, c, nftnl_flag2cmd(flags),
556  type, flags);
557 }
558 
559 static int nftnl_flowtable_do_snprintf(char *buf, size_t size, const void *c,
560  uint32_t cmd, uint32_t type, uint32_t flags)
561 {
562  return nftnl_flowtable_snprintf(buf, size, c, type, flags);
563 }
564 
565 EXPORT_SYMBOL(nftnl_flowtable_fprintf);
566 int nftnl_flowtable_fprintf(FILE *fp, const struct nftnl_flowtable *c,
567  uint32_t type, uint32_t flags)
568 {
569  return nftnl_fprintf(fp, c, NFTNL_CMD_UNSPEC, type, flags,
570  nftnl_flowtable_do_snprintf);
571 }
572 
574  struct list_head list;
575 };
576 
577 EXPORT_SYMBOL(nftnl_flowtable_list_alloc);
578 struct nftnl_flowtable_list *nftnl_flowtable_list_alloc(void)
579 {
580  struct nftnl_flowtable_list *list;
581 
582  list = calloc(1, sizeof(struct nftnl_flowtable_list));
583  if (list == NULL)
584  return NULL;
585 
586  INIT_LIST_HEAD(&list->list);
587 
588  return list;
589 }
590 
591 EXPORT_SYMBOL(nftnl_flowtable_list_free);
592 void nftnl_flowtable_list_free(struct nftnl_flowtable_list *list)
593 {
594  struct nftnl_flowtable *s, *tmp;
595 
596  list_for_each_entry_safe(s, tmp, &list->list, head) {
597  list_del(&s->head);
598  nftnl_flowtable_free(s);
599  }
600  xfree(list);
601 }
602 
603 EXPORT_SYMBOL(nftnl_flowtable_list_is_empty);
604 int nftnl_flowtable_list_is_empty(const struct nftnl_flowtable_list *list)
605 {
606  return list_empty(&list->list);
607 }
608 
609 EXPORT_SYMBOL(nftnl_flowtable_list_add);
610 void nftnl_flowtable_list_add(struct nftnl_flowtable *s,
611  struct nftnl_flowtable_list *list)
612 {
613  list_add(&s->head, &list->list);
614 }
615 
616 EXPORT_SYMBOL(nftnl_flowtable_list_add_tail);
617 void nftnl_flowtable_list_add_tail(struct nftnl_flowtable *s,
618  struct nftnl_flowtable_list *list)
619 {
620  list_add_tail(&s->head, &list->list);
621 }
622 
623 EXPORT_SYMBOL(nftnl_flowtable_list_del);
624 void nftnl_flowtable_list_del(struct nftnl_flowtable *s)
625 {
626  list_del(&s->head);
627 }
628 
629 EXPORT_SYMBOL(nftnl_flowtable_list_foreach);
630 int nftnl_flowtable_list_foreach(struct nftnl_flowtable_list *flowtable_list,
631  int (*cb)(struct nftnl_flowtable *t, void *data), void *data)
632 {
633  struct nftnl_flowtable *cur, *tmp;
634  int ret;
635 
636  list_for_each_entry_safe(cur, tmp, &flowtable_list->list, head) {
637  ret = cb(cur, data);
638  if (ret < 0)
639  return ret;
640  }
641  return 0;
642 }