The flow statement contains a statement within the statement, in order to parse it we need to return the parsed statement instead of adding it to the rule list unconditionally. Signed-off-by: Patrick McHardy <kaber@xxxxxxxxx> --- include/netlink.h | 2 +- src/netlink_delinearize.c | 64 +++++++++++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/include/netlink.h b/include/netlink.h index 8444742..c1def09 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -84,7 +84,7 @@ extern void netlink_linearize_rule(struct netlink_ctx *ctx, struct nftnl_rule *nlr, const struct rule *rule); extern struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx, - const struct nftnl_rule *r); + struct nftnl_rule *r); extern int netlink_add_rule(struct netlink_ctx *ctx, const struct handle *h, const struct rule *rule, uint32_t flags); diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 3584de7..97ac3ec 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -30,6 +30,7 @@ struct netlink_parse_ctx { struct list_head *msgs; struct table *table; struct rule *rule; + struct stmt *stmt; struct expr *registers[1 + NFT_REG32_15 - NFT_REG32_00 + 1]; }; @@ -167,7 +168,6 @@ static void netlink_parse_immediate(struct netlink_parse_ctx *ctx, { struct nft_data_delinearize nld; enum nft_registers dreg; - struct stmt *stmt; struct expr *expr; if (nftnl_expr_is_set(nle, NFTNL_EXPR_IMM_VERDICT)) { @@ -183,10 +183,9 @@ static void netlink_parse_immediate(struct netlink_parse_ctx *ctx, dreg = netlink_parse_register(nle, NFTNL_EXPR_IMM_DREG); expr = netlink_alloc_data(loc, &nld, dreg); - if (dreg == NFT_REG_VERDICT) { - stmt = verdict_stmt_alloc(loc, expr); - list_add_tail(&stmt->list, &ctx->rule->stmts); - } else + if (dreg == NFT_REG_VERDICT) + ctx->stmt = verdict_stmt_alloc(loc, expr); + else netlink_set_register(ctx, dreg, expr); } @@ -217,7 +216,6 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx, struct nft_data_delinearize nld; enum nft_registers sreg; struct expr *expr, *left, *right; - struct stmt *stmt; enum ops op; sreg = netlink_parse_register(nle, NFTNL_EXPR_CMP_SREG); @@ -246,8 +244,7 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx, } expr = relational_expr_alloc(loc, op, left, right); - stmt = expr_stmt_alloc(loc, expr); - list_add_tail(&stmt->list, &ctx->rule->stmts); + ctx->stmt = expr_stmt_alloc(loc, expr); } static void netlink_parse_lookup(struct netlink_parse_ctx *ctx, @@ -256,7 +253,6 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx, { enum nft_registers sreg, dreg; const char *name; - struct stmt *stmt; struct expr *expr, *left, *right; struct set *set; @@ -290,8 +286,7 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx, expr = relational_expr_alloc(loc, OP_LOOKUP, left, right); } - stmt = expr_stmt_alloc(loc, expr); - list_add_tail(&stmt->list, &ctx->rule->stmts); + ctx->stmt = expr_stmt_alloc(loc, expr); } static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx, @@ -467,7 +462,7 @@ static void netlink_parse_meta_stmt(struct netlink_parse_ctx *ctx, stmt = meta_stmt_alloc(loc, key, expr); expr_set_type(expr, stmt->meta.tmpl->dtype, stmt->meta.tmpl->byteorder); - list_add_tail(&stmt->list, &ctx->rule->stmts); + ctx->stmt = stmt; } static void netlink_parse_meta(struct netlink_parse_ctx *ctx, @@ -496,7 +491,7 @@ static void netlink_parse_ct_stmt(struct netlink_parse_ctx *ctx, stmt = ct_stmt_alloc(loc, key, expr); expr_set_type(expr, stmt->ct.tmpl->dtype, stmt->ct.tmpl->byteorder); - list_add_tail(&stmt->list, &ctx->rule->stmts); + ctx->stmt = stmt; } static void netlink_parse_ct_expr(struct netlink_parse_ctx *ctx, @@ -535,7 +530,8 @@ static void netlink_parse_counter(struct netlink_parse_ctx *ctx, nftnl_expr_get_u64(nle, NFTNL_EXPR_CTR_PACKETS); stmt->counter.bytes = nftnl_expr_get_u64(nle, NFTNL_EXPR_CTR_BYTES); - list_add_tail(&stmt->list, &ctx->rule->stmts); + + ctx->stmt = stmt; } static void netlink_parse_log(struct netlink_parse_ctx *ctx, @@ -571,7 +567,8 @@ static void netlink_parse_log(struct netlink_parse_ctx *ctx, nftnl_expr_get_u32(nle, NFTNL_EXPR_LOG_LEVEL); stmt->log.flags |= STMT_LOG_LEVEL; } - list_add_tail(&stmt->list, &ctx->rule->stmts); + + ctx->stmt = stmt; } static void netlink_parse_limit(struct netlink_parse_ctx *ctx, @@ -585,7 +582,8 @@ static void netlink_parse_limit(struct netlink_parse_ctx *ctx, stmt->limit.unit = nftnl_expr_get_u64(nle, NFTNL_EXPR_LIMIT_UNIT); stmt->limit.type = nftnl_expr_get_u32(nle, NFTNL_EXPR_LIMIT_TYPE); stmt->limit.burst = nftnl_expr_get_u32(nle, NFTNL_EXPR_LIMIT_BURST); - list_add_tail(&stmt->list, &ctx->rule->stmts); + + ctx->stmt = stmt; } static void netlink_parse_reject(struct netlink_parse_ctx *ctx, @@ -602,7 +600,7 @@ static void netlink_parse_reject(struct netlink_parse_ctx *ctx, stmt->reject.expr = constant_expr_alloc(loc, &integer_type, BYTEORDER_HOST_ENDIAN, 8, &icmp_code); - list_add_tail(&stmt->list, &ctx->rule->stmts); + ctx->stmt = stmt; } static void netlink_parse_nat(struct netlink_parse_ctx *ctx, @@ -683,7 +681,7 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx, stmt->nat.proto = proto; } - list_add_tail(&stmt->list, &ctx->rule->stmts); + ctx->stmt = stmt; } static void netlink_parse_masq(struct netlink_parse_ctx *ctx, @@ -700,7 +698,7 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx, stmt = masq_stmt_alloc(loc); stmt->masq.flags = flags; - list_add_tail(&stmt->list, &ctx->rule->stmts); + ctx->stmt = stmt; } static void netlink_parse_redir(struct netlink_parse_ctx *ctx, @@ -746,7 +744,7 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx, stmt->redir.proto = proto; } - list_add_tail(&stmt->list, &ctx->rule->stmts); + ctx->stmt = stmt; } static void netlink_parse_dup(struct netlink_parse_ctx *ctx, @@ -792,7 +790,7 @@ static void netlink_parse_dup(struct netlink_parse_ctx *ctx, stmt->dup.dev = dev; } - list_add_tail(&stmt->list, &ctx->rule->stmts); + ctx->stmt = stmt; } static void netlink_parse_queue(struct netlink_parse_ctx *ctx, @@ -818,7 +816,8 @@ static void netlink_parse_queue(struct netlink_parse_ctx *ctx, stmt = queue_stmt_alloc(loc); stmt->queue.queue = expr; stmt->queue.flags = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_FLAGS); - list_add_tail(&stmt->list, &ctx->rule->stmts); + + ctx->stmt = stmt; } static void netlink_parse_dynset(struct netlink_parse_ctx *ctx, @@ -858,7 +857,7 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx, stmt->set.op = nftnl_expr_get_u32(nle, NFTNL_EXPR_DYNSET_OP); stmt->set.key = expr; - list_add_tail(&stmt->list, &ctx->rule->stmts); + ctx->stmt = stmt; } static const struct { @@ -907,6 +906,21 @@ static int netlink_parse_expr(struct nftnl_expr *nle, void *arg) } netlink_error(ctx, &loc, "unknown expression type '%s'", type); + return -1; +} + +static int netlink_parse_rule_expr(struct nftnl_expr *nle, void *arg) +{ + struct netlink_parse_ctx *ctx = arg; + int err; + + err = netlink_parse_expr(nle, ctx); + if (err < 0) + return err; + if (ctx->stmt != NULL) { + list_add_tail(&ctx->stmt->list, &ctx->rule->stmts); + ctx->stmt = NULL; + } return 0; } @@ -1592,7 +1606,7 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r } struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx, - const struct nftnl_rule *nlr) + struct nftnl_rule *nlr) { struct netlink_parse_ctx _ctx, *pctx = &_ctx; struct handle h; @@ -1622,7 +1636,7 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx, pctx->rule = rule_alloc(&netlink_location, &h); pctx->table = table_lookup(&h); assert(pctx->table != NULL); - nftnl_expr_foreach((struct nftnl_rule *)nlr, netlink_parse_expr, pctx); + nftnl_expr_foreach(nlr, netlink_parse_rule_expr, pctx); rule_parse_postprocess(pctx, pctx->rule); netlink_release_registers(pctx); -- 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html