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;
41 EXPORT_SYMBOL(nftnl_flowtable_alloc);
47 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
49 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
51 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
52 for (i = 0; i < c->dev_array_len; i++)
53 xfree(c->dev_array[i]);
59 EXPORT_SYMBOL(nftnl_flowtable_free);
61 bool nftnl_flowtable_is_set(
const struct nftnl_flowtable *c, uint16_t attr)
63 return c->flags & (1 << attr);
65 EXPORT_SYMBOL(nftnl_flowtable_is_set);
71 if (!(c->flags & (1 << attr)))
75 case NFTNL_FLOWTABLE_NAME:
78 case NFTNL_FLOWTABLE_TABLE:
81 case NFTNL_FLOWTABLE_HOOKNUM:
82 case NFTNL_FLOWTABLE_PRIO:
83 case NFTNL_FLOWTABLE_USE:
84 case NFTNL_FLOWTABLE_FAMILY:
85 case NFTNL_FLOWTABLE_FLAGS:
87 case NFTNL_FLOWTABLE_DEVICES:
88 for (i = 0; i < c->dev_array_len; i++) {
89 xfree(c->dev_array[i]);
97 c->flags &= ~(1 << attr);
99 EXPORT_SYMBOL(nftnl_flowtable_unset);
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_FLAGS] =
sizeof(uint32_t),
109 const void *data, uint32_t data_len)
111 const char **dev_array;
114 nftnl_assert_attr_exists(attr, NFTNL_FLOWTABLE_MAX);
115 nftnl_assert_validate(data, nftnl_flowtable_validate, attr, data_len);
118 case NFTNL_FLOWTABLE_NAME:
119 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
122 c->name = strdup(data);
126 case NFTNL_FLOWTABLE_TABLE:
127 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
130 c->table = strdup(data);
134 case NFTNL_FLOWTABLE_HOOKNUM:
135 memcpy(&c->hooknum, data,
sizeof(c->hooknum));
137 case NFTNL_FLOWTABLE_PRIO:
138 memcpy(&c->prio, data,
sizeof(c->prio));
140 case NFTNL_FLOWTABLE_FAMILY:
141 memcpy(&c->family, data,
sizeof(c->family));
143 case NFTNL_FLOWTABLE_DEVICES:
144 dev_array = (
const char **)data;
145 while (dev_array[len] != NULL)
148 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
149 for (i = 0; i < c->dev_array_len; i++) {
150 xfree(c->dev_array[i]);
155 c->dev_array = calloc(len + 1,
sizeof(
char *));
159 for (i = 0; i < len; i++)
160 c->dev_array[i] = strdup(dev_array[i]);
162 c->dev_array_len = len;
164 case NFTNL_FLOWTABLE_SIZE:
165 memcpy(&c->size, data,
sizeof(c->size));
166 case NFTNL_FLOWTABLE_FLAGS:
167 memcpy(&c->ft_flags, data,
sizeof(c->ft_flags));
170 c->flags |= (1 << attr);
173 EXPORT_SYMBOL(nftnl_flowtable_set_data);
175 void nftnl_flowtable_set(
struct nftnl_flowtable *c, uint16_t attr,
const void *data)
177 nftnl_flowtable_set_data(c, attr, data, nftnl_flowtable_validate[attr]);
179 EXPORT_SYMBOL(nftnl_flowtable_set);
181 void nftnl_flowtable_set_u32(
struct nftnl_flowtable *c, uint16_t attr, uint32_t data)
183 nftnl_flowtable_set_data(c, attr, &data,
sizeof(uint32_t));
185 EXPORT_SYMBOL(nftnl_flowtable_set_u32);
187 void nftnl_flowtable_set_s32(
struct nftnl_flowtable *c, uint16_t attr, int32_t data)
189 nftnl_flowtable_set_data(c, attr, &data,
sizeof(int32_t));
191 EXPORT_SYMBOL(nftnl_flowtable_set_s32);
193 int nftnl_flowtable_set_str(
struct nftnl_flowtable *c, uint16_t attr,
const char *str)
195 return nftnl_flowtable_set_data(c, attr, str, strlen(str) + 1);
197 EXPORT_SYMBOL(nftnl_flowtable_set_str);
200 uint16_t attr, uint32_t *data_len)
202 if (!(c->flags & (1 << attr)))
206 case NFTNL_FLOWTABLE_NAME:
207 *data_len = strlen(c->name) + 1;
209 case NFTNL_FLOWTABLE_TABLE:
210 *data_len = strlen(c->table) + 1;
212 case NFTNL_FLOWTABLE_HOOKNUM:
213 *data_len =
sizeof(uint32_t);
215 case NFTNL_FLOWTABLE_PRIO:
216 *data_len =
sizeof(int32_t);
218 case NFTNL_FLOWTABLE_FAMILY:
219 *data_len =
sizeof(int32_t);
221 case NFTNL_FLOWTABLE_DEVICES:
222 return &c->dev_array[0];
223 case NFTNL_FLOWTABLE_SIZE:
224 *data_len =
sizeof(int32_t);
226 case NFTNL_FLOWTABLE_FLAGS:
227 *data_len =
sizeof(int32_t);
232 EXPORT_SYMBOL(nftnl_flowtable_get_data);
234 const void *nftnl_flowtable_get(
const struct nftnl_flowtable *c, uint16_t attr)
237 return nftnl_flowtable_get_data(c, attr, &data_len);
239 EXPORT_SYMBOL(nftnl_flowtable_get);
241 const char *nftnl_flowtable_get_str(
const struct nftnl_flowtable *c, uint16_t attr)
243 return nftnl_flowtable_get(c, attr);
245 EXPORT_SYMBOL(nftnl_flowtable_get_str);
247 uint32_t nftnl_flowtable_get_u32(
const struct nftnl_flowtable *c, uint16_t attr)
250 const uint32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
252 nftnl_assert(val, attr, data_len ==
sizeof(uint32_t));
254 return val ? *val : 0;
256 EXPORT_SYMBOL(nftnl_flowtable_get_u32);
258 int32_t nftnl_flowtable_get_s32(
const struct nftnl_flowtable *c, uint16_t attr)
261 const int32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
263 nftnl_assert(val, attr, data_len ==
sizeof(int32_t));
265 return val ? *val : 0;
267 EXPORT_SYMBOL(nftnl_flowtable_get_s32);
269 void nftnl_flowtable_nlmsg_build_payload(
struct nlmsghdr *nlh,
274 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
275 mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, c->table);
276 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
277 mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME, c->name);
278 if ((c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM)) &&
279 (c->flags & (1 << NFTNL_FLOWTABLE_PRIO))) {
282 nest = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK);
283 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_NUM, htonl(c->hooknum));
284 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_PRIORITY, htonl(c->prio));
285 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
286 struct nlattr *nest_dev;
288 nest_dev = mnl_attr_nest_start(nlh,
289 NFTA_FLOWTABLE_HOOK_DEVS);
290 for (i = 0; i < c->dev_array_len; i++)
291 mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME,
293 mnl_attr_nest_end(nlh, nest_dev);
295 mnl_attr_nest_end(nlh, nest);
297 if (c->flags & (1 << NFTNL_FLOWTABLE_FLAGS))
298 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_FLAGS, htonl(c->ft_flags));
299 if (c->flags & (1 << NFTNL_FLOWTABLE_USE))
300 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_USE, htonl(c->use));
301 if (c->flags & (1 << NFTNL_FLOWTABLE_SIZE))
302 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_SIZE, htonl(c->size));
304 EXPORT_SYMBOL(nftnl_flowtable_nlmsg_build_payload);
306 static int nftnl_flowtable_parse_attr_cb(
const struct nlattr *attr,
void *data)
308 const struct nlattr **tb = data;
309 int type = mnl_attr_get_type(attr);
311 if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_MAX) < 0)
315 case NFTA_FLOWTABLE_NAME:
316 case NFTA_FLOWTABLE_TABLE:
317 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
320 case NFTA_FLOWTABLE_HOOK:
321 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
324 case NFTA_FLOWTABLE_FLAGS:
325 case NFTA_FLOWTABLE_USE:
326 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
335 static int nftnl_flowtable_parse_hook_cb(
const struct nlattr *attr,
void *data)
337 const struct nlattr **tb = data;
338 int type = mnl_attr_get_type(attr);
340 if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_HOOK_MAX) < 0)
344 case NFTA_FLOWTABLE_HOOK_NUM:
345 case NFTA_FLOWTABLE_HOOK_PRIORITY:
346 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
349 case NFTA_FLOWTABLE_HOOK_DEVS:
350 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
359 static int nftnl_flowtable_parse_devs(
struct nlattr *nest,
366 mnl_attr_for_each_nested(attr, nest) {
367 if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
369 dev_array[len++] = strdup(mnl_attr_get_str(attr));
377 c->dev_array = calloc(len + 1,
sizeof(
char *));
381 c->dev_array_len = len;
383 for (i = 0; i < len; i++)
384 c->dev_array[i] = strdup(dev_array[i]);
389 static int nftnl_flowtable_parse_hook(
struct nlattr *attr,
struct nftnl_flowtable *c)
391 struct nlattr *tb[NFTA_FLOWTABLE_HOOK_MAX + 1] = {};
394 if (mnl_attr_parse_nested(attr, nftnl_flowtable_parse_hook_cb, tb) < 0)
397 if (tb[NFTA_FLOWTABLE_HOOK_NUM]) {
398 c->hooknum = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_HOOK_NUM]));
399 c->flags |= (1 << NFTNL_FLOWTABLE_HOOKNUM);
401 if (tb[NFTA_FLOWTABLE_HOOK_PRIORITY]) {
402 c->prio = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_HOOK_PRIORITY]));
403 c->flags |= (1 << NFTNL_FLOWTABLE_PRIO);
405 if (tb[NFTA_FLOWTABLE_HOOK_DEVS]) {
406 ret = nftnl_flowtable_parse_devs(tb[NFTA_FLOWTABLE_HOOK_DEVS], c);
409 c->flags |= (1 << NFTNL_FLOWTABLE_DEVICES);
415 int nftnl_flowtable_nlmsg_parse(
const struct nlmsghdr *nlh,
struct nftnl_flowtable *c)
417 struct nlattr *tb[NFTA_FLOWTABLE_MAX + 1] = {};
418 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
421 if (mnl_attr_parse(nlh,
sizeof(*nfg), nftnl_flowtable_parse_attr_cb, tb) < 0)
424 if (tb[NFTA_FLOWTABLE_NAME]) {
425 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
427 c->name = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_NAME]));
430 c->flags |= (1 << NFTNL_FLOWTABLE_NAME);
432 if (tb[NFTA_FLOWTABLE_TABLE]) {
433 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
435 c->table = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_TABLE]));
438 c->flags |= (1 << NFTNL_FLOWTABLE_TABLE);
440 if (tb[NFTA_FLOWTABLE_HOOK]) {
441 ret = nftnl_flowtable_parse_hook(tb[NFTA_FLOWTABLE_HOOK], c);
445 if (tb[NFTA_FLOWTABLE_FLAGS]) {
446 c->ft_flags = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_FLAGS]));
447 c->flags |= (1 << NFTNL_FLOWTABLE_FLAGS);
449 if (tb[NFTA_FLOWTABLE_USE]) {
450 c->use = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_USE]));
451 c->flags |= (1 << NFTNL_FLOWTABLE_USE);
453 if (tb[NFTA_FLOWTABLE_SIZE]) {
454 c->size = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_SIZE]));
455 c->flags |= (1 << NFTNL_FLOWTABLE_SIZE);
458 c->family = nfg->nfgen_family;
459 c->flags |= (1 << NFTNL_FLOWTABLE_FAMILY);
463 EXPORT_SYMBOL(nftnl_flowtable_nlmsg_parse);
465 static const char *nftnl_hooknum2str(
int family,
int hooknum)
473 case NF_INET_PRE_ROUTING:
475 case NF_INET_LOCAL_IN:
477 case NF_INET_FORWARD:
479 case NF_INET_LOCAL_OUT:
481 case NF_INET_POST_ROUTING:
482 return "postrouting";
497 case NF_NETDEV_INGRESS:
505 static inline int nftnl_str2hooknum(
int family,
const char *hook)
509 for (hooknum = 0; hooknum < NF_INET_NUMHOOKS; hooknum++) {
510 if (strcmp(hook, nftnl_hooknum2str(family, hooknum)) == 0)
516 int nftnl_flowtable_parse(
struct nftnl_flowtable *c,
enum nftnl_parse_type type,
517 const char *data,
struct nftnl_parse_err *err)
522 EXPORT_SYMBOL(nftnl_flowtable_parse);
525 enum nftnl_parse_type type,
526 FILE *fp,
struct nftnl_parse_err *err)
531 EXPORT_SYMBOL(nftnl_flowtable_parse_file);
533 static int nftnl_flowtable_snprintf_default(
char *buf,
size_t size,
536 int ret, remain = size, offset = 0, i;
538 ret = snprintf(buf, remain,
"flow table %s %s use %u size %u flags %x",
539 c->table, c->name, c->use, c->size, c->ft_flags);
540 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
542 if (c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM)) {
543 ret = snprintf(buf + offset, remain,
" hook %s prio %d ",
544 nftnl_hooknum2str(c->family, c->hooknum),
546 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
548 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
549 ret = snprintf(buf + offset, remain,
" dev { ");
550 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
552 for (i = 0; i < c->dev_array_len; i++) {
553 ret = snprintf(buf + offset, remain,
" %s ",
555 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
557 ret = snprintf(buf + offset, remain,
" } ");
558 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
565 static int nftnl_flowtable_cmd_snprintf(
char *buf,
size_t size,
567 uint32_t cmd, uint32_t type,
570 int ret, remain = size, offset = 0;
573 case NFTNL_OUTPUT_DEFAULT:
574 ret = nftnl_flowtable_snprintf_default(buf + offset, remain, c);
575 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
577 case NFTNL_OUTPUT_XML:
578 case NFTNL_OUTPUT_JSON:
587 int nftnl_flowtable_snprintf(
char *buf,
size_t size,
const struct nftnl_flowtable *c,
588 uint32_t type, uint32_t flags)
593 return nftnl_flowtable_cmd_snprintf(buf, size, c, nftnl_flag2cmd(flags),
596 EXPORT_SYMBOL(nftnl_flowtable_snprintf);
598 static int nftnl_flowtable_do_snprintf(
char *buf,
size_t size,
const void *c,
599 uint32_t cmd, uint32_t type, uint32_t flags)
601 return nftnl_flowtable_snprintf(buf, size, c, type, flags);
605 uint32_t type, uint32_t flags)
607 return nftnl_fprintf(fp, c, NFTNL_CMD_UNSPEC, type, flags,
608 nftnl_flowtable_do_snprintf);
610 EXPORT_SYMBOL(nftnl_flowtable_fprintf);
613 struct list_head list;
624 INIT_LIST_HEAD(&list->list);
628 EXPORT_SYMBOL(nftnl_flowtable_list_alloc);
634 list_for_each_entry_safe(s, tmp, &list->list, head) {
636 nftnl_flowtable_free(s);
640 EXPORT_SYMBOL(nftnl_flowtable_list_free);
644 return list_empty(&list->list);
646 EXPORT_SYMBOL(nftnl_flowtable_list_is_empty);
651 list_add(&s->head, &list->list);
653 EXPORT_SYMBOL(nftnl_flowtable_list_add);
658 list_add_tail(&s->head, &list->list);
660 EXPORT_SYMBOL(nftnl_flowtable_list_add_tail);
666 EXPORT_SYMBOL(nftnl_flowtable_list_del);
674 list_for_each_entry_safe(cur, tmp, &flowtable_list->list, head) {
681 EXPORT_SYMBOL(nftnl_flowtable_list_foreach);