From patchwork Tue Feb 5 17:29:09 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luigi Rizzo X-Patchwork-Id: 218306 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 153C32C0099 for ; Wed, 6 Feb 2013 04:29:28 +1100 (EST) Received: from localhost ([::1]:33205 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U2mKk-0008Bt-5y for incoming@patchwork.ozlabs.org; Tue, 05 Feb 2013 12:29:26 -0500 Received: from eggs.gnu.org ([208.118.235.92]:32809) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U2mKc-0008BI-ON for qemu-devel@nongnu.org; Tue, 05 Feb 2013 12:29:20 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1U2mKX-00037Q-Js for qemu-devel@nongnu.org; Tue, 05 Feb 2013 12:29:18 -0500 Received: from onelab2.iet.unipi.it ([131.114.59.238]:50944) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U2mKX-00037F-Dl for qemu-devel@nongnu.org; Tue, 05 Feb 2013 12:29:13 -0500 Received: by onelab2.iet.unipi.it (Postfix, from userid 275) id 45D6C73027; Tue, 5 Feb 2013 18:29:09 +0100 (CET) Date: Tue, 5 Feb 2013 18:29:09 +0100 From: Luigi Rizzo To: qemu-devel@nongnu.org Message-ID: <20130205172909.GD31226@onelab2.iet.unipi.it> Mime-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.4.2.3i X-detected-operating-system: by eggs.gnu.org: Mac OS X 10.x X-Received-From: 131.114.59.238 Subject: [Qemu-devel] [PATCH v2] fix unbounded NetQueue X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org In the current implementation of qemu, running without a network backend will cause the queue to grow unbounded when the guest is transmitting traffic. This patch fixes the problem by implementing bounded size NetQueue, used with an arbitrary limit of 10000 packets, and dropping packets when the queue is full _and_ the sender does not pass a callback. The second condition makes sure that we never drop packets that contains a callback (which would be tricky, because the producer expects the callback to be run when all previous packets have been consumed; so we cannot run it when the packet is dropped). If documentation is correct, producers that submit a callback should stop sending when their packet is queued, so there is no real risk that the queue exceeds the max size by large values. Signed-off-by: Luigi Rizzo diff --git a/net/queue.c b/net/queue.c index 6eaf5b6..859d02a 100644 --- a/net/queue.c +++ b/net/queue.c @@ -50,6 +50,8 @@ struct NetPacket { struct NetQueue { void *opaque; + uint32_t nq_maxlen; + uint32_t nq_count; QTAILQ_HEAD(packets, NetPacket) packets; @@ -63,6 +65,8 @@ NetQueue *qemu_new_net_queue(void *opaque) queue = g_malloc0(sizeof(NetQueue)); queue->opaque = opaque; + queue->nq_maxlen = 10000; + queue->nq_count = 0; QTAILQ_INIT(&queue->packets); @@ -92,6 +96,9 @@ static void qemu_net_queue_append(NetQueue *queue, { NetPacket *packet; + 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; @@ -99,6 +106,7 @@ static void qemu_net_queue_append(NetQueue *queue, packet->sent_cb = sent_cb; memcpy(packet->data, buf, size); + queue->nq_count++; QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); } @@ -113,6 +121,9 @@ static void qemu_net_queue_append_iov(NetQueue *queue, 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; } @@ -130,6 +141,7 @@ static void qemu_net_queue_append_iov(NetQueue *queue, packet->size += len; } + queue->nq_count++; QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); } @@ -220,6 +232,7 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from) QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) { if (packet->sender == from) { QTAILQ_REMOVE(&queue->packets, packet, entry); + queue->nq_count--; g_free(packet); } } @@ -233,6 +246,7 @@ bool qemu_net_queue_flush(NetQueue *queue) packet = QTAILQ_FIRST(&queue->packets); QTAILQ_REMOVE(&queue->packets, packet, entry); + queue->nq_count--; ret = qemu_net_queue_deliver(queue, packet->sender, @@ -240,6 +254,7 @@ bool qemu_net_queue_flush(NetQueue *queue) packet->data, packet->size); if (ret == 0) { + queue->nq_count++; QTAILQ_INSERT_HEAD(&queue->packets, packet, entry); return false; }