[openwrt/openwrt] iptables: backport "nft: track each register individually" from 1.9

LEDE Commits lede-commits at lists.infradead.org
Sat Oct 19 10:46:54 PDT 2024


hauke pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/44b1993f766e66c13e09d7c09a3c8f85655a446e

commit 44b1993f766e66c13e09d7c09a3c8f85655a446e
Author: Rodrigo B. de Sousa Martins <rodrigo.sousa.577 at gmail.com>
AuthorDate: Wed Sep 25 15:35:20 2024 -0300

    iptables: backport "nft: track each register individually" from 1.9
    
    From the upstream repo:
    
    Instead of assuming only one register is used, track all 16 regs
    individually.
    
    This avoids need for the 'PREV_PAYLOAD' hack and also avoids the need to
    clear out old flags:
    
    When we see that register 'x' will be written to, that register state is
    reset automatically.
    
    Existing dissector decodes
    ip saddr 1.2.3.4 meta l4proto tcp
    ... as
    -s 6.0.0.0 -p tcp
    
    iptables-nft -s 1.2.3.4 -p tcp is decoded correctly because the expressions
    are ordered like:
    
    meta l4proto tcp ip saddr 1.2.3.4
                                                                                                                                                                                                                       |
    ... and 'meta l4proto' did clear the PAYLOAD flag.
    
    The simpler fix is:
                    ctx->flags &= ~NFT_XT_CTX_PAYLOAD;
    
    in nft_parse_cmp(), but that breaks dissection of '1-42', because
    the second compare ('cmp lte 42') will not find the
    payload expression anymore.
    
    This commit fixes #11169 and openwrt/packages#22727, and potentially anyone that uses iptables-nft legacy support.
    
    Signed-off-by: Rodrigo B. de Sousa Martins <rodrigo.sousa.577 at gmail.com>
    Link: https://github.com/openwrt/openwrt/pull/16504
    [Added patch header]
    Signed-off-by: Hauke Mehrtens <hauke at hauke-m.de>
---
 package/network/utils/iptables/Makefile            |    2 +-
 .../104-nft-track-each-register-individually.patch | 1054 ++++++++++++++++++++
 2 files changed, 1055 insertions(+), 1 deletion(-)

diff --git a/package/network/utils/iptables/Makefile b/package/network/utils/iptables/Makefile
index 2fc7977038..0d5bbb1c5d 100644
--- a/package/network/utils/iptables/Makefile
+++ b/package/network/utils/iptables/Makefile
@@ -10,7 +10,7 @@ include $(INCLUDE_DIR)/kernel.mk
 
 PKG_NAME:=iptables
 PKG_VERSION:=1.8.8
