Skip to content

Commit

Permalink
lkl: Fix netperf TCP_STREAM server hangs
Browse files Browse the repository at this point in the history
The netserver hangs after haijacking in TCP_STREAM test.

To reproduce:
$ LKL_HIJACK_NET_TAP=lkl_ptt1 LKL_HIJACK_NET_IP=192.168.20.2 LKL_HIJACK_NET_NETMASK_LEN=24 LKL_HIJACK_DEBUG=1  ./bin/lkl-hijack.sh netserver -D -f
$ echo "set -e && for i in \`seq 1000\`;do echo Test:\$i; netperf -L
192.168.20.1 -H 192.168.20.2 ; done" > /tmp/test.sh
$ sh /tmp/test.sh

The netperf may fail with error "recv_response_timed_n: no response
received. errno 113 counter 0" after hundreds of runs.

This fix make virtio trigger an irq whenever the avail queue is empty.

Signed-off-by: Yuan Liu <liuyuan@google.com>
  • Loading branch information
liuyuan10 committed Jun 7, 2016
1 parent 202e4f5 commit 7204d9d
Showing 1 changed file with 13 additions and 5 deletions.
18 changes: 13 additions & 5 deletions tools/lkl/lib/virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ void virtio_req_complete(struct virtio_req *req, uint32_t len)
struct virtio_dev *dev = req->dev;
uint16_t idx = le16toh(q->used->idx) & (q->num - 1);
uint16_t new = le16toh(q->used->idx) + 1;
int send_irq = 0;

q->used->ring[idx].id = htole16(req->idx);
q->used->ring[idx].len = htole16(len);
Expand All @@ -83,6 +84,13 @@ void virtio_req_complete(struct virtio_req *req, uint32_t len)
__sync_synchronize();
q->used->idx = htole16(new);

/* Triggers the irq whenever there is no available buffer.
* q->last_avail_idx is incremented after calling virtio_req_complete(),
* so here we need to add one to it.
*/
if (q->last_avail_idx + 1 == q->avail->idx)
send_irq = 1;

/* There are two rings: q->avail and q->used for each of the rx and tx
* queues that are used to pass buffers between kernel driver and the
* virtio device implementation.
Expand All @@ -105,16 +113,16 @@ void virtio_req_complete(struct virtio_req *req, uint32_t len)
* increased to a larger one. So we need to trigger the irq when
* virtio_get_used_event(q) < q->used->idx.
*
* To avoid unnessary irqs for each packet after
* To avoid unnessary irqs for each packet after
* virtio_get_used_event(q) < q->used->idx, last_used_idx_signaled is
* stored and irq is only triggered if
* stored and irq is only triggered if
* last_used_idx_signaled <= virtio_get_used_event(q) < q->used->idx
*
* This is what lkl_vring_need_event() checks and it evens covers the
* case when those numbers round up.
* case when those numbers wrap up.
*/
if (lkl_vring_need_event(le16toh(virtio_get_used_event(q)), new,
q->last_used_idx_signaled)) {
if (send_irq || lkl_vring_need_event(le16toh(virtio_get_used_event(q)),
new, q->last_used_idx_signaled)) {
q->last_used_idx_signaled = new;
virtio_deliver_irq(dev);
}
Expand Down

0 comments on commit 7204d9d

Please sign in to comment.