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