---
 Documentation/lguest/lguest.c |   87 ++++++++++++++++++++++++++++++++++++++++-
 drivers/net/Makefile          |    1 
 drivers/net/netring.c         |   88 +++++++++++++++++++++++++++++++-----------
 drivers/virtio/virtio_ring.c  |    4 +
 net/core/dev.c                |   18 ++++++--
 5 files changed, 168 insertions(+), 30 deletions(-)

diff -r f4a099082092 Documentation/lguest/lguest.c
--- a/Documentation/lguest/lguest.c	Tue Apr 01 20:50:03 2008 +1000
+++ b/Documentation/lguest/lguest.c	Tue Apr 01 20:55:40 2008 +1000
@@ -43,6 +43,7 @@
 #include "linux/virtio_console.h"
 #include "linux/virtio_rng.h"
 #include "linux/virtio_ring.h"
+#include "linux/if_netring.h"
 #include "asm-x86/bootparam.h"
 /*L:110 We can ignore the 39 include files we need for this program, but I do
  * want to draw attention to the use of kernel-style types.
@@ -1270,8 +1271,8 @@ static void add_to_bridge(int fd, const 
 /* This sets up the Host end of the network device with an IP address, brings
  * it up so packets will flow, the copies the MAC address into the hwaddr
  * pointer. */
