forked from mirrors/linux
		
	net: core: move push MPLS functionality from OvS to core helper
Open vSwitch provides code to push an MPLS header to a packet. In preparation for supporting this in TC, move the push code to an skb helper that can be reused. Signed-off-by: John Hurley <john.hurley@netronome.com> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Simon Horman <simon.horman@netronome.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Acked-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									af144a9834
								
							
						
					
					
						commit
						8822e270d6
					
				
					 3 changed files with 69 additions and 27 deletions
				
			
		|  | @ -3447,6 +3447,7 @@ int skb_ensure_writable(struct sk_buff *skb, int write_len); | |||
| int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci); | ||||
| int skb_vlan_pop(struct sk_buff *skb); | ||||
| int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci); | ||||
| int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto); | ||||
| struct sk_buff *pskb_extract(struct sk_buff *skb, int off, int to_copy, | ||||
| 			     gfp_t gfp); | ||||
| 
 | ||||
|  |  | |||
|  | @ -66,6 +66,7 @@ | |||
| #include <net/checksum.h> | ||||
| #include <net/ip6_checksum.h> | ||||
| #include <net/xfrm.h> | ||||
| #include <net/mpls.h> | ||||
| 
 | ||||
| #include <linux/uaccess.h> | ||||
| #include <trace/events/skb.h> | ||||
|  | @ -5425,6 +5426,69 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci) | |||
| } | ||||
| EXPORT_SYMBOL(skb_vlan_push); | ||||
| 
 | ||||
| /* Update the ethertype of hdr and the skb csum value if required. */ | ||||
| static void skb_mod_eth_type(struct sk_buff *skb, struct ethhdr *hdr, | ||||
| 			     __be16 ethertype) | ||||
| { | ||||
| 	if (skb->ip_summed == CHECKSUM_COMPLETE) { | ||||
| 		__be16 diff[] = { ~hdr->h_proto, ethertype }; | ||||
| 
 | ||||
| 		skb->csum = csum_partial((char *)diff, sizeof(diff), skb->csum); | ||||
| 	} | ||||
| 
 | ||||
| 	hdr->h_proto = ethertype; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * skb_mpls_push() - push a new MPLS header after the mac header | ||||
|  * | ||||
|  * @skb: buffer | ||||
|  * @mpls_lse: MPLS label stack entry to push | ||||
|  * @mpls_proto: ethertype of the new MPLS header (expects 0x8847 or 0x8848) | ||||
|  * | ||||
|  * Expects skb->data at mac header. | ||||
|  * | ||||
|  * Returns 0 on success, -errno otherwise. | ||||
|  */ | ||||
| int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto) | ||||
| { | ||||
| 	struct mpls_shim_hdr *lse; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (unlikely(!eth_p_mpls(mpls_proto))) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* Networking stack does not allow simultaneous Tunnel and MPLS GSO. */ | ||||
| 	if (skb->encapsulation) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	err = skb_cow_head(skb, MPLS_HLEN); | ||||
| 	if (unlikely(err)) | ||||
| 		return err; | ||||
| 
 | ||||
| 	if (!skb->inner_protocol) { | ||||
| 		skb_set_inner_network_header(skb, skb->mac_len); | ||||
| 		skb_set_inner_protocol(skb, skb->protocol); | ||||
| 	} | ||||
| 
 | ||||
| 	skb_push(skb, MPLS_HLEN); | ||||
| 	memmove(skb_mac_header(skb) - MPLS_HLEN, skb_mac_header(skb), | ||||
| 		skb->mac_len); | ||||
| 	skb_reset_mac_header(skb); | ||||
| 	skb_set_network_header(skb, skb->mac_len); | ||||
| 
 | ||||
| 	lse = mpls_hdr(skb); | ||||
| 	lse->label_stack_entry = mpls_lse; | ||||
| 	skb_postpush_rcsum(skb, lse, MPLS_HLEN); | ||||
| 
 | ||||
| 	if (skb->dev && skb->dev->type == ARPHRD_ETHER) | ||||
| 		skb_mod_eth_type(skb, eth_hdr(skb), mpls_proto); | ||||
| 	skb->protocol = mpls_proto; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(skb_mpls_push); | ||||
| 
 | ||||
| /**
 | ||||
|  * alloc_skb_with_frags - allocate skb with page frags | ||||
|  * | ||||
|  |  | |||
|  | @ -175,34 +175,11 @@ static void update_ethertype(struct sk_buff *skb, struct ethhdr *hdr, | |||
| static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, | ||||
| 		     const struct ovs_action_push_mpls *mpls) | ||||
| { | ||||
| 	struct mpls_shim_hdr *new_mpls_lse; | ||||
| 	int err; | ||||
| 
 | ||||
| 	/* Networking stack do not allow simultaneous Tunnel and MPLS GSO. */ | ||||
| 	if (skb->encapsulation) | ||||
| 		return -ENOTSUPP; | ||||
| 
 | ||||
| 	if (skb_cow_head(skb, MPLS_HLEN) < 0) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	if (!skb->inner_protocol) { | ||||
| 		skb_set_inner_network_header(skb, skb->mac_len); | ||||
| 		skb_set_inner_protocol(skb, skb->protocol); | ||||
| 	} | ||||
| 
 | ||||
| 	skb_push(skb, MPLS_HLEN); | ||||
| 	memmove(skb_mac_header(skb) - MPLS_HLEN, skb_mac_header(skb), | ||||
| 		skb->mac_len); | ||||
| 	skb_reset_mac_header(skb); | ||||
| 	skb_set_network_header(skb, skb->mac_len); | ||||
| 
 | ||||
| 	new_mpls_lse = mpls_hdr(skb); | ||||
| 	new_mpls_lse->label_stack_entry = mpls->mpls_lse; | ||||
| 
 | ||||
| 	skb_postpush_rcsum(skb, new_mpls_lse, MPLS_HLEN); | ||||
| 
 | ||||
| 	if (ovs_key_mac_proto(key) == MAC_PROTO_ETHERNET) | ||||
| 		update_ethertype(skb, eth_hdr(skb), mpls->mpls_ethertype); | ||||
| 	skb->protocol = mpls->mpls_ethertype; | ||||
| 	err = skb_mpls_push(skb, mpls->mpls_lse, mpls->mpls_ethertype); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	invalidate_flow_key(key); | ||||
| 	return 0; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 John Hurley
						John Hurley