OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

virtio-dev message

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