netfilter: nftables_offload: special ethertype handling for VLAN
The nftables offload parser sets FLOW_DISSECTOR_KEY_BASIC .n_proto to the
ethertype field in the ethertype frame. However:
- FLOW_DISSECTOR_KEY_BASIC .n_proto field always stores either IPv4 or IPv6
ethertypes.
- FLOW_DISSECTOR_KEY_VLAN .vlan_tpid stores either the 802.1q and 802.1ad
ethertypes. Same as for FLOW_DISSECTOR_KEY_CVLAN.
This function adjusts the flow dissector to handle two scenarios:
1) FLOW_DISSECTOR_KEY_VLAN .vlan_tpid is set to 802.1q or 802.1ad.
Then, transfer:
- the .n_proto field to FLOW_DISSECTOR_KEY_VLAN .tpid.
- the original FLOW_DISSECTOR_KEY_VLAN .tpid to the
FLOW_DISSECTOR_KEY_CVLAN .tpid
- the original FLOW_DISSECTOR_KEY_CVLAN .tpid to the .n_proto field.
2) .n_proto is set to 802.1q or 802.1ad. Then, transfer:
- the .n_proto field to FLOW_DISSECTOR_KEY_VLAN .tpid.
- the original FLOW_DISSECTOR_KEY_VLAN .tpid to the .n_proto field.
Fixes: a82055af59
("netfilter: nft_payload: add VLAN offload support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
ff4d90a89d
commit
783003f3bb
@ -47,6 +47,48 @@ void nft_flow_rule_set_addr_type(struct nft_flow_rule *flow,
|
||||
offsetof(struct nft_flow_key, control);
|
||||
}
|
||||
|
||||
struct nft_offload_ethertype {
|
||||
__be16 value;
|
||||
__be16 mask;
|
||||
};
|
||||
|
||||
static void nft_flow_rule_transfer_vlan(struct nft_offload_ctx *ctx,
|
||||
struct nft_flow_rule *flow)
|
||||
{
|
||||
struct nft_flow_match *match = &flow->match;
|
||||
struct nft_offload_ethertype ethertype;
|
||||
|
||||
if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL) &&
|
||||
match->key.basic.n_proto != htons(ETH_P_8021Q) &&
|
||||
match->key.basic.n_proto != htons(ETH_P_8021AD))
|
||||
return;
|
||||
|
||||
ethertype.value = match->key.basic.n_proto;
|
||||
ethertype.mask = match->mask.basic.n_proto;
|
||||
|
||||
if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_VLAN) &&
|
||||
(match->key.vlan.vlan_tpid == htons(ETH_P_8021Q) ||
|
||||
match->key.vlan.vlan_tpid == htons(ETH_P_8021AD))) {
|
||||
match->key.basic.n_proto = match->key.cvlan.vlan_tpid;
|
||||
match->mask.basic.n_proto = match->mask.cvlan.vlan_tpid;
|
||||
match->key.cvlan.vlan_tpid = match->key.vlan.vlan_tpid;
|
||||
match->mask.cvlan.vlan_tpid = match->mask.vlan.vlan_tpid;
|
||||
match->key.vlan.vlan_tpid = ethertype.value;
|
||||
match->mask.vlan.vlan_tpid = ethertype.mask;
|
||||
match->dissector.offset[FLOW_DISSECTOR_KEY_CVLAN] =
|
||||
offsetof(struct nft_flow_key, cvlan);
|
||||
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_CVLAN);
|
||||
} else {
|
||||
match->key.basic.n_proto = match->key.vlan.vlan_tpid;
|
||||
match->mask.basic.n_proto = match->mask.vlan.vlan_tpid;
|
||||
match->key.vlan.vlan_tpid = ethertype.value;
|
||||
match->mask.vlan.vlan_tpid = ethertype.mask;
|
||||
match->dissector.offset[FLOW_DISSECTOR_KEY_VLAN] =
|
||||
offsetof(struct nft_flow_key, vlan);
|
||||
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_VLAN);
|
||||
}
|
||||
}
|
||||
|
||||
struct nft_flow_rule *nft_flow_rule_create(struct net *net,
|
||||
const struct nft_rule *rule)
|
||||
{
|
||||
@ -91,6 +133,8 @@ struct nft_flow_rule *nft_flow_rule_create(struct net *net,
|
||||
|
||||
expr = nft_expr_next(expr);
|
||||
}
|
||||
nft_flow_rule_transfer_vlan(ctx, flow);
|
||||
|
||||
flow->proto = ctx->dep.l3num;
|
||||
kfree(ctx);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user