aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2012-03-06 00:00:07 +0100
committerJan Kiszka <jan.kiszka@siemens.com>2012-03-13 14:05:48 +0100
commitfe0653759544c60f1776e2db99b3d6ce24a039a0 (patch)
tree801c07a6c5e26d9926bba7b239074348d46543bf
parent344de2562fd725d3900faa7c0e738c01dfdeacb1 (diff)
downloadslirp-fe0653759544c60f1776e2db99b3d6ce24a039a0.zip
slirp-fe0653759544c60f1776e2db99b3d6ce24a039a0.tar.gz
slirp-fe0653759544c60f1776e2db99b3d6ce24a039a0.tar.bz2
slirp: Fix queue walking in if_start
Another attempt to get this right: We need to carefully walk both the fastq and the batchq in if_start while trying to send packets to possibly not yet resolved hosts on the virtual network. So far we just requeued a delayed packet where it was and then started walking the queues from the top again - that couldn't work. Now we pre- calculate the next packet in the queue so that the current one can safely be removed if it was sent successfully. We also need to take into account that the next packet can be from the same session if the current one was sent and there are no other sessions. CC: Fabien Chouteau <chouteau@adacore.com> CC: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com> CC: Stefan Weil <sw@weilnetz.de> Tested-by: Stefan Weil <sw@weilnetz.de> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
-rw-r--r--if.c59
1 files changed, 39 insertions, 20 deletions
diff --git a/if.c b/if.c
index ff9f572..a0f48c9 100644
--- a/if.c
+++ b/if.c
@@ -154,8 +154,8 @@ void if_start(Slirp *slirp)
{
uint64_t now = qemu_get_clock_ns(rt_clock);
int requeued = 0;
- bool from_batchq = false;
- struct mbuf *ifm, *ifqt;
+ bool from_batchq, next_from_batchq;
+ struct mbuf *ifm, *ifm_next, *ifqt;
DEBUG_CALL("if_start");
@@ -164,23 +164,36 @@ void if_start(Slirp *slirp)
}
slirp->if_start_busy = true;
- while (slirp->if_queued) {
+ if (slirp->if_fastq.ifq_next != &slirp->if_fastq) {
+ ifm_next = slirp->if_fastq.ifq_next;
+ next_from_batchq = false;
+ } else if (slirp->next_m != &slirp->if_batchq) {
+ /* Nothing on fastq, pick up from batchq via next_m */
+ ifm_next = slirp->next_m;
+ next_from_batchq = true;
+ } else {
+ ifm_next = NULL;
+ }
+
+ while (ifm_next) {
/* check if we can really output */
if (!slirp_can_output(slirp->opaque)) {
slirp->if_start_busy = false;
return;
}
- /*
- * See which queue to get next packet from
- * If there's something in the fastq, select it immediately
- */
- if (slirp->if_fastq.ifq_next != &slirp->if_fastq) {
- ifm = slirp->if_fastq.ifq_next;
- } else {
- /* Nothing on fastq, pick up from batchq via next_m */
- ifm = slirp->next_m;
- from_batchq = true;
+ ifm = ifm_next;
+ from_batchq = next_from_batchq;
+
+ ifm_next = ifm->ifq_next;
+ if (ifm_next == &slirp->if_fastq) {
+ /* No more packets in fastq, switch to batchq */
+ ifm_next = slirp->next_m;
+ next_from_batchq = true;
+ }
+ if (ifm_next == &slirp->if_batchq) {
+ /* end of batchq */
+ ifm_next = NULL;
}
slirp->if_queued--;
@@ -192,7 +205,7 @@ void if_start(Slirp *slirp)
continue;
}
- if (from_batchq) {
+ if (ifm == slirp->next_m) {
/* Set which packet to send on next iteration */
slirp->next_m = ifm->ifq_next;
}
@@ -203,13 +216,19 @@ void if_start(Slirp *slirp)
/* If there are more packets for this session, re-queue them */
if (ifm->ifs_next != ifm) {
- insque(ifm->ifs_next, ifqt);
+ struct mbuf *next = ifm->ifs_next;
+
+ insque(next, ifqt);
ifs_remque(ifm);
- /* Set next_m if the session packet is now the only one on
- * batchq */
- if (ifqt == &slirp->if_batchq &&
- slirp->next_m == &slirp->if_batchq) {
- slirp->next_m = ifm->ifs_next;
+
+ if (!from_batchq) {
+ /* Next packet in fastq is from the same session */
+ ifm_next = next;
+ next_from_batchq = false;
+ } else if (slirp->next_m == &slirp->if_batchq) {
+ /* Set next_m and ifm_next if the session packet is now the
+ * only one on batchq */
+ slirp->next_m = ifm_next = next;
}
}