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 <ja...@ovn.org>
Signed-off-by: Yi Yang <yi.y.y...@intel.com>
---
 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
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to