summaryrefslogtreecommitdiffstats
path: root/src/netlink_linearize.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/netlink_linearize.c')
-rw-r--r--src/netlink_linearize.c492
1 files changed, 376 insertions, 116 deletions
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 08f7f89f..6204d8fd 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -9,9 +9,11 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nf_log.h>
-#include <string.h>
#include <rule.h>
#include <statement.h>
#include <expression.h>
@@ -23,11 +25,34 @@
#include <linux/netfilter.h>
#include <libnftnl/udata.h>
+struct nft_expr_loc *nft_expr_loc_find(const struct nftnl_expr *nle,
+ struct netlink_linearize_ctx *ctx)
+{
+ struct nft_expr_loc *eloc;
+ uint32_t hash;
+
+ hash = (uint64_t)nle % NFT_EXPR_LOC_HSIZE;
+ list_for_each_entry(eloc, &ctx->expr_loc_htable[hash], hlist) {
+ if (eloc->nle == nle)
+ return eloc;
+ }
+
+ return NULL;
+}
-struct netlink_linearize_ctx {
- struct nftnl_rule *nlr;
- unsigned int reg_low;
-};
+static void nft_expr_loc_add(const struct nftnl_expr *nle,
+ const struct location *loc,
+ struct netlink_linearize_ctx *ctx)
+{
+ struct nft_expr_loc *eloc;
+ uint32_t hash;
+
+ eloc = xmalloc(sizeof(*eloc));
+ eloc->nle = nle;
+ eloc->loc = loc;
+ hash = (uint64_t)nle % NFT_EXPR_LOC_HSIZE;
+ list_add_tail(&eloc->hlist, &ctx->expr_loc_htable[hash]);
+}
static void netlink_put_register(struct nftnl_expr *nle,
uint32_t attr, uint32_t reg)
@@ -104,6 +129,14 @@ static void netlink_gen_concat(struct netlink_linearize_ctx *ctx,
}
}
+static void nft_rule_add_expr(struct netlink_linearize_ctx *ctx,
+ struct nftnl_expr *nle,
+ const struct location *loc)
+{
+ nft_expr_loc_add(nle, loc, ctx);
+ nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
static void netlink_gen_fib(struct netlink_linearize_ctx *ctx,
const struct expr *expr,
enum nft_registers dreg)
@@ -115,7 +148,7 @@ static void netlink_gen_fib(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_FIB_RESULT, expr->fib.result);
nftnl_expr_set_u32(nle, NFTNL_EXPR_FIB_FLAGS, expr->fib.flags);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_hash(struct netlink_linearize_ctx *ctx,
@@ -143,12 +176,11 @@ static void netlink_gen_hash(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_SEED, expr->hash.seed);
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_OFFSET, expr->hash.offset);
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_TYPE, expr->hash.type);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
-static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
- const struct expr *expr,
- enum nft_registers dreg)
+static struct nftnl_expr *
+__netlink_gen_payload(const struct expr *expr, enum nft_registers dreg)
{
struct nftnl_expr *nle;
@@ -161,26 +193,92 @@ static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_LEN,
div_round_up(expr->len, BITS_PER_BYTE));
- nftnl_rule_add_expr(ctx->nlr, nle);
+ return nle;
+}
+
+static struct nftnl_expr *
+__netlink_gen_meta(const struct expr *expr, enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("meta");
+ netlink_put_register(nle, NFTNL_EXPR_META_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, expr->meta.key);
+
+ return nle;
+}
+
+static struct nftnl_expr *netlink_gen_inner_expr(const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct expr *_expr = (struct expr *)expr;
+ struct nftnl_expr *nle;
+
+ switch (expr->etype) {
+ case EXPR_PAYLOAD:
+ if (expr->payload.base == NFT_PAYLOAD_INNER_HEADER + 1)
+ _expr->payload.base = NFT_PAYLOAD_TUN_HEADER + 1;
+
+ nle = __netlink_gen_payload(expr, dreg);
+ break;
+ case EXPR_META:
+ nle = __netlink_gen_meta(expr, dreg);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ return nle;
+}
+
+static void netlink_gen_inner(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg,
+ const struct proto_desc *desc)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("inner");
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_HDRSIZE, desc->inner.hdrsize);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_FLAGS, desc->inner.flags);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_TYPE, desc->inner.type);
+ nftnl_expr_set(nle, NFTNL_EXPR_INNER_EXPR, netlink_gen_inner_expr(expr, dreg), 0);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ if (expr->payload.inner_desc) {
+ netlink_gen_inner(ctx, expr, dreg, expr->payload.inner_desc);
+ return;
+ }
+
+ nle = __netlink_gen_payload(expr, dreg);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx,
const struct expr *expr,
enum nft_registers dreg)
{
- unsigned int offset = expr->exthdr.tmpl->offset + expr->exthdr.offset;
+ unsigned int offset = expr->exthdr.offset;
struct nftnl_expr *nle;
nle = alloc_nft_expr("exthdr");
netlink_put_register(nle, NFTNL_EXPR_EXTHDR_DREG, dreg);
nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
- expr->exthdr.desc->type);
+ expr->exthdr.raw_type);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
div_round_up(expr->len, BITS_PER_BYTE));
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_FLAGS, expr->exthdr.flags);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_meta(struct netlink_linearize_ctx *ctx,
@@ -189,10 +287,13 @@ static void netlink_gen_meta(struct netlink_linearize_ctx *ctx,
{
struct nftnl_expr *nle;
- nle = alloc_nft_expr("meta");
- netlink_put_register(nle, NFTNL_EXPR_META_DREG, dreg);
- nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, expr->meta.key);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ if (expr->meta.inner_desc) {
+ netlink_gen_inner(ctx, expr, dreg, expr->meta.inner_desc);
+ return;
+ }
+
+ nle = __netlink_gen_meta(expr, dreg);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_rt(struct netlink_linearize_ctx *ctx,
@@ -204,7 +305,7 @@ static void netlink_gen_rt(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("rt");
netlink_put_register(nle, NFTNL_EXPR_RT_DREG, dreg);
nftnl_expr_set_u32(nle, NFTNL_EXPR_RT_KEY, expr->rt.key);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_socket(struct netlink_linearize_ctx *ctx,
@@ -216,7 +317,8 @@ static void netlink_gen_socket(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("socket");
netlink_put_register(nle, NFTNL_EXPR_SOCKET_DREG, dreg);
nftnl_expr_set_u32(nle, NFTNL_EXPR_SOCKET_KEY, expr->socket.key);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_SOCKET_LEVEL, expr->socket.level);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_osf(struct netlink_linearize_ctx *ctx,
@@ -229,7 +331,7 @@ static void netlink_gen_osf(struct netlink_linearize_ctx *ctx,
netlink_put_register(nle, NFTNL_EXPR_OSF_DREG, dreg);
nftnl_expr_set_u8(nle, NFTNL_EXPR_OSF_TTL, expr->osf.ttl);
nftnl_expr_set_u32(nle, NFTNL_EXPR_OSF_FLAGS, expr->osf.flags);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_numgen(struct netlink_linearize_ctx *ctx,
@@ -243,7 +345,7 @@ static void netlink_gen_numgen(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_TYPE, expr->numgen.type);
nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_MODULUS, expr->numgen.mod);
nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_OFFSET, expr->numgen.offset);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_ct(struct netlink_linearize_ctx *ctx,
@@ -259,7 +361,7 @@ static void netlink_gen_ct(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u8(nle, NFTNL_EXPR_CT_DIR,
expr->ct.direction);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
@@ -297,7 +399,7 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
if (dreg == NFT_REG_VERDICT)
release_register(ctx, expr->map);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
@@ -323,7 +425,7 @@ static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_FLAGS, NFT_LOOKUP_F_INV);
release_register(ctx, expr->left);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static enum nft_cmp_ops netlink_gen_cmp_op(enum ops op)
@@ -358,7 +460,8 @@ static struct expr *netlink_gen_prefix(struct netlink_linearize_ctx *ctx,
mpz_init(mask);
mpz_prefixmask(mask, expr->right->len, expr->right->prefix_len);
netlink_gen_raw_data(mask, expr->right->byteorder,
- expr->right->len / BITS_PER_BYTE, &nld);
+ div_round_up(expr->right->len, BITS_PER_BYTE),
+ &nld);
mpz_clear(mask);
zero.len = nld.len;
@@ -369,7 +472,7 @@ static struct expr *netlink_gen_prefix(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, nld.len);
nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld.value, nld.len);
nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &zero.value, zero.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
return expr->right->prefix;
}
@@ -399,7 +502,7 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
netlink_gen_data(range->right, &nld);
nftnl_expr_set(nle, NFTNL_EXPR_RANGE_TO_DATA,
nld.value, nld.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
break;
case OP_EQ:
case OP_IMPLICIT:
@@ -409,7 +512,7 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
netlink_gen_cmp_op(OP_GTE));
netlink_gen_data(range->left, &nld);
nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
nle = alloc_nft_expr("cmp");
netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
@@ -417,7 +520,7 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
netlink_gen_cmp_op(OP_LTE));
netlink_gen_data(range->right, &nld);
nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
break;
default:
BUG("invalid range operation %u\n", expr->op);
@@ -448,19 +551,31 @@ static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
netlink_gen_raw_data(zero, expr->right->byteorder, len, &nld);
netlink_gen_data(expr->right, &nld2);
- nle = alloc_nft_expr("bitwise");
- netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, sreg);
- netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, sreg);
- nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
- nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld2.value, nld2.len);
- nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &nld.value, nld.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ if (expr->left->etype == EXPR_BINOP) {
+ nle = alloc_nft_expr("cmp");
+ netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
+ nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld2.value, nld2.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+ } else {
+ nle = alloc_nft_expr("bitwise");
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, sreg);
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld2.value, nld2.len);
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &nld.value, nld.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
- nle = alloc_nft_expr("cmp");
- netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
- nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_NEQ);
- nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nle = alloc_nft_expr("cmp");
+ netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
+ if (expr->op == OP_NEG)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
+ else
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_NEQ);
+
+ nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+ }
mpz_clear(zero);
release_register(ctx, expr->left);
@@ -486,6 +601,7 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
case OP_GT:
case OP_LTE:
case OP_GTE:
+ case OP_NEG:
break;
default:
BUG("invalid relational operation %u\n", expr->op);
@@ -501,7 +617,10 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
return netlink_gen_flagcmp(ctx, expr, dreg);
case EXPR_PREFIX:
sreg = get_register(ctx, expr->left);
- if (expr_basetype(expr->left)->type != TYPE_STRING) {
+ if (expr_basetype(expr->left)->type != TYPE_STRING &&
+ (expr->right->byteorder != BYTEORDER_BIG_ENDIAN ||
+ !expr->right->prefix_len ||
+ expr->right->prefix_len % BITS_PER_BYTE)) {
len = div_round_up(expr->right->len, BITS_PER_BYTE);
netlink_gen_expr(ctx, expr->left, sreg);
right = netlink_gen_prefix(ctx, expr, sreg);
@@ -513,7 +632,7 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
}
break;
default:
- if (expr->op == OP_IMPLICIT &&
+ if ((expr->op == OP_IMPLICIT || expr->op == OP_NEG) &&
expr->right->dtype->basetype != NULL &&
expr->right->dtype->basetype->type == TYPE_BITMASK)
return netlink_gen_flagcmp(ctx, expr, dreg);
@@ -533,7 +652,7 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, len);
release_register(ctx, expr->left);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void combine_binop(mpz_t mask, mpz_t xor, const mpz_t m, const mpz_t x)
@@ -569,17 +688,17 @@ static void netlink_gen_shift(struct netlink_linearize_ctx *ctx,
nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_DATA, nld.value,
nld.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx,
const struct expr *expr,
enum nft_registers dreg)
{
+ struct expr *binops[NFT_MAX_EXPR_RECURSION];
struct nftnl_expr *nle;
struct nft_data_linearize nld;
struct expr *left, *i;
- struct expr *binops[16];
mpz_t mask, xor, val, tmp;
unsigned int len;
int n = 0;
@@ -591,16 +710,18 @@ static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx,
binops[n++] = left = (struct expr *) expr;
while (left->etype == EXPR_BINOP && left->left != NULL &&
- (left->op == OP_AND || left->op == OP_OR || left->op == OP_XOR))
+ (left->op == OP_AND || left->op == OP_OR || left->op == OP_XOR)) {
+ if (n == array_size(binops))
+ BUG("NFT_MAX_EXPR_RECURSION limit reached");
binops[n++] = left = left->left;
- n--;
+ }
- netlink_gen_expr(ctx, binops[n--], dreg);
+ netlink_gen_expr(ctx, binops[--n], dreg);
mpz_bitmask(mask, expr->len);
mpz_set_ui(xor, 0);
- for (; n >= 0; n--) {
- i = binops[n];
+ while (n > 0) {
+ i = binops[--n];
mpz_set(val, i->right->value);
switch (i->op) {
@@ -639,7 +760,7 @@ static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx,
mpz_clear(xor);
mpz_clear(mask);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
@@ -676,6 +797,8 @@ static void netlink_gen_unary(struct netlink_linearize_ctx *ctx,
struct nftnl_expr *nle;
int byte_size;
+ assert(div_round_up(expr->arg->len, BITS_PER_BYTE) != 1);
+
if ((expr->arg->len % 64) == 0)
byte_size = 8;
else if ((expr->arg->len % 32) == 0)
@@ -689,20 +812,21 @@ static void netlink_gen_unary(struct netlink_linearize_ctx *ctx,
netlink_put_register(nle, NFTNL_EXPR_BYTEORDER_SREG, dreg);
netlink_put_register(nle, NFTNL_EXPR_BYTEORDER_DREG, dreg);
nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_LEN,
- expr->len / BITS_PER_BYTE);
+ div_round_up(expr->len, BITS_PER_BYTE));
nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_SIZE,
byte_size);
nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_OP,
netlink_gen_unary_op(expr->op));
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_immediate(struct netlink_linearize_ctx *ctx,
const struct expr *expr,
enum nft_registers dreg)
{
- struct nftnl_expr *nle;
+ const struct location *loc = &expr->location;
struct nft_data_linearize nld;
+ struct nftnl_expr *nle;
nle = alloc_nft_expr("immediate");
netlink_put_register(nle, NFTNL_EXPR_IMM_DREG, dreg);
@@ -712,17 +836,20 @@ static void netlink_gen_immediate(struct netlink_linearize_ctx *ctx,
nftnl_expr_set(nle, NFTNL_EXPR_IMM_DATA, nld.value, nld.len);
break;
case EXPR_VERDICT:
- if ((expr->chain != NULL) &&
- !nftnl_expr_is_set(nle, NFTNL_EXPR_IMM_CHAIN)) {
+ if (expr->chain) {
nftnl_expr_set_str(nle, NFTNL_EXPR_IMM_CHAIN,
nld.chain);
+ loc = &expr->chain->location;
+ } else if (expr->chain_id) {
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_IMM_CHAIN_ID,
+ nld.chain_id);
}
nftnl_expr_set_u32(nle, NFTNL_EXPR_IMM_VERDICT, nld.verdict);
break;
default:
break;
}
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, loc);
}
static void netlink_gen_xfrm(struct netlink_linearize_ctx *ctx,
@@ -736,7 +863,7 @@ static void netlink_gen_xfrm(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_XFRM_KEY, expr->xfrm.key);
nftnl_expr_set_u8(nle, NFTNL_EXPR_XFRM_DIR, expr->xfrm.direction);
nftnl_expr_set_u32(nle, NFTNL_EXPR_XFRM_SPNUM, expr->xfrm.spnum);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
@@ -819,7 +946,7 @@ static void netlink_gen_objref_stmt(struct netlink_linearize_ctx *ctx,
default:
BUG("unsupported expression %u\n", expr->etype);
}
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static struct nftnl_expr *netlink_gen_connlimit_stmt(const struct stmt *stmt)
@@ -880,6 +1007,17 @@ static struct nftnl_expr *netlink_gen_quota_stmt(const struct stmt *stmt)
return nle;
}
+static struct nftnl_expr *netlink_gen_last_stmt(const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("last");
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LAST_SET, stmt->last.set);
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_LAST_MSECS, stmt->last.used);
+
+ return nle;
+}
+
struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt)
{
switch (stmt->ops->type) {
@@ -891,6 +1029,8 @@ struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt)
return netlink_gen_limit_stmt(stmt);
case STMT_QUOTA:
return netlink_gen_quota_stmt(stmt);
+ case STMT_LAST:
+ return netlink_gen_last_stmt(stmt);
default:
BUG("unknown stateful statement type %s\n", stmt->ops->name);
}
@@ -928,17 +1068,17 @@ static void netlink_gen_exthdr_stmt(struct netlink_linearize_ctx *ctx,
expr = stmt->exthdr.expr;
- offset = expr->exthdr.tmpl->offset + expr->exthdr.offset;
+ offset = expr->exthdr.offset;
nle = alloc_nft_expr("exthdr");
netlink_put_register(nle, NFTNL_EXPR_EXTHDR_SREG, sreg);
nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
- expr->exthdr.desc->type);
+ expr->exthdr.raw_type);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
div_round_up(expr->len, BITS_PER_BYTE));
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx,
@@ -971,16 +1111,17 @@ static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx,
expr->len / BITS_PER_BYTE);
if (csum_off) {
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_CSUM_TYPE,
- NFT_PAYLOAD_CSUM_INET);
+ desc->checksum_type);
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_CSUM_OFFSET,
csum_off / BITS_PER_BYTE);
}
- if (expr->payload.base == PROTO_BASE_NETWORK_HDR && desc &&
- payload_needs_l4csum_update_pseudohdr(expr, desc))
+ if ((expr->payload.base == PROTO_BASE_NETWORK_HDR && desc &&
+ payload_needs_l4csum_update_pseudohdr(expr, desc)) ||
+ expr->payload.base == PROTO_BASE_INNER_HDR)
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_FLAGS,
NFT_PAYLOAD_L4CSUM_PSEUDOHDR);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_meta_stmt(struct netlink_linearize_ctx *ctx,
@@ -996,7 +1137,7 @@ static void netlink_gen_meta_stmt(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("meta");
netlink_put_register(nle, NFTNL_EXPR_META_SREG, sreg);
nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, stmt->meta.key);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx,
@@ -1006,8 +1147,10 @@ static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("log");
if (stmt->log.prefix != NULL) {
- nftnl_expr_set_str(nle, NFTNL_EXPR_LOG_PREFIX,
- stmt->log.prefix);
+ char prefix[NF_LOG_PREFIXLEN] = {};
+
+ expr_to_string(stmt->log.prefix, prefix);
+ nftnl_expr_set_str(nle, NFTNL_EXPR_LOG_PREFIX, prefix);
}
if (stmt->log.flags & STMT_LOG_GROUP) {
nftnl_expr_set_u16(nle, NFTNL_EXPR_LOG_GROUP, stmt->log.group);
@@ -1025,7 +1168,7 @@ static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOG_FLAGS,
stmt->log.logflags);
}
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx,
@@ -1039,7 +1182,7 @@ static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u8(nle, NFTNL_EXPR_REJECT_CODE,
stmt->reject.icmp_code);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static unsigned int nat_addrlen(uint8_t family)
@@ -1119,11 +1262,14 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
amin_reg);
if (stmt->nat.addr->etype == EXPR_MAP &&
stmt->nat.addr->mappings->set->data->flags & EXPR_F_INTERVAL) {
- amax_reg = get_register(ctx, NULL);
- registers++;
amin_reg += netlink_register_space(nat_addrlen(family));
- netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX,
- amin_reg);
+ if (stmt->nat.type_flags & STMT_NAT_F_CONCAT) {
+ netlink_put_register(nle, nftnl_reg_pmin,
+ amin_reg);
+ } else {
+ netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX,
+ amin_reg);
+ }
}
}
@@ -1135,6 +1281,12 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
pmin_reg = amin_reg;
+ if (stmt->nat.type_flags & STMT_NAT_F_INTERVAL) {
+ pmin_reg += netlink_register_space(nat_addrlen(family));
+ netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX,
+ pmin_reg);
+ }
+
/* if STMT_NAT_F_CONCAT is set, the mapped type is a
* concatenation of 'addr . inet_service'.
* The map lookup will then return the
@@ -1143,7 +1295,10 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
* will hold the inet_service part.
*/
pmin_reg += netlink_register_space(nat_addrlen(family));
- netlink_put_register(nle, nftnl_reg_pmin, pmin_reg);
+ if (stmt->nat.type_flags & STMT_NAT_F_INTERVAL)
+ netlink_put_register(nle, nftnl_reg_pmax, pmin_reg);
+ else
+ netlink_put_register(nle, nftnl_reg_pmin, pmin_reg);
}
}
@@ -1170,7 +1325,7 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
registers--;
}
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_tproxy_stmt(struct netlink_linearize_ctx *ctx,
@@ -1209,7 +1364,7 @@ static void netlink_gen_tproxy_stmt(struct netlink_linearize_ctx *ctx,
registers--;
}
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_synproxy_stmt(struct netlink_linearize_ctx *ctx,
@@ -1224,7 +1379,7 @@ static void netlink_gen_synproxy_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_SYNPROXY_FLAGS,
stmt->synproxy.flags);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_dup_stmt(struct netlink_linearize_ctx *ctx,
@@ -1255,7 +1410,7 @@ static void netlink_gen_dup_stmt(struct netlink_linearize_ctx *ctx,
if (stmt->dup.to != NULL)
release_register(ctx, stmt->dup.to);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_fwd_stmt(struct netlink_linearize_ctx *ctx,
@@ -1282,32 +1437,62 @@ static void netlink_gen_fwd_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_FWD_NFPROTO,
stmt->fwd.family);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_optstrip_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle = alloc_nft_expr("exthdr");
+ struct expr *expr = stmt->optstrip.expr;
+
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
+ expr->exthdr.raw_type);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_queue_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
+ enum nft_registers sreg = 0;
struct nftnl_expr *nle;
uint16_t total_queues;
+ struct expr *expr;
mpz_t low, high;
mpz_init2(low, 16);
mpz_init2(high, 16);
- if (stmt->queue.queue != NULL) {
- range_expr_value_low(low, stmt->queue.queue);
- range_expr_value_high(high, stmt->queue.queue);
+
+ expr = stmt->queue.queue;
+
+ if (expr) {
+ if (expr->etype == EXPR_RANGE || expr->etype == EXPR_VALUE) {
+ range_expr_value_low(low, stmt->queue.queue);
+ range_expr_value_high(high, stmt->queue.queue);
+ } else {
+ sreg = get_register(ctx, expr);
+ netlink_gen_expr(ctx, expr, sreg);
+ release_register(ctx, expr);
+ }
}
+
total_queues = mpz_get_uint16(high) - mpz_get_uint16(low) + 1;
nle = alloc_nft_expr("queue");
- nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_NUM, mpz_get_uint16(low));
- nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_TOTAL, total_queues);
+
+ if (sreg) {
+ netlink_put_register(nle, NFTNL_EXPR_QUEUE_SREG_QNUM, sreg);
+ } else {
+ nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_NUM, mpz_get_uint16(low));
+ nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_TOTAL, total_queues);
+ }
+
if (stmt->queue.flags)
nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_FLAGS,
stmt->queue.flags);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
mpz_clear(low);
mpz_clear(high);
@@ -1330,7 +1515,7 @@ static void netlink_gen_ct_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u8(nle, NFTNL_EXPR_CT_DIR,
stmt->ct.direction);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_notrack_stmt(struct netlink_linearize_ctx *ctx,
@@ -1339,7 +1524,7 @@ static void netlink_gen_notrack_stmt(struct netlink_linearize_ctx *ctx,
struct nftnl_expr *nle;
nle = alloc_nft_expr("notrack");
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_flow_offload_stmt(struct netlink_linearize_ctx *ctx,
@@ -1350,15 +1535,17 @@ static void netlink_gen_flow_offload_stmt(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("flow_offload");
nftnl_expr_set_str(nle, NFTNL_EXPR_FLOW_TABLE_NAME,
stmt->flow.table_name);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
struct set *set = stmt->meter.set->set;
- struct nftnl_expr *nle;
enum nft_registers sreg_key;
+ struct nftnl_expr *nle;
+ int num_stmts = 0;
+ struct stmt *this;
sreg_key = get_register(ctx, stmt->set.key->key);
netlink_gen_expr(ctx, stmt->set.key->key, sreg_key);
@@ -1372,11 +1559,24 @@ static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_OP, stmt->set.op);
nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
- if (stmt->set.stmt)
- nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
- netlink_gen_stmt_stateful(stmt->set.stmt), 0);
+ list_for_each_entry(this, &stmt->set.stmt_list, list)
+ num_stmts++;
+
+ if (num_stmts == 1) {
+ list_for_each_entry(this, &stmt->set.stmt_list, list) {
+ nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
+ netlink_gen_stmt_stateful(this), 0);
+ }
+ } else if (num_stmts > 1) {
+ list_for_each_entry(this, &stmt->set.stmt_list, list) {
+ nftnl_expr_add_expr(nle, NFTNL_EXPR_DYNSET_EXPRESSIONS,
+ netlink_gen_stmt_stateful(this));
+ }
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_FLAGS,
+ NFT_DYNSET_F_EXPR);
+ }
}
static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
@@ -1386,14 +1586,16 @@ static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
enum nft_registers sreg_data;
enum nft_registers sreg_key;
struct nftnl_expr *nle;
+ int num_stmts = 0;
+ struct stmt *this;
- sreg_key = get_register(ctx, stmt->map.key);
- netlink_gen_expr(ctx, stmt->map.key, sreg_key);
+ sreg_key = get_register(ctx, stmt->map.key->key);
+ netlink_gen_expr(ctx, stmt->map.key->key, sreg_key);
sreg_data = get_register(ctx, stmt->map.data);
netlink_gen_expr(ctx, stmt->map.data, sreg_data);
- release_register(ctx, stmt->map.key);
+ release_register(ctx, stmt->map.key->key);
release_register(ctx, stmt->map.data);
nle = alloc_nft_expr("dynset");
@@ -1403,12 +1605,26 @@ static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_OP, stmt->map.op);
nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
- if (stmt->map.stmt)
- nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
- netlink_gen_stmt_stateful(stmt->map.stmt), 0);
+ if (stmt->map.key->timeout > 0)
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT,
+ stmt->map.key->timeout);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ list_for_each_entry(this, &stmt->map.stmt_list, list)
+ num_stmts++;
+
+ if (num_stmts == 1) {
+ list_for_each_entry(this, &stmt->map.stmt_list, list) {
+ nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
+ netlink_gen_stmt_stateful(this), 0);
+ }
+ } else if (num_stmts > 1) {
+ list_for_each_entry(this, &stmt->map.stmt_list, list) {
+ nftnl_expr_add_expr(nle, NFTNL_EXPR_DYNSET_EXPRESSIONS,
+ netlink_gen_stmt_stateful(this));
+ }
+ }
}
static void netlink_gen_meter_stmt(struct netlink_linearize_ctx *ctx,
@@ -1439,7 +1655,13 @@ static void netlink_gen_meter_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
netlink_gen_stmt_stateful(stmt->meter.stmt), 0);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_chain_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ return netlink_gen_expr(ctx, stmt->chain.expr, NFT_REG_VERDICT);
}
static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
@@ -1484,8 +1706,9 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
case STMT_COUNTER:
case STMT_LIMIT:
case STMT_QUOTA:
+ case STMT_LAST:
nle = netlink_gen_stmt_stateful(stmt);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
break;
case STMT_NOTRACK:
return netlink_gen_notrack_stmt(ctx, stmt);
@@ -1495,23 +1718,49 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
return netlink_gen_objref_stmt(ctx, stmt);
case STMT_MAP:
return netlink_gen_map_stmt(ctx, stmt);
+ case STMT_CHAIN:
+ return netlink_gen_chain_stmt(ctx, stmt);
+ case STMT_OPTSTRIP:
+ return netlink_gen_optstrip_stmt(ctx, stmt);
default:
BUG("unknown statement type %s\n", stmt->ops->name);
}
}
-void netlink_linearize_rule(struct netlink_ctx *ctx, struct nftnl_rule *nlr,
- const struct rule *rule)
+void netlink_linearize_init(struct netlink_linearize_ctx *lctx,
+ struct nftnl_rule *nlr)
{
- struct netlink_linearize_ctx lctx;
- const struct stmt *stmt;
+ int i;
+
+ memset(lctx, 0, sizeof(*lctx));
+ lctx->reg_low = NFT_REG_1;
+ lctx->nlr = nlr;
+ lctx->expr_loc_htable =
+ xmalloc(sizeof(struct list_head) * NFT_EXPR_LOC_HSIZE);
+ for (i = 0; i < NFT_EXPR_LOC_HSIZE; i++)
+ init_list_head(&lctx->expr_loc_htable[i]);
+}
- memset(&lctx, 0, sizeof(lctx));
- lctx.reg_low = NFT_REG_1;
- lctx.nlr = nlr;
+void netlink_linearize_fini(struct netlink_linearize_ctx *lctx)
+{
+ struct nft_expr_loc *eloc, *next;
+ int i;
+
+ for (i = 0; i < NFT_EXPR_LOC_HSIZE; i++) {
+ list_for_each_entry_safe(eloc, next, &lctx->expr_loc_htable[i], hlist)
+ free(eloc);
+ }
+ free(lctx->expr_loc_htable);
+}
+
+void netlink_linearize_rule(struct netlink_ctx *ctx,
+ const struct rule *rule,
+ struct netlink_linearize_ctx *lctx)
+{
+ const struct stmt *stmt;
list_for_each_entry(stmt, &rule->stmts, list)
- netlink_gen_stmt(&lctx, stmt);
+ netlink_gen_stmt(lctx, stmt);
if (rule->comment) {
struct nftnl_udata_buf *udata;
@@ -1523,12 +1772,23 @@ void netlink_linearize_rule(struct netlink_ctx *ctx, struct nftnl_rule *nlr,
if (!nftnl_udata_put_strz(udata, NFTNL_UDATA_RULE_COMMENT,
rule->comment))
memory_allocation_error();
- nftnl_rule_set_data(nlr, NFTNL_RULE_USERDATA,
+ nftnl_rule_set_data(lctx->nlr, NFTNL_RULE_USERDATA,
nftnl_udata_buf_data(udata),
nftnl_udata_buf_len(udata));
nftnl_udata_buf_free(udata);
}
- netlink_dump_rule(nlr, ctx);
+ if (ctx->nft->debug_mask & NFT_DEBUG_NETLINK) {
+ nftnl_rule_set_str(lctx->nlr, NFTNL_RULE_TABLE,
+ rule->handle.table.name);
+ if (rule->handle.chain.name)
+ nftnl_rule_set_str(lctx->nlr, NFTNL_RULE_CHAIN,
+ rule->handle.chain.name);
+
+ netlink_dump_rule(lctx->nlr, ctx);
+
+ nftnl_rule_unset(lctx->nlr, NFTNL_RULE_CHAIN);
+ nftnl_rule_unset(lctx->nlr, NFTNL_RULE_TABLE);
+ }
}