mirror of
https://github.com/xen-project/xen.git
synced 2026-10-30 03:00:05 +01:00
bitkeeper revision 1.1236.12.25 (422f282953v_J4bTBy1CN1Z9x3rhog)
.del-util.c~fb55f547242f9869: Delete: tools/x2d2/util.c .del-minixend.h~9bba8a3fbfa4153: Delete: tools/x2d2/minixend.h .del-minixend.c~ef5576bb71152607: Delete: tools/x2d2/minixend.c .del-cntrl_con.c~9df6acbfc777c229: Delete: tools/x2d2/cntrl_con.c .del-Makefile~7ab0b94e34972cb0: Delete: tools/x2d2/Makefile
This commit is contained in:
1 parent
1593fed993
commit
fffb91d4d8
6 files changed
-1709
No files matched your search
@@ -850,11 +850,6 @@
|
||||
41a2188ar6_vOO3_tEJQjmFVU3409A tools/vnet/vnetd/vcache.h
|
||||
41a2188aETrGU60X9WtGhYVfU7z0Pw tools/vnet/vnetd/vnetd.c
|
||||
41a2188ahYjemudGyB7078AWMFR-0w tools/vnet/vnetd/vnetd.h
|
||||
4194e861IgTabTt8HOuh143QIJFD1Q tools/x2d2/Makefile
|
||||
4194e861M2gcBz4i94cQYpqzi8n6UA tools/x2d2/cntrl_con.c
|
||||
4194e8612TrrMvC8ZlA4h2ZYCPWz4g tools/x2d2/minixend.c
|
||||
4194e861x2eqNCD61RYPCUEBVdMYuw tools/x2d2/minixend.h
|
||||
4194e861A4V9VbD_FYmgXpYEj5YwVg tools/x2d2/util.c
|
||||
41d58ba63w1WfBmd6Cr_18nhLNv7PA tools/xcs/Makefile
|
||||
41d58ba6NxgkfzD_rmsGjgd_zJ3H_w tools/xcs/bindings.c
|
||||
41d58ba6I2umi60mShq4Pl0RDg7lzQ tools/xcs/connection.c
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
XEN_ROOT=../..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
CC = gcc
|
||||
CFLAGS += -Wall -Werror -O3 -fno-strict-aliasing
|
||||
|
||||
CFLAGS += -I $(XEN_XC)
|
||||
CFLAGS += -I $(XEN_LIBXC)
|
||||
CFLAGS += -I $(XEN_LIBXUTIL)
|
||||
|
||||
HDRS = $(wildcard *.h)
|
||||
OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
|
||||
|
||||
BIN = minixend
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
clean:
|
||||
$(RM) *.a *.so *.o *.rpm $(BIN)
|
||||
|
||||
$(BIN): $(OBJS)
|
||||
$(CC) $(CFLAGS) $^ -o $@ -L$(XEN_LIBXC) -L$(XEN_LIBXUTIL) -lxc -lxutil -lpthread
|
||||
@@ -1,457 +0,0 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "minixend.h"
|
||||
|
||||
struct command {
|
||||
const char *name;
|
||||
void (*func)(struct open_connection *oc, const struct command *c,
|
||||
const char *, const char *);
|
||||
};
|
||||
|
||||
static void
|
||||
domain_created(const char *name, int mem_kb, int domid)
|
||||
{
|
||||
struct domain *d;
|
||||
d = xmalloc(sizeof(*d));
|
||||
d->domid = domid;
|
||||
d->name = xstrdup(name);
|
||||
d->mem_kb = mem_kb;
|
||||
d->state = DOM_STATE_CREATED;
|
||||
d->control_evtchn = -1; /* Not connected yet. */
|
||||
|
||||
memcpy(d->netif_mac, "\xaa\x00\x00\x02\x00\x00", 6);
|
||||
d->netif_mac[5] = d->domid;
|
||||
|
||||
pthread_mutex_init(&d->mux, NULL);
|
||||
pthread_cond_init(&d->cond, NULL);
|
||||
pthread_create(&d->thread, NULL, domain_thread_func, d);
|
||||
|
||||
list_insert_after(&d->domain_list, &head_domain);
|
||||
}
|
||||
|
||||
static struct domain *
|
||||
find_domain(int domain_id)
|
||||
{
|
||||
struct domain *d;
|
||||
|
||||
foreach_domain(d) {
|
||||
if (d->domid == domain_id)
|
||||
return d;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
free_event_port(struct domain *d, int port)
|
||||
{
|
||||
if (d == NULL)
|
||||
return xc_evtchn_close(xc_handle, DOMID_SELF, port);
|
||||
else
|
||||
return xc_evtchn_close(xc_handle, d->domid, port);
|
||||
}
|
||||
|
||||
static char *
|
||||
readline(struct open_connection *oc)
|
||||
{
|
||||
char *end;
|
||||
char *res;
|
||||
int line_length;
|
||||
|
||||
if (oc->state == OC_STATE_ERROR)
|
||||
return NULL;
|
||||
|
||||
end = memchr(oc->buf, '\r', oc->buf_used);
|
||||
assert(end != NULL);
|
||||
line_length = end - oc->buf;
|
||||
|
||||
res = xmalloc(line_length + 1);
|
||||
memcpy(res, oc->buf, line_length);
|
||||
res[line_length] = 0;
|
||||
memmove(oc->buf, oc->buf + line_length + 2,
|
||||
oc->buf_used - line_length - 2);
|
||||
|
||||
oc->buf_used -= line_length + 2;
|
||||
|
||||
if (memchr(oc->buf, '\n', oc->buf_used))
|
||||
oc->state = OC_STATE_COMMAND_PENDING;
|
||||
else
|
||||
oc->state = OC_STATE_CONNECTED;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
find_domain_shared_info_mfn(struct domain *d)
|
||||
{
|
||||
xc_dominfo_t info;
|
||||
|
||||
xc_domain_getinfo(xc_handle, d->domid, 1, &info);
|
||||
return info.shared_info_frame;
|
||||
}
|
||||
|
||||
static void
|
||||
send_message(struct open_connection *oc, const char *fmt, ...)
|
||||
{
|
||||
char *buf;
|
||||
va_list ap;
|
||||
int size;
|
||||
int off;
|
||||
ssize_t r;
|
||||
|
||||
if (oc->state == OC_STATE_ERROR)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
size = vasprintf(&buf, fmt, ap);
|
||||
va_end(ap);
|
||||
if (size < 0)
|
||||
err(1, "preparing response to a query");
|
||||
assert(buf[0] == 'E' || buf[0] == 'N');
|
||||
assert(isdigit(buf[1]));
|
||||
assert(isdigit(buf[2]));
|
||||
assert(buf[3] == ' ' || buf[3] == '\n');
|
||||
|
||||
off = 0;
|
||||
while (off < size) {
|
||||
r = write(oc->fd, buf + off, size - off);
|
||||
if (r < 0) {
|
||||
warn("sending response to remote");
|
||||
oc->state = OC_STATE_ERROR;
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
off += r;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static void
|
||||
default_command_handler(struct open_connection *oc, const struct command *ign,
|
||||
const char *buf, const char *args)
|
||||
{
|
||||
warnx("bad command %s", buf);
|
||||
send_message(oc, "E00 unknown command %s\n", buf);
|
||||
}
|
||||
|
||||
static void
|
||||
create_command_handler(struct open_connection *oc, const struct command *ign,
|
||||
const char *buf, const char *args)
|
||||
{
|
||||
char *name;
|
||||
unsigned mem_kb;
|
||||
int r;
|
||||
u32 domid = -1;
|
||||
|
||||
r = sscanf(args, "%d %a[^\n]", &mem_kb, &name);
|
||||
if (r != 2) {
|
||||
send_message(oc, "E01 failed to parse %s\n", args);
|
||||
return;
|
||||
}
|
||||
r = xc_domain_create(xc_handle, mem_kb, -1, 0, &domid);
|
||||
if (r < 0) {
|
||||
send_message(oc, "E02 creating domain (%s)\n",
|
||||
strerror(errno));
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
|
||||
domain_created(name, mem_kb, domid);
|
||||
|
||||
send_message(oc, "N00 %d\n", domid);
|
||||
free(name);
|
||||
}
|
||||
|
||||
static void
|
||||
build_command_handler(struct open_connection *oc, const struct command *ign,
|
||||
const char *buf, const char *args)
|
||||
{
|
||||
struct domain *d;
|
||||
int domain_id;
|
||||
char *image, *cmdline;
|
||||
int event_ports[2];
|
||||
int r;
|
||||
|
||||
r = sscanf(args, "%d %a[^\t] %a[^\n]", &domain_id,
|
||||
&image, &cmdline);
|
||||
if (r != 3) {
|
||||
send_message(oc, "E03 failed to parse %s\n", args);
|
||||
return;
|
||||
}
|
||||
d = find_domain(domain_id);
|
||||
if (d == NULL) {
|
||||
send_message(oc, "E04 unknown domain %d\n", domain_id);
|
||||
goto out;
|
||||
}
|
||||
if (d->state != DOM_STATE_CREATED) {
|
||||
send_message(oc, "E05 domain %d in bad state\n", domain_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = allocate_event_channel(d, event_ports);
|
||||
if (r < 0) {
|
||||
send_message(oc, "E06 allocating control event channel: %s\n",
|
||||
strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = xc_linux_build(xc_handle, domain_id, image, NULL, cmdline,
|
||||
event_ports[1], 0);
|
||||
if (r < 0) {
|
||||
send_message(oc, "E07 building domain: %s\n",
|
||||
strerror(errno));
|
||||
free_event_port(NULL, event_ports[0]);
|
||||
free_event_port(d, event_ports[1]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ioctl(evtchn_fd, EVTCHN_BIND, event_ports[0]) < 0)
|
||||
err(1, "binding to event control event channel");
|
||||
|
||||
d->shared_info_mfn = find_domain_shared_info_mfn(d);
|
||||
d->shared_info = map_domain_mem(d, d->shared_info_mfn);
|
||||
if (d->shared_info == NULL)
|
||||
err(1, "maping domain shared info page at %lx.\n",
|
||||
d->shared_info_mfn);
|
||||
d->ctrl_if = (control_if_t *)((unsigned)d->shared_info + 2048);
|
||||
|
||||
d->control_evtchn = event_ports[0];
|
||||
d->state = DOM_STATE_PAUSED;
|
||||
|
||||
send_message(oc, "N00\n");
|
||||
|
||||
out:
|
||||
free(image);
|
||||
free(cmdline);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
unpause_command_handler(struct open_connection *oc,
|
||||
const struct command *ign,
|
||||
const char *buf,
|
||||
const char *args)
|
||||
{
|
||||
int domain_id;
|
||||
int r;
|
||||
struct domain *d;
|
||||
|
||||
r = sscanf(args, "%d", &domain_id);
|
||||
if (r != 1) {
|
||||
send_message(oc, "E08 cannot parse %s\n", args);
|
||||
return;
|
||||
}
|
||||
d = find_domain(domain_id);
|
||||
if (d == NULL) {
|
||||
send_message(oc, "E09 cannot find domain %d\n", domain_id);
|
||||
return;
|
||||
}
|
||||
if (d->state != DOM_STATE_PAUSED) {
|
||||
send_message(oc, "E10 domain not paused\n");
|
||||
return;
|
||||
}
|
||||
|
||||
r = xc_domain_unpause(xc_handle, d->domid);
|
||||
if (r < 0) {
|
||||
send_message(oc, "E11 unpausing domain: %s\n",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
d->state = DOM_STATE_RUNNING;
|
||||
send_message(oc, "N00\n");
|
||||
}
|
||||
|
||||
static void
|
||||
console_command_handler(struct open_connection *oc,
|
||||
const struct command *ign,
|
||||
const char *buf,
|
||||
const char *args)
|
||||
{
|
||||
int domain_id;
|
||||
struct domain *d;
|
||||
int r;
|
||||
struct sockaddr_in name;
|
||||
socklen_t namelen;
|
||||
|
||||
r = sscanf(args, "%d", &domain_id);
|
||||
if (r != 1) {
|
||||
send_message(oc, "E12 cannot parse %s\n", args);
|
||||
return;
|
||||
}
|
||||
d = find_domain(domain_id);
|
||||
if (d == NULL) {
|
||||
send_message(oc, "E13 cannot find domain %d\n", domain_id);
|
||||
return;
|
||||
}
|
||||
if (d->cc != NULL) {
|
||||
send_message(oc, "E14 console already exists\n");
|
||||
return;
|
||||
}
|
||||
|
||||
d->cc = xmalloc(sizeof(*d->cc));
|
||||
d->cc->fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (d->cc->fd < 0)
|
||||
err(1, "creating console socket");
|
||||
d->cc->dom = d;
|
||||
d->cc->state = CC_STATE_PENDING;
|
||||
d->cc->buf_used = 0;
|
||||
d->cc->buf_allocated = 0;
|
||||
d->cc->buf = NULL;
|
||||
|
||||
r = listen(d->cc->fd, 1);
|
||||
if (r < 0)
|
||||
err(1, "listening on console socket");
|
||||
namelen = sizeof(name);
|
||||
r = getsockname(d->cc->fd, (struct sockaddr *)&name, &namelen);
|
||||
if (r < 0)
|
||||
err(1, "getting name of console socket");
|
||||
assert(name.sin_family == AF_INET);
|
||||
assert(namelen == sizeof(name));
|
||||
list_insert_after(&d->cc->list, &head_console);
|
||||
send_message(oc, "N00 %d\n", ntohs(name.sin_port));
|
||||
}
|
||||
|
||||
static void
|
||||
plug_command_handler(struct open_connection *oc,
|
||||
const struct command *ign,
|
||||
const char *buf,
|
||||
const char *args)
|
||||
{
|
||||
unsigned domid;
|
||||
int r;
|
||||
struct domain *d;
|
||||
|
||||
r = sscanf(args, "%d", &domid);
|
||||
if (r != 1) {
|
||||
send_message(oc, "E15 cannot parse %s\n", args);
|
||||
return;
|
||||
}
|
||||
d = find_domain(domid);
|
||||
if (d == NULL) {
|
||||
send_message(oc, "E16 cannot find domain %d\n", domid);
|
||||
return;
|
||||
}
|
||||
|
||||
d->plugged = 1;
|
||||
send_message(oc, "N00\n");
|
||||
PRINTF(1, "set domain %d plug state to %d\n", d->domid, d->plugged);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_command_handler(struct open_connection *oc,
|
||||
const struct command *ign,
|
||||
const char *buf,
|
||||
const char *args)
|
||||
{
|
||||
unsigned domid;
|
||||
int r;
|
||||
struct domain *d;
|
||||
|
||||
r = sscanf(args, "%d", &domid);
|
||||
if (r != 1) {
|
||||
send_message(oc, "E17 cannot parse %s\n", args);
|
||||
return;
|
||||
}
|
||||
d = find_domain(domid);
|
||||
if (d == NULL) {
|
||||
send_message(oc, "E18 cannot find domain %d\n", domid);
|
||||
return;
|
||||
}
|
||||
|
||||
r = xc_domain_destroy(xc_handle, domid);
|
||||
if (r < 0) {
|
||||
send_message( oc, "E19 error destroying domain %d: %s\n",
|
||||
domid, strerror(errno) );
|
||||
return;
|
||||
}
|
||||
d->state = DOM_STATE_DEAD;
|
||||
|
||||
send_message(oc, "N00\n");
|
||||
}
|
||||
|
||||
static void
|
||||
list_command_handler(struct open_connection *oc,
|
||||
const struct command *ign,
|
||||
const char *buf,
|
||||
const char *args)
|
||||
{
|
||||
struct domain *d;
|
||||
static const char *const state_strings[] = {
|
||||
[DOM_STATE_CREATED] = "created",
|
||||
[DOM_STATE_PAUSED] = "paused",
|
||||
[DOM_STATE_RUNNING] = "running",
|
||||
[DOM_STATE_DEAD] = "dead"
|
||||
};
|
||||
|
||||
foreach_domain(d) {
|
||||
send_message(oc, "N01 %d %s %d %s\n",
|
||||
d->domid,
|
||||
d->name,
|
||||
d->mem_kb,
|
||||
state_strings[d->state]);
|
||||
}
|
||||
send_message(oc, "N00\n");
|
||||
}
|
||||
|
||||
static struct command
|
||||
default_command = { NULL, default_command_handler };
|
||||
|
||||
static struct command
|
||||
commands[] = {
|
||||
{ "build", build_command_handler },
|
||||
{ "console", console_command_handler },
|
||||
{ "create", create_command_handler },
|
||||
{ "destroy", destroy_command_handler },
|
||||
{ "plug", plug_command_handler },
|
||||
{ "list", list_command_handler },
|
||||
{ "unpause", unpause_command_handler }
|
||||
};
|
||||
|
||||
void
|
||||
process_command(struct open_connection *oc)
|
||||
{
|
||||
char *buf, *b;
|
||||
int command_len;
|
||||
int x;
|
||||
struct command *cmd;
|
||||
|
||||
buf = readline(oc);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
b = strchr(buf, ' ');
|
||||
if (b == NULL)
|
||||
command_len = strlen(buf);
|
||||
else
|
||||
command_len = b - buf;
|
||||
b = buf + command_len;
|
||||
while (b[0] && b[0] == ' ')
|
||||
b++;
|
||||
|
||||
cmd = &default_command;
|
||||
for (x = 0; x < sizeof(commands) / sizeof(commands[0]); x++) {
|
||||
if (strlen(commands[x].name) == command_len &&
|
||||
memcmp(commands[x].name, buf, command_len) == 0) {
|
||||
cmd = &commands[x];
|
||||
break;
|
||||
}
|
||||
}
|
||||
cmd->func(oc, cmd, buf, b);
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
@@ -1,939 +0,0 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <asm/page.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <printf.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "minixend.h"
|
||||
|
||||
#define NETWORK_SCRIPT "/etc/xen/scripts/network"
|
||||
#define VIFBRIDGE_SCRIPT "/etc/xen/scripts/vif-bridge"
|
||||
|
||||
#define MINIXEND_PORT 5123
|
||||
|
||||
#define mb() asm volatile ("" ::: "memory")
|
||||
|
||||
static void send_control_message(int type, int subtype, int id,
|
||||
int size, void *payload,
|
||||
struct domain *target);
|
||||
|
||||
struct list_head
|
||||
head_domain = LIST_HEAD(&head_domain);
|
||||
|
||||
static struct list_head
|
||||
head_connection = LIST_HEAD(&head_connection);
|
||||
|
||||
struct list_head
|
||||
head_console = LIST_HEAD(&head_console);
|
||||
|
||||
#define foreach_open_connection(d) \
|
||||
foreach_item(d, &head_connection, struct open_connection, connection_list)
|
||||
|
||||
/* Not modified after initial start up */
|
||||
static struct domain *dom0;
|
||||
unsigned xc_handle;
|
||||
static int listen_fd;
|
||||
int evtchn_fd;
|
||||
|
||||
static struct list_head
|
||||
head_event_receiver = LIST_HEAD(&head_event_receiver);
|
||||
|
||||
struct event_receiver {
|
||||
struct list_head list;
|
||||
int id;
|
||||
pthread_cond_t cond;
|
||||
};
|
||||
|
||||
/* We're protected by the dom0 mutex in here */
|
||||
static struct event_receiver *
|
||||
allocate_event_receiver(struct domain *d)
|
||||
{
|
||||
static int next_message_id;
|
||||
struct event_receiver *work;
|
||||
|
||||
assert(d == dom0);
|
||||
work = xmalloc(sizeof(*work));
|
||||
work->id = next_message_id++;
|
||||
pthread_cond_init(&work->cond, NULL);
|
||||
|
||||
list_insert_after(&work->list, &head_event_receiver);
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
static struct event_receiver *
|
||||
find_event_receiver(int id)
|
||||
{
|
||||
struct event_receiver *work;
|
||||
foreach_item(work, &head_event_receiver, struct event_receiver, list)
|
||||
if (work->id == id)
|
||||
return work;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
release_event_receiver(struct event_receiver *w)
|
||||
{
|
||||
list_remove(&w->list);
|
||||
pthread_cond_destroy(&w->cond);
|
||||
free(w);
|
||||
}
|
||||
|
||||
/* Send a message to dom0, and then block awaiting a reply. */
|
||||
/* Make sure we don't hold any domain mutexs */
|
||||
static void
|
||||
send_dom0_message_block(control_msg_t *msg)
|
||||
{
|
||||
CONTROL_RING_IDX c;
|
||||
struct event_receiver *er;
|
||||
control_msg_t buf;
|
||||
|
||||
PRINTF(0, "sending message to dom0 and blocking for reply.\n");
|
||||
pthread_mutex_lock(&dom0->mux);
|
||||
PRINTF(0, "got dom0 lock.\n");
|
||||
er = allocate_event_receiver(dom0);
|
||||
PRINTF(0, "allocated evetn receiver.\n");
|
||||
msg->id = er->id;
|
||||
PRINTF(1, "sending message with id %d\n", msg->id);
|
||||
send_control_message(msg->type, msg->subtype,
|
||||
msg->id, msg->length, msg->msg, dom0);
|
||||
xc_evtchn_send(xc_handle, dom0->control_evtchn);
|
||||
|
||||
PRINTF(0, "waiting for reply\n");
|
||||
pthread_cond_wait(&er->cond, &dom0->mux);
|
||||
PRINTF(0, "got reply\n");
|
||||
|
||||
c = dom0->rx_resp_cons % CONTROL_RING_SIZE;
|
||||
memcpy(&buf, &dom0->ctrl_if->rx_ring[c], sizeof(buf));
|
||||
assert(msg->id == buf.id);
|
||||
assert(msg->type == buf.type);
|
||||
assert(msg->subtype == buf.subtype);
|
||||
memcpy(msg, &buf, sizeof(*msg));
|
||||
dom0->rx_resp_cons++;
|
||||
|
||||
release_event_receiver(er);
|
||||
|
||||
pthread_mutex_unlock(&dom0->mux);
|
||||
|
||||
PRINTF(1, "got reply to message with id %d\n", msg->id);
|
||||
}
|
||||
|
||||
/* Allocate an interdomain event channel. event_ports[0] is the
|
||||
local event port number, event_ports[1] the remote */
|
||||
int
|
||||
allocate_event_channel(struct domain *d, int event_ports[2])
|
||||
{
|
||||
return xc_evtchn_bind_interdomain(xc_handle, DOMID_SELF,
|
||||
d->domid, event_ports,
|
||||
event_ports+1);
|
||||
}
|
||||
|
||||
static void
|
||||
accept_new_connection(void)
|
||||
{
|
||||
int fd;
|
||||
struct open_connection *oc;
|
||||
|
||||
fd = accept(listen_fd, NULL, NULL);
|
||||
if (fd < 0)
|
||||
return;
|
||||
oc = xmalloc(sizeof(*oc));
|
||||
oc->fd = fd;
|
||||
oc->state = OC_STATE_CONNECTED;
|
||||
oc->buf_used = 0;
|
||||
oc->buf_allocated = 16;
|
||||
oc->buf = xmalloc(oc->buf_allocated);
|
||||
list_insert_after(&oc->connection_list, &head_connection);
|
||||
}
|
||||
|
||||
static void
|
||||
closedown_connection(struct open_connection *oc)
|
||||
{
|
||||
close(oc->fd);
|
||||
assert(oc->buf);
|
||||
free(oc->buf);
|
||||
free(oc);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Hackl for the benefit of domain replay */
|
||||
static unsigned
|
||||
report_work(u32 *ptr, u32 val, unsigned dom, int do_direct)
|
||||
{
|
||||
if (!do_direct) {
|
||||
int rc;
|
||||
asm("int $0x80" : "=a" (rc)
|
||||
: "0" (264), "b" (ptr), "c" (val), "d" (dom));
|
||||
if (rc < 0) {
|
||||
errno = -rc;
|
||||
rc = -1;
|
||||
}
|
||||
return rc;
|
||||
} else {
|
||||
*ptr = val;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static unsigned
|
||||
report_work(u32 *ptr, u32 val, unsigned dom, int do_direct)
|
||||
{
|
||||
*ptr = val;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
send_control_reply(const control_msg_t *msg, struct domain *d)
|
||||
{
|
||||
CONTROL_RING_IDX c;
|
||||
|
||||
PRINTF(3,"Control reply, type %d:%d, length %d.\n",
|
||||
msg->type, msg->subtype, msg->length);
|
||||
c = d->ctrl_if->tx_resp_prod % CONTROL_RING_SIZE;
|
||||
memcpy(&d->ctrl_if->tx_ring[c], msg, sizeof(*msg));
|
||||
report_work(&d->ctrl_if->tx_resp_prod,
|
||||
d->ctrl_if->tx_resp_prod + 1,
|
||||
d->domid,
|
||||
0);
|
||||
PRINTF(4,"tx_resp_prod %ld.\n", d->ctrl_if->tx_resp_prod);
|
||||
assert(!d->plugged);
|
||||
}
|
||||
|
||||
static void
|
||||
send_trivial_control_reply(const control_msg_t *msg, struct domain *d)
|
||||
{
|
||||
control_msg_t rep;
|
||||
|
||||
memset(&rep, 0, sizeof(rep));
|
||||
rep.type = msg->type;
|
||||
rep.subtype = msg->subtype;
|
||||
rep.id = msg->id;
|
||||
send_control_reply(&rep, d);
|
||||
}
|
||||
|
||||
static void
|
||||
process_console_control_message(control_msg_t *m, struct domain *d)
|
||||
{
|
||||
int off;
|
||||
int r;
|
||||
|
||||
if (m->subtype != CMSG_CONSOLE_DATA) {
|
||||
warnx("unknown console message subtype %d",
|
||||
m->subtype);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m->length > 60) {
|
||||
warnx("truncating message from domain %d (was length %d)",
|
||||
d->domid, m->length);
|
||||
m->length = 60;
|
||||
}
|
||||
PRINTF(1, "DOM%d: %.*s\n", d->domid, m->length, m->msg);
|
||||
send_trivial_control_reply(m, d);
|
||||
|
||||
if (d->cc) {
|
||||
PRINTF(5, "Have a console connection.\n");
|
||||
if (d->cc->state == CC_STATE_CONNECTED) {
|
||||
PRINTF(5, "Console is connected, sending directly.\n");
|
||||
for (off = 0; off < m->length; off += r) {
|
||||
r = write(d->cc->fd, m->msg + off,
|
||||
m->length - off);
|
||||
if (r <= 0) {
|
||||
d->cc->state = CC_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PRINTF(5, "Console not connected, buffering.\n");
|
||||
if (d->cc->buf_allocated == 0) {
|
||||
d->cc->buf_allocated = 60;
|
||||
d->cc->buf = xmalloc(d->cc->buf_allocated);
|
||||
d->cc->buf_used = 0;
|
||||
} else if (d->cc->buf_allocated <
|
||||
d->cc->buf_used + m->length) {
|
||||
d->cc->buf_allocated += 60;
|
||||
d->cc->buf = xrealloc(d->cc->buf,
|
||||
d->cc->buf_allocated);
|
||||
}
|
||||
assert(d->cc->buf_allocated >=
|
||||
d->cc->buf_used + m->length);
|
||||
memcpy(d->cc->buf + d->cc->buf_used,
|
||||
m->msg,
|
||||
m->length);
|
||||
d->cc->buf_used += m->length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
process_blkif_fe_message(control_msg_t *m, struct domain *d)
|
||||
{
|
||||
switch (m->subtype) {
|
||||
default:
|
||||
warnx("unknown blkif front end message subtype %d",
|
||||
m->subtype);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
send_control_message(int type, int subtype, int id,
|
||||
int size, void *payload, struct domain *target)
|
||||
{
|
||||
control_msg_t msg;
|
||||
CONTROL_RING_IDX c;
|
||||
|
||||
msg.type = type;
|
||||
msg.subtype = subtype;
|
||||
msg.id = id;
|
||||
msg.length = size;
|
||||
memcpy(msg.msg, payload, size);
|
||||
|
||||
c = target->ctrl_if->rx_req_prod % CONTROL_RING_SIZE;
|
||||
memcpy(&target->ctrl_if->rx_ring[c], &msg, sizeof(msg));
|
||||
report_work(&target->ctrl_if->rx_req_prod,
|
||||
target->ctrl_if->rx_req_prod + 1,
|
||||
target->domid,
|
||||
0);
|
||||
assert(!target->plugged);
|
||||
}
|
||||
|
||||
/* Procedure for bringing a new netif front end up:
|
||||
|
||||
-- Front end sends us NETIF_FE_DRIVER_STATUS_CHANGED
|
||||
-- We send back end NETIF_BE_CREATE, wait for a reply
|
||||
-- Back end creates a new netif for us, replies
|
||||
-- We send front end a NETIF_FE_DRIVER_STATUS_CHANGED message saying
|
||||
how many interfaces we've created for it
|
||||
-- We send front end a NETIF_FE_INTERFACE_STATUS_CHANGED for each
|
||||
netif created
|
||||
-- Front end sends us a NETIF_FE_INTERFACE_CONNECT for each netif
|
||||
*/
|
||||
static void
|
||||
handle_netif_fe_driver_status(control_msg_t *m,
|
||||
netif_fe_driver_status_t *sh,
|
||||
struct domain *d)
|
||||
{
|
||||
netif_fe_interface_status_t if_s;
|
||||
control_msg_t be_msg;
|
||||
netif_be_create_t *be = (void *)be_msg.msg;
|
||||
int r;
|
||||
|
||||
switch (sh->status) {
|
||||
case NETIF_DRIVER_STATUS_UP:
|
||||
/* Tell the back end about the new interface coming
|
||||
* up. */
|
||||
if (d->created_netif_backend) {
|
||||
send_control_reply(m, d);
|
||||
send_control_message(CMSG_NETIF_FE,
|
||||
CMSG_NETIF_FE_DRIVER_STATUS,
|
||||
1,
|
||||
sizeof(*sh),
|
||||
sh,
|
||||
d);
|
||||
return;
|
||||
}
|
||||
be_msg.type = CMSG_NETIF_BE;
|
||||
be_msg.subtype = CMSG_NETIF_BE_CREATE;
|
||||
be_msg.id = d->domid;
|
||||
be_msg.length = sizeof(*be);
|
||||
be->domid = d->domid;
|
||||
be->netif_handle = 0;
|
||||
memcpy(be->mac, d->netif_mac, 6);
|
||||
|
||||
PRINTF(2,"Telling back end about new front end.\n");
|
||||
pthread_mutex_unlock(&d->mux);
|
||||
send_dom0_message_block(&be_msg);
|
||||
pthread_mutex_lock(&d->mux);
|
||||
PRINTF(3,"Done.\n");
|
||||
|
||||
if (be->status != NETIF_BE_STATUS_OKAY) {
|
||||
/* Uh oh... can't bring back end
|
||||
* up. */
|
||||
send_control_reply(m, d);
|
||||
send_control_message(CMSG_NETIF_FE,
|
||||
CMSG_NETIF_FE_DRIVER_STATUS,
|
||||
1,
|
||||
sizeof(*sh),
|
||||
sh,
|
||||
d);
|
||||
return;
|
||||
}
|
||||
d->created_netif_backend = 1;
|
||||
|
||||
r = our_system(VIFBRIDGE_SCRIPT " up domain=%s mac=%.02x:%.02x:%.02x:%.02x:%.02x:%.02x vif=vif%d.0 bridge=xen-br0",
|
||||
d->name,
|
||||
d->netif_mac[0],
|
||||
d->netif_mac[1],
|
||||
d->netif_mac[2],
|
||||
d->netif_mac[3],
|
||||
d->netif_mac[4],
|
||||
d->netif_mac[5],
|
||||
d->domid);
|
||||
if (r != 0)
|
||||
warn("error %d running " VIFBRIDGE_SCRIPT, r);
|
||||
|
||||
/* Tell domain how many interfaces it has to deal
|
||||
* with. */
|
||||
send_control_reply(m, d);
|
||||
send_control_message(CMSG_NETIF_FE,
|
||||
CMSG_NETIF_FE_DRIVER_STATUS,
|
||||
1,
|
||||
sizeof(*sh),
|
||||
sh,
|
||||
d);
|
||||
|
||||
PRINTF(2,"Telling front end about its interfaces.\n");
|
||||
if_s.handle = 0;
|
||||
if_s.status = NETIF_INTERFACE_STATUS_DISCONNECTED;
|
||||
send_control_message(CMSG_NETIF_FE,
|
||||
CMSG_NETIF_FE_INTERFACE_STATUS,
|
||||
1,
|
||||
sizeof(if_s),
|
||||
&if_s,
|
||||
d);
|
||||
PRINTF(3,"Done.\n");
|
||||
|
||||
break;
|
||||
default:
|
||||
warnx("unknown netif status %ld", sh->status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_netif_fe_interface_connect(control_msg_t *m,
|
||||
netif_fe_interface_connect_t *ic,
|
||||
struct domain *d)
|
||||
{
|
||||
control_msg_t be_msg;
|
||||
netif_be_connect_t *bmsg = (void *)be_msg.msg;
|
||||
netif_fe_interface_status_t fmsg = {0};
|
||||
int evtchn_ports[2];
|
||||
int r;
|
||||
|
||||
PRINTF(4, "front end sent us an interface connect message.\n");
|
||||
send_trivial_control_reply(m, d);
|
||||
|
||||
r = xc_evtchn_bind_interdomain(xc_handle,
|
||||
dom0->domid,
|
||||
d->domid,
|
||||
&evtchn_ports[0],
|
||||
&evtchn_ports[1]);
|
||||
if (r < 0)
|
||||
err(1, "allocating network event channel");
|
||||
|
||||
be_msg.type = CMSG_NETIF_BE;
|
||||
be_msg.subtype = CMSG_NETIF_BE_CONNECT;
|
||||
be_msg.id = 0;
|
||||
be_msg.length = sizeof(*bmsg);
|
||||
bmsg->domid = d->domid;
|
||||
bmsg->netif_handle = ic->handle;
|
||||
bmsg->tx_shmem_frame = ic->tx_shmem_frame;
|
||||
bmsg->rx_shmem_frame = ic->rx_shmem_frame;
|
||||
bmsg->evtchn = evtchn_ports[0];
|
||||
|
||||
pthread_mutex_unlock(&d->mux);
|
||||
send_dom0_message_block(&be_msg);
|
||||
pthread_mutex_lock(&d->mux);
|
||||
|
||||
if (bmsg->status != NETIF_BE_STATUS_OKAY) {
|
||||
PRINTF(2, "error connected backend netif: %ld\n",
|
||||
bmsg->status);
|
||||
abort(); /* Need to handle this */
|
||||
} else {
|
||||
PRINTF(3, "connect backend netif\n");
|
||||
|
||||
/* Tell the domain that we've connected it up. */
|
||||
fmsg.handle = ic->handle;
|
||||
fmsg.status = NETIF_INTERFACE_STATUS_CONNECTED;
|
||||
fmsg.evtchn = evtchn_ports[1];
|
||||
memcpy(fmsg.mac, d->netif_mac, 6);
|
||||
|
||||
send_control_message(CMSG_NETIF_FE,
|
||||
CMSG_NETIF_FE_INTERFACE_STATUS,
|
||||
0,
|
||||
sizeof(fmsg),
|
||||
&fmsg,
|
||||
d);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
process_netif_fe_message(control_msg_t *m, struct domain *d)
|
||||
{
|
||||
switch (m->subtype) {
|
||||
case CMSG_NETIF_FE_DRIVER_STATUS:
|
||||
{
|
||||
netif_fe_driver_status_t *sh =
|
||||
(netif_fe_driver_status_t *)m->msg;
|
||||
handle_netif_fe_driver_status(m, sh, d);
|
||||
break;
|
||||
}
|
||||
case CMSG_NETIF_FE_INTERFACE_CONNECT:
|
||||
{
|
||||
netif_fe_interface_connect_t *ic =
|
||||
(netif_fe_interface_connect_t *)m->msg;
|
||||
handle_netif_fe_interface_connect(m, ic, d);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
warnx("unknown netif front end message subtype %d",
|
||||
m->subtype);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
process_control_message(control_msg_t *msg, struct domain *d)
|
||||
{
|
||||
control_msg_t m;
|
||||
|
||||
/* Don't want a malicous domain messing us about, so copy the
|
||||
control mesasge into a local buffer. */
|
||||
memcpy(&m, msg, sizeof(m));
|
||||
switch (m.type) {
|
||||
case CMSG_CONSOLE:
|
||||
process_console_control_message(&m, d);
|
||||
break;
|
||||
case CMSG_BLKIF_FE:
|
||||
process_blkif_fe_message(&m, d);
|
||||
break;
|
||||
case CMSG_NETIF_FE:
|
||||
process_netif_fe_message(&m, d);
|
||||
break;
|
||||
default:
|
||||
warnx("unknown control message type %d", m.type);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
domain_did_control_event(struct domain *d)
|
||||
{
|
||||
CONTROL_RING_IDX c;
|
||||
|
||||
/* Pick up and process control ring messages. */
|
||||
while (d->tx_req_cons != d->ctrl_if->tx_req_prod) {
|
||||
c = d->tx_req_cons % CONTROL_RING_SIZE;
|
||||
process_control_message(&d->ctrl_if->tx_ring[c], d);
|
||||
d->tx_req_cons++;
|
||||
assert(d->tx_req_cons <= d->ctrl_if->tx_req_prod);
|
||||
PRINTF(5, "req_cons %ld, req_prod %ld.\n",
|
||||
d->tx_req_cons, d->ctrl_if->tx_req_prod);
|
||||
}
|
||||
|
||||
/* Take any replies off, and discard them. */
|
||||
if (d->rx_resp_cons != d->ctrl_if->rx_resp_prod)
|
||||
PRINTF(1, "discard %ld events\n",
|
||||
d->ctrl_if->rx_resp_prod -
|
||||
d->rx_resp_cons);
|
||||
d->rx_resp_cons = d->ctrl_if->rx_resp_prod;
|
||||
}
|
||||
|
||||
/* This is the main function for domain control threads */
|
||||
void *
|
||||
domain_thread_func(void *D)
|
||||
{
|
||||
struct domain *d = D;
|
||||
int r;
|
||||
CONTROL_RING_IDX old_resp_prod, old_req_prod;
|
||||
|
||||
pthread_mutex_lock(&d->mux);
|
||||
for (;;) {
|
||||
pthread_cond_wait(&d->cond, &d->mux);
|
||||
|
||||
old_resp_prod = d->ctrl_if->tx_resp_prod;
|
||||
old_req_prod = d->ctrl_if->rx_req_prod;
|
||||
|
||||
domain_did_control_event(d);
|
||||
if (d->cc && d->cc->in_buf_used != 0 && d->plugged == 0) {
|
||||
r = d->cc->in_buf_used;
|
||||
if (r > 60)
|
||||
r = 60;
|
||||
PRINTF(1, "Sending to domain: %.*s\n",
|
||||
r, d->cc->in_buf);
|
||||
send_control_message(CMSG_CONSOLE,
|
||||
CMSG_CONSOLE_DATA,
|
||||
0,
|
||||
r,
|
||||
d->cc->in_buf,
|
||||
d);
|
||||
memmove(d->cc->in_buf, d->cc->in_buf + r,
|
||||
d->cc->in_buf_used - r);
|
||||
d->cc->in_buf_used -= r;
|
||||
}
|
||||
|
||||
if (d->ctrl_if->tx_resp_prod != old_resp_prod ||
|
||||
d->ctrl_if->rx_req_prod != old_req_prod)
|
||||
xc_evtchn_send(xc_handle, d->control_evtchn);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is the only thing you can do with a domain structure if you're
|
||||
not in the thread which controls that domain. Domain 0 is
|
||||
special. */
|
||||
void
|
||||
signal_domain(struct domain *d)
|
||||
{
|
||||
CONTROL_RING_IDX c;
|
||||
int id;
|
||||
struct event_receiver *evt;
|
||||
|
||||
pthread_mutex_lock(&d->mux);
|
||||
if (d == dom0) {
|
||||
/* Take events off of dom0's control ring, and send
|
||||
them to the event receivers. */
|
||||
while (d->tx_req_cons != d->ctrl_if->tx_req_prod) {
|
||||
c = d->tx_req_cons % CONTROL_RING_SIZE;
|
||||
id = d->ctrl_if->tx_ring[c].id;
|
||||
evt = find_event_receiver(id);
|
||||
if (evt != NULL) {
|
||||
PRINTF(1, "delivering event id %d\n", evt->id);
|
||||
pthread_cond_broadcast(&evt->cond);
|
||||
pthread_mutex_unlock(&d->mux);
|
||||
sched_yield();
|
||||
pthread_mutex_lock(&d->mux);
|
||||
} else {
|
||||
warnx("unexpected message id %d discarded",
|
||||
id);
|
||||
d->tx_req_cons++;
|
||||
}
|
||||
}
|
||||
while (d->rx_resp_cons != d->ctrl_if->rx_resp_prod) {
|
||||
c = d->rx_resp_cons % CONTROL_RING_SIZE;
|
||||
id = d->ctrl_if->rx_ring[c].id;
|
||||
evt = find_event_receiver(id);
|
||||
if (evt != NULL) {
|
||||
PRINTF(1, "delivering event rep id %d\n", evt->id);
|
||||
pthread_cond_broadcast(&evt->cond);
|
||||
pthread_mutex_unlock(&d->mux);
|
||||
sched_yield();
|
||||
pthread_mutex_lock(&d->mux);
|
||||
} else {
|
||||
warnx("unexpected message reply id %d discarded",
|
||||
id);
|
||||
d->rx_resp_cons++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (d->plugged) {
|
||||
d->event_pending = 1;
|
||||
} else {
|
||||
pthread_cond_broadcast(&d->cond);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&d->mux);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_evtchn_event(void)
|
||||
{
|
||||
short port;
|
||||
struct domain *d;
|
||||
|
||||
read(evtchn_fd, &port, sizeof(short));
|
||||
write(evtchn_fd, &port, sizeof(short));
|
||||
foreach_domain (d) {
|
||||
if (d->control_evtchn == port) {
|
||||
signal_domain(d);
|
||||
return;
|
||||
}
|
||||
}
|
||||
warnx("got an event on an unknown port %d", port);
|
||||
}
|
||||
|
||||
void *
|
||||
map_domain_mem(struct domain *d, unsigned long mfn)
|
||||
{
|
||||
return xc_map_foreign_range(xc_handle, d->domid,
|
||||
PAGE_SIZE, PROT_READ | PROT_WRITE,
|
||||
mfn);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_console_event(struct console_connection *cc)
|
||||
{
|
||||
int r;
|
||||
int fd;
|
||||
|
||||
switch (cc->state) {
|
||||
case CC_STATE_ERROR:
|
||||
/* Errors shouldn't get here. */
|
||||
abort();
|
||||
case CC_STATE_PENDING:
|
||||
fd = accept(cc->fd, NULL, NULL);
|
||||
if (fd >= 0) {
|
||||
PRINTF(3, "Accepted console connection for domain %d",
|
||||
cc->dom->domid);
|
||||
close(cc->fd);
|
||||
cc->fd = fd;
|
||||
cc->state = CC_STATE_CONNECTED;
|
||||
while (cc->buf_used != 0) {
|
||||
r = write(cc->fd,
|
||||
cc->buf,
|
||||
cc->buf_used);
|
||||
if (r <= 0) {
|
||||
cc->state = CC_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
memmove(cc->buf,
|
||||
cc->buf + r,
|
||||
cc->buf_used - r);
|
||||
cc->buf_used -= r;
|
||||
}
|
||||
free(cc->buf);
|
||||
cc->buf = NULL;
|
||||
cc->buf_allocated = 0;
|
||||
} else {
|
||||
PRINTF(1, "error %s accepting console", strerror(errno));
|
||||
}
|
||||
pthread_mutex_unlock(&cc->dom->mux);
|
||||
break;
|
||||
case CC_STATE_CONNECTED:
|
||||
if (cc->in_buf_allocated == 0) {
|
||||
assert(cc->in_buf_used == 0);
|
||||
cc->in_buf_allocated = 128;
|
||||
cc->in_buf = xmalloc(cc->in_buf_allocated);
|
||||
}
|
||||
if (cc->in_buf_used == cc->in_buf_allocated) {
|
||||
cc->in_buf_allocated *= 2;
|
||||
cc->in_buf = xrealloc(cc->in_buf, cc->in_buf_allocated);
|
||||
}
|
||||
r = read(cc->fd, cc->in_buf + cc->in_buf_used,
|
||||
cc->in_buf_allocated - cc->in_buf_used);
|
||||
if (r <= 0) {
|
||||
cc->state = CC_STATE_ERROR;
|
||||
} else {
|
||||
cc->in_buf_used += r;
|
||||
}
|
||||
pthread_mutex_unlock(&cc->dom->mux);
|
||||
signal_domain(cc->dom);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_connection_event(struct open_connection *oc)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* We know that some amount of data is ready and waiting for
|
||||
us. Slurp it in. */
|
||||
if (oc->buf_used == oc->buf_allocated) {
|
||||
oc->buf_allocated *= 2;
|
||||
oc->buf = xrealloc(oc->buf, oc->buf_allocated);
|
||||
}
|
||||
r = read(oc->fd, oc->buf + oc->buf_used,
|
||||
oc->buf_allocated - oc->buf_used);
|
||||
if (r < 0) {
|
||||
warn("reading command from remote");
|
||||
oc->state = OC_STATE_ERROR;
|
||||
} else if (r == 0) {
|
||||
warnx("reading command from remote");
|
||||
oc->state = OC_STATE_ERROR;
|
||||
} else {
|
||||
oc->buf_used += r;
|
||||
if (strchr(oc->buf, '\n'))
|
||||
oc->state = OC_STATE_COMMAND_PENDING;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_and_process_event(void)
|
||||
{
|
||||
fd_set read_fds, except_fds;
|
||||
struct open_connection *oc;
|
||||
struct console_connection *cc;
|
||||
int max_fd = listen_fd;
|
||||
int r;
|
||||
struct list_head *li, *temp_li;
|
||||
|
||||
FD_ZERO(&read_fds);
|
||||
FD_ZERO(&except_fds);
|
||||
FD_SET(listen_fd, &read_fds);
|
||||
FD_SET(evtchn_fd, &read_fds);
|
||||
if (evtchn_fd > max_fd)
|
||||
max_fd = evtchn_fd;
|
||||
foreach_open_connection(oc) {
|
||||
FD_SET(oc->fd, &read_fds);
|
||||
FD_SET(oc->fd, &except_fds);
|
||||
if (oc->fd > max_fd)
|
||||
max_fd = oc->fd;
|
||||
}
|
||||
foreach_console_connection(cc) {
|
||||
FD_SET(cc->fd, &read_fds);
|
||||
FD_SET(cc->fd, &except_fds);
|
||||
if (cc->fd > max_fd)
|
||||
max_fd = cc->fd;
|
||||
}
|
||||
|
||||
r = select(max_fd + 1, &read_fds, NULL, &except_fds, NULL);
|
||||
if (r < 0)
|
||||
err(1, "select");
|
||||
if (FD_ISSET(listen_fd, &read_fds)) {
|
||||
accept_new_connection();
|
||||
} else if (FD_ISSET(evtchn_fd, &read_fds))
|
||||
handle_evtchn_event();
|
||||
|
||||
|
||||
foreach_open_connection(oc) {
|
||||
if (FD_ISSET(oc->fd, &read_fds))
|
||||
handle_connection_event(oc);
|
||||
if (FD_ISSET(oc->fd, &except_fds))
|
||||
oc->state = OC_STATE_ERROR;
|
||||
}
|
||||
list_foreach_safe(&head_console, li, temp_li) {
|
||||
cc = list_item(li, struct console_connection, list);
|
||||
if (FD_ISSET(cc->fd, &read_fds))
|
||||
handle_console_event(cc);
|
||||
if (FD_ISSET(cc->fd, &except_fds) ||
|
||||
cc->state == CC_STATE_ERROR) {
|
||||
PRINTF(1, "Cleaning up console connection");
|
||||
cc->dom->cc = NULL;
|
||||
list_remove(&cc->list);
|
||||
close(cc->fd);
|
||||
if (cc->buf_allocated != 0)
|
||||
free(cc->buf);
|
||||
if (cc->in_buf_allocated != 0)
|
||||
free(cc->in_buf);
|
||||
free(cc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Run pending stuff on the open connections. */
|
||||
list_foreach_safe(&head_connection, li, temp_li) {
|
||||
oc = list_item(li, struct open_connection, connection_list);
|
||||
switch (oc->state) {
|
||||
case OC_STATE_ERROR:
|
||||
list_remove(&oc->connection_list);
|
||||
closedown_connection(oc);
|
||||
break;
|
||||
case OC_STATE_COMMAND_PENDING:
|
||||
process_command(oc);
|
||||
break;
|
||||
case OC_STATE_CONNECTED:
|
||||
/* Don't need to do anything */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
start_listening(void)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_in inaddr;
|
||||
|
||||
sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
err(1, "creating socket");
|
||||
memset(&inaddr, 0, sizeof(inaddr));
|
||||
inaddr.sin_family = AF_INET;
|
||||
inaddr.sin_port = htons(MINIXEND_PORT);
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
|
||||
err(1, "binding to port %d", MINIXEND_PORT);
|
||||
if (listen(sock, 5) < 0)
|
||||
err(1, "listening for connections");
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static struct domain *
|
||||
find_dom0(void)
|
||||
{
|
||||
int r;
|
||||
xc_dominfo_t info;
|
||||
struct domain *work;
|
||||
|
||||
r = xc_domain_getinfo(xc_handle, 0, 1, &info);
|
||||
if (r < 0)
|
||||
err(1, "getting domain 0 information");
|
||||
work = xmalloc(sizeof(*work));
|
||||
work->control_evtchn = 2;
|
||||
if (ioctl(evtchn_fd, EVTCHN_BIND, 2) < 0)
|
||||
err(1, "binding to domain 0 control event channel");
|
||||
|
||||
work->domid = 0;
|
||||
work->name = strdup("dom0");
|
||||
work->mem_kb = info.max_memkb;
|
||||
work->state = DOM_STATE_RUNNING;
|
||||
work->shared_info_mfn = info.shared_info_frame;
|
||||
|
||||
work->shared_info = map_domain_mem(work, info.shared_info_frame);
|
||||
work->ctrl_if = (control_if_t *)((unsigned)work->shared_info + 2048);
|
||||
work->tx_req_cons = work->ctrl_if->tx_req_prod;
|
||||
work->rx_resp_cons = work->ctrl_if->rx_resp_prod;
|
||||
|
||||
pthread_mutex_init(&work->mux, NULL);
|
||||
pthread_cond_init(&work->cond, NULL);
|
||||
|
||||
list_insert_after(&work->domain_list, &head_domain);
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int r;
|
||||
|
||||
r = our_system(NETWORK_SCRIPT " start antispoof=no");
|
||||
if (r < 0)
|
||||
err(1, "running " NETWORK_SCRIPT);
|
||||
if (!WIFEXITED(r)) {
|
||||
if (WIFSIGNALED(r)) {
|
||||
errx(1, NETWORK_SCRIPT " killed by signal %d",
|
||||
WTERMSIG(r));
|
||||
}
|
||||
errx(1, NETWORK_SCRIPT " terminated abnormally");
|
||||
}
|
||||
if (WEXITSTATUS(r) != 0)
|
||||
errx(1, NETWORK_SCRIPT " returned error status %d",
|
||||
WEXITSTATUS(r));
|
||||
|
||||
xc_handle = xc_interface_open();
|
||||
|
||||
listen_fd = start_listening();
|
||||
|
||||
evtchn_fd = open("/dev/xen/evtchn", O_RDWR);
|
||||
if (evtchn_fd < 0)
|
||||
err(1, "openning /dev/xen/evtchn");
|
||||
|
||||
dom0 = find_dom0();
|
||||
|
||||
while (1) {
|
||||
get_and_process_event();
|
||||
|
||||
PRINTF(5, "Dom0 ring state:\n");
|
||||
PRINTF(5, "RX: req_prod %ld, resp_prod %ld, resp_cons %ld\n",
|
||||
dom0->ctrl_if->rx_req_prod,
|
||||
dom0->ctrl_if->rx_resp_prod,
|
||||
dom0->rx_resp_cons);
|
||||
PRINTF(5, "TX: req_prod %ld, resp_prod %ld, req_cons %ld\n",
|
||||
dom0->ctrl_if->tx_req_prod,
|
||||
dom0->ctrl_if->tx_resp_prod,
|
||||
dom0->tx_req_cons);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
#ifndef MINIXEND_H__
|
||||
#define MINIXEND_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <xc.h>
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, **pprev;
|
||||
};
|
||||
|
||||
struct open_connection {
|
||||
struct list_head connection_list;
|
||||
int fd;
|
||||
enum {
|
||||
OC_STATE_CONNECTED,
|
||||
OC_STATE_ERROR,
|
||||
OC_STATE_COMMAND_PENDING
|
||||
} state;
|
||||
|
||||
/* Buffer of stuff coming from the remote until we get a whole
|
||||
command */
|
||||
int buf_used;
|
||||
int buf_allocated;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
struct console_connection;
|
||||
|
||||
/* Only ever accessed from the domain's controlling thread, unless
|
||||
it's dom0, in which case we perform a moderately complex dance to
|
||||
avoid needing any sort of locking at all. */
|
||||
struct domain {
|
||||
struct list_head domain_list;
|
||||
int control_evtchn; /* the local port for the doain control
|
||||
interface event channel. */
|
||||
int domid;
|
||||
char *name;
|
||||
int mem_kb;
|
||||
enum {
|
||||
DOM_STATE_CREATED, /* created but not built */
|
||||
DOM_STATE_PAUSED, /* built but not started or paused */
|
||||
DOM_STATE_RUNNING, /* running normally */
|
||||
DOM_STATE_DEAD /* dead; either destroyed, crashed,
|
||||
or exitted. */
|
||||
} state;
|
||||
|
||||
unsigned long shared_info_mfn;
|
||||
shared_info_t *shared_info;
|
||||
control_if_t *ctrl_if;
|
||||
CONTROL_RING_IDX tx_req_cons;
|
||||
CONTROL_RING_IDX rx_resp_cons;
|
||||
|
||||
unsigned created_netif_backend:1;
|
||||
unsigned plugged:1;
|
||||
unsigned event_pending:1; /* True if an event arrived while
|
||||
the domain was plugged. */
|
||||
|
||||
struct console_connection *cc;
|
||||
|
||||
char netif_mac[6];
|
||||
|
||||
/* Used for two purposes: waking up domain threads when
|
||||
necessary, and synchronising access to dom0, which doesn't
|
||||
have a domain thread. */
|
||||
pthread_mutex_t mux;
|
||||
pthread_cond_t cond;
|
||||
|
||||
pthread_t thread;
|
||||
};
|
||||
|
||||
struct console_connection {
|
||||
struct list_head list;
|
||||
int fd;
|
||||
struct domain *dom;
|
||||
|
||||
enum {
|
||||
CC_STATE_PENDING,
|
||||
CC_STATE_CONNECTED,
|
||||
CC_STATE_ERROR
|
||||
} state;
|
||||
|
||||
unsigned buf_allocated;
|
||||
unsigned buf_used;
|
||||
char *buf;
|
||||
|
||||
unsigned in_buf_allocated;
|
||||
unsigned in_buf_used;
|
||||
char *in_buf;
|
||||
};
|
||||
|
||||
|
||||
void *domain_thread_func(void *d);
|
||||
void process_command(struct open_connection *oc);
|
||||
|
||||
void *xmalloc(size_t s);
|
||||
void *xrealloc(void *x, size_t s);
|
||||
char *xstrdup(const char *s);
|
||||
|
||||
int allocate_event_channel(struct domain *d, int event_ports[2]);
|
||||
void *map_domain_mem(struct domain *d, unsigned long mfn);
|
||||
void signal_domain(struct domain *d);
|
||||
int our_system(const char *fmt, ...);
|
||||
|
||||
extern unsigned xc_handle;
|
||||
#define EVTCHN_BIND _IO('E', 2)
|
||||
extern int evtchn_fd;
|
||||
|
||||
#define list_item(head, type, field) \
|
||||
((type *)((unsigned)(head) - offsetof(type, field)))
|
||||
|
||||
#define foreach_item(iter, head, type, field) \
|
||||
for ((iter) = list_item((head)->next, type, field); \
|
||||
(iter) != list_item((head), type, field); \
|
||||
(iter) = list_item((iter)->field.next, type, field))
|
||||
|
||||
#define list_insert_after(what, head) \
|
||||
do { \
|
||||
(what)->next = (head)->next; \
|
||||
(what)->pprev = &(head)->next; \
|
||||
(head)->next->pprev = &(what)->next; \
|
||||
(head)->next = what; \
|
||||
} while (0)
|
||||
|
||||
#define list_remove(head) \
|
||||
(head)->next->pprev = (head)->pprev; \
|
||||
*(head)->pprev = (head)->next;
|
||||
|
||||
#define list_foreach_safe(head, li, temp) \
|
||||
for ((li) = (head)->next, (temp) = (li)->next; \
|
||||
(li) != (head); \
|
||||
(li) = (temp), (temp) = (li)->next)
|
||||
|
||||
#define LIST_HEAD(x) { (x), &(x)->next }
|
||||
|
||||
|
||||
extern struct list_head head_domain;
|
||||
extern struct list_head head_console;
|
||||
|
||||
#define foreach_domain(d) \
|
||||
foreach_item(d, &head_domain, struct domain, domain_list)
|
||||
#define foreach_console_connection(cc) \
|
||||
foreach_item(cc, &head_console, struct console_connection, list)
|
||||
|
||||
|
||||
#define CURRENT_LOG_LEVEL 0
|
||||
|
||||
#define PRINTF(level, ...) \
|
||||
do { \
|
||||
if ((level) >= CURRENT_LOG_LEVEL) \
|
||||
printf(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif /* MINIXEND_H__ */
|
||||
@@ -1,132 +0,0 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void *
|
||||
xmalloc(size_t s)
|
||||
{
|
||||
void *x;
|
||||
|
||||
x = malloc(s);
|
||||
if (x == NULL)
|
||||
err(1, "allocating memory");
|
||||
memset(x, 0, s);
|
||||
return x;
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc(void *x, size_t s)
|
||||
{
|
||||
void *y;
|
||||
y = realloc(x, s);
|
||||
if (y == NULL)
|
||||
err(1, "allocating more memory");
|
||||
return y;
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup(const char *s)
|
||||
{
|
||||
char *x = strdup(s);
|
||||
if (x == NULL)
|
||||
err(1, "duplicating %s", s);
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Slightly less stupid implementation of system(). We return
|
||||
negative iff there is an error executing the shell; otherwise, we
|
||||
return the wait status as reported by waitpid(). Also, we support
|
||||
printf-style escapes. We don't handle setting the SIGCHLD handler
|
||||
to SIGIGN, though: in that case, we have a race. */
|
||||
int
|
||||
our_system(const char *fmt, ...)
|
||||
{
|
||||
char *cmd = NULL;
|
||||
int r;
|
||||
va_list ap;
|
||||
pid_t child = -1;
|
||||
int pip[2] = {-1, -1};
|
||||
int e;
|
||||
fd_set fds;
|
||||
struct timeval to;
|
||||
int res;
|
||||
pid_t c;
|
||||
unsigned status;
|
||||
|
||||
va_start(ap, fmt);
|
||||
r = vasprintf(&cmd, fmt, ap);
|
||||
va_end(ap);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = pipe(pip);
|
||||
if (r < 0) {
|
||||
res = r;
|
||||
goto out;
|
||||
}
|
||||
child = fork();
|
||||
if (child < 0) {
|
||||
res = child;
|
||||
goto out;
|
||||
}
|
||||
if (child == 0) {
|
||||
close(pip[0]);
|
||||
fcntl(pip[1], F_SETFD, 1);
|
||||
r = execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
|
||||
/* Uh oh, exec failed */
|
||||
write(pip[1], &r, sizeof(r));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
close(pip[1]);
|
||||
pip[1] = -1;
|
||||
|
||||
c = waitpid(child, &status, 0);
|
||||
if (c < 0) {
|
||||
res = c;
|
||||
goto out;
|
||||
}
|
||||
assert(c == child);
|
||||
child = -1;
|
||||
|
||||
/* Check execl result */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(pip[0], &fds);
|
||||
memset(&to, 0, sizeof(to));
|
||||
r = select(pip[0]+1, &fds, NULL, NULL, &to);
|
||||
if (r == 0) {
|
||||
res = status;
|
||||
} else {
|
||||
assert(FD_ISSET(pip[0], &fds));
|
||||
r = read(pip[0], &res, sizeof(res));
|
||||
if (r != sizeof(res))
|
||||
res = status;
|
||||
}
|
||||
close(pip[0]);
|
||||
pip[0] = -1;
|
||||
|
||||
out:
|
||||
e = errno;
|
||||
if (child >= 0) {
|
||||
/* Not obvious what the correct thing to do here is. */
|
||||
/* Don't want to kill the child; that will create a
|
||||
zombie. */
|
||||
// kill(child, 9);
|
||||
}
|
||||
if (pip[0] >= 0)
|
||||
close(pip[0]);
|
||||
if (pip[1] >= 0)
|
||||
close(pip[1]);
|
||||
free(cmd);
|
||||
errno = e;
|
||||
return res;
|
||||
}
|
||||