summaryrefslogtreecommitdiffstats
path: root/src/set_elem.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/set_elem.c')
-rw-r--r--src/set_elem.c207
1 files changed, 164 insertions, 43 deletions
diff --git a/src/set_elem.c b/src/set_elem.c
index d3ce807..9207a0d 100644
--- a/src/set_elem.c
+++ b/src/set_elem.c
@@ -36,17 +36,21 @@ struct nftnl_set_elem *nftnl_set_elem_alloc(void)
if (s == NULL)
return NULL;
+ INIT_LIST_HEAD(&s->expr_list);
+
return s;
}
EXPORT_SYMBOL(nftnl_set_elem_free);
void nftnl_set_elem_free(struct nftnl_set_elem *s)
{
+ struct nftnl_expr *e, *tmp;
+
if (s->flags & (1 << NFTNL_SET_ELEM_CHAIN))
xfree(s->data.chain);
- if (s->flags & (1 << NFTNL_SET_ELEM_EXPR))
- nftnl_expr_free(s->expr);
+ list_for_each_entry_safe(e, tmp, &s->expr_list, head)
+ nftnl_expr_free(e);
if (s->flags & (1 << NFTNL_SET_ELEM_USERDATA))
xfree(s->user.data);
@@ -66,6 +70,8 @@ bool nftnl_set_elem_is_set(const struct nftnl_set_elem *s, uint16_t attr)
EXPORT_SYMBOL(nftnl_set_elem_unset);
void nftnl_set_elem_unset(struct nftnl_set_elem *s, uint16_t attr)
{
+ struct nftnl_expr *expr, *tmp;
+
if (!(s->flags & (1 << attr)))
return;
@@ -75,6 +81,7 @@ void nftnl_set_elem_unset(struct nftnl_set_elem *s, uint16_t attr)
break;
case NFTNL_SET_ELEM_FLAGS:
case NFTNL_SET_ELEM_KEY: /* NFTA_SET_ELEM_KEY */
+ case NFTNL_SET_ELEM_KEY_END: /* NFTA_SET_ELEM_KEY_END */
case NFTNL_SET_ELEM_VERDICT: /* NFTA_SET_ELEM_DATA */
case NFTNL_SET_ELEM_DATA: /* NFTA_SET_ELEM_DATA */
case NFTNL_SET_ELEM_TIMEOUT: /* NFTA_SET_ELEM_TIMEOUT */
@@ -84,7 +91,9 @@ void nftnl_set_elem_unset(struct nftnl_set_elem *s, uint16_t attr)
xfree(s->user.data);
break;
case NFTNL_SET_ELEM_EXPR:
- nftnl_expr_free(s->expr);
+ case NFTNL_SET_ELEM_EXPRESSIONS:
+ list_for_each_entry_safe(expr, tmp, &s->expr_list, head)
+ nftnl_expr_free(expr);
break;
case NFTNL_SET_ELEM_OBJREF:
xfree(s->objref);
@@ -107,6 +116,8 @@ EXPORT_SYMBOL(nftnl_set_elem_set);
int nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr,
const void *data, uint32_t data_len)
{
+ struct nftnl_expr *expr, *tmp;
+
nftnl_assert_attr_exists(attr, NFTNL_SET_ELEM_MAX);
nftnl_assert_validate(data, nftnl_set_elem_validate, attr, data_len);
@@ -115,8 +126,12 @@ int nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr,
memcpy(&s->set_elem_flags, data, sizeof(s->set_elem_flags));
break;
case NFTNL_SET_ELEM_KEY: /* NFTA_SET_ELEM_KEY */
- memcpy(&s->key.val, data, data_len);
- s->key.len = data_len;
+ if (nftnl_data_cpy(&s->key, data, data_len) < 0)
+ return -1;
+ break;
+ case NFTNL_SET_ELEM_KEY_END: /* NFTA_SET_ELEM_KEY_END */
+ if (nftnl_data_cpy(&s->key_end, data, data_len) < 0)
+ return -1;
break;
case NFTNL_SET_ELEM_VERDICT: /* NFTA_SET_ELEM_DATA */
memcpy(&s->data.verdict, data, sizeof(s->data.verdict));
@@ -130,8 +145,8 @@ int nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr,
return -1;
break;
case NFTNL_SET_ELEM_DATA: /* NFTA_SET_ELEM_DATA */
- memcpy(s->data.val, data, data_len);
- s->data.len = data_len;
+ if (nftnl_data_cpy(&s->data, data, data_len) < 0)
+ return -1;
break;
case NFTNL_SET_ELEM_TIMEOUT: /* NFTA_SET_ELEM_TIMEOUT */
memcpy(&s->timeout, data, sizeof(s->timeout));
@@ -157,6 +172,13 @@ int nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr,
if (!s->objref)
return -1;
break;
+ case NFTNL_SET_ELEM_EXPR:
+ list_for_each_entry_safe(expr, tmp, &s->expr_list, head)
+ nftnl_expr_free(expr);
+
+ expr = (void *)data;
+ list_add(&expr->head, &s->expr_list);
+ break;
}
s->flags |= (1 << attr);
return 0;
@@ -183,6 +205,8 @@ int nftnl_set_elem_set_str(struct nftnl_set_elem *s, uint16_t attr, const char *
EXPORT_SYMBOL(nftnl_set_elem_get);
const void *nftnl_set_elem_get(struct nftnl_set_elem *s, uint16_t attr, uint32_t *data_len)
{
+ struct nftnl_expr *expr;
+
if (!(s->flags & (1 << attr)))
return NULL;
@@ -193,6 +217,9 @@ const void *nftnl_set_elem_get(struct nftnl_set_elem *s, uint16_t attr, uint32_t
case NFTNL_SET_ELEM_KEY: /* NFTA_SET_ELEM_KEY */
*data_len = s->key.len;
return &s->key.val;
+ case NFTNL_SET_ELEM_KEY_END: /* NFTA_SET_ELEM_KEY_END */
+ *data_len = s->key_end.len;
+ return &s->key_end.val;
case NFTNL_SET_ELEM_VERDICT: /* NFTA_SET_ELEM_DATA */
*data_len = sizeof(s->data.verdict);
return &s->data.verdict;
@@ -212,7 +239,9 @@ const void *nftnl_set_elem_get(struct nftnl_set_elem *s, uint16_t attr, uint32_t
*data_len = s->user.len;
return s->user.data;
case NFTNL_SET_ELEM_EXPR:
- return s->expr;
+ list_for_each_entry(expr, &s->expr_list, head)
+ break;
+ return expr;
case NFTNL_SET_ELEM_OBJREF:
*data_len = strlen(s->objref) + 1;
return s->objref;
@@ -271,9 +300,13 @@ err:
return NULL;
}
+EXPORT_SYMBOL(nftnl_set_elem_nlmsg_build_payload);
void nftnl_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh,
struct nftnl_set_elem *e)
{
+ struct nftnl_expr *expr;
+ int num_exprs = 0;
+
if (e->flags & (1 << NFTNL_SET_ELEM_FLAGS))
mnl_attr_put_u32(nlh, NFTA_SET_ELEM_FLAGS, htonl(e->set_elem_flags));
if (e->flags & (1 << NFTNL_SET_ELEM_TIMEOUT))
@@ -287,6 +320,14 @@ void nftnl_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh,
mnl_attr_put(nlh, NFTA_DATA_VALUE, e->key.len, e->key.val);
mnl_attr_nest_end(nlh, nest1);
}
+ if (e->flags & (1 << NFTNL_SET_ELEM_KEY_END)) {
+ struct nlattr *nest1;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_KEY_END);
+ mnl_attr_put(nlh, NFTA_DATA_VALUE, e->key_end.len,
+ e->key_end.val);
+ mnl_attr_nest_end(nlh, nest1);
+ }
if (e->flags & (1 << NFTNL_SET_ELEM_VERDICT)) {
struct nlattr *nest1, *nest2;
@@ -310,6 +351,31 @@ void nftnl_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh,
mnl_attr_put(nlh, NFTA_SET_ELEM_USERDATA, e->user.len, e->user.data);
if (e->flags & (1 << NFTNL_SET_ELEM_OBJREF))
mnl_attr_put_strz(nlh, NFTA_SET_ELEM_OBJREF, e->objref);
+
+ if (!list_empty(&e->expr_list)) {
+ list_for_each_entry(expr, &e->expr_list, head)
+ num_exprs++;
+
+ if (num_exprs == 1) {
+ struct nlattr *nest1;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_EXPR);
+ list_for_each_entry(expr, &e->expr_list, head)
+ nftnl_expr_build_payload(nlh, expr);
+
+ mnl_attr_nest_end(nlh, nest1);
+ } else if (num_exprs > 1) {
+ struct nlattr *nest1, *nest2;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_EXPRESSIONS);
+ list_for_each_entry(expr, &e->expr_list, head) {
+ nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
+ nftnl_expr_build_payload(nlh, expr);
+ mnl_attr_nest_end(nlh, nest2);
+ }
+ mnl_attr_nest_end(nlh, nest1);
+ }
+ }
}
static void nftnl_set_elem_nlmsg_build_def(struct nlmsghdr *nlh,
@@ -323,8 +389,9 @@ static void nftnl_set_elem_nlmsg_build_def(struct nlmsghdr *nlh,
mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_TABLE, s->table);
}
-static struct nlattr *nftnl_set_elem_build(struct nlmsghdr *nlh,
- struct nftnl_set_elem *elem, int i)
+EXPORT_SYMBOL(nftnl_set_elem_nlmsg_build);
+struct nlattr *nftnl_set_elem_nlmsg_build(struct nlmsghdr *nlh,
+ struct nftnl_set_elem *elem, int i)
{
struct nlattr *nest2;
@@ -349,11 +416,33 @@ void nftnl_set_elems_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set
nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_LIST_ELEMENTS);
list_for_each_entry(elem, &s->element_list, head)
- nftnl_set_elem_build(nlh, elem, ++i);
+ nftnl_set_elem_nlmsg_build(nlh, elem, ++i);
mnl_attr_nest_end(nlh, nest1);
}
+EXPORT_SYMBOL(nftnl_set_elem_add_expr);
+void nftnl_set_elem_add_expr(struct nftnl_set_elem *e, struct nftnl_expr *expr)
+{
+ list_add_tail(&expr->head, &e->expr_list);
+}
+
+EXPORT_SYMBOL(nftnl_set_elem_expr_foreach);
+int nftnl_set_elem_expr_foreach(struct nftnl_set_elem *e,
+ int (*cb)(struct nftnl_expr *e, void *data),
+ void *data)
+{
+ struct nftnl_expr *cur, *tmp;
+ int ret;
+
+ list_for_each_entry_safe(cur, tmp, &e->expr_list, head) {
+ ret = cb(cur, data);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
static int nftnl_set_elem_parse_attr_cb(const struct nlattr *attr, void *data)
{
const struct nlattr **tb = data;
@@ -373,8 +462,10 @@ static int nftnl_set_elem_parse_attr_cb(const struct nlattr *attr, void *data)
abi_breakage();
break;
case NFTA_SET_ELEM_KEY:
+ case NFTA_SET_ELEM_KEY_END:
case NFTA_SET_ELEM_DATA:
case NFTA_SET_ELEM_EXPR:
+ case NFTA_SET_ELEM_EXPRESSIONS:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
abi_breakage();
break;
@@ -421,6 +512,13 @@ static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest
goto out_set_elem;
e->flags |= (1 << NFTNL_SET_ELEM_KEY);
}
+ if (tb[NFTA_SET_ELEM_KEY_END]) {
+ ret = nftnl_parse_data(&e->key_end, tb[NFTA_SET_ELEM_KEY_END],
+ &type);
+ if (ret < 0)
+ goto out_set_elem;
+ e->flags |= (1 << NFTNL_SET_ELEM_KEY_END);
+ }
if (tb[NFTA_SET_ELEM_DATA]) {
ret = nftnl_parse_data(&e->data, tb[NFTA_SET_ELEM_DATA], &type);
if (ret < 0)
@@ -439,12 +537,32 @@ static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest
}
}
if (tb[NFTA_SET_ELEM_EXPR]) {
- e->expr = nftnl_expr_parse(tb[NFTA_SET_ELEM_EXPR]);
- if (e->expr == NULL) {
+ struct nftnl_expr *expr;
+
+ expr = nftnl_expr_parse(tb[NFTA_SET_ELEM_EXPR]);
+ if (expr == NULL) {
ret = -1;
goto out_set_elem;
}
+ list_add_tail(&expr->head, &e->expr_list);
e->flags |= (1 << NFTNL_SET_ELEM_EXPR);
+ } else if (tb[NFTA_SET_ELEM_EXPRESSIONS]) {
+ struct nftnl_expr *expr;
+ struct nlattr *attr;
+
+ mnl_attr_for_each_nested(attr, tb[NFTA_SET_ELEM_EXPRESSIONS]) {
+ if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM) {
+ ret = -1;
+ goto out_set_elem;
+ }
+ expr = nftnl_expr_parse(attr);
+ if (expr == NULL) {
+ ret = -1;
+ goto out_set_elem;
+ }
+ list_add_tail(&expr->head, &e->expr_list);
+ }
+ e->flags |= (1 << NFTNL_SET_ELEM_EXPRESSIONS);
}
if (tb[NFTA_SET_ELEM_USERDATA]) {
const void *udata =
@@ -457,7 +575,7 @@ static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest
e->user.data = malloc(e->user.len);
if (e->user.data == NULL) {
ret = -1;
- goto out_expr;
+ goto out_set_elem;
}
memcpy(e->user.data, udata, e->user.len);
e->flags |= (1 << NFTNL_RULE_USERDATA);
@@ -475,8 +593,6 @@ static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest
list_add_tail(&e->head, &s->element_list);
return 0;
-out_expr:
- nftnl_expr_free(e->expr);
out_set_elem:
nftnl_set_elem_free(e);
return ret;
@@ -584,67 +700,72 @@ int nftnl_set_elem_parse_file(struct nftnl_set_elem *e, enum nftnl_parse_type ty
return -1;
}
-static int nftnl_set_elem_snprintf_default(char *buf, size_t size,
- const struct nftnl_set_elem *e)
+int nftnl_set_elem_snprintf_default(char *buf, size_t remain,
+ const struct nftnl_set_elem *e)
{
- int ret, remain = size, offset = 0, i;
+ int ret, dregtype = DATA_VALUE, offset = 0, i;
ret = snprintf(buf, remain, "element ");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- for (i = 0; i < div_round_up(e->key.len, sizeof(uint32_t)); i++) {
- ret = snprintf(buf + offset, remain, "%.8x ", e->key.val[i]);
+ ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->key,
+ DATA_F_NOPFX, DATA_VALUE);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+
+ if (e->flags & (1 << NFTNL_SET_ELEM_KEY_END)) {
+ ret = snprintf(buf + offset, remain, " - ");
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+
+ ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->key_end,
+ DATA_F_NOPFX, DATA_VALUE);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
ret = snprintf(buf + offset, remain, " : ");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- for (i = 0; i < div_round_up(e->data.len, sizeof(uint32_t)); i++) {
- ret = snprintf(buf + offset, remain, "%.8x ", e->data.val[i]);
- SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- }
+ if (e->flags & (1 << NFTNL_SET_ELEM_VERDICT))
+ dregtype = DATA_VERDICT;
+
+ ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->data,
+ DATA_F_NOPFX, dregtype);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
ret = snprintf(buf + offset, remain, "%u [end]", e->set_elem_flags);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
if (e->user.len) {
- ret = snprintf(buf + offset, remain, " userdata = {");
+ ret = snprintf(buf + offset, remain, " userdata = { ");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
for (i = 0; i < e->user.len; i++) {
char *c = e->user.data;
- ret = snprintf(buf + offset, remain, "%c",
- isalnum(c[i]) ? c[i] : 0);
+ ret = snprintf(buf + offset, remain,
+ isprint(c[i]) ? "%c" : "\\x%02hhx",
+ c[i]);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
- ret = snprintf(buf + offset, remain, " }\n");
+ ret = snprintf(buf + offset, remain, " }");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
return offset;
}
-static int nftnl_set_elem_cmd_snprintf(char *buf, size_t size,
+static int nftnl_set_elem_cmd_snprintf(char *buf, size_t remain,
const struct nftnl_set_elem *e,
uint32_t cmd, uint32_t type,
uint32_t flags)
{
- int ret, remain = size, offset = 0;
+ int ret, offset = 0;
- switch(type) {
- case NFTNL_OUTPUT_DEFAULT:
- ret = nftnl_set_elem_snprintf_default(buf + offset, remain, e);
- SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- break;
- case NFTNL_OUTPUT_XML:
- case NFTNL_OUTPUT_JSON:
- break;
- default:
+ if (type != NFTNL_OUTPUT_DEFAULT)
return -1;
- }
+
+ ret = nftnl_set_elem_snprintf_default(buf + offset, remain, e);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
return offset;
}
@@ -669,7 +790,7 @@ static int nftnl_set_elem_do_snprintf(char *buf, size_t size, const void *e,
}
EXPORT_SYMBOL(nftnl_set_elem_fprintf);
-int nftnl_set_elem_fprintf(FILE *fp, struct nftnl_set_elem *se, uint32_t type,
+int nftnl_set_elem_fprintf(FILE *fp, const struct nftnl_set_elem *se, uint32_t type,
uint32_t flags)
{
return nftnl_fprintf(fp, se, NFTNL_CMD_UNSPEC, type, flags,
@@ -781,7 +902,7 @@ int nftnl_set_elems_nlmsg_build_payload_iter(struct nlmsghdr *nlh,
nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_LIST_ELEMENTS);
elem = nftnl_set_elems_iter_next(iter);
while (elem != NULL) {
- nest2 = nftnl_set_elem_build(nlh, elem, ++i);
+ nest2 = nftnl_set_elem_nlmsg_build(nlh, elem, ++i);
if (nftnl_attr_nest_overflow(nlh, nest1, nest2)) {
/* Go back to previous not to miss this element */
iter->cur = list_entry(iter->cur->head.prev,