-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJVrS76AAoJEJykq7OBq3PIMmMH/0mW/ClwudW80iOcTKrdHSPJ Fha4gy3m1GNt1sa0uvKxCivgF9H1RDmiCJRajaYsvlZYlQ/y15r6gqs3R+BAe2RX PVuJw0mB1pglsqJ2EBSiFQXGqLUnu2nWw9uH+URVtK9Ek7pVgNMZGRm/dhOFIxVC VGSchZrWvcARH1YoYRONebRVjXn5M4hNLtwEmcIiAZIvmHFPc88UAIkatCblCdAP BPQcR7FPUyuDZrGvT4UGjEUo62u7Hz+81MVfoAZsOQAY0QPzoZPpKIo17UFxxbsS qe2fwvtUjLhYwSozhP6JGAtlp6RG+9wOKHNBFswzU8VywT3Lt0ACcgz1xDKCE1s= =agJl -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stefanha/tags/net-pull-request' into staging # gpg: Signature made Mon Jul 20 18:25:14 2015 BST using RSA key ID 81AB73C8 # gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" # gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>" * remotes/stefanha/tags/net-pull-request: net: Flush queued packets when guest resumes lan9118: Drop lan9118_can_receive etraxfs_eth: Drop eth_can_receive musicpal: Drop eth_can_receive net/vmxnet3: Fix RX TCP/UDP checksum on partially summed packets net/vmxnet3: Refactor 'vmxnet_rx_pkt_attach_data' socket: pass correct size in net_socket_send() Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
bd03a38fdf
@ -187,11 +187,6 @@ static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc)
|
|||||||
le32_to_cpus(&desc->next);
|
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)
|
static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||||
{
|
{
|
||||||
mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
|
mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
|
||||||
@ -381,7 +376,6 @@ static void eth_cleanup(NetClientState *nc)
|
|||||||
static NetClientInfo net_mv88w8618_info = {
|
static NetClientInfo net_mv88w8618_info = {
|
||||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||||
.size = sizeof(NICState),
|
.size = sizeof(NICState),
|
||||||
.can_receive = eth_can_receive,
|
|
||||||
.receive = eth_receive,
|
.receive = eth_receive,
|
||||||
.cleanup = eth_cleanup,
|
.cleanup = eth_cleanup,
|
||||||
};
|
};
|
||||||
|
@ -520,11 +520,6 @@ static int eth_match_groupaddr(ETRAXFSEthState *eth, const unsigned char *sa)
|
|||||||
return match;
|
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)
|
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 };
|
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 = {
|
static NetClientInfo net_etraxfs_info = {
|
||||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||||
.size = sizeof(NICState),
|
.size = sizeof(NICState),
|
||||||
.can_receive = eth_can_receive,
|
|
||||||
.receive = eth_receive,
|
.receive = eth_receive,
|
||||||
.link_status_changed = eth_set_link,
|
.link_status_changed = eth_set_link,
|
||||||
};
|
};
|
||||||
|
@ -461,11 +461,6 @@ static void lan9118_reset(DeviceState *d)
|
|||||||
lan9118_reload_eeprom(s);
|
lan9118_reload_eeprom(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lan9118_can_receive(NetClientState *nc)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rx_fifo_push(lan9118_state *s, uint32_t val)
|
static void rx_fifo_push(lan9118_state *s, uint32_t val)
|
||||||
{
|
{
|
||||||
int fifo_pos;
|
int fifo_pos;
|
||||||
@ -1312,7 +1307,6 @@ static const MemoryRegionOps lan9118_16bit_mem_ops = {
|
|||||||
static NetClientInfo net_lan9118_info = {
|
static NetClientInfo net_lan9118_info = {
|
||||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||||
.size = sizeof(NICState),
|
.size = sizeof(NICState),
|
||||||
.can_receive = lan9118_can_receive,
|
|
||||||
.receive = lan9118_receive,
|
.receive = lan9118_receive,
|
||||||
.link_status_changed = lan9118_set_link,
|
.link_status_changed = lan9118_set_link,
|
||||||
};
|
};
|
||||||
|
@ -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,
|
static void vmxnet3_rx_update_descr(struct VmxnetRxPkt *pkt,
|
||||||
struct Vmxnet3_RxCompDesc *rxcd)
|
struct Vmxnet3_RxCompDesc *rxcd)
|
||||||
{
|
{
|
||||||
@ -1897,6 +1954,8 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|||||||
get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
|
get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
|
||||||
|
|
||||||
if (vmxnet3_rx_filter_may_indicate(s, buf, 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);
|
vmxnet_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping);
|
||||||
bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1;
|
bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1;
|
||||||
if (bytes_indicated < size) {
|
if (bytes_indicated < size) {
|
||||||
|
@ -92,9 +92,6 @@ void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pkt->tci = tci;
|
pkt->tci = tci;
|
||||||
|
|
||||||
eth_get_protocols(data, len, &pkt->isip4, &pkt->isip6,
|
|
||||||
&pkt->isudp, &pkt->istcp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt)
|
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;
|
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,
|
void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt,
|
||||||
bool *isip4, bool *isip6,
|
bool *isip4, bool *isip6,
|
||||||
bool *isudp, bool *istcp)
|
bool *isudp, bool *istcp)
|
||||||
|
@ -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);
|
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
|
* fetches packet analysis results
|
||||||
*
|
*
|
||||||
|
19
net/net.c
19
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,
|
static void net_vm_change_state_handler(void *opaque, int running,
|
||||||
RunState state)
|
RunState state)
|
||||||
{
|
{
|
||||||
/* Complete all queued packets, to guarantee we don't modify
|
NetClientState *nc;
|
||||||
* state later when VM is not running.
|
NetClientState *tmp;
|
||||||
*/
|
|
||||||
if (!running) {
|
|
||||||
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);
|
qemu_flush_or_purge_queued_packets(nc, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,7 @@ static void net_socket_send(void *opaque)
|
|||||||
if (s->index >= s->packet_len) {
|
if (s->index >= s->packet_len) {
|
||||||
s->index = 0;
|
s->index = 0;
|
||||||
s->state = 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_send_completed) == 0) {
|
||||||
net_socket_read_poll(s, false);
|
net_socket_read_poll(s, false);
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user