drivers/net,ipv6: Fix virtio/IPv6 regression in 3.16
svn path=/dists/sid/linux/; revision=21998
This commit is contained in:
parent
a4a6a59131
commit
6f3eb650e5
|
@ -129,6 +129,9 @@ linux (3.16.7-1) UNRELEASED; urgency=medium
|
|||
(Closes: #767148)
|
||||
* wireless: rt2x00: add new rt2800usb device (thanks to Cyril Brulebois)
|
||||
(Closes: #766802)
|
||||
* drivers/net,ipv6: Fix virtio/IPv6 regression in 3.16:
|
||||
- drivers/net: Disable UFO through virtio
|
||||
- drivers/net,ipv6: Select IPv6 fragment idents for virtio UFO packets
|
||||
|
||||
[ Mauricio Faria de Oliveira ]
|
||||
* [ppc64el] Disable CONFIG_CMDLINE{,_BOOL} usage for setting consoles
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
From: Ben Hutchings <ben@decadent.org.uk>
|
||||
Date: Thu, 30 Oct 2014 18:27:12 +0000
|
||||
Subject: [1/2] drivers/net: Disable UFO through virtio
|
||||
Origin: https://git.kernel.org/cgit/linux/kernel/git/davem/net.git/commit?id=3d0ad09412ffe00c9afa201d01effdb6023d09b4
|
||||
|
||||
IPv6 does not allow fragmentation by routers, so there is no
|
||||
fragmentation ID in the fixed header. UFO for IPv6 requires the ID to
|
||||
be passed separately, but there is no provision for this in the virtio
|
||||
net protocol.
|
||||
|
||||
Until recently our software implementation of UFO/IPv6 generated a new
|
||||
ID, but this was a bug. Now we will use ID=0 for any UFO/IPv6 packet
|
||||
passed through a tap, which is even worse.
|
||||
|
||||
Unfortunately there is no distinction between UFO/IPv4 and v6
|
||||
features, so disable UFO on taps and virtio_net completely until we
|
||||
have a proper solution.
|
||||
|
||||
We cannot depend on VM managers respecting the tap feature flags, so
|
||||
keep accepting UFO packets but log a warning the first time we do
|
||||
this.
|
||||
|
||||
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
|
||||
Fixes: 916e4cf46d02 ("ipv6: reuse ip6_frag_id from ip6_ufo_append_data")
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/macvtap.c | 13 +++++--------
|
||||
drivers/net/tun.c | 19 +++++++++++--------
|
||||
drivers/net/virtio_net.c | 24 ++++++++++++++----------
|
||||
3 files changed, 30 insertions(+), 26 deletions(-)
|
||||
|
||||
--- a/drivers/net/macvtap.c
|
||||
+++ b/drivers/net/macvtap.c
|
||||
@@ -65,7 +65,7 @@ static struct cdev macvtap_cdev;
|
||||
static const struct proto_ops macvtap_socket_ops;
|
||||
|
||||
#define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
|
||||
- NETIF_F_TSO6 | NETIF_F_UFO)
|
||||
+ NETIF_F_TSO6)
|
||||
#define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO)
|
||||
#define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG)
|
||||
|
||||
@@ -569,6 +569,8 @@ static int macvtap_skb_from_vnet_hdr(str
|
||||
gso_type = SKB_GSO_TCPV6;
|
||||
break;
|
||||
case VIRTIO_NET_HDR_GSO_UDP:
|
||||
+ pr_warn_once("macvtap: %s: using disabled UFO feature; please fix this program\n",
|
||||
+ current->comm);
|
||||
gso_type = SKB_GSO_UDP;
|
||||
break;
|
||||
default:
|
||||
@@ -614,8 +616,6 @@ static void macvtap_skb_to_vnet_hdr(cons
|
||||
vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
|
||||
else if (sinfo->gso_type & SKB_GSO_TCPV6)
|
||||
vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
|
||||
- else if (sinfo->gso_type & SKB_GSO_UDP)
|
||||
- vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
|
||||
else
|
||||
BUG();
|
||||
if (sinfo->gso_type & SKB_GSO_TCP_ECN)
|
||||
@@ -950,9 +950,6 @@ static int set_offload(struct macvtap_qu
|
||||
if (arg & TUN_F_TSO6)
|
||||
feature_mask |= NETIF_F_TSO6;
|
||||
}
|
||||
-
|
||||
- if (arg & TUN_F_UFO)
|
||||
- feature_mask |= NETIF_F_UFO;
|
||||
}
|
||||
|
||||
/* tun/tap driver inverts the usage for TSO offloads, where
|
||||
@@ -963,7 +960,7 @@ static int set_offload(struct macvtap_qu
|
||||
* When user space turns off TSO, we turn off GSO/LRO so that
|
||||
* user-space will not receive TSO frames.
|
||||
*/
|
||||
- if (feature_mask & (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO))
|
||||
+ if (feature_mask & (NETIF_F_TSO | NETIF_F_TSO6))
|
||||
features |= RX_OFFLOADS;
|
||||
else
|
||||
features &= ~RX_OFFLOADS;
|
||||
@@ -1064,7 +1061,7 @@ static long macvtap_ioctl(struct file *f
|
||||
case TUNSETOFFLOAD:
|
||||
/* let the user check for future flags */
|
||||
if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
|
||||
- TUN_F_TSO_ECN | TUN_F_UFO))
|
||||
+ TUN_F_TSO_ECN))
|
||||
return -EINVAL;
|
||||
|
||||
rtnl_lock();
|
||||
--- a/drivers/net/tun.c
|
||||
+++ b/drivers/net/tun.c
|
||||
@@ -174,7 +174,7 @@ struct tun_struct {
|
||||
struct net_device *dev;
|
||||
netdev_features_t set_features;
|
||||
#define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \
|
||||
- NETIF_F_TSO6|NETIF_F_UFO)
|
||||
+ NETIF_F_TSO6)
|
||||
|
||||
int vnet_hdr_sz;
|
||||
int sndbuf;
|
||||
@@ -1149,8 +1149,18 @@ static ssize_t tun_get_user(struct tun_s
|
||||
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
|
||||
break;
|
||||
case VIRTIO_NET_HDR_GSO_UDP:
|
||||
+ {
|
||||
+ static bool warned;
|
||||
+
|
||||
+ if (!warned) {
|
||||
+ warned = true;
|
||||
+ netdev_warn(tun->dev,
|
||||
+ "%s: using disabled UFO feature; please fix this program\n",
|
||||
+ current->comm);
|
||||
+ }
|
||||
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
|
||||
break;
|
||||
+ }
|
||||
default:
|
||||
tun->dev->stats.rx_frame_errors++;
|
||||
kfree_skb(skb);
|
||||
@@ -1251,8 +1261,6 @@ static ssize_t tun_put_user(struct tun_s
|
||||
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
|
||||
else if (sinfo->gso_type & SKB_GSO_TCPV6)
|
||||
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
|
||||
- else if (sinfo->gso_type & SKB_GSO_UDP)
|
||||
- gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
|
||||
else {
|
||||
pr_err("unexpected GSO type: "
|
||||
"0x%x, gso_size %d, hdr_len %d\n",
|
||||
@@ -1761,11 +1769,6 @@ static int set_offload(struct tun_struct
|
||||
features |= NETIF_F_TSO6;
|
||||
arg &= ~(TUN_F_TSO4|TUN_F_TSO6);
|
||||
}
|
||||
-
|
||||
- if (arg & TUN_F_UFO) {
|
||||
- features |= NETIF_F_UFO;
|
||||
- arg &= ~TUN_F_UFO;
|
||||
- }
|
||||
}
|
||||
|
||||
/* This gives the user a way to test for new features in future by
|
||||
--- a/drivers/net/virtio_net.c
|
||||
+++ b/drivers/net/virtio_net.c
|
||||
@@ -496,8 +496,17 @@ static void receive_buf(struct receive_q
|
||||
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
|
||||
break;
|
||||
case VIRTIO_NET_HDR_GSO_UDP:
|
||||
+ {
|
||||
+ static bool warned;
|
||||
+
|
||||
+ if (!warned) {
|
||||
+ warned = true;
|
||||
+ netdev_warn(dev,
|
||||
+ "host using disabled UFO feature; please fix it\n");
|
||||
+ }
|
||||
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
|
||||
break;
|
||||
+ }
|
||||
case VIRTIO_NET_HDR_GSO_TCPV6:
|
||||
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
|
||||
break;
|
||||
@@ -836,8 +845,6 @@ static int xmit_skb(struct send_queue *s
|
||||
hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
|
||||
else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
|
||||
hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
|
||||
- else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
|
||||
- hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_UDP;
|
||||
else
|
||||
BUG();
|
||||
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
|
||||
@@ -1657,7 +1664,7 @@ static int virtnet_probe(struct virtio_d
|
||||
dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
|
||||
- dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO
|
||||
+ dev->hw_features |= NETIF_F_TSO
|
||||
| NETIF_F_TSO_ECN | NETIF_F_TSO6;
|
||||
}
|
||||
/* Individual feature bits: what can host handle? */
|
||||
@@ -1667,11 +1674,9 @@ static int virtnet_probe(struct virtio_d
|
||||
dev->hw_features |= NETIF_F_TSO6;
|
||||
if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
|
||||
dev->hw_features |= NETIF_F_TSO_ECN;
|
||||
- if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
|
||||
- dev->hw_features |= NETIF_F_UFO;
|
||||
|
||||
if (gso)
|
||||
- dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO);
|
||||
+ dev->features |= dev->hw_features & NETIF_F_ALL_TSO;
|
||||
/* (!csum && gso) case will be fixed by register_netdev() */
|
||||
}
|
||||
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
|
||||
@@ -1711,8 +1716,7 @@ static int virtnet_probe(struct virtio_d
|
||||
/* If we can receive ANY GSO packets, we must allocate large ones. */
|
||||
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
|
||||
virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
|
||||
- virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
|
||||
- virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
|
||||
+ virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
|
||||
vi->big_packets = true;
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
|
||||
@@ -1910,9 +1914,9 @@ static struct virtio_device_id id_table[
|
||||
static unsigned int features[] = {
|
||||
VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM,
|
||||
VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
|
||||
- VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
|
||||
+ VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6,
|
||||
VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
|
||||
- VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
|
||||
+ VIRTIO_NET_F_GUEST_ECN,
|
||||
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
|
||||
VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
|
||||
VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ,
|
135
debian/patches/bugfix/all/drivers-net-ipv6-Select-IPv6-fragment-idents-for-vir.patch
vendored
Normal file
135
debian/patches/bugfix/all/drivers-net-ipv6-Select-IPv6-fragment-idents-for-vir.patch
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
From: Ben Hutchings <ben@decadent.org.uk>
|
||||
Date: Thu, 30 Oct 2014 18:27:17 +0000
|
||||
Subject: [2/2] drivers/net, ipv6: Select IPv6 fragment idents for virtio UFO
|
||||
packets
|
||||
Origin: https://git.kernel.org/cgit/linux/kernel/git/davem/net.git/commit?id=5188cd44c55db3e92cd9e77a40b5baa7ed4340f7
|
||||
|
||||
UFO is now disabled on all drivers that work with virtio net headers,
|
||||
but userland may try to send UFO/IPv6 packets anyway. Instead of
|
||||
sending with ID=0, we should select identifiers on their behalf (as we
|
||||
used to).
|
||||
|
||||
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
|
||||
Fixes: 916e4cf46d02 ("ipv6: reuse ip6_frag_id from ip6_ufo_append_data")
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/macvtap.c | 3 +++
|
||||
drivers/net/tun.c | 6 +++++-
|
||||
include/net/ipv6.h | 2 ++
|
||||
net/ipv6/output_core.c | 34 ++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 44 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/macvtap.c
|
||||
+++ b/drivers/net/macvtap.c
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/idr.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
+#include <net/ipv6.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <net/sock.h>
|
||||
@@ -572,6 +573,8 @@ static int macvtap_skb_from_vnet_hdr(str
|
||||
pr_warn_once("macvtap: %s: using disabled UFO feature; please fix this program\n",
|
||||
current->comm);
|
||||
gso_type = SKB_GSO_UDP;
|
||||
+ if (skb->protocol == htons(ETH_P_IPV6))
|
||||
+ ipv6_proxy_select_ident(skb);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
--- a/drivers/net/tun.c
|
||||
+++ b/drivers/net/tun.c
|
||||
@@ -65,6 +65,7 @@
|
||||
#include <linux/nsproxy.h>
|
||||
#include <linux/virtio_net.h>
|
||||
#include <linux/rcupdate.h>
|
||||
+#include <net/ipv6.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
#include <net/rtnetlink.h>
|
||||
@@ -1139,6 +1140,8 @@ static ssize_t tun_get_user(struct tun_s
|
||||
break;
|
||||
}
|
||||
|
||||
+ skb_reset_network_header(skb);
|
||||
+
|
||||
if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
|
||||
pr_debug("GSO!\n");
|
||||
switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
|
||||
@@ -1159,6 +1162,8 @@ static ssize_t tun_get_user(struct tun_s
|
||||
current->comm);
|
||||
}
|
||||
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
|
||||
+ if (skb->protocol == htons(ETH_P_IPV6))
|
||||
+ ipv6_proxy_select_ident(skb);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1189,7 +1194,6 @@ static ssize_t tun_get_user(struct tun_s
|
||||
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
|
||||
}
|
||||
|
||||
- skb_reset_network_header(skb);
|
||||
skb_probe_transport_header(skb, 0);
|
||||
|
||||
rxhash = skb_get_hash(skb);
|
||||
--- a/include/net/ipv6.h
|
||||
+++ b/include/net/ipv6.h
|
||||
@@ -668,6 +668,8 @@ static inline int ipv6_addr_diff(const s
|
||||
return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
|
||||
}
|
||||
|
||||
+void ipv6_proxy_select_ident(struct sk_buff *skb);
|
||||
+
|
||||
int ip6_dst_hoplimit(struct dst_entry *dst);
|
||||
|
||||
static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6,
|
||||
--- a/net/ipv6/output_core.c
|
||||
+++ b/net/ipv6/output_core.c
|
||||
@@ -3,11 +3,45 @@
|
||||
* not configured or static. These functions are needed by GSO/GRO implementation.
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
+#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/ip6_fib.h>
|
||||
#include <net/addrconf.h>
|
||||
#include <net/secure_seq.h>
|
||||
|
||||
+/* This function exists only for tap drivers that must support broken
|
||||
+ * clients requesting UFO without specifying an IPv6 fragment ID.
|
||||
+ *
|
||||
+ * This is similar to ipv6_select_ident() but we use an independent hash
|
||||
+ * seed to limit information leakage.
|
||||
+ *
|
||||
+ * The network header must be set before calling this.
|
||||
+ */
|
||||
+void ipv6_proxy_select_ident(struct sk_buff *skb)
|
||||
+{
|
||||
+ static u32 ip6_proxy_idents_hashrnd __read_mostly;
|
||||
+ struct in6_addr buf[2];
|
||||
+ struct in6_addr *addrs;
|
||||
+ u32 hash, id;
|
||||
+
|
||||
+ addrs = skb_header_pointer(skb,
|
||||
+ skb_network_offset(skb) +
|
||||
+ offsetof(struct ipv6hdr, saddr),
|
||||
+ sizeof(buf), buf);
|
||||
+ if (!addrs)
|
||||
+ return;
|
||||
+
|
||||
+ net_get_random_once(&ip6_proxy_idents_hashrnd,
|
||||
+ sizeof(ip6_proxy_idents_hashrnd));
|
||||
+
|
||||
+ hash = __ipv6_addr_jhash(&addrs[1], ip6_proxy_idents_hashrnd);
|
||||
+ hash = __ipv6_addr_jhash(&addrs[0], hash);
|
||||
+
|
||||
+ id = ip_idents_reserve(hash, 1);
|
||||
+ skb_shinfo(skb)->ip6_frag_id = htonl(id);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
|
||||
+
|
||||
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
|
||||
{
|
||||
u16 offset = sizeof(struct ipv6hdr);
|
|
@ -404,3 +404,5 @@ bugfix/all/mtd-m25p80-spi-nor-Fix-module-aliases-for-m25p80.patch
|
|||
bugfix/all/HID-i2c-hid-call-the-hid-driver-s-suspend-and-resume.patch
|
||||
bugfix/x86/drm-i915-Add-some-L3-registers-to-the-parser-whiteli.patch
|
||||
features/all/wireless-rt2x00-add-new-rt2800usb-device.patch
|
||||
bugfix/all/drivers-net-Disable-UFO-through-virtio.patch
|
||||
bugfix/all/drivers-net-ipv6-Select-IPv6-fragment-idents-for-vir.patch
|
||||
|
|
Loading…
Reference in New Issue