net: disable receiving if client returns zero

If a receiver returns zero, that means its queue is full and it will
notify us when room is available using qemu_flush_queued_packets().

Take note of that and disable that receiver until it flushes its queue.

This is a first step towards allowing can_receive() handlers to return
true even if no buffer space is available.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Mark McLoughlin 2009-10-27 18:16:36 +00:00 committed by Anthony Liguori
parent be1636b3ab
commit 893379efd0
2 changed files with 39 additions and 11 deletions

49
net.c
View File

@ -438,11 +438,13 @@ int qemu_can_send_packet(VLANClientState *sender)
VLANClientState *vc; VLANClientState *vc;
if (sender->peer) { if (sender->peer) {
if (!sender->peer->can_receive || if (sender->peer->receive_disabled) {
sender->peer->can_receive(sender->peer)) {
return 1;
} else {
return 0; return 0;
} else if (sender->peer->can_receive &&
!sender->peer->can_receive(sender->peer)) {
return 0;
} else {
return 1;
} }
} }
@ -470,15 +472,27 @@ static ssize_t qemu_deliver_packet(VLANClientState *sender,
void *opaque) void *opaque)
{ {
VLANClientState *vc = opaque; VLANClientState *vc = opaque;
ssize_t ret;
if (vc->link_down) { if (vc->link_down) {
return size; return size;
} }
if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->receive_raw) if (vc->receive_disabled) {
return vc->receive_raw(vc, data, size); return 0;
else }
return vc->receive(vc, data, size);
if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->receive_raw) {
ret = vc->receive_raw(vc, data, size);
} else {
ret = vc->receive(vc, data, size);
}
if (ret == 0) {
vc->receive_disabled = 1;
};
return ret;
} }
static ssize_t qemu_vlan_deliver_packet(VLANClientState *sender, static ssize_t qemu_vlan_deliver_packet(VLANClientState *sender,
@ -489,7 +503,7 @@ static ssize_t qemu_vlan_deliver_packet(VLANClientState *sender,
{ {
VLANState *vlan = opaque; VLANState *vlan = opaque;
VLANClientState *vc; VLANClientState *vc;
int ret = -1; ssize_t ret = -1;
QTAILQ_FOREACH(vc, &vlan->clients, next) { QTAILQ_FOREACH(vc, &vlan->clients, next) {
ssize_t len; ssize_t len;
@ -503,12 +517,23 @@ static ssize_t qemu_vlan_deliver_packet(VLANClientState *sender,
continue; continue;
} }
if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->receive_raw) if (vc->receive_disabled) {
ret = 0;
continue;
}
if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->receive_raw) {
len = vc->receive_raw(vc, buf, size); len = vc->receive_raw(vc, buf, size);
else } else {
len = vc->receive(vc, buf, size); len = vc->receive(vc, buf, size);
}
if (len == 0) {
vc->receive_disabled = 1;
}
ret = (ret >= 0) ? ret : len; ret = (ret >= 0) ? ret : len;
} }
return ret; return ret;
@ -535,6 +560,8 @@ void qemu_flush_queued_packets(VLANClientState *vc)
{ {
NetQueue *queue; NetQueue *queue;
vc->receive_disabled = 0;
if (vc->vlan) { if (vc->vlan) {
queue = vc->vlan->send_queue; queue = vc->vlan->send_queue;
} else { } else {

1
net.h
View File

@ -61,6 +61,7 @@ struct VLANClientState {
char *model; char *model;
char *name; char *name;
char info_str[256]; char info_str[256];
unsigned receive_disabled : 1;
}; };
struct VLANState { struct VLANState {