From 091f1f52963d7093ea578e4a05e67bc015b21192 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 7 Jul 2015 17:00:56 +0800 Subject: socket: pass correct size in net_socket_send() We should pass the size of packet instead of the remaining to qemu_send_packet_async(). Fixes: 6e99c631f116221d169ea53953d91b8aa74d297a ("net/socket: Drop net_socket_can_send") Signed-off-by: Jason Wang Reviewed-by: Fam Zheng Message-id: 1436259656-24263-1-git-send-email-jasowang@redhat.com Signed-off-by: Stefan Hajnoczi --- net/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/socket.c b/net/socket.c index c752696cbb..b1e3b1c8d9 100644 --- a/net/socket.c +++ b/net/socket.c @@ -213,7 +213,7 @@ static void net_socket_send(void *opaque) if (s->index >= s->packet_len) { s->index = 0; s->state = 0; - if (qemu_send_packet_async(&s->nc, s->buf, size, + if (qemu_send_packet_async(&s->nc, s->buf, s->packet_len, net_socket_send_completed) == 0) { net_socket_read_poll(s, false); break; -- cgit v1.2.3 From fcf0cdc362dd96cb8d2935b892d3dd9ab73ad393 Mon Sep 17 00:00:00 2001 From: Shmulik Ladkani Date: Tue, 14 Jul 2015 11:55:15 +0300 Subject: net/vmxnet3: Refactor 'vmxnet_rx_pkt_attach_data' Separate RX packet protocol parsing out of 'vmxnet_rx_pkt_attach_data'. Signed-off-by: Shmulik Ladkani Message-id: 1436864116-19154-2-git-send-email-shmulik.ladkani@ravellosystems.com Signed-off-by: Stefan Hajnoczi --- hw/net/vmxnet3.c | 1 + hw/net/vmxnet_rx_pkt.c | 12 +++++++++--- hw/net/vmxnet_rx_pkt.h | 11 +++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 706e0606a9..dd22a0a8cd 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -1897,6 +1897,7 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size) get_eth_packet_type(PKT_GET_ETH_HDR(buf))); if (vmxnet3_rx_filter_may_indicate(s, buf, size)) { + vmxnet_rx_pkt_set_protocols(s->rx_pkt, buf, size); vmxnet_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping); bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1; if (bytes_indicated < size) { diff --git a/hw/net/vmxnet_rx_pkt.c b/hw/net/vmxnet_rx_pkt.c index acbca6a3db..aa5462931e 100644 --- a/hw/net/vmxnet_rx_pkt.c +++ b/hw/net/vmxnet_rx_pkt.c @@ -92,9 +92,6 @@ void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data, } pkt->tci = tci; - - eth_get_protocols(data, len, &pkt->isip4, &pkt->isip6, - &pkt->isudp, &pkt->istcp); } void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt) @@ -131,6 +128,15 @@ size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt) return pkt->tot_len; } +void vmxnet_rx_pkt_set_protocols(struct VmxnetRxPkt *pkt, const void *data, + size_t len) +{ + assert(pkt); + + eth_get_protocols(data, len, &pkt->isip4, &pkt->isip6, + &pkt->isudp, &pkt->istcp); +} + void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt, bool *isip4, bool *isip6, bool *isudp, bool *istcp) diff --git a/hw/net/vmxnet_rx_pkt.h b/hw/net/vmxnet_rx_pkt.h index 5f8352a468..a425846b52 100644 --- a/hw/net/vmxnet_rx_pkt.h +++ b/hw/net/vmxnet_rx_pkt.h @@ -54,6 +54,17 @@ void vmxnet_rx_pkt_init(struct VmxnetRxPkt **pkt, bool has_virt_hdr); */ size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt); +/** + * parse and set packet analysis results + * + * @pkt: packet + * @data: pointer to the data buffer to be parsed + * @len: data length + * + */ +void vmxnet_rx_pkt_set_protocols(struct VmxnetRxPkt *pkt, const void *data, + size_t len); + /** * fetches packet analysis results * -- cgit v1.2.3 From 80da311d81c389860bc387fbe6677c71f7a3c596 Mon Sep 17 00:00:00 2001 From: Dana Rubin Date: Tue, 14 Jul 2015 11:55:16 +0300 Subject: net/vmxnet3: Fix RX TCP/UDP checksum on partially summed packets Convert partially summed packets to be fully checksummed. In case csum offloaded packet, vmxnet3 implementation always passes an RxCompDesc with the "Checksum calculated and found correct" notification to the OS. This emulates the observed ESXi behavior. Therefore, if packet has the NEEDS_CSUM bit set, we must calculate and place a fully computed checksum into the tcp/udp header. Otherwise, the OS driver will receive a checksum-correct indication but with the actual tcp/udp checksum field having just the pseudo header csum value. If host OS performs forwarding, it will forward an incorrectly checksummed packet. Signed-off-by: Dana Rubin Signed-off-by: Shmulik Ladkani Message-id: 1436864116-19154-3-git-send-email-shmulik.ladkani@ravellosystems.com Signed-off-by: Stefan Hajnoczi --- hw/net/vmxnet3.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index dd22a0a8cd..59b06b8412 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -885,6 +885,63 @@ vmxnet3_get_next_rx_descr(VMXNET3State *s, bool is_head, } } +/* In case packet was csum offloaded (either NEEDS_CSUM or DATA_VALID), + * the implementation always passes an RxCompDesc with a "Checksum + * calculated and found correct" to the OS (cnc=0 and tuc=1, see + * vmxnet3_rx_update_descr). This emulates the observed ESXi behavior. + * + * Therefore, if packet has the NEEDS_CSUM set, we must calculate + * and place a fully computed checksum into the tcp/udp header. + * Otherwise, the OS driver will receive a checksum-correct indication + * (CHECKSUM_UNNECESSARY), but with the actual tcp/udp checksum field + * having just the pseudo header csum value. + * + * While this is not a problem if packet is destined for local delivery, + * in the case the host OS performs forwarding, it will forward an + * incorrectly checksummed packet. + */ +static void vmxnet3_rx_need_csum_calculate(struct VmxnetRxPkt *pkt, + const void *pkt_data, + size_t pkt_len) +{ + struct virtio_net_hdr *vhdr; + bool isip4, isip6, istcp, isudp; + uint8_t *data; + int len; + + if (!vmxnet_rx_pkt_has_virt_hdr(pkt)) { + return; + } + + vhdr = vmxnet_rx_pkt_get_vhdr(pkt); + if (!VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_NEEDS_CSUM)) { + return; + } + + vmxnet_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); + if (!(isip4 || isip6) || !(istcp || isudp)) { + return; + } + + vmxnet3_dump_virt_hdr(vhdr); + + /* Validate packet len: csum_start + scum_offset + length of csum field */ + if (pkt_len < (vhdr->csum_start + vhdr->csum_offset + 2)) { + VMW_PKPRN("packet len:%d < csum_start(%d) + csum_offset(%d) + 2, " + "cannot calculate checksum", + len, vhdr->csum_start, vhdr->csum_offset); + return; + } + + data = (uint8_t *)pkt_data + vhdr->csum_start; + len = pkt_len - vhdr->csum_start; + /* Put the checksum obtained into the packet */ + stw_be_p(data + vhdr->csum_offset, net_raw_checksum(data, len)); + + vhdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM; + vhdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID; +} + static void vmxnet3_rx_update_descr(struct VmxnetRxPkt *pkt, struct Vmxnet3_RxCompDesc *rxcd) { @@ -1898,6 +1955,7 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size) if (vmxnet3_rx_filter_may_indicate(s, buf, size)) { vmxnet_rx_pkt_set_protocols(s->rx_pkt, buf, size); + vmxnet3_rx_need_csum_calculate(s->rx_pkt, buf, size); vmxnet_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping); bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1; if (bytes_indicated < size) { -- cgit v1.2.3 From f63eab8becf92b18c18b6c31950f99f764848902 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 1 Jul 2015 15:10:45 +0800 Subject: musicpal: Drop eth_can_receive True is the default. Signed-off-by: Fam Zheng Reviewed-by: Jason Wang Message-id: 1435734647-8371-2-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/arm/musicpal.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index a3b1314d96..42f66b33e1 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -187,11 +187,6 @@ static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc) le32_to_cpus(&desc->next); } -static int eth_can_receive(NetClientState *nc) -{ - return 1; -} - static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) { mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); @@ -381,7 +376,6 @@ static void eth_cleanup(NetClientState *nc) static NetClientInfo net_mv88w8618_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = eth_can_receive, .receive = eth_receive, .cleanup = eth_cleanup, }; -- cgit v1.2.3 From da69028261abd12dbf974754e69d017f6e8710b5 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 1 Jul 2015 15:10:46 +0800 Subject: etraxfs_eth: Drop eth_can_receive True is the default. Signed-off-by: Fam Zheng Reviewed-by: Jason Wang Message-id: 1435734647-8371-3-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/etraxfs_eth.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c index 4773dea927..d6002750f0 100644 --- a/hw/net/etraxfs_eth.c +++ b/hw/net/etraxfs_eth.c @@ -520,11 +520,6 @@ static int eth_match_groupaddr(ETRAXFSEthState *eth, const unsigned char *sa) return match; } -static int eth_can_receive(NetClientState *nc) -{ - return 1; -} - static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) { unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -584,7 +579,6 @@ static const MemoryRegionOps eth_ops = { static NetClientInfo net_etraxfs_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = eth_can_receive, .receive = eth_receive, .link_status_changed = eth_set_link, }; -- cgit v1.2.3 From b49b8c572f885ea2b16fc744e8837e974df34401 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 1 Jul 2015 15:10:47 +0800 Subject: lan9118: Drop lan9118_can_receive True is the default. Signed-off-by: Fam Zheng Reviewed-by: Jason Wang Message-id: 1435734647-8371-4-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/lan9118.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index f169c383df..4f0e840f0e 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -461,11 +461,6 @@ static void lan9118_reset(DeviceState *d) lan9118_reload_eeprom(s); } -static int lan9118_can_receive(NetClientState *nc) -{ - return 1; -} - static void rx_fifo_push(lan9118_state *s, uint32_t val) { int fifo_pos; @@ -1312,7 +1307,6 @@ static const MemoryRegionOps lan9118_16bit_mem_ops = { static NetClientInfo net_lan9118_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = lan9118_can_receive, .receive = lan9118_receive, .link_status_changed = lan9118_set_link, }; -- cgit v1.2.3 From 625de449fc5597f2e1aff9cb586e249e198f03c9 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 7 Jul 2015 09:21:07 +0800 Subject: net: Flush queued packets when guest resumes Since commit 6e99c63 "net/socket: Drop net_socket_can_send" and friends, net queues need to be explicitly flushed after qemu_can_send_packet() returns false, because the netdev side will disable the polling of fd. This fixes the case of "cont" after "stop" (or migration). Signed-off-by: Fam Zheng Message-id: 1436232067-29144-1-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- net/net.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/net/net.c b/net/net.c index 6ff7fec1bb..28a5597b8d 100644 --- a/net/net.c +++ b/net/net.c @@ -1257,14 +1257,19 @@ void qmp_set_link(const char *name, bool up, Error **errp) static void net_vm_change_state_handler(void *opaque, int running, RunState state) { - /* Complete all queued packets, to guarantee we don't modify - * state later when VM is not running. - */ - if (!running) { - NetClientState *nc; - NetClientState *tmp; + NetClientState *nc; + NetClientState *tmp; - QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) { + QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) { + if (running) { + /* Flush queued packets and wake up backends. */ + if (nc->peer && qemu_can_send_packet(nc)) { + qemu_flush_queued_packets(nc->peer); + } + } else { + /* Complete all queued packets, to guarantee we don't modify + * state later when VM is not running. + */ qemu_flush_or_purge_queued_packets(nc, true); } } -- cgit v1.2.3