diff options
Diffstat (limited to 'net/openvswitch/flow.c')
| -rw-r--r-- | net/openvswitch/flow.c | 15 | 
1 files changed, 12 insertions, 3 deletions
| diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index dbe2379329c5..f039064ce922 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -579,6 +579,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); @@ -592,15 +593,23 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)  		if (unlikely(parse_vlan(skb, key)))  			return -ENOMEM; -		skb->protocol = parse_ethertype(skb); -		if (unlikely(skb->protocol == htons(0))) +		key->eth.type = parse_ethertype(skb); +		if (unlikely(key->eth.type == htons(0)))  			return -ENOMEM; +		/* Multiple tagged packets need to retain TPID to satisfy +		 * skb_vlan_pop(), which will later shift the ethertype into +		 * skb->protocol. +		 */ +		if (key->eth.cvlan.tci & htons(VLAN_TAG_PRESENT)) +			skb->protocol = key->eth.cvlan.tpid; +		else +			skb->protocol = key->eth.type; +  		skb_reset_network_header(skb);  		__skb_push(skb, skb->data - skb_mac_header(skb));  	}  	skb_reset_mac_len(skb); -	key->eth.type = skb->protocol;  	/* Network layer. */  	if (key->eth.type == htons(ETH_P_IP)) { |