Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49499c3e authored by Patrick McHardy's avatar Patrick McHardy Committed by Pablo Neira Ayuso
Browse files

netfilter: nf_tables: switch registers to 32 bit addressing



Switch the nf_tables registers from 128 bit addressing to 32 bit
addressing to support so called concatenations, where multiple values
can be concatenated over multiple registers for O(1) exact matches of
multiple dimensions using sets.

The old register values are mapped to areas of 128 bits for compatibility.
When dumping register numbers, values are expressed using the old values
if they refer to the beginning of a 128 bit area for compatibility.

To support concatenations, register loads of less than a full 32 bit
value need to be padded. This mainly affects the payload and exthdr
expressions, which both unconditionally zero the last word before
copying the data.

Userspace fully passes the testsuite using both old and new register
addressing.

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent b1c96ed3
Loading
Loading
Loading
Loading
+5 −8
Original line number Diff line number Diff line
@@ -64,17 +64,15 @@ struct nft_data {
 */
struct nft_regs {
	union {
		struct nft_data 	data[NFT_REG_MAX + 1];
		u32			data[20];
		struct nft_verdict	verdict;
	};
};

static inline void nft_data_copy(struct nft_data *dst,
				 const struct nft_data *src)
static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
				 unsigned int len)
{
	BUILD_BUG_ON(__alignof__(*dst) != __alignof__(u64));
	*(u64 *)&dst->data[0] = *(u64 *)&src->data[0];
	*(u64 *)&dst->data[2] = *(u64 *)&src->data[2];
	memcpy(dst, src, len);
}

static inline void nft_data_debug(const struct nft_data *data)
@@ -502,8 +500,7 @@ static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,

void *nft_set_elem_init(const struct nft_set *set,
			const struct nft_set_ext_tmpl *tmpl,
			const struct nft_data *key,
			const struct nft_data *data,
			const u32 *key, const u32 *data,
			u64 timeout, gfp_t gfp);
void nft_set_elem_destroy(const struct nft_set *set, void *elem);

+30 −1
Original line number Diff line number Diff line
@@ -5,16 +5,45 @@
#define NFT_CHAIN_MAXNAMELEN	32
#define NFT_USERDATA_MAXLEN	256

/**
 * enum nft_registers - nf_tables registers
 *
 * nf_tables used to have five registers: a verdict register and four data
 * registers of size 16. The data registers have been changed to 16 registers
 * of size 4. For compatibility reasons, the NFT_REG_[1-4] registers still
 * map to areas of size 16, the 4 byte registers are addressed using
 * NFT_REG32_00 - NFT_REG32_15.
 */
enum nft_registers {
	NFT_REG_VERDICT,
	NFT_REG_1,
	NFT_REG_2,
	NFT_REG_3,
	NFT_REG_4,
	__NFT_REG_MAX
	__NFT_REG_MAX,

	NFT_REG32_00	= 8,
	MFT_REG32_01,
	NFT_REG32_02,
	NFT_REG32_03,
	NFT_REG32_04,
	NFT_REG32_05,
	NFT_REG32_06,
	NFT_REG32_07,
	NFT_REG32_08,
	NFT_REG32_09,
	NFT_REG32_10,
	NFT_REG32_11,
	NFT_REG32_12,
	NFT_REG32_13,
	NFT_REG32_14,
	NFT_REG32_15,
};
#define NFT_REG_MAX	(__NFT_REG_MAX - 1)

#define NFT_REG_SIZE	16
#define NFT_REG32_SIZE	4

/**
 * enum nft_verdicts - nf_tables internal verdicts
 *
+1 −1
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr,
{
	const struct nft_meta *priv = nft_expr_priv(expr);
	const struct net_device *in = pkt->in, *out = pkt->out;
	u32 *dest = &regs->data[priv->dreg].data[0];
	u32 *dest = &regs->data[priv->dreg];
	const struct net_bridge_port *p;

	switch (priv->key) {
+2 −2
Original line number Diff line number Diff line
@@ -27,9 +27,9 @@ static void nft_redir_ipv4_eval(const struct nft_expr *expr,
	memset(&mr, 0, sizeof(mr));
	if (priv->sreg_proto_min) {
		mr.range[0].min.all =
			*(__be16 *)&regs->data[priv->sreg_proto_min].data[0];
			*(__be16 *)&regs->data[priv->sreg_proto_min];
		mr.range[0].max.all =
			*(__be16 *)&regs->data[priv->sreg_proto_max].data[0];
			*(__be16 *)&regs->data[priv->sreg_proto_max];
		mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
	}

+2 −2
Original line number Diff line number Diff line
@@ -27,9 +27,9 @@ static void nft_redir_ipv6_eval(const struct nft_expr *expr,
	memset(&range, 0, sizeof(range));
	if (priv->sreg_proto_min) {
		range.min_proto.all =
			*(__be16 *)&regs->data[priv->sreg_proto_min].data[0];
			*(__be16 *)&regs->data[priv->sreg_proto_min],
		range.max_proto.all =
			*(__be16 *)&regs->data[priv->sreg_proto_max].data[0];
			*(__be16 *)&regs->data[priv->sreg_proto_max],
		range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
	}

Loading