summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2017-09-14 22:59:13 +0200
committerFlorian Westphal <fw@strlen.de>2017-09-27 15:18:14 +0200
commitda06a74244cbe4b02431ea2c34b8299f3562c9ff (patch)
tree5f060ff612d59e67d15b3ac796c9af85d6dd9d14 /src
parent027734420b213560ab7e261d6b4b969e16e97343 (diff)
src: store expression as set key instead of data type
Doing so retains legth information in case of unqualified data types, e.g. we now have 'meta iifname' expression instead of an (unqualified) string type. This allows to eventually use iifnames as set keys without adding yet another special data type for them. Signed-off-by: Florian Westphal <fw@strlen.de> Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/evaluate.c62
-rw-r--r--src/expression.c4
-rw-r--r--src/netlink.c27
-rw-r--r--src/netlink_delinearize.c12
-rw-r--r--src/parser_bison.y65
-rw-r--r--src/rule.c4
-rw-r--r--src/segtree.c4
7 files changed, 98 insertions, 80 deletions
diff --git a/src/evaluate.c b/src/evaluate.c
index 86159cf5..836c9528 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -60,6 +60,18 @@ static int __fmtstring(3, 4) set_error(struct eval_ctx *ctx,
return -1;
}
+static void key_fix_dtype_byteorder(struct expr *key)
+{
+ const struct datatype *dtype = key->dtype;
+
+ if (dtype->byteorder == key->byteorder)
+ return;
+
+ key->dtype = set_datatype_alloc(dtype, key->byteorder);
+ if (dtype->flags & DTYPE_F_ALLOC)
+ concat_type_destroy(dtype);
+}
+
static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
const char *name,
struct expr *key,
@@ -69,11 +81,12 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
struct set *set;
struct handle h;
+ key_fix_dtype_byteorder(key);
+
set = set_alloc(&expr->location);
set->flags = NFT_SET_ANONYMOUS | expr->set_flags;
- set->handle.set = xstrdup(name),
- set->keytype = set_datatype_alloc(key->dtype, key->byteorder);
- set->keylen = key->len;
+ set->handle.set = xstrdup(name);
+ set->key = key;
set->init = expr;
if (ctx->table != NULL)
@@ -1204,8 +1217,6 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
mappings = implicit_set_declaration(ctx, "__map%d",
key,
mappings);
- expr_free(key);
-
mappings->set->datatype = set_datatype_alloc(ectx.dtype,
ectx.byteorder);
mappings->set->datalen = ectx.len;
@@ -1232,11 +1243,11 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
map->mappings->ops->name);
}
- if (!datatype_equal(map->map->dtype, map->mappings->set->keytype))
+ if (!datatype_equal(map->map->dtype, map->mappings->set->key->dtype))
return expr_binary_error(ctx->msgs, map->mappings, map->map,
"datatype mismatch, map expects %s, "
"mapping expression has type %s",
- map->mappings->set->keytype->desc,
+ map->mappings->set->key->dtype->desc,
map->map->dtype->desc);
map->dtype = map->mappings->set->datatype;
@@ -1261,7 +1272,7 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
if (!(set->flags & (NFT_SET_MAP | NFT_SET_OBJECT)))
return set_error(ctx, set, "set is not a map");
- expr_set_context(&ctx->ectx, set->keytype, set->keylen);
+ expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
if (expr_evaluate(ctx, &mapping->left) < 0)
return -1;
if (!expr_is_constant(mapping->left))
@@ -2589,9 +2600,9 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
"Expression does not refer to a set");
if (stmt_evaluate_arg(ctx, stmt,
- stmt->set.set->set->keytype,
- stmt->set.set->set->keylen,
- stmt->set.set->set->keytype->byteorder,
+ stmt->set.set->set->key->dtype,
+ stmt->set.set->set->key->len,
+ stmt->set.set->set->key->byteorder,
&stmt->set.key) < 0)
return -1;
if (expr_is_constant(stmt->set.key))
@@ -2629,8 +2640,6 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
mappings = implicit_set_declaration(ctx, "__objmap%d",
key, mappings);
- expr_free(key);
-
mappings->set->datatype = &string_type;
mappings->set->datalen = NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE;
mappings->set->objtype = stmt->objref.type;
@@ -2657,11 +2666,11 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
map->mappings->ops->name);
}
- if (!datatype_equal(map->map->dtype, map->mappings->set->keytype))
+ if (!datatype_equal(map->map->dtype, map->mappings->set->key->dtype))
return expr_binary_error(ctx->msgs, map->mappings, map->map,
"datatype mismatch, map expects %s, "
"mapping expression has type %s",
- map->mappings->set->keytype->desc,
+ map->mappings->set->key->dtype->desc,
map->map->dtype->desc);
map->dtype = map->mappings->set->datatype;
@@ -2765,7 +2774,7 @@ static int setelem_evaluate(struct eval_ctx *ctx, struct expr **expr)
ctx->cmd->handle.set);
ctx->set = set;
- expr_set_context(&ctx->ectx, set->keytype, set->keylen);
+ expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
if (expr_evaluate(ctx, expr) < 0)
return -1;
ctx->set = NULL;
@@ -2784,15 +2793,20 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
type = set->flags & NFT_SET_MAP ? "map" : "set";
- if (set->keytype == NULL)
- return set_error(ctx, set, "%s definition does not specify "
- "key data type", type);
+ if (set->key == NULL)
+ return set_error(ctx, set, "%s definition does not specify key",
+ type);
- set->keylen = set->keytype->size;
- if (set->keylen == 0)
- return set_error(ctx, set, "unqualified key data type "
- "specified in %s definition", type);
+ if (set->key->len == 0) {
+ if (set->key->ops->type == EXPR_CONCAT &&
+ expr_evaluate_concat(ctx, &set->key) < 0)
+ return -1;
+ if (set->key->len == 0)
+ return set_error(ctx, set, "unqualified key type %s "
+ "specified in %s definition",
+ set->key->dtype->name, type);
+ }
if (set->flags & NFT_SET_MAP) {
if (set->datatype == NULL)
return set_error(ctx, set, "map definition does not "
@@ -2809,7 +2823,7 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
ctx->set = set;
if (set->init != NULL) {
- expr_set_context(&ctx->ectx, set->keytype, set->keylen);
+ expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
if (expr_evaluate(ctx, &set->init) < 0)
return -1;
}
diff --git a/src/expression.c b/src/expression.c
index d41ada39..ff3550c7 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -832,7 +832,7 @@ struct expr *set_expr_alloc(const struct location *loc, const struct set *set)
return set_expr;
set_expr->set_flags = set->flags;
- set_expr->dtype = set->keytype;
+ set_expr->dtype = set->key->dtype;
return set_expr;
}
@@ -960,7 +960,7 @@ struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set)
{
struct expr *expr;
- expr = expr_alloc(loc, &set_ref_expr_ops, set->keytype, 0, 0);
+ expr = expr_alloc(loc, &set_ref_expr_ops, set->key->dtype, 0, 0);
expr->set = set_get(set);
expr->flags |= EXPR_F_CONSTANT;
return expr;
diff --git a/src/netlink.c b/src/netlink.c
index 291bbdee..e414718b 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1118,8 +1118,11 @@ static struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
set->handle.table = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_TABLE));
set->handle.set = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_NAME));
- set->keytype = set_datatype_alloc(keytype, keybyteorder);
- set->keylen = nftnl_set_get_u32(nls, NFTNL_SET_KEY_LEN) * BITS_PER_BYTE;
+ set->key = constant_expr_alloc(&netlink_location,
+ set_datatype_alloc(keytype, keybyteorder),
+ keybyteorder,
+ nftnl_set_get_u32(nls, NFTNL_SET_KEY_LEN) * BITS_PER_BYTE,
+ NULL);
set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
set->objtype = objtype;
@@ -1158,9 +1161,9 @@ static int netlink_add_set_compat(struct netlink_ctx *ctx,
nls = alloc_nftnl_set(h);
nftnl_set_set_u32(nls, NFTNL_SET_FLAGS, set->flags);
nftnl_set_set_u32(nls, NFTNL_SET_KEY_TYPE,
- dtype_map_to_kernel(set->keytype));
+ dtype_map_to_kernel(set->key->dtype));
nftnl_set_set_u32(nls, NFTNL_SET_KEY_LEN,
- div_round_up(set->keylen, BITS_PER_BYTE));
+ div_round_up(set->key->len, BITS_PER_BYTE));
if (set->flags & NFT_SET_MAP) {
nftnl_set_set_u32(nls, NFTNL_SET_DATA_TYPE,
dtype_map_to_kernel(set->datatype));
@@ -1192,9 +1195,9 @@ static int netlink_add_set_batch(struct netlink_ctx *ctx,
nls = alloc_nftnl_set(h);
nftnl_set_set_u32(nls, NFTNL_SET_FLAGS, set->flags);
nftnl_set_set_u32(nls, NFTNL_SET_KEY_TYPE,
- dtype_map_to_kernel(set->keytype));
+ dtype_map_to_kernel(set->key->dtype));
nftnl_set_set_u32(nls, NFTNL_SET_KEY_LEN,
- div_round_up(set->keylen, BITS_PER_BYTE));
+ div_round_up(set->key->len, BITS_PER_BYTE));
if (set->flags & NFT_SET_MAP) {
nftnl_set_set_u32(nls, NFTNL_SET_DATA_TYPE,
dtype_map_to_kernel(set->datatype));
@@ -1226,7 +1229,7 @@ static int netlink_add_set_batch(struct netlink_ctx *ctx,
if (!udbuf)
memory_allocation_error();
if (!nftnl_udata_put_u32(udbuf, UDATA_SET_KEYBYTEORDER,
- set->keytype->byteorder))
+ set->key->byteorder))
memory_allocation_error();
if (set->flags & NFT_SET_MAP &&
@@ -1537,10 +1540,10 @@ static int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
flags = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_FLAGS);
key = netlink_alloc_value(&netlink_location, &nld);
- key->dtype = set->keytype;
- key->byteorder = set->keytype->byteorder;
- if (set->keytype->subtypes)
- key = netlink_parse_concat_elem(set->keytype, key);
+ key->dtype = set->key->dtype;
+ key->byteorder = set->key->byteorder;
+ if (set->key->dtype->subtypes)
+ key = netlink_parse_concat_elem(set->key->dtype, key);
if (!(set->flags & NFT_SET_INTERVAL) &&
key->byteorder == BYTEORDER_HOST_ENDIAN)
@@ -2197,7 +2200,7 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
* used by named sets, so use a dummy set.
*/
dummyset = set_alloc(monh->loc);
- dummyset->keytype = set->keytype;
+ dummyset->key = expr_clone(set->key);
dummyset->datatype = set->datatype;
dummyset->flags = set->flags;
dummyset->init = set_expr_alloc(monh->loc, set);
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 3f42d092..42206ebc 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -307,8 +307,8 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
return netlink_error(ctx, loc,
"Lookup expression has no left hand side");
- if (left->len < set->keylen) {
- left = netlink_parse_concat_expr(ctx, loc, sreg, set->keylen);
+ if (left->len < set->key->len) {
+ left = netlink_parse_concat_expr(ctx, loc, sreg, set->key->len);
if (left == NULL)
return;
}
@@ -1122,8 +1122,8 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
return netlink_error(ctx, loc,
"Dynset statement has no key expression");
- if (expr->len < set->keylen) {
- expr = netlink_parse_concat_expr(ctx, loc, sreg, set->keylen);
+ if (expr->len < set->key->len) {
+ expr = netlink_parse_concat_expr(ctx, loc, sreg, set->key->len);
if (expr == NULL)
return;
}
@@ -1193,8 +1193,8 @@ static void netlink_parse_objref(struct netlink_parse_ctx *ctx,
return netlink_error(ctx, loc,
"objref expression has no left hand side");
- if (left->len < set->keylen) {
- left = netlink_parse_concat_expr(ctx, loc, sreg, set->keylen);
+ if (left->len < set->key->len) {
+ left = netlink_parse_concat_expr(ctx, loc, sreg, set->key->len);
if (left == NULL)
return;
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 970d773e..c7ba1495 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -478,8 +478,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <val> time_spec quota_used
-%type <val> type_identifier_list
-%type <datatype> data_type
+%type <expr> data_type_expr data_type_atom_expr
+%destructor { expr_free($$); } data_type_expr data_type_atom_expr
%type <cmd> line
%destructor { cmd_free($$); } line
@@ -1405,9 +1405,9 @@ set_block_alloc : /* empty */
set_block : /* empty */ { $$ = $<set>-1; }
| set_block common_block
| set_block stmt_separator
- | set_block TYPE data_type stmt_separator
+ | set_block TYPE data_type_expr stmt_separator
{
- $1->keytype = $3;
+ $1->key = $3;
$$ = $1;
}
| set_block FLAGS set_flag_list stmt_separator
@@ -1459,28 +1459,30 @@ map_block : /* empty */ { $$ = $<set>-1; }
| map_block common_block
| map_block stmt_separator
| map_block TYPE
- data_type COLON data_type
+ data_type_expr COLON data_type_expr
stmt_separator
{
- $1->keytype = $3;
- $1->datatype = $5;
+ $1->key = $3;
+ $1->datatype = $5->dtype;
+
+ expr_free($5);
$1->flags |= NFT_SET_MAP;
$$ = $1;
}
| map_block TYPE
- data_type COLON COUNTER
+ data_type_expr COLON COUNTER
stmt_separator
{
- $1->keytype = $3;
+ $1->key = $3;
$1->objtype = NFT_OBJECT_COUNTER;
$1->flags |= NFT_SET_OBJECT;
$$ = $1;
}
| map_block TYPE
- data_type COLON QUOTA
+ data_type_expr COLON QUOTA
stmt_separator
{
- $1->keytype = $3;
+ $1->key = $3;
$1->objtype = NFT_OBJECT_QUOTA;
$1->flags |= NFT_SET_OBJECT;
$$ = $1;
@@ -1512,16 +1514,7 @@ set_policy_spec : PERFORMANCE { $$ = NFT_SET_POL_PERFORMANCE; }
| MEMORY { $$ = NFT_SET_POL_MEMORY; }
;
-data_type : type_identifier_list
- {
- if ($1 & ~TYPE_MASK)
- $$ = concat_type_alloc($1);
- else
- $$ = datatype_lookup($1);
- }
- ;
-
-type_identifier_list : type_identifier
+data_type_atom_expr : type_identifier
{
const struct datatype *dtype = datatype_lookup_byname($1);
if (dtype == NULL) {
@@ -1530,20 +1523,28 @@ type_identifier_list : type_identifier
xfree($1);
YYERROR;
}
- xfree($1);
- $$ = dtype->type;
+ $$ = constant_expr_alloc(&@1, dtype, dtype->byteorder,
+ dtype->size, NULL);
}
- | type_identifier_list DOT type_identifier
+ ;
+
+data_type_expr : data_type_atom_expr
+ | data_type_expr DOT data_type_atom_expr
{
- const struct datatype *dtype = datatype_lookup_byname($3);
- if (dtype == NULL) {
- erec_queue(error(&@3, "unknown datatype %s", $3),
- state->msgs);
- xfree($3);
- YYERROR;
+ if ($1->ops->type != EXPR_CONCAT) {
+ $$ = concat_expr_alloc(&@$);
+ compound_expr_add($$, $1);
+ } else {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+ location_update(&$3->location, rhs, 2);
+
+ $$ = $1;
+ $$->location = @$;
}
- xfree($3);
- $$ = concat_subtype_add($$, dtype->type);
+ compound_expr_add($$, $3);
}
;
diff --git a/src/rule.c b/src/rule.c
index 8f0e752f..1e0558ea 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -215,7 +215,7 @@ void set_free(struct set *set)
if (set->init != NULL)
expr_free(set->init);
handle_free(&set->handle);
- set_datatype_destroy(set->keytype);
+ expr_free(set->key);
set_datatype_destroy(set->datatype);
xfree(set);
}
@@ -296,7 +296,7 @@ static void set_print_declaration(const struct set *set,
printf(" %s {%s", set->handle.set, opts->nl);
- printf("%s%stype %s", opts->tab, opts->tab, set->keytype->name);
+ printf("%s%stype %s", opts->tab, opts->tab, set->key->dtype->name);
if (set->flags & NFT_SET_MAP)
printf(" : %s", set->datatype->name);
else if (set->flags & NFT_SET_OBJECT)
diff --git a/src/segtree.c b/src/segtree.c
index f81e1174..f0efd155 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -76,8 +76,8 @@ static void seg_tree_init(struct seg_tree *tree, const struct set *set,
first = list_entry(init->expressions.next, struct expr, list);
tree->root = RB_ROOT;
- tree->keytype = set->keytype;
- tree->keylen = set->keylen;
+ tree->keytype = set->key->dtype;
+ tree->keylen = set->key->len;
tree->datatype = set->datatype;
tree->datalen = set->datalen;
tree->byteorder = first->byteorder;