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:
kaf24@firebug.cl.cam.ac.uk committed 2005-03-09 16:45:29 +00:00
1 parent 1593fed993
commit fffb91d4d8
6 files changed
-1709

No files matched your search

-5
View File
@@ -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
-22
View File
@@ -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
-457
View File
@@ -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;
}
-939
View File
@@ -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;
}
-154
View File
@@ -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__ */
-132
View File
@@ -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;
}
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.