lguest: Use the IFF_GSO_HDR option to tap.

This actually simplifies the lguest launcher, since it can now pass
the whole packet (with gso header) straight to the tap device.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 Documentation/lguest/lguest.c |   29 ++++++++++++++---------------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff -r 2eab16ea3ef1 Documentation/lguest/lguest.c
--- a/Documentation/lguest/lguest.c	Tue Jan 15 19:21:27 2008 +1100
+++ b/Documentation/lguest/lguest.c	Tue Jan 15 20:47:08 2008 +1100
@@ -852,11 +852,9 @@ static void handle_net_output(int fd, st
 	while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
 		if (in)
 			errx(1, "Input buffers in output queue?");
-		/* Check header, but otherwise ignore it (we told the Guest we
-		 * supported no features, so it shouldn't have anything
-		 * interesting). */
-		(void)convert(&iov[0], struct virtio_net_hdr);
-		len = writev(vq->dev->fd, iov+1, out-1);
+		/* With IFF_GSO_HDR, tap takes the same format header as
+		 * virtio_net, so we just pass it through. */
+		len = writev(vq->dev->fd, iov, out);
 		add_used_and_trigger(fd, vq, head, len);
 	}
 }
@@ -868,7 +866,6 @@ static bool handle_tun_input(int fd, str
 	unsigned int head, in_num, out_num;
 	int len;
 	struct iovec iov[dev->vq->vring.num];
-	struct virtio_net_hdr *hdr;
 
 	/* First we need a network buffer from the Guests's recv virtqueue. */
 	head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
@@ -884,18 +881,14 @@ static bool handle_tun_input(int fd, str
 	} else if (out_num)
 		errx(1, "Output buffers in network recv queue?");
 
-	/* First element is the header: we set it to 0 (no features). */
-	hdr = convert(&iov[0], struct virtio_net_hdr);
-	hdr->flags = 0;
-	hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
-
-	/* Read the packet from the device directly into the Guest's buffer. */
-	len = readv(dev->fd, iov+1, in_num-1);
+	/* Read the GSO header and packet from the tun device directly into the
+	 * Guest's buffer. */
+	len = readv(dev->fd, iov, in_num);
 	if (len <= 0)
 		err(1, "reading network");
 
 	/* Tell the Guest about the new packet. */
-	add_used_and_trigger(fd, dev->vq, head, sizeof(*hdr) + len);
+	add_used_and_trigger(fd, dev->vq, head, len);
 
 	verbose("tun input packet len %i [%02x %02x] (%s)\n", len,
 		((u8 *)iov[1].iov_base)[0], ((u8 *)iov[1].iov_base)[1],
@@ -1266,7 +1259,7 @@ static void setup_tun_net(const char *ar
 	 * works now! */
 	netfd = open_or_die("/dev/net/tun", O_RDWR);
 	memset(&ifr, 0, sizeof(ifr));
-	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+	ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_GSO_HDR;
 	strcpy(ifr.ifr_name, "tap%d");
 	if (ioctl(netfd, TUNSETIFF, &ifr) != 0)
 		err(1, "configuring /dev/net/tun");
@@ -1302,6 +1295,12 @@ static void setup_tun_net(const char *ar
 	/* Tell Guest what MAC address to use. */
 	add_feature(dev, VIRTIO_NET_F_MAC);
 	set_config(dev, sizeof(conf), &conf);
+	/* Tap device can handle no csum, and all types of GSO. */
+	add_feature(dev, VIRTIO_NET_F_NO_CSUM);
+	add_feature(dev, VIRTIO_NET_F_TSO4);
+	add_feature(dev, VIRTIO_NET_F_UFO);
+	add_feature(dev, VIRTIO_NET_F_TSO4_ECN);
+	add_feature(dev, VIRTIO_NET_F_TSO6);
 
 	/* We don't need the socket any more; setup is done. */
 	close(ipfd);
