Commit ad43c3565bebada7e5a13288e37542fd940369e8
Committed by
Linus Torvalds
1 parent
6d536e4b59
Exists in
master
and in
39 other branches
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>
Showing 5 changed files with 335 additions and 2 deletions Side-by-side Diff
arch/um/Kconfig.net
... | ... | @@ -108,6 +108,28 @@ |
108 | 108 | more than one without conflict. If you don't need UML networking, |
109 | 109 | say N. |
110 | 110 | |
111 | +config UML_NET_VDE | |
112 | + bool "VDE transport" | |
113 | + depends on UML_NET | |
114 | + help | |
115 | + This User-Mode Linux network transport allows one or more running | |
116 | + UMLs on a single host to communicate with each other and also | |
117 | + with the rest of the world using Virtual Distributed Ethernet, | |
118 | + an improved fork of uml_switch. | |
119 | + | |
120 | + You must have libvdeplug installed in order to build the vde | |
121 | + transport into UML. | |
122 | + | |
123 | + To use this form of networking, you will need to run vde_switch | |
124 | + on the host. | |
125 | + | |
126 | + For more information, see <http://wiki.virtualsquare.org/> | |
127 | + That site has a good overview of what VDE is and also examples | |
128 | + of the UML command line to use to enable VDE networking. | |
129 | + | |
130 | + If you need UML networking with VDE, | |
131 | + say Y. | |
132 | + | |
111 | 133 | config UML_NET_MCAST |
112 | 134 | bool "Multicast transport" |
113 | 135 | depends on UML_NET |
arch/um/drivers/Makefile
... | ... | @@ -19,10 +19,16 @@ |
19 | 19 | |
20 | 20 | LDFLAGS_pcap.o := -r $(shell $(CC) $(CFLAGS) -print-file-name=libpcap.a) |
21 | 21 | |
22 | -targets := pcap_kern.o pcap_user.o | |
22 | +LDFLAGS_vde.o := -r $(shell $(CC) $(CFLAGS) -print-file-name=libvdeplug.a) | |
23 | 23 | |
24 | +targets := pcap_kern.o pcap_user.o vde_kern.o vde_user.o | |
25 | + | |
24 | 26 | $(obj)/pcap.o: $(obj)/pcap_kern.o $(obj)/pcap_user.o |
25 | 27 | $(LD) -r -dp -o $@ $^ $(LDFLAGS) $(LDFLAGS_pcap.o) |
28 | + | |
29 | +$(obj)/vde.o: $(obj)/vde_kern.o $(obj)/vde_user.o | |
30 | + $(LD) -r -dp -o $@ $^ $(LDFLAGS) $(LDFLAGS_vde.o) | |
31 | + | |
26 | 32 | #XXX: The call below does not work because the flags are added before the |
27 | 33 | # object name, so nothing from the library gets linked. |
28 | 34 | #$(call if_changed,ld) |
... | ... | @@ -37,6 +43,7 @@ |
37 | 43 | obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o |
38 | 44 | obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o |
39 | 45 | obj-$(CONFIG_UML_NET_DAEMON) += daemon.o |
46 | +obj-$(CONFIG_UML_NET_VDE) += vde.o | |
40 | 47 | obj-$(CONFIG_UML_NET_MCAST) += mcast.o |
41 | 48 | obj-$(CONFIG_UML_NET_PCAP) += pcap.o |
42 | 49 | obj-$(CONFIG_UML_NET) += net.o |
... | ... | @@ -54,7 +61,7 @@ |
54 | 61 | obj-$(CONFIG_UML_RANDOM) += random.o |
55 | 62 | |
56 | 63 | # pcap_user.o must be added explicitly. |
57 | -USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o | |
64 | +USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o | |
58 | 65 | |
59 | 66 | include arch/um/scripts/Makefile.rules |
arch/um/drivers/vde.h
1 | +/* | |
2 | + * Copyright (C) 2007 Luca Bigliardi (shammash@artha.org). | |
3 | + * Licensed under the GPL. | |
4 | + */ | |
5 | + | |
6 | +#ifndef __UM_VDE_H__ | |
7 | +#define __UM_VDE_H__ | |
8 | + | |
9 | +struct vde_data { | |
10 | + char *vde_switch; | |
11 | + char *descr; | |
12 | + void *args; | |
13 | + void *conn; | |
14 | + void *dev; | |
15 | +}; | |
16 | + | |
17 | +struct vde_init { | |
18 | + char *vde_switch; | |
19 | + char *descr; | |
20 | + int port; | |
21 | + char *group; | |
22 | + int mode; | |
23 | +}; | |
24 | + | |
25 | +extern const struct net_user_info vde_user_info; | |
26 | + | |
27 | +extern void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init); | |
28 | + | |
29 | +extern int vde_user_read(void *conn, void *buf, int len); | |
30 | +extern int vde_user_write(void *conn, void *buf, int len); | |
31 | + | |
32 | +#endif |
arch/um/drivers/vde_kern.c
1 | +/* | |
2 | + * Copyright (C) 2007 Luca Bigliardi (shammash@artha.org). | |
3 | + * Licensed under the GPL. | |
4 | + * | |
5 | + * Transport usage: | |
6 | + * ethN=vde,<vde_switch>,<mac addr>,<port>,<group>,<mode>,<description> | |
7 | + * | |
8 | + */ | |
9 | + | |
10 | +#include "linux/kernel.h" | |
11 | +#include "linux/init.h" | |
12 | +#include "linux/netdevice.h" | |
13 | +#include "linux/etherdevice.h" | |
14 | +#include "net_kern.h" | |
15 | +#include "net_user.h" | |
16 | +#include "vde.h" | |
17 | + | |
18 | +static void vde_init(struct net_device *dev, void *data) | |
19 | +{ | |
20 | + struct vde_init *init = data; | |
21 | + struct uml_net_private *pri; | |
22 | + struct vde_data *vpri; | |
23 | + | |
24 | + pri = dev->priv; | |
25 | + vpri = (struct vde_data *) pri->user; | |
26 | + | |
27 | + vpri->vde_switch = init->vde_switch; | |
28 | + vpri->descr = init->descr ? init->descr : "UML vde_transport"; | |
29 | + vpri->args = NULL; | |
30 | + vpri->conn = NULL; | |
31 | + vpri->dev = dev; | |
32 | + | |
33 | + printk(KERN_INFO "vde backend - %s, ", vpri->vde_switch ? | |
34 | + vpri->vde_switch : "(default socket)"); | |
35 | + | |
36 | + vde_init_libstuff(vpri, init); | |
37 | + | |
38 | + printk(KERN_INFO "\n"); | |
39 | +} | |
40 | + | |
41 | +static int vde_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) | |
42 | +{ | |
43 | + struct vde_data *pri = (struct vde_data *) &lp->user; | |
44 | + | |
45 | + if (pri->conn != NULL) { | |
46 | + *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); | |
47 | + if (*skb == NULL) | |
48 | + return -ENOMEM; | |
49 | + | |
50 | + return vde_user_read(pri->conn, skb_mac_header(*skb), | |
51 | + (*skb)->dev->mtu + ETH_HEADER_OTHER); | |
52 | + } | |
53 | + | |
54 | + printk(KERN_ERR "vde_read - we have no VDECONN to read from"); | |
55 | + return -EBADF; | |
56 | +} | |
57 | + | |
58 | +static int vde_write(int fd, struct sk_buff **skb, struct uml_net_private *lp) | |
59 | +{ | |
60 | + struct vde_data *pri = (struct vde_data *) &lp->user; | |
61 | + | |
62 | + if (pri->conn != NULL) | |
63 | + return vde_user_write((void *)pri->conn, (*skb)->data, | |
64 | + (*skb)->len); | |
65 | + | |
66 | + printk(KERN_ERR "vde_write - we have no VDECONN to write to"); | |
67 | + return -EBADF; | |
68 | +} | |
69 | + | |
70 | +static const struct net_kern_info vde_kern_info = { | |
71 | + .init = vde_init, | |
72 | + .protocol = eth_protocol, | |
73 | + .read = vde_read, | |
74 | + .write = vde_write, | |
75 | +}; | |
76 | + | |
77 | +static int vde_setup(char *str, char **mac_out, void *data) | |
78 | +{ | |
79 | + struct vde_init *init = data; | |
80 | + char *remain, *port_str = NULL, *mode_str = NULL, *last; | |
81 | + | |
82 | + *init = ((struct vde_init) | |
83 | + { .vde_switch = NULL, | |
84 | + .descr = NULL, | |
85 | + .port = 0, | |
86 | + .group = NULL, | |
87 | + .mode = 0 }); | |
88 | + | |
89 | + remain = split_if_spec(str, &init->vde_switch, mac_out, &port_str, | |
90 | + &init->group, &mode_str, &init->descr, NULL); | |
91 | + | |
92 | + if (remain != NULL) | |
93 | + printk(KERN_WARNING "vde_setup - Ignoring extra data :" | |
94 | + "'%s'\n", remain); | |
95 | + | |
96 | + if (port_str != NULL) { | |
97 | + init->port = simple_strtoul(port_str, &last, 10); | |
98 | + if ((*last != '\0') || (last == port_str)) { | |
99 | + printk(KERN_ERR "vde_setup - Bad port : '%s'\n", | |
100 | + port_str); | |
101 | + return 0; | |
102 | + } | |
103 | + } | |
104 | + | |
105 | + if (mode_str != NULL) { | |
106 | + init->mode = simple_strtoul(mode_str, &last, 8); | |
107 | + if ((*last != '\0') || (last == mode_str)) { | |
108 | + printk(KERN_ERR "vde_setup - Bad mode : '%s'\n", | |
109 | + mode_str); | |
110 | + return 0; | |
111 | + } | |
112 | + } | |
113 | + | |
114 | + printk(KERN_INFO "Configured vde device: %s\n", init->vde_switch ? | |
115 | + init->vde_switch : "(default socket)"); | |
116 | + | |
117 | + return 1; | |
118 | +} | |
119 | + | |
120 | +static struct transport vde_transport = { | |
121 | + .list = LIST_HEAD_INIT(vde_transport.list), | |
122 | + .name = "vde", | |
123 | + .setup = vde_setup, | |
124 | + .user = &vde_user_info, | |
125 | + .kern = &vde_kern_info, | |
126 | + .private_size = sizeof(struct vde_data), | |
127 | + .setup_size = sizeof(struct vde_init), | |
128 | +}; | |
129 | + | |
130 | +static int register_vde(void) | |
131 | +{ | |
132 | + register_transport(&vde_transport); | |
133 | + return 0; | |
134 | +} | |
135 | + | |
136 | +late_initcall(register_vde); |
arch/um/drivers/vde_user.c
1 | +/* | |
2 | + * Copyright (C) 2007 Luca Bigliardi (shammash@artha.org). | |
3 | + * Licensed under the GPL. | |
4 | + */ | |
5 | + | |
6 | +#include <errno.h> | |
7 | +#include <unistd.h> | |
8 | +#include <libvdeplug.h> | |
9 | +#include "net_user.h" | |
10 | +#include "kern_util.h" | |
11 | +#include "kern_constants.h" | |
12 | +#include "user.h" | |
13 | +#include "os.h" | |
14 | +#include "um_malloc.h" | |
15 | +#include "vde.h" | |
16 | + | |
17 | +#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) | |
18 | + | |
19 | +static int vde_user_init(void *data, void *dev) | |
20 | +{ | |
21 | + struct vde_data *pri = data; | |
22 | + VDECONN *conn = NULL; | |
23 | + int err = -EINVAL; | |
24 | + | |
25 | + pri->dev = dev; | |
26 | + | |
27 | + conn = vde_open(pri->vde_switch, pri->descr, pri->args); | |
28 | + | |
29 | + if (conn == NULL) { | |
30 | + err = -errno; | |
31 | + printk(UM_KERN_ERR "vde_user_init: vde_open failed, " | |
32 | + "errno = %d\n", errno); | |
33 | + return err; | |
34 | + } | |
35 | + | |
36 | + printk(UM_KERN_INFO "vde backend - connection opened\n"); | |
37 | + | |
38 | + pri->conn = conn; | |
39 | + | |
40 | + return 0; | |
41 | +} | |
42 | + | |
43 | +static int vde_user_open(void *data) | |
44 | +{ | |
45 | + struct vde_data *pri = data; | |
46 | + | |
47 | + if (pri->conn != NULL) | |
48 | + return vde_datafd(pri->conn); | |
49 | + | |
50 | + printk(UM_KERN_WARNING "vde_open - we have no VDECONN to open"); | |
51 | + return -EINVAL; | |
52 | +} | |
53 | + | |
54 | +static void vde_remove(void *data) | |
55 | +{ | |
56 | + struct vde_data *pri = data; | |
57 | + | |
58 | + if (pri->conn != NULL) { | |
59 | + printk(UM_KERN_INFO "vde backend - closing connection\n"); | |
60 | + vde_close(pri->conn); | |
61 | + pri->conn = NULL; | |
62 | + kfree(pri->args); | |
63 | + pri->args = NULL; | |
64 | + return; | |
65 | + } | |
66 | + | |
67 | + printk(UM_KERN_WARNING "vde_remove - we have no VDECONN to remove"); | |
68 | +} | |
69 | + | |
70 | +static int vde_set_mtu(int mtu, void *data) | |
71 | +{ | |
72 | + return mtu; | |
73 | +} | |
74 | + | |
75 | +const struct net_user_info vde_user_info = { | |
76 | + .init = vde_user_init, | |
77 | + .open = vde_user_open, | |
78 | + .close = NULL, | |
79 | + .remove = vde_remove, | |
80 | + .set_mtu = vde_set_mtu, | |
81 | + .add_address = NULL, | |
82 | + .delete_address = NULL, | |
83 | + .max_packet = MAX_PACKET - ETH_HEADER_OTHER | |
84 | +}; | |
85 | + | |
86 | +void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init) | |
87 | +{ | |
88 | + struct vde_open_args *args; | |
89 | + | |
90 | + vpri->args = kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL); | |
91 | + if (vpri->args == NULL) { | |
92 | + printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args" | |
93 | + "allocation failed"); | |
94 | + return; | |
95 | + } | |
96 | + | |
97 | + args = vpri->args; | |
98 | + | |
99 | + args->port = init->port; | |
100 | + args->group = init->group; | |
101 | + args->mode = init->mode ? init->mode : 0700; | |
102 | + | |
103 | + args->port ? printk(UM_KERN_INFO "port %d", args->port) : | |
104 | + printk(UM_KERN_INFO "undefined port"); | |
105 | +} | |
106 | + | |
107 | +int vde_user_read(void *conn, void *buf, int len) | |
108 | +{ | |
109 | + VDECONN *vconn = conn; | |
110 | + int rv; | |
111 | + | |
112 | + if (vconn == NULL) | |
113 | + return 0; | |
114 | + | |
115 | + rv = vde_recv(vconn, buf, len, 0); | |
116 | + if (rv < 0) { | |
117 | + if (errno == EAGAIN) | |
118 | + return 0; | |
119 | + return -errno; | |
120 | + } | |
121 | + else if (rv == 0) | |
122 | + return -ENOTCONN; | |
123 | + | |
124 | + return rv; | |
125 | +} | |
126 | + | |
127 | +int vde_user_write(void *conn, void *buf, int len) | |
128 | +{ | |
129 | + VDECONN *vconn = conn; | |
130 | + | |
131 | + if (vconn == NULL) | |
132 | + return 0; | |
133 | + | |
134 | + return vde_send(vconn, buf, len, 0); | |
135 | +} |