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>
23 struct list_head head;
30 const char **dev_array;
31 uint32_t dev_array_len;
38 EXPORT_SYMBOL(nftnl_flowtable_alloc);
44 EXPORT_SYMBOL(nftnl_flowtable_free);
49 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
51 if (c->flags & (1 << NFTNL_FLOWTABLE_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]);
62 EXPORT_SYMBOL(nftnl_flowtable_is_set);
63 bool nftnl_flowtable_is_set(
const struct nftnl_flowtable *c, uint16_t attr)
65 return c->flags & (1 << attr);
68 EXPORT_SYMBOL(nftnl_flowtable_unset);
73 if (!(c->flags & (1 << attr)))
77 case NFTNL_FLOWTABLE_NAME:
80 case NFTNL_FLOWTABLE_TABLE:
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:
90 case NFTNL_FLOWTABLE_DEVICES:
91 for (i = 0; i < c->dev_array_len; i++)
92 xfree(c->dev_array[i]);
99 c->flags &= ~(1 << attr);
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),
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 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
125 c->name = strdup(data);
129 case NFTNL_FLOWTABLE_TABLE:
130 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
133 c->table = strdup(data);
137 case NFTNL_FLOWTABLE_HOOKNUM:
138 memcpy(&c->hooknum, data,
sizeof(c->hooknum));
140 case NFTNL_FLOWTABLE_PRIO:
141 memcpy(&c->prio, data,
sizeof(c->prio));
143 case NFTNL_FLOWTABLE_FAMILY:
144 memcpy(&c->family, data,
sizeof(c->family));
146 case NFTNL_FLOWTABLE_DEVICES:
147 dev_array = (
const char **)data;
148 while (dev_array[len] != NULL)
151 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
152 for (i = 0; i < c->dev_array_len; i++)
153 xfree(c->dev_array[i]);
157 c->dev_array = calloc(len + 1,
sizeof(
char *));
161 for (i = 0; i < len; i++)
162 c->dev_array[i] = strdup(dev_array[i]);
164 c->dev_array_len = len;
166 case NFTNL_FLOWTABLE_SIZE:
167 memcpy(&c->size, data,
sizeof(c->size));
169 case NFTNL_FLOWTABLE_FLAGS:
170 memcpy(&c->ft_flags, data,
sizeof(c->ft_flags));
172 case NFTNL_FLOWTABLE_HANDLE:
173 memcpy(&c->handle, data,
sizeof(c->handle));
176 c->flags |= (1 << attr);
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)
183 nftnl_flowtable_set_data(c, attr, data, nftnl_flowtable_validate[attr]);
186 EXPORT_SYMBOL(nftnl_flowtable_set_u32);
187 void nftnl_flowtable_set_u32(
struct nftnl_flowtable *c, uint16_t attr, uint32_t data)
189 nftnl_flowtable_set_data(c, attr, &data,
sizeof(uint32_t));
192 EXPORT_SYMBOL(nftnl_flowtable_set_s32);
193 void nftnl_flowtable_set_s32(
struct nftnl_flowtable *c, uint16_t attr, int32_t data)
195 nftnl_flowtable_set_data(c, attr, &data,
sizeof(int32_t));
198 EXPORT_SYMBOL(nftnl_flowtable_set_str);
199 int nftnl_flowtable_set_str(
struct nftnl_flowtable *c, uint16_t attr,
const char *str)
201 return nftnl_flowtable_set_data(c, attr, str, strlen(str) + 1);
204 EXPORT_SYMBOL(nftnl_flowtable_set_u64);
205 void nftnl_flowtable_set_u64(
struct nftnl_flowtable *c, uint16_t attr, uint64_t data)
207 nftnl_flowtable_set_data(c, attr, &data,
sizeof(uint64_t));
210 EXPORT_SYMBOL(nftnl_flowtable_get_data);
212 uint16_t attr, uint32_t *data_len)
214 if (!(c->flags & (1 << attr)))
218 case NFTNL_FLOWTABLE_NAME:
219 *data_len = strlen(c->name) + 1;
221 case NFTNL_FLOWTABLE_TABLE:
222 *data_len = strlen(c->table) + 1;
224 case NFTNL_FLOWTABLE_HOOKNUM:
225 *data_len =
sizeof(uint32_t);
227 case NFTNL_FLOWTABLE_PRIO:
228 *data_len =
sizeof(int32_t);
230 case NFTNL_FLOWTABLE_FAMILY:
231 *data_len =
sizeof(int32_t);
233 case NFTNL_FLOWTABLE_DEVICES:
234 return &c->dev_array[0];
235 case NFTNL_FLOWTABLE_SIZE:
236 *data_len =
sizeof(int32_t);
238 case NFTNL_FLOWTABLE_FLAGS:
239 *data_len =
sizeof(int32_t);
241 case NFTNL_FLOWTABLE_HANDLE:
242 *data_len =
sizeof(uint64_t);
248 EXPORT_SYMBOL(nftnl_flowtable_get);
249 const void *nftnl_flowtable_get(
const struct nftnl_flowtable *c, uint16_t attr)
252 return nftnl_flowtable_get_data(c, attr, &data_len);
255 EXPORT_SYMBOL(nftnl_flowtable_get_str);
256 const char *nftnl_flowtable_get_str(
const struct nftnl_flowtable *c, uint16_t attr)
258 return nftnl_flowtable_get(c, attr);
261 EXPORT_SYMBOL(nftnl_flowtable_get_u32);
262 uint32_t nftnl_flowtable_get_u32(
const struct nftnl_flowtable *c, uint16_t attr)
264 uint32_t data_len = 0;
265 const uint32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
267 nftnl_assert(val, attr, data_len ==
sizeof(uint32_t));
269 return val ? *val : 0;
272 EXPORT_SYMBOL(nftnl_flowtable_get_u64);
273 uint64_t nftnl_flowtable_get_u64(
const struct nftnl_flowtable *c, uint16_t attr)
275 uint32_t data_len = 0;
276 const uint64_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
278 nftnl_assert(val, attr, data_len ==
sizeof(uint64_t));
280 return val ? *val : 0;
283 EXPORT_SYMBOL(nftnl_flowtable_get_s32);
284 int32_t nftnl_flowtable_get_s32(
const struct nftnl_flowtable *c, uint16_t attr)
286 uint32_t data_len = 0;
287 const int32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
289 nftnl_assert(val, attr, data_len ==
sizeof(int32_t));
291 return val ? *val : 0;
294 EXPORT_SYMBOL(nftnl_flowtable_nlmsg_build_payload);
295 void nftnl_flowtable_nlmsg_build_payload(
struct nlmsghdr *nlh,
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))) {
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;
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,
319 mnl_attr_nest_end(nlh, nest_dev);
321 mnl_attr_nest_end(nlh, nest);
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));
331 static int nftnl_flowtable_parse_attr_cb(
const struct nlattr *attr,
void *data)
333 const struct nlattr **tb = data;
334 int type = mnl_attr_get_type(attr);
336 if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_MAX) < 0)
340 case NFTA_FLOWTABLE_NAME:
341 case NFTA_FLOWTABLE_TABLE:
342 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
345 case NFTA_FLOWTABLE_HOOK:
346 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
349 case NFTA_FLOWTABLE_FLAGS:
350 case NFTA_FLOWTABLE_USE:
351 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
354 case NFTA_FLOWTABLE_HANDLE:
355 if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
364 static int nftnl_flowtable_parse_hook_cb(
const struct nlattr *attr,
void *data)
366 const struct nlattr **tb = data;
367 int type = mnl_attr_get_type(attr);
369 if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_HOOK_MAX) < 0)
373 case NFTA_FLOWTABLE_HOOK_NUM:
374 case NFTA_FLOWTABLE_HOOK_PRIORITY:
375 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
378 case NFTA_FLOWTABLE_HOOK_DEVS:
379 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
388 static int nftnl_flowtable_parse_devs(
struct nlattr *nest,
391 const char **dev_array;
392 int len = 0, size = 8;
395 dev_array = calloc(8,
sizeof(
char *));
399 mnl_attr_for_each_nested(attr, nest) {
400 if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
402 dev_array[len++] = strdup(mnl_attr_get_str(attr));
404 dev_array = realloc(dev_array,
405 size * 2 *
sizeof(
char *));
410 memset(&dev_array[len], 0,
411 (size - len) *
sizeof(
char *));
415 c->dev_array = dev_array;
416 c->dev_array_len = len;
421 xfree(dev_array[len]);
425 static int nftnl_flowtable_parse_hook(
struct nlattr *attr,
struct nftnl_flowtable *c)
427 struct nlattr *tb[NFTA_FLOWTABLE_HOOK_MAX + 1] = {};
430 if (mnl_attr_parse_nested(attr, nftnl_flowtable_parse_hook_cb, tb) < 0)
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);
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);
441 if (tb[NFTA_FLOWTABLE_HOOK_DEVS]) {
442 ret = nftnl_flowtable_parse_devs(tb[NFTA_FLOWTABLE_HOOK_DEVS], c);
445 c->flags |= (1 << NFTNL_FLOWTABLE_DEVICES);
451 EXPORT_SYMBOL(nftnl_flowtable_nlmsg_parse);
452 int nftnl_flowtable_nlmsg_parse(
const struct nlmsghdr *nlh,
struct nftnl_flowtable *c)
454 struct nlattr *tb[NFTA_FLOWTABLE_MAX + 1] = {};
455 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
458 if (mnl_attr_parse(nlh,
sizeof(*nfg), nftnl_flowtable_parse_attr_cb, tb) < 0)
461 if (tb[NFTA_FLOWTABLE_NAME]) {
462 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
464 c->name = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_NAME]));
467 c->flags |= (1 << NFTNL_FLOWTABLE_NAME);
469 if (tb[NFTA_FLOWTABLE_TABLE]) {
470 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
472 c->table = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_TABLE]));
475 c->flags |= (1 << NFTNL_FLOWTABLE_TABLE);
477 if (tb[NFTA_FLOWTABLE_HOOK]) {
478 ret = nftnl_flowtable_parse_hook(tb[NFTA_FLOWTABLE_HOOK], c);
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);
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);
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);
495 c->family = nfg->nfgen_family;
496 c->flags |= (1 << NFTNL_FLOWTABLE_FAMILY);
501 static const char *nftnl_hooknum2str(
int family,
int hooknum)
509 case NF_INET_PRE_ROUTING:
511 case NF_INET_LOCAL_IN:
513 case NF_INET_FORWARD:
515 case NF_INET_LOCAL_OUT:
517 case NF_INET_POST_ROUTING:
518 return "postrouting";
533 case NF_NETDEV_INGRESS:
541 static inline int nftnl_str2hooknum(
int family,
const char *hook)
545 for (hooknum = 0; hooknum < NF_INET_NUMHOOKS; hooknum++) {
546 if (strcmp(hook, nftnl_hooknum2str(family, hooknum)) == 0)
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)
560 EXPORT_SYMBOL(nftnl_flowtable_parse_file);
562 enum nftnl_parse_type type,
563 FILE *fp,
struct nftnl_parse_err *err)
569 static int nftnl_flowtable_snprintf_default(
char *buf,
size_t size,
572 int ret, remain = size, offset = 0, i;
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);
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),
582 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
584 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
585 ret = snprintf(buf + offset, remain,
" dev { ");
586 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
588 for (i = 0; i < c->dev_array_len; i++) {
589 ret = snprintf(buf + offset, remain,
" %s ",
591 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
593 ret = snprintf(buf + offset, remain,
" } ");
594 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
601 static int nftnl_flowtable_cmd_snprintf(
char *buf,
size_t size,
603 uint32_t cmd, uint32_t type,
606 int ret, remain = size, offset = 0;
609 case NFTNL_OUTPUT_DEFAULT:
610 ret = nftnl_flowtable_snprintf_default(buf + offset, remain, c);
611 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
613 case NFTNL_OUTPUT_XML:
614 case NFTNL_OUTPUT_JSON:
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)
630 return nftnl_flowtable_cmd_snprintf(buf, size, c, nftnl_flag2cmd(flags),
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)
637 return nftnl_flowtable_snprintf(buf, size, c, type, flags);
640 EXPORT_SYMBOL(nftnl_flowtable_fprintf);
642 uint32_t type, uint32_t flags)
644 return nftnl_fprintf(fp, c, NFTNL_CMD_UNSPEC, type, flags,
645 nftnl_flowtable_do_snprintf);
649 struct list_head list;
652 EXPORT_SYMBOL(nftnl_flowtable_list_alloc);
661 INIT_LIST_HEAD(&list->list);
666 EXPORT_SYMBOL(nftnl_flowtable_list_free);
671 list_for_each_entry_safe(s, tmp, &list->list, head) {
673 nftnl_flowtable_free(s);
678 EXPORT_SYMBOL(nftnl_flowtable_list_is_empty);
681 return list_empty(&list->list);
684 EXPORT_SYMBOL(nftnl_flowtable_list_add);
688 list_add(&s->head, &list->list);
691 EXPORT_SYMBOL(nftnl_flowtable_list_add_tail);
695 list_add_tail(&s->head, &list->list);
698 EXPORT_SYMBOL(nftnl_flowtable_list_del);
704 EXPORT_SYMBOL(nftnl_flowtable_list_foreach);
711 list_for_each_entry_safe(cur, tmp, &flowtable_list->list, head) {