[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]