Performance difference on sendfile Guest -> Host is close to the noise
(understandable, because we copy anyway).
---
 Documentation/lguest/lguest.c |   17 +++++++++++------
 drivers/net/tun.c             |   16 +++++++++-------
 drivers/net/virtio_net.c      |    1 +
 3 files changed, 21 insertions(+), 13 deletions(-)

diff -r 1af7beb174e4 Documentation/lguest/lguest.c
--- a/Documentation/lguest/lguest.c	Thu Jan 10 17:44:33 2008 +1100
+++ b/Documentation/lguest/lguest.c	Fri Jan 11 14:04:03 2008 +1100
@@ -852,11 +852,10 @@ 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);
+		printf("Wrote %i bytes\n", len);
 		add_used_and_trigger(fd, vq, head, len);
 	}
 }
@@ -1266,7 +1265,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 +1301,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);
diff -r 1af7beb174e4 drivers/net/tun.c
--- a/drivers/net/tun.c	Thu Jan 10 17:44:33 2008 +1100
+++ b/drivers/net/tun.c	Fri Jan 11 14:04:03 2008 +1100
@@ -257,7 +257,7 @@ static struct sk_buff *copy_user_skb(siz
 }
 
 /* This will fail if they give us a crazy iovec, but that's their own fault. */
-static int get_user_skb_frags(const struct iovec *iv, size_t count,
+static int get_user_skb_frags(const struct iovec *iv, size_t num,
 			      struct skb_frag_struct *f)
 {
 	unsigned int i, j, num_pg = 0;
@@ -265,11 +265,11 @@ static int get_user_skb_frags(const stru
 	struct page *pages[MAX_SKB_FRAGS];
 
 	down_read(&current->mm->mmap_sem);
-	for (i = 0; i < count; i++) {
+	for (i = 0; i < num; i++) {
 		int expect, n;
 		unsigned long base, len;
-		base = (unsigned long)iv[count].iov_base;
-		len = (unsigned long)iv[count].iov_len;
+		base = (unsigned long)iv[i].iov_base;
+		len = (unsigned long)iv[i].iov_len;
 
 		/* How many pages will this take? */
 		expect = (base + len)/PAGE_SIZE - base/PAGE_SIZE;
@@ -318,7 +318,7 @@ fail:
 
 static struct sk_buff *map_user_skb(const struct virtio_net_hdr *gso,
 				    size_t align, struct iovec *iv,
-				    size_t count, size_t len)
+				    size_t num, size_t len)
 {
 	struct sk_buff *skb;
 	struct skb_shared_info *sinfo;
@@ -361,11 +361,12 @@ static struct sk_buff *map_user_skb(cons
 		goto fail;
 	}
 
-	err = get_user_skb_frags(iv, count, sinfo->frags);
+	err = get_user_skb_frags(iv, num, sinfo->frags);
 	if (err < 0)
 		goto fail;
 
 	sinfo->nr_frags = err;
+	printk("len = %u, nr_frags = %u\n", skb->len, sinfo->nr_frags);
 
 	/* GSO code expects transport header set up */
 	skb_set_transport_header(skb, gso->gso_hdr_len);
@@ -410,13 +411,14 @@ static __inline__ ssize_t tun_get_user(s
 
 		if (memcpy_fromiovec((void *)&gso, iv, sizeof(gso)))
 			return -EFAULT;
+		printk("tun: GSO, len = %lu\n", len);
 	}
 
 	if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV)
 		align = NET_IP_ALIGN;
 
 	if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE)
-		skb = map_user_skb(&gso, align, iv, count, len);
+		skb = map_user_skb(&gso, align, iv, num, len);
 	else
 		skb = copy_user_skb(align, iv, len);
 
diff -r 1af7beb174e4 drivers/net/virtio_net.c
--- a/drivers/net/virtio_net.c	Thu Jan 10 17:44:33 2008 +1100
+++ b/drivers/net/virtio_net.c	Fri Jan 11 14:04:03 2008 +1100
@@ -246,6 +246,7 @@ static int start_xmit(struct sk_buff *sk
 	}
 
 	if (skb_is_gso(skb)) {
+		printk("GSO skb!\n");
 		hdr->gso_hdr_len = skb_transport_header(skb) - skb->data;
 		hdr->gso_size = skb_shinfo(skb)->gso_size;
 		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
