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 <mar...@redhat.com> --- net.c | 49 ++++++++++++++++++++++++++++++++++++++----------- net.h | 1 + 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/net.c b/net.c index 661bbc1..9dea615 100644 --- a/net.c +++ b/net.c @@ -423,11 +423,13 @@ int qemu_can_send_packet(VLANClientState *sender) VLANClientState *vc; if (sender->peer) { - if (!sender->peer->can_receive || - sender->peer->can_receive(sender->peer)) { - return 1; - } else { + if (sender->peer->receive_disabled) { return 0; + } else if (sender->peer->can_receive && + !sender->peer->can_receive(sender->peer)) { + return 0; + } else { + return 1; } } @@ -455,15 +457,27 @@ static ssize_t qemu_deliver_packet(VLANClientState *sender, void *opaque) { VLANClientState *vc = opaque; + ssize_t ret; if (vc->link_down) { return size; } - if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->receive_raw) - return vc->receive_raw(vc, data, size); - else - return vc->receive(vc, data, size); + if (vc->receive_disabled) { + return 0; + } + + 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, @@ -474,7 +488,7 @@ static ssize_t qemu_vlan_deliver_packet(VLANClientState *sender, { VLANState *vlan = opaque; VLANClientState *vc; - int ret = -1; + ssize_t ret = -1; QTAILQ_FOREACH(vc, &vlan->clients, next) { ssize_t len; @@ -488,12 +502,23 @@ static ssize_t qemu_vlan_deliver_packet(VLANClientState *sender, 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); - else + } else { len = vc->receive(vc, buf, size); + } + + if (len == 0) { + vc->receive_disabled = 1; + } ret = (ret >= 0) ? ret : len; + } return ret; @@ -520,6 +545,8 @@ void qemu_flush_queued_packets(VLANClientState *vc) { NetQueue *queue; + vc->receive_disabled = 0; + if (vc->vlan) { queue = vc->vlan->send_queue; } else { diff --git a/net.h b/net.h index 8074c66..c1fe515 100644 --- a/net.h +++ b/net.h @@ -44,6 +44,7 @@ struct VLANClientState { char *model; char *name; char info_str[256]; + unsigned receive_disabled : 1; }; struct VLANState { -- 1.6.2.5