summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/chain.c1
-rw-r--r--src/expr/ct.c95
-rw-r--r--src/expr/meta.c147
-rw-r--r--src/expr/queue.c254
-rw-r--r--src/table.c35
-rw-r--r--src/utils.c4
6 files changed, 487 insertions, 49 deletions
diff --git a/src/chain.c b/src/chain.c
index e26200d..2cc7c61 100644
--- a/src/chain.c
+++ b/src/chain.c
@@ -50,6 +50,7 @@ static const char *nft_hooknum2str(int family, int hooknum)
switch (family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
+ case NFPROTO_INET:
case NFPROTO_BRIDGE:
switch (hooknum) {
case NF_INET_PRE_ROUTING:
diff --git a/src/expr/ct.c b/src/expr/ct.c
index 051a1c5..2df761c 100644
--- a/src/expr/ct.c
+++ b/src/expr/ct.c
@@ -25,6 +25,7 @@
struct nft_expr_ct {
enum nft_ct_keys key;
enum nft_registers dreg;
+ enum nft_registers sreg;
uint8_t dir;
};
@@ -51,6 +52,9 @@ nft_rule_expr_ct_set(struct nft_rule_expr *e, uint16_t type,
case NFT_EXPR_CT_DREG:
ct->dreg = *((uint32_t *)data);
break;
+ case NFT_EXPR_CT_SREG:
+ ct->sreg = *((uint32_t *)data);
+ break;
default:
return -1;
}
@@ -73,6 +77,9 @@ nft_rule_expr_ct_get(const struct nft_rule_expr *e, uint16_t type,
case NFT_EXPR_CT_DREG:
*data_len = sizeof(ct->dreg);
return &ct->dreg;
+ case NFT_EXPR_CT_SREG:
+ *data_len = sizeof(ct->sreg);
+ return &ct->sreg;
}
return NULL;
}
@@ -88,6 +95,7 @@ static int nft_rule_expr_ct_cb(const struct nlattr *attr, void *data)
switch(type) {
case NFTA_CT_KEY:
case NFTA_CT_DREG:
+ case NFTA_CT_SREG:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
perror("mnl_attr_validate");
return MNL_CB_ERROR;
@@ -116,6 +124,8 @@ nft_rule_expr_ct_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
mnl_attr_put_u32(nlh, NFTA_CT_DREG, htonl(ct->dreg));
if (e->flags & (1 << NFT_EXPR_CT_DIR))
mnl_attr_put_u8(nlh, NFTA_CT_DIRECTION, ct->dir);
+ if (e->flags & (1 << NFT_EXPR_CT_SREG))
+ mnl_attr_put_u32(nlh, NFTA_CT_SREG, htonl(ct->sreg));
}
static int
@@ -135,6 +145,10 @@ nft_rule_expr_ct_parse(struct nft_rule_expr *e, struct nlattr *attr)
ct->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_CT_DREG]));
e->flags |= (1 << NFT_EXPR_CT_DREG);
}
+ if (tb[NFTA_CT_SREG]) {
+ ct->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_CT_SREG]));
+ e->flags |= (1 << NFT_EXPR_CT_SREG);
+ }
if (tb[NFTA_CT_DIRECTION]) {
ct->dir = mnl_attr_get_u8(tb[NFTA_CT_DIRECTION]);
e->flags |= (1 << NFT_EXPR_CT_DIR);
@@ -215,10 +229,19 @@ static int nft_rule_expr_ct_json_parse(struct nft_rule_expr *e, json_t *root,
uint8_t dir;
int key;
- if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg, err) < 0)
- return -1;
+ if (nft_jansson_node_exist(root, "dreg")) {
+ if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg, err) < 0)
+ return -1;
- nft_rule_expr_set_u32(e, NFT_EXPR_CT_DREG, reg);
+ nft_rule_expr_set_u32(e, NFT_EXPR_CT_DREG, reg);
+ }
+
+ if (nft_jansson_node_exist(root, "sreg")) {
+ if (nft_jansson_parse_reg(root, "sreg", NFT_TYPE_U32, &reg, err) < 0)
+ return -1;
+
+ nft_rule_expr_set_u32(e, NFT_EXPR_CT_SREG, reg);
+ }
if (nft_jansson_node_exist(root, "key")) {
key_str = nft_jansson_parse_str(root, "key", err);
@@ -269,11 +292,16 @@ static int nft_rule_expr_ct_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree
uint32_t reg;
if (nft_mxml_reg_parse(tree, "dreg", &reg, MXML_DESCEND_FIRST,
- NFT_XML_MAND, err) != 0)
- return -1;
+ NFT_XML_OPT, err) >= 0) {
+ ct->dreg = reg;
+ e->flags |= (1 << NFT_EXPR_CT_DREG);
+ }
- ct->dreg = reg;
- e->flags |= (1 << NFT_EXPR_CT_DREG);
+ if (nft_mxml_reg_parse(tree, "sreg", &reg, MXML_DESCEND_FIRST,
+ NFT_XML_OPT, err) >= 0) {
+ ct->sreg = reg;
+ e->flags |= (1 << NFT_EXPR_CT_SREG);
+ }
key_str = nft_mxml_str_parse(tree, "key", MXML_DESCEND_FIRST,
NFT_XML_MAND, err);
@@ -315,22 +343,32 @@ nft_expr_ct_snprintf_json(char *buf, size_t size, struct nft_rule_expr *e)
int ret, len = size, offset = 0;
struct nft_expr_ct *ct = nft_expr_data(e);
- ret = snprintf(buf, len, "\"dreg\":%u", ct->dreg);
- SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ if (e->flags & (1 << NFT_EXPR_CT_DREG)) {
+ ret = snprintf(buf+offset, len, "\"dreg\":%u,", ct->dreg);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ if (e->flags & (1 << NFT_EXPR_CT_SREG)) {
+ ret = snprintf(buf+offset, len, "\"sreg:\":%u,", ct->sreg);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
if (e->flags & (1 << NFT_EXPR_CT_KEY)) {
- ret = snprintf(buf+offset, len, ",\"key\":\"%s\"",
+ ret = snprintf(buf+offset, len, "\"key\":\"%s\",",
ctkey2str(ct->key));
SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
}
if (nft_rule_expr_is_set(e, NFT_EXPR_CT_DIR)) {
- ret = snprintf(buf+offset, len, ",\"dir\":\"%s\"",
+ ret = snprintf(buf+offset, len, "\"dir\":\"%s\",",
ctdir2str(ct->dir));
SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
}
- return offset;
+ /* Remove the last separator characther */
+ buf[offset-1] = '\0';
+
+ return offset-1;
}
static int
@@ -339,12 +377,21 @@ nft_expr_ct_snprintf_xml(char *buf, size_t size, struct nft_rule_expr *e)
int ret, len = size, offset = 0;
struct nft_expr_ct *ct = nft_expr_data(e);
- ret = snprintf(buf, len, "<dreg>%u</dreg>", ct->dreg);
- SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ if (e->flags & (1 << NFT_EXPR_CT_DREG)) {
+ ret = snprintf(buf+offset, len, "<dreg>%u</dreg>", ct->dreg);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ if (e->flags & (1 << NFT_EXPR_CT_SREG)) {
+ ret = snprintf(buf+offset, len, "<sreg>%u</sreg>", ct->sreg);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
- ret = snprintf(buf+offset, len, "<key>%s</key>",
- ctkey2str(ct->key));
- SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ if (e->flags & (1 << NFT_EXPR_CT_KEY)) {
+ ret = snprintf(buf+offset, len, "<key>%s</key>",
+ ctkey2str(ct->key));
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
if (nft_rule_expr_is_set(e, NFT_EXPR_CT_DIR)) {
ret = snprintf(buf+offset, len, "<dir>%s</dir>",
@@ -361,9 +408,17 @@ nft_expr_ct_snprintf_default(char *buf, size_t size, struct nft_rule_expr *e)
int ret, len = size, offset = 0;
struct nft_expr_ct *ct = nft_expr_data(e);
- ret = snprintf(buf, len, "load %s => reg %u ",
- ctkey2str(ct->key), ct->dreg);
- SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ if (e->flags & (1 << NFT_EXPR_CT_SREG)) {
+ ret = snprintf(buf, size, "set %s with reg %u ",
+ ctkey2str(ct->key), ct->sreg);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ if (e->flags & (1 << NFT_EXPR_CT_DREG)) {
+ ret = snprintf(buf, len, "load %s => reg %u ",
+ ctkey2str(ct->key), ct->dreg);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
if (nft_rule_expr_is_set(e, NFT_EXPR_CT_DIR)) {
ret = snprintf(buf+offset, len, ", dir %s ",
diff --git a/src/expr/meta.c b/src/expr/meta.c
index e2a198a..bee2f4c 100644
--- a/src/expr/meta.c
+++ b/src/expr/meta.c
@@ -23,12 +23,13 @@
#include "expr_ops.h"
#ifndef NFT_META_MAX
-#define NFT_META_MAX (NFT_META_SECMARK + 1)
+#define NFT_META_MAX (NFT_META_L4PROTO + 1)
#endif
struct nft_expr_meta {
enum nft_meta_keys key;
enum nft_registers dreg;
+ enum nft_registers sreg;
};
static int
@@ -44,6 +45,9 @@ nft_rule_expr_meta_set(struct nft_rule_expr *e, uint16_t type,
case NFT_EXPR_META_DREG:
meta->dreg = *((uint32_t *)data);
break;
+ case NFT_EXPR_META_SREG:
+ meta->sreg = *((uint32_t *)data);
+ break;
default:
return -1;
}
@@ -63,6 +67,9 @@ nft_rule_expr_meta_get(const struct nft_rule_expr *e, uint16_t type,
case NFT_EXPR_META_DREG:
*data_len = sizeof(meta->dreg);
return &meta->dreg;
+ case NFT_EXPR_META_SREG:
+ *data_len = sizeof(meta->sreg);
+ return &meta->sreg;
}
return NULL;
}
@@ -78,6 +85,7 @@ static int nft_rule_expr_meta_cb(const struct nlattr *attr, void *data)
switch(type) {
case NFTA_META_KEY:
case NFTA_META_DREG:
+ case NFTA_META_SREG:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
perror("mnl_attr_validate");
return MNL_CB_ERROR;
@@ -98,6 +106,8 @@ nft_rule_expr_meta_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
mnl_attr_put_u32(nlh, NFTA_META_KEY, htonl(meta->key));
if (e->flags & (1 << NFT_EXPR_META_DREG))
mnl_attr_put_u32(nlh, NFTA_META_DREG, htonl(meta->dreg));
+ if (e->flags & (1 << NFT_EXPR_META_SREG))
+ mnl_attr_put_u32(nlh, NFTA_META_SREG, htonl(meta->sreg));
}
static int
@@ -117,6 +127,10 @@ nft_rule_expr_meta_parse(struct nft_rule_expr *e, struct nlattr *attr)
meta->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_META_DREG]));
e->flags |= (1 << NFT_EXPR_META_DREG);
}
+ if (tb[NFTA_META_SREG]) {
+ meta->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_META_SREG]));
+ e->flags |= (1 << NFT_EXPR_META_SREG);
+ }
return 0;
}
@@ -124,6 +138,8 @@ nft_rule_expr_meta_parse(struct nft_rule_expr *e, struct nlattr *attr)
static const char *meta_key2str_array[NFT_META_MAX] = {
[NFT_META_LEN] = "len",
[NFT_META_PROTOCOL] = "protocol",
+ [NFT_META_NFPROTO] = "nfproto",
+ [NFT_META_L4PROTO] = "l4proto",
[NFT_META_PRIORITY] = "priority",
[NFT_META_MARK] = "mark",
[NFT_META_IIF] = "iif",
@@ -168,11 +184,6 @@ static int nft_rule_expr_meta_json_parse(struct nft_rule_expr *e, json_t *root,
uint32_t reg;
int key;
- if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg, err) < 0)
- return -1;
-
- nft_rule_expr_set_u32(e, NFT_EXPR_META_DREG, reg);
-
key_str = nft_jansson_parse_str(root, "key", err);
if (key_str == NULL)
return -1;
@@ -183,6 +194,22 @@ static int nft_rule_expr_meta_json_parse(struct nft_rule_expr *e, json_t *root,
nft_rule_expr_set_u32(e, NFT_EXPR_META_KEY, key);
+ if (nft_jansson_node_exist(root, "dreg")) {
+ if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg,
+ err) < 0)
+ return -1;
+
+ nft_rule_expr_set_u32(e, NFT_EXPR_META_DREG, reg);
+ }
+
+ if (nft_jansson_node_exist(root, "sreg")) {
+ if (nft_jansson_parse_reg(root, "sreg", NFT_TYPE_U32, &reg,
+ err) < 0)
+ return -1;
+
+ nft_rule_expr_set_u32(e, NFT_EXPR_META_SREG, reg);
+ }
+
return 0;
#else
errno = EOPNOTSUPP;
@@ -200,13 +227,6 @@ static int nft_rule_expr_meta_xml_parse(struct nft_rule_expr *e, mxml_node_t *tr
int key;
uint32_t reg;
- if (nft_mxml_reg_parse(tree, "dreg", &reg, MXML_DESCEND_FIRST,
- NFT_XML_MAND, err) < 0)
- return -1;
-
- meta->dreg = reg;
- e->flags |= (1 << NFT_EXPR_META_DREG);
-
key_str = nft_mxml_str_parse(tree, "key", MXML_DESCEND_FIRST,
NFT_XML_MAND, err);
if (key_str == NULL)
@@ -219,6 +239,18 @@ static int nft_rule_expr_meta_xml_parse(struct nft_rule_expr *e, mxml_node_t *tr
meta->key = key;
e->flags |= (1 << NFT_EXPR_META_KEY);
+ if (nft_mxml_reg_parse(tree, "dreg", &reg, MXML_DESCEND_FIRST,
+ NFT_XML_OPT, err) >= 0) {
+ meta->dreg = reg;
+ e->flags |= (1 << NFT_EXPR_META_DREG);
+ }
+
+ if (nft_mxml_reg_parse(tree, "sreg", &reg, MXML_DESCEND_FIRST,
+ NFT_XML_OPT, err) >= 0) {
+ meta->sreg = reg;
+ e->flags |= (1 << NFT_EXPR_META_SREG);
+ }
+
return 0;
#else
errno = EOPNOTSUPP;
@@ -227,23 +259,92 @@ static int nft_rule_expr_meta_xml_parse(struct nft_rule_expr *e, mxml_node_t *tr
}
static int
-nft_rule_expr_meta_snprintf(char *buf, size_t len, uint32_t type,
- uint32_t flags, struct nft_rule_expr *e)
+nft_rule_expr_meta_snprintf_default(char *buf, size_t len,
+ struct nft_rule_expr *e)
{
struct nft_expr_meta *meta = nft_expr_data(e);
- switch(type) {
- case NFT_OUTPUT_DEFAULT:
+ if (e->flags & (1 << NFT_EXPR_META_SREG)) {
+ return snprintf(buf, len, "set %s with reg %u ",
+ meta_key2str(meta->key), meta->sreg);
+ }
+ if (e->flags & (1 << NFT_EXPR_META_DREG)) {
return snprintf(buf, len, "load %s => reg %u ",
meta_key2str(meta->key), meta->dreg);
+ }
+ return 0;
+}
+
+static int
+nft_rule_expr_meta_snprintf_xml(char *buf, size_t size,
+ struct nft_rule_expr *e)
+{
+ int ret, len = size, offset = 0;
+ struct nft_expr_meta *meta = nft_expr_data(e);
+
+ if (e->flags & (1 << NFT_EXPR_META_DREG)) {
+ ret = snprintf(buf+offset, len, "<dreg>%u</dreg>",
+ meta->dreg);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ if (e->flags & (1 << NFT_EXPR_META_KEY)) {
+ ret = snprintf(buf+offset, len, "<key>%s</key>",
+ meta_key2str(meta->key));
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ if (e->flags & (1 << NFT_EXPR_META_SREG)) {
+ ret = snprintf(buf+offset, len, "<sreg>%u</sreg>",
+ meta->sreg);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ return offset;
+}
+
+static int
+nft_rule_expr_meta_snprintf_json(char *buf, size_t size,
+ struct nft_rule_expr *e)
+{
+ int ret, len = size, offset = 0;
+ struct nft_expr_meta *meta = nft_expr_data(e);
+
+ if (e->flags & (1 << NFT_EXPR_META_DREG)) {
+ ret = snprintf(buf+offset, len, "\"dreg\":%u,",
+ meta->dreg);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ if (e->flags & (1 << NFT_EXPR_META_KEY)) {
+ ret = snprintf(buf+offset, len, "\"key\":\"%s\",",
+ meta_key2str(meta->key));
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ if (e->flags & (1 << NFT_EXPR_META_SREG)) {
+ ret = snprintf(buf+offset, len, "\"sreg\":%u,",
+ meta->sreg);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ /* Remove the last separator characther */
+ buf[offset-1] = '\0';
+
+ return offset-1;
+}
+
+static int
+nft_rule_expr_meta_snprintf(char *buf, size_t len, uint32_t type,
+ uint32_t flags, struct nft_rule_expr *e)
+{
+ switch(type) {
+ case NFT_OUTPUT_DEFAULT:
+ return nft_rule_expr_meta_snprintf_default(buf, len, e);
case NFT_OUTPUT_XML:
- return snprintf(buf, len, "<dreg>%u</dreg>"
- "<key>%s</key>",
- meta->dreg, meta_key2str(meta->key));
+ return nft_rule_expr_meta_snprintf_xml(buf, len, e);
case NFT_OUTPUT_JSON:
- return snprintf(buf, len, "\"dreg\":%u,"
- "\"key\":\"%s\"",
- meta->dreg, meta_key2str(meta->key));
+ return nft_rule_expr_meta_snprintf_json(buf, len, e);
default:
break;
}
diff --git a/src/expr/queue.c b/src/expr/queue.c
new file mode 100644
index 0000000..c3d0e19
--- /dev/null
+++ b/src/expr/queue.c
@@ -0,0 +1,254 @@
+/*
+ * (C) 2013 by Eric Leblond <eric@regit.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include "internal.h"
+#include <libmnl/libmnl.h>
+#include <libnftnl/expr.h>
+#include <libnftnl/rule.h>
+#include "expr_ops.h"
+
+struct nft_expr_queue {
+ uint16_t queuenum;
+ uint16_t queues_total;
+ uint16_t flags;
+};
+
+static int nft_rule_expr_queue_set(struct nft_rule_expr *e, uint16_t type,
+ const void *data, uint32_t data_len)
+{
+ struct nft_expr_queue *queue = nft_expr_data(e);
+
+ switch(type) {
+ case NFT_EXPR_QUEUE_NUM:
+ queue->queuenum = *((uint16_t *)data);
+ break;
+ case NFT_EXPR_QUEUE_TOTAL:
+ queue->queues_total = *((uint16_t *)data);
+ break;
+ case NFT_EXPR_QUEUE_FLAGS:
+ queue->flags = *((uint16_t *)data);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static const void *
+nft_rule_expr_queue_get(const struct nft_rule_expr *e, uint16_t type,
+ uint32_t *data_len)
+{
+ struct nft_expr_queue *queue = nft_expr_data(e);
+
+ switch(type) {
+ case NFT_EXPR_QUEUE_NUM:
+ *data_len = sizeof(queue->queuenum);
+ return &queue->queuenum;
+ case NFT_EXPR_QUEUE_TOTAL:
+ *data_len = sizeof(queue->queues_total);
+ return &queue->queues_total;
+ case NFT_EXPR_QUEUE_FLAGS:
+ *data_len = sizeof(queue->flags);
+ return &queue->flags;
+ }
+ return NULL;
+}
+
+static int nft_rule_expr_queue_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, NFTA_QUEUE_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case NFTA_QUEUE_NUM:
+ case NFTA_QUEUE_TOTAL:
+ case NFTA_QUEUE_FLAGS:
+ if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static void
+nft_rule_expr_queue_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
+{
+ struct nft_expr_queue *queue = nft_expr_data(e);
+
+ if (e->flags & (1 << NFT_EXPR_QUEUE_NUM))
+ mnl_attr_put_u16(nlh, NFTA_QUEUE_NUM, htons(queue->queuenum));
+ if (e->flags & (1 << NFT_EXPR_QUEUE_TOTAL))
+ mnl_attr_put_u16(nlh, NFTA_QUEUE_TOTAL, htons(queue->queues_total));
+ if (e->flags & (1 << NFT_EXPR_QUEUE_FLAGS))
+ mnl_attr_put_u16(nlh, NFTA_QUEUE_FLAGS, htons(queue->flags));
+}
+
+static int
+nft_rule_expr_queue_parse(struct nft_rule_expr *e, struct nlattr *attr)
+{
+ struct nft_expr_queue *queue = nft_expr_data(e);
+ struct nlattr *tb[NFTA_QUEUE_MAX+1] = {};
+
+ if (mnl_attr_parse_nested(attr, nft_rule_expr_queue_cb, tb) < 0)
+ return -1;
+
+ if (tb[NFTA_QUEUE_NUM]) {
+ queue->queuenum = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_NUM]));
+ e->flags |= (1 << NFT_EXPR_QUEUE_NUM);
+ }
+ if (tb[NFTA_QUEUE_TOTAL]) {
+ queue->queues_total = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_TOTAL]));
+ e->flags |= (1 << NFT_EXPR_QUEUE_TOTAL);
+ }
+ if (tb[NFTA_QUEUE_FLAGS]) {
+ queue->flags = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_FLAGS]));
+ e->flags |= (1 << NFT_EXPR_QUEUE_FLAGS);
+ }
+
+ return 0;
+}
+
+static int
+nft_rule_expr_queue_json_parse(struct nft_rule_expr *e, json_t *root)
+{
+#ifdef JSON_PARSING
+ uint32_t type;
+ uint16_t code;
+
+ if (nft_jansson_parse_val(root, "num", NFT_TYPE_U16, &type) < 0)
+ return -1;
+
+ nft_rule_expr_set_u32(e, NFT_EXPR_QUEUE_NUM, type);
+
+ if (nft_jansson_parse_val(root, "total", NFT_TYPE_U16, &code) < 0)
+ return -1;
+
+ nft_rule_expr_set_u16(e, NFT_EXPR_QUEUE_TOTAL, code);
+
+ if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U16, &code) < 0)
+ return -1;
+
+ nft_rule_expr_set_u16(e, NFT_EXPR_QUEUE_FLAGS, code);
+
+ return 0;
+#else
+ errno = EOPNOTSUPP;
+ return -1;
+#endif
+}
+
+static int
+nft_rule_expr_queue_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+{
+#ifdef XML_PARSING
+ struct nft_expr_queue *queue = nft_expr_data(e);
+
+ if (nft_mxml_num_parse(tree, "num", MXML_DESCEND_FIRST, BASE_DEC,
+ &queue->queuenum, NFT_TYPE_U16, NFT_XML_MAND) != 0)
+ return -1;
+
+ e->flags |= (1 << NFT_EXPR_QUEUE_NUM);
+
+ if (nft_mxml_num_parse(tree, "total", MXML_DESCEND_FIRST, BASE_DEC,
+ &queue->queues_total, NFT_TYPE_U8, NFT_XML_MAND) != 0)
+ return -1;
+
+ e->flags |= (1 << NFT_EXPR_QUEUE_TOTAL);
+
+ if (nft_mxml_num_parse(tree, "flags", MXML_DESCEND_FIRST, BASE_DEC,
+ &queue->flags, NFT_TYPE_U8, NFT_XML_MAND) != 0)
+ return -1;
+
+ e->flags |= (1 << NFT_EXPR_QUEUE_FLAGS);
+
+ return 0;
+#else
+ errno = EOPNOTSUPP;
+ return -1;
+#endif
+}
+
+static int
+nft_rule_expr_queue_snprintf(char *buf, size_t len, uint32_t type,
+ uint32_t flags, struct nft_rule_expr *e)
+{
+ struct nft_expr_queue *queue = nft_expr_data(e);
+ int ret;
+ int one = 0;
+
+ switch(type) {
+ case NFT_OUTPUT_DEFAULT:
+ ret = snprintf(buf, len, "num %u total %u",
+ queue->queuenum, queue->queues_total);
+ if (queue->flags) {
+ ret += snprintf(buf + ret , len - ret, " options ");
+ if (queue->flags & NFT_QUEUE_FLAG_BYPASS) {
+ ret += snprintf(buf + ret ,
+ len - ret, "bypass");
+ one = 1;
+ }
+ if (queue->flags & NFT_QUEUE_FLAG_CPU_FANOUT) {
+ if (one)
+ ret += snprintf(buf + ret ,
+ len - ret, ",");
+ ret += snprintf(buf + ret ,
+ len - ret, "fanout");
+ }
+ }
+ return ret;
+ case NFT_OUTPUT_XML:
+ return snprintf(buf, len, "<num>%u</num>"
+ "<total>%u</total>"
+ "<flags>%u</flags>",
+ queue->queuenum, queue->queues_total,
+ queue->flags);
+ case NFT_OUTPUT_JSON:
+ return snprintf(buf, len, "\"num\":%u,"
+ "\"total\":%u,"
+ "\"flags\":%u,",
+ queue->queuenum, queue->queues_total,
+ queue->flags);
+ default:
+ break;
+ }
+ return -1;
+}
+
+struct expr_ops expr_ops_queue = {
+ .name = "queue",
+ .alloc_len = sizeof(struct nft_expr_queue),
+ .max_attr = NFTA_QUEUE_MAX,
+ .set = nft_rule_expr_queue_set,
+ .get = nft_rule_expr_queue_get,
+ .parse = nft_rule_expr_queue_parse,
+ .build = nft_rule_expr_queue_build,
+ .snprintf = nft_rule_expr_queue_snprintf,
+ .xml_parse = nft_rule_expr_queue_xml_parse,
+ .json_parse = nft_rule_expr_queue_json_parse,
+};
+
+static void __init expr_queue_init(void)
+{
+ nft_expr_ops_register(&expr_ops_queue);
+}
diff --git a/src/table.c b/src/table.c
index f50a968..c834a4e 100644
--- a/src/table.c
+++ b/src/table.c
@@ -31,6 +31,7 @@ struct nft_table {
const char *name;
uint8_t family;
uint32_t table_flags;
+ uint32_t use;
uint32_t flags;
};
@@ -70,6 +71,9 @@ void nft_table_attr_unset(struct nft_table *t, uint16_t attr)
case NFT_TABLE_ATTR_FLAGS:
case NFT_TABLE_ATTR_FAMILY:
break;
+ case NFT_TABLE_ATTR_USE:
+ /* Cannot be unset, ignoring it */
+ return;
}
t->flags &= ~(1 << attr);
}
@@ -93,6 +97,9 @@ void nft_table_attr_set(struct nft_table *t, uint16_t attr, const void *data)
t->family = *((uint8_t *)data);
t->flags |= (1 << NFT_TABLE_ATTR_FAMILY);
break;
+ case NFT_TABLE_ATTR_USE:
+ /* Cannot be unset, ignoring it */
+ break;
}
}
EXPORT_SYMBOL(nft_table_attr_set);
@@ -127,6 +134,8 @@ const void *nft_table_attr_get(struct nft_table *t, uint16_t attr)
return &t->table_flags;
case NFT_TABLE_ATTR_FAMILY:
return &t->family;
+ case NFT_TABLE_ATTR_USE:
+ return &t->use;
}
return NULL;
}
@@ -182,6 +191,12 @@ static int nft_table_parse_attr_cb(const struct nlattr *attr, void *data)
return MNL_CB_ERROR;
}
break;
+ case NFTA_TABLE_USE:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
}
tb[type] = attr;
@@ -202,6 +217,10 @@ int nft_table_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_table *t)
t->table_flags = ntohl(mnl_attr_get_u32(tb[NFTA_TABLE_FLAGS]));
t->flags |= (1 << NFT_TABLE_ATTR_FLAGS);
}
+ if (tb[NFTA_TABLE_USE]) {
+ t->use = ntohl(mnl_attr_get_u32(tb[NFTA_TABLE_USE]));
+ t->flags |= (1 << NFT_TABLE_ATTR_USE);
+ }
t->family = nfg->nfgen_family;
t->flags |= (1 << NFT_TABLE_ATTR_FAMILY);
@@ -368,23 +387,27 @@ static int nft_table_snprintf_json(char *buf, size_t size, struct nft_table *t)
"{\"table\":{"
"\"name\":\"%s\","
"\"family\":\"%s\","
- "\"flags\":%d"
+ "\"flags\":%d,"
+ "\"use\":%d"
"}"
"}" ,
- t->name, nft_family2str(t->family), t->table_flags);
+ t->name, nft_family2str(t->family),
+ t->table_flags, t->use);
}
static int nft_table_snprintf_xml(char *buf, size_t size, struct nft_table *t)
{
return snprintf(buf, size, "<table><name>%s</name><family>%s</family>"
- "<flags>%d</flags></table>",
- t->name, nft_family2str(t->family), t->table_flags);
+ "<flags>%d</flags><use>%d</use></table>",
+ t->name, nft_family2str(t->family),
+ t->table_flags, t->use);
}
static int nft_table_snprintf_default(char *buf, size_t size, struct nft_table *t)
{
- return snprintf(buf, size, "table %s %s flags %x",
- t->name, nft_family2str(t->family), t->table_flags);
+ return snprintf(buf, size, "table %s %s flags %x use %d",
+ t->name, nft_family2str(t->family),
+ t->table_flags, t->use);
}
int nft_table_snprintf(char *buf, size_t size, struct nft_table *t,
diff --git a/src/utils.c b/src/utils.c
index dd7fd1d..9691c4c 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -27,6 +27,8 @@ const char *nft_family2str(uint32_t family)
return "ip";
case AF_INET6:
return "ip6";
+ case 1:
+ return "inet";
case AF_BRIDGE:
return "bridge";
case 3: /* NFPROTO_ARP */
@@ -42,6 +44,8 @@ int nft_str2family(const char *family)
return AF_INET;
else if (strcmp(family, "ip6") == 0)
return AF_INET6;
+ else if (strcmp(family, "inet") == 0)
+ return 1;
else if (strcmp(family, "bridge") == 0)
return AF_BRIDGE;
else if (strcmp(family, "arp") == 0)