mirror of https://gitee.com/openkylin/linux.git
Merge branch 'ufo-fix'
Ben Hutchings says: ==================== drivers/net,ipv6: Fix IPv6 fragment ID selection for virtio The virtio net protocol supports UFO but does not provide for passing a fragment ID for fragmentation of IPv6 packets. We used to generate a fragment ID wherever such a packet was fragmented, but currently we always use ID=0! v2: Add blank lines after declarations ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c1304b217c
|
@ -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>
|
||||
|
@ -65,7 +66,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,7 +570,11 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
|
|||
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;
|
||||
if (skb->protocol == htons(ETH_P_IPV6))
|
||||
ipv6_proxy_select_ident(skb);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -614,8 +619,6 @@ static void macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
|
|||
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 +953,6 @@ static int set_offload(struct macvtap_queue *q, unsigned long arg)
|
|||
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 +963,7 @@ static int set_offload(struct macvtap_queue *q, unsigned long arg)
|
|||
* 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 +1064,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
|
|||
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();
|
||||
|
|
|
@ -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>
|
||||
|
@ -174,7 +175,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;
|
||||
|
@ -1139,6 +1140,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
|
|||
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) {
|
||||
|
@ -1149,8 +1152,20 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
|
|||
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;
|
||||
if (skb->protocol == htons(ETH_P_IPV6))
|
||||
ipv6_proxy_select_ident(skb);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
tun->dev->stats.rx_frame_errors++;
|
||||
kfree_skb(skb);
|
||||
|
@ -1179,7 +1194,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
|
|||
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
|
||||
}
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
skb_probe_transport_header(skb, 0);
|
||||
|
||||
rxhash = skb_get_hash(skb);
|
||||
|
@ -1251,8 +1265,6 @@ static ssize_t tun_put_user(struct tun_struct *tun,
|
|||
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",
|
||||
|
@ -1762,11 +1774,6 @@ static int set_offload(struct tun_struct *tun, unsigned long arg)
|
|||
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
|
||||
|
|
|
@ -491,8 +491,17 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
|
|||
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;
|
||||
|
@ -881,8 +890,6 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
|
|||
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)
|
||||
|
@ -1705,7 +1712,7 @@ static int virtnet_probe(struct virtio_device *vdev)
|
|||
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? */
|
||||
|
@ -1715,11 +1722,9 @@ static int virtnet_probe(struct virtio_device *vdev)
|
|||
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))
|
||||
|
@ -1757,8 +1762,7 @@ static int virtnet_probe(struct virtio_device *vdev)
|
|||
/* 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))
|
||||
|
@ -1952,9 +1956,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,
|
||||
|
|
|
@ -671,6 +671,8 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add
|
|||
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,
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue