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:
parent
6d536e4b59
commit
ad43c3565b
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue