References: bsc#1182975

Some NIC supports loopback mode and this is done by calling
nc->info->receive() directly which in fact suppresses the effort of
reentrancy check that is done in qemu_net_queue_send().

Unfortunately we can't use qemu_net_queue_send() here since for
loopback there's no sender as peer, so this patch introduce a
qemu_receive_packet() which is used for implementing loopback mode
for a NIC with this check.

NIC that supports loopback mode will be converted to this helper.

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 include/net/net.h   |  5 +++++
 include/net/queue.h |  8 ++++++++
 net/net.c           | 38 +++++++++++++++++++++++++++++++-------
 net/queue.c         | 22 ++++++++++++++++++++++
 4 files changed, 66 insertions(+), 7 deletions(-)

Index: xen-4.2.5-testing/tools/qemu-xen-dir-remote/net.h
===================================================================
--- xen-4.2.5-testing.orig/tools/qemu-xen-dir-remote/net.h
+++ xen-4.2.5-testing/tools/qemu-xen-dir-remote/net.h
@@ -103,12 +103,17 @@ VLANClientState *qemu_find_vlan_client_b
                                                const char *client_str);
 typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque);
 void qemu_foreach_nic(qemu_nic_foreach func, void *opaque);
+int qemu_can_receive_packet(VLANClientState *vc);
 int qemu_can_send_packet(VLANClientState *vc);
 ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov,
                           int iovcnt);
 ssize_t qemu_sendv_packet_async(VLANClientState *vc, const struct iovec *iov,
                                 int iovcnt, NetPacketSent *sent_cb);
 void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
+ssize_t qemu_receive_packet(VLANClientState *nc, const uint8_t *buf, int size);
+ssize_t qemu_receive_packet_iov(VLANClientState *nc,
+                                const struct iovec *iov,
+                                int iovcnt);
 ssize_t qemu_send_packet_raw(VLANClientState *vc, const uint8_t *buf, int size);
 ssize_t qemu_send_packet_async(VLANClientState *vc, const uint8_t *buf,
                                int size, NetPacketSent *sent_cb);
Index: xen-4.2.5-testing/tools/qemu-xen-dir-remote/net/queue.h
===================================================================
--- xen-4.2.5-testing.orig/tools/qemu-xen-dir-remote/net/queue.h
+++ xen-4.2.5-testing/tools/qemu-xen-dir-remote/net/queue.h
@@ -51,6 +51,14 @@ NetQueue *qemu_new_net_queue(NetPacketDe
                              void *opaque);
 void qemu_del_net_queue(NetQueue *queue);
 
+ssize_t qemu_net_queue_receive(NetQueue *queue,
+                               const uint8_t *data,
+                               size_t size);
+
+ssize_t qemu_net_queue_receive_iov(NetQueue *queue,
+                                   const struct iovec *iov,
+                                   int iovcnt);
+
 ssize_t qemu_net_queue_send(NetQueue *queue,
                             VLANClientState *sender,
                             unsigned flags,
Index: xen-4.2.5-testing/tools/qemu-xen-dir-remote/net.c
===================================================================
--- xen-4.2.5-testing.orig/tools/qemu-xen-dir-remote/net.c
+++ xen-4.2.5-testing/tools/qemu-xen-dir-remote/net.c
@@ -349,20 +349,24 @@ void qemu_foreach_nic(qemu_nic_foreach f
     }
 }
 
+int qemu_can_receive_packet(VLANClientState *vc)
+{
+    if (vc->receive_disabled) {
+        return 0;
+    } else if (vc->info->can_receive &&
+               !vc->info->can_receive(vc)) {
+        return 0;
+    }
+    return 1;
+}
+
 int qemu_can_send_packet(VLANClientState *sender)
 {
     VLANState *vlan = sender->vlan;
     VLANClientState *vc;
 
     if (sender->peer) {
-        if (sender->peer->receive_disabled) {
-            return 0;
-        } else if (sender->peer->info->can_receive &&
-                   !sender->peer->info->can_receive(sender->peer)) {
-            return 0;
-        } else {
-            return 1;
-        }
+        return qemu_can_receive_packet(sender->peer);
     }
 
     if (!sender->vlan) {
@@ -526,6 +530,25 @@ void qemu_send_packet(VLANClientState *v
     qemu_send_packet_async(vc, buf, size, NULL);
 }
 
+ssize_t qemu_receive_packet(VLANClientState *vc, const uint8_t *buf, int size)
+{
+    if (!qemu_can_receive_packet(vc)) {
+        return 0;
+    }
+
+    return qemu_net_queue_receive(vc->send_queue, buf, size);
+}
+
+ssize_t qemu_receive_packet_iov(VLANClientState *vc, const struct iovec *iov,
+                                int iovcnt)
+{
+    if (!qemu_can_receive_packet(vc)) {
+        return 0;
+    }
+
+    return qemu_net_queue_receive_iov(vc->send_queue, iov, iovcnt);
+}
+
 ssize_t qemu_send_packet_raw(VLANClientState *vc, const uint8_t *buf, int size)
 {
     return qemu_send_packet_async_with_flags(vc, QEMU_NET_PACKET_FLAG_RAW,
Index: xen-4.2.5-testing/tools/qemu-xen-dir-remote/net/queue.c
===================================================================
--- xen-4.2.5-testing.orig/tools/qemu-xen-dir-remote/net/queue.c
+++ xen-4.2.5-testing/tools/qemu-xen-dir-remote/net/queue.c
@@ -172,6 +172,28 @@ static ssize_t qemu_net_queue_deliver_io
     return ret;
 }
 
+ssize_t qemu_net_queue_receive(NetQueue *queue,
+                               const uint8_t *data,
+                               size_t size)
+{
+    if (queue->delivering) {
+        return 0;
+    }
+
+    return qemu_net_queue_deliver(queue, NULL, 0, data, size);
+}
+
+ssize_t qemu_net_queue_receive_iov(NetQueue *queue,
+                                   const struct iovec *iov,
+                                   int iovcnt)
+{
+    if (queue->delivering) {
+        return 0;
+    }
+
+    return qemu_net_queue_deliver_iov(queue, NULL, 0, iov, iovcnt);
+}
+
 ssize_t qemu_net_queue_send(NetQueue *queue,
                             VLANClientState *sender,
                             unsigned flags,
