Skip to content

Commit

Permalink
netfilter: nftables_offload: VLAN id needs host byteorder in flow dis…
Browse files Browse the repository at this point in the history
…sector

The flow dissector representation expects the VLAN id in host byteorder.
Add the NFT_OFFLOAD_F_NETWORK2HOST flag to swap the bytes from nft_cmp.

Fixes: a82055a ("netfilter: nft_payload: add VLAN offload support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Pablo Neira Ayuso committed Apr 18, 2021
1 parent 14c2064 commit ff4d90a
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 7 deletions.
11 changes: 10 additions & 1 deletion include/net/netfilter/nf_tables_offload.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@
#include <net/flow_offload.h>
#include <net/netfilter/nf_tables.h>

enum nft_offload_reg_flags {
NFT_OFFLOAD_F_NETWORK2HOST = (1 << 0),
};

struct nft_offload_reg {
u32 key;
u32 len;
u32 base_offset;
u32 offset;
u32 flags;
struct nft_data data;
struct nft_data mask;
};
Expand Down Expand Up @@ -72,13 +77,17 @@ struct nft_flow_rule *nft_flow_rule_create(struct net *net, const struct nft_rul
void nft_flow_rule_destroy(struct nft_flow_rule *flow);
int nft_flow_rule_offload_commit(struct net *net);

#define NFT_OFFLOAD_MATCH(__key, __base, __field, __len, __reg) \
#define NFT_OFFLOAD_MATCH_FLAGS(__key, __base, __field, __len, __reg, __flags) \
(__reg)->base_offset = \
offsetof(struct nft_flow_key, __base); \
(__reg)->offset = \
offsetof(struct nft_flow_key, __base.__field); \
(__reg)->len = __len; \
(__reg)->key = __key; \
(__reg)->flags = __flags;

#define NFT_OFFLOAD_MATCH(__key, __base, __field, __len, __reg) \
NFT_OFFLOAD_MATCH_FLAGS(__key, __base, __field, __len, __reg, 0)

#define NFT_OFFLOAD_MATCH_EXACT(__key, __base, __field, __len, __reg) \
NFT_OFFLOAD_MATCH(__key, __base, __field, __len, __reg) \
Expand Down
41 changes: 39 additions & 2 deletions net/netfilter/nft_cmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,19 +114,56 @@ static int nft_cmp_dump(struct sk_buff *skb, const struct nft_expr *expr)
return -1;
}

union nft_cmp_offload_data {
u16 val16;
u32 val32;
u64 val64;
};

static void nft_payload_n2h(union nft_cmp_offload_data *data,
const u8 *val, u32 len)
{
switch (len) {
case 2:
data->val16 = ntohs(*((u16 *)val));
break;
case 4:
data->val32 = ntohl(*((u32 *)val));
break;
case 8:
data->val64 = be64_to_cpu(*((u64 *)val));
break;
default:
WARN_ON_ONCE(1);
break;
}
}

static int __nft_cmp_offload(struct nft_offload_ctx *ctx,
struct nft_flow_rule *flow,
const struct nft_cmp_expr *priv)
{
struct nft_offload_reg *reg = &ctx->regs[priv->sreg];
union nft_cmp_offload_data _data, _datamask;
u8 *mask = (u8 *)&flow->match.mask;
u8 *key = (u8 *)&flow->match.key;
u8 *data, *datamask;

if (priv->op != NFT_CMP_EQ || priv->len > reg->len)
return -EOPNOTSUPP;

memcpy(key + reg->offset, &priv->data, reg->len);
memcpy(mask + reg->offset, &reg->mask, reg->len);
if (reg->flags & NFT_OFFLOAD_F_NETWORK2HOST) {
nft_payload_n2h(&_data, (u8 *)&priv->data, reg->len);
nft_payload_n2h(&_datamask, (u8 *)&reg->mask, reg->len);
data = (u8 *)&_data;
datamask = (u8 *)&_datamask;
} else {
data = (u8 *)&priv->data;
datamask = (u8 *)&reg->mask;
}

memcpy(key + reg->offset, data, reg->len);
memcpy(mask + reg->offset, datamask, reg->len);

flow->match.dissector.used_keys |= BIT(reg->key);
flow->match.dissector.offset[reg->key] = reg->base_offset;
Expand Down
10 changes: 6 additions & 4 deletions net/netfilter/nft_payload.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,9 @@ static int nft_payload_offload_ll(struct nft_offload_ctx *ctx,
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
return -EOPNOTSUPP;

NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_VLAN, vlan,
vlan_tci, sizeof(__be16), reg);
NFT_OFFLOAD_MATCH_FLAGS(FLOW_DISSECTOR_KEY_VLAN, vlan,
vlan_tci, sizeof(__be16), reg,
NFT_OFFLOAD_F_NETWORK2HOST);
break;
case offsetof(struct vlan_ethhdr, h_vlan_encapsulated_proto):
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
Expand All @@ -241,8 +242,9 @@ static int nft_payload_offload_ll(struct nft_offload_ctx *ctx,
if (!nft_payload_offload_mask(reg, priv->len, sizeof(__be16)))
return -EOPNOTSUPP;

NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_CVLAN, cvlan,
vlan_tci, sizeof(__be16), reg);
NFT_OFFLOAD_MATCH_FLAGS(FLOW_DISSECTOR_KEY_CVLAN, cvlan,
vlan_tci, sizeof(__be16), reg,
NFT_OFFLOAD_F_NETWORK2HOST);
break;
case offsetof(struct vlan_ethhdr, h_vlan_encapsulated_proto) +
sizeof(struct vlan_hdr):
Expand Down

0 comments on commit ff4d90a

Please sign in to comment.