diff options
Diffstat (limited to 'src/expr')
-rw-r--r-- | src/expr/ct.c | 95 | ||||
-rw-r--r-- | src/expr/meta.c | 147 | ||||
-rw-r--r-- | src/expr/queue.c | 254 |
3 files changed, 453 insertions, 43 deletions
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, ®, err) < 0) - return -1; + if (nft_jansson_node_exist(root, "dreg")) { + if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, ®, 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, ®, 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", ®, 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", ®, 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, ®, 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, ®, + 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, ®, + 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", ®, 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", ®, 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", ®, 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); +} |