aboutsummaryrefslogtreecommitdiff
path: root/net.c
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2009-05-08 12:34:17 +0200
committerMark McLoughlin <markmc@redhat.com>2009-06-09 11:38:48 +0100
commitc27ff60871aff588a35e51d1a90faed410993e55 (patch)
tree1573d7f0e1f986346d87f69b2c64d57228f2bff2 /net.c
parentc8aa237c643e7cb44fe878eeb76399ff8b73821a (diff)
net: Fix and improved ordered packet delivery
Fix a race in qemu_send_packet when delivering deferred packets and add proper deferring also to qemu_sendv_packet. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Diffstat (limited to 'net.c')
-rw-r--r--net.c57
1 files changed, 42 insertions, 15 deletions
diff --git a/net.c b/net.c
index 42b6b93247..6563b424ce 100644
--- a/net.c
+++ b/net.c
@@ -438,8 +438,8 @@ void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size)
vlan->delivering = 1;
qemu_deliver_packet(vc, buf, size);
while ((packet = vlan->send_queue) != NULL) {
- qemu_deliver_packet(packet->sender, packet->data, packet->size);
vlan->send_queue = packet->next;
+ qemu_deliver_packet(packet->sender, packet->data, packet->size);
qemu_free(packet);
}
vlan->delivering = 0;
@@ -476,30 +476,57 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt)
return offset;
}
-ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov,
+ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov,
int iovcnt)
{
- VLANState *vlan = vc1->vlan;
+ VLANState *vlan = sender->vlan;
VLANClientState *vc;
+ VLANPacket *packet;
ssize_t max_len = 0;
+ int i;
- if (vc1->link_down)
+ if (sender->link_down)
return calc_iov_length(iov, iovcnt);
- for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
- ssize_t len = 0;
+ if (vlan->delivering) {
+ max_len = calc_iov_length(iov, iovcnt);
- if (vc == vc1)
- continue;
+ packet = qemu_malloc(sizeof(VLANPacket) + max_len);
+ packet->next = vlan->send_queue;
+ packet->sender = sender;
+ packet->size = 0;
+ for (i = 0; i < iovcnt; i++) {
+ size_t len = iov[i].iov_len;
+
+ memcpy(packet->data + packet->size, iov[i].iov_base, len);
+ packet->size += len;
+ }
+ vlan->send_queue = packet;
+ } else {
+ vlan->delivering = 1;
+
+ for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
+ ssize_t len = 0;
- if (vc->link_down)
- len = calc_iov_length(iov, iovcnt);
- else if (vc->fd_readv)
- len = vc->fd_readv(vc->opaque, iov, iovcnt);
- else if (vc->fd_read)
- len = vc_sendv_compat(vc, iov, iovcnt);
+ if (vc == sender) {
+ continue;
+ }
+ if (vc->link_down) {
+ len = calc_iov_length(iov, iovcnt);
+ } else if (vc->fd_readv) {
+ len = vc->fd_readv(vc->opaque, iov, iovcnt);
+ } else if (vc->fd_read) {
+ len = vc_sendv_compat(vc, iov, iovcnt);
+ }
+ max_len = MAX(max_len, len);
+ }
- max_len = MAX(max_len, len);
+ while ((packet = vlan->send_queue) != NULL) {
+ vlan->send_queue = packet->next;
+ qemu_deliver_packet(packet->sender, packet->data, packet->size);
+ qemu_free(packet);
+ }
+ vlan->delivering = 0;
}
return max_len;