diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index a449439bd65366e5790037c21a4d3ce3f0e1ce97..acf6450ceff5dda54a5e11360f44ee97432dfb9e 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -21,6 +21,7 @@ #include #include #include +#include /* * A macvtap queue is the central object of this driver, it connects @@ -645,6 +646,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, int vnet_hdr_len = 0; int copylen = 0; bool zerocopy = false; + struct flow_keys keys; if (q->flags & IFF_VNET_HDR) { vnet_hdr_len = q->vnet_hdr_sz; @@ -725,6 +727,13 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, goto err_kfree; } + if (skb->ip_summed == CHECKSUM_PARTIAL) + skb_set_transport_header(skb, skb_checksum_start_offset(skb)); + else if (skb_flow_dissect(skb, &keys)) + skb_set_transport_header(skb, keys.thoff); + else + skb_set_transport_header(skb, ETH_HLEN); + rcu_read_lock_bh(); vlan = rcu_dereference_bh(q->vlan); /* copy skb_ubuf_info for callback when skb has no error */ diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 95837c1b197ae5b5803bc1f78f895ac4fba51039..48cd73a2dc5506afa26d41dac57721205ae0e48e 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -70,6 +70,7 @@ #include #include +#include /* Uncomment to enable debugging */ /* #define TUN_DEBUG 1 */ @@ -1049,6 +1050,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, bool zerocopy = false; int err; u32 rxhash; + struct flow_keys keys; if (!(tun->flags & TUN_NO_PI)) { if ((len -= sizeof(pi)) > total_len) @@ -1203,6 +1205,14 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, } skb_reset_network_header(skb); + + if (skb->ip_summed == CHECKSUM_PARTIAL) + skb_set_transport_header(skb, skb_checksum_start_offset(skb)); + else if (skb_flow_dissect(skb, &keys)) + skb_set_transport_header(skb, keys.thoff); + else + skb_reset_transport_header(skb); + rxhash = skb_get_rxhash(skb); netif_rx_ni(skb); diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index aa28550fc9b616d39d9e6269b1fb3e2cc6aa1a7a..fc8faa74b25003d06216a8cbf81bf2625e26bfdb 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -1184,6 +1185,7 @@ static int checksum_setup(struct xenvif *vif, struct sk_buff *skb) if (th >= skb_tail_pointer(skb)) goto out; + skb_set_transport_header(skb, 4 * iph->ihl); skb->csum_start = th - skb->head; switch (iph->protocol) { case IPPROTO_TCP: @@ -1495,6 +1497,7 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk) skb->dev = vif->dev; skb->protocol = eth_type_trans(skb, skb->dev); + skb_reset_network_header(skb); if (checksum_setup(vif, skb)) { netdev_dbg(vif->dev, @@ -1503,6 +1506,15 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk) continue; } + if (!skb_transport_header_was_set(skb)) { + struct flow_keys keys; + + if (skb_flow_dissect(skb, &keys)) + skb_set_transport_header(skb, keys.thoff); + else + skb_reset_transport_header(skb); + } + vif->dev->stats.rx_bytes += skb->len; vif->dev->stats.rx_packets++; diff --git a/net/core/dev.c b/net/core/dev.c index de930b75171267004892382438d6e8c122f4720f..f5ad23bb24fcb42551ec1875c696ae5a4a8ac000 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2588,6 +2588,7 @@ static void qdisc_pkt_len_init(struct sk_buff *skb) */ if (shinfo->gso_size) { unsigned int hdr_len; + u16 gso_segs = shinfo->gso_segs; /* mac layer + network layer */ hdr_len = skb_transport_header(skb) - skb_mac_header(skb); @@ -2597,7 +2598,12 @@ static void qdisc_pkt_len_init(struct sk_buff *skb) hdr_len += tcp_hdrlen(skb); else hdr_len += sizeof(struct udphdr); - qdisc_skb_cb(skb)->pkt_len += (shinfo->gso_segs - 1) * hdr_len; + + if (shinfo->gso_type & SKB_GSO_DODGY) + gso_segs = DIV_ROUND_UP(skb->len - hdr_len, + shinfo->gso_size); + + qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len; } } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index bd0d14c97d412c7276504bc29d3977be93f3b067..83fdd0a87eb6d738b6932c9cbd92d9ca7739a964 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -88,6 +88,7 @@ #include #include #include +#include #ifdef CONFIG_INET #include @@ -1412,6 +1413,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, __be16 proto = 0; int err; int extra_len = 0; + struct flow_keys keys; /* * Get and verify the address. @@ -1512,6 +1514,11 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, if (unlikely(extra_len == 4)) skb->no_fcs = 1; + if (skb_flow_dissect(skb, &keys)) + skb_set_transport_header(skb, keys.thoff); + else + skb_reset_transport_header(skb); + dev_queue_xmit(skb); rcu_read_unlock(); return len; @@ -1918,6 +1925,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, struct page *page; void *data; int err; + struct flow_keys keys; ph.raw = frame; @@ -1943,6 +1951,11 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, skb_reserve(skb, hlen); skb_reset_network_header(skb); + if (skb_flow_dissect(skb, &keys)) + skb_set_transport_header(skb, keys.thoff); + else + skb_reset_transport_header(skb); + if (po->tp_tx_has_off) { int off_min, off_max, off; off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll); @@ -2199,6 +2212,7 @@ static int packet_snd(struct socket *sock, unsigned short gso_type = 0; int hlen, tlen; int extra_len = 0; + struct flow_keys keys; /* * Get and verify the address. @@ -2351,6 +2365,13 @@ static int packet_snd(struct socket *sock, len += vnet_hdr_len; } + if (skb->ip_summed == CHECKSUM_PARTIAL) + skb_set_transport_header(skb, skb_checksum_start_offset(skb)); + else if (skb_flow_dissect(skb, &keys)) + skb_set_transport_header(skb, keys.thoff); + else + skb_set_transport_header(skb, reserve); + if (unlikely(extra_len == 4)) skb->no_fcs = 1;