public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
To: Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
Cc: "kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org"
	<kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>,
	Christian Borntraeger
	<cborntra-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>,
	Martin Schwidefsky
	<schwidefsky-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
Subject: Re: [PATCH/RFC 8/9] Virtual network host switch support
Date: Fri, 11 May 2007 15:21:28 -0500	[thread overview]
Message-ID: <4644D048.7060106@us.ibm.com> (raw)
In-Reply-To: <1178904968.25135.35.camel-WIxn4w2hgUz3YA32ykw5MLlKpX0K8NHHQQ4Iyu8u01E@public.gmane.org>

Carsten Otte wrote:
> From: Christian Borntraeger <cborntra-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
>
> This is the host counterpart for the virtual network device driver. This driver
> has an char device node where the hypervisor can attach. It also
> has a kind of dumb switch that passes packets between guests. Last but not least
> it contains a host network interface. Patches for attaching other host network
> devices to the switch via raw sockets, extensions to qeth or netfilter are
>   

Any feel for the performance relative to the bridging code?  The 
bridging code is a pretty big bottle neck in guest=>guest communications 
in Xen at least.

> currently tested but not ready yet. We did not use the linux bridging code to
> allow non-root users to create virtual networks between guests. 
>   

Is that the primary reason?  If so, that seems like a rather large 
hammer for something that a userspace suid wrapper could have addressed...

Regards,

Anthony Liguori