-static void configure_device(int fd, const char *devname, u32 ipaddr,
-			     unsigned char hwaddr[6])
+static void configure_interface(int fd, const char *devname, u32 ipaddr,
+				unsigned char hwaddr[6])
 {
 	struct ifreq ifr;
 	struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
@@ -1345,7 +1346,7 @@ static void setup_tun_net(const char *ar
 		ip = str2ip(arg);
 
 	/* Set up the tun device, and get the mac address for the interface. */
-	configure_device(ipfd, ifr.ifr_name, ip, conf.mac);
+	configure_interface(ipfd, ifr.ifr_name, ip, conf.mac);
 
 	/* Tell Guest what MAC address to use. */
 	add_feature(dev, VIRTIO_NET_F_MAC);
@@ -1359,6 +1360,81 @@ static void setup_tun_net(const char *ar
 		(u8)(ip>>24),(u8)(ip>>16),(u8)(ip>>8),(u8)ip);
 	if (br_name)
 		verbose("attached to bridge: %s\n", br_name);
+}
+/*:*/
+
+/* Something happened to our tun ring. */
+static bool handle_netring_input(int fd, struct device *dev)
+{
+	/* FIXME: just ping both queues. */
+	trigger_irq(fd, dev->vq);
+	trigger_irq(fd, dev->vq->next);
+
+	/* All good. */
+	return true;
+}
+
+/* The Guest sent something */
+static void handle_netring_output(int fd, struct virtqueue *vq)
+{
+	char c = 0;
+
+	if (write(vq->dev->fd, &c, 1) < 0)
+		err(1, "Writing to netring");
+}
+
+static void setup_netring(const char *arg)
+{
+	struct device *dev;
+	char ifname[IFNAMSIZ];
+	int netfd, ipfd;
+	u32 ip;
+	struct virtio_net_config conf;
+	struct netring nr;
+
+	netfd = open_or_die("/dev/netring", O_RDWR);
+	
+	/* First we create a new network device. */
+	dev = new_device("netring", VIRTIO_ID_NET, netfd, handle_netring_input);
+
+	/* Network devices need a receive and a send queue, just like
+	 * console. */
+	add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd);
+	add_virtqueue(dev, VIRTQUEUE_NUM, handle_netring_output);
+
+	nr.recv_addr = (unsigned long)dev->vq->vring.desc;
+	nr.xmit_addr = (unsigned long)dev->vq->next->vring.desc;
+	nr.recv_num = dev->vq->vring.num;
+	nr.xmit_num = dev->vq->next->vring.num;
+	nr.limit = guest_limit;
+	nr.offset = (unsigned long)guest_base;
+	nr.flags = 0;
+	if (ioctl(netfd, NETRINGBIND, &nr) != 0)
+		err(1, "binding netring interface to virtqueues");
+
+	if (ioctl(netfd, NETRINGGETIF, ifname) != 0)
+		err(1, "getting netring interface name");
+
+	/* We need a socket to perform the magic network ioctls to bring up the
+	 * tap interface, connect to the bridge etc.  Any socket will do! */
+	ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+	if (ipfd < 0)
+		err(1, "opening IP socket");
+
+	/* Set up the interface, and get the mac address for the interface. */
+	ip = str2ip(arg);
+	configure_interface(ipfd, ifname, ip, conf.mac);
+
+	/* Tell Guest what MAC address to use. */
+	add_feature(dev, VIRTIO_NET_F_MAC);
+	set_config(dev, sizeof(conf), &conf);
+
+	/* We don't need the socket any more; setup is done. */
+	close(ipfd);
+
+	verbose("device %u: netring %u.%u.%u.%u\n",
+		devices.device_num++,
+		(u8)(ip>>24),(u8)(ip>>16),(u8)(ip>>8),(u8)ip);
 }
 
 /* Our block (disk) device should be really simple: the Guest asks for a block
@@ -1716,6 +1792,7 @@ static struct option opts[] = {
 static struct option opts[] = {
 	{ "verbose", 0, NULL, 'v' },
 	{ "tunnet", 1, NULL, 't' },
+	{ "netring", 1, NULL, 'n' },
 	{ "block", 1, NULL, 'b' },
 	{ "rng", 0, NULL, 'r' },
 	{ "initrd", 1, NULL, 'i' },
@@ -1724,6 +1801,7 @@ static void usage(void)
 static void usage(void)
 {
 	errx(1, "Usage: lguest [--verbose] "
+	     "[--netring=<ipaddr>]\n"
 	     "[--tunnet=(<ipaddr>|bridge:<bridgename>)\n"
 	     "|--block=<filename>|--initrd=<filename>]...\n"
 	     "<mem-in-mb> vmlinux [args...]");
@@ -1788,6 +1866,9 @@ int main(int argc, char *argv[])
 			break;
 		case 't':
 			setup_tun_net(optarg);
+			break;
+		case 'n':
+			setup_netring(optarg);
 			break;
 		case 'b':
 			setup_block_file(optarg);
diff -r f4a099082092 drivers/net/Makefile
--- a/drivers/net/Makefile	Tue Apr 01 20:50:03 2008 +1000
+++ b/drivers/net/Makefile	Tue Apr 01 20:55:40 2008 +1000
@@ -253,3 +253,4 @@ obj-$(CONFIG_NIU) += niu.o
 obj-$(CONFIG_NIU) += niu.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_NETRING) += netring.o
+CFLAGS_netring.o += -O0
diff -r f4a099082092 drivers/net/netring.c
--- a/drivers/net/netring.c	Tue Apr 01 20:50:03 2008 +1000
+++ b/drivers/net/netring.c	Tue Apr 01 20:55:40 2008 +1000
@@ -129,6 +129,7 @@ static void netring_setup(struct net_dev
 	atomic_set(&nr->recvq_estimate, 0);
 
 	ether_setup(dev);
+	random_ether_addr(dev->dev_addr);
 	dev->hard_start_xmit = netring_receive_input;
 }
 
@@ -240,23 +241,12 @@ free_netdev:
 	return err;
 }
 
-/* Assumes src is locked, and dest is or doesn't need to be. */
-static void __skb_queue_steal(struct sk_buff_head *dest,
-			      struct sk_buff_head *src)
-{
-	dest->prev = src->prev;
-	dest->next = src->next;
-	dest->qlen = src->qlen;
-	src->prev = src->next = NULL;
-	src->qlen = 0;
-}
-
 /* Chases down this descriptor, checking validity, and put it in iov[].
  * Returne -errno or number of iovs used (max is 1 + MAX_SKB_FRAGS).
  * Also fills in the total length (needed before using memcpy_toiovec etc). */
 static int get_iovec(struct netring_struct *nr,
 		     struct vring *v, unsigned int head,
-		     struct iovec iov[], unsigned int *len)
+		     struct iovec iov[], int flags, unsigned int *len)
 {
 	u32 i, iov_num = 0;
 	struct vring_desc d;
@@ -272,11 +262,11 @@ static int get_iovec(struct netring_stru
 		}
 
 		if (copy_from_user(&d, &v->desc[i], sizeof(d)) != 0)
-			return -EINVAL;
+			return -EFAULT;
 
 		/* We expect every recvq descriptor to be writable. */
-		if (!(d.flags & VRING_DESC_F_WRITE)) {
-			dev_dbg(&nr->dev->dev, "non-writable desc %u\n", i);
+		if ((d.flags & VRING_DESC_F_WRITE) != flags) {
+			dev_dbg(&nr->dev->dev, "desc %u flags wrong\n", i);
 			return -EINVAL;
 		}
 
@@ -290,6 +280,11 @@ static int get_iovec(struct netring_stru
 		iov[iov_num].iov_len = d.len;
 		*len += d.len;
 		iov[iov_num].iov_base = (void __user*)(long)d.addr + nr->offset;
+		printk("iovec[%i] = %u@%p (guest %p)\n",
+		       iov_num, iov[iov_num].iov_len,
+		       iov[iov_num].iov_base, 
+		       iov[iov_num].iov_base - nr->offset);
+		       
 		iov_num++;
 
 		if (!(d.flags & VRING_DESC_F_NEXT))
@@ -298,6 +293,20 @@ static int get_iovec(struct netring_stru
 		i = v->desc[i].next;
 	}
 	return iov_num;
+}
+
+/* Assumes src is locked, and dst is or doesn't need to be. */
+static void __skb_queue_steal(struct sk_buff_head *dst,
+			      struct sk_buff_head *src)
+{
+	dst->prev = src->prev;
+	src->prev->next = (struct sk_buff *)dst;
+	dst->next = src->next;
+	src->next->prev = (struct sk_buff *)dst;
+
+	dst->qlen = src->qlen;
+	src->prev = src->next = (struct sk_buff *)src;
+	src->qlen = 0;
 }
 
 static int copy_recv_skbs(struct netring_struct *nr)
@@ -322,19 +331,28 @@ static int copy_recv_skbs(struct netring
 		unsigned int len, num, head;
 		struct vring_used_elem __user *used;
 
+		printk("%s:%u\n", __FILE__, __LINE__);
 		num = nr->last_recv_avail % nr->recv.num;
+		printk("%s:%u\n", __FILE__, __LINE__);
 		head = get_index(&nr->recv.avail->ring[num]);
-		err = get_iovec(nr, &nr->recv, head, iov, &len);
+		printk("%s:%u\n", __FILE__, __LINE__);
+		err = get_iovec(nr, &nr->recv, head, iov, VRING_DESC_F_WRITE,
+				&len);
+		printk("%s:%u\n", __FILE__, __LINE__);
 		if (err < 0)
 			goto requeue;
+		printk("%s:%u\n", __FILE__, __LINE__);
 		num = err;
 
 		/* Progress to next descriptor. */
+		printk("%s:%u\n", __FILE__, __LINE__);
 		nr->last_recv_avail++;
 
+		printk("%s:%u\n", __FILE__, __LINE__);
 		skb = __skb_dequeue(&q);
 		sinfo = skb_shinfo(skb);
 
+		printk("%s:%u\n", __FILE__, __LINE__);
 		/* FIXME: we could stash this descriptor and go looking for a
 		 * better-sized one.  That would allow them to mix different
 		 * buffer sizes for efficiency. */
@@ -444,6 +462,8 @@ static int get_user_skb_frags(const stru
 		n = get_user_pages(current, current->mm, base, npages,
 				   0, 0, pages, NULL);
 		if (unlikely(n < 0)) {
+			printk("get_user_pages of %u @ %p failed\n",
+			       npages, (void *)base);
 			err = n;
 			goto fail;
 		}
@@ -460,6 +480,8 @@ static int get_user_skb_frags(const stru
 		}
 
 		if (unlikely(n != npages)) {
+			printk("get_user_pages of %u @ %p gave %u\n",
+			       npages, (void *)base, n);
 			err = -EFAULT;
 			goto fail;
 		}
@@ -486,22 +508,37 @@ static struct sk_buff *map_gso_skb(struc
 	int err;
 
 	/* Don't get silly with the lengths. */
-	if (len < sizeof(gso) || len > sizeof(gso) + 65536)
+	if (len < sizeof(gso) || len > sizeof(gso) + 65536) {
+		dev_dbg(&nr->dev->dev, "silly iovec len len %u\n", len);
 		return ERR_PTR(-EINVAL);
+	}
 
 	err = memcpy_fromiovec((void *)&gso, iov, sizeof(gso));
-	if (err < 0)
+	if (err < 0) {
+		dev_dbg(&nr->dev->dev, "iovec memcpy failed \n");
 		return ERR_PTR(err);
+	}
 	len -= sizeof(gso);
 
 	/* If you recommend an amount to copy, it must be < len. */
-	if (gso.hdr_len > len)
+	if (gso.hdr_len > len) {
+		dev_dbg(&nr->dev->dev, "GSO header len %u > %u\n",
+			gso.hdr_len, len);
 		return ERR_PTR(-EINVAL);
+	}
+
+	/* If no GSO len, implies the entire length. */
+	if (gso.hdr_len == 0)
+		gso.hdr_len = len;
+
 	len -= gso.hdr_len;
 
 	/* Can't have scatter gather packet already csummed. */
-	if (len && !(gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM))
+	if (len && !(gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) {
+		dev_dbg(&nr->dev->dev, "GSO pkt (%u+%u) w/o CSUM flag %#x\n",
+			gso.hdr_len, len, gso.flags);
 		return ERR_PTR(-EINVAL);
+	}
 
 	skb = alloc_skb_data_destructor(NET_IP_ALIGN + gso.hdr_len,
 					GFP_KERNEL, skb_finished,
@@ -530,7 +567,11 @@ static struct sk_buff *map_gso_skb(struc
 	case VIRTIO_NET_HDR_GSO_UDP:
 		sinfo->gso_type |= SKB_GSO_UDP;
 		break;
+	case VIRTIO_NET_HDR_GSO_NONE:
+		sinfo->gso_type = 0;
+		break;
 	default:
+		dev_dbg(&nr->dev->dev, "unknown GSO type %#x\n", gso.gso_type);
 		err = -EINVAL;
 		goto free_skb;
 	}
@@ -540,6 +581,7 @@ static struct sk_buff *map_gso_skb(struc
 
 	/* Copy in the header. */
 	if (memcpy_fromiovec(skb_put(skb, gso.hdr_len), iov, gso.hdr_len)) {
+		dev_dbg(&nr->dev->dev, "iovec hdr memcpy failed\n");
 		err = -EFAULT;
 		goto free_skb;
 	}
@@ -574,9 +616,11 @@ static int xmit_buffers(struct netring_s
 
 		num = nr->last_xmit_avail % nr->xmit.num;
 		head = get_index(&nr->xmit.avail->ring[num]);
-		err = get_iovec(nr, &nr->xmit, head, iov, &len);
-		if (err < 0)
+		err = get_iovec(nr, &nr->xmit, head, iov, 0, &len);
+		if (err < 0) {
+			printk("xmit_buffers: get_iovec ret %i\n", err);
 			return err;
+		}
 		num = err;
 
 		skb = map_gso_skb(nr, iov, num, len, head);
diff -r f4a099082092 drivers/virtio/virtio_ring.c
--- a/drivers/virtio/virtio_ring.c	Tue Apr 01 20:50:03 2008 +1000
+++ b/drivers/virtio/virtio_ring.c	Tue Apr 01 20:55:40 2008 +1000
@@ -246,7 +246,11 @@ irqreturn_t vring_interrupt(int irq, voi
 
 	if (!more_used(vq)) {
 		pr_debug("virtqueue interrupt with no work for %p\n", vq);
+#if 0
 		return IRQ_NONE;
+#else
+		return IRQ_HANDLED;
+#endif
 	}
 
 	if (unlikely(vq->broken))
diff -r f4a099082092 net/core/dev.c
--- a/net/core/dev.c	Tue Apr 01 20:50:03 2008 +1000
+++ b/net/core/dev.c	Tue Apr 01 20:55:40 2008 +1000
@@ -1004,19 +1004,25 @@ int dev_open(struct net_device *dev)
 	/*
 	 *	Is it even present?
 	 */
-	if (!netif_device_present(dev))
-		return -ENODEV;
+	if (!netif_device_present(dev)) {
+		printk("%s: not present\n", dev->name);
+		return -ENODEV;
+	}
 
 	/*
 	 *	Call device private open method
 	 */
 	set_bit(__LINK_STATE_START, &dev->state);
 
-	if (dev->validate_addr)
+	if (dev->validate_addr) {
 		ret = dev->validate_addr(dev);
-
-	if (!ret && dev->open)
+		printk("%s: validating address = %i\n", dev->name, ret);
+	}
+
+	if (!ret && dev->open) {
 		ret = dev->open(dev);
+		printk("%s: opening = %i\n", dev->name, ret);
+	}
 
 	/*
 	 *	If it went open OK then:
@@ -3150,6 +3156,8 @@ int dev_change_flags(struct net_device *
 		if (!ret)
 			dev_set_rx_mode(dev);
 	}
+
+	printk("%s:%u ret = %i\n", __FILE__, __LINE__, ret);
 
 	if (dev->flags & IFF_UP &&
 	    ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI |
