[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]
Subject: [PATCH 16/16] lguest: support v1 endian for net device headers.
From: Rusty Russell <rusty@rustcorp.com.au> Since tap device is the same endian as userspace, we convert on the way through and back. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> --- tools/lguest/lguest.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index 1845e0d..92b6483 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c @@ -86,6 +86,12 @@ typedef uint8_t u8; static bool verbose; #define verbose(args...) \ do { if (verbose) printf(args); } while(0) + +/* + * The kernel's classic unlikely macro: tell gcc and the reader that a + * condition is usually false. + */ +#define unlikely(x) __builtin_expect(!!(x), 0) /*:*/ /* The pointer to the start of guest memory. */ @@ -245,6 +251,35 @@ static u64 virtio_to_cpu64(u64 v) | ((v & 0x00000000000000FFULL) << 56); } +/* Endian convert a u16 at this offset in the iovec. */ +static void iov_conv_cpu16(struct iovec iov[], unsigned num, size_t off) +{ + u8 *byte1, *byte2, tmp; + + assert(num); + while (iov->iov_len <= off) { + off -= iov->iov_len; + iov++; + if (--num == 0) + errx(1, "Short descriptor for conversion at %zu", off); + } + + byte1 = iov->iov_base + off; + if (unlikely(off + 1 > iov->iov_len)) { + /* Right on end of iov? Find next non-empty. */ + do { + iov++; + if (--num == 0) + errx(1, "Short split descriptor at %zu", off); + } while (iov->iov_len == 0); + off = -1; + } + byte2 = iov->iov_base + off + 1; + tmp = *byte2; + *byte2 = *byte1; + *byte1 = tmp; +} + /* Is this iovec empty? */ static bool iov_empty(const struct iovec iov[], unsigned int num_iov) { @@ -948,6 +983,15 @@ static void net_output(struct virtqueue *vq) head = wait_for_vq_desc(vq, iov, &out, &in); if (in) errx(1, "Input buffers in net output queue?"); + + /* + * Endian conversion for tun device. + */ + iov_conv_cpu16(iov, out, offsetof(struct virtio_net_hdr, hdr_len)); + iov_conv_cpu16(iov, out, offsetof(struct virtio_net_hdr, gso_size)); + iov_conv_cpu16(iov, out, offsetof(struct virtio_net_hdr, csum_start)); + iov_conv_cpu16(iov, out, offsetof(struct virtio_net_hdr, csum_offset)); + /* * Send the whole thing through to /dev/net/tun. It expects the exact * same format: what a coincidence! @@ -1013,6 +1057,14 @@ static void net_input(struct virtqueue *vq) warn("Failed to read from tun (%d).", errno); /* + * Endian conversion for tun device. + */ + iov_conv_cpu16(iov, in, offsetof(struct virtio_net_hdr, hdr_len)); + iov_conv_cpu16(iov, in, offsetof(struct virtio_net_hdr, gso_size)); + iov_conv_cpu16(iov, in, offsetof(struct virtio_net_hdr, csum_start)); + iov_conv_cpu16(iov, in, offsetof(struct virtio_net_hdr, csum_offset)); + + /* * Mark that packet buffer as used, but don't interrupt here. We want * to wait until we've done as much work as we can. */ -- 1.8.1.2
[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]