On Thu, Jun 27, 2019 at 6:37 AM John Hurley <john.hur...@netronome.com> wrote: > > Skbs may have their checksum value populated by HW. If this is a checksum > calculated over the entire packet then the CHECKSUM_COMPLETE field is > marked. Changes to the data pointer on the skb throughout the network > stack still try to maintain this complete csum value if it is required > through functions such as skb_postpush_rcsum. > > The MPLS actions in Open vSwitch modify a CHECKSUM_COMPLETE value when > changes are made to packet data without a push or a pull. This occurs when > the ethertype of the MAC header is changed or when MPLS lse fields are > modified. > > The modification is carried out using the csum_partial function to get the > csum of a buffer and add it into the larger checksum. The buffer is an > inversion of the data to be removed followed by the new data. Because the > csum is calculated over 16 bits and these values align with 16 bits, the > effect is the removal of the old value from the CHECKSUM_COMPLETE and > addition of the new value. > > However, the csum fed into the function and the outcome of the > calculation are also inverted. This would only make sense if it was the > new value rather than the old that was inverted in the input buffer. > > Fix the issue by removing the bit inverts in the csum_partial calculation. > > The bug was verified and the fix tested by comparing the folded value of > the updated CHECKSUM_COMPLETE value with the folded value of a full > software checksum calculation (reset skb->csum to 0 and run > skb_checksum_complete(skb)). Prior to the fix the outcomes differed but > after they produce the same result. > > Fixes: 25cd9ba0abc0 ("openvswitch: Add basic MPLS support to kernel") > Fixes: bc7cc5999fd3 ("openvswitch: update checksum in {push,pop}_mpls") > Signed-off-by: John Hurley <john.hur...@netronome.com> > Reviewed-by: Jakub Kicinski <jakub.kicin...@netronome.com> > Reviewed-by: Simon Horman <simon.hor...@netronome.com> > ---
Thanks for fixing it. Acked-by: Pravin B Shelar <pshe...@ovn.org> > net/openvswitch/actions.c | 6 ++---- > 1 file changed, 2 insertions(+), 4 deletions(-) > > diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c > index 151518d..bd13146 100644 > --- a/net/openvswitch/actions.c > +++ b/net/openvswitch/actions.c > @@ -166,8 +166,7 @@ static void update_ethertype(struct sk_buff *skb, struct > ethhdr *hdr, > if (skb->ip_summed == CHECKSUM_COMPLETE) { > __be16 diff[] = { ~(hdr->h_proto), ethertype }; > > - skb->csum = ~csum_partial((char *)diff, sizeof(diff), > - ~skb->csum); > + skb->csum = csum_partial((char *)diff, sizeof(diff), > skb->csum); > } > > hdr->h_proto = ethertype; > @@ -259,8 +258,7 @@ static int set_mpls(struct sk_buff *skb, struct > sw_flow_key *flow_key, > if (skb->ip_summed == CHECKSUM_COMPLETE) { > __be32 diff[] = { ~(stack->label_stack_entry), lse }; > > - skb->csum = ~csum_partial((char *)diff, sizeof(diff), > - ~skb->csum); > + skb->csum = csum_partial((char *)diff, sizeof(diff), > skb->csum); > } > > stack->label_stack_entry = lse; > -- > 2.7.4 >