From b51367aad315985c3d6cf7782bb72438e3b270d8 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Sun, 17 Jul 2016 09:52:11 -0700 Subject: [PATCH] datapath: openvswitch: update checksum in {push,pop}_mpls Upstream commit: commit bc7cc5999fd392cc799630d7e375b2f4e29cc398 Author: Simon Horman openvswitch: update checksum in {push,pop}_mpls In the case of CHECKSUM_COMPLETE the skb checksum should be updated in {push,pop}_mpls() as they the type in the ethernet header. As suggested by Pravin Shelar. Cc: Pravin Shelar Fixes: 25cd9ba0abc0 ("openvswitch: Add basic MPLS support to kernel") Signed-off-by: Simon Horman Acked-by: Pravin B Shelar Signed-off-by: David S. Miller Signed-off-by: Pravin B Shelar Acked-by: Jesse Gross --- datapath/actions.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/datapath/actions.c b/datapath/actions.c index fb5fa8a95..abf7e3bdf 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -139,11 +139,23 @@ static bool is_flow_key_valid(const struct sw_flow_key *key) return !!key->eth.type; } +static void update_ethertype(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; +} + static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, const struct ovs_action_push_mpls *mpls) { __be32 *new_mpls_lse; - struct ethhdr *hdr; /* Networking stack do not allow simultaneous Tunnel and MPLS GSO. */ if (skb->encapsulation) @@ -162,8 +174,7 @@ static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, skb_postpush_rcsum(skb, new_mpls_lse, MPLS_HLEN); - hdr = eth_hdr(skb); - hdr->h_proto = mpls->mpls_ethertype; + update_ethertype(skb, eth_hdr(skb), mpls->mpls_ethertype); if (!ovs_skb_get_inner_protocol(skb)) ovs_skb_set_inner_protocol(skb, skb->protocol); skb->protocol = mpls->mpls_ethertype; @@ -194,7 +205,7 @@ static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key, * field correctly in the presence of VLAN tags. */ hdr = (struct ethhdr *)(skb_mpls_header(skb) - ETH_HLEN); - hdr->h_proto = ethertype; + update_ethertype(skb, hdr, ethertype); if (eth_p_mpls(skb->protocol)) skb->protocol = ethertype; -- 2.20.1