*
* @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),
};
/**
* @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;
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);
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,
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;
}
case NFT_CT_PROTO_DST:
if (desc == NULL)
break;
- expr->dtype = &inet_service_type;
+ datatype_set(expr, &inet_service_type);
break;
default:
break;
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;
*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)
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,
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,
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);
}
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);
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;
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;
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;
}
}
(*expr)->flags |= flags;
- (*expr)->dtype = concat_type_alloc(ntype);
+ datatype_set(*expr, concat_type_alloc(ntype));
(*expr)->len = (*expr)->dtype->size;
if (off > 0)
}
}
- elem->dtype = elem->key->dtype;
+ datatype_set(elem, elem->key->dtype);
elem->len = elem->key->len;
elem->flags = elem->key->flags;
return 0;
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;
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;
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 */
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;
}
}
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;
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);
}
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 */
expr = xzalloc(sizeof(*expr));
expr->location = *loc;
- expr->dtype = dtype;
+ expr->dtype = datatype_get(dtype);
expr->etype = etype;
expr->byteorder = byteorder;
expr->len = len;
{
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);
if (--expr->refcnt > 0)
return;
+ datatype_free(expr->dtype);
+
/* EXPR_INVALID expressions lack ->ops structure.
* This happens for compound types.
*/
if (ops->set_type)
ops->set_type(expr, dtype, byteorder);
else {
- expr->dtype = dtype;
+ datatype_set(expr, dtype);
expr->byteorder = byteorder;
}
}
static void concat_expr_destroy(struct expr *expr)
{
- concat_type_destroy(expr->dtype);
compound_expr_destroy(expr);
}
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;
}
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)
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;
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);
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);
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;
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:
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))
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))
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;
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;
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;
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
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
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
stmt_free(stmt);
return NULL;
}
- if (dtype)
- stmt->reject.expr->dtype = dtype;
+ datatype_set(stmt->reject.expr, dtype);
}
return stmt;
}
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;
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;
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;