*/
#include "net/queue.h"
-#include "qemu-queue.h"
+#include "qemu/queue.h"
+#include "net/net.h"
/* The delivery handler may only return zero if it will call
* qemu_net_queue_flush() when it determines that it is once again able
struct NetPacket {
QTAILQ_ENTRY(NetPacket) entry;
- VLANClientState *sender;
+ NetClientState *sender;
unsigned flags;
int size;
NetPacketSent *sent_cb;
};
struct NetQueue {
- NetPacketDeliver *deliver;
- NetPacketDeliverIOV *deliver_iov;
void *opaque;
+ uint32_t nq_maxlen;
+ uint32_t nq_count;
+ NetQueueDeliverFunc *deliver;
QTAILQ_HEAD(packets, NetPacket) packets;
unsigned delivering : 1;
};
-NetQueue *qemu_new_net_queue(NetPacketDeliver *deliver,
- NetPacketDeliverIOV *deliver_iov,
- void *opaque)
+NetQueue *qemu_new_net_queue(NetQueueDeliverFunc *deliver, void *opaque)
{
NetQueue *queue;
- queue = qemu_mallocz(sizeof(NetQueue));
+ queue = g_new0(NetQueue, 1);
- queue->deliver = deliver;
- queue->deliver_iov = deliver_iov;
queue->opaque = opaque;
+ queue->nq_maxlen = 10000;
+ queue->nq_count = 0;
+ queue->deliver = deliver;
QTAILQ_INIT(&queue->packets);
QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
QTAILQ_REMOVE(&queue->packets, packet, entry);
- qemu_free(packet);
+ g_free(packet);
}
- qemu_free(queue);
+ g_free(queue);
}
-static ssize_t qemu_net_queue_append(NetQueue *queue,
- VLANClientState *sender,
- unsigned flags,
- const uint8_t *buf,
- size_t size,
- NetPacketSent *sent_cb)
+static void qemu_net_queue_append(NetQueue *queue,
+ NetClientState *sender,
+ unsigned flags,
+ const uint8_t *buf,
+ size_t size,
+ NetPacketSent *sent_cb)
{
NetPacket *packet;
- packet = qemu_malloc(sizeof(NetPacket) + size);
+ if (queue->nq_count >= queue->nq_maxlen && !sent_cb) {
+ return; /* drop if queue full and no callback */
+ }
+ packet = g_malloc(sizeof(NetPacket) + size);
packet->sender = sender;
packet->flags = flags;
packet->size = size;
packet->sent_cb = sent_cb;
memcpy(packet->data, buf, size);
+ queue->nq_count++;
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
-
- return size;
}
-static ssize_t qemu_net_queue_append_iov(NetQueue *queue,
- VLANClientState *sender,
- unsigned flags,
- const struct iovec *iov,
- int iovcnt,
- NetPacketSent *sent_cb)
+void qemu_net_queue_append_iov(NetQueue *queue,
+ NetClientState *sender,
+ unsigned flags,
+ const struct iovec *iov,
+ int iovcnt,
+ NetPacketSent *sent_cb)
{
NetPacket *packet;
size_t max_len = 0;
int i;
+ if (queue->nq_count >= queue->nq_maxlen && !sent_cb) {
+ return; /* drop if queue full and no callback */
+ }
for (i = 0; i < iovcnt; i++) {
max_len += iov[i].iov_len;
}
- packet = qemu_malloc(sizeof(NetPacket) + max_len);
+ packet = g_malloc(sizeof(NetPacket) + max_len);
packet->sender = sender;
packet->sent_cb = sent_cb;
packet->flags = flags;
packet->size += len;
}
+ queue->nq_count++;
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
-
- return packet->size;
}
static ssize_t qemu_net_queue_deliver(NetQueue *queue,
- VLANClientState *sender,
+ NetClientState *sender,
unsigned flags,
const uint8_t *data,
size_t size)
{
ssize_t ret = -1;
+ struct iovec iov = {
+ .iov_base = (void *)data,
+ .iov_len = size
+ };
queue->delivering = 1;
- ret = queue->deliver(sender, flags, data, size, queue->opaque);
+ ret = queue->deliver(sender, flags, &iov, 1, queue->opaque);
queue->delivering = 0;
return ret;
}
static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue,
- VLANClientState *sender,
+ NetClientState *sender,
unsigned flags,
const struct iovec *iov,
int iovcnt)
ssize_t ret = -1;
queue->delivering = 1;
- ret = queue->deliver_iov(sender, flags, iov, iovcnt, queue->opaque);
+ ret = queue->deliver(sender, flags, iov, iovcnt, queue->opaque);
queue->delivering = 0;
return ret;
}
ssize_t qemu_net_queue_send(NetQueue *queue,
- VLANClientState *sender,
+ NetClientState *sender,
unsigned flags,
const uint8_t *data,
size_t size,
{
ssize_t ret;
- if (queue->delivering) {
- return qemu_net_queue_append(queue, sender, flags, data, size, NULL);
+ if (queue->delivering || !qemu_can_send_packet(sender)) {
+ qemu_net_queue_append(queue, sender, flags, data, size, sent_cb);
+ return 0;
}
ret = qemu_net_queue_deliver(queue, sender, flags, data, size);
}
ssize_t qemu_net_queue_send_iov(NetQueue *queue,
- VLANClientState *sender,
+ NetClientState *sender,
unsigned flags,
const struct iovec *iov,
int iovcnt,
{
ssize_t ret;
- if (queue->delivering) {
- return qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, NULL);
+ if (queue->delivering || !qemu_can_send_packet(sender)) {
+ qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
+ return 0;
}
ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt);
return ret;
}
-void qemu_net_queue_purge(NetQueue *queue, VLANClientState *from)
+void qemu_net_queue_purge(NetQueue *queue, NetClientState *from)
{
NetPacket *packet, *next;
QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
if (packet->sender == from) {
QTAILQ_REMOVE(&queue->packets, packet, entry);
- qemu_free(packet);
+ queue->nq_count--;
+ if (packet->sent_cb) {
+ packet->sent_cb(packet->sender, 0);
+ }
+ g_free(packet);
}
}
}
-void qemu_net_queue_flush(NetQueue *queue)
+bool qemu_net_queue_flush(NetQueue *queue)
{
while (!QTAILQ_EMPTY(&queue->packets)) {
NetPacket *packet;
packet = QTAILQ_FIRST(&queue->packets);
QTAILQ_REMOVE(&queue->packets, packet, entry);
+ queue->nq_count--;
ret = qemu_net_queue_deliver(queue,
packet->sender,
packet->data,
packet->size);
if (ret == 0) {
+ queue->nq_count++;
QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
- break;
+ return false;
}
if (packet->sent_cb) {
packet->sent_cb(packet->sender, ret);
}
- qemu_free(packet);
+ g_free(packet);
}
+ return true;
}