> Signed-off-by: Christian Borntraeger <cborntra-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
>
> ---
>  drivers/s390/guest/Makefile          |    3 
>  drivers/s390/guest/vnet_port_guest.c |  302 ++++++++++++
>  drivers/s390/guest/vnet_port_guest.h |   21 
>  drivers/s390/guest/vnet_port_host.c  |  418 +++++++++++++++++
>  drivers/s390/guest/vnet_port_host.h  |   18 
>  drivers/s390/guest/vnet_switch.c     |  828 +++++++++++++++++++++++++++++++++++
>  drivers/s390/guest/vnet_switch.h     |  119 +++++
>  drivers/s390/net/Kconfig             |   12 
>  8 files changed, 1721 insertions(+)
>
> Index: linux-2.6.21/drivers/s390/guest/vnet_port_guest.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6.21/drivers/s390/guest/vnet_port_guest.c
> @@ -0,0 +1,302 @@
> +/*
> + *  Copyright (C) 2005 IBM Corporation
> + *  Authors:	Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> + *		Christian Borntraeger <borntrae-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> + *
> + */
> +#include <linux/etherdevice.h>
> +#include <linux/fs.h>
> +#include <linux/kernel.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/pagemap.h>
> +#include <linux/poll.h>
> +#include <linux/spinlock.h>
> +
> +#include "vnet.h"
> +#include "vnet_port_guest.h"
> +#include "vnet_switch.h"
> +
> +static void COFIXME_add_irq(struct vnet_guest_port *zgp, int data)
> +{
> +	int oldval, newval;
> +
> +	do {
> +		oldval = atomic_read(&zgp->pending_irqs);
> +		newval = oldval | data;
> +	} while (atomic_cmpxchg(&zgp->pending_irqs, oldval, newval) != oldval);
> +}
> +
> +static int COFIXME_get_irq(struct vnet_guest_port *zgp)
> +{
> +	int oldval;
> +
> +	do {
> +		oldval = atomic_read(&zgp->pending_irqs);
> +	} while (atomic_cmpxchg(&zgp->pending_irqs, oldval, 0) != oldval);
> +
> +	return oldval;
> +}
> +
> +static void
> +vnet_guest_interrupt(struct vnet_port *port, int type)
> +{
> +	struct vnet_guest_port *priv;
> +
> +	priv = port->priv;
> +
> +	if (!priv->fasync) {
> +		printk (KERN_WARNING "vnet: cannot send interrupt,"
> +			"fd not async\n");
> +		return;
> +	}
> +	switch (type) {
> +	case VNET_IRQ_START_RX:
> +		COFIXME_add_irq(priv, POLLIN);
> +		kill_fasync(&priv->fasync, SIGIO, POLL_IN);
> +		break;
> +	case VNET_IRQ_START_TX:
> +		COFIXME_add_irq(priv, POLLOUT);
> +		kill_fasync(&priv->fasync, SIGIO, POLL_OUT);
> +		break;
> +	default:
> +		BUG();
> +	}
> +}
> +
> +/* release all pinned user pages*/
> +static void
> +vnet_guest_release_pages(struct vnet_port *port)
> +{
> +	int i,j;
> +
> +	for (i=0; i<VNET_QUEUE_LEN; i++)
> +		for (j=0; j<VNET_BUFFER_PAGES; j++) {
> +			if (port->s2p_data[i][j]) {
> +				page_cache_release(virt_to_page(port->s2p_data[i][j]));
> +				port->s2p_data[i][j] = NULL;
> +			}
> +			if (port->p2s_data[i][j]) {
> +				page_cache_release(virt_to_page(port->p2s_data[i][j]));
> +				port->p2s_data[i][j] = NULL;
> +			}
> +	}
> +	if (port->control) {
> +		page_cache_release(virt_to_page(port->control));
> +		port->control = NULL;
> +	}
> +}
> +
> +static int
> +vnet_chr_open(struct inode *ino, struct file *filp)
> +{
> +	int minor;
> +	struct vnet_port *port;
> +	char name[BUS_ID_SIZE];
> +
> +	minor = iminor(filp->f_dentry->d_inode);
> +	snprintf(name, BUS_ID_SIZE, "guest:%d", current->pid);
> +	port = vnet_port_get(minor, name);
> +	if (!port)
> +		return -ENODEV;
> +	port->priv = kzalloc(sizeof(struct vnet_guest_port), GFP_KERNEL);
> +	if (!port->priv) {
> +		vnet_port_put(port);
> +		return -ENOMEM;
> +	}
> +	port->interrupt = vnet_guest_interrupt;
> +	filp->private_data = port;
> +	return nonseekable_open(ino, filp);
> +}
> +
> +static int
> +vnet_chr_release (struct inode *ino, struct file *filp)
> +{
> +	struct vnet_port *port;
> +	port  = (struct vnet_port *) filp->private_data;
> +
> +//FIXME: what about open close? We unregister non exisiting mac addresses
> +// in vnet_port_detach!
> +	vnet_port_detach(port);
> +	vnet_guest_release_pages(port);
> +	vnet_port_put(port);
> +	return 0;
> +}
> +
> +
> +/* helper function which maps a user page into the kernel
> + * the memory must be free with page_cache_release */
> +static void *user_to_kernel(char __user *user)
> +{
> +	struct page *temp_page;
> +	int rc;
> +
> +	BUG_ON(((unsigned long) user) % PAGE_SIZE);
> +	rc = fault_in_pages_writeable(user, PAGE_SIZE);
> +	if (rc)
> +		return NULL;
> +	rc = get_user_pages(current, current->mm, (unsigned long) user,
> +				1, 1, 1, &temp_page, NULL);
> +	if (rc != 1)
> +		return NULL;
> +	return page_address(temp_page);
> +}
> +
> +/* this function pins the userspace buffers into memory*/
> +static int
> +vnet_guest_alloc_pages(struct vnet_port *port)
> +{
> +	int i,j;
> +
> +	down_read(&current->mm->mmap_sem);
> +	for (i=0; i<VNET_QUEUE_LEN; i++)
> +		for (j=0; j<VNET_BUFFER_PAGES; j++) {
> +			port->s2p_data[i][j] = user_to_kernel(port->control->
> +					s2pbufs[i].data + j*PAGE_SIZE);
> +			if (!port->s2p_data[i][j])
> +				goto cleanup;
> +			port->p2s_data[i][j] = user_to_kernel(port->control->
> +					p2sbufs[i].data + j*PAGE_SIZE);
> +			if (!port->p2s_data[i][j])
> +				goto cleanup;
> +
> +		}
> +	up_read(&current->mm->mmap_sem);
> +	return 0;
> +cleanup:
> +	up_read(&current->mm->mmap_sem);
> +	vnet_guest_release_pages(port);
> +	return -ENOMEM;
> +}
> +
> +/* userspace control data structure stuff */
> +static int
> +vnet_register_control(struct vnet_port *port, unsigned long user_addr)
> +{
> +	u64 uaddr;
> +	int rc;
> +	struct  page *control_page;
> +
> +	rc = copy_from_user(&uaddr, (void __user *) user_addr, sizeof(uaddr));
> +	if (rc)
> +		return -EFAULT;
> +	if (uaddr % PAGE_SIZE)
> +		return -EFAULT;
> +	down_read(&current->mm->mmap_sem);
> +	rc = get_user_pages(current, current->mm, (unsigned long)uaddr,
> +			    1, 1, 1, &control_page, NULL);
> +	up_read(&current->mm->mmap_sem);
> +	if (rc!=1)
> +		return -EFAULT;
> +	port->control = (struct vnet_control *) page_address(control_page);
> +	rc = vnet_guest_alloc_pages(port);
> +	if (rc) {
> +		printk("vnet: could not get buffers\n");
> +		return rc;
> +	}
> +	random_ether_addr(port->mac);
> +	memcpy(port->control->mac, port->mac,6);
> +	vnet_port_attach(port);
> +	return 0;
> +}
> +
> +static int
> +vnet_interrupt(struct vnet_port *port, int __user *u_type)
> +{
> +	int type, rc;
> +
> +	rc = copy_from_user (&type, u_type, sizeof(int));
> +	if (rc)
> +		return -EFAULT;
> +	switch (type) {
> +	case VNET_IRQ_START_RX:
> +		vnet_port_rx(port);
> +		break;
> +	case VNET_IRQ_START_TX: /* noop with current drop packet approach*/
> +		break;
> +	default:
> +		printk(KERN_ERR "vnet: Unknown interrupt type %d\n", type);
> +		rc = -EINVAL;
> +	}
> +	return rc;
> +}
> +
> +
> +
> +
> +//this is a HACK. >>COFIXME<<
> +unsigned int
> +vnet_poll(struct file *filp, poll_table * wait)
> +{
> +	struct vnet_port *port;
> +	struct vnet_guest_port *zgp;
> +
> +	port = filp->private_data;
> +	zgp = port->priv;
> +	return COFIXME_get_irq(zgp);
> +}
> +
> +static int vnet_fill_info(struct vnet_port *zp, void __user *data)
> +{
> +	struct vnet_info info;
> +
> +	info.linktype = zp->zs->linktype;
> +	info.maxmtu=32768; //FIXME
> +	return copy_to_user(data, &info, sizeof(info));
> +}
> +long
> +vnet_ioctl(struct file *filp, unsigned int no, unsigned long data)
> +{
> +	struct vnet_port *port =
> +		(struct vnet_port *) filp->private_data;
> +	int rc;
> +
> +	switch (no) {
> +	case VNET_REGISTER_CTL:
> +		rc = vnet_register_control(port, data);
> +		break;
> +	case VNET_INTERRUPT:
> +		rc = vnet_interrupt(port, (int __user *) data);
> +		break;
> +	case VNET_INFO:
> +		rc = vnet_fill_info(port, (void __user *) data);
> +		break;
> +	default:
> +		rc = -ENOTTY;
> +	}
> +	return rc;
> +}
> +
> +int vnet_fasync(int fd, struct file *filp, int on)
> +{
> +	struct vnet_port *port;
> +	struct vnet_guest_port *zgp;
> +	int rc;
> +
> +	port = filp->private_data;
> +	zgp = port->priv;
> +
> +	if ((rc = fasync_helper(fd, filp, on, &zgp->fasync)) < 0)
> +		return rc;
> +
> +	if (on)
> +		rc = f_setown(filp, current->pid, 0);
> +	return rc;
> +}
> +
> +
> +static struct file_operations vnet_char_fops = {
> +	.owner          = THIS_MODULE,
> +	.open           = vnet_chr_open,
> +	.release        = vnet_chr_release,
> +	.unlocked_ioctl = vnet_ioctl,
> +	.fasync         = vnet_fasync,
> +	.poll           = vnet_poll,
> +};
> +
> +
> +
> +void vnet_cdev_init(struct cdev *cdev)
> +{
> +	cdev_init(cdev, &vnet_char_fops);
> +}
> Index: linux-2.6.21/drivers/s390/guest/vnet_port_guest.h
> ===================================================================
> --- /dev/null
> +++ linux-2.6.21/drivers/s390/guest/vnet_port_guest.h
> @@ -0,0 +1,21 @@
> +/*
> + *  Copyright (C) 2005 IBM Corporation
> + *  Authors:	Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> + *		Christian Borntraeger <cborntra-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> + *
> + */
> +
> +#ifndef __VNET_PORTS_GUEST_H
> +#define __VNET_PORTS_GUEST_H
> +
> +#include <linux/fs.h>
> +#include <linux/cdev.h>
> +#include <asm/atomic.h>
> +
> +struct vnet_guest_port {
> +	struct fasync_struct *fasync;
> +	atomic_t pending_irqs;
> +};
> +
> +extern void vnet_cdev_init(struct cdev *cdev);
> +#endif
> Index: linux-2.6.21/drivers/s390/guest/vnet_port_host.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6.21/drivers/s390/guest/vnet_port_host.c
> @@ -0,0 +1,418 @@
> +/*
> + *  vnet zlswitch handling
> + *
> + *  Copyright (C) 2005 IBM Corporation
> + *  Authors:	Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> + *		Christian Borntraeger <borntrae-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> + *
> + */
> +
> +#include <linux/etherdevice.h>
> +#include <linux/if.h>
> +#include <linux/if_ether.h>
> +#include <linux/if_arp.h>
> +#include <linux/kernel.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/rtnetlink.h>
> +#include <linux/pagemap.h>
> +#include <linux/spinlock.h>
> +
> +#include "vnet.h"
> +#include "vnet_switch.h"
> +#include "vnet_port_host.h"
> +
> +static void
> +vnet_host_interrupt(struct vnet_port *zp,  int type)
> +{
> +	struct vnet_host_port *zhp;
> +
> +	zhp = zp->priv;
> +
> +	BUG_ON(!zhp->netdev);
> +
> +	switch (type) {
> +	case VNET_IRQ_START_RX:
> +		netif_rx_schedule(zhp->netdev);
> +		break;
> +	case VNET_IRQ_START_TX:
> +		netif_wake_queue(zhp->netdev);
> +		break;
> +	default:
> +		BUG();
> +	}
> +	/* we are called via system call path. enforce softirq handling */
> +	do_softirq();
> +}
> +
> +static void
> +vnet_host_free(struct vnet_port *zp)
> +{
> +	int i,j;
> +
> +	for (i=0; i<VNET_QUEUE_LEN; i++)
> +		for (j=0; j<VNET_BUFFER_PAGES; j++) {
> +			if (zp->s2p_data[i][j]) {
> +				free_page((unsigned long) zp->s2p_data[i][j]);
> +				zp->s2p_data[i][j] = NULL;
> +			}
> +			if (zp->p2s_data[i][j]) {
> +				free_page((unsigned long) zp->p2s_data[i][j]);
> +				zp->p2s_data[i][j] = NULL;
> +			}
> +	}
> +	if (zp->control) {
> +		kfree(zp->control);
> +		zp->control = NULL;
> +	}
> +}
> +
> +static int
> +vnet_port_hostsetup(struct vnet_port *zp)
> +{
> +	int i,j;
> +
> +	zp->control = kzalloc(sizeof(*zp->control), GFP_KERNEL);
> +	if (!zp->control)
> +		return -ENOMEM;
> +	for (i=0; i<VNET_QUEUE_LEN; i++)
> +		for (j=0; j<VNET_BUFFER_PAGES; j++) {
> +			zp->s2p_data[i][j] = (void *) __get_free_pages(GFP_KERNEL,0);
> +			if (!zp->s2p_data[i][j])
> +				goto oom;
> +			zp->p2s_data[i][j] = (void *) __get_free_pages(GFP_KERNEL,0);
> +			if (!zp->p2s_data[i][j]) {
> +				free_page((unsigned long) zp->s2p_data[i][j]);
> +				goto oom;
> +			}
> +		}
> +	zp->control->buffer_size = VNET_BUFFER_SIZE;
> +	return 0;
> +oom:
> +	printk(KERN_WARNING "vnet: No memory for buffer space of host device\n");
> +	vnet_host_free(zp);
> +	return -ENOMEM;
> +}
> +
> +/* host interface specific parts */
> +
> +
> +static int
> +vnet_net_open(struct net_device *dev)
> +{
> +	struct vnet_port *port;
> +	struct vnet_control *control;
> +
> +	port = dev->priv;
> +	control = port->control;
> +	atomic_set(&control->s2pmit, 0);
> +	netif_start_queue(dev);
> +	return 0;
> +}
> +
> +static int
> +vnet_net_stop(struct net_device *dev)
> +{
> +	netif_stop_queue(dev);
> +	return 0;
> +}
> +
> +static void vnet_net_tx_timeout(struct net_device *dev)
> +{
> +	struct vnet_port *port = dev->priv;
> +	struct vnet_control *control = port->control;
> +
> +	printk(KERN_ERR "problems in xmit for device %s\n Resetting...\n",
> +			 dev->name);
> +	atomic_set(&control->p2smit, 0);
> +	atomic_set(&control->s2pmit, 0);
> +	vnet_port_rx(port);
> +	netif_wake_queue(dev);
> +}
> +
> +
> +static int
> +vnet_net_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> +	struct vnet_port  *zhost;
> +	struct vnet_host_port *zhp;
> +	struct vnet_control *control;
> +	struct xmit_buffer *buf;
> +	int buffer_status;
> +	int pkid;
> +
> +	zhost = dev->priv;
> +	zhp = zhost->priv;
> +	control = zhost->control;
> +
> +	if (!spin_trylock(&zhost->txlock))
> +		return NETDEV_TX_LOCKED;
> +	if (vnet_q_full(atomic_read(&control->p2smit))) {
> +		netif_stop_queue(dev);
> +		goto full;
> +	}
> +	pkid = __nextx(atomic_read(&control->p2smit));
> +	buf = &control->p2sbufs[pkid];
> +	buf->len = skb->len;
> +	buf->proto = skb->protocol;
> +	vnet_copy_buf_to_pages(zhost->p2s_data[pkid], skb->data, skb->len);
> +	buffer_status = vnet_tx_packet(&control->p2smit);
> +	spin_unlock(&zhost->txlock);
> +	zhp->stats.tx_packets++;
> +	zhp->stats.tx_bytes += skb->len;
> +	dev_kfree_skb(skb);
> +	dev->trans_start = jiffies;
> +	if (buffer_status & QUEUE_WAS_EMPTY)
> +		vnet_port_rx(zhost);
> +	if (buffer_status & QUEUE_IS_FULL) {
> +		netif_stop_queue(dev);
> +		spin_lock(&zhost->txlock);
> +	} else
> +		return NETDEV_TX_OK;
> +full:
> +	/* we might have raced against the wakeup */
> +	if (!vnet_q_full(atomic_read(&control->p2smit)))
> +		netif_start_queue(dev);
> +	spin_unlock(&zhost->txlock);
> +	return NETDEV_TX_OK;
> +}
> +
> +static int
> +vnet_l3_poll(struct net_device *dev, int *budget)
> +{
> +	struct vnet_port  *zp = dev->priv;
> +	struct vnet_host_port *zhp = zp->priv;
> +	struct vnet_control *control = zp->control;
> +	struct xmit_buffer *buf;
> +	struct sk_buff *skb;
> +	int pkid, count, numpackets = min(64, min(dev->quota, *budget));
> +	int buffer_status;
> +
> +	if (vnet_q_empty(atomic_read(&control->s2pmit))) {
> +		count = 0;
> +		goto empty;
> +	}
> +loop:
> +	count = 0;
> +	while(numpackets) {
> +		pkid = __nextr(atomic_read(&control->s2pmit));
> +		buf = &control->s2pbufs[pkid];
> +		skb = dev_alloc_skb(buf->len + 2);
> +		if (likely(skb)) {
> +			skb_reserve(skb, 2);
> +			vnet_copy_pages_to_buf(skb_put(skb, buf->len),
> +						zp->s2p_data[pkid], buf->len);
> +			skb->dev = dev;
> +			skb->protocol = buf->proto;
> +//			skb->ip_summed = CHECKSUM_UNNECESSARY;
> +			zhp->stats.rx_packets++;
> +			zhp->stats.rx_bytes += buf->len;
> +			netif_receive_skb(skb);
> +			numpackets--;
> +			(*budget)--;
> +			dev->quota--;
> +			count++;
> +		} else
> +			zhp->stats.rx_dropped++;
> +		buffer_status = vnet_rx_packet(&control->s2pmit);
> +		if (buffer_status & QUEUE_IS_EMPTY)
> +			goto empty;
> +	}
> +	return 1; //please ask us again
> +empty:
> +	netif_rx_complete(dev);
> +	/* we might have raced against a wakup*/
> +	if (!vnet_q_empty(atomic_read(&control->s2pmit))) {
> +		if (netif_rx_reschedule(dev, count))
> +			goto loop;
> +	}
> +	return 0;
> +}
> +
> +
> +static int
> +vnet_l2_poll(struct net_device *dev, int *budget)
> +{
> +	struct vnet_port  *zp = dev->priv;
> +	struct vnet_host_port *zhp = zp->priv;
> +	struct vnet_control *control = zp->control;
> +	struct xmit_buffer *buf;
> +	struct sk_buff *skb;
> +	int pkid, count, numpackets = min(64, min(dev->quota, *budget));
> +	int buffer_status;
> +
> +	if (vnet_q_empty(atomic_read(&control->s2pmit))) {
> +		count = 0;
> +		goto empty;
> +	}
> +loop:
> +	count = 0;
> +	while(numpackets) {
> +		pkid = __nextr(atomic_read(&control->s2pmit));
> +		buf = &control->s2pbufs[pkid];
> +		skb = dev_alloc_skb(buf->len + 2);
> +		if (likely(skb)) {
> +			skb_reserve(skb, 2);
> +			vnet_copy_pages_to_buf(skb_put(skb, buf->len),
> +						zp->s2p_data[pkid], buf->len);
> +			skb->dev = dev;
> +			skb->protocol = eth_type_trans(skb, dev);
> +//			skb->ip_summed = CHECKSUM_UNNECESSARY;
> +			zhp->stats.rx_packets++;
> +			zhp->stats.rx_bytes += buf->len;
> +			netif_receive_skb(skb);
> +			numpackets--;
> +			(*budget)--;
> +			dev->quota--;
> +			count++;
> +		} else
> +			zhp->stats.rx_dropped++;
> +		buffer_status = vnet_rx_packet(&control->s2pmit);
> +		if (buffer_status & QUEUE_IS_EMPTY)
> +			goto empty;
> +	}
> +	return 1; //please ask us again
> +empty:
> +	netif_rx_complete(dev);
> +	/* we might have raced against a wakup*/
> +	if (!vnet_q_empty(atomic_read(&control->s2pmit))) {
> +		if (netif_rx_reschedule(dev, count))
> +			goto loop;
> +	}
> +	return 0;
> +}
> +
> +static struct net_device_stats *
> +vnet_net_stats(struct net_device *dev)
> +{
> +	struct vnet_port  *zp;
> +	struct vnet_host_port  *zhp;
> +
> +	zp = dev->priv;
> +	zhp = zp->priv;
> +	return &zhp->stats;
> +}
> +
> +static int
> +vnet_net_change_mtu(struct net_device *dev, int new_mtu)
> +{
> +	if (new_mtu <= ETH_ZLEN)
> +		return -ERANGE;
> +	if (new_mtu > VNET_BUFFER_SIZE-ETH_HLEN)
> +		return -ERANGE;
> +	dev->mtu = new_mtu;
> +	return 0;
> +}
> +
> +static void
> +__vnet_common_init(struct net_device *dev)
> +{
> +	dev->open		= vnet_net_open;
> +	dev->stop		= vnet_net_stop;
> +	dev->hard_start_xmit	= vnet_net_xmit;
> +	dev->get_stats		= vnet_net_stats;
> +	dev->tx_timeout		= vnet_net_tx_timeout;
> +	dev->watchdog_timeo	= VNET_TIMEOUT;
> +	dev->change_mtu		= vnet_net_change_mtu;
> +	dev->weight		= 64;
> +	//dev->features		|= NETIF_F_NO_CSUM | NETIF_F_LLTX;
> +	dev->features		|= NETIF_F_LLTX;
> +}
> +
> +static void
> +__vnet_layer3_init(struct net_device *dev)
> +{
> +        dev->mtu		= ETH_DATA_LEN;
> +        dev->tx_queue_len	= 1000;
> +        dev->flags		= IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP;
> +        dev->type		= ARPHRD_PPP;
> +	dev->mtu		= 1492;
> +	dev->poll		= vnet_l3_poll;
> +	__vnet_common_init(dev);
> +}
> +
> +static void
> +__vnet_layer2_init(struct net_device *dev)
> +{
> +	ether_setup(dev);
> +	random_ether_addr(dev->dev_addr);
> +	dev->mtu	= 1492;
> +	dev->poll	= vnet_l2_poll;
> +	__vnet_common_init(dev);
> +}
> +
> +static void
> +vnet_host_destroy(struct vnet_port  *zhost)
> +{
> +	struct vnet_host_port *zhp;
> +	zhp = zhost->priv;
> +
> +	vnet_port_detach(zhost);
> +	unregister_netdev(zhp->netdev);
> +	free_netdev(zhp->netdev);
> +	zhp->netdev = NULL;
> +	vnet_host_free(zhost);
> +	kfree(zhp);
> +	vnet_port_put(zhost);
> +}
> +
> +
> +
> +struct vnet_port *
> +vnet_host_create(char *name)
> +{
> +	int rc;
> +	struct vnet_port *port;
> +	struct vnet_host_port *host;
> +	char busname[BUS_ID_SIZE];
> +	int minor;
> +
> +	snprintf(busname, BUS_ID_SIZE, "host:%s", name);
> +
> +	minor = vnet_minor_by_name(name);
> +	if (minor < 0)
> +		return NULL;
> +	port = vnet_port_get(minor, busname);
> +	if (!port)
> +		goto out;
> +	host = kzalloc(sizeof(struct vnet_host_port), GFP_KERNEL);
> +	if (!host) {
> +		kfree(port);
> +		port = NULL;
> +		goto out;
> +	}
> +	port->priv = host;
> +	rc =vnet_port_hostsetup(port);
> +	if (rc)
> +		goto out_free_host;
> +	rtnl_lock();
> +	if (port->zs->linktype == 2)
> +		host->netdev = alloc_netdev(0, name, __vnet_layer2_init);
> +	else
> +		host->netdev = alloc_netdev(0, name, __vnet_layer3_init);
> +	if (!host->netdev)
> +		goto out_unlock;
> +	memcpy(port->mac, host->netdev->dev_addr, ETH_ALEN);
> +
> +	host->netdev->priv = port;
> +	port->interrupt = vnet_host_interrupt;
> +	port->destroy = vnet_host_destroy;
> +
> +	if (!register_netdevice(host->netdev)) {
> +		/* good case */
> +		rtnl_unlock();
> +		return port;
> +	}
> +	host->netdev->priv = NULL;
> +	free_netdev(host->netdev);
> +	host->netdev = NULL;
> +out_unlock:
> +	rtnl_unlock();
> +	vnet_host_free(port);
> +out_free_host:
> +	vnet_port_put(port);
> +	port = NULL;
> +out:
> +	return port;
> +}
> Index: linux-2.6.21/drivers/s390/guest/vnet_port_host.h
> ===================================================================
> --- /dev/null
> +++ linux-2.6.21/drivers/s390/guest/vnet_port_host.h
> @@ -0,0 +1,18 @@
> +/*
> + *  Copyright (C) 2005 IBM Corporation
> + *          Christian Borntraeger <cborntra-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> + *
> + */
> +
> +#ifndef __VNET_PORTS_HOST_H
> +#define __VNET_PORTS_HOST_H
> +
> +#include <linux/netdevice.h>
> +#include "vnet_switch.h"
> +
> +struct vnet_host_port {
> +	struct net_device_stats stats;
> +	struct net_device *netdev;
> +};
> +extern struct vnet_port * vnet_host_create(char *name);
> +#endif
> Index: linux-2.6.21/drivers/s390/guest/vnet_switch.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6.21/drivers/s390/guest/vnet_switch.c
> @@ -0,0 +1,828 @@
> +/*
> + *  vnet zlswitch handling
> + *
> + *  Copyright (C) 2005 IBM Corporation
> + *  Author: Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> + *  Author: Christian Borntraeger <borntrae-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> + *
> + */
> +
> +#include <linux/device.h>
> +#include <linux/etherdevice.h>
> +#include <linux/fs.h>
> +#include <linux/if.h>
> +#include <linux/if_ether.h>
> +#include <linux/kernel.h>
> +#include <linux/list.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/rtnetlink.h>
> +#include <linux/pagemap.h>
> +#include <linux/spinlock.h>
> +
> +#include "vnet.h"
> +#include "vnet_port_guest.h"
> +#include "vnet_port_host.h"
> +#include "vnet_switch.h"
> +
> +#define NUM_MINORS 1024
> +
> +/* devices housekeeping, creation & destruction */
> +static LIST_HEAD(vnet_switches);
> +static rwlock_t vnet_switches_lock = RW_LOCK_UNLOCKED;
> +static struct class *zwitch_class;
> +static int vnet_major;
> +static struct device *root_dev;
> +
> +
> +/* The following functions allow ports of the switch to know about
> + * the MAC addresses of other ports. This is necessary for special
> + * hardware like OSA express which silently drops incoming packets
> + * that not match known MAC addresses and do not support promiscous
> + * mode as well. We have to register all guest MAC addresses at OSA
> + * make packet receive working */
> +
> +/* Announces the own MAC address to all other ports
> + * this function is called if a new port is added */
> +static void vnet_switch_add_mac(struct vnet_port *port)
> +{
> +	struct vnet_port *other_port;
> +
> +	read_lock(&port->zs->ports_lock);
> +	list_for_each_entry(other_port, &port->zs->switch_ports, lh)
> +		if ((other_port != port) && (other_port->set_mac))
> +			other_port->set_mac(other_port,port->mac, 1);
> +	read_unlock(&port->zs->ports_lock);
> +}
> +
> +/* Removes the own MAC address from all other ports
> + * this function is called if a port is detached*/
> +static void vnet_switch_del_mac(struct vnet_port *port)
> +{
> +	struct vnet_port *other_port;
> +
> +	read_lock(&port->zs->ports_lock);
> +	list_for_each_entry(other_port, &port->zs->switch_ports, lh)
> +		if (other_port->set_mac)
> +			other_port->set_mac(other_port, port->mac, 0);
> +	read_unlock(&port->zs->ports_lock);
> +}
> +
> +/* Learn MACs from other ports on the same zwitch and forward
> + * the MAC addresses to the set_mac function of the port.*/
> +static void __vnet_port_learn_macs(struct vnet_port *port)
> +{
> +	struct vnet_port *other_port;
> +
> +	if (!port->set_mac)
> +		return;
> +	list_for_each_entry(other_port, &port->zs->switch_ports, lh)
> +		if (other_port != port)
> +			port->set_mac(port, other_port->mac, 1);
> +}
> +
> +/* Unlearn MACS from other ports on the same zwitch */
> +static void __vnet_port_unlearn_macs(struct vnet_port *port)
> +{
> +	struct vnet_port *other_port;
> +
> +	if (!port->set_mac)
> +		return;
> +	list_for_each_entry(other_port, &port->zs->switch_ports, lh)
> +		if (other_port != port)
> +			port->set_mac(port, other_port->mac, 0);
> +}
> +
> +
> +static struct vnet_switch *__vnet_switch_by_minor(int minor)
> +{
> +	struct vnet_switch *zs;
> +
> +	list_for_each_entry(zs, &vnet_switches, lh) {
> +		if (MINOR(zs->cdev.dev) == minor)
> +			return zs;
> +	}
> +	return NULL;
> +}
> +
> +static struct vnet_switch *__vnet_switch_by_name(char *name)
> +{
> +	struct vnet_switch *zs;
> +
> +	list_for_each_entry(zs, &vnet_switches, lh)
> +		if (strncmp(zs->name, name, ZWITCH_NAME_SIZE) == 0)
> +			return zs;
> +	return NULL;
> +}
> +
> +/* Returns a switch structure and increases the reference count. If no such
> + * switch exists a new one is created with reference count 1 */
> +static struct vnet_switch *zwitch_get(int minor)
> +{
> +	struct vnet_switch *zs;
> +
> +	read_lock(&vnet_switches_lock);
> +	zs = __vnet_switch_by_minor(minor);
> +	if (!zs) {
> +			read_unlock(&vnet_switches_lock);
> +			return zs;
> +	}
> +	get_device(&zs->dev);
> +	read_unlock(&vnet_switches_lock);
> +	return zs;
> +}
> +
> +/* reduces the reference count of the switch. */
> +static void zwitch_put(struct vnet_switch * zs)
> +{
> +	put_device(&zs->dev);
> +}
> +
> +/* looks into the packet and searches a matching MAC address
> + * return NULL if unknown or broadcast */
> +static struct vnet_port *__vnet_find_l2(struct vnet_switch *zs, char *data)
> +{
> +	//FIXME: make this a hash lookup, more macs per device?
> +	struct vnet_port *port;
> +
> +	if (is_multicast_ether_addr(data))
> +		return NULL;
> +	list_for_each_entry(port, &zs->switch_ports, lh) {
> +		if (compare_ether_addr(port->mac, data)==0)
> +			goto out;
> +	}
> +	port = NULL;
> + out:
> +	return port;
> +}
> +
> +/* searches the destination for IP only interfaces. Normally routing
> + * is the way to go, but guests should see the net transparently without
> + * a hop in between*/
> +static struct vnet_port *__vnet_find_l3(struct vnet_switch *zs, char *data)
> +{
> +	return NULL;
> +}
> +
> +static struct vnet_port * __vnet_find_destination(struct vnet_switch *zs,
> +								char *data)
> +{
> +	switch (zs->linktype) {
> +	case 2:
> +		return __vnet_find_l2(zs, data);
> +	case 3:
> +		return __vnet_find_l3(zs, data);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +/* copies len bytes of data from the memory specified by the list of
> + * pointers **from into the memory specified by the list of pointers **to
> + * with each pointer pointing to a page */
> +static void
> +vnet_switch_page_copy(void **to, void **from, int len)
> +{
> +	int remaining=len;
> +	int pageid = 0;
> +	int amount;
> +
> +	while(remaining) {
> +		amount = min((int)PAGE_SIZE, remaining);
> +		memcpy(to[pageid], from[pageid], amount);
> +		pageid++;
> +		remaining -= amount;
> +	}
> +}
> +
> +/* copies to data into a buffer of destination
> + * returns 0 if ok*/
> +static int
> +vnet_unicast(struct vnet_port *destination, void **from_data, int len, int proto)
> +{
> +	int pkid;
> +	int buffer_status;
> +	void  **to_data;
> +	struct vnet_control *control;
> +
> +	control = destination->control;
> +	spin_lock_bh(&destination->rxlock);
> +	if (vnet_q_full(atomic_read(&control->s2pmit))) {
> +		destination->rx_dropped++;
> +		spin_unlock_bh(&destination->rxlock);
> +		return -ENOBUFS;
> +	}
> +	pkid = __nextx(atomic_read(&control->s2pmit));
> +	to_data = destination->s2p_data[pkid];
> +	vnet_switch_page_copy(to_data, from_data, len);
> +	control->s2pbufs[pkid].len = len;
> +	control->s2pbufs[pkid].proto = proto;
> +	buffer_status = vnet_tx_packet(&control->s2pmit);
> +	spin_unlock_bh(&destination->rxlock);
> +	if (buffer_status & QUEUE_WAS_EMPTY)
> +		destination->interrupt(destination, VNET_IRQ_START_RX);
> +	destination->rx_bytes += len;
> +	destination->rx_packets++;
> +	return 0;
> +}
> +
> +/* send packets to all ports and emulate broadcasts via unicasts*/
> +static int vnet_allcast(struct vnet_port *from_port, void **fromdata,
> +			int len, int proto)
> +{
> +	struct vnet_port *destination;
> +	int failure = 0;
> +
> +	list_for_each_entry(destination, &from_port->zs->switch_ports, lh)
> +		if (destination != from_port)
> +			failure |= vnet_unicast(destination, fromdata,
> +							len, proto);
> +	return failure;
> +}
> +
> +/* takes an incoming packet and forwards it to the right port
> + * if a failure occurs, increase the tx_dropped count of the sender*/
> +static void vnet_switch_packet(struct vnet_port *from_port,
> +				void **from_data, int len, int proto)
> +{
> +	struct vnet_port *destination;
> +	int failure;
> +
> +	read_lock(&from_port->zs->ports_lock);
> +	destination = __vnet_find_destination(from_port->zs, from_data[0]);
> +	/* we dont want to loop. FIXME: document when this can happen*/
> +	if (destination == from_port) {
> +		read_unlock(&from_port->zs->ports_lock);
> +		return;
> +	}
> +	if (destination)
> +		failure = vnet_unicast(destination, from_data, len, proto);
> +	else
> +		failure = vnet_allcast(from_port, from_data, len, proto);
> +	read_unlock(&from_port->zs->ports_lock);
> +	if (failure)
> +		from_port->tx_dropped++;
> +	else {
> +		from_port->tx_packets++;
> +		from_port->tx_bytes += len;
> +	}
> +}
> +
> +static void vnet_port_release(struct device *dev)
> +{
> +	struct vnet_port *port;
> +
> +	port = container_of(dev, struct vnet_port, dev);
> +	zwitch_put(port->zs);
> +	kfree(port);
> +}
> +
> +static ssize_t vnet_port_read_mac(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf)
> +{
> +	struct vnet_port *port;
> +
> +	port = container_of(dev, struct vnet_port, dev);
> +	return sprintf(buf,"%02X:%02X:%02X:%02X:%02X:%02X", port->mac[0],
> +				port->mac[1], port->mac[2], port->mac[3],
> +				port->mac[4], port->mac[5]);
> +}
> +
> +static ssize_t vnet_port_read_tx_bytes(struct device *dev,
> +					struct device_attribute *attr,
> +					char *buf)
> +{
> +	struct vnet_port *port;
> +
> +	port = container_of(dev, struct vnet_port, dev);
> +	return sprintf(buf,"%lu", port->tx_bytes);
> +}
> +
> +static ssize_t vnet_port_read_rx_bytes(struct device *dev,
> +					struct device_attribute *attr,
> +					char *buf)
> +{
> +	struct vnet_port *port;
> +
> +	port = container_of(dev, struct vnet_port, dev);
> +	return sprintf(buf,"%lu", port->rx_bytes);
> +}
> +
> +static ssize_t vnet_port_read_tx_packets(struct device *dev,
> +					struct device_attribute *attr,
> +					char *buf)
> +{
> +	struct vnet_port *port;
> +
> +	port = container_of(dev, struct vnet_port, dev);
> +	return sprintf(buf,"%lu", port->tx_packets);
> +}
> +
> +static ssize_t vnet_port_read_rx_packets(struct device *dev,
> +					struct device_attribute *attr,
> +					char *buf)
> +{
> +	struct vnet_port *port;
> +
> +	port = container_of(dev, struct vnet_port, dev);
> +	return sprintf(buf,"%lu", port->rx_packets);
> +}
> +
> +static ssize_t vnet_port_read_tx_dropped(struct device *dev,
> +					struct device_attribute *attr,
> +					char *buf)
> +{
> +	struct vnet_port *port;
> +
> +	port = container_of(dev, struct vnet_port, dev);
> +	return sprintf(buf,"%lu", port->tx_dropped);
> +}
> +
> +static ssize_t vnet_port_read_rx_dropped(struct device *dev,
> +					struct device_attribute *attr,
> +					char *buf)
> +{
> +	struct vnet_port *port;
> +
> +	port = container_of(dev, struct vnet_port, dev);
> +	return sprintf(buf,"%lu", port->rx_dropped);
> +}
> +
> +static DEVICE_ATTR(mac, S_IRUSR, vnet_port_read_mac, NULL);
> +static DEVICE_ATTR(tx_bytes, S_IRUSR, vnet_port_read_tx_bytes, NULL);
> +static DEVICE_ATTR(rx_bytes, S_IRUSR, vnet_port_read_rx_bytes, NULL);
> +static DEVICE_ATTR(tx_packets, S_IRUSR, vnet_port_read_tx_packets, NULL);
> +static DEVICE_ATTR(rx_packets, S_IRUSR, vnet_port_read_rx_packets, NULL);
> +static DEVICE_ATTR(tx_dropped, S_IRUSR, vnet_port_read_tx_dropped, NULL);
> +static DEVICE_ATTR(rx_dropped, S_IRUSR, vnet_port_read_rx_dropped, NULL);
> +
> +static int vnet_port_attributes(struct device *dev)
> +{
> +	int rc;
> +	rc = device_create_file(dev, &dev_attr_mac);
> +	if (rc)
> +		return rc;
> +	rc = device_create_file(dev, &dev_attr_tx_dropped);
> +	if (rc)
> +		return rc;
> +	rc = device_create_file(dev, &dev_attr_rx_dropped);
> +	if (rc)
> +		return rc;
> +	rc = device_create_file(dev, &dev_attr_rx_bytes);
> +	if (rc)
> +		return rc;
> +	rc = device_create_file(dev, &dev_attr_tx_bytes);
> +	if (rc)
> +		return rc;
> +	rc = device_create_file(dev, &dev_attr_rx_packets);
> +	if (rc)
> +		return rc;
> +	rc = device_create_file(dev, &dev_attr_tx_packets);
> +	return rc;
> +}
> +
> +
> +//FIXME implement this
> +static int vnet_port_exists(struct vnet_switch *zs, char *name)
> +{
> +	read_lock(&zs->ports_lock);
> +	read_unlock(&zs->ports_lock);
> +	return 0;
> +
> +}
> +
> +static struct vnet_port *vnet_port_create(struct vnet_switch *zs,
> +					char *name)
> +{
> +	struct vnet_port *port;
> +
> +	if (vnet_port_exists(zs, name))
> +		return NULL;
> +
> +	port = kzalloc(sizeof(*port), GFP_KERNEL);
> +	if (port) {
> +		spin_lock_init(&port->rxlock);
> +		spin_lock_init(&port->txlock);
> +		INIT_LIST_HEAD(&port->lh);
> +		port->zs = zs;
> +	} else
> +		return NULL;
> +	port->dev.parent = &zs->dev;
> +	port->dev.release = vnet_port_release;
> +	strncpy(port->dev.bus_id, name, BUS_ID_SIZE);
> +	if (device_register(&port->dev)) {
> +		kfree(port);
> +		return NULL;
> +	}
> +	if (vnet_port_attributes(&port->dev)) {
> +		device_unregister(&port->dev);
> +		kfree(port);
> +		return NULL;
> +	}
> +	return port;
> +}
> +
> +/*------------------------ switch creation/Destruction/housekeeping---------*/
> +
> +static void zwitch_destroy_ports(struct vnet_switch *zs)
> +{
> +	struct vnet_port *port, *tmp;
> +
> +	list_for_each_entry_safe(port, tmp, &zs->switch_ports, lh) {
> +	if (port->destroy)
> +		port->destroy(port);
> +	else
> +		printk("No destroy function for port\n");
> +	}
> +}
> +
> +
> +static void zwitch_destroy(struct vnet_switch *zs)
> +{
> +	class_device_destroy(zwitch_class, zs->cdev.dev);
> +	cdev_del(&zs->cdev);
> +	device_unregister(&zs->dev);
> +}
> +
> +static void zwitch_release(struct device *dev)
> +{
> +	struct vnet_switch *zs;
> +
> +	zs = container_of(dev, struct vnet_switch, dev);
> +	kfree(zs);
> +}
> +
> +static int __zwitch_get_minor(void)
> +{
> +	int d, found;
> +	struct vnet_switch *zs;
> +
> +	for (d=0; d< NUM_MINORS; d++) {
> +		found = 0;
> +		list_for_each_entry(zs, &vnet_switches, lh)
> +			if (MINOR(zs->cdev.dev) == d)
> +				found++;
> +		if (!found) break;
> +	}
> +	if (found) return -ENODEV;
> +	return d;
> +}
> +
> +/*
> + * checks if this name already exists for a zwitch
> + */
> +static int __zwitch_check_name(char *name)
> +{
> +	struct vnet_switch *zs;
> +
> +	list_for_each_entry(zs, &vnet_switches, lh)
> +		if (!strncmp(name, zs->name, ZWITCH_NAME_SIZE))
> +			return -EEXIST;
> +	return 0;
> +}
> +
> +static int zwitch_create(char *name, int linktype)
> +{
> +	struct vnet_switch *zs;
> +	int minor;
> +	int ret;
> +
> +	if ((linktype < 2) || (linktype > 3))
> +		return -EINVAL;
> +	zs = kzalloc(sizeof(*zs), GFP_KERNEL);
> +	if (!zs) {
> +		printk("Creation of %s failed: out of memory\n", name);
> +		return -ENOMEM;
> +	}
> +	zs->linktype = linktype;
> +	strncpy(zs->name, name, ZWITCH_NAME_SIZE);
> +	rwlock_init(&zs->ports_lock);
> +	INIT_LIST_HEAD(&zs->switch_ports);
> +
> +	write_lock(&vnet_switches_lock);
> +	minor = __zwitch_get_minor();
> +	if (minor < 0) {
> +		write_unlock(&vnet_switches_lock);
> +		printk("Creation of %s failed: No free minor number\n",	name);
> +		kfree(zs);
> +		return minor;
> +	}
> +	if (__zwitch_check_name(zs->name)) {
> +		write_unlock(&vnet_switches_lock);
> +		printk("Creation of %s failed: name exists\n", name);
> +		kfree(zs);
> +		return -EEXIST;
> +	}
> +	list_add_tail(&zs->lh, &vnet_switches);
> +	write_unlock(&vnet_switches_lock);
> +	strncpy(zs->dev.bus_id, name, min((int) strlen(name),
> +		ZWITCH_NAME_SIZE));
> +	zs->dev.parent = root_dev;
> +	zs->dev.release = zwitch_release;
> +	ret = device_register(&zs->dev);
> +	if (ret) {
> +		write_lock(&vnet_switches_lock);
> +		list_del(&zs->lh);
> +		write_unlock(&vnet_switches_lock);
> +		printk("Creation of %s failed: no device\n",name);
> +		return ret;
> +	}
> +	vnet_cdev_init(&zs->cdev);
> +	cdev_add(&zs->cdev, MKDEV(vnet_major, minor), 1);
> +	zs->class_device = class_device_create(zwitch_class, NULL,
> +						zs->cdev.dev, &zs->dev, name);
> +	if (IS_ERR(zs->class_device)) {
> +		cdev_del(&zs->cdev);
> +		write_lock(&vnet_switches_lock);
> +		list_del(&zs->lh);
> +		write_unlock(&vnet_switches_lock);
> +		printk("Creation of %s failed: no class_device\n", name);
> +		device_unregister(&zs->dev);
> +		return PTR_ERR(zs->class_device);
> +	}
> +	return 0;
> +}
> +
> +
> +static int zwitch_delete(char *name)
> +{
> +	struct vnet_switch *zs;
> +
> +	write_lock(&vnet_switches_lock);
> +	zs = __vnet_switch_by_name(name);
> +	if (!zs) {
> +		write_unlock(&vnet_switches_lock);
> +		return -ENOENT;
> +	}
> +	list_del(&zs->lh);
> +	write_unlock(&vnet_switches_lock);
> +	zwitch_destroy_ports(zs);
> +	zwitch_destroy(zs);
> +	return 0;
> +}
> +
> +/* checks if a switch for the given minor exists
> + * if yes, create an unconnected  port on this switch
> + * if no, return NULL */
> +struct vnet_port *vnet_port_get(int minor, char *port_name)
> +{
> +	struct vnet_switch *zs;
> +	struct vnet_port *port;
> +
> +	zs = zwitch_get(minor);
> +	if (!zs)
> +		return NULL;
> +	port = vnet_port_create(zs, port_name);
> +	if (!port)
> +		zwitch_put(zs);
> +	return port;
> +}
> +
> +/* attaches the port to the switch. The port must be
> + * fully initialized, as it may get called immediately afterwards */
> +void vnet_port_attach(struct vnet_port *port)
> +{
> +	write_lock_bh(&port->zs->ports_lock);
> +	__vnet_port_learn_macs(port);
> +	list_add(&port->lh, &port->zs->switch_ports);
> +	write_unlock_bh(&port->zs->ports_lock);
> +	vnet_switch_add_mac(port);
> +	return;
> +}
> +
> +/* detaches the port from the switch. After that,
> + * no calls into the port are made */
> +void vnet_port_detach(struct vnet_port *port)
> +{
> +	vnet_switch_del_mac(port);
> +	write_lock_bh(&port->zs->ports_lock);
> +	if (!list_empty(&port->lh))
> +		list_del(&port->lh);
> +	__vnet_port_unlearn_macs(port);
> +	write_unlock_bh(&port->zs->ports_lock);
> +}
> +
> +/* releases all ressources allocated with vnet_port_get */
> +void vnet_port_put(struct vnet_port *port)
> +{
> +	BUG_ON(!list_empty(&port->lh) &&( port->lh.next != LIST_POISON1));
> +	device_unregister(&port->dev);
> +}
> +
> +/* tell the switch that new data is available */
> +void vnet_port_rx(struct vnet_port *port)
> +{
> +	struct vnet_control *control;
> +	int pkid, rc;
> +
> +	control = port->control;
> +	if (vnet_q_empty(atomic_read(&control->p2smit))) {
> +		printk(KERN_WARNING "vnet_switch: Empty buffer"
> +				"on interrupt\n");
> +		return;
> +	}
> +	do {
> +		pkid = __nextr(atomic_read(&control->p2smit));
> +		/* fire and forget. Let the switch care about lost packets*/
> +		vnet_switch_packet(port, port->p2s_data[pkid],
> +					control->p2sbufs[pkid].len,
> +					control->p2sbufs[pkid].proto);
> +		rc = vnet_rx_packet(&control->p2smit);
> +		if (rc & QUEUE_WAS_FULL) {
> +			port->interrupt(port, VNET_IRQ_START_TX);
> +		}
> +	} while (!(rc & QUEUE_IS_EMPTY));
> +	return;
> +}
> +
> +/* checks if the given address is locally attached to the switch*/
> +int vnet_address_is_local(struct vnet_switch *zs, char *address)
> +{
> +	struct vnet_port *port;
> +
> +	read_lock(&zs->ports_lock);
> +	port = __vnet_find_destination(zs, address);
> +	read_unlock(&zs->ports_lock);
> +	return (port != NULL);
> +}
> +
> +
> +int vnet_minor_by_name(char *name)
> +{
> +	struct vnet_switch *zs;
> +	int ret;
> +
> +	read_lock(&vnet_switches_lock);
> +	zs = __vnet_switch_by_name(name);
> +	if (zs)
> +		ret = MINOR(zs->cdev.dev);
> +	else
> +		ret = -ENODEV;
> +	read_unlock(&vnet_switches_lock);
> +	return ret;
> +}
> +
> +static void vnet_root_release(struct device *dev)
> +{
> +	kfree(dev);
> +}
> +
> +
> +struct command {
> +	char *string1;
> +	char *string2;
> +};
> +
> +/*FIXME this is ugly. Dont worry: as soon as we have finalized the interface,
> + this crap is going away. Still, it works.......*/
> +static long vnet_control_ioctl(struct file *f, unsigned int command,
> +						unsigned long data)
> +{
> +	char string1[BUS_ID_SIZE];
> +	char string2[BUS_ID_SIZE];
> +	struct command com;
> +	struct vnet_port *port;
> +
> +	if (!capable(CAP_NET_ADMIN))
> +		return -EPERM;
> +	if (copy_from_user(&com, (__user struct command*) data, sizeof(struct command)))
> +		return -EFAULT;
> +	if (copy_from_user(string1, (__user char *) com.string1, ZWITCH_NAME_SIZE))
> +		return -EFAULT;
> +	if (command >=2)
> +		if (copy_from_user(string2, (__user char *) com.string2, ZWITCH_NAME_SIZE))
> +			return -EFAULT;
> +	if (strnlen(string1, ZWITCH_NAME_SIZE) == ZWITCH_NAME_SIZE)
> +		return -EINVAL;
> +	switch(command) {
> +	case ADD_SWITCH:
> +		return zwitch_create(string1,3);
> +	case DEL_SWITCH:
> +		return zwitch_delete(string1);
> +	case ADD_HOST:
> +		port = vnet_host_create(string1);
> +		if (port) {
> +			vnet_port_attach(port);
> +			return 0;
> +		} else
> +			return -ENODEV;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static int vnet_control_open(struct inode *inode, struct file *file)
> +{
> +	return 0;
> +}
> +
> +static int vnet_control_release(struct inode *inode, struct file *file)
> +{
> +	return 0;
> +}
> +
> +struct file_operations vnet_control_fops = {
> +	.open		= vnet_control_open,
> +	.release	= vnet_control_release,
> +	.unlocked_ioctl	= &vnet_control_ioctl,
> +	.compat_ioctl	= &vnet_control_ioctl,
> +};
> +
> +struct miscdevice vnet_control_device = {
> +	.minor = MISC_DYNAMIC_MINOR,
> +	.name = "vnet",
> +	.fops = &vnet_control_fops,
> +};
> +
> +int vnet_register_control_device(void)
> +{
> +	return misc_register(&vnet_control_device);
> +}
> +
> +int __init vnet_switch_init(void)
> +{
> +	int ret;
> +	dev_t dev;
> +
> +	zwitch_class = class_create(THIS_MODULE, "vnet");
> +	if (IS_ERR(zwitch_class)) {
> +                printk(KERN_ERR "vnet_switch: class_create failed!\n");
> +		ret = PTR_ERR(zwitch_class);
> +		goto out;
> +        }
> +	ret = alloc_chrdev_region(&dev, 0, NUM_MINORS, "vnet");
> +	if (ret) {
> +		printk(KERN_ERR "vnet_switch: alloc_chrdev_region failed\n");
> +		goto out_class;
> +	}
> +	vnet_major = MAJOR(dev);
> +	root_dev = kzalloc(sizeof(*root_dev), GFP_KERNEL);
> +	if (!root_dev) {
> +		printk(KERN_ERR "vnet_switch:allocation of device failed\n");
> +		ret = -ENOMEM;
> +		goto out_chrdev;
> +	}
> +	strncpy(root_dev->bus_id, "vnet", 5);
> +	root_dev->release = vnet_root_release;
> +	ret =device_register(root_dev);
> +	if (ret) {
> +		printk(KERN_ERR "vnet_switch: could not register device\n");
> +		kfree(root_dev);
> +		goto out_chrdev;
> +	}
> +	ret = vnet_register_control_device();
> +	if (ret) {
> +		printk("vnet_switch: could not create control device\n");
> +		goto out_dev;
> +	}
> +	printk ("vnet_switch loaded\n");
> +/* FIXME ---------- remove these static defines as soon as everyone has the
> + *                  user tools */
> +	{
> +		struct vnet_port *port;
> +		zwitch_create("myswitch0",2);
> +		zwitch_create("myswitch1",3);
> +
> +		port = vnet_host_create("myswitch0");
> +		if (port)
> +			vnet_port_attach(port);
> +		port = vnet_host_create("myswitch1");
> +		if (port)
> +			vnet_port_attach(port);
> +	}
> +/*-----------------------------------------------------------*/
> +	return 0;
> +out_dev:
> +	device_unregister(root_dev);
> +out_chrdev:
> +	unregister_chrdev_region(MKDEV(vnet_major,0), NUM_MINORS);
> +out_class:
> +	class_destroy(zwitch_class);
> +out:
> +	return ret;
> +}
> +
> +/* remove all existing vnet_zwitches in the system and unregister the
> + * character device from the system */
> +void vnet_switch_exit(void)
> +{
> +	struct vnet_switch *zs, *tmp;
> +	list_for_each_entry_safe(zs, tmp, &vnet_switches, lh) {
> +		zwitch_destroy_ports(zs);
> +		zwitch_destroy(zs);
> +	}
> +	device_unregister(root_dev);
> +	misc_deregister(&vnet_control_device);
> +	unregister_chrdev_region(MKDEV(vnet_major,0), NUM_MINORS);
> +	class_destroy(zwitch_class);
> +	printk ("vnet_switch unloaded\n");
> +}
> +
> +module_init(vnet_switch_init);
> +module_exit(vnet_switch_exit);
> +MODULE_DESCRIPTION("VNET: Virtual switch for vnet interfaces");
> +MODULE_AUTHOR("Christian Borntraeger <borntrae-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>");
> +MODULE_LICENSE("GPL");
> Index: linux-2.6.21/drivers/s390/guest/vnet_switch.h
> ===================================================================
> --- /dev/null
> +++ linux-2.6.21/drivers/s390/guest/vnet_switch.h
> @@ -0,0 +1,119 @@
> +/*
> + * vnet_switch - zlive insular communication knack switch
> + * infrastructure for virtual switching of Linux guests running under Linux
> + *
> + * Copyright (C) 2005 IBM Corporation
> + * Author: Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> + *         Christian Borntraeger <borntrae-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
> + *
> + */
> +
> +#ifndef __VNET_SWITCH_H
> +#define __VNET_SWITCH_H
> +
> +#include <linux/cdev.h>
> +#include <linux/device.h>
> +#include <linux/if_ether.h>
> +#include <linux/spinlock.h>
> +
> +#include "vnet.h"
> +
> +/* defines for IOCTLs. interface should be replaced by something better */
> +#define ADD_SWITCH	0
> +#define DEL_SWITCH	1
> +#define ADD_OSA		2
> +#define DEL_OSA		3
> +#define ADD_HOST	4
> +#define DEL_HOST	5
> +
> +/* min(IFNAMSIZ, BUS_ID_SIZE)*/
> +#define ZWITCH_NAME_SIZE 16
> +
> +/* This structure describes a virtual switch for ports to userspace network
> + * interfaces, e.g. in Linux under Linux environments*/
> +struct vnet_switch {
> +	struct list_head lh;
> +	char name[ZWITCH_NAME_SIZE];
> +	struct list_head switch_ports;		/* list of ports */
> +	rwlock_t ports_lock;			/* lock for switch_ports */
> +	struct class_device *class_device;
> +	struct cdev cdev;
> +	struct device dev;
> +	struct vnet_port *osa;
> +	int linktype;				/* 2=ethernet 3=IP */
> +};
> +
> +/* description of a port of the vnet_switch */
> +struct vnet_port {
> +	struct list_head lh;
> +	struct vnet_switch *zs;
> +	struct vnet_control *control;
> +	void *s2p_data[VNET_QUEUE_LEN][(VNET_BUFFER_SIZE>>PAGE_SHIFT)];
> +	void *p2s_data[VNET_QUEUE_LEN][(VNET_BUFFER_SIZE>>PAGE_SHIFT)];
> +	char mac[ETH_ALEN];
> +	void *priv;
> +	int (*set_mac) (struct vnet_port *port, char mac[ETH_ALEN], int add);
> +	void (*interrupt) (struct vnet_port *port, int type);
> +	void (*destroy) (struct vnet_port *port);
> +	struct device dev;
> +	unsigned long	rx_packets;	/* total packets received */
> +	unsigned long	tx_packets;	/* total packets transmitted */
> +	unsigned long	rx_bytes;	/* total bytes received	*/
> +	unsigned long	tx_bytes;	/* total bytes transmitted */
> +	unsigned long	rx_dropped;	/* no space in receive buffer */
> +	unsigned long	tx_dropped;	/* no space in destination buffer */
> +	spinlock_t rxlock;
> +	spinlock_t txlock;
> +};
> +
> +
> +static inline int
> +vnet_copy_buf_to_pages(void **data, char *buf, int len)
> +{
> +	int i;
> +
> +	if (len == 0)
> +		return 0;
> +	for (i=0; i <= ((len - 1) >> PAGE_SHIFT); i++ )
> +		memcpy(data[i], buf + i*PAGE_SIZE, min(PAGE_SIZE, len - i*PAGE_SIZE));
> +	return len;
> +}
> +
> +static inline int
> +vnet_copy_pages_to_buf(char *buf, void **data, int len)
> +{
> +	int i;
> +
> +	if (len == 0)
> +		return 0;
> +	for (i=0; i <= ((len -1) >> PAGE_SHIFT); i++ )
> +		memcpy(buf + i*PAGE_SIZE, data[i], min(PAGE_SIZE, len - i*PAGE_SIZE));
> +	return len;
> +}
> +
> +
> +/* checks if a switch with the given minor exists
> + * if yes, create a named and unconnected port on
> + * this switch with the given name. if no, return NULL */
> +extern struct vnet_port *vnet_port_get(int minor, char *port_name);
> +
> +/* attaches the port to the switch. The port must be
> + * fully initialized, as it may get data immediately afterwards */
> +extern void vnet_port_attach(struct vnet_port *port);
> +
> +/* detaches the port from the switch. After that,
> + * no calls into the port are made */
> +extern void vnet_port_detach(struct vnet_port *port);
> +
> +/* releases all ressources allocated with vnet_port_get */
> +extern void vnet_port_put(struct vnet_port *port);
> +
> +/* tell the switch that new data is available */
> +extern void vnet_port_rx(struct vnet_port *port);
> +
> +/* get the minor for a given name */
> +extern int vnet_minor_by_name(char *name);
> +
> +/* checks if the given address is locally attached to the switch*/
> +extern int vnet_address_is_local(struct vnet_switch *zs, char *address);
> +#endif
> Index: linux-2.6.21/drivers/s390/guest/Makefile
> ===================================================================
> --- linux-2.6.21.orig/drivers/s390/guest/Makefile
> +++ linux-2.6.21/drivers/s390/guest/Makefile
> @@ -6,3 +6,6 @@ obj-$(CONFIG_GUEST_CONSOLE) += guest_con
>  obj-$(CONFIG_S390_GUEST) += vdev.o vdev_device.o
>  obj-$(CONFIG_VDISK) += vdisk.o vdisk_blk.o
>  obj-$(CONFIG_VNET_GUEST) += vnet_guest.o
> +vnet_host-objs := vnet_switch.o vnet_port_guest.o vnet_port_host.o
> +obj-$(CONFIG_VNET_HOST) += vnet_host.o
> +
> Index: linux-2.6.21/drivers/s390/net/Kconfig
> ===================================================================
> --- linux-2.6.21.orig/drivers/s390/net/Kconfig
> +++ linux-2.6.21/drivers/s390/net/Kconfig
> @@ -95,4 +95,16 @@ config VNET_GUEST
>            connection.
>  	  If you're not using host/guest support, say N.
>  
> +config VNET_HOST
> +	tristate "virtual networking support (HOST)"
> +	depends on QETH && S390_HOST
> +	help
> +	  This is the host part of the vnet guest network connection.
> +          Say Y if you plan to host guests with network
> +          connection. The host part consists of a virtual switch
> +          a host device as well as a connection to the qeth
> +          driver.
> +	  If you're not using this kernel for hosting guest, say N.
> +
> +
>  endmenu
>
>
>
> -------------------------------------------------------------------------
> This SF.net email is sponsored by DB2 Express
> Download DB2 Express C - the FREE version of DB2 express and take
> control of your XML. No limits. Just data. Click to get it now.
> http://sourceforge.net/powerbar/db2/
> _______________________________________________
> kvm-devel mailing list
> kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
> https://lists.sourceforge.net/lists/listinfo/kvm-devel
>
>   


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

  parent reply	other threads:[~2007-05-11 20:21 UTC|newest]

Thread overview: 104+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <1178903957.25135.13.camel@cotte.boeblingen.de.ibm.com>
     [not found] ` <1178903957.25135.13.camel-WIxn4w2hgUz3YA32ykw5MLlKpX0K8NHHQQ4Iyu8u01E@public.gmane.org>
2007-05-11 17:35   ` [PATCH/RFC 2/9] s390 virtualization interface Carsten Otte
2007-05-11 17:35   ` [PATCH/RFC 3/9] s390 guest detection Carsten Otte
2007-05-11 17:35   ` [PATCH/RFC 4/9] Basic guest virtual devices infrastructure Carsten Otte
     [not found]     ` <1178904958.25135.31.camel-WIxn4w2hgUz3YA32ykw5MLlKpX0K8NHHQQ4Iyu8u01E@public.gmane.org>
2007-05-11 20:06       ` Arnd Bergmann
2007-05-14 11:26       ` Avi Kivity
     [not found]         ` <46484753.30602-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-05-14 11:43           ` Carsten Otte
     [not found]             ` <46484B5D.6080605-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
2007-05-14 12:00               ` [PATCH/RFC 4/9] Basic guest virtualdevices infrastructure Dor Laor
     [not found]                 ` <64F9B87B6B770947A9F8391472E032160BC7483D-yEcIvxbTEBqsx+V+t5oei8rau4O3wl8o3fe8/T/H7NteoWH0uzbU5w@public.gmane.org>
2007-05-14 13:32                   ` Carsten Otte
2007-05-11 17:36   ` [PATCH/RFC 5/9] s390 virtual console for guests Carsten Otte
     [not found]     ` <1178904960.25135.32.camel-WIxn4w2hgUz3YA32ykw5MLlKpX0K8NHHQQ4Iyu8u01E@public.gmane.org>
2007-05-11 19:00       ` Anthony Liguori
     [not found]         ` <4644BD3C.8040901-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2007-05-11 19:42           ` Christian Bornträger
2007-05-12  8:07           ` Carsten Otte
2007-05-14 16:23           ` Christian Bornträger
     [not found]             ` <200705141823.13424.cborntra-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
2007-05-14 16:48               ` Christian Borntraeger
     [not found]                 ` <200705141848.18996.borntrae-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
2007-05-14 17:49                   ` Anthony Liguori
     [not found]                     ` <4648A11D.3050607-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2007-05-15  0:27                       ` Arnd Bergmann
2007-05-15  7:54                       ` Carsten Otte
2007-05-11 17:36   ` [PATCH/RFC 6/9] virtual block device driver Carsten Otte
     [not found]     ` <1178904963.25135.33.camel-WIxn4w2hgUz3YA32ykw5MLlKpX0K8NHHQQ4Iyu8u01E@public.gmane.org>
2007-05-14 11:49       ` Avi Kivity
     [not found]         ` <46484CDF.505-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-05-14 13:23           ` Carsten Otte
     [not found]             ` <464862E9.7020105-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
2007-05-14 14:39               ` Avi Kivity
     [not found]                 ` <46487494.1070802-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-05-15 11:47                   ` Carsten Otte
     [not found]                     ` <46499DE9.9090202-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
2007-05-16 10:01                       ` Avi Kivity
2007-05-14 11:52       ` Avi Kivity
     [not found]         ` <46484D84.3060601-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-05-14 13:26           ` Carsten Otte
2007-05-11 17:36   ` [PATCH/RFC 7/9] Virtual network guest " Carsten Otte
     [not found]     ` <1178904965.25135.34.camel-WIxn4w2hgUz3YA32ykw5MLlKpX0K8NHHQQ4Iyu8u01E@public.gmane.org>
2007-05-11 19:44       ` ron minnich
     [not found]         ` <13426df10705111244w1578ebedy8259bc42ca1f588d-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-11 20:12           ` Anthony Liguori
     [not found]             ` <4644CE15.6080505-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2007-05-11 21:15               ` Eric Van Hensbergen
     [not found]                 ` <a4e6962a0705111415n47e77a15o331b59cf2a03b4-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-11 21:47                   ` Anthony Liguori
     [not found]                     ` <4644E456.2060507-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2007-05-11 22:21                       ` Eric Van Hensbergen
     [not found]                         ` <a4e6962a0705111521v2d451ddcjecf209e2031c85af-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-16 17:28                           ` Anthony Liguori
     [not found]                             ` <464B3F20.4030904-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2007-05-16 17:38                               ` Daniel P. Berrange
     [not found]                                 ` <20070516173822.GD16863-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2007-05-17  9:29                                   ` Carsten Otte
     [not found]                                     ` <464C2069.20909-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
2007-05-17 14:22                                       ` Anthony Liguori
     [not found]                                         ` <464C651F.5070700-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2007-05-21 11:11                                           ` Christian Borntraeger
2007-05-16 17:41                               ` Eric Van Hensbergen
     [not found]                                 ` <a4e6962a0705161041s5393c1a6wc455b20ff3fe8106-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-16 18:47                                   ` Anthony Liguori
     [not found]                                     ` <464B51A8.7050307-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2007-05-16 19:33                                       ` Eric Van Hensbergen
2007-05-16 17:45                               ` Gregory Haskins
     [not found]                                 ` <464B0ADB.BA47.005A.0-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
2007-05-16 18:39                                   ` Anthony Liguori
     [not found]                                     ` <464B4FEB.7070300-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2007-05-16 18:57                                       ` Gregory Haskins
     [not found]                                         ` <464B1B9C.BA47.005A.0-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
2007-05-16 19:10                                           ` Anthony Liguori
     [not found]                                             ` <464B572C.6090800-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2007-05-17  4:24                                               ` Rusty Russell
     [not found]                                                 ` <1179375881.21871.83.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2007-05-17 16:13                                                   ` Anthony Liguori
     [not found]                                                     ` <464C7F45.50908-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2007-05-17 23:34                                                       ` Rusty Russell
2007-05-21  9:07                                               ` Christian Borntraeger
     [not found]                                                 ` <OFC1AADF6F.DB57C7AC-ON422572E2.0030BE22-422572E2.0032174C-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
2007-05-21  9:27                                                   ` Cornelia Huck
2007-05-21 11:28                                                   ` Arnd Bergmann
     [not found]                                                     ` <200705211328.04565.arnd-r2nGTMty4D4@public.gmane.org>
2007-05-21 11:56                                                       ` Cornelia Huck
     [not found]                                                         ` <20070521135628.17a4f9cc-XQvu0L+U/CiXI4yAdoq52KN5r0PSdgG1zG2AekJRRhI@public.gmane.org>
2007-05-21 13:53                                                           ` Arnd Bergmann
2007-05-21 18:45                                                       ` Anthony Liguori
     [not found]                                                         ` <4651E8D1.4010208-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2007-05-21 23:09                                                           ` ron minnich
     [not found]                                                             ` <13426df10705211609j613032c6j373d9a4660f8ec6c-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-22  0:29                                                               ` Anthony Liguori
     [not found]                                                                 ` <46523952.7070405-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2007-05-22  0:45                                                                   ` ron minnich
     [not found]                                                                     ` <13426df10705211745r69acc95ai458b2192fe0d0132-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-22  1:13                                                                       ` Anthony Liguori
2007-05-22  1:34                                                                   ` Eric Van Hensbergen
     [not found]                                                                     ` <a4e6962a0705211834s4db19c7t3b95765bf2c092d7-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-22  1:42                                                                       ` Anthony Liguori
     [not found]                                                                         ` <46524A79.8070004-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2007-05-22  5:17                                                                           ` Avi Kivity
     [not found]                                                                             ` <46527CD9.5000603-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-05-22 12:49                                                                               ` Eric Van Hensbergen
     [not found]                                                                                 ` <a4e6962a0705220549j1c9565f2ic160c672b74aea35-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-22 12:56                                                                                   ` Christoph Hellwig
     [not found]                                                                                     ` <20070522125655.GA4506-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
2007-05-22 14:50                                                                                       ` Eric Van Hensbergen
     [not found]                                                                                         ` <a4e6962a0705220750s5abe380dg8dd8e7d0b84de7cd-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-22 15:05                                                                                           ` Anthony Liguori
     [not found]                                                                                             ` <465306AE.5080902-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2007-05-22 15:31                                                                                               ` ron minnich
2007-05-22 16:25                                                                                               ` Eric Van Hensbergen
     [not found]                                                                                                 ` <a4e6962a0705220925l580f136we269380fe3c9691c-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-22 17:00                                                                                                   ` ron minnich
     [not found]                                                                                                     ` <13426df10705221000i749badc5h8afe4f2fc95bc2ce-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-22 17:06                                                                                                       ` Christoph Hellwig
     [not found]                                                                                                         ` <20070522170628.GA16624-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
2007-05-22 17:34                                                                                                           ` ron minnich
     [not found]                                                                                                             ` <13426df10705221034k7baf5bccrc77aabca8c9e225c-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-22 20:03                                                                                                               ` Dor Laor
     [not found]                                                                                                                 ` <64F9B87B6B770947A9F8391472E032160BF29F1E-yEcIvxbTEBqsx+V+t5oei8rau4O3wl8o3fe8/T/H7NteoWH0uzbU5w@public.gmane.org>
2007-05-22 20:10                                                                                                                   ` ron minnich
2007-05-22 22:56                                                                                                                   ` Nakajima, Jun
     [not found]                                                                                                                     ` <8FFF7E42E93CC646B632AB40643802A8032793AC-1a9uaKK1+wJcIJlls4ac1rfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2007-05-23  8:15                                                                                                                       ` Carsten Otte
     [not found]                                                                                                                         ` <4653F807.2010209-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
2007-05-23 12:25                                                                                                                           ` Avi Kivity
2007-05-23 14:12                                                                                                                           ` Eric Van Hensbergen
     [not found]                                                                                                                             ` <a4e6962a0705230712pd8c2958m9dee6b2ccec0899d-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-23 23:02                                                                                                                               ` Arnd Bergmann
     [not found]                                                                                                                                 ` <200705240102.40795.arnd-r2nGTMty4D4@public.gmane.org>
2007-05-23 23:57                                                                                                                                   ` Eric Van Hensbergen
     [not found]                                                                                                                                     ` <a4e6962a0705231657n65946ba4n74393f7028b6d61c-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-24  0:07                                                                                                                                       ` Eric Van Hensbergen
2007-05-23 12:21                                                                                                                       ` Avi Kivity
2007-05-23 12:16                                                                                                           ` Avi Kivity
     [not found]                                                                                                             ` <465430B2.7050101-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-05-23 12:20                                                                                                               ` Christoph Hellwig
2007-05-23 12:20                                                                                                       ` Avi Kivity
2007-05-23 11:55                                                                                           ` Avi Kivity
2007-05-22 13:08                                                                                   ` Anthony Liguori
2007-05-18  5:31                               ` ron minnich
     [not found]                                 ` <13426df10705172231y5e93d1f5y398d4f187a8978e1-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-05-18 14:31                                   ` Anthony Liguori
     [not found]                                     ` <464DB8A5.6080503-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2007-05-18 15:14                                       ` ron minnich
2007-05-11 21:51               ` ron minnich
2007-05-12  8:46           ` Carsten Otte
     [not found]             ` <46457EF9.2070706-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
2007-05-13 12:04               ` Dor Laor
     [not found]                 ` <64F9B87B6B770947A9F8391472E032160BC74612-yEcIvxbTEBqsx+V+t5oei8rau4O3wl8o3fe8/T/H7NteoWH0uzbU5w@public.gmane.org>
2007-05-13 14:49                   ` Anthony Liguori
     [not found]                     ` <4647257F.4020900-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2007-05-13 16:23                       ` Dor Laor
     [not found]                         ` <64F9B87B6B770947A9F8391472E032160BC74675-yEcIvxbTEBqsx+V+t5oei8rau4O3wl8o3fe8/T/H7NteoWH0uzbU5w@public.gmane.org>
2007-05-13 16:49                           ` Anthony Liguori
     [not found]                             ` <4647418A.2040201-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2007-05-13 17:06                               ` Muli Ben-Yehuda
     [not found]                                 ` <20070513170608.GA4343-WD1JZD8MxeCTrf4lBMg6DdBPR1lH4CV8@public.gmane.org>
2007-05-13 20:31                                   ` Dor Laor
2007-05-14  2:39                               ` Rusty Russell
2007-05-14 11:53                               ` Avi Kivity
2007-05-14 12:05           ` Avi Kivity
     [not found]             ` <46485070.3000106-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-05-14 12:24               ` Christian Bornträger
     [not found]                 ` <200705141424.44423.cborntra-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
2007-05-14 12:32                   ` Avi Kivity
2007-05-14 13:36               ` Carsten Otte
2007-05-11 17:36   ` [PATCH/RFC 8/9] Virtual network host switch support Carsten Otte
     [not found]     ` <1178904968.25135.35.camel-WIxn4w2hgUz3YA32ykw5MLlKpX0K8NHHQQ4Iyu8u01E@public.gmane.org>
2007-05-11 20:21       ` Anthony Liguori [this message]
     [not found]         ` <4644D048.7060106-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2007-05-11 20:50           ` Christian Bornträger
2007-05-11 17:36   ` [PATCH/RFC 9/9] Fix system<->user misaccount of interpreted execution Carsten Otte

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4644D048.7060106@us.ibm.com \
    --to=aliguori-r/jw6+rmf7hqt0dzr+alfa@public.gmane.org \
    --cc=cborntra-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org \
    --cc=cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org \
    --cc=kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    --cc=schwidefsky-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox