diff options
Diffstat (limited to 'net/openvswitch/flow.c')
| -rw-r--r-- | net/openvswitch/flow.c | 20 | 
1 files changed, 14 insertions, 6 deletions
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 38147e6a20f5..9d375e74b607 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -637,27 +637,35 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)  			memset(&key->ipv4, 0, sizeof(key->ipv4));  		}  	} else if (eth_p_mpls(key->eth.type)) { -		size_t stack_len = MPLS_HLEN; +		u8 label_count = 1; +		memset(&key->mpls, 0, sizeof(key->mpls));  		skb_set_inner_network_header(skb, skb->mac_len);  		while (1) {  			__be32 lse; -			error = check_header(skb, skb->mac_len + stack_len); +			error = check_header(skb, skb->mac_len + +					     label_count * MPLS_HLEN);  			if (unlikely(error))  				return 0;  			memcpy(&lse, skb_inner_network_header(skb), MPLS_HLEN); -			if (stack_len == MPLS_HLEN) -				memcpy(&key->mpls.top_lse, &lse, MPLS_HLEN); +			if (label_count <= MPLS_LABEL_DEPTH) +				memcpy(&key->mpls.lse[label_count - 1], &lse, +				       MPLS_HLEN); -			skb_set_inner_network_header(skb, skb->mac_len + stack_len); +			skb_set_inner_network_header(skb, skb->mac_len + +						     label_count * MPLS_HLEN);  			if (lse & htonl(MPLS_LS_S_MASK))  				break; -			stack_len += MPLS_HLEN; +			label_count++;  		} +		if (label_count > MPLS_LABEL_DEPTH) +			label_count = MPLS_LABEL_DEPTH; + +		key->mpls.num_labels_mask = GENMASK(label_count - 1, 0);  	} else if (key->eth.type == htons(ETH_P_IPV6)) {  		int nh_len;             /* IPv6 Header + Extensions */  |