-PKG_RELEASE:=2
+PKG_RELEASE:=3
 
 PKG_SOURCE_URL:=https://netfilter.org/projects/iptables/files
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
diff --git a/package/network/utils/iptables/patches/104-nft-track-each-register-individually.patch b/package/network/utils/iptables/patches/104-nft-track-each-register-individually.patch
new file mode 100644
index 0000000000..166dc86fa1
--- /dev/null
+++ b/package/network/utils/iptables/patches/104-nft-track-each-register-individually.patch
@@ -0,0 +1,1054 @@
+From f315af1cf88714702dcc51dc00b109df3d52e9e9 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw at strlen.de>
+Date: Fri, 23 Sep 2022 14:17:08 +0200
+Subject: nft: track each register individually
+
+Instead of assuming only one register is used, track all 16 regs
+individually.
+
+This avoids need for the 'PREV_PAYLOAD' hack and also avoids the need to
+clear out old flags:
+
+When we see that register 'x' will be written to, that register state is
+reset automatically.
+
+Existing dissector decodes
+ip saddr 1.2.3.4 meta l4proto tcp
+... as
+-s 6.0.0.0 -p tcp
+
+iptables-nft -s 1.2.3.4 -p tcp is decoded correctly because the expressions
+are ordered like:
+
+meta l4proto tcp ip saddr 1.2.3.4
+                                                                                                                                                                                                                   |
+... and 'meta l4proto' did clear the PAYLOAD flag.
+
+The simpler fix is:
+		ctx->flags &= ~NFT_XT_CTX_PAYLOAD;
+
+in nft_parse_cmp(), but that breaks dissection of '1-42', because
+the second compare ('cmp lte 42') will not find the
+payload expression anymore.
+
+Link: https://lore.kernel.org/netfilter-devel/20220922143544.GA22541@breakpoint.cc/T/#t
+Signed-off-by: Florian Westphal <fw at strlen.de>
+Reviewed-by: Phil Sutter <phil at nwl.cc>
+---
+ iptables/nft-arp.c    |  57 +++++++-------
+ iptables/nft-bridge.c | 102 +++++++++++++++----------
+ iptables/nft-ipv4.c   |  49 ++++++------
+ iptables/nft-ipv6.c   |  36 ++++-----
+ iptables/nft-shared.c | 205 +++++++++++++++++++++++++++++++++++---------------
+ iptables/nft-shared.h | 110 ++++++++++++++++++++-------
+ 6 files changed, 360 insertions(+), 199 deletions(-)
+
+--- a/iptables/nft-arp.c
++++ b/iptables/nft-arp.c
+@@ -160,25 +160,27 @@ static int nft_arp_add(struct nft_handle
+ 	return ret;
+ }
+ 
+-static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
++static void nft_arp_parse_meta(struct nft_xt_ctx *ctx,
++			       const struct nft_xt_ctx_reg *reg,
++			       struct nftnl_expr *e,
+ 			       struct iptables_command_state *cs)
+ {
+ 	struct arpt_entry *fw = &cs->arp;
+ 	uint8_t flags = 0;
+ 
+-	parse_meta(ctx, e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask,
++	parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface, fw->arp.iniface_mask,
+ 		   fw->arp.outiface, fw->arp.outiface_mask,
+ 		   &flags);
+ 
+ 	fw->arp.invflags |= flags;
+ }
+ 
+-static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
++static void parse_mask_ipv4(const struct nft_xt_ctx_reg *reg, struct in_addr *mask)
+ {
+-	mask->s_addr = ctx->bitwise.mask[0];
++	mask->s_addr = reg->bitwise.mask[0];
+ }
+ 
+-static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx,
++static bool nft_arp_parse_devaddr(const struct nft_xt_ctx_reg *reg,
+ 				  struct nftnl_expr *e,
+ 				  struct arpt_devaddr_info *info)
+ {
+@@ -192,18 +194,17 @@ static bool nft_arp_parse_devaddr(struct
+ 
+ 	get_cmp_data(e, info->addr, ETH_ALEN, &inv);
+ 
+-	if (ctx->flags & NFT_XT_CTX_BITWISE) {
+-		memcpy(info->mask, ctx->bitwise.mask, ETH_ALEN);
+-		ctx->flags &= ~NFT_XT_CTX_BITWISE;
+-	} else {
++	if (reg->bitwise.set)
++		memcpy(info->mask, reg->bitwise.mask, ETH_ALEN);
++	else
+ 		memset(info->mask, 0xff,
+-		       min(ctx->payload.len, ETH_ALEN));
+-	}
++		       min(reg->payload.len, ETH_ALEN));
+ 
+ 	return inv;
+ }
+ 
+ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
++				  const struct nft_xt_ctx_reg *reg,
+ 				  struct nftnl_expr *e,
+ 				  struct iptables_command_state *cs)
+ {
+@@ -213,7 +214,7 @@ static void nft_arp_parse_payload(struct
+ 	uint8_t ar_hln;
+ 	bool inv;
+ 
+-	switch (ctx->payload.offset) {
++	switch (reg->payload.offset) {
+ 	case offsetof(struct arphdr, ar_hrd):
+ 		get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv);
+ 		fw->arp.arhrd = ar_hrd;
+@@ -243,43 +244,39 @@ static void nft_arp_parse_payload(struct
+ 			fw->arp.invflags |= IPT_INV_ARPOP;
+ 		break;
+ 	default:
+-		if (ctx->payload.offset == sizeof(struct arphdr)) {
+-			if (nft_arp_parse_devaddr(ctx, e, &fw->arp.src_devaddr))
++		if (reg->payload.offset == sizeof(struct arphdr)) {
++			if (nft_arp_parse_devaddr(reg, e, &fw->arp.src_devaddr))
+ 				fw->arp.invflags |= IPT_INV_SRCDEVADDR;
+-		} else if (ctx->payload.offset == sizeof(struct arphdr) +
++		} else if (reg->payload.offset == sizeof(struct arphdr) +
+ 					   fw->arp.arhln) {
+ 			get_cmp_data(e, &addr, sizeof(addr), &inv);
+ 			fw->arp.src.s_addr = addr.s_addr;
+-			if (ctx->flags & NFT_XT_CTX_BITWISE) {
+-				parse_mask_ipv4(ctx, &fw->arp.smsk);
+-				ctx->flags &= ~NFT_XT_CTX_BITWISE;
+-			} else {
++			if (reg->bitwise.set)
++				parse_mask_ipv4(reg, &fw->arp.smsk);
++			else
+ 				memset(&fw->arp.smsk, 0xff,
+-				       min(ctx->payload.len,
++				       min(reg->payload.len,
+ 					   sizeof(struct in_addr)));
+-			}
+ 
+ 			if (inv)
+ 				fw->arp.invflags |= IPT_INV_SRCIP;
+-		} else if (ctx->payload.offset == sizeof(struct arphdr) +
++		} else if (reg->payload.offset == sizeof(struct arphdr) +
+ 						  fw->arp.arhln +
+ 						  sizeof(struct in_addr)) {
+-			if (nft_arp_parse_devaddr(ctx, e, &fw->arp.tgt_devaddr))
++			if (nft_arp_parse_devaddr(reg, e, &fw->arp.tgt_devaddr))
+ 				fw->arp.invflags |= IPT_INV_TGTDEVADDR;
+-		} else if (ctx->payload.offset == sizeof(struct arphdr) +
++		} else if (reg->payload.offset == sizeof(struct arphdr) +
+ 						  fw->arp.arhln +
+ 						  sizeof(struct in_addr) +
+ 						  fw->arp.arhln) {
+ 			get_cmp_data(e, &addr, sizeof(addr), &inv);
+ 			fw->arp.tgt.s_addr = addr.s_addr;
+-			if (ctx->flags & NFT_XT_CTX_BITWISE) {
+-				parse_mask_ipv4(ctx, &fw->arp.tmsk);
+-				ctx->flags &= ~NFT_XT_CTX_BITWISE;
+-			} else {
++			if (reg->bitwise.set)
++				parse_mask_ipv4(reg, &fw->arp.tmsk);
++			else
+ 				memset(&fw->arp.tmsk, 0xff,
+-				       min(ctx->payload.len,
++				       min(reg->payload.len,
+ 					   sizeof(struct in_addr)));
+-			}
+ 
+ 			if (inv)
+ 				fw->arp.invflags |= IPT_INV_DSTIP;
+--- a/iptables/nft-bridge.c
++++ b/iptables/nft-bridge.c
+@@ -170,6 +170,7 @@ static int nft_bridge_add(struct nft_han
+ }
+ 
+ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx,
++				  const struct nft_xt_ctx_reg *reg,
+ 				  struct nftnl_expr *e,
+ 				  struct iptables_command_state *cs)
+ {
+@@ -177,9 +178,9 @@ static void nft_bridge_parse_meta(struct
+ 	uint8_t invflags = 0;
+ 	char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {};
+ 
+-	parse_meta(ctx, e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags);
++	parse_meta(ctx, e, reg->meta_dreg.key, iifname, NULL, oifname, NULL, &invflags);
+ 
+-	switch (ctx->meta.key) {
++	switch (reg->meta_dreg.key) {
+ 	case NFT_META_BRI_IIFNAME:
+ 		if (invflags & IPT_INV_VIA_IN)
+ 			cs->eb.invflags |= EBT_ILOGICALIN;
+@@ -206,6 +207,7 @@ static void nft_bridge_parse_meta(struct
+ }
+ 
+ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
++				     const struct nft_xt_ctx_reg *reg,
+ 				     struct nftnl_expr *e,
+ 				     struct iptables_command_state *cs)
+ {
+@@ -215,7 +217,7 @@ static void nft_bridge_parse_payload(str
+ 	bool inv;
+ 	int i;
+ 
+-	switch (ctx->payload.offset) {
++	switch (reg->payload.offset) {
+ 	case offsetof(struct ethhdr, h_dest):
+ 		get_cmp_data(e, addr, sizeof(addr), &inv);
+ 		for (i = 0; i < ETH_ALEN; i++)
+@@ -223,13 +225,11 @@ static void nft_bridge_parse_payload(str
+ 		if (inv)
+ 			fw->invflags |= EBT_IDEST;
+ 
+-		if (ctx->flags & NFT_XT_CTX_BITWISE) {
+-                        memcpy(fw->destmsk, ctx->bitwise.mask, ETH_ALEN);
+-                        ctx->flags &= ~NFT_XT_CTX_BITWISE;
+-                } else {
++		if (reg->bitwise.set)
++                        memcpy(fw->destmsk, reg->bitwise.mask, ETH_ALEN);
++                else
+ 			memset(&fw->destmsk, 0xff,
+-			       min(ctx->payload.len, ETH_ALEN));
+-                }
++			       min(reg->payload.len, ETH_ALEN));
+ 		fw->bitmask |= EBT_IDEST;
+ 		break;
+ 	case offsetof(struct ethhdr, h_source):
+@@ -238,13 +238,11 @@ static void nft_bridge_parse_payload(str
+ 			fw->sourcemac[i] = addr[i];
+ 		if (inv)
+ 			fw->invflags |= EBT_ISOURCE;
+-		if (ctx->flags & NFT_XT_CTX_BITWISE) {
+-                        memcpy(fw->sourcemsk, ctx->bitwise.mask, ETH_ALEN);
+-                        ctx->flags &= ~NFT_XT_CTX_BITWISE;
+-                } else {
++		if (reg->bitwise.set)
++                        memcpy(fw->sourcemsk, reg->bitwise.mask, ETH_ALEN);
++                else
+ 			memset(&fw->sourcemsk, 0xff,
+-			       min(ctx->payload.len, ETH_ALEN));
+-                }
++			       min(reg->payload.len, ETH_ALEN));
+ 		fw->bitmask |= EBT_ISOURCE;
+ 		break;
+ 	case offsetof(struct ethhdr, h_proto):
+@@ -294,28 +292,53 @@ lookup_check_iphdr_payload(uint32_t base
+ /* Make sure previous payload expression(s) is/are consistent and extract if
+  * matching on source or destination address and if matching on MAC and IP or
+  * only MAC address. */
+-static int lookup_analyze_payloads(const struct nft_xt_ctx *ctx,
++static int lookup_analyze_payloads(struct nft_xt_ctx *ctx,
++				   enum nft_registers sreg,
++				   uint32_t key_len,
+ 				   bool *dst, bool *ip)
+ {
++	const struct nft_xt_ctx_reg *reg;
++	uint32_t sreg_count;
+ 	int val, val2 = -1;
+ 
+-	if (ctx->flags & NFT_XT_CTX_PREV_PAYLOAD) {
+-		val = lookup_check_ether_payload(ctx->prev_payload.base,
+-						 ctx->prev_payload.offset,
+-						 ctx->prev_payload.len);
++	reg = nft_xt_ctx_get_sreg(ctx, sreg);
++	if (!reg)
++		return -1;
++
++	if (reg->type != NFT_XT_REG_PAYLOAD) {
++		ctx->errmsg = "lookup reg is not payload type";
++		return -1;
++	}
++
++	sreg_count = sreg;
++	switch (key_len) {
++	case 12: /* ether + ipv4addr */
++		val = lookup_check_ether_payload(reg->payload.base,
++						 reg->payload.offset,
++						 reg->payload.len);
+ 		if (val < 0) {
+ 			DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
+-			       ctx->prev_payload.base, ctx->prev_payload.offset,
+-			       ctx->prev_payload.len);
++			       reg->payload.base, reg->payload.offset,
++			       reg->payload.len);
+ 			return -1;
+ 		}
+-		if (!(ctx->flags & NFT_XT_CTX_PAYLOAD)) {
+-			DEBUGP("Previous but no current payload?\n");
++
++		sreg_count += 2;
++
++		reg = nft_xt_ctx_get_sreg(ctx, sreg_count);
++		if (!reg) {
++			ctx->errmsg = "next lookup register is invalid";
++			return -1;
++		}
++
++		if (reg->type != NFT_XT_REG_PAYLOAD) {
++			ctx->errmsg = "next lookup reg is not payload type";
+ 			return -1;
+ 		}
+-		val2 = lookup_check_iphdr_payload(ctx->payload.base,
+-						  ctx->payload.offset,
+-						  ctx->payload.len);
++
++		val2 = lookup_check_iphdr_payload(reg->payload.base,
++						  reg->payload.offset,
++						  reg->payload.len);
+ 		if (val2 < 0) {
+ 			DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
+ 			       ctx->payload.base, ctx->payload.offset,
+@@ -325,18 +348,20 @@ static int lookup_analyze_payloads(const
+ 			DEBUGP("mismatching payload match offsets\n");
+ 			return -1;
+ 		}
+-	} else if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
+-		val = lookup_check_ether_payload(ctx->payload.base,
+-						 ctx->payload.offset,
+-						 ctx->payload.len);
++		break;
++	case 4: /* ipv4addr */
++		val = lookup_check_ether_payload(reg->payload.base,
++						 reg->payload.offset,
++						 reg->payload.len);
+ 		if (val < 0) {
+ 			DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
+ 			       ctx->payload.base, ctx->payload.offset,
+ 			       ctx->payload.len);
+ 			return -1;
+ 		}
+-	} else {
+-		DEBUGP("unknown LHS of lookup expression\n");
++		break;
++	default:
++		ctx->errmsg = "unsupported lookup key length";
+ 		return -1;
+ 	}
+ 
+@@ -413,14 +438,17 @@ static void nft_bridge_parse_lookup(stru
+ 	size_t poff, size;
+ 	uint32_t cnt;
+ 
+-	if (lookup_analyze_payloads(ctx, &is_dst, &have_ip))
+-		return;
+-
+ 	s = set_from_lookup_expr(ctx, e);
+ 	if (!s)
+ 		xtables_error(OTHER_PROBLEM,
+ 			      "BUG: lookup expression references unknown set");
+ 
++	if (lookup_analyze_payloads(ctx,
++				    nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SREG),
++				    nftnl_set_get_u32(s, NFTNL_SET_KEY_LEN),
++				    &is_dst, &have_ip))
++		return;
++
+ 	cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE);
+ 
+ 	for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) {
+@@ -468,8 +496,6 @@ static void nft_bridge_parse_lookup(stru
+ 	if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt))
+ 		xtables_error(OTHER_PROBLEM,
+ 			      "ebtables among pair parsing failed");
+-
+-	ctx->flags &= ~(NFT_XT_CTX_PAYLOAD | NFT_XT_CTX_PREV_PAYLOAD);
+ }
+ 
+ static void parse_watcher(void *object, struct ebt_match **match_list,
+--- a/iptables/nft-ipv4.c
++++ b/iptables/nft-ipv4.c
+@@ -115,28 +115,28 @@ static bool nft_ipv4_is_same(const struc
+ 				  b->fw.ip.iniface_mask, b->fw.ip.outiface_mask);
+ }
+ 
+-static void get_frag(struct nft_xt_ctx *ctx, struct nftnl_expr *e, bool *inv)
++static bool get_frag(const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e)
+ {
+ 	uint8_t op;
+ 
+ 	/* we assume correct mask and xor */
+-	if (!(ctx->flags & NFT_XT_CTX_BITWISE))
+-		return;
++	if (!reg->bitwise.set)
++		return false;
+ 
+ 	/* we assume correct data */
+ 	op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
+ 	if (op == NFT_CMP_EQ)
+-		*inv = true;
+-	else
+-		*inv = false;
++		return true;
+ 
+-	ctx->flags &= ~NFT_XT_CTX_BITWISE;
++	return false;
+ }
+ 
+-static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
++static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx,
++				const struct nft_xt_ctx_reg *reg,
++				struct nftnl_expr *e,
+ 				struct iptables_command_state *cs)
+ {
+-	switch (ctx->meta.key) {
++	switch (reg->meta_dreg.key) {
+ 	case NFT_META_L4PROTO:
+ 		cs->fw.ip.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
+ 		if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
+@@ -146,17 +146,18 @@ static void nft_ipv4_parse_meta(struct n
+ 		break;
+ 	}
+ 
+-	parse_meta(ctx, e, ctx->meta.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask,
++	parse_meta(ctx, e, reg->meta_dreg.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask,
+ 		   cs->fw.ip.outiface, cs->fw.ip.outiface_mask,
+ 		   &cs->fw.ip.invflags);
+ }
+ 
+-static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
++static void parse_mask_ipv4(const struct nft_xt_ctx_reg *sreg, struct in_addr *mask)
+ {
+-	mask->s_addr = ctx->bitwise.mask[0];
++	mask->s_addr = sreg->bitwise.mask[0];
+ }
+ 
+ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
++				   const struct nft_xt_ctx_reg *sreg,
+ 				   struct nftnl_expr *e,
+ 				   struct iptables_command_state *cs)
+ {
+@@ -164,16 +165,15 @@ static void nft_ipv4_parse_payload(struc
+ 	uint8_t proto;
+ 	bool inv;
+ 
+-	switch(ctx->payload.offset) {
++	switch (sreg->payload.offset) {
+ 	case offsetof(struct iphdr, saddr):
+ 		get_cmp_data(e, &addr, sizeof(addr), &inv);
+ 		cs->fw.ip.src.s_addr = addr.s_addr;
+-		if (ctx->flags & NFT_XT_CTX_BITWISE) {
+-			parse_mask_ipv4(ctx, &cs->fw.ip.smsk);
+-			ctx->flags &= ~NFT_XT_CTX_BITWISE;
++		if (sreg->bitwise.set) {
++			parse_mask_ipv4(sreg, &cs->fw.ip.smsk);
+ 		} else {
+ 			memset(&cs->fw.ip.smsk, 0xff,
+-			       min(ctx->payload.len, sizeof(struct in_addr)));
++			       min(sreg->payload.len, sizeof(struct in_addr)));
+ 		}
+ 
+ 		if (inv)
+@@ -182,13 +182,11 @@ static void nft_ipv4_parse_payload(struc
+ 	case offsetof(struct iphdr, daddr):
+ 		get_cmp_data(e, &addr, sizeof(addr), &inv);
+ 		cs->fw.ip.dst.s_addr = addr.s_addr;
+-		if (ctx->flags & NFT_XT_CTX_BITWISE) {
+-			parse_mask_ipv4(ctx, &cs->fw.ip.dmsk);
+-			ctx->flags &= ~NFT_XT_CTX_BITWISE;
+-		} else {
++		if (sreg->bitwise.set)
++			parse_mask_ipv4(sreg, &cs->fw.ip.dmsk);
++		else
+ 			memset(&cs->fw.ip.dmsk, 0xff,
+-			       min(ctx->payload.len, sizeof(struct in_addr)));
+-		}
++			       min(sreg->payload.len, sizeof(struct in_addr)));
+ 
+ 		if (inv)
+ 			cs->fw.ip.invflags |= IPT_INV_DSTIP;
+@@ -201,13 +199,12 @@ static void nft_ipv4_parse_payload(struc
+ 		break;
+ 	case offsetof(struct iphdr, frag_off):
+ 		cs->fw.ip.flags |= IPT_F_FRAG;
+-		inv = false;
+-		get_frag(ctx, e, &inv);
++		inv = get_frag(sreg, e);
+ 		if (inv)
+ 			cs->fw.ip.invflags |= IPT_INV_FRAG;
+ 		break;
+ 	default:
+-		DEBUGP("unknown payload offset %d\n", ctx->payload.offset);
++		DEBUGP("unknown payload offset %d\n", sreg->payload.offset);
+ 		break;
+ 	}
+ }
+--- a/iptables/nft-ipv6.c
++++ b/iptables/nft-ipv6.c
+@@ -104,10 +104,12 @@ static bool nft_ipv6_is_same(const struc
+ 				  b->fw6.ipv6.outiface_mask);
+ }
+ 
+-static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
++static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx,
++				const struct nft_xt_ctx_reg *reg,
++				struct nftnl_expr *e,
+ 				struct iptables_command_state *cs)
+ {
+-	switch (ctx->meta.key) {
++	switch (reg->meta_dreg.key) {
+ 	case NFT_META_L4PROTO:
+ 		cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
+ 		if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
+@@ -117,17 +119,19 @@ static void nft_ipv6_parse_meta(struct n
+ 		break;
+ 	}
+ 
+-	parse_meta(ctx, e, ctx->meta.key, cs->fw6.ipv6.iniface,
++	parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface,
+ 		   cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface,
+ 		   cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags);
+ }
+ 
+-static void parse_mask_ipv6(struct nft_xt_ctx *ctx, struct in6_addr *mask)
++static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg,
++			    struct in6_addr *mask)
+ {
+-	memcpy(mask, ctx->bitwise.mask, sizeof(struct in6_addr));
++	memcpy(mask, reg->bitwise.mask, sizeof(struct in6_addr));
+ }
+ 
+ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
++				   const struct nft_xt_ctx_reg *reg,
+ 				   struct nftnl_expr *e,
+ 				   struct iptables_command_state *cs)
+ {
+@@ -135,17 +139,15 @@ static void nft_ipv6_parse_payload(struc
+ 	uint8_t proto;
+ 	bool inv;
+ 
+-	switch (ctx->payload.offset) {
++	switch (reg->payload.offset) {
+ 	case offsetof(struct ip6_hdr, ip6_src):
+ 		get_cmp_data(e, &addr, sizeof(addr), &inv);
+ 		memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr));
+-		if (ctx->flags & NFT_XT_CTX_BITWISE) {
+-			parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk);
+-			ctx->flags &= ~NFT_XT_CTX_BITWISE;
+-		} else {
++		if (reg->bitwise.set)
++			parse_mask_ipv6(reg, &cs->fw6.ipv6.smsk);
++		else
+ 			memset(&cs->fw6.ipv6.smsk, 0xff,
+-			       min(ctx->payload.len, sizeof(struct in6_addr)));
+-		}
++			       min(reg->payload.len, sizeof(struct in6_addr)));
+ 
+ 		if (inv)
+ 			cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP;
+@@ -153,13 +155,11 @@ static void nft_ipv6_parse_payload(struc
+ 	case offsetof(struct ip6_hdr, ip6_dst):
+ 		get_cmp_data(e, &addr, sizeof(addr), &inv);
+ 		memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr));
+-		if (ctx->flags & NFT_XT_CTX_BITWISE) {
+-			parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk);
+-			ctx->flags &= ~NFT_XT_CTX_BITWISE;
+-		} else {
++		if (reg->bitwise.set)
++			parse_mask_ipv6(reg, &cs->fw6.ipv6.dmsk);
++		else
+ 			memset(&cs->fw6.ipv6.dmsk, 0xff,
+-			       min(ctx->payload.len, sizeof(struct in6_addr)));
+-		}
++			       min(reg->payload.len, sizeof(struct in6_addr)));
+ 
+ 		if (inv)
+ 			cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP;
+--- a/iptables/nft-shared.c
++++ b/iptables/nft-shared.c
+@@ -295,6 +295,16 @@ nft_create_match(struct nft_xt_ctx *ctx,
+ 		 struct iptables_command_state *cs,
+ 		 const char *name);
+ 
++static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg)
++{
++	struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_sreg(ctx, sreg);
++
++	if (reg->bitwise.set)
++		return reg->bitwise.mask[0];
++
++	return ~0u;
++}
++
+ static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+ {
+ 	struct xt_mark_mtinfo1 *mark;
+@@ -312,12 +322,7 @@ static int parse_meta_mark(struct nft_xt
+ 
+ 	value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
+ 	mark->mark = value;
+-	if (ctx->flags & NFT_XT_CTX_BITWISE) {
+-		memcpy(&mark->mask, &ctx->bitwise.mask, sizeof(mark->mask));
+-		ctx->flags &= ~NFT_XT_CTX_BITWISE;
+-	} else {
+-		mark->mask = 0xffffffff;
+-	}
++	mark->mask = get_meta_mask(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG));
+ 
+ 	return 0;
+ }
+@@ -451,20 +456,40 @@ void get_cmp_data(struct nftnl_expr *e,
+ 		*inv = false;
+ }
+ 
+-static void nft_meta_set_to_target(struct nft_xt_ctx *ctx)
++static void nft_meta_set_to_target(struct nft_xt_ctx *ctx,
++				   struct nftnl_expr *e)
+ {
+ 	struct xtables_target *target;
++	struct nft_xt_ctx_reg *sreg;
++	enum nft_registers sregnum;
+ 	struct xt_entry_target *t;
+ 	unsigned int size;
+ 	const char *targname;
+ 
+-	switch (ctx->meta.key) {
++	sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG);
++	sreg = nft_xt_ctx_get_sreg(ctx, sregnum);
++	if (!sreg)
++		return;
++
++	if (sreg->meta_sreg.set == 0)
++		return;
++
++	switch (sreg->meta_sreg.key) {
+ 	case NFT_META_NFTRACE:
+-		if (ctx->immediate.data[0] == 0)
++		if ((sreg->type != NFT_XT_REG_IMMEDIATE)) {
++			ctx->errmsg = "meta nftrace but reg not immediate";
+ 			return;
++		}
++
++		if (sreg->immediate.data[0] == 0) {
++			ctx->errmsg = "trace is cleared";
++			return;
++		}
++
+ 		targname = "TRACE";
+ 		break;
+ 	default:
++		ctx->errmsg = "meta sreg key not supported";
+ 		return;
+ 	}
+ 
+@@ -486,51 +511,74 @@ static void nft_meta_set_to_target(struc
+ 
+ static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+ {
+-	ctx->meta.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY);
++        struct nft_xt_ctx_reg *reg;
+ 
+-	if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG) &&
+-	    (ctx->flags & NFT_XT_CTX_IMMEDIATE) &&
+-	     nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG) == ctx->immediate.reg) {
+-		ctx->flags &= ~NFT_XT_CTX_IMMEDIATE;
+-		nft_meta_set_to_target(ctx);
++	if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG)) {
++		nft_meta_set_to_target(ctx, e);
+ 		return;
+ 	}
+ 
+-	ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
+-	ctx->flags |= NFT_XT_CTX_META;
++	reg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG));
++	if (!reg)
++		return;
++
++	reg->meta_dreg.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY);
++	reg->type = NFT_XT_REG_META_DREG;
+ }
+ 
+ static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+ {
+-	if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
+-		memcpy(&ctx->prev_payload, &ctx->payload,
+-		       sizeof(ctx->prev_payload));
+-		ctx->flags |= NFT_XT_CTX_PREV_PAYLOAD;
+-	}
++	enum nft_registers regnum = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG);
++	struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_dreg(ctx, regnum);
+ 
+-	ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG);
+-	ctx->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE);
+-	ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET);
+-	ctx->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN);
+-	ctx->flags |= NFT_XT_CTX_PAYLOAD;
++	if (!reg)
++		return;
++
++	reg->type = NFT_XT_REG_PAYLOAD;
++	reg->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE);
++	reg->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET);
++	reg->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN);
+ }
+ 
+ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+ {
+-	uint32_t reg, len;
++	enum nft_registers sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG);
++	enum nft_registers dregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG);
++	struct nft_xt_ctx_reg *sreg = nft_xt_ctx_get_sreg(ctx, sregnum);
++	struct nft_xt_ctx_reg *dreg = sreg;
+ 	const void *data;
++	uint32_t len;
+ 
+-	reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG);
+-	if (ctx->reg && reg != ctx->reg)
++	if (!sreg)
+ 		return;
+ 
+-	reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG);
+-	ctx->reg = reg;
++	if (sregnum != dregnum) {
++		dreg = nft_xt_ctx_get_sreg(ctx, dregnum); /* sreg, do NOT clear ... */
++		if (!dreg)
++			return;
++
++		*dreg = *sreg;  /* .. and copy content instead */
++	}
++
+ 	data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len);
+-	memcpy(ctx->bitwise.xor, data, len);
++
++	if (len > sizeof(dreg->bitwise.xor)) {
++		ctx->errmsg = "bitwise xor too large";
++		return;
++	}
++
++	memcpy(dreg->bitwise.xor, data, len);
++
+ 	data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len);
+-	memcpy(ctx->bitwise.mask, data, len);
+-	ctx->flags |= NFT_XT_CTX_BITWISE;
++
++	if (len > sizeof(dreg->bitwise.mask)) {
++		ctx->errmsg = "bitwise mask too large";
++		return;
++	}
++
++	memcpy(dreg->bitwise.mask, data, len);
++
++	dreg->bitwise.set = true;
+ }
+ 
+ static struct xtables_match *
+@@ -835,6 +883,8 @@ static void nft_parse_transport(struct n
+ 				struct nftnl_expr *e,
+ 				struct iptables_command_state *cs)
+ {
++	struct nft_xt_ctx_reg *sreg;
++	enum nft_registers reg;
+ 	uint32_t sdport;
+ 	uint16_t port;
+ 	uint8_t proto, op;
+@@ -855,7 +905,17 @@ static void nft_parse_transport(struct n
+ 	nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
+ 	op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
+ 
+-	switch(ctx->payload.offset) {
++	reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG);
++	sreg = nft_xt_ctx_get_sreg(ctx, reg);
++	if (!sreg)
++		return;
++
++	if (sreg->type != NFT_XT_REG_PAYLOAD) {
++		ctx->errmsg = "sgreg not payload";
++		return;
++	}
++
++	switch(sreg->payload.offset) {
+ 	case 0: /* th->sport */
+ 		switch (len) {
+ 		case 2: /* load sport only */
+@@ -881,10 +941,9 @@ static void nft_parse_transport(struct n
+ 			uint8_t flags = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
+ 			uint8_t mask = ~0;
+ 
+-			if (ctx->flags & NFT_XT_CTX_BITWISE) {
+-				memcpy(&mask, &ctx->bitwise.mask, sizeof(mask));
+-				ctx->flags &= ~NFT_XT_CTX_BITWISE;
+-			}
++			if (sreg->bitwise.set)
++				memcpy(&mask, &sreg->bitwise.mask, sizeof(mask));
++
+ 			nft_parse_tcp_flags(ctx, cs, op, flags, mask);
+ 		}
+ 		return;
+@@ -892,6 +951,7 @@ static void nft_parse_transport(struct n
+ }
+ 
+ static void nft_parse_transport_range(struct nft_xt_ctx *ctx,
++				      const struct nft_xt_ctx_reg *sreg,
+ 				      struct nftnl_expr *e,
+ 				      struct iptables_command_state *cs)
+ {
+@@ -921,7 +981,7 @@ static void nft_parse_transport_range(st
+ 	from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA));
+ 	to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA));
+ 
+-	switch(ctx->payload.offset) {
++	switch (sreg->payload.offset) {
+ 	case 0:
+ 		nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op);
+ 		return;
+@@ -934,30 +994,40 @@ static void nft_parse_transport_range(st
+ 
+ static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+ {
++	struct nft_xt_ctx_reg *sreg;
+ 	uint32_t reg;
+ 
+ 	reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG);
+-	if (ctx->reg && reg != ctx->reg)
++
++	sreg = nft_xt_ctx_get_sreg(ctx, reg);
++	if (!sreg)
+ 		return;
+ 
+-	if (ctx->flags & NFT_XT_CTX_META) {
+-		ctx->h->ops->parse_meta(ctx, e, ctx->cs);
+-		ctx->flags &= ~NFT_XT_CTX_META;
+-	}
+-	/* bitwise context is interpreted from payload */
+-	if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
+-		switch (ctx->payload.base) {
++	switch (sreg->type) {
++	case NFT_XT_REG_UNDEF:
++		ctx->errmsg = "cmp sreg undef";
++		break;
++	case NFT_XT_REG_META_DREG:
++		ctx->h->ops->parse_meta(ctx, sreg, e, ctx->cs);
++		break;
++	case NFT_XT_REG_PAYLOAD:
++		switch (sreg->payload.base) {
+ 		case NFT_PAYLOAD_LL_HEADER:
+ 			if (ctx->h->family == NFPROTO_BRIDGE)
+-				ctx->h->ops->parse_payload(ctx, e, ctx->cs);
++				ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs);
+ 			break;
+ 		case NFT_PAYLOAD_NETWORK_HEADER:
+-			ctx->h->ops->parse_payload(ctx, e, ctx->cs);
++			ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs);
+ 			break;
+ 		case NFT_PAYLOAD_TRANSPORT_HEADER:
+ 			nft_parse_transport(ctx, e, ctx->cs);
+ 			break;
+ 		}
++
++		break;
++	default:
++		ctx->errmsg = "cmp sreg has unknown type";
++		break;
+ 	}
+ }
+ 
+@@ -976,18 +1046,22 @@ static void nft_parse_immediate(struct n
+ 	int verdict;
+ 
+ 	if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) {
++		struct nft_xt_ctx_reg *dreg;
+ 		const void *imm_data;
+ 		uint32_t len;
+ 
+ 		imm_data = nftnl_expr_get_data(e, NFTNL_EXPR_IMM_DATA, &len);
++		dreg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG));
++		if (!dreg)
++			return;
+ 
+-		if (len > sizeof(ctx->immediate.data))
++		if (len > sizeof(dreg->immediate.data))
+ 			return;
+ 
+-		memcpy(ctx->immediate.data, imm_data, len);
+-		ctx->immediate.len = len;
+-		ctx->immediate.reg = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG);
+-		ctx->flags |= NFT_XT_CTX_IMMEDIATE;
++		memcpy(dreg->immediate.data, imm_data, len);
++		dreg->immediate.len = len;
++		dreg->type = NFT_XT_REG_IMMEDIATE;
++
+ 		return;
+ 	}
+ 
+@@ -1124,20 +1198,29 @@ static void nft_parse_lookup(struct nft_
+ 
+ static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+ {
++	struct nft_xt_ctx_reg *sreg;
+ 	uint32_t reg;
+ 
+ 	reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG);
+-	if (reg != ctx->reg)
+-		return;
++	sreg = nft_xt_ctx_get_sreg(ctx, reg);
+ 
+-	if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
+-		switch (ctx->payload.base) {
++	switch (sreg->type) {
++	case NFT_XT_REG_UNDEF:
++		ctx->errmsg = "range sreg undef";
++		break;
++	case NFT_XT_REG_PAYLOAD:
++		switch (sreg->payload.base) {
+ 		case NFT_PAYLOAD_TRANSPORT_HEADER:
+-			nft_parse_transport_range(ctx, e, ctx->cs);
++			nft_parse_transport_range(ctx, sreg, e, ctx->cs);
+ 			break;
+ 		default:
++			ctx->errmsg = "range with unknown payload base";
+ 			break;
+ 		}
++		break;
++	default:
++		ctx->errmsg = "range sreg type unsupported";
++		break;
+ 	}
+ }
+ 
+--- a/iptables/nft-shared.h
++++ b/iptables/nft-shared.h
+@@ -38,13 +38,41 @@ struct xtables_args;
+ struct nft_handle;
+ struct xt_xlate;
+ 
+-enum {
+-	NFT_XT_CTX_PAYLOAD	= (1 << 0),
+-	NFT_XT_CTX_META		= (1 << 1),
+-	NFT_XT_CTX_BITWISE	= (1 << 2),
+-	NFT_XT_CTX_IMMEDIATE	= (1 << 3),
+-	NFT_XT_CTX_PREV_PAYLOAD	= (1 << 4),
+-	NFT_XT_CTX_RANGE	= (1 << 5),
++enum nft_ctx_reg_type {
++	NFT_XT_REG_UNDEF,
++	NFT_XT_REG_PAYLOAD,
++	NFT_XT_REG_IMMEDIATE,
++	NFT_XT_REG_META_DREG,
++};
++
++struct nft_xt_ctx_reg {
++	enum nft_ctx_reg_type type:8;
++
++	union {
++		struct {
++			uint32_t base;
++			uint32_t offset;
++			uint32_t len;
++		} payload;
++		struct {
++			uint32_t data[4];
++			uint8_t len;
++		} immediate;
++		struct {
++			uint32_t key;
++		} meta_dreg;
++	};
++
++	struct {
++		uint32_t mask[4];
++		uint32_t xor[4];
++		bool set;
++	} bitwise;
++
++	struct {
++		uint32_t key;
++		bool set;
++	} meta_sreg;
+ };
+ 
+ struct nft_xt_ctx {
+@@ -58,25 +86,51 @@ struct nft_xt_ctx {
+ 		struct xt_udp *udp;
+ 	} tcpudp;
+ 
+-	uint32_t reg;
+-	struct {
+-		uint32_t base;
+-		uint32_t offset;
+-		uint32_t len;
+-	} payload, prev_payload;
+-	struct {
+-		uint32_t key;
+-	} meta;
+-	struct {
+-		uint32_t data[4];
+-		uint32_t len, reg;
+-	} immediate;
+-	struct {
+-		uint32_t mask[4];
+-		uint32_t xor[4];
+-	} bitwise;
++	struct nft_xt_ctx_reg regs[1 + 16];
++
++	const char *errmsg;
+ };
+ 
++static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_sreg(struct nft_xt_ctx *ctx, enum nft_registers reg)
++{
++	switch (reg) {
++	case NFT_REG_VERDICT:
++		return &ctx->regs[0];
++	case NFT_REG_1:
++		return &ctx->regs[1];
++	case NFT_REG_2:
++		return &ctx->regs[5];
++	case NFT_REG_3:
++		return &ctx->regs[9];
++	case NFT_REG_4:
++		return &ctx->regs[13];
++	case NFT_REG32_00...NFT_REG32_15:
++		return &ctx->regs[reg - NFT_REG32_00];
++	default:
++		ctx->errmsg = "Unknown register requested";
++		break;
++	}
++
++	return NULL;
++}
++
++static inline void nft_xt_reg_clear(struct nft_xt_ctx_reg *r)
++{
++	r->type = 0;
++	r->bitwise.set = false;
++	r->meta_sreg.set = false;
++}
++
++static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_dreg(struct nft_xt_ctx *ctx, enum nft_registers reg)
++{
++	struct nft_xt_ctx_reg *r = nft_xt_ctx_get_sreg(ctx, reg);
++
++	if (r)
++		nft_xt_reg_clear(r);
++
++	return r;
++}
++
+ struct nft_family_ops {
+ 	int (*add)(struct nft_handle *h, struct nftnl_rule *r,
+ 		   struct iptables_command_state *cs);
+@@ -84,9 +138,13 @@ struct nft_family_ops {
+ 			const struct iptables_command_state *cs_b);
+ 	void (*print_payload)(struct nftnl_expr *e,
+ 			      struct nftnl_expr_iter *iter);
+-	void (*parse_meta)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
++	void (*parse_meta)(struct nft_xt_ctx *ctx,
++			   const struct nft_xt_ctx_reg *sreg,
++			   struct nftnl_expr *e,
+ 			   struct iptables_command_state *cs);
+-	void (*parse_payload)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
++	void (*parse_payload)(struct nft_xt_ctx *ctx,
++			      const struct nft_xt_ctx_reg *sreg,
++			      struct nftnl_expr *e,
+ 			      struct iptables_command_state *cs);
+ 	void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e);
+ 	void (*set_goto_flag)(struct iptables_command_state *cs);




More information about the lede-commits mailing list