@@ -152,7 +152,7 @@ config UML_NET_TUNTAP
depends on UML_NET
help
The UML TUN/TAP network transport allows a UML instance to exchange
- packets with the host over a TUN/TAP device.
+ packets with the host over a TUN/TAP device.
To use this transport, your host kernel must have support for TUN/TAP
devices, either built-in or as a module.
@@ -1187,6 +1187,10 @@ static int vector_net_close(struct net_device *dev)
os_close_file(vp->fds->rx_fd);
vp->fds->rx_fd = -1;
}
+ if (vp->fds->control_fd > 0) {
+ os_close_file(vp->fds->control_fd);
+ vp->fds->control_fd = -1;
+ }
if (vp->fds->tx_fd > 0) {
os_close_file(vp->fds->tx_fd);
vp->fds->tx_fd = -1;
@@ -25,6 +25,7 @@
#include <linux/if_packet.h>
#include <sys/wait.h>
#include <sys/uio.h>
+#include <sys/time.h>
#include <linux/virtio_net.h>
#include <netdb.h>
#include <stdlib.h>
@@ -37,7 +38,8 @@
#define ID_BESS 2
#define ID_UCAST 3
#define ID_MCAST 4
-#define ID_MAX 4
+#define ID_DAEMON 5
+#define ID_MAX 5
#define TOKEN_IFNAME "ifname"
#define TOKEN_SCRIPT "script"
@@ -57,6 +59,18 @@
static const char padchar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char *template = "tapXXXXXX";
+enum request_type { REQ_NEW_CONTROL };
+
+#define SWITCH_MAGIC 0xfeedface
+
+struct request_v3 {
+ uint32_t magic;
+ uint32_t version;
+ enum request_type type;
+ struct sockaddr_un sock;
+};
+
+
/* This is very ugly and brute force lookup, but it is done
* only once at initialization so not worth doing hashes or
* anything more intelligent
@@ -217,6 +231,7 @@ static struct vector_fds *user_init_tap_fds(struct arglist *ifspec)
}
result->rx_fd = -1;
result->tx_fd = -1;
+ result->control_fd = -1;
result->remote_addr = NULL;
result->remote_addr_size = 0;
@@ -272,6 +287,7 @@ static struct vector_fds *user_init_hybrid_fds(struct arglist *ifspec)
}
result->rx_fd = -1;
result->tx_fd = -1;
+ result->control_fd = -1;
result->remote_addr = NULL;
result->remote_addr_size = 0;
@@ -305,21 +321,35 @@ static struct vector_fds *user_init_hybrid_fds(struct arglist *ifspec)
return NULL;
}
+#define SWITCH_VERSION 3
+
static struct vector_fds *user_init_unix_fds(struct arglist *ifspec, int id)
{
- int fd = -1;
+ int fd = -1, n;
int socktype;
char *src, *dst;
struct vector_fds *result = NULL;
- struct sockaddr_un *local_addr = NULL, *remote_addr = NULL;
+ struct sockaddr_un *local_addr = NULL, *remote_addr = NULL, *control_addr = NULL;
+ struct request_v3 req;
+ struct {
+ char zero;
+ int pid;
+ int usecs;
+ } name;
+ struct timeval tv;
src = uml_vector_fetch_arg(ifspec, "src");
dst = uml_vector_fetch_arg(ifspec, "dst");
+
+ if (dst == NULL)
+ dst = "/tmp/uml.ctl";
+
result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
if (result == NULL) {
printk(UM_KERN_ERR "unix open:cannot allocate remote addr");
goto unix_cleanup;
}
+ result->control_fd = -1;
remote_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
if (remote_addr == NULL) {
printk(UM_KERN_ERR "unix open:cannot allocate remote addr");
@@ -327,6 +357,62 @@ static struct vector_fds *user_init_unix_fds(struct arglist *ifspec, int id)
}
switch (id) {
+ case ID_DAEMON:
+ name.zero = 0;
+ name.pid = os_getpid();
+ gettimeofday(&tv, NULL);
+ name.usecs = tv.tv_usec;
+
+ local_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
+ if (local_addr == NULL) {
+ printk(UM_KERN_ERR "daemon open:cannot allocate local addr");
+ goto unix_cleanup;
+ }
+ local_addr->sun_family = AF_UNIX;
+ memcpy(local_addr->sun_path, &name, sizeof(name));
+
+ result->control_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (result->control_fd < 0) {
+ printk(UM_KERN_ERR
+ "unix open: could not open socket, error = %d",
+ -errno
+ );
+ goto unix_cleanup;
+ }
+ if (strlen(dst) <= MAX_UN_LEN) {
+ control_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
+ if (control_addr == NULL) {
+ printk(UM_KERN_ERR "daemon open:cannot allocate control addr");
+ goto unix_cleanup;
+ }
+ control_addr->sun_family = AF_UNIX;
+ memcpy(control_addr->sun_path, dst, strlen(dst) + 1);
+ }
+
+ if (connect(result->control_fd, (struct sockaddr *) control_addr, sizeof(*control_addr)) < 0) {
+ printk(UM_KERN_ERR "daemon_open : control connect failed, " "errno = %d\n", -errno);
+ goto unix_cleanup;
+ }
+ req.magic = SWITCH_MAGIC;
+ req.version = SWITCH_VERSION;
+ req.type = REQ_NEW_CONTROL;
+ req.sock = *local_addr;
+
+ n = write(result->control_fd, &req, sizeof(req));
+ if (n != sizeof(req)) {
+ printk(UM_KERN_ERR "daemon_open : control setup request "
+ "failed, err = %d\n", -errno);
+ goto unix_cleanup;
+ }
+ n = read(result->control_fd, remote_addr, sizeof(struct sockaddr_un));
+ if (n != sizeof(struct sockaddr_un)) {
+ printk(UM_KERN_ERR "daemon_open : read of data socket failed, "
+ "err = %d\n", -errno);
+ goto unix_cleanup;
+ }
+ socktype = SOCK_DGRAM;
+
+ break;
case ID_BESS:
socktype = SOCK_SEQPACKET;
if ((src != NULL) && (strlen(src) <= MAX_UN_LEN)) {
@@ -374,14 +460,27 @@ static struct vector_fds *user_init_unix_fds(struct arglist *ifspec, int id)
result->tx_fd = fd;
result->remote_addr_size = sizeof(struct sockaddr_un);
result->remote_addr = remote_addr;
+
+ if (control_addr != NULL)
+ kfree(control_addr);
+ if (local_addr != NULL)
+ kfree(local_addr);
+
return result;
unix_cleanup:
if (fd >= 0)
os_close_file(fd);
if (remote_addr != NULL)
kfree(remote_addr);
- if (result != NULL)
+ if (control_addr != NULL)
+ kfree(control_addr);
+ if (local_addr != NULL)
+ kfree(local_addr);
+ if (result != NULL) {
+ if (result->control_fd > 0)
+ close(result->control_fd);
kfree(result);
+ }
return NULL;
}
@@ -422,6 +521,7 @@ static struct vector_fds *user_init_raw_fds(struct arglist *ifspec)
if (result != NULL) {
result->rx_fd = rxfd;
result->tx_fd = txfd;
+ result->control_fd = -1;
result->remote_addr = NULL;
result->remote_addr_size = 0;
}
@@ -677,6 +777,8 @@ struct vector_fds *uml_vector_user_open(
return user_init_socket_fds(parsed, ID_L2TPV3);
if (strncmp(transport, TRANS_BESS, TRANS_BESS_LEN) == 0)
return user_init_unix_fds(parsed, ID_BESS);
+ if (strncmp(transport, TRANS_DAEMON, TRANS_DAEMON_LEN) == 0)
+ return user_init_unix_fds(parsed, ID_DAEMON);
if (strncmp(transport, TRANS_UCAST, TRANS_UCAST_LEN) == 0)
return user_init_socket_fds(parsed, ID_UCAST);
if (strncmp(transport, TRANS_MCAST, TRANS_MCAST_LEN) == 0)
@@ -34,6 +34,9 @@
#define TRANS_MCAST "mcast"
#define TRANS_MCAST_LEN strlen(TRANS_MCAST)
+#define TRANS_DAEMON "daemon"
+#define TRANS_DAEMON_LEN strlen(TRANS_MCAST)
+
#define DEFAULT_BPF_LEN 6
#ifndef IPPROTO_GRE
@@ -71,6 +74,7 @@ struct vector_fds {
int tx_fd;
void *remote_addr;
int remote_addr_size;
+ int control_fd;
};
#define VECTOR_READ 1