diff options
Diffstat (limited to 'net/openvswitch')
| -rw-r--r-- | net/openvswitch/datapath.c | 2 | ||||
| -rw-r--r-- | net/openvswitch/flow.c | 15 | ||||
| -rw-r--r-- | net/openvswitch/flow_netlink.c | 16 | 
3 files changed, 21 insertions, 12 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 99cfafc2a139..ef38e5aecd28 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -308,7 +308,7 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,  			     const struct dp_upcall_info *upcall_info,  				 uint32_t cutlen)  { -	unsigned short gso_type = skb_shinfo(skb)->gso_type; +	unsigned int gso_type = skb_shinfo(skb)->gso_type;  	struct sw_flow_key later_key;  	struct sk_buff *segs, *nskb;  	int err; 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)) { diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index dc424798ba6f..624ea74353dd 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -2241,14 +2241,11 @@ int ovs_nla_put_mask(const struct sw_flow *flow, struct sk_buff *skb)  #define MAX_ACTIONS_BUFSIZE	(32 * 1024) -static struct sw_flow_actions *nla_alloc_flow_actions(int size, bool log) +static struct sw_flow_actions *nla_alloc_flow_actions(int size)  {  	struct sw_flow_actions *sfa; -	if (size > MAX_ACTIONS_BUFSIZE) { -		OVS_NLERR(log, "Flow action size %u bytes exceeds max", size); -		return ERR_PTR(-EINVAL); -	} +	WARN_ON_ONCE(size > MAX_ACTIONS_BUFSIZE);  	sfa = kmalloc(sizeof(*sfa) + size, GFP_KERNEL);  	if (!sfa) @@ -2321,12 +2318,15 @@ static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa,  	new_acts_size = ksize(*sfa) * 2;  	if (new_acts_size > MAX_ACTIONS_BUFSIZE) { -		if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size) +		if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size) { +			OVS_NLERR(log, "Flow action size exceeds max %u", +				  MAX_ACTIONS_BUFSIZE);  			return ERR_PTR(-EMSGSIZE); +		}  		new_acts_size = MAX_ACTIONS_BUFSIZE;  	} -	acts = nla_alloc_flow_actions(new_acts_size, log); +	acts = nla_alloc_flow_actions(new_acts_size);  	if (IS_ERR(acts))  		return (void *)acts; @@ -3059,7 +3059,7 @@ int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,  {  	int err; -	*sfa = nla_alloc_flow_actions(nla_len(attr), log); +	*sfa = nla_alloc_flow_actions(min(nla_len(attr), MAX_ACTIONS_BUFSIZE));  	if (IS_ERR(*sfa))  		return PTR_ERR(*sfa);  | 

