uml: add VDE networking support

Added vde network backend in uml to introduce native Virtual Distributed
Ethernet support (using libvdeplug).

Signed-off-by: Luca Bigliardi <shammash@artha.org>
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Jeff Dike 2007-10-16 01:26:48 -07:00 committed by Linus Torvalds
parent 6d536e4b59
commit ad43c3565b
5 changed files with 335 additions and 2 deletions

View File

@ -108,6 +108,28 @@ config UML_NET_DAEMON
more than one without conflict. If you don't need UML networking,
say N.
config UML_NET_VDE
bool "VDE transport"
depends on UML_NET
help
This User-Mode Linux network transport allows one or more running
UMLs on a single host to communicate with each other and also
with the rest of the world using Virtual Distributed Ethernet,
an improved fork of uml_switch.
You must have libvdeplug installed in order to build the vde
transport into UML.
To use this form of networking, you will need to run vde_switch
on the host.
For more information, see <http://wiki.virtualsquare.org/>
That site has a good overview of what VDE is and also examples
of the UML command line to use to enable VDE networking.
If you need UML networking with VDE,
say Y.
config UML_NET_MCAST
bool "Multicast transport"
depends on UML_NET

View File

@ -19,10 +19,16 @@ harddog-objs := harddog_kern.o harddog_user.o
LDFLAGS_pcap.o := -r $(shell $(CC) $(CFLAGS) -print-file-name=libpcap.a)
targets := pcap_kern.o pcap_user.o
LDFLAGS_vde.o := -r $(shell $(CC) $(CFLAGS) -print-file-name=libvdeplug.a)
targets := pcap_kern.o pcap_user.o vde_kern.o vde_user.o
$(obj)/pcap.o: $(obj)/pcap_kern.o $(obj)/pcap_user.o
$(LD) -r -dp -o $@ $^ $(LDFLAGS) $(LDFLAGS_pcap.o)
$(obj)/vde.o: $(obj)/vde_kern.o $(obj)/vde_user.o
$(LD) -r -dp -o $@ $^ $(LDFLAGS) $(LDFLAGS_vde.o)
#XXX: The call below does not work because the flags are added before the
# object name, so nothing from the library gets linked.
#$(call if_changed,ld)
@ -37,6 +43,7 @@ obj-$(CONFIG_STDERR_CONSOLE) += stderr_console.o
obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o
obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o
obj-$(CONFIG_UML_NET_DAEMON) += daemon.o
obj-$(CONFIG_UML_NET_VDE) += vde.o
obj-$(CONFIG_UML_NET_MCAST) += mcast.o
obj-$(CONFIG_UML_NET_PCAP) += pcap.o
obj-$(CONFIG_UML_NET) += net.o
@ -54,6 +61,6 @@ obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
obj-$(CONFIG_UML_RANDOM) += random.o
# pcap_user.o must be added explicitly.
USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o
USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o
include arch/um/scripts/Makefile.rules

32
arch/um/drivers/vde.h Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2007 Luca Bigliardi (shammash@artha.org).
* Licensed under the GPL.
*/
#ifndef __UM_VDE_H__
#define __UM_VDE_H__
struct vde_data {
char *vde_switch;
char *descr;
void *args;
void *conn;
void *dev;
};
struct vde_init {
char *vde_switch;
char *descr;
int port;
char *group;
int mode;
};
extern const struct net_user_info vde_user_info;
extern void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init);
extern int vde_user_read(void *conn, void *buf, int len);
extern int vde_user_write(void *conn, void *buf, int len);
#endif

136
arch/um/drivers/vde_kern.c Normal file
View File

