aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/vxlan.c
diff options
context:
space:
mode:
authorTom Herbert <therbert@google.com>2015-02-10 19:30:27 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-11 18:12:09 -0500
commit26c4f7da3e413da697a7beb22ad496390eda7da0 (patch)
tree55182c7a68fc4129369ffce2ac30a897cc3d55a1 /drivers/net/vxlan.c
parent13101602c4a9f653d59af9469040797bc5b361ca (diff)
net: Fix remcsum in GRO path to not change packet
Remote checksum offload processing is currently the same for both the GRO and non-GRO path. When the remote checksum offload option is encountered, the checksum field referred to is modified in the packet. So in the GRO case, the packet is modified in the GRO path and then the operation is skipped when the packet goes through the normal path based on skb->remcsum_offload. There is a problem in that the packet may be modified in the GRO path, but then forwarded off host still containing the remote checksum option. A remote host will again perform RCO but now the checksum verification will fail since GRO RCO already modified the checksum. To fix this, we ensure that GRO restores a packet to it's original state before returning. In this model, when GRO processes a remote checksum option it still changes the checksum per the algorithm but on return from lower layer processing the checksum is restored to its original value. In this patch we add define gro_remcsum structure which is passed to skb_gro_remcsum_process to save offset and delta for the checksum being changed. After lower layer processing, skb_gro_remcsum_cleanup is called to restore the checksum before returning from GRO. Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vxlan.c')
-rw-r--r--drivers/net/vxlan.c19
1 files changed, 9 insertions, 10 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 0e57e862c399..30310a63475a 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -555,12 +555,12 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
555static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, 555static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
556 unsigned int off, 556 unsigned int off,
557 struct vxlanhdr *vh, size_t hdrlen, 557 struct vxlanhdr *vh, size_t hdrlen,
558 u32 data) 558 u32 data, struct gro_remcsum *grc)
559{ 559{
560 size_t start, offset, plen; 560 size_t start, offset, plen;
561 561
562 if (skb->remcsum_offload) 562 if (skb->remcsum_offload)
563 return vh; 563 return NULL;
564 564
565 if (!NAPI_GRO_CB(skb)->csum_valid) 565 if (!NAPI_GRO_CB(skb)->csum_valid)
566 return NULL; 566 return NULL;
@@ -579,7 +579,8 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
579 return NULL; 579 return NULL;
580 } 580 }
581 581
582 skb_gro_remcsum_process(skb, (void *)vh + hdrlen, start, offset); 582 skb_gro_remcsum_process(skb, (void *)vh + hdrlen,
583 start, offset, grc);
583 584
584 skb->remcsum_offload = 1; 585 skb->remcsum_offload = 1;
585 586
@@ -597,6 +598,9 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
597 struct vxlan_sock *vs = container_of(uoff, struct vxlan_sock, 598 struct vxlan_sock *vs = container_of(uoff, struct vxlan_sock,
598 udp_offloads); 599 udp_offloads);
599 u32 flags; 600 u32 flags;
601 struct gro_remcsum grc;
602
603 skb_gro_remcsum_init(&grc);
600 604
601 off_vx = skb_gro_offset(skb); 605 off_vx = skb_gro_offset(skb);
602 hlen = off_vx + sizeof(*vh); 606 hlen = off_vx + sizeof(*vh);
@@ -614,7 +618,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
614 618
615 if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) { 619 if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) {
616 vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr), 620 vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr),
617 ntohl(vh->vx_vni)); 621 ntohl(vh->vx_vni), &grc);
618 622
619 if (!vh) 623 if (!vh)
620 goto out; 624 goto out;
@@ -637,6 +641,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
637 pp = eth_gro_receive(head, skb); 641 pp = eth_gro_receive(head, skb);
638 642
639out: 643out:
644 skb_gro_remcsum_cleanup(skb, &grc);
640 NAPI_GRO_CB(skb)->flush |= flush; 645 NAPI_GRO_CB(skb)->flush |= flush;
641 646
642 return pp; 647 return pp;
@@ -1154,12 +1159,6 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh,
1154{ 1159{
1155 size_t start, offset, plen; 1160 size_t start, offset, plen;
1156 1161
1157 if (skb->remcsum_offload) {
1158 /* Already processed in GRO path */
1159 skb->remcsum_offload = 0;
1160 return vh;
1161 }
1162
1163 start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT; 1162 start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT;
1164 offset = start + ((data & VXLAN_RCO_UDP) ? 1163 offset = start + ((data & VXLAN_RCO_UDP) ?
1165 offsetof(struct udphdr, check) : 1164 offsetof(struct udphdr, check) :