diff --git a/flock/container.c b/flock/container.c index 234610e1..d3fe2e95 100644 --- a/flock/container.c +++ b/flock/container.c @@ -31,7 +31,7 @@ struct container_runtime { uint hash; pid_t pid; sock *s; - struct container_created_callback { + struct container_operation_callback { callback cb; sock *s; void *data; @@ -60,6 +60,19 @@ container_child_sighandler(int signo UNUSED) 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) { @@ -83,15 +96,27 @@ 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 */ @@ -203,6 +228,14 @@ container_start(void) /* 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) { @@ -215,7 +248,25 @@ 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; } @@ -267,18 +318,23 @@ hypervisor_container_forker_rx(sock *sk, uint _sz UNUSED) 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; } @@ -303,8 +359,8 @@ crt_err(sock *s, int err UNUSED) 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); @@ -363,8 +419,8 @@ hypervisor_container_request(sock *s, const char *name, const char *basedir, con 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, }; @@ -397,6 +453,72 @@ hypervisor_container_request(sock *s, const char *name, const char *basedir, con 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; diff --git a/flock/ctl.c b/flock/ctl.c index 83433e3d..7d816d58 100644 --- a/flock/ctl.c +++ b/flock/ctl.c @@ -212,7 +212,14 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size) 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; @@ -285,6 +292,31 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size) 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"); } @@ -342,6 +374,10 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size) 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 */ @@ -395,6 +431,15 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size) 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"); } diff --git a/flock/flock-cli b/flock/flock-cli index ed60d81e..5cac0e6c 100755 --- a/flock/flock-cli +++ b/flock/flock-cli @@ -100,6 +100,11 @@ def container_start(hypervisor: str, name: str): }}).items(): print(k,v) +@handler +def container_stop(hypervisor: str, name: str): + for k,v in msg(hypervisor, { 4: { 0: name, }}).items(): + print(k,v) + try: binname = sys.argv.pop(0) except Exception as e: diff --git a/flock/flock.h b/flock/flock.h index 01835de9..0601848f 100644 --- a/flock/flock.h +++ b/flock/flock.h @@ -47,6 +47,7 @@ union flock_machine_config { void hypervisor_container_request(sock *s, const char *name, const char *basedir, const char *workdir); +void hypervisor_container_shutdown(sock *s, const char *name); extern event reboot_event, poweroff_event; extern event_list shutdown_event_list;