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