uint hash;
pid_t pid;
sock *s;
- struct container_created_callback {
+ struct container_operation_callback {
callback cb;
sock *s;
void *data;
static int container_forker_fd = -1;
+static void
+container_poweroff(int fd, int sig)
+{
+ byte outbuf[128];
+ linpool *lp = lp_new(&root_pool);
+ struct cbor_writer *cw = cbor_init(outbuf, sizeof outbuf, lp);
+ cbor_open_block_with_length(cw, 1);
+ cbor_add_int(cw, -4);
+ cbor_add_int(cw, sig);
+ ASSERT_DIE(write(fd, outbuf, cw->pt) == cw->pt);
+ exit(0);
+}
+
static void
container_mainloop(int fd)
{
int res = ppoll(&pfd, 1, NULL, &newmask);
if (poweroff)
+ container_poweroff(fd, poweroff);
+
+ if (pfd.revents & POLLIN)
{
- byte outbuf[128];
- linpool *lp = lp_new(&root_pool);
- struct cbor_writer *cw = cbor_init(outbuf, sizeof outbuf, lp);
- cbor_open_block_with_length(cw, 1);
- cbor_add_int(cw, -4);
- cbor_add_int(cw, poweroff);
- ASSERT_DIE(write(fd, outbuf, cw->pt) == cw->pt);
- exit(0);
+ byte buf[128];
+ ssize_t sz = read(fd, buf, sizeof buf);
+ if (sz < 0)
+ {
+ log(L_ERR "error reading data from control socket: %m");
+ exit(1);
+ }
+
+ ASSERT_DIE(sz >= 3);
+ ASSERT_DIE(buf[0] == 0xa1);
+ switch (buf[1]) {
+ case 0:
+ ASSERT_DIE(buf[2] == 0xf6);
+ container_poweroff(fd, 0);
+ break;
+
+ }
}
/* TODO: check for telnet socket */
/* The Parent */
+static void
+container_cleanup(struct container_runtime *crt)
+{
+ HASH_REMOVE(hcf.hash, CRT, crt);
+ sk_close(crt->s);
+ mb_free(crt);
+}
+
static int
hypervisor_container_rx(sock *sk, uint _sz UNUSED)
{
return 0;
}
- log(L_INFO "received %u data from %p (container_rx)", sz, sk);
+ struct container_runtime *crt = sk->data;
+ ASSERT_DIE(crt->s == sk);
+
+ ASSERT_DIE(sz >= 3);
+ ASSERT_DIE(buf[0] == 0xa1);
+
+ switch (buf[1]) {
+ case 0x23:
+ log(L_INFO "container %s ended by signal %d", crt->ccf.hostname, buf[2]);
+ if (crt->ccc)
+ callback_activate(&crt->ccc->cb);
+ container_cleanup(crt);
+ break;
+
+ default:
+ log(L_ERR "container %s sent a weird message 0x%02x sz %d", crt->ccf.hostname, buf[1], sz);
+ break;
+ }
+
return 0;
}
skl->type = SK_MAGIC;
skl->rx_hook = hypervisor_container_rx;
skl->fd = sfd;
+ sk_set_tbsize(skl, 1024);
+
if (sk_open(skl, sk->loop) < 0)
bug("Machine control socket: sk_open failed");
ASSERT_DIE(birdloop_inside(hcf.loop));
ASSERT_DIE(hcf.cur_crt);
+ skl->data = hcf.cur_crt;
+
hcf.cur_crt->pid = pid;
hcf.cur_crt->s = skl;
if (hcf.cur_crt->ccc)
callback_activate(&hcf.cur_crt->ccc->cb);
hcf.cur_crt->ccc = NULL;
hcf.cur_crt = NULL;
+
return 0;
}
static void
container_created(callback *cb)
{
- SKIP_BACK_DECLARE(struct container_created_callback, ccc, cb, cb);
-
+ SKIP_BACK_DECLARE(struct container_operation_callback, ccc, cb, cb);
+
sock *s = ccc->s;
linpool *lp = lp_new(s->pool);
struct cbor_writer *cw = cbor_init(s->tbuf, s->tbsize, lp);
crt->hash = h;
- struct container_created_callback *ccc = mb_alloc(s->pool, sizeof *ccc);
- *ccc = (struct container_created_callback) {
+ struct container_operation_callback *ccc = mb_alloc(s->pool, sizeof *ccc);
+ *ccc = (struct container_operation_callback) {
.s = s,
.data = s->data,
};
birdloop_leave(hcf.loop);
}
+static void
+container_stopped(callback *cb)
+{
+ SKIP_BACK_DECLARE(struct container_operation_callback, ccc, cb, cb);
+
+ sock *s = ccc->s;
+ linpool *lp = lp_new(s->pool);
+ struct cbor_writer *cw = cbor_init(s->tbuf, s->tbsize, lp);
+ cbor_open_block_with_length(cw, 1);
+ cbor_add_int(cw, -1);
+ cbor_add_string(cw, "OK");
+ sk_send(s, cw->pt);
+ rfree(lp);
+
+ s->data = ccc->data;
+ sk_resume_rx(s->loop, s);
+
+ mb_free(ccc);
+}
+
+void
+hypervisor_container_shutdown(sock *s, const char *name)
+{
+ birdloop_enter(hcf.loop);
+
+ uint h = mem_hash(name, strlen(name));
+ struct container_runtime *crt = HASH_FIND(hcf.hash, CRT, name, h);
+
+ linpool *lp = lp_new(hcf.p);
+
+ if (!crt || !crt->s)
+ {
+ struct cbor_writer *cw = cbor_init(s->tbuf, s->tbsize, lp);
+ cbor_open_block_with_length(cw, 1);
+ cbor_add_int(cw, -127);
+ cbor_add_string(cw, "BAD: Not found");
+
+ sk_send(s, cw->pt);
+ rfree(lp);
+ birdloop_leave(hcf.loop);
+ return;
+ }
+
+ struct cbor_writer *cw = cbor_init(crt->s->tbuf, crt->s->tbsize, lp);
+ cbor_open_block_with_length(cw, 1);
+ cbor_add_int(cw, 0);
+ write_item(cw, 7, 22);
+
+ sk_send(crt->s, cw->pt);
+ rfree(lp);
+
+ struct container_operation_callback *ccc = mb_alloc(s->pool, sizeof *ccc);
+ *ccc = (struct container_operation_callback) {
+ .s = s,
+ .data = s->data,
+ };
+ callback_init(&ccc->cb, container_stopped, s->loop);
+ crt->ccc = ccc;
+
+ s->err_paused = crt_err;
+ s->data = crt;
+ sk_pause_rx(s->loop, s);
+
+ birdloop_leave(hcf.loop);
+}
+
struct cbor_parser_context {
linpool *lp;
ctx->major_state = 501;
break;
- case 6: /* process spawner */
+ case 6: /* machine shutdown request */
+ if (ctx->type != 5)
+ CBOR_PARSER_ERROR("Expecting mapping, got %u", ctx->type);
+
+ ctx->major_state = 601;
+ break;
+
+ case 7: /* process spawner */
CBOR_PARSER_ERROR("NOT IMPLEMENTED YET");
break;
ctx->target_len = ctx->value;
break;
+ case 601: /* machine shutdown argument */
+ if (ctx->type != 0)
+ CBOR_PARSER_ERROR("Expected integer, got %u", ctx->type);
+
+ if (ctx->value >= 1)
+ CBOR_PARSER_ERROR("Command key too high, got %lu", ctx->value);
+
+ ctx->major_state = ctx->value + 602;
+ break;
+
+ case 602: /* machine creation argument 0: name */
+ if (ctx->type != 3)
+ CBOR_PARSER_ERROR("Expected string, got %u", ctx->type);
+
+ if (value_is_special)
+ CBOR_PARSER_ERROR("Variable length string not supported yet");
+
+ if (ctx->cfg.cf.name)
+ CBOR_PARSER_ERROR("Duplicate argument 0 / name");
+
+ ASSERT_DIE(!ctx->target_buf);
+ ctx->cfg.cf.name = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
+ ctx->target_len = ctx->value;
+ break;
+
default:
bug("invalid parser state");
}
ctx->major_state = 501;
break;
+ case 602:
+ ctx->major_state = 601;
+ break;
+
default:
bug("Unexpected state to end a (byte)string in");
/* Code to run at the end of a (byte)string */
ctx->major_state = 1;
break;
+ case 601:
+ if (!ctx->cfg.cf.name)
+ CBOR_PARSER_ERROR("Machine name not specified");
+
+ hypervisor_container_shutdown(ctx->sock, ctx->cfg.cf.name);
+
+ ctx->major_state = 1;
+ break;
+
default:
bug("Unexpected state to end a mapping in");
}