9 #include <netinet/in.h>
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>
19 #include <libnftnl/flowtable.h>
22 struct list_head head;
29 const char **dev_array;
30 uint32_t dev_array_len;
37 EXPORT_SYMBOL(nftnl_flowtable_alloc);
43 EXPORT_SYMBOL(nftnl_flowtable_free);
48 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
50 if (c->flags & (1 << NFTNL_FLOWTABLE_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]);
61 EXPORT_SYMBOL(nftnl_flowtable_is_set);
62 bool nftnl_flowtable_is_set(
const struct nftnl_flowtable *c, uint16_t attr)
64 return c->flags & (1 << attr);
67 EXPORT_SYMBOL(nftnl_flowtable_unset);
72 if (!(c->flags & (1 << attr)))
76 case NFTNL_FLOWTABLE_NAME:
79 case NFTNL_FLOWTABLE_TABLE:
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:
89 case NFTNL_FLOWTABLE_DEVICES:
90 for (i = 0; i < c->dev_array_len; i++)
91 xfree(c->dev_array[i]);
98 c->flags &= ~(1 << attr);
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),
110 EXPORT_SYMBOL(nftnl_flowtable_set_data);
112 const void *data, uint32_t data_len)
114 const char **dev_array;
117 nftnl_assert_attr_exists(attr, NFTNL_FLOWTABLE_MAX);
118 nftnl_assert_validate(data, nftnl_flowtable_validate, attr, data_len);
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);
128 case NFTNL_FLOWTABLE_HOOKNUM:
129 memcpy(&c->hooknum, data,
sizeof(c->hooknum));
131 case NFTNL_FLOWTABLE_PRIO:
132 memcpy(&c->prio, data,
sizeof(c->prio));
134 case NFTNL_FLOWTABLE_FAMILY:
135 memcpy(&c->family, data,
sizeof(c->family));
137 case NFTNL_FLOWTABLE_DEVICES:
138 dev_array = (
const char **)data;
139 while (dev_array[len] != NULL)
142 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
143 for (i = 0; i < c->dev_array_len; i++)
144 xfree(c->dev_array[i]);
148 c->dev_array = calloc(len + 1,
sizeof(
char *));
152 for (i = 0; i < len; i++)
153 c->dev_array[i] = strdup(dev_array[i]);
155 c->dev_array_len = len;
157 case NFTNL_FLOWTABLE_SIZE:
158 memcpy(&c->size, data,
sizeof(c->size));
160 case NFTNL_FLOWTABLE_FLAGS:
161 memcpy(&c->ft_flags, data,
sizeof(c->ft_flags));
163 case NFTNL_FLOWTABLE_HANDLE:
164 memcpy(&c->handle, data,
sizeof(c->handle));
167 c->flags |= (1 << attr);
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)
174 nftnl_flowtable_set_data(c, attr, data, nftnl_flowtable_validate[attr]);
177 EXPORT_SYMBOL(nftnl_flowtable_set_u32);
178 void nftnl_flowtable_set_u32(
struct nftnl_flowtable *c, uint16_t attr, uint32_t data)
180 nftnl_flowtable_set_data(c, attr, &data,
sizeof(uint32_t));
183 EXPORT_SYMBOL(nftnl_flowtable_set_s32);
184 void nftnl_flowtable_set_s32(
struct nftnl_flowtable *c, uint16_t attr, int32_t data)
186 nftnl_flowtable_set_data(c, attr, &data,
sizeof(int32_t));
189 EXPORT_SYMBOL(nftnl_flowtable_set_str);
190 int nftnl_flowtable_set_str(
struct nftnl_flowtable *c, uint16_t attr,
const char *str)
192 return nftnl_flowtable_set_data(c, attr, str, strlen(str) + 1);
195 EXPORT_SYMBOL(nftnl_flowtable_set_u64);
196 void nftnl_flowtable_set_u64(
struct nftnl_flowtable *c, uint16_t attr, uint64_t data)
198 nftnl_flowtable_set_data(c, attr, &data,
sizeof(uint64_t));
201 EXPORT_SYMBOL(nftnl_flowtable_set_array);
202 int nftnl_flowtable_set_array(
struct nftnl_flowtable *c, uint16_t attr,
205 return nftnl_flowtable_set_data(c, attr, data, 0);
208 EXPORT_SYMBOL(nftnl_flowtable_get_data);
210 uint16_t attr, uint32_t *data_len)
212 if (!(c->flags & (1 << attr)))
216 case NFTNL_FLOWTABLE_NAME:
217 *data_len = strlen(c->name) + 1;
219 case NFTNL_FLOWTABLE_TABLE:
220 *data_len = strlen(c->table) + 1;
222 case NFTNL_FLOWTABLE_HOOKNUM:
223 *data_len =
sizeof(uint32_t);
225 case NFTNL_FLOWTABLE_PRIO:
226 *data_len =
sizeof(int32_t);
228 case NFTNL_FLOWTABLE_FAMILY:
229 *data_len =
sizeof(int32_t);
231 case NFTNL_FLOWTABLE_DEVICES:
233 return &c->dev_array[0];
234 case NFTNL_FLOWTABLE_SIZE:
235 *data_len =
sizeof(int32_t);
237 case NFTNL_FLOWTABLE_FLAGS:
238 *data_len =
sizeof(int32_t);
240 case NFTNL_FLOWTABLE_HANDLE:
241 *data_len =
sizeof(uint64_t);
247 EXPORT_SYMBOL(nftnl_flowtable_get);
248 const void *nftnl_flowtable_get(
const struct nftnl_flowtable *c, uint16_t attr)
251 return nftnl_flowtable_get_data(c, attr, &data_len);
254 EXPORT_SYMBOL(nftnl_flowtable_get_str);
255 const char *nftnl_flowtable_get_str(
const struct nftnl_flowtable *c, uint16_t attr)
257 return nftnl_flowtable_get(c, attr);
260 EXPORT_SYMBOL(nftnl_flowtable_get_u32);
261 uint32_t nftnl_flowtable_get_u32(
const struct nftnl_flowtable *c, uint16_t attr)
263 uint32_t data_len = 0;
264 const uint32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
266 nftnl_assert(val, attr, data_len ==
sizeof(uint32_t));
268 return val ? *val : 0;
271 EXPORT_SYMBOL(nftnl_flowtable_get_u64);
272 uint64_t nftnl_flowtable_get_u64(
const struct nftnl_flowtable *c, uint16_t attr)
274 uint32_t data_len = 0;
275 const uint64_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
277 nftnl_assert(val, attr, data_len ==
sizeof(uint64_t));
279 return val ? *val : 0;
282 EXPORT_SYMBOL(nftnl_flowtable_get_s32);
283 int32_t nftnl_flowtable_get_s32(
const struct nftnl_flowtable *c, uint16_t attr)
285 uint32_t data_len = 0;
286 const int32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
288 nftnl_assert(val, attr, data_len ==
sizeof(int32_t));
290 return val ? *val : 0;
293 EXPORT_SYMBOL(nftnl_flowtable_get_array);
294 const char *
const *nftnl_flowtable_get_array(
const struct nftnl_flowtable *c, uint16_t attr)
297 const char *
const *val = nftnl_flowtable_get_data(c, attr, &data_len);
299 nftnl_assert(val, attr, attr == NFTNL_FLOWTABLE_DEVICES);
304 EXPORT_SYMBOL(nftnl_flowtable_nlmsg_build_payload);
305 void nftnl_flowtable_nlmsg_build_payload(
struct nlmsghdr *nlh,
308 struct nlattr *nest = NULL;
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);
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);
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));
326 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
327 struct nlattr *nest_dev;
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,
334 mnl_attr_nest_end(nlh, nest_dev);
338 mnl_attr_nest_end(nlh, nest);
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));
348 static int nftnl_flowtable_parse_attr_cb(
const struct nlattr *attr,
void *data)
350 const struct nlattr **tb = data;
351 int type = mnl_attr_get_type(attr);
353 if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_MAX) < 0)
357 case NFTA_FLOWTABLE_NAME:
358 case NFTA_FLOWTABLE_TABLE:
359 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
362 case NFTA_FLOWTABLE_HOOK:
363 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
366 case NFTA_FLOWTABLE_FLAGS:
367 case NFTA_FLOWTABLE_USE:
368 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
371 case NFTA_FLOWTABLE_HANDLE:
372 if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
381 static int nftnl_flowtable_parse_hook_cb(
const struct nlattr *attr,
void *data)
383 const struct nlattr **tb = data;
384 int type = mnl_attr_get_type(attr);
386 if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_HOOK_MAX) < 0)
390 case NFTA_FLOWTABLE_HOOK_NUM:
391 case NFTA_FLOWTABLE_HOOK_PRIORITY:
392 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
395 case NFTA_FLOWTABLE_HOOK_DEVS:
396 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
405 static int nftnl_flowtable_parse_devs(
struct nlattr *nest,
408 const char **dev_array, **tmp;
409 int len = 0, size = 8;
412 dev_array = calloc(8,
sizeof(
char *));
416 mnl_attr_for_each_nested(attr, nest) {
417 if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
419 dev_array[len++] = strdup(mnl_attr_get_str(attr));
421 tmp = realloc(dev_array, size * 2 *
sizeof(
char *));
426 memset(&tmp[len], 0, (size - len) *
sizeof(
char *));
431 c->dev_array = dev_array;
432 c->dev_array_len = len;
437 xfree(dev_array[len]);
442 static int nftnl_flowtable_parse_hook(
struct nlattr *attr,
struct nftnl_flowtable *c)
444 struct nlattr *tb[NFTA_FLOWTABLE_HOOK_MAX + 1] = {};
447 if (mnl_attr_parse_nested(attr, nftnl_flowtable_parse_hook_cb, tb) < 0)
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);
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);
458 if (tb[NFTA_FLOWTABLE_HOOK_DEVS]) {
459 ret = nftnl_flowtable_parse_devs(tb[NFTA_FLOWTABLE_HOOK_DEVS], c);
462 c->flags |= (1 << NFTNL_FLOWTABLE_DEVICES);
468 EXPORT_SYMBOL(nftnl_flowtable_nlmsg_parse);
469 int nftnl_flowtable_nlmsg_parse(
const struct nlmsghdr *nlh,
struct nftnl_flowtable *c)
471 struct nlattr *tb[NFTA_FLOWTABLE_MAX + 1] = {};
472 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
475 if (mnl_attr_parse(nlh,
sizeof(*nfg), nftnl_flowtable_parse_attr_cb, tb) < 0)
478 if (tb[NFTA_FLOWTABLE_NAME]) {
479 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
481 c->name = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_NAME]));
484 c->flags |= (1 << NFTNL_FLOWTABLE_NAME);
486 if (tb[NFTA_FLOWTABLE_TABLE]) {
487 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
489 c->table = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_TABLE]));
492 c->flags |= (1 << NFTNL_FLOWTABLE_TABLE);
494 if (tb[NFTA_FLOWTABLE_HOOK]) {
495 ret = nftnl_flowtable_parse_hook(tb[NFTA_FLOWTABLE_HOOK], c);
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);
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);
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);
512 c->family = nfg->nfgen_family;
513 c->flags |= (1 << NFTNL_FLOWTABLE_FAMILY);
518 static const char *nftnl_hooknum2str(
int family,
int hooknum)
526 case NF_INET_PRE_ROUTING:
528 case NF_INET_LOCAL_IN:
530 case NF_INET_FORWARD:
532 case NF_INET_LOCAL_OUT:
534 case NF_INET_POST_ROUTING:
535 return "postrouting";
550 case NF_NETDEV_INGRESS:
558 static inline int nftnl_str2hooknum(
int family,
const char *hook)
562 for (hooknum = 0; hooknum < NF_INET_NUMHOOKS; hooknum++) {
563 if (strcmp(hook, nftnl_hooknum2str(family, hooknum)) == 0)
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)
577 EXPORT_SYMBOL(nftnl_flowtable_parse_file);
579 enum nftnl_parse_type type,
580 FILE *fp,
struct nftnl_parse_err *err)
586 static int nftnl_flowtable_snprintf_default(
char *buf,
size_t remain,
589 int ret, offset = 0, i;
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);
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),
599 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
601 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
602 ret = snprintf(buf + offset, remain,
" dev { ");
603 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
605 for (i = 0; i < c->dev_array_len; i++) {
606 ret = snprintf(buf + offset, remain,
" %s ",
608 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
610 ret = snprintf(buf + offset, remain,
" } ");
611 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
618 static int nftnl_flowtable_cmd_snprintf(
char *buf,
size_t remain,
620 uint32_t cmd, uint32_t type,
625 if (type != NFTNL_OUTPUT_DEFAULT)
628 ret = nftnl_flowtable_snprintf_default(buf + offset, remain, c);
629 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
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)
640 return nftnl_flowtable_cmd_snprintf(buf, size, c, nftnl_flag2cmd(flags),
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)
647 return nftnl_flowtable_snprintf(buf, size, c, type, flags);
650 EXPORT_SYMBOL(nftnl_flowtable_fprintf);
652 uint32_t type, uint32_t flags)
654 return nftnl_fprintf(fp, c, NFTNL_CMD_UNSPEC, type, flags,
655 nftnl_flowtable_do_snprintf);
659 struct list_head list;
662 EXPORT_SYMBOL(nftnl_flowtable_list_alloc);
671 INIT_LIST_HEAD(&list->list);
676 EXPORT_SYMBOL(nftnl_flowtable_list_free);
681 list_for_each_entry_safe(s, tmp, &list->list, head) {
683 nftnl_flowtable_free(s);
688 EXPORT_SYMBOL(nftnl_flowtable_list_is_empty);
691 return list_empty(&list->list);
694 EXPORT_SYMBOL(nftnl_flowtable_list_add);
698 list_add(&s->head, &list->list);
701 EXPORT_SYMBOL(nftnl_flowtable_list_add_tail);
705 list_add_tail(&s->head, &list->list);
708 EXPORT_SYMBOL(nftnl_flowtable_list_del);
714 EXPORT_SYMBOL(nftnl_flowtable_list_foreach);
721 list_for_each_entry_safe(cur, tmp, &flowtable_list->list, head) {