@ -0,0 +1,136 @@
/*
* Copyright (C) 2007 Luca Bigliardi (shammash@artha.org).
* Licensed under the GPL.
*
* Transport usage:
* ethN=vde,<vde_switch>,<mac addr>,<port>,<group>,<mode>,<description>
*
*/
#include "linux/kernel.h"
#include "linux/init.h"
#include "linux/netdevice.h"
#include "linux/etherdevice.h"
#include "net_kern.h"
#include "net_user.h"
#include "vde.h"
static void vde_init(struct net_device *dev, void *data)
{
struct vde_init *init = data;
struct uml_net_private *pri;
struct vde_data *vpri;
pri = dev->priv;
vpri = (struct vde_data *) pri->user;
vpri->vde_switch = init->vde_switch;
vpri->descr = init->descr ? init->descr : "UML vde_transport";
vpri->args = NULL;
vpri->conn = NULL;
vpri->dev = dev;
printk(KERN_INFO "vde backend - %s, ", vpri->vde_switch ?
vpri->vde_switch : "(default socket)");
vde_init_libstuff(vpri, init);
printk(KERN_INFO "\n");
}
static int vde_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
{
struct vde_data *pri = (struct vde_data *) &lp->user;
if (pri->conn != NULL) {
*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
if (*skb == NULL)
return -ENOMEM;
return vde_user_read(pri->conn, skb_mac_header(*skb),
(*skb)->dev->mtu + ETH_HEADER_OTHER);
}
printk(KERN_ERR "vde_read - we have no VDECONN to read from");
return -EBADF;
}
static int vde_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
{
struct vde_data *pri = (struct vde_data *) &lp->user;
if (pri->conn != NULL)
return vde_user_write((void *)pri->conn, (*skb)->data,
(*skb)->len);
printk(KERN_ERR "vde_write - we have no VDECONN to write to");
return -EBADF;
}
static const struct net_kern_info vde_kern_info = {
.init = vde_init,
.protocol = eth_protocol,
.read = vde_read,
.write = vde_write,
};
static int vde_setup(char *str, char **mac_out, void *data)
{
struct vde_init *init = data;
char *remain, *port_str = NULL, *mode_str = NULL, *last;
*init = ((struct vde_init)
{ .vde_switch = NULL,
.descr = NULL,
.port = 0,
.group = NULL,
.mode = 0 });
remain = split_if_spec(str, &init->vde_switch, mac_out, &port_str,
&init->group, &mode_str, &init->descr, NULL);
if (remain != NULL)
printk(KERN_WARNING "vde_setup - Ignoring extra data :"
"'%s'\n", remain);
if (port_str != NULL) {
init->port = simple_strtoul(port_str, &last, 10);
if ((*last != '\0') || (last == port_str)) {
printk(KERN_ERR "vde_setup - Bad port : '%s'\n",
port_str);
return 0;
}
}
if (mode_str != NULL) {
init->mode = simple_strtoul(mode_str, &last, 8);
if ((*last != '\0') || (last == mode_str)) {
printk(KERN_ERR "vde_setup - Bad mode : '%s'\n",
mode_str);
return 0;
}
}
printk(KERN_INFO "Configured vde device: %s\n", init->vde_switch ?
init->vde_switch : "(default socket)");
return 1;
}
static struct transport vde_transport = {
.list = LIST_HEAD_INIT(vde_transport.list),
.name = "vde",
.setup = vde_setup,
.user = &vde_user_info,
.kern = &vde_kern_info,
.private_size = sizeof(struct vde_data),
.setup_size = sizeof(struct vde_init),
};
static int register_vde(void)
{
register_transport(&vde_transport);
return 0;
}
late_initcall(register_vde);

136
arch/um/drivers/vde_user.c Normal file
View File

@ -0,0 +1,136 @@
/*
* Copyright (C) 2007 Luca Bigliardi (shammash@artha.org).
* Licensed under the GPL.
*/
#include <errno.h>
#include <unistd.h>
#include <libvdeplug.h>
#include "net_user.h"
#include "kern_util.h"
#include "kern_constants.h"
#include "user.h"
#include "os.h"
#include "um_malloc.h"
#include "vde.h"
#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
static int vde_user_init(void *data, void *dev)
{
struct vde_data *pri = data;
VDECONN *conn = NULL;
int err = -EINVAL;
pri->dev = dev;
conn = vde_open(pri->vde_switch, pri->descr, pri->args);
if (conn == NULL) {
err = -errno;
printk(UM_KERN_ERR "vde_user_init: vde_open failed, "
"errno = %d\n", errno);
return err;
}
printk(UM_KERN_INFO "vde backend - connection opened\n");
pri->conn = conn;
return 0;
}
static int vde_user_open(void *data)
{
struct vde_data *pri = data;
if (pri->conn != NULL)
return vde_datafd(pri->conn);
printk(UM_KERN_WARNING "vde_open - we have no VDECONN to open");
return -EINVAL;
}
static void vde_remove(void *data)
{
struct vde_data *pri = data;
if (pri->conn != NULL) {
printk(UM_KERN_INFO "vde backend - closing connection\n");
vde_close(pri->conn);
pri->conn = NULL;
kfree(pri->args);
pri->args = NULL;
return;
}
printk(UM_KERN_WARNING "vde_remove - we have no VDECONN to remove");
}
static int vde_set_mtu(int mtu, void *data)
{
return mtu;
}
const struct net_user_info vde_user_info = {
.init = vde_user_init,
.open = vde_user_open,
.close = NULL,
.remove = vde_remove,
.set_mtu = vde_set_mtu,
.add_address = NULL,
.delete_address = NULL,
.max_packet = MAX_PACKET - ETH_HEADER_OTHER
};
void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init)
{
struct vde_open_args *args;
vpri->args = kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL);
if (vpri->args == NULL) {
printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args"
"allocation failed");
return;
}
args = vpri->args;
args->port = init->port;
args->group = init->group;
args->mode = init->mode ? init->mode : 0700;
args->port ? printk(UM_KERN_INFO "port %d", args->port) :
printk(UM_KERN_INFO "undefined port");
}
int vde_user_read(void *conn, void *buf, int len)
{
VDECONN *vconn = conn;
int rv;
if (vconn == NULL)
return 0;
rv = vde_recv(vconn, buf, len, 0);
if (rv < 0) {
if (errno == EAGAIN)
return 0;
return -errno;
}
else if (rv == 0)
return -ENOTCONN;
return rv;
}
int vde_user_write(void *conn, void *buf, int len)
{
VDECONN *vconn = conn;
if (vconn == NULL)
return 0;
return vde_send(vconn, buf, len, 0);
}