Skip to content

Commit e28fbd1

Browse files
Antoine DamhetstefanhaRH
authored andcommitted
Revert "virtio-net: Copy received header to buffer"
This reverts commit 7987d2b. The goal was to remove the need to patch the (const) input buffer with a recomputed UDP checksum by copying headers to a RW region and inject the checksum there. The patch computed the checksum only from the header fields (missing the rest of the payload) producing an invalid one and making guests fail to acquire a DHCP lease. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2727 Cc: [email protected] Signed-off-by: Antoine Damhet <[email protected]> Acked-by: Michael S. Tsirkin <[email protected]> Message-ID: <[email protected]> Signed-off-by: Stefan Hajnoczi <[email protected]>
1 parent 8bdd3a0 commit e28fbd1

File tree

1 file changed

+40
-47
lines changed

1 file changed

+40
-47
lines changed

hw/net/virtio-net.c

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,44 +1702,41 @@ static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr)
17021702
* cache.
17031703
*/
17041704
static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
1705-
size_t *hdr_len, const uint8_t *buf,
1706-
size_t buf_size, size_t *buf_offset)
1705+
uint8_t *buf, size_t size)
17071706
{
17081707
size_t csum_size = ETH_HLEN + sizeof(struct ip_header) +
17091708
sizeof(struct udp_header);
17101709

1711-
buf += *buf_offset;
1712-
buf_size -= *buf_offset;
1713-
17141710
if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
1715-
(buf_size >= csum_size && buf_size < 1500) && /* normal sized MTU */
1711+
(size >= csum_size && size < 1500) && /* normal sized MTU */
17161712
(buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
17171713
(buf[23] == 17) && /* ip.protocol == UDP */
17181714
(buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
1719-
memcpy((uint8_t *)hdr + *hdr_len, buf, csum_size);
1720-
net_checksum_calculate((uint8_t *)hdr + *hdr_len, csum_size, CSUM_UDP);
1715+
net_checksum_calculate(buf, size, CSUM_UDP);
17211716
hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
1722-
*hdr_len += csum_size;
1723-
*buf_offset += csum_size;
17241717
}
17251718
}
17261719

1727-
static size_t receive_header(VirtIONet *n, struct virtio_net_hdr *hdr,
1728-
const void *buf, size_t buf_size,
1729-
size_t *buf_offset)
1720+
static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt,
1721+
const void *buf, size_t size)
17301722
{
1731-
size_t hdr_len = n->guest_hdr_len;
1732-
1733-
memcpy(hdr, buf, sizeof(struct virtio_net_hdr));
1734-
1735-
*buf_offset = n->host_hdr_len;
1736-
work_around_broken_dhclient(hdr, &hdr_len, buf, buf_size, buf_offset);
1723+
if (n->has_vnet_hdr) {
1724+
/* FIXME this cast is evil */
1725+
void *wbuf = (void *)buf;
1726+
work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len,
1727+
size - n->host_hdr_len);
17371728

1738-
if (n->needs_vnet_hdr_swap) {
1739-
virtio_net_hdr_swap(VIRTIO_DEVICE(n), hdr);
1729+
if (n->needs_vnet_hdr_swap) {
1730+
virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf);
1731+
}
1732+
iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr));
1733+
} else {
1734+
struct virtio_net_hdr hdr = {
1735+
.flags = 0,
1736+
.gso_type = VIRTIO_NET_HDR_GSO_NONE
1737+
};
1738+
iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr);
17401739
}
1741-
1742-
return hdr_len;
17431740
}
17441741

17451742
static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
@@ -1907,13 +1904,6 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
19071904
return (index == new_index) ? -1 : new_index;
19081905
}
19091906

1910-
typedef struct Header {
1911-
struct virtio_net_hdr_v1_hash virtio_net;
1912-
struct eth_header eth;
1913-
struct ip_header ip;
1914-
struct udp_header udp;
1915-
} Header;
1916-
19171907
static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
19181908
size_t size)
19191909
{
@@ -1923,15 +1913,15 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
19231913
VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE];
19241914
size_t lens[VIRTQUEUE_MAX_SIZE];
19251915
struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
1926-
Header hdr;
1916+
struct virtio_net_hdr_v1_hash extra_hdr;
19271917
unsigned mhdr_cnt = 0;
19281918
size_t offset, i, guest_offset, j;
19291919
ssize_t err;
19301920

1931-
memset(&hdr.virtio_net, 0, sizeof(hdr.virtio_net));
1921+
memset(&extra_hdr, 0, sizeof(extra_hdr));
19321922

19331923
if (n->rss_data.enabled && n->rss_data.enabled_software_rss) {
1934-
int index = virtio_net_process_rss(nc, buf, size, &hdr.virtio_net);
1924+
int index = virtio_net_process_rss(nc, buf, size, &extra_hdr);
19351925
if (index >= 0) {
19361926
nc = qemu_get_subqueue(n->nic, index % n->curr_queue_pairs);
19371927
}
@@ -1996,20 +1986,23 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
19961986
if (n->mergeable_rx_bufs) {
19971987
mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg),
19981988
sg, elem->in_num,
1999-
offsetof(typeof(hdr),
2000-
virtio_net.hdr.num_buffers),
2001-
sizeof(hdr.virtio_net.hdr.num_buffers));
1989+
offsetof(typeof(extra_hdr), hdr.num_buffers),
1990+
sizeof(extra_hdr.hdr.num_buffers));
20021991
} else {
2003-
hdr.virtio_net.hdr.num_buffers = cpu_to_le16(1);
1992+
extra_hdr.hdr.num_buffers = cpu_to_le16(1);
20041993
}
20051994

2006-
guest_offset = n->has_vnet_hdr ?
2007-
receive_header(n, (struct virtio_net_hdr *)&hdr,
2008-
buf, size, &offset) :
2009-
n->guest_hdr_len;
2010-
2011-
iov_from_buf(sg, elem->in_num, 0, &hdr, guest_offset);
2012-
total += guest_offset;
1995+
receive_header(n, sg, elem->in_num, buf, size);
1996+
if (n->rss_data.populate_hash) {
1997+
offset = offsetof(typeof(extra_hdr), hash_value);
1998+
iov_from_buf(sg, elem->in_num, offset,
1999+
(char *)&extra_hdr + offset,
2000+
sizeof(extra_hdr.hash_value) +
2001+
sizeof(extra_hdr.hash_report));
2002+
}
2003+
offset = n->host_hdr_len;
2004+
total += n->guest_hdr_len;
2005+
guest_offset = n->guest_hdr_len;
20132006
} else {
20142007
guest_offset = 0;
20152008
}
@@ -2035,11 +2028,11 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
20352028
}
20362029

20372030
if (mhdr_cnt) {
2038-
virtio_stw_p(vdev, &hdr.virtio_net.hdr.num_buffers, i);
2031+
virtio_stw_p(vdev, &extra_hdr.hdr.num_buffers, i);
20392032
iov_from_buf(mhdr_sg, mhdr_cnt,
20402033
0,
2041-
&hdr.virtio_net.hdr.num_buffers,
2042-
sizeof hdr.virtio_net.hdr.num_buffers);
2034+
&extra_hdr.hdr.num_buffers,
2035+
sizeof extra_hdr.hdr.num_buffers);
20432036
}
20442037

20452038
for (j = 0; j < i; j++) {

0 commit comments

Comments
 (0)