Do not always set skb->protocol to be the ethertype of the L3 header.
For a packet with non-accelerated VLAN tags skb->protocol needs to be the
ethertype of the outermost non-accelerated VLAN ethertype.
Any VLAN offloading is undone on the OVS netlink interface, and any VLAN tags
added by userspace are non-accelerated, as are double tagged VLAN packets.
Fixes: 018c1dda5f ("openvswitch: 802.1AD Flow handling, actions, vlan parsing,
netlink attributes")
Fixes: 5108bbaddc ("openvswitch: add processing of L3 packets")
Signed-off-by: Jarno Rajahalme <[email protected]>
Signed-off-by: Yi Yang <[email protected]>
---
datapath/datapath.c | 1 -
datapath/flow.c | 42 +++++++++++++++++-------------------------
2 files changed, 17 insertions(+), 26 deletions(-)
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 1deb62d..dd19a0e 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -617,7 +617,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb,
struct genl_info *info)
rcu_assign_pointer(flow->sf_acts, acts);
packet->priority = flow->key.phy.priority;
packet->mark = flow->key.phy.skb_mark;
- packet->protocol = flow->key.eth.type;
rcu_read_lock();
dp = get_dp_rcu(net, ovs_header->dp_ifindex);
diff --git a/datapath/flow.c b/datapath/flow.c
index 240bd00..cf35272 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -334,6 +334,7 @@ static int parse_vlan(struct sk_buff *skb, struct
sw_flow_key *key)
qp = (struct qtag_prefix *) skb->data;
key->eth.tci = qp->tci | htons(VLAN_TAG_PRESENT);
+ key->eth.type = qp->eth_type;
__skb_pull(skb, sizeof(struct qtag_prefix));
return 0;
@@ -493,6 +494,7 @@ static int key_extract(struct sk_buff *skb, struct
sw_flow_key *key)
return -EINVAL;
skb_reset_network_header(skb);
+ key->eth.type = skb->protocol;
} else {
eth = eth_hdr(skb);
ether_addr_copy(key->eth.src, eth->h_source);
@@ -504,11 +506,14 @@ static int key_extract(struct sk_buff *skb, struct
sw_flow_key *key)
*/
key->eth.tci = 0;
- if (skb_vlan_tag_present(skb))
+ if (skb_vlan_tag_present(skb)) {
key->eth.tci = htons(skb->vlan_tci);
+ key->eth.type = skb->vlan_proto;
+ }
else if (eth->h_proto == htons(ETH_P_8021Q))
if (unlikely(parse_vlan(skb, key)))
return -ENOMEM;
+ skb->protocol = key->eth.type;
key->eth.type = parse_ethertype(skb);
if (unlikely(key->eth.type == htons(0)))
@@ -519,7 +524,8 @@ static int key_extract(struct sk_buff *skb, struct
sw_flow_key *key)
}
skb_reset_mac_len(skb);
- key->eth.type = skb->protocol;
+ if (!eth_type_is_vlan(skb->protocol))
+ skb->protocol = key->eth.type;
/* Network layer. */
if (key->eth.type == htons(ETH_P_IP)) {
@@ -786,29 +792,15 @@ int ovs_flow_key_extract_userspace(struct net *net, const
struct nlattr *attr,
if (err)
return err;
- if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) {
- /* key_extract assumes that skb->protocol is set-up for
- * layer 3 packets which is the case for other callers,
- * in particular packets recieved from the network stack.
- * Here the correct value can be set from the metadata
- * extracted above.
- */
- skb->protocol = key->eth.type;
- } else {
- struct ethhdr *eth;
-
- skb_reset_mac_header(skb);
- eth = eth_hdr(skb);
-
- /* Normally, setting the skb 'protocol' field would be
- * handled by a call to eth_type_trans(), but it assumes
- * there's a sending device, which we may not have.
- */
- if (eth_proto_is_802_3(eth->h_proto))
- skb->protocol = eth->h_proto;
- else
- skb->protocol = htons(ETH_P_802_2);
- }
+ /* key_extract assumes that skb->protocol is set-up for
+ * layer 3 packets which is the case for other callers,
+ * in particular packets recieved from the network stack.
+ * Here the correct value can be set from the metadata
+ * extracted above. For layer 2 packets we initialize
+ * skb->protocol to zero and set it in key_extract() while
+ * parsing the L2 headers.
+ */
+ skb->protocol = key->eth.type;
return key_extract(skb, key);
}
--
2.1.0
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev