Some matches may turn into multiple nft statements (naturally or via translation). Such statements must parse into a single extension again in order to rebuild the rule as it was. Introduce nft_find_match_in_cs() to iterate through the lists and drop tcp/udp port match caching in struct nft_xt_ctx which is not needed anymore. Note: Match reuse is not enabled unconditionally for all matches, because iptables supports having multiple instances of the same extension. Signed-off-by: Phil Sutter <phil@xxxxxx> --- iptables/nft-shared.c | 70 +++++++++++++++++++++++++------------------ iptables/nft-shared.h | 4 --- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 4a7b5406892c4..df3cc6ac994cf 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -304,7 +304,7 @@ static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned static struct xtables_match * nft_create_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, - const char *name); + const char *name, bool reuse); static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg) { @@ -322,7 +322,7 @@ static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) struct xtables_match *match; uint32_t value; - match = nft_create_match(ctx, ctx->cs, "mark"); + match = nft_create_match(ctx, ctx->cs, "mark", false); if (!match) return -1; @@ -344,7 +344,7 @@ static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e) struct xtables_match *match; uint8_t value; - match = nft_create_match(ctx, ctx->cs, "pkttype"); + match = nft_create_match(ctx, ctx->cs, "pkttype", false); if (!match) return -1; @@ -641,15 +641,39 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) dreg->bitwise.set = true; } +static struct xtables_match * +nft_find_match_in_cs(struct iptables_command_state *cs, const char *name) +{ + struct xtables_rule_match *rm; + struct ebt_match *ebm; + + for (ebm = cs->match_list; ebm; ebm = ebm->next) { + if (ebm->ismatch && + !strcmp(ebm->u.match->m->u.user.name, name)) + return ebm->u.match; + } + for (rm = cs->matches; rm; rm = rm->next) { + if (!strcmp(rm->match->m->u.user.name, name)) + return rm->match; + } + return NULL; +} + static struct xtables_match * nft_create_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, - const char *name) + const char *name, bool reuse) { struct xtables_match *match; struct xt_entry_match *m; unsigned int size; + if (reuse) { + match = nft_find_match_in_cs(cs, name); + if (match) + return match; + } + match = xtables_find_match(name, XTF_TRY_LOAD, &cs->matches); if (!match) @@ -671,38 +695,26 @@ nft_create_match(struct nft_xt_ctx *ctx, static struct xt_udp *nft_udp_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs) { - struct xt_udp *udp = ctx->tcpudp.udp; struct xtables_match *match; - if (!udp) { - match = nft_create_match(ctx, cs, "udp"); - if (!match) - return NULL; - - udp = (void*)match->m->data; - ctx->tcpudp.udp = udp; - } + match = nft_create_match(ctx, cs, "udp", true); + if (!match) + return NULL; - return udp; + return (struct xt_udp *)match->m->data; } static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs) { - struct xt_tcp *tcp = ctx->tcpudp.tcp; struct xtables_match *match; - if (!tcp) { - match = nft_create_match(ctx, cs, "tcp"); - if (!match) { - ctx->errmsg = "tcp match extension not found"; - return NULL; - } - tcp = (void*)match->m->data; - ctx->tcpudp.tcp = tcp; + match = nft_create_match(ctx, cs, "tcp", true); + if (!match) { + ctx->errmsg = "tcp match extension not found"; + return NULL; } - - return tcp; + return (struct xt_tcp *)match->m->data; } static void nft_parse_udp_range(struct nft_xt_ctx *ctx, @@ -872,14 +884,14 @@ static void nft_parse_icmp(struct nft_xt_ctx *ctx, switch (ctx->h->family) { case NFPROTO_IPV4: - match = nft_create_match(ctx, cs, "icmp"); + match = nft_create_match(ctx, cs, "icmp", false); break; case NFPROTO_IPV6: if (icmp.type == UINT8_MAX) { ctx->errmsg = "icmp6 code with any type match not supported"; return; } - match = nft_create_match(ctx, cs, "icmp6"); + match = nft_create_match(ctx, cs, "icmp6", false); break; default: ctx->errmsg = "unexpected family for icmp match"; @@ -1640,10 +1652,10 @@ int nft_parse_hl(struct nft_xt_ctx *ctx, */ switch (ctx->h->family) { case NFPROTO_IPV4: - match = nft_create_match(ctx, ctx->cs, "ttl"); + match = nft_create_match(ctx, ctx->cs, "ttl", false); break; case NFPROTO_IPV6: - match = nft_create_match(ctx, ctx->cs, "hl"); + match = nft_create_match(ctx, ctx->cs, "hl", false); break; default: return -1; diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 07d39131cb0d6..b8bc1a6ce2e93 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -76,10 +76,6 @@ struct nft_xt_ctx { struct nft_handle *h; uint32_t flags; const char *table; - union { - struct xt_tcp *tcp; - struct xt_udp *udp; - } tcpudp; struct nft_xt_ctx_reg regs[1 + 16]; -- 2.38.0