diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2013-02-11 04:27:41 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-13 13:30:10 -0500 |
commit | c9af6db4c11ccc6c3e7f19bbc15d54023956f97c (patch) | |
tree | c596e747d8940b848931ac31701e245a6c0efaf6 /drivers/net/virtio_net.c | |
parent | b8fa4100350432504df438014e2e5e9c1bbb6325 (diff) |
net: Fix possible wrong checksum generation.
Patch cef401de7be8c4e (net: fix possible wrong checksum
generation) fixed wrong checksum calculation but it broke TSO by
defining new GSO type but not a netdev feature for that type.
net_gso_ok() would not allow hardware checksum/segmentation
offload of such packets without the feature.
Following patch fixes TSO and wrong checksum. This patch uses
same logic that Eric Dumazet used. Patch introduces new flag
SKBTX_SHARED_FRAG if at least one frag can be modified by
the user. but SKBTX_SHARED_FRAG flag is kept in skb shared
info tx_flags rather than gso_type.
tx_flags is better compared to gso_type since we can have skb with
shared frag without gso packet. It does not link SHARED_FRAG to
GSO, So there is no need to define netdev feature for this.
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r-- | drivers/net/virtio_net.c | 13 |
1 files changed, 5 insertions, 8 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 381a2d8d8a81..192c91c8e799 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -227,7 +227,7 @@ static void set_skb_frag(struct sk_buff *skb, struct page *page, | |||
227 | skb->len += size; | 227 | skb->len += size; |
228 | skb->truesize += PAGE_SIZE; | 228 | skb->truesize += PAGE_SIZE; |
229 | skb_shinfo(skb)->nr_frags++; | 229 | skb_shinfo(skb)->nr_frags++; |
230 | skb_shinfo(skb)->gso_type |= SKB_GSO_SHARED_FRAG; | 230 | skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; |
231 | *len -= size; | 231 | *len -= size; |
232 | } | 232 | } |
233 | 233 | ||
@@ -387,18 +387,16 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len) | |||
387 | ntohs(skb->protocol), skb->len, skb->pkt_type); | 387 | ntohs(skb->protocol), skb->len, skb->pkt_type); |
388 | 388 | ||
389 | if (hdr->hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE) { | 389 | if (hdr->hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE) { |
390 | unsigned short gso_type = 0; | ||
391 | |||
392 | pr_debug("GSO!\n"); | 390 | pr_debug("GSO!\n"); |
393 | switch (hdr->hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { | 391 | switch (hdr->hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { |
394 | case VIRTIO_NET_HDR_GSO_TCPV4: | 392 | case VIRTIO_NET_HDR_GSO_TCPV4: |
395 | gso_type = SKB_GSO_TCPV4; | 393 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; |
396 | break; | 394 | break; |
397 | case VIRTIO_NET_HDR_GSO_UDP: | 395 | case VIRTIO_NET_HDR_GSO_UDP: |
398 | gso_type = SKB_GSO_UDP; | 396 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP; |
399 | break; | 397 | break; |
400 | case VIRTIO_NET_HDR_GSO_TCPV6: | 398 | case VIRTIO_NET_HDR_GSO_TCPV6: |
401 | gso_type = SKB_GSO_TCPV6; | 399 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; |
402 | break; | 400 | break; |
403 | default: | 401 | default: |
404 | net_warn_ratelimited("%s: bad gso type %u.\n", | 402 | net_warn_ratelimited("%s: bad gso type %u.\n", |
@@ -407,7 +405,7 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len) | |||
407 | } | 405 | } |
408 | 406 | ||
409 | if (hdr->hdr.gso_type & VIRTIO_NET_HDR_GSO_ECN) | 407 | if (hdr->hdr.gso_type & VIRTIO_NET_HDR_GSO_ECN) |
410 | gso_type |= SKB_GSO_TCP_ECN; | 408 | skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; |
411 | 409 | ||
412 | skb_shinfo(skb)->gso_size = hdr->hdr.gso_size; | 410 | skb_shinfo(skb)->gso_size = hdr->hdr.gso_size; |
413 | if (skb_shinfo(skb)->gso_size == 0) { | 411 | if (skb_shinfo(skb)->gso_size == 0) { |
@@ -415,7 +413,6 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len) | |||
415 | goto frame_err; | 413 | goto frame_err; |
416 | } | 414 | } |
417 | 415 | ||
418 | skb_shinfo(skb)->gso_type |= gso_type; | ||
419 | /* Header must be checked, and gso_segs computed. */ | 416 | /* Header must be checked, and gso_segs computed. */ |
420 | skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; | 417 | skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; |
421 | skb_shinfo(skb)->gso_segs = 0; | 418 | skb_shinfo(skb)->gso_segs = 0; |