Change the payload-dependency context to store a dependency for every protocol layer. This allows us to eliminate more redundant protocol expressions. --- include/payload.h | 13 +++++------ src/netlink_delinearize.c | 16 ++++++++----- src/payload.c | 49 ++++++++++++++++++++++++--------------- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/include/payload.h b/include/payload.h index 10ae9fe4f9c5..8341f4e67183 100644 --- a/include/payload.h +++ b/include/payload.h @@ -25,16 +25,14 @@ extern int exthdr_gen_dependency(struct eval_ctx *ctx, const struct expr *expr, /** * struct payload_dep_ctx - payload protocol dependency tracking * - * @pbase: protocol base of last dependency match * @icmp_type: extra info for icmp(6) decoding - * @pdep: last dependency match * @prev: previous statement + * @pdeps: last dependency match per protocol layer */ struct payload_dep_ctx { - enum proto_bases pbase:8; - uint8_t icmp_type; - struct stmt *pdep; - struct stmt *prev; + uint8_t icmp_type; + struct stmt *prev; + struct stmt *pdeps[PROTO_BASE_MAX + 1]; }; extern bool payload_is_known(const struct expr *expr); @@ -49,7 +47,8 @@ extern bool payload_dependency_exists(const struct payload_dep_ctx *ctx, enum proto_bases base); extern struct stmt *payload_dependency_get(struct payload_dep_ctx *ctx, enum proto_bases base); -extern void payload_dependency_release(struct payload_dep_ctx *ctx); +extern void payload_dependency_release(struct payload_dep_ctx *ctx, + enum proto_bases base); extern void payload_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr, unsigned int family); extern void exthdr_dependency_kill(struct payload_dep_ctx *ctx, diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 2a62b309be1d..10b1e5fbd000 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -2062,7 +2062,7 @@ static bool meta_may_dependency_kill(struct payload_dep_ctx *ctx, uint8_t l4proto, nfproto = NFPROTO_UNSPEC; struct expr *dep; - if (ctx->pbase != PROTO_BASE_NETWORK_HDR) + if (!payload_dependency_exists(ctx, PROTO_BASE_NETWORK_HDR)) return true; dep = payload_dependency_get(ctx, PROTO_BASE_NETWORK_HDR)->expr; @@ -2121,11 +2121,12 @@ static void ct_meta_common_postprocess(struct rule_pp_ctx *ctx, relational_expr_pctx_update(&ctx->pctx, expr); - if (ctx->pdctx.pbase < PROTO_BASE_TRANSPORT_HDR) { + if (base < PROTO_BASE_TRANSPORT_HDR) { if (payload_dependency_exists(&ctx->pdctx, base) && meta_may_dependency_kill(&ctx->pdctx, ctx->pctx.family, expr)) - payload_dependency_release(&ctx->pdctx); + payload_dependency_release(&ctx->pdctx, base); + if (left->flags & EXPR_F_PROTOCOL) payload_dependency_store(&ctx->pdctx, ctx->stmt, base); } @@ -2655,7 +2656,8 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx) if (stmt->reject.type == NFT_REJECT_TCP_RST && payload_dependency_exists(&rctx->pdctx, PROTO_BASE_TRANSPORT_HDR)) - payload_dependency_release(&rctx->pdctx); + payload_dependency_release(&rctx->pdctx, + PROTO_BASE_TRANSPORT_HDR); break; case NFPROTO_IPV6: stmt->reject.family = rctx->pctx.family; @@ -2663,7 +2665,8 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx) if (stmt->reject.type == NFT_REJECT_TCP_RST && payload_dependency_exists(&rctx->pdctx, PROTO_BASE_TRANSPORT_HDR)) - payload_dependency_release(&rctx->pdctx); + payload_dependency_release(&rctx->pdctx, + PROTO_BASE_TRANSPORT_HDR); break; case NFPROTO_INET: case NFPROTO_BRIDGE: @@ -2697,7 +2700,8 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx) } if (payload_dependency_exists(&rctx->pdctx, PROTO_BASE_NETWORK_HDR)) - payload_dependency_release(&rctx->pdctx); + payload_dependency_release(&rctx->pdctx, + PROTO_BASE_NETWORK_HDR); break; default: break; diff --git a/src/payload.c b/src/payload.c index 902b318ae23a..91eec112351d 100644 --- a/src/payload.c +++ b/src/payload.c @@ -610,8 +610,7 @@ void payload_dependency_store(struct payload_dep_ctx *ctx, if (ignore_dep) return; - ctx->pdep = stmt; - ctx->pbase = base + 1; + ctx->pdeps[base + 1] = stmt; } /** @@ -626,9 +625,11 @@ void payload_dependency_store(struct payload_dep_ctx *ctx, bool payload_dependency_exists(const struct payload_dep_ctx *ctx, enum proto_bases base) { - return ctx->pbase != PROTO_BASE_INVALID && - ctx->pdep != NULL && - (ctx->pbase == base || (base == PROTO_BASE_TRANSPORT_HDR && ctx->pbase == base + 1)); + if (ctx->pdeps[base]) + return true; + + return base == PROTO_BASE_TRANSPORT_HDR && + ctx->pdeps[PROTO_BASE_INNER_HDR]; } /** @@ -642,25 +643,35 @@ bool payload_dependency_exists(const struct payload_dep_ctx *ctx, struct stmt *payload_dependency_get(struct payload_dep_ctx *ctx, enum proto_bases base) { - if (ctx->pbase == base) - return ctx->pdep; + if (ctx->pdeps[base]) + return ctx->pdeps[base]; if (base == PROTO_BASE_TRANSPORT_HDR && - ctx->pbase == PROTO_BASE_INNER_HDR) - return ctx->pdep; + ctx->pdeps[PROTO_BASE_INNER_HDR]) + return ctx->pdeps[PROTO_BASE_INNER_HDR]; return NULL; } -void payload_dependency_release(struct payload_dep_ctx *ctx) +static void __payload_dependency_release(struct payload_dep_ctx *ctx, + enum proto_bases base) { - list_del(&ctx->pdep->list); - stmt_free(ctx->pdep); + list_del(&ctx->pdeps[base]->list); + stmt_free(ctx->pdeps[base]); - ctx->pbase = PROTO_BASE_INVALID; - if (ctx->pdep == ctx->prev) + if (ctx->pdeps[base] == ctx->prev) ctx->prev = NULL; - ctx->pdep = NULL; + ctx->pdeps[base] = NULL; +} + +void payload_dependency_release(struct payload_dep_ctx *ctx, + enum proto_bases base) +{ + if (ctx->pdeps[base]) + __payload_dependency_release(ctx, base); + else if (base == PROTO_BASE_TRANSPORT_HDR && + ctx->pdeps[PROTO_BASE_INNER_HDR]) + __payload_dependency_release(ctx, PROTO_BASE_INNER_HDR); } static uint8_t icmp_dep_to_type(enum icmp_hdr_field_type t) @@ -786,7 +797,7 @@ void payload_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr, { if (payload_dependency_exists(ctx, expr->payload.base) && payload_may_dependency_kill(ctx, family, expr)) - payload_dependency_release(ctx); + payload_dependency_release(ctx, expr->payload.base); } void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr, @@ -795,15 +806,15 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr, switch (expr->exthdr.op) { case NFT_EXTHDR_OP_TCPOPT: if (payload_dependency_exists(ctx, PROTO_BASE_TRANSPORT_HDR)) - payload_dependency_release(ctx); + payload_dependency_release(ctx, PROTO_BASE_TRANSPORT_HDR); break; case NFT_EXTHDR_OP_IPV6: if (payload_dependency_exists(ctx, PROTO_BASE_NETWORK_HDR)) - payload_dependency_release(ctx); + payload_dependency_release(ctx, PROTO_BASE_NETWORK_HDR); break; case NFT_EXTHDR_OP_IPV4: if (payload_dependency_exists(ctx, PROTO_BASE_NETWORK_HDR)) - payload_dependency_release(ctx); + payload_dependency_release(ctx, PROTO_BASE_NETWORK_HDR); break; default: break; -- 2.34.1