summaryrefslogtreecommitdiffstats
path: root/src/set.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/set.c')
-rw-r--r--src/set.c171
1 files changed, 137 insertions, 34 deletions
diff --git a/src/set.c b/src/set.c
index 651dcfa..07e332d 100644
--- a/src/set.c
+++ b/src/set.c
@@ -37,6 +37,7 @@ struct nftnl_set *nftnl_set_alloc(void)
return NULL;
INIT_LIST_HEAD(&s->element_list);
+ INIT_LIST_HEAD(&s->expr_list);
return s;
}
@@ -44,6 +45,7 @@ EXPORT_SYMBOL(nftnl_set_free);
void nftnl_set_free(const struct nftnl_set *s)
{
struct nftnl_set_elem *elem, *tmp;
+ struct nftnl_expr *expr, *next;
if (s->flags & (1 << NFTNL_SET_TABLE))
xfree(s->table);
@@ -52,6 +54,11 @@ void nftnl_set_free(const struct nftnl_set *s)
if (s->flags & (1 << NFTNL_SET_USERDATA))
xfree(s->user.data);
+ list_for_each_entry_safe(expr, next, &s->expr_list, head) {
+ list_del(&expr->head);
+ nftnl_expr_free(expr);
+ }
+
list_for_each_entry_safe(elem, tmp, &s->element_list, head) {
list_del(&elem->head);
nftnl_set_elem_free(elem);
@@ -68,6 +75,8 @@ bool nftnl_set_is_set(const struct nftnl_set *s, uint16_t attr)
EXPORT_SYMBOL(nftnl_set_unset);
void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
{
+ struct nftnl_expr *expr, *tmp;
+
if (!(s->flags & (1 << attr)))
return;
@@ -96,6 +105,13 @@ void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
case NFTNL_SET_USERDATA:
xfree(s->user.data);
break;
+ case NFTNL_SET_EXPR:
+ case NFTNL_SET_EXPRESSIONS:
+ list_for_each_entry_safe(expr, tmp, &s->expr_list, head) {
+ list_del(&expr->head);
+ nftnl_expr_free(expr);
+ }
+ break;
default:
return;
}
@@ -112,6 +128,7 @@ static uint32_t nftnl_set_validate[NFTNL_SET_MAX + 1] = {
[NFTNL_SET_DATA_LEN] = sizeof(uint32_t),
[NFTNL_SET_OBJ_TYPE] = sizeof(uint32_t),
[NFTNL_SET_FAMILY] = sizeof(uint32_t),
+ [NFTNL_SET_ID] = sizeof(uint32_t),
[NFTNL_SET_POLICY] = sizeof(uint32_t),
[NFTNL_SET_DESC_SIZE] = sizeof(uint32_t),
[NFTNL_SET_TIMEOUT] = sizeof(uint64_t),
@@ -122,26 +139,18 @@ EXPORT_SYMBOL(nftnl_set_set_data);
int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
uint32_t data_len)
{
+ struct nftnl_expr *expr, *tmp;
+
nftnl_assert_attr_exists(attr, NFTNL_SET_MAX);
nftnl_assert_validate(data, nftnl_set_validate, attr, data_len);
switch(attr) {
case NFTNL_SET_TABLE:
- if (s->flags & (1 << NFTNL_SET_TABLE))
- xfree(s->table);
-
- s->table = strdup(data);
- if (!s->table)
- return -1;
- break;
+ return nftnl_set_str_attr(&s->table, &s->flags,
+ attr, data, data_len);
case NFTNL_SET_NAME:
- if (s->flags & (1 << NFTNL_SET_NAME))
- xfree(s->name);
-
- s->name = strdup(data);
- if (!s->name)
- return -1;
- break;
+ return nftnl_set_str_attr(&s->name, &s->flags,
+ attr, data, data_len);
case NFTNL_SET_HANDLE:
memcpy(&s->handle, data, sizeof(s->handle));
break;
@@ -176,8 +185,14 @@ int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
memcpy(&s->desc.size, data, sizeof(s->desc.size));
break;
case NFTNL_SET_DESC_CONCAT:
+ if (data_len > sizeof(s->desc.field_len))
+ return -1;
+
memcpy(&s->desc.field_len, data, data_len);
- while (s->desc.field_len[++s->desc.field_count]);
+ while (s->desc.field_len[++s->desc.field_count]) {
+ if (s->desc.field_count >= NFT_REG32_COUNT)
+ break;
+ }
break;
case NFTNL_SET_TIMEOUT:
memcpy(&s->timeout, data, sizeof(s->timeout));
@@ -195,6 +210,15 @@ int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
memcpy(s->user.data, data, data_len);
s->user.len = data_len;
break;
+ case NFTNL_SET_EXPR:
+ list_for_each_entry_safe(expr, tmp, &s->expr_list, head) {
+ list_del(&expr->head);
+ nftnl_expr_free(expr);
+ }
+
+ expr = (void *)data;
+ list_add(&expr->head, &s->expr_list);
+ break;
}
s->flags |= (1 << attr);
return 0;
@@ -228,6 +252,8 @@ EXPORT_SYMBOL(nftnl_set_get_data);
const void *nftnl_set_get_data(const struct nftnl_set *s, uint16_t attr,
uint32_t *data_len)
{
+ struct nftnl_expr *expr;
+
if (!(s->flags & (1 << attr)))
return NULL;
@@ -283,6 +309,10 @@ const void *nftnl_set_get_data(const struct nftnl_set *s, uint16_t attr,
case NFTNL_SET_USERDATA:
*data_len = s->user.len;
return s->user.data;
+ case NFTNL_SET_EXPR:
+ list_for_each_entry(expr, &s->expr_list, head)
+ break;
+ return expr;
}
return NULL;
}
@@ -401,6 +431,8 @@ nftnl_set_nlmsg_build_desc_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
EXPORT_SYMBOL(nftnl_set_nlmsg_build_payload);
void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
{
+ int num_exprs = 0;
+
if (s->flags & (1 << NFTNL_SET_TABLE))
mnl_attr_put_strz(nlh, NFTA_SET_TABLE, s->table);
if (s->flags & (1 << NFTNL_SET_NAME))
@@ -432,8 +464,55 @@ void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
mnl_attr_put_u32(nlh, NFTA_SET_GC_INTERVAL, htonl(s->gc_interval));
if (s->flags & (1 << NFTNL_SET_USERDATA))
mnl_attr_put(nlh, NFTA_SET_USERDATA, s->user.len, s->user.data);
+ if (!list_empty(&s->expr_list)) {
+ struct nftnl_expr *expr;
+
+ list_for_each_entry(expr, &s->expr_list, head)
+ num_exprs++;
+
+ if (num_exprs == 1) {
+ struct nlattr *nest1;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_EXPR);
+ list_for_each_entry(expr, &s->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_EXPRESSIONS);
+ list_for_each_entry(expr, &s->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);
+ }
+ }
+}
+
+EXPORT_SYMBOL(nftnl_set_add_expr);
+void nftnl_set_add_expr(struct nftnl_set *s, struct nftnl_expr *expr)
+{
+ list_add_tail(&expr->head, &s->expr_list);
}
+EXPORT_SYMBOL(nftnl_set_expr_foreach);
+int nftnl_set_expr_foreach(const struct nftnl_set *s,
+ int (*cb)(struct nftnl_expr *e, void *data),
+ void *data)
+{
+ struct nftnl_expr *cur, *tmp;
+ int ret;
+
+ list_for_each_entry_safe(cur, tmp, &s->expr_list, head) {
+ ret = cb(cur, data);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data)
{
@@ -473,6 +552,8 @@ static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data)
abi_breakage();
break;
case NFTA_SET_DESC:
+ case NFTA_SET_EXPR:
+ case NFTA_SET_EXPRESSIONS:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
abi_breakage();
break;
@@ -558,6 +639,7 @@ int nftnl_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s)
{
struct nlattr *tb[NFTA_SET_MAX+1] = {};
struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+ struct nftnl_expr *expr, *next;
int ret;
if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_set_parse_attr_cb, tb) < 0)
@@ -635,11 +717,40 @@ int nftnl_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s)
if (ret < 0)
return ret;
}
+ if (tb[NFTA_SET_EXPR]) {
+ expr = nftnl_expr_parse(tb[NFTA_SET_EXPR]);
+ if (!expr)
+ goto out_set_expr;
+
+ list_add(&expr->head, &s->expr_list);
+ s->flags |= (1 << NFTNL_SET_EXPR);
+ } else if (tb[NFTA_SET_EXPRESSIONS]) {
+ struct nlattr *attr;
+
+ mnl_attr_for_each_nested(attr, tb[NFTA_SET_EXPRESSIONS]) {
+ if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM)
+ goto out_set_expr;
+
+ expr = nftnl_expr_parse(attr);
+ if (expr == NULL)
+ goto out_set_expr;
+
+ list_add_tail(&expr->head, &s->expr_list);
+ }
+ s->flags |= (1 << NFTNL_SET_EXPRESSIONS);
+ }
s->family = nfg->nfgen_family;
s->flags |= (1 << NFTNL_SET_FAMILY);
return 0;
+out_set_expr:
+ list_for_each_entry_safe(expr, next, &s->expr_list, head) {
+ list_del(&expr->head);
+ nftnl_expr_free(expr);
+ }
+
+ return -1;
}
static int nftnl_set_do_parse(struct nftnl_set *s, enum nftnl_parse_type type,
@@ -678,13 +789,12 @@ int nftnl_set_parse_file(struct nftnl_set *s, enum nftnl_parse_type type,
return nftnl_set_do_parse(s, type, fp, err, NFTNL_PARSE_FILE);
}
-static int nftnl_set_snprintf_default(char *buf, size_t size,
+static int nftnl_set_snprintf_default(char *buf, size_t remain,
const struct nftnl_set *s,
uint32_t type, uint32_t flags)
{
- int ret;
- int remain = size, offset = 0;
struct nftnl_set_elem *elem;
+ int ret, offset = 0;
ret = snprintf(buf, remain, "%s %s %x",
s->name, s->table, s->set_flags);
@@ -723,37 +833,30 @@ static int nftnl_set_snprintf_default(char *buf, size_t size,
ret = snprintf(buf + offset, remain, "\t");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- ret = nftnl_set_elem_snprintf(buf + offset, remain, elem, type,
- flags);
+ ret = nftnl_set_elem_snprintf_default(buf + offset, remain,
+ elem);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
return offset;
}
-static int nftnl_set_cmd_snprintf(char *buf, size_t size,
+static int nftnl_set_cmd_snprintf(char *buf, size_t remain,
const struct nftnl_set *s, uint32_t cmd,
uint32_t type, uint32_t flags)
{
- int ret, remain = size, offset = 0;
uint32_t inner_flags = flags;
+ int ret, offset = 0;
- if (type == NFTNL_OUTPUT_XML)
- return 0;
+ if (type != NFTNL_OUTPUT_DEFAULT)
+ return -1;
/* prevent set_elems to print as events */
inner_flags &= ~NFTNL_OF_EVENT_ANY;
- switch(type) {
- case NFTNL_OUTPUT_DEFAULT:
- ret = nftnl_set_snprintf_default(buf + offset, remain, s, type,
- inner_flags);
- SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- break;
- default:
- return -1;
- }
-
+ ret = nftnl_set_snprintf_default(buf + offset, remain, s, type,
+ inner_flags);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
return offset;
}