summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/datatype.h7
-rw-r--r--include/expression.h2
-rw-r--r--src/ct.c6
-rw-r--r--src/datatype.c46
-rw-r--r--src/evaluate.c37
-rw-r--r--src/expression.c13
-rw-r--r--src/exthdr.c4
-rw-r--r--src/netlink.c7
-rw-r--r--src/netlink_delinearize.c20
-rw-r--r--src/parser_bison.y6
-rw-r--r--src/parser_json.c3
-rw-r--r--src/rt.c4
-rw-r--r--src/rule.c2
-rw-r--r--src/tcpopt.c4
14 files changed, 96 insertions, 65 deletions
diff --git a/include/datatype.h b/include/datatype.h
index 14ece282..23f45ab7 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -117,12 +117,10 @@ struct expr;
*
* @DTYPE_F_ALLOC: datatype is dynamically allocated
* @DTYPE_F_PREFIX: preferred representation for ranges is a prefix
- * @DTYPE_F_CLONE: this is an instance from original datatype
*/
enum datatype_flags {
DTYPE_F_ALLOC = (1 << 0),
DTYPE_F_PREFIX = (1 << 1),
- DTYPE_F_CLONE = (1 << 2),
};
/**
@@ -140,6 +138,7 @@ enum datatype_flags {
* @print: function to print a constant of this type
* @parse: function to parse a symbol and return an expression
* @sym_tbl: symbol table for this type
+ * @refcnt: reference counter (only for DTYPE_F_ALLOC)
*/
struct datatype {
uint32_t type;
@@ -158,10 +157,14 @@ struct datatype {
struct error_record *(*parse)(const struct expr *sym,
struct expr **res);
const struct symbol_table *sym_tbl;
+ unsigned int refcnt;
};
extern const struct datatype *datatype_lookup(enum datatypes type);
extern const struct datatype *datatype_lookup_byname(const char *name);
+extern struct datatype *datatype_get(const struct datatype *dtype);
+extern void datatype_set(struct expr *expr, const struct datatype *dtype);
+extern void datatype_free(const struct datatype *dtype);
extern struct error_record *symbol_parse(const struct expr *sym,
struct expr **res);
diff --git a/include/expression.h b/include/expression.h
index ef412554..4de53682 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -415,7 +415,7 @@ static inline void symbol_expr_set_type(struct expr *expr,
const struct datatype *dtype)
{
if (expr->etype == EXPR_SYMBOL)
- expr->dtype = dtype;
+ datatype_set(expr, dtype);
}
struct expr *variable_expr_alloc(const struct location *loc,
diff --git a/src/ct.c b/src/ct.c
index 2256ce32..72346cd5 100644
--- a/src/ct.c
+++ b/src/ct.c
@@ -413,10 +413,10 @@ void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr)
case NFT_CT_SRC:
case NFT_CT_DST:
if (desc == &proto_ip) {
- expr->dtype = &ipaddr_type;
+ datatype_set(expr, &ipaddr_type);
expr->ct.nfproto = NFPROTO_IPV4;
} else if (desc == &proto_ip6) {
- expr->dtype = &ip6addr_type;
+ datatype_set(expr, &ip6addr_type);
expr->ct.nfproto = NFPROTO_IPV6;
}
@@ -426,7 +426,7 @@ void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr)
case NFT_CT_PROTO_DST:
if (desc == NULL)
break;
- expr->dtype = &inet_service_type;
+ datatype_set(expr, &inet_service_type);
break;
default:
break;
diff --git a/src/datatype.c b/src/datatype.c
index 1d5ed6f7..43cf45bd 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -1076,6 +1076,25 @@ static struct datatype *dtype_alloc(void)
return dtype;
}
+struct datatype *datatype_get(const struct datatype *ptr)
+{
+ struct datatype *dtype = (struct datatype *)ptr;
+
+ if (!dtype)
+ return NULL;
+ if (!(dtype->flags & DTYPE_F_ALLOC))
+ return dtype;
+
+ dtype->refcnt++;
+ return dtype;
+}
+
+void datatype_set(struct expr *expr, const struct datatype *dtype)
+{
+ datatype_free(expr->dtype);
+ expr->dtype = datatype_get(dtype);
+}
+
static struct datatype *dtype_clone(const struct datatype *orig_dtype)
{
struct datatype *dtype;
@@ -1084,18 +1103,26 @@ static struct datatype *dtype_clone(const struct datatype *orig_dtype)
*dtype = *orig_dtype;
dtype->name = xstrdup(orig_dtype->name);
dtype->desc = xstrdup(orig_dtype->desc);
- dtype->flags = DTYPE_F_ALLOC | DTYPE_F_CLONE;
+ dtype->flags = DTYPE_F_ALLOC;
+ dtype->refcnt = 0;
return dtype;
}
-static void dtype_free(const struct datatype *dtype)
+void datatype_free(const struct datatype *ptr)
{
- if (dtype->flags & DTYPE_F_ALLOC) {
- xfree(dtype->name);
- xfree(dtype->desc);
- xfree(dtype);
- }
+ struct datatype *dtype = (struct datatype *)ptr;
+
+ if (!dtype)
+ return;
+ if (!(dtype->flags & DTYPE_F_ALLOC))
+ return;
+ if (--dtype->refcnt > 0)
+ return;
+
+ xfree(dtype->name);
+ xfree(dtype->desc);
+ xfree(dtype);
}
const struct datatype *concat_type_alloc(uint32_t type)
@@ -1137,7 +1164,7 @@ const struct datatype *concat_type_alloc(uint32_t type)
void concat_type_destroy(const struct datatype *dtype)
{
- dtype_free(dtype);
+ datatype_free(dtype);
}
const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype,
@@ -1157,8 +1184,7 @@ const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype,
void set_datatype_destroy(const struct datatype *dtype)
{
- if (dtype && dtype->flags & DTYPE_F_CLONE)
- dtype_free(dtype);
+ datatype_free(dtype);
}
static struct error_record *time_unit_parse(const struct location *loc,
diff --git a/src/evaluate.c b/src/evaluate.c
index 39101b48..4a06c7e8 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -70,7 +70,7 @@ static void key_fix_dtype_byteorder(struct expr *key)
if (dtype->byteorder == key->byteorder)
return;
- key->dtype = set_datatype_alloc(dtype, key->byteorder);
+ datatype_set(key, set_datatype_alloc(dtype, key->byteorder));
if (dtype->flags & DTYPE_F_ALLOC)
concat_type_destroy(dtype);
}
@@ -229,7 +229,7 @@ static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
switch ((*expr)->symtype) {
case SYMBOL_VALUE:
- (*expr)->dtype = ctx->ectx.dtype;
+ datatype_set(*expr, ctx->ectx.dtype);
erec = symbol_parse(*expr, &new);
if (erec != NULL) {
erec_queue(erec, ctx->msgs);
@@ -312,7 +312,7 @@ static int expr_evaluate_string(struct eval_ctx *ctx, struct expr **exprp)
prefix = prefix_expr_alloc(&expr->location, value,
datalen * BITS_PER_BYTE);
- prefix->dtype = ctx->ectx.dtype;
+ datatype_set(prefix, ctx->ectx.dtype);
prefix->flags |= EXPR_F_CONSTANT;
prefix->byteorder = BYTEORDER_HOST_ENDIAN;
@@ -489,7 +489,7 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
struct expr *expr = *exprp;
if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
- expr->dtype = &boolean_type;
+ datatype_set(expr, &boolean_type);
if (expr_evaluate_primary(ctx, exprp) < 0)
return -1;
@@ -915,7 +915,7 @@ static int expr_evaluate_range(struct eval_ctx *ctx, struct expr **expr)
return expr_error(ctx->msgs, range,
"Range has zero or negative size");
- range->dtype = left->dtype;
+ datatype_set(range, left->dtype);
range->flags |= EXPR_F_CONSTANT;
return 0;
}
@@ -1172,7 +1172,7 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr,
}
(*expr)->flags |= flags;
- (*expr)->dtype = concat_type_alloc(ntype);
+ datatype_set(*expr, concat_type_alloc(ntype));
(*expr)->len = (*expr)->dtype->size;
if (off > 0)
@@ -1239,7 +1239,7 @@ static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
}
}
- elem->dtype = elem->key->dtype;
+ datatype_set(elem, elem->key->dtype);
elem->len = elem->key->len;
elem->flags = elem->key->flags;
return 0;
@@ -1285,7 +1285,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
set->set_flags |= NFT_SET_CONSTANT;
- set->dtype = ctx->ectx.dtype;
+ datatype_set(set, ctx->ectx.dtype);
set->len = ctx->ectx.len;
set->flags |= EXPR_F_CONSTANT;
return 0;
@@ -1311,15 +1311,16 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
switch (map->mappings->etype) {
case EXPR_SET:
key = constant_expr_alloc(&map->location,
- ctx->ectx.dtype,
- ctx->ectx.byteorder,
- ctx->ectx.len, NULL);
+ ctx->ectx.dtype,
+ ctx->ectx.byteorder,
+ ctx->ectx.len, NULL);
mappings = implicit_set_declaration(ctx, "__map%d",
key,
mappings);
- mappings->set->datatype = set_datatype_alloc(ectx.dtype,
- ectx.byteorder);
+ mappings->set->datatype =
+ datatype_get(set_datatype_alloc(ectx.dtype,
+ ectx.byteorder));
mappings->set->datalen = ectx.len;
map->mappings = mappings;
@@ -1356,7 +1357,7 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
map->mappings->set->key->dtype->desc,
map->map->dtype->desc);
- map->dtype = map->mappings->set->datatype;
+ datatype_set(map, map->mappings->set->datatype);
map->flags |= EXPR_F_CONSTANT;
/* Data for range lookups needs to be in big endian order */
@@ -1413,7 +1414,7 @@ static void expr_dtype_integer_compatible(struct eval_ctx *ctx,
if (ctx->ectx.dtype &&
ctx->ectx.dtype->basetype == &integer_type &&
ctx->ectx.len == 4 * BITS_PER_BYTE) {
- expr->dtype = ctx->ectx.dtype;
+ datatype_set(expr, ctx->ectx.dtype);
expr->len = ctx->ectx.len;
}
}
@@ -1554,7 +1555,7 @@ static void binop_transfer_handle_lhs(struct expr **expr)
case OP_LSHIFT:
case OP_XOR:
tmp = expr_get(left->left);
- tmp->dtype = left->dtype;
+ datatype_set(tmp, left->dtype);
expr_free(left);
*expr = tmp;
break;
@@ -1745,7 +1746,7 @@ static int expr_evaluate_fib(struct eval_ctx *ctx, struct expr **exprp)
if (expr->flags & EXPR_F_BOOLEAN) {
expr->fib.flags |= NFTA_FIB_F_PRESENT;
- expr->dtype = &boolean_type;
+ datatype_set(expr, &boolean_type);
}
return expr_evaluate_primary(ctx, exprp);
}
@@ -2965,7 +2966,7 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
map->mappings->set->key->dtype->desc,
map->map->dtype->desc);
- map->dtype = map->mappings->set->datatype;
+ datatype_set(map, map->mappings->set->datatype);
map->flags |= EXPR_F_CONSTANT;
/* Data for range lookups needs to be in big endian order */
diff --git a/src/expression.c b/src/expression.c
index ef694f2a..5d0b4f82 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -44,7 +44,7 @@ struct expr *expr_alloc(const struct location *loc, enum expr_types etype,
expr = xzalloc(sizeof(*expr));
expr->location = *loc;
- expr->dtype = dtype;
+ expr->dtype = datatype_get(dtype);
expr->etype = etype;
expr->byteorder = byteorder;
expr->len = len;
@@ -57,8 +57,8 @@ struct expr *expr_clone(const struct expr *expr)
{
struct expr *new;
- new = expr_alloc(&expr->location, expr->etype, expr->dtype,
- expr->byteorder, expr->len);
+ new = expr_alloc(&expr->location, expr->etype,
+ expr->dtype, expr->byteorder, expr->len);
new->flags = expr->flags;
new->op = expr->op;
expr_ops(expr)->clone(new, expr);
@@ -86,6 +86,8 @@ void expr_free(struct expr *expr)
if (--expr->refcnt > 0)
return;
+ datatype_free(expr->dtype);
+
/* EXPR_INVALID expressions lack ->ops structure.
* This happens for compound types.
*/
@@ -165,7 +167,7 @@ void expr_set_type(struct expr *expr, const struct datatype *dtype,
if (ops->set_type)
ops->set_type(expr, dtype, byteorder);
else {
- expr->dtype = dtype;
+ datatype_set(expr, dtype);
expr->byteorder = byteorder;
}
}
@@ -803,7 +805,6 @@ void compound_expr_remove(struct expr *compound, struct expr *expr)
static void concat_expr_destroy(struct expr *expr)
{
- concat_type_destroy(expr->dtype);
compound_expr_destroy(expr);
}
@@ -936,7 +937,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->key->dtype;
+ datatype_set(set_expr, set->key->dtype);
return set_expr;
}
diff --git a/src/exthdr.c b/src/exthdr.c
index 0cd03198..c9c2bf50 100644
--- a/src/exthdr.c
+++ b/src/exthdr.c
@@ -206,9 +206,9 @@ void exthdr_init_raw(struct expr *expr, uint8_t type,
out:
expr->exthdr.tmpl = tmpl;
if (flags & NFT_EXTHDR_F_PRESENT)
- expr->dtype = &boolean_type;
+ datatype_set(expr, &boolean_type);
else
- expr->dtype = tmpl->dtype;
+ datatype_set(expr, tmpl->dtype);
}
static unsigned int mask_length(const struct expr *mask)
diff --git a/src/netlink.c b/src/netlink.c
index 7a431249..a6d81b4f 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -617,7 +617,8 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
set->objtype = objtype;
if (datatype)
- set->datatype = set_datatype_alloc(datatype, databyteorder);
+ set->datatype = datatype_get(set_datatype_alloc(datatype,
+ databyteorder));
else
set->datatype = NULL;
@@ -767,7 +768,7 @@ 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->key->dtype;
+ datatype_set(key, set->key->dtype);
key->byteorder = set->key->byteorder;
if (set->key->dtype->subtypes)
key = netlink_parse_concat_elem(set->key->dtype, key);
@@ -811,7 +812,7 @@ int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
data = netlink_alloc_data(&netlink_location, &nld,
set->datatype->type == TYPE_VERDICT ?
NFT_REG_VERDICT : NFT_REG_1);
- data->dtype = set->datatype;
+ datatype_set(data, set->datatype);
data->byteorder = set->datatype->byteorder;
if (data->byteorder == BYTEORDER_HOST_ENDIAN)
mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 0270e1fd..6576687c 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1389,7 +1389,7 @@ static void netlink_parse_objref(struct netlink_parse_ctx *ctx,
nld.value = nftnl_expr_get(nle, NFTNL_EXPR_OBJREF_IMM_NAME,
&nld.len);
expr = netlink_alloc_value(&netlink_location, &nld);
- expr->dtype = &string_type;
+ datatype_set(expr, &string_type);
expr->byteorder = BYTEORDER_HOST_ENDIAN;
} else if (nftnl_expr_is_set(nle, NFTNL_EXPR_OBJREF_SET_SREG)) {
struct expr *left, *right;
@@ -2064,7 +2064,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
ntype = concat_subtype_add(ntype, i->dtype->type);
}
- expr->dtype = concat_type_alloc(ntype);
+ datatype_set(expr, concat_type_alloc(ntype));
break;
}
case EXPR_UNARY:
@@ -2165,7 +2165,7 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx)
switch (rctx->pctx.family) {
case NFPROTO_IPV4:
stmt->reject.family = rctx->pctx.family;
- stmt->reject.expr->dtype = &icmp_code_type;
+ datatype_set(stmt->reject.expr, &icmp_code_type);
if (stmt->reject.type == NFT_REJECT_TCP_RST &&
payload_dependency_exists(&rctx->pdctx,
PROTO_BASE_TRANSPORT_HDR))
@@ -2173,7 +2173,7 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx)
break;
case NFPROTO_IPV6:
stmt->reject.family = rctx->pctx.family;
- stmt->reject.expr->dtype = &icmpv6_code_type;
+ datatype_set(stmt->reject.expr, &icmpv6_code_type);
if (stmt->reject.type == NFT_REJECT_TCP_RST &&
payload_dependency_exists(&rctx->pdctx,
PROTO_BASE_TRANSPORT_HDR))
@@ -2181,7 +2181,7 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx)
break;
case NFPROTO_INET:
if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH) {
- stmt->reject.expr->dtype = &icmpx_code_type;
+ datatype_set(stmt->reject.expr, &icmpx_code_type);
break;
}
base = rctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
@@ -2189,17 +2189,17 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx)
protocol = proto_find_num(base, desc);
switch (protocol) {
case NFPROTO_IPV4:
- stmt->reject.expr->dtype = &icmp_code_type;
+ datatype_set(stmt->reject.expr, &icmp_code_type);
break;
case NFPROTO_IPV6:
- stmt->reject.expr->dtype = &icmpv6_code_type;
+ datatype_set(stmt->reject.expr, &icmpv6_code_type);
break;
}
stmt->reject.family = protocol;
break;
case NFPROTO_BRIDGE:
if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH) {
- stmt->reject.expr->dtype = &icmpx_code_type;
+ datatype_set(stmt->reject.expr, &icmpx_code_type);
break;
}
base = rctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
@@ -2208,11 +2208,11 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx)
switch (protocol) {
case __constant_htons(ETH_P_IP):
stmt->reject.family = NFPROTO_IPV4;
- stmt->reject.expr->dtype = &icmp_code_type;
+ datatype_set(stmt->reject.expr, &icmp_code_type);
break;
case __constant_htons(ETH_P_IPV6):
stmt->reject.family = NFPROTO_IPV6;
- stmt->reject.expr->dtype = &icmpv6_code_type;
+ datatype_set(stmt->reject.expr, &icmpv6_code_type);
break;
default:
break;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 97a48f38..1c0b60cf 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -2598,7 +2598,7 @@ reject_opts : /* empty */
symbol_expr_alloc(&@$, SYMBOL_VALUE,
current_scope(state),
$4);
- $<stmt>0->reject.expr->dtype = &icmp_code_type;
+ datatype_set($<stmt>0->reject.expr, &icmp_code_type);
xfree($4);
}
| WITH ICMP6 TYPE STRING
@@ -2609,7 +2609,7 @@ reject_opts : /* empty */
symbol_expr_alloc(&@$, SYMBOL_VALUE,
current_scope(state),
$4);
- $<stmt>0->reject.expr->dtype = &icmpv6_code_type;
+ datatype_set($<stmt>0->reject.expr, &icmpv6_code_type);
xfree($4);
}
| WITH ICMPX TYPE STRING
@@ -2619,7 +2619,7 @@ reject_opts : /* empty */
symbol_expr_alloc(&@$, SYMBOL_VALUE,
current_scope(state),
$4);
- $<stmt>0->reject.expr->dtype = &icmpx_code_type;
+ datatype_set($<stmt>0->reject.expr, &icmpx_code_type);
xfree($4);
}
| WITH TCP RESET
diff --git a/src/parser_json.c b/src/parser_json.c
index ac110f16..af7701fc 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -1966,8 +1966,7 @@ static struct stmt *json_parse_reject_stmt(struct json_ctx *ctx,
stmt_free(stmt);
return NULL;
}
- if (dtype)
- stmt->reject.expr->dtype = dtype;
+ datatype_set(stmt->reject.expr, dtype);
}
return stmt;
}
diff --git a/src/rt.c b/src/rt.c
index 090831fe..3ad77bcd 100644
--- a/src/rt.c
+++ b/src/rt.c
@@ -148,10 +148,10 @@ void rt_expr_update_type(struct proto_ctx *ctx, struct expr *expr)
case NFT_RT_NEXTHOP4:
desc = ctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
if (desc == &proto_ip)
- expr->dtype = &ipaddr_type;
+ datatype_set(expr, &ipaddr_type);
else if (desc == &proto_ip6) {
expr->rt.key++;
- expr->dtype = &ip6addr_type;
+ datatype_set(expr, &ip6addr_type);
}
expr->len = expr->dtype->size;
break;
diff --git a/src/rule.c b/src/rule.c
index ad549b1e..7eb89a00 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -341,7 +341,7 @@ struct set *set_clone(const struct set *set)
new_set->gc_int = set->gc_int;
new_set->timeout = set->timeout;
new_set->key = expr_clone(set->key);
- new_set->datatype = set->datatype;
+ new_set->datatype = datatype_get(set->datatype);
new_set->datalen = set->datalen;
new_set->objtype = set->objtype;
new_set->policy = set->policy;
diff --git a/src/tcpopt.c b/src/tcpopt.c
index 6920ff94..ec305d94 100644
--- a/src/tcpopt.c
+++ b/src/tcpopt.c
@@ -218,9 +218,9 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
continue;
if (flags & NFT_EXTHDR_F_PRESENT)
- expr->dtype = &boolean_type;
+ datatype_set(expr, &boolean_type);
else
- expr->dtype = tmpl->dtype;
+ datatype_set(expr, tmpl->dtype);
expr->exthdr.tmpl = tmpl;
expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
break;