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]);
96 c->flags &= ~(1 << attr);
98 EXPORT_SYMBOL(nftnl_flowtable_unset);
100 static uint32_t nftnl_flowtable_validate[NFTNL_FLOWTABLE_MAX + 1] = {
101 [NFTNL_FLOWTABLE_HOOKNUM] =
sizeof(uint32_t),
102 [NFTNL_FLOWTABLE_PRIO] =
sizeof(int32_t),
103 [NFTNL_FLOWTABLE_FAMILY] =
sizeof(uint32_t),
104 [NFTNL_FLOWTABLE_FLAGS] =
sizeof(uint32_t),
108 const void *data, uint32_t data_len)
110 const char **dev_array;
113 nftnl_assert_attr_exists(attr, NFTNL_FLOWTABLE_MAX);
114 nftnl_assert_validate(data, nftnl_flowtable_validate, attr, data_len);
117 case NFTNL_FLOWTABLE_NAME:
118 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
121 c->name = strdup(data);
125 case NFTNL_FLOWTABLE_TABLE:
126 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
129 c->table = strdup(data);
133 case NFTNL_FLOWTABLE_HOOKNUM:
134 memcpy(&c->hooknum, data,
sizeof(c->hooknum));
136 case NFTNL_FLOWTABLE_PRIO:
137 memcpy(&c->prio, data,
sizeof(c->prio));
139 case NFTNL_FLOWTABLE_FAMILY:
140 memcpy(&c->family, data,
sizeof(c->family));
142 case NFTNL_FLOWTABLE_DEVICES:
143 dev_array = (
const char **)data;
144 while (dev_array[len] != NULL)
147 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
148 for (i = 0; i < c->dev_array_len; i++)
149 xfree(c->dev_array[i]);
153 c->dev_array = calloc(len + 1,
sizeof(
char *));
157 for (i = 0; i < len; i++)
158 c->dev_array[i] = strdup(dev_array[i]);
160 c->dev_array_len = len;
162 case NFTNL_FLOWTABLE_SIZE:
163 memcpy(&c->size, data,
sizeof(c->size));
165 case NFTNL_FLOWTABLE_FLAGS:
166 memcpy(&c->ft_flags, data,
sizeof(c->ft_flags));
169 c->flags |= (1 << attr);
172 EXPORT_SYMBOL(nftnl_flowtable_set_data);
174 void nftnl_flowtable_set(
struct nftnl_flowtable *c, uint16_t attr,
const void *data)
176 nftnl_flowtable_set_data(c, attr, data, nftnl_flowtable_validate[attr]);
178 EXPORT_SYMBOL(nftnl_flowtable_set);
180 void nftnl_flowtable_set_u32(
struct nftnl_flowtable *c, uint16_t attr, uint32_t data)
182 nftnl_flowtable_set_data(c, attr, &data,
sizeof(uint32_t));
184 EXPORT_SYMBOL(nftnl_flowtable_set_u32);
186 void nftnl_flowtable_set_s32(
struct nftnl_flowtable *c, uint16_t attr, int32_t data)
188 nftnl_flowtable_set_data(c, attr, &data,
sizeof(int32_t));
190 EXPORT_SYMBOL(nftnl_flowtable_set_s32);
192 int nftnl_flowtable_set_str(
struct nftnl_flowtable *c, uint16_t attr,
const char *str)
194 return nftnl_flowtable_set_data(c, attr, str, strlen(str) + 1);
196 EXPORT_SYMBOL(nftnl_flowtable_set_str);
199 uint16_t attr, uint32_t *data_len)
201 if (!(c->flags & (1 << attr)))
205 case NFTNL_FLOWTABLE_NAME:
206 *data_len = strlen(c->name) + 1;
208 case NFTNL_FLOWTABLE_TABLE:
209 *data_len = strlen(c->table) + 1;
211 case NFTNL_FLOWTABLE_HOOKNUM:
212 *data_len =
sizeof(uint32_t);
214 case NFTNL_FLOWTABLE_PRIO:
215 *data_len =
sizeof(int32_t);
217 case NFTNL_FLOWTABLE_FAMILY:
218 *data_len =
sizeof(int32_t);
220 case NFTNL_FLOWTABLE_DEVICES:
221 return &c->dev_array[0];
222 case NFTNL_FLOWTABLE_SIZE:
223 *data_len =
sizeof(int32_t);
225 case NFTNL_FLOWTABLE_FLAGS:
226 *data_len =
sizeof(int32_t);
231 EXPORT_SYMBOL(nftnl_flowtable_get_data);
233 const void *nftnl_flowtable_get(
const struct nftnl_flowtable *c, uint16_t attr)
236 return nftnl_flowtable_get_data(c, attr, &data_len);
238 EXPORT_SYMBOL(nftnl_flowtable_get);
240 const char *nftnl_flowtable_get_str(
const struct nftnl_flowtable *c, uint16_t attr)
242 return nftnl_flowtable_get(c, attr);
244 EXPORT_SYMBOL(nftnl_flowtable_get_str);
246 uint32_t nftnl_flowtable_get_u32(
const struct nftnl_flowtable *c, uint16_t attr)
248 uint32_t data_len = 0;
249 const uint32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
251 nftnl_assert(val, attr, data_len ==
sizeof(uint32_t));
253 return val ? *val : 0;
255 EXPORT_SYMBOL(nftnl_flowtable_get_u32);
257 int32_t nftnl_flowtable_get_s32(
const struct nftnl_flowtable *c, uint16_t attr)
259 uint32_t data_len = 0;
260 const int32_t *val = nftnl_flowtable_get_data(c, attr, &data_len);
262 nftnl_assert(val, attr, data_len ==
sizeof(int32_t));
264 return val ? *val : 0;
266 EXPORT_SYMBOL(nftnl_flowtable_get_s32);
268 void nftnl_flowtable_nlmsg_build_payload(
struct nlmsghdr *nlh,
273 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
274 mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, c->table);
275 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
276 mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME, c->name);
277 if ((c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM)) &&
278 (c->flags & (1 << NFTNL_FLOWTABLE_PRIO))) {
281 nest = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK);
282 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_NUM, htonl(c->hooknum));
283 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_PRIORITY, htonl(c->prio));
284 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
285 struct nlattr *nest_dev;
287 nest_dev = mnl_attr_nest_start(nlh,
288 NFTA_FLOWTABLE_HOOK_DEVS);
289 for (i = 0; i < c->dev_array_len; i++)
290 mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME,
292 mnl_attr_nest_end(nlh, nest_dev);
294 mnl_attr_nest_end(nlh, nest);
296 if (c->flags & (1 << NFTNL_FLOWTABLE_FLAGS))
297 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_FLAGS, htonl(c->ft_flags));
298 if (c->flags & (1 << NFTNL_FLOWTABLE_USE))
299 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_USE, htonl(c->use));
300 if (c->flags & (1 << NFTNL_FLOWTABLE_SIZE))
301 mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_SIZE, htonl(c->size));
303 EXPORT_SYMBOL(nftnl_flowtable_nlmsg_build_payload);
305 static int nftnl_flowtable_parse_attr_cb(
const struct nlattr *attr,
void *data)
307 const struct nlattr **tb = data;
308 int type = mnl_attr_get_type(attr);
310 if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_MAX) < 0)
314 case NFTA_FLOWTABLE_NAME:
315 case NFTA_FLOWTABLE_TABLE:
316 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
319 case NFTA_FLOWTABLE_HOOK:
320 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
323 case NFTA_FLOWTABLE_FLAGS:
324 case NFTA_FLOWTABLE_USE:
325 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
334 static int nftnl_flowtable_parse_hook_cb(
const struct nlattr *attr,
void *data)
336 const struct nlattr **tb = data;
337 int type = mnl_attr_get_type(attr);
339 if (mnl_attr_type_valid(attr, NFTA_FLOWTABLE_HOOK_MAX) < 0)
343 case NFTA_FLOWTABLE_HOOK_NUM:
344 case NFTA_FLOWTABLE_HOOK_PRIORITY:
345 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
348 case NFTA_FLOWTABLE_HOOK_DEVS:
349 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
358 static int nftnl_flowtable_parse_devs(
struct nlattr *nest,
365 mnl_attr_for_each_nested(attr, nest) {
366 if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
368 dev_array[len++] = strdup(mnl_attr_get_str(attr));
376 c->dev_array = calloc(len + 1,
sizeof(
char *));
380 c->dev_array_len = len;
382 for (i = 0; i < len; i++)
383 c->dev_array[i] = dev_array[i];
388 xfree(dev_array[len]);
392 static int nftnl_flowtable_parse_hook(
struct nlattr *attr,
struct nftnl_flowtable *c)
394 struct nlattr *tb[NFTA_FLOWTABLE_HOOK_MAX + 1] = {};
397 if (mnl_attr_parse_nested(attr, nftnl_flowtable_parse_hook_cb, tb) < 0)
400 if (tb[NFTA_FLOWTABLE_HOOK_NUM]) {
401 c->hooknum = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_HOOK_NUM]));
402 c->flags |= (1 << NFTNL_FLOWTABLE_HOOKNUM);
404 if (tb[NFTA_FLOWTABLE_HOOK_PRIORITY]) {
405 c->prio = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_HOOK_PRIORITY]));
406 c->flags |= (1 << NFTNL_FLOWTABLE_PRIO);
408 if (tb[NFTA_FLOWTABLE_HOOK_DEVS]) {
409 ret = nftnl_flowtable_parse_devs(tb[NFTA_FLOWTABLE_HOOK_DEVS], c);
412 c->flags |= (1 << NFTNL_FLOWTABLE_DEVICES);
418 int nftnl_flowtable_nlmsg_parse(
const struct nlmsghdr *nlh,
struct nftnl_flowtable *c)
420 struct nlattr *tb[NFTA_FLOWTABLE_MAX + 1] = {};
421 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
424 if (mnl_attr_parse(nlh,
sizeof(*nfg), nftnl_flowtable_parse_attr_cb, tb) < 0)
427 if (tb[NFTA_FLOWTABLE_NAME]) {
428 if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
430 c->name = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_NAME]));
433 c->flags |= (1 << NFTNL_FLOWTABLE_NAME);
435 if (tb[NFTA_FLOWTABLE_TABLE]) {
436 if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
438 c->table = strdup(mnl_attr_get_str(tb[NFTA_FLOWTABLE_TABLE]));
441 c->flags |= (1 << NFTNL_FLOWTABLE_TABLE);
443 if (tb[NFTA_FLOWTABLE_HOOK]) {
444 ret = nftnl_flowtable_parse_hook(tb[NFTA_FLOWTABLE_HOOK], c);
448 if (tb[NFTA_FLOWTABLE_FLAGS]) {
449 c->ft_flags = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_FLAGS]));
450 c->flags |= (1 << NFTNL_FLOWTABLE_FLAGS);
452 if (tb[NFTA_FLOWTABLE_USE]) {
453 c->use = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_USE]));
454 c->flags |= (1 << NFTNL_FLOWTABLE_USE);
456 if (tb[NFTA_FLOWTABLE_SIZE]) {
457 c->size = ntohl(mnl_attr_get_u32(tb[NFTA_FLOWTABLE_SIZE]));
458 c->flags |= (1 << NFTNL_FLOWTABLE_SIZE);
461 c->family = nfg->nfgen_family;
462 c->flags |= (1 << NFTNL_FLOWTABLE_FAMILY);
466 EXPORT_SYMBOL(nftnl_flowtable_nlmsg_parse);
468 static const char *nftnl_hooknum2str(
int family,
int hooknum)
476 case NF_INET_PRE_ROUTING:
478 case NF_INET_LOCAL_IN:
480 case NF_INET_FORWARD:
482 case NF_INET_LOCAL_OUT:
484 case NF_INET_POST_ROUTING:
485 return "postrouting";
500 case NF_NETDEV_INGRESS:
508 static inline int nftnl_str2hooknum(
int family,
const char *hook)
512 for (hooknum = 0; hooknum < NF_INET_NUMHOOKS; hooknum++) {
513 if (strcmp(hook, nftnl_hooknum2str(family, hooknum)) == 0)
519 int nftnl_flowtable_parse(
struct nftnl_flowtable *c,
enum nftnl_parse_type type,
520 const char *data,
struct nftnl_parse_err *err)
525 EXPORT_SYMBOL(nftnl_flowtable_parse);
528 enum nftnl_parse_type type,
529 FILE *fp,
struct nftnl_parse_err *err)
534 EXPORT_SYMBOL(nftnl_flowtable_parse_file);
536 static int nftnl_flowtable_snprintf_default(
char *buf,
size_t size,
539 int ret, remain = size, offset = 0, i;
541 ret = snprintf(buf, remain,
"flow table %s %s use %u size %u flags %x",
542 c->table, c->name, c->use, c->size, c->ft_flags);
543 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
545 if (c->flags & (1 << NFTNL_FLOWTABLE_HOOKNUM)) {
546 ret = snprintf(buf + offset, remain,
" hook %s prio %d ",
547 nftnl_hooknum2str(c->family, c->hooknum),
549 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
551 if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
552 ret = snprintf(buf + offset, remain,
" dev { ");
553 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
555 for (i = 0; i < c->dev_array_len; i++) {
556 ret = snprintf(buf + offset, remain,
" %s ",
558 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
560 ret = snprintf(buf + offset, remain,
" } ");
561 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
568 static int nftnl_flowtable_cmd_snprintf(
char *buf,
size_t size,
570 uint32_t cmd, uint32_t type,
573 int ret, remain = size, offset = 0;
576 case NFTNL_OUTPUT_DEFAULT:
577 ret = nftnl_flowtable_snprintf_default(buf + offset, remain, c);
578 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
580 case NFTNL_OUTPUT_XML:
581 case NFTNL_OUTPUT_JSON:
590 int nftnl_flowtable_snprintf(
char *buf,
size_t size,
const struct nftnl_flowtable *c,
591 uint32_t type, uint32_t flags)
596 return nftnl_flowtable_cmd_snprintf(buf, size, c, nftnl_flag2cmd(flags),
599 EXPORT_SYMBOL(nftnl_flowtable_snprintf);
601 static int nftnl_flowtable_do_snprintf(
char *buf,
size_t size,
const void *c,
602 uint32_t cmd, uint32_t type, uint32_t flags)
604 return nftnl_flowtable_snprintf(buf, size, c, type, flags);
608 uint32_t type, uint32_t flags)
610 return nftnl_fprintf(fp, c, NFTNL_CMD_UNSPEC, type, flags,
611 nftnl_flowtable_do_snprintf);
613 EXPORT_SYMBOL(nftnl_flowtable_fprintf);
616 struct list_head list;
627 INIT_LIST_HEAD(&list->list);
631 EXPORT_SYMBOL(nftnl_flowtable_list_alloc);
637 list_for_each_entry_safe(s, tmp, &list->list, head) {
639 nftnl_flowtable_free(s);
643 EXPORT_SYMBOL(nftnl_flowtable_list_free);
647 return list_empty(&list->list);
649 EXPORT_SYMBOL(nftnl_flowtable_list_is_empty);
654 list_add(&s->head, &list->list);
656 EXPORT_SYMBOL(nftnl_flowtable_list_add);
661 list_add_tail(&s->head, &list->list);
663 EXPORT_SYMBOL(nftnl_flowtable_list_add_tail);
669 EXPORT_SYMBOL(nftnl_flowtable_list_del);
677 list_for_each_entry_safe(cur, tmp, &flowtable_list->list, head) {
684 EXPORT_SYMBOL(nftnl_flowtable_list_foreach);