diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2012-10-27 18:34:04 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2012-10-27 18:34:04 +0000 |
commit | a1ce5fd60b5bd673846b158bf5be6128178aba37 (patch) | |
tree | 5fae1930b001c927114b1641721a65845636be1c | |
parent | 484332caaf7eae3f6ad6ccff18e72c7a259efeae (diff) |
Give ldomd(8) its own copy of the domain services support code and modify it
to handle multiple channels. Use it to provide the var-config domain service
to all the currently configured guest domains.
-rw-r--r-- | usr.sbin/ldomd/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/ldomd/ds.c | 725 | ||||
-rw-r--r-- | usr.sbin/ldomd/ds.h | 231 | ||||
-rw-r--r-- | usr.sbin/ldomd/ldomd.c | 172 | ||||
-rw-r--r-- | usr.sbin/ldomd/ldomd.h | 14 | ||||
-rw-r--r-- | usr.sbin/ldomd/var-config.c | 147 |
6 files changed, 1172 insertions, 121 deletions
diff --git a/usr.sbin/ldomd/Makefile b/usr.sbin/ldomd/Makefile index b12b22f3f01..df937bd2f75 100644 --- a/usr.sbin/ldomd/Makefile +++ b/usr.sbin/ldomd/Makefile @@ -1,9 +1,9 @@ -# $OpenBSD: Makefile,v 1.1 2012/10/26 18:26:13 kettenis Exp $ +# $OpenBSD: Makefile,v 1.2 2012/10/27 18:34:03 kettenis Exp $ .PATH: ${.CURDIR}/../ldomctl PROG= ldomd -SRCS= ldomd.c ds.c mdesc.c util.c +SRCS= ldomd.c ds.c mdesc.c util.c var-config.c NOMAN= CFLAGS+= -Wall CFLAGS+= -I${.CURDIR}/../ldomctl diff --git a/usr.sbin/ldomd/ds.c b/usr.sbin/ldomd/ds.c new file mode 100644 index 00000000000..c287bf66098 --- /dev/null +++ b/usr.sbin/ldomd/ds.c @@ -0,0 +1,725 @@ +/* $OpenBSD: ds.c,v 1.1 2012/10/27 18:34:03 kettenis Exp $ */ + +/* + * Copyright (c) 2012 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/poll.h> +#include <sys/queue.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ds.h" +#include "util.h" + +void ldc_rx_ctrl_vers(struct ldc_conn *, struct ldc_pkt *); +void ldc_rx_ctrl_rtr(struct ldc_conn *, struct ldc_pkt *); +void ldc_rx_ctrl_rts(struct ldc_conn *, struct ldc_pkt *); +void ldc_rx_ctrl_rdx(struct ldc_conn *, struct ldc_pkt *); + +void ldc_send_ack(struct ldc_conn *); +void ldc_send_rtr(struct ldc_conn *); +void ldc_send_rts(struct ldc_conn *); +void ldc_send_rdx(struct ldc_conn *); + +void +ldc_rx_ctrl(struct ldc_conn *lc, struct ldc_pkt *lp) +{ + switch (lp->ctrl) { + case LDC_VERS: + ldc_rx_ctrl_vers(lc, lp); + break; + + case LDC_RTS: + ldc_rx_ctrl_rts(lc, lp); + break; + + case LDC_RTR: + ldc_rx_ctrl_rtr(lc, lp); + break; + + case LDC_RDX: + ldc_rx_ctrl_rdx(lc, lp); + break; + + default: + DPRINTF(("CTRL/0x%02x/0x%02x\n", lp->stype, lp->ctrl)); + ldc_reset(lc); + break; + } +} + +void +ldc_rx_ctrl_vers(struct ldc_conn *lc, struct ldc_pkt *lp) +{ + struct ldc_pkt *lvp = (struct ldc_pkt *)lp; + + switch (lp->stype) { + case LDC_INFO: + if (lc->lc_state == LDC_RCV_VERS) { + DPRINTF(("Spurious CTRL/INFO/VERS: state %d\n", + lc->lc_state)); + return; + } + DPRINTF(("CTRL/INFO/VERS\n")); + if (lvp->major == LDC_VERSION_MAJOR && + lvp->minor == LDC_VERSION_MINOR) + ldc_send_ack(lc); + else + /* XXX do nothing for now. */ + ; + break; + + case LDC_ACK: + if (lc->lc_state != LDC_SND_VERS) { + DPRINTF(("Spurious CTRL/ACK/VERS: state %d\n", + lc->lc_state)); + ldc_reset(lc); + return; + } + DPRINTF(("CTRL/ACK/VERS\n")); + ldc_send_rts(lc); + break; + + case LDC_NACK: + DPRINTF(("CTRL/NACK/VERS\n")); + ldc_reset(lc); + break; + + default: + DPRINTF(("CTRL/0x%02x/VERS\n", lp->stype)); + ldc_reset(lc); + break; + } +} + +void +ldc_rx_ctrl_rts(struct ldc_conn *lc, struct ldc_pkt *lp) +{ + switch (lp->stype) { + case LDC_INFO: + if (lc->lc_state != LDC_RCV_VERS) { + DPRINTF(("Spurious CTRL/INFO/RTS: state %d\n", + lc->lc_state)); + ldc_reset(lc); + return; + } + DPRINTF(("CTRL/INFO/RTS\n")); + if (lp->env != LDC_MODE_RELIABLE) { + ldc_reset(lc); + return; + } + ldc_send_rtr(lc); + break; + + case LDC_ACK: + DPRINTF(("CTRL/ACK/RTS\n")); + ldc_reset(lc); + break; + + case LDC_NACK: + DPRINTF(("CTRL/NACK/RTS\n")); + ldc_reset(lc); + break; + + default: + DPRINTF(("CTRL/0x%02x/RTS\n", lp->stype)); + ldc_reset(lc); + break; + } +} + +void +ldc_rx_ctrl_rtr(struct ldc_conn *lc, struct ldc_pkt *lp) +{ + switch (lp->stype) { + case LDC_INFO: + if (lc->lc_state != LDC_SND_RTS) { + DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n", + lc->lc_state)); + ldc_reset(lc); + return; + } + DPRINTF(("CTRL/INFO/RTR\n")); + if (lp->env != LDC_MODE_RELIABLE) { + ldc_reset(lc); + return; + } + ldc_send_rdx(lc); +#if 0 + lc->lc_start(lc); +#endif + break; + + case LDC_ACK: + DPRINTF(("CTRL/ACK/RTR\n")); + ldc_reset(lc); + break; + + case LDC_NACK: + DPRINTF(("CTRL/NACK/RTR\n")); + ldc_reset(lc); + break; + + default: + DPRINTF(("CTRL/0x%02x/RTR\n", lp->stype)); + ldc_reset(lc); + break; + } +} + +void +ldc_rx_ctrl_rdx(struct ldc_conn *lc, struct ldc_pkt *lp) +{ + switch (lp->stype) { + case LDC_INFO: + if (lc->lc_state != LDC_SND_RTR) { + DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n", + lc->lc_state)); + ldc_reset(lc); + return; + } + DPRINTF(("CTRL/INFO/RDX\n")); +#if 0 + lc->lc_start(lc); +#endif + break; + + case LDC_ACK: + DPRINTF(("CTRL/ACK/RDX\n")); + ldc_reset(lc); + break; + + case LDC_NACK: + DPRINTF(("CTRL/NACK/RDX\n")); + ldc_reset(lc); + break; + + default: + DPRINTF(("CTRL/0x%02x/RDX\n", lp->stype)); + ldc_reset(lc); + break; + } +} + +void +ldc_rx_data(struct ldc_conn *lc, struct ldc_pkt *lp) +{ + size_t len; + + if (lp->stype != LDC_INFO && lp->stype != LDC_ACK) { + DPRINTF(("DATA/0x%02x\n", lp->stype)); + ldc_reset(lc); + return; + } + + if (lc->lc_state != LDC_SND_RTR && + lc->lc_state != LDC_SND_RDX) { + DPRINTF(("Spurious DATA/INFO: state %d\n", lc->lc_state)); + ldc_reset(lc); + return; + } + +#if 0 + if (lp->ackid) { + int i; + + for (i = 0; ds_service[i].ds_svc_id; i++) { + if (ds_service[i].ds_ackid && + lp->ackid >= ds_service[i].ds_ackid) { + ds_service[i].ds_ackid = 0; + ds_service[i].ds_start(lc, ds_service[i].ds_svc_handle); + } + } + } +#endif + if (lp->stype == LDC_ACK) + return; + + if (lp->env & LDC_FRAG_START) { + lc->lc_len = (lp->env & LDC_LEN_MASK); + memcpy((uint8_t *)lc->lc_msg, &lp->data, lc->lc_len); + } else { + len = (lp->env & LDC_LEN_MASK); + if (lc->lc_len + len > sizeof(lc->lc_msg)) { + DPRINTF(("Buffer overrun\n")); + ldc_reset(lc); + return; + } + memcpy((uint8_t *)lc->lc_msg + lc->lc_len, &lp->data, len); + lc->lc_len += len; + } + + if (lp->env & LDC_FRAG_STOP) { + ldc_ack(lc, lp->seqid); + lc->lc_rx_data(lc, lc->lc_msg, lc->lc_len); + } +} + +void +ldc_send_vers(struct ldc_conn *lc) +{ + struct ldc_pkt lp; + ssize_t nbytes; + + bzero(&lp, sizeof(lp)); + lp.type = LDC_CTRL; + lp.stype = LDC_INFO; + lp.ctrl = LDC_VERS; + lp.major = 1; + lp.minor = 0; + + nbytes = write(lc->lc_fd, &lp, sizeof(lp)); + if (nbytes != sizeof(lp)) + err(1, "write"); + + lc->lc_state = LDC_SND_VERS; +} + +void +ldc_send_ack(struct ldc_conn *lc) +{ + struct ldc_pkt lp; + ssize_t nbytes; + + bzero(&lp, sizeof(lp)); + lp.type = LDC_CTRL; + lp.stype = LDC_ACK; + lp.ctrl = LDC_VERS; + lp.major = 1; + lp.minor = 0; + + nbytes = write(lc->lc_fd, &lp, sizeof(lp)); + if (nbytes != sizeof(lp)) + err(1, "write"); + + lc->lc_state = LDC_RCV_VERS; +} + +void +ldc_send_rts(struct ldc_conn *lc) +{ + struct ldc_pkt lp; + ssize_t nbytes; + + bzero(&lp, sizeof(lp)); + lp.type = LDC_CTRL; + lp.stype = LDC_INFO; + lp.ctrl = LDC_RTS; + lp.env = LDC_MODE_RELIABLE; + lp.seqid = lc->lc_tx_seqid++; + + nbytes = write(lc->lc_fd, &lp, sizeof(lp)); + if (nbytes != sizeof(lp)) + err(1, "write"); + + lc->lc_state = LDC_SND_RTS; +} + +void +ldc_send_rtr(struct ldc_conn *lc) +{ + struct ldc_pkt lp; + ssize_t nbytes; + + bzero(&lp, sizeof(lp)); + lp.type = LDC_CTRL; + lp.stype = LDC_INFO; + lp.ctrl = LDC_RTR; + lp.env = LDC_MODE_RELIABLE; + lp.seqid = lc->lc_tx_seqid++; + + nbytes = write(lc->lc_fd, &lp, sizeof(lp)); + if (nbytes != sizeof(lp)) + err(1, "write"); + + lc->lc_state = LDC_SND_RTR; +} + +void +ldc_send_rdx(struct ldc_conn *lc) +{ + struct ldc_pkt lp; + ssize_t nbytes; + + bzero(&lp, sizeof(lp)); + lp.type = LDC_CTRL; + lp.stype = LDC_INFO; + lp.ctrl = LDC_RDX; + lp.env = LDC_MODE_RELIABLE; + lp.seqid = lc->lc_tx_seqid++; + + nbytes = write(lc->lc_fd, &lp, sizeof(lp)); + if (nbytes != sizeof(lp)) + err(1, "write"); + + lc->lc_state = LDC_SND_RDX; +} + +void +ldc_reset(struct ldc_conn *lc) +{ + lc->lc_tx_seqid = 0; + lc->lc_state = 0; +#if 0 + lc->lc_reset(lc); +#endif +} + +void +ldc_ack(struct ldc_conn *lc, uint32_t ackid) +{ + struct ldc_pkt lp; + ssize_t nbytes; + + bzero(&lp, sizeof(lp)); + lp.type = LDC_DATA; + lp.stype = LDC_ACK; + lp.seqid = lc->lc_tx_seqid++; + lp.ackid = ackid; + nbytes = write(lc->lc_fd, &lp, sizeof(lp)); + if (nbytes != sizeof(lp)) + err(1, "write"); +} + +void +ds_rx_msg(struct ldc_conn *lc, void *data, size_t len) +{ + struct ds_conn *dc = lc->lc_cookie; + struct ds_msg *dm = data; + + switch(dm->msg_type) { + case DS_INIT_REQ: + { + struct ds_init_req *dr = data; + + DPRINTF(("DS_INIT_REQ %d.%d\n", dr->major_vers, + dr->minor_vers)); + if (dr->major_vers != 1 || dr->minor_vers != 0){ + ldc_reset(lc); + return; + } + ds_init_ack(lc); + break; + } + + case DS_REG_REQ: + { + struct ds_reg_req *dr = data; + struct ds_conn *dc = lc->lc_cookie; + struct ds_conn_svc *dcs; + + DPRINTF(("DS_REG_REQ %s %d.%d 0x%016llx\n", dr->svc_id, + dr->major_vers, dr->minor_vers, dr->svc_handle)); + TAILQ_FOREACH(dcs, &dc->services, link) { + if (strcmp(dr->svc_id, dcs->service->ds_svc_id) == 0) { + dcs->svc_handle = dr->svc_handle; + dcs->ackid = lc->lc_tx_seqid; + ds_reg_ack(lc, dr->svc_handle); + return; + } + } + + ds_reg_nack(lc, dr->svc_handle); + break; + } + + case DS_UNREG: + { + struct ds_unreg *du = data; + + DPRINTF(("DS_UNREG 0x%016llx\n", du->svc_handle)); + ds_unreg_ack(lc, du->svc_handle); + break; + } + + case DS_DATA: + { + struct ds_data *dd = data; + struct ds_conn *dc = lc->lc_cookie; + struct ds_conn_svc *dcs; + + DPRINTF(("DS_DATA 0x%016llx\n", dd->svc_handle)); + TAILQ_FOREACH(dcs, &dc->services, link) { + if (dcs->svc_handle == dd->svc_handle) + dcs->service->ds_rx_data(lc, dd->svc_handle, + data, len); + } + break; + } + + default: + DPRINTF(("Unknown DS message type 0x%x\n", dm->msg_type)); + ldc_reset(lc); + break; + } +} + +void +ds_init_ack(struct ldc_conn *lc) +{ + struct ds_init_ack da; + + DPRINTF((" DS_INIT_ACK\n")); + bzero(&da, sizeof(da)); + da.msg_type = DS_INIT_ACK; + da.payload_len = sizeof(da) - 8; + da.minor_vers = 0; + ds_send_msg(lc, &da, sizeof(da)); +} + +void +ds_reg_ack(struct ldc_conn *lc, uint64_t svc_handle) +{ + struct ds_reg_ack da; + + DPRINTF((" DS_REG_ACK 0x%016llx\n", svc_handle)); + bzero(&da, sizeof(da)); + da.msg_type = DS_REG_ACK; + da.payload_len = sizeof(da) - 8; + da.svc_handle = svc_handle; + da.minor_vers = 0; + ds_send_msg(lc, &da, sizeof(da)); +} + +void +ds_reg_nack(struct ldc_conn *lc, uint64_t svc_handle) +{ + struct ds_reg_nack dn; + + DPRINTF((" DS_REG_NACK 0x%016llx\n", svc_handle)); + bzero(&dn, sizeof(dn)); + dn.msg_type = DS_REG_NACK; + dn.payload_len = sizeof(dn) - 8; + dn.svc_handle = svc_handle; + dn.result = DS_REG_VER_NACK; + dn.major_vers = 0; + ds_send_msg(lc, &dn, sizeof(dn)); +} + +void +ds_unreg_ack(struct ldc_conn *lc, uint64_t svc_handle) +{ + struct ds_unreg du; + + DPRINTF((" DS_UNREG_ACK 0x%016llx\n", svc_handle)); + bzero(&du, sizeof(du)); + du.msg_type = DS_UNREG_ACK; + du.payload_len = sizeof(du) - 8; + du.svc_handle = svc_handle; + ds_send_msg(lc, &du, sizeof(du)); +} + +void +ds_unreg_nack(struct ldc_conn *lc, uint64_t svc_handle) +{ + struct ds_unreg du; + + DPRINTF((" DS_UNREG_NACK 0x%016llx\n", svc_handle)); + bzero(&du, sizeof(du)); + du.msg_type = DS_UNREG_NACK; + du.payload_len = sizeof(du) - 8; + du.svc_handle = svc_handle; + ds_send_msg(lc, &du, sizeof(du)); +} + +void +ds_receive_msg(struct ldc_conn *lc, void *buf, size_t len) +{ + int env = LDC_FRAG_START; + struct ldc_pkt lp; + uint8_t *p = buf; + ssize_t nbytes; + + while (len > 0) { + nbytes = read(lc->lc_fd, &lp, sizeof(lp)); + if (nbytes != sizeof(lp)) + err(1, "read"); + + if (lp.type != LDC_DATA && + lp.stype != LDC_INFO) { + ldc_reset(lc); + return; + } + + if ((lp.env & LDC_FRAG_START) != env) { + ldc_reset(lc); + return; + } + + bcopy(&lp.data, p, (lp.env & LDC_LEN_MASK)); + p += (lp.env & LDC_LEN_MASK); + len -= (lp.env & LDC_LEN_MASK); + + if (lp.env & LDC_FRAG_STOP) + ldc_ack(lc, lp.seqid); + + env = (lp.env & LDC_FRAG_STOP) ? LDC_FRAG_START : 0; + } +} + +void +ldc_send_msg(struct ldc_conn *lc, void *buf, size_t len) +{ + struct ldc_pkt lp; + uint8_t *p = buf; + ssize_t nbytes; + + while (len > 0) { + bzero(&lp, sizeof(lp)); + lp.type = LDC_DATA; + lp.stype = LDC_INFO; + lp.env = min(len, LDC_PKT_PAYLOAD); + if (p == buf) + lp.env |= LDC_FRAG_START; + if (len <= LDC_PKT_PAYLOAD) + lp.env |= LDC_FRAG_STOP; + lp.seqid = lc->lc_tx_seqid++; + bcopy(p, &lp.data, min(len, LDC_PKT_PAYLOAD)); + + nbytes = write(lc->lc_fd, &lp, sizeof(lp)); + if (nbytes != sizeof(lp)) + err(1, "write"); + p += min(len, LDC_PKT_PAYLOAD); + len -= min(len, LDC_PKT_PAYLOAD); + } +} + +void +ds_send_msg(struct ldc_conn *lc, void *buf, size_t len) +{ + uint8_t *p = buf; +#if 0 + struct ldc_pkt lp; + ssize_t nbytes; +#endif + + while (len > 0) { + ldc_send_msg(lc, p, min(len, LDC_MSG_MAX)); + p += min(len, LDC_MSG_MAX); + len -= min(len, LDC_MSG_MAX); + +#if 0 + /* Consume ACK. */ + nbytes = read(lc->lc_fd, &lp, sizeof(lp)); + if (nbytes != sizeof(lp)) + err(1, "read"); + + { + uint64_t *msg = (uint64_t *)&lp; + int i; + + for (i = 0; i < 8; i++) + printf("%02x: %016llx\n", i, msg[i]); + } +#endif + } +} + +TAILQ_HEAD(ds_conn_head, ds_conn) ds_conns = + TAILQ_HEAD_INITIALIZER(ds_conns); +int num_ds_conns; + +struct ds_conn * +ds_conn_open(const char *path, void *cookie) +{ + struct ds_conn *dc; + + dc = xmalloc(sizeof(*dc)); + dc->path = xstrdup(path); + dc->cookie = cookie; + + dc->fd = open(path, O_RDWR, 0); + if (dc->fd == -1) + err(1, "open"); + + memset(&dc->lc, 0, sizeof(dc->lc)); + dc->lc.lc_fd = dc->fd; + dc->lc.lc_cookie = dc; + dc->lc.lc_rx_data = ds_rx_msg; + + TAILQ_INIT(&dc->services); + TAILQ_INSERT_TAIL(&ds_conns, dc, link); + dc->id = num_ds_conns++; + return dc; +} + +void +ds_conn_register_service(struct ds_conn *dc, struct ds_service *ds) +{ + struct ds_conn_svc *dcs; + + dcs = xzalloc(sizeof(*dcs)); + dcs->service = ds; + + TAILQ_INSERT_TAIL(&dc->services, dcs, link); +} + +void +ds_conn_handle(struct ds_conn *dc) +{ + struct ldc_pkt lp; + ssize_t nbytes; + + nbytes = read(dc->fd, &lp, sizeof(lp)); + if (nbytes != sizeof(lp)) { + ldc_reset(&dc->lc); + return; + } + + switch (lp.type) { + case LDC_CTRL: + ldc_rx_ctrl(&dc->lc, &lp); + break; + case LDC_DATA: + ldc_rx_data(&dc->lc, &lp); + break; + default: + DPRINTF(("0x%02x/0x%02x/0x%02x\n", lp.type, lp.stype, + lp.ctrl)); + ldc_reset(&dc->lc); + break; + } +} + +void +ds_conn_serve(void) +{ + struct ds_conn *dc; + struct pollfd *pfd; + int nfds;; + + pfd = xmalloc(num_ds_conns * sizeof(*pfd)); + TAILQ_FOREACH(dc, &ds_conns, link) { + pfd[dc->id].fd = dc->fd; + pfd[dc->id].events = POLLIN; + } + + while (1) { + nfds = poll(pfd, num_ds_conns, -1); + if (nfds == -1 || nfds == 0) + errx(1, "poll"); + + TAILQ_FOREACH(dc, &ds_conns, link) { + if (pfd[dc->id].revents) + ds_conn_handle(dc); + } + } +} diff --git a/usr.sbin/ldomd/ds.h b/usr.sbin/ldomd/ds.h new file mode 100644 index 00000000000..f1758977234 --- /dev/null +++ b/usr.sbin/ldomd/ds.h @@ -0,0 +1,231 @@ +/* $OpenBSD: ds.h,v 1.1 2012/10/27 18:34:03 kettenis Exp $ */ + +/* + * Copyright (c) 2012 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/queue.h> + +/* + * LDC virtual link layer protocol. + */ + +#define LDC_VERSION_MAJOR 1 +#define LDC_VERSION_MINOR 0 + +#define LDC_PKT_PAYLOAD 48 + +struct ldc_pkt { + uint8_t type; + uint8_t stype; + uint8_t ctrl; + uint8_t env; + uint32_t seqid; + + uint16_t major; + uint16_t minor; + uint32_t ackid; + + uint64_t data[6]; +}; + +/* Packet types. */ +#define LDC_CTRL 0x01 +#define LDC_DATA 0x02 +#define LDC_ERR 0x10 + +/* Packet subtypes. */ +#define LDC_INFO 0x01 +#define LDC_ACK 0x02 +#define LDC_NACK 0x04 + +/* Control info values. */ +#define LDC_VERS 0x01 +#define LDC_RTS 0x02 +#define LDC_RTR 0x03 +#define LDC_RDX 0x04 + +/* Packet envelope. */ +#define LDC_MODE_RAW 0x00 +#define LDC_MODE_UNRELIABLE 0x01 +#define LDC_MODE_RELIABLE 0x03 + +#define LDC_LEN_MASK 0x3f +#define LDC_FRAG_MASK 0xc0 +#define LDC_FRAG_START 0x40 +#define LDC_FRAG_STOP 0x80 + +#define LDC_MSG_MAX 4096 + +struct ldc_conn { + int lc_fd; + + uint32_t lc_tx_seqid; + uint8_t lc_state; +#define LDC_SND_VERS 1 +#define LDC_RCV_VERS 2 +#define LDC_SND_RTS 3 +#define LDC_SND_RTR 4 +#define LDC_SND_RDX 5 + + uint64_t lc_msg[LDC_MSG_MAX / 8]; + size_t lc_len; + + void *lc_cookie; + void (*lc_reset)(struct ldc_conn *); + void (*lc_start)(struct ldc_conn *); + void (*lc_rx_data)(struct ldc_conn *, void *, size_t); +}; + +void ldc_rx_ctrl(struct ldc_conn *, struct ldc_pkt *); +void ldc_rx_data(struct ldc_conn *, struct ldc_pkt *); + +void ldc_send_vers(struct ldc_conn *); + +void ldc_reset(struct ldc_conn *); + +struct ds_msg { + uint32_t msg_type; + uint32_t payload_len; + uint64_t data[5]; +}; + +struct ds_init_req { + uint32_t msg_type; + uint32_t payload_len; + uint16_t major_vers; + uint16_t minor_vers; +} __packed; + +struct ds_init_ack { + uint32_t msg_type; + uint32_t payload_len; + uint16_t minor_vers; +} __packed; + +#define DS_INIT_REQ 0x00 +#define DS_INIT_ACK 0x01 +#define DS_INIT_NACK 0x02 + +struct ds_reg_req { + uint32_t msg_type; + uint32_t payload_len; + uint64_t svc_handle; + uint16_t major_vers; + uint16_t minor_vers; + char svc_id[1]; +} __packed; + +#define DS_REG_REQ 0x03 + +struct ds_reg_ack { + uint32_t msg_type; + uint32_t payload_len; + uint64_t svc_handle; + uint16_t minor_vers; + uint8_t _reserved[6]; +} __packed; + +#define DS_REG_ACK 0x04 + +struct ds_reg_nack { + uint32_t msg_type; + uint32_t payload_len; + uint64_t svc_handle; + uint64_t result; + uint16_t major_vers; + uint8_t _reserved[6]; +} __packed; + +#define DS_REG_NACK 0x05 + +struct ds_unreg { + uint32_t msg_type; + uint32_t payload_len; + uint64_t svc_handle; +} __packed; + +#define DS_UNREG 0x06 +#define DS_UNREG_ACK 0x07 +#define DS_UNREG_NACK 0x08 + +struct ds_data { + uint32_t msg_type; + uint32_t payload_len; + uint64_t svc_handle; + uint64_t data[4]; +}; + +#define DS_DATA 0x09 + +struct ds_nack { + uint32_t msg_type; + uint32_t payload_len; + uint64_t svc_handle; + uint64_t result; +} __packed; + +#define DS_NACK 0x0a + +#define DS_REG_VER_NACK 0x01 +#define DS_REG_DUP 0x02 +#define DS_INV_HDL 0x03 +#define DS_TYPE_UNKNOWN 0x04 + +struct ds_service { + const char *ds_svc_id; + uint16_t ds_major_vers; + uint16_t ds_minor_vers; + + void (*ds_start)(struct ldc_conn *, uint64_t); + void (*ds_rx_data)(struct ldc_conn *, uint64_t, void *, + size_t); +}; + +void ldc_ack(struct ldc_conn *, uint32_t); +void ds_rx_msg(struct ldc_conn *, void *, size_t); + +void ds_init_ack(struct ldc_conn *); +void ds_reg_ack(struct ldc_conn *, uint64_t); +void ds_reg_nack(struct ldc_conn *, uint64_t); +void ds_unreg_ack(struct ldc_conn *, uint64_t); +void ds_unreg_nack(struct ldc_conn *, uint64_t); + +void ds_receive_msg(struct ldc_conn *lc, void *, size_t); +void ds_send_msg(struct ldc_conn *lc, void *, size_t); + +struct ds_conn_svc { + struct ds_service *service; + uint64_t svc_handle; + uint32_t ackid; + + TAILQ_ENTRY(ds_conn_svc) link; +}; + +struct ds_conn { + char *path; + void *cookie; + int id; + struct ldc_conn lc; + int fd; + + TAILQ_HEAD(ds_conn_svc_head, ds_conn_svc) services; + TAILQ_ENTRY(ds_conn) link; +}; + +struct ds_conn *ds_conn_open(const char *, void *); +void ds_conn_register_service(struct ds_conn *, struct ds_service *); +void ds_conn_serve(void); diff --git a/usr.sbin/ldomd/ldomd.c b/usr.sbin/ldomd/ldomd.c index 87487c752a2..7bbe4105d27 100644 --- a/usr.sbin/ldomd/ldomd.c +++ b/usr.sbin/ldomd/ldomd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldomd.c,v 1.1 2012/10/26 18:26:13 kettenis Exp $ */ +/* $OpenBSD: ldomd.c,v 1.2 2012/10/27 18:34:03 kettenis Exp $ */ /* * Copyright (c) 2012 Mark Kettenis @@ -29,6 +29,7 @@ #include "ds.h" #include "mdesc.h" #include "util.h" +#include "ldomd.h" struct hv_io { uint64_t hi_cookie; @@ -135,20 +136,10 @@ struct hvctl_msg { #define HVCTL_INFO_GUEST_SOFT_STATE 1 #define HVCTL_INFO_GUEST_UTILISATION 3 -struct guest { - const char *name; - uint64_t gid; - uint64_t mdpa; - - struct md_node *node; - struct md *md; - - TAILQ_ENTRY(guest) link; -}; - TAILQ_HEAD(guest_head, guest) guests; void add_guest(struct md_node *); +void map_domain_services(struct md *); void frag_init(void); void add_frag_mblock(struct md_node *); @@ -177,8 +168,7 @@ main(int argc, char **argv) struct md_header hdr; struct md_node *node; struct md_prop *prop; - struct ldc_conn lc; - int fd; + struct guest *guest; hvctl_fd = open("/dev/hvctl", O_RDWR, 0); if (hvctl_fd == -1) @@ -263,48 +253,19 @@ main(int argc, char **argv) frag_init(); - fd = open("/dev/ldom0", O_RDWR, 0); - if (fd == -1) - err(1, "open"); - - memset(&lc, 0, sizeof(lc)); - lc.lc_fd = fd; - lc.lc_rx_data = ds_rx_msg; + TAILQ_FOREACH(guest, &guests, link) { + struct ds_conn *dc; + char path[64]; - while (1) { - struct ldc_pkt lp; + if (strcmp(guest->name, "primary") == 0) + continue; - bzero(&lp, sizeof(lp)); - nbytes = read(fd, &lp, sizeof(lp)); - if (nbytes != sizeof(lp)) - err(1, "read"); - -#if 0 - { - uint64_t *msg = (uint64_t *)&lp; - int i; - - for (i = 0; i < 8; i++) - printf("%02x: %016llx\n", i, msg[i]); - } -#endif - - switch (lp.type) { - case LDC_CTRL: - ldc_rx_ctrl(&lc, &lp); - break; - case LDC_DATA: - ldc_rx_data(&lc, &lp); - break; - default: - DPRINTF(("%0x02/%0x02/%0x02\n", lp.type, lp.stype, - lp.ctrl)); - ldc_reset(&lc); - break; - } + snprintf(path, sizeof(path), "/dev/ldom-%s", guest->name); + dc = ds_conn_open(path, guest); + ds_conn_register_service(dc, &var_config_service); } - close(fd); + ds_conn_serve(); exit(EXIT_SUCCESS); } @@ -319,8 +280,6 @@ usage(void) exit(EXIT_FAILURE); } -struct guest *svendsen; - void add_guest(struct md_node *node) { @@ -330,7 +289,7 @@ add_guest(struct md_node *node) void *buf; size_t len; - guest = xmalloc (sizeof(*guest)); + guest = xmalloc(sizeof(*guest)); if (!md_get_prop_str(hvmd, node, "name", &guest->name)) goto free; @@ -359,14 +318,42 @@ add_guest(struct md_node *node) guest->node = node; guest->md = md_ingest(buf, len); - if (strcmp(guest->name, "svendsen") == 0) - svendsen = guest; + if (strcmp(guest->name, "primary") == 0) + map_domain_services(guest->md); TAILQ_INSERT_TAIL(&guests, guest, link); + return; + free: free(guest); } +void +map_domain_services(struct md *md) +{ + struct md_node *node; + const char *name; + char source[64]; + char target[64]; + int unit = 0; + + TAILQ_FOREACH(node, &md->node_list, link) { + if (strcmp(node->name->str, "virtual-device-port") != 0) + continue; + + if (!md_get_prop_str(md, node, "vldc-svc-name", &name)) + continue; + + if (strncmp(name, "ldom-", 5) != 0 || + strcmp(name, "ldom-primary") == 0) + continue; + + snprintf(source, sizeof(source), "/dev/ldom%d", unit++); + snprintf(target, sizeof(target), "/dev/%s", name); + unlink(target); + symlink(source, target); + } +} struct frag { TAILQ_ENTRY(frag) link; @@ -453,63 +440,6 @@ alloc_frag(void) return base; } -#if 0 - -#define VAR_CONFIG_SUCCESS 0x00 -#define VAR_CONFIG_NO_SPACE 0x01 -#define VAR_CONFIG_INVALID_VAR 0x02 -#define VAR_CONFIG_INVALID_VAL 0x03 -#define VAR_CONFIG_VAR_NOT_PRESENT 0x04 - -uint32_t -set_variable(struct md *md, const char *name, const char *value) -{ - struct md_node *node; - struct md_prop *prop; - md = svendsen->md; /* XXX */ - - node = md_find_node(md, "variables"); - if (node == NULL) { - struct md_node *root = md_find_node(md, "root"); - - assert(root); - node = md_add_node(md, "variables"); - md_link_node(md, root, node); - } - - prop = md_add_prop_str(md, node, name, value); - if (prop == NULL) - return VAR_CONFIG_NO_SPACE; - - md_write(md, "tmp.md"); - hv_update_md(NULL); - return VAR_CONFIG_SUCCESS; -} - -uint32_t -delete_variable(struct md *md, const char *name) -{ - struct md_node *node; - struct md_prop *prop; - md = svendsen->md; /* XXX */ - - node = md_find_node(md, "variables"); - if (node == NULL) - return VAR_CONFIG_VAR_NOT_PRESENT; - - prop = md_find_prop(md, node, name); - if (prop == NULL) - return VAR_CONFIG_VAR_NOT_PRESENT; - - md_delete_prop(md, node, prop); - - md_write(md, "tmp.md"); - hv_update_md(NULL); - return VAR_CONFIG_SUCCESS; -} - -#endif - void hv_update_md(struct guest *guest) { @@ -517,18 +447,22 @@ hv_update_md(struct guest *guest) size_t nbytes; void *buf; size_t size; - guest = svendsen; /* XXX */ + uint64_t mdpa; - guest->mdpa = alloc_frag(); + mdpa = alloc_frag(); size = md_exhume(guest->md, &buf); - hv_write(guest->mdpa, buf, size); + hv_write(mdpa, buf, size); + add_frag(guest->mdpa); + guest->mdpa = mdpa; free(buf); md_set_prop_val(hvmd, guest->node, "mdpa", guest->mdpa); - hv_mdpa = alloc_frag(); + mdpa = alloc_frag(); size = md_exhume(hvmd, &buf); - hv_write(hv_mdpa, buf, size); + hv_write(mdpa, buf, size); + add_frag(hv_mdpa); + hv_mdpa = mdpa; free(buf); /* Update config. */ diff --git a/usr.sbin/ldomd/ldomd.h b/usr.sbin/ldomd/ldomd.h new file mode 100644 index 00000000000..b5539d1b7cb --- /dev/null +++ b/usr.sbin/ldomd/ldomd.h @@ -0,0 +1,14 @@ +extern struct ds_service var_config_service; + +struct guest { + const char *name; + uint64_t gid; + uint64_t mdpa; + + struct md_node *node; + struct md *md; + + TAILQ_ENTRY(guest) link; +}; + +void hv_update_md(struct guest *); diff --git a/usr.sbin/ldomd/var-config.c b/usr.sbin/ldomd/var-config.c new file mode 100644 index 00000000000..6bc057653c5 --- /dev/null +++ b/usr.sbin/ldomd/var-config.c @@ -0,0 +1,147 @@ +/* $OpenBSD: var-config.c,v 1.1 2012/10/27 18:34:03 kettenis Exp $ */ + +/* + * Copyright (c) 2012 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/poll.h> +#include <sys/queue.h> +#include <assert.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ds.h" +#include "mdesc.h" +#include "util.h" +#include "ldomd.h" + +void var_config_start(struct ldc_conn *, uint64_t); +void var_config_rx_data(struct ldc_conn *, uint64_t, void *, size_t); + +struct ds_service var_config_service = { + "var-config", 1, 0, var_config_start, var_config_rx_data +}; + +#define VAR_CONFIG_SET_REQ 0x00 +#define VAR_CONFIG_DELETE_REQ 0x01 + +struct var_config_set_req { + uint32_t msg_type; + uint32_t payload_len; + uint64_t svc_handle; + uint32_t cmd; + char name[1]; +} __packed; + +#define VAR_CONFIG_SET_RESP 0x02 +#define VAR_CONFIG_DELETE_RESP 0x03 + +struct var_config_resp { + uint32_t msg_type; + uint32_t payload_len; + uint64_t svc_handle; + uint32_t result; +} __packed; + +#define VAR_CONFIG_SUCCESS 0x00 +#define VAR_CONFIG_NO_SPACE 0x01 +#define VAR_CONFIG_INVALID_VAR 0x02 +#define VAR_CONFIG_INVALID_VAL 0x03 +#define VAR_CONFIG_VAR_NOT_PRESENT 0x04 + +uint32_t +set_variable(struct guest *guest, const char *name, const char *value) +{ + struct md *md = guest->md; + struct md_node *node; + struct md_prop *prop; + + node = md_find_node(md, "variables"); + if (node == NULL) { + struct md_node *root = md_find_node(md, "root"); + + assert(root); + node = md_add_node(md, "variables"); + md_link_node(md, root, node); + } + + prop = md_add_prop_str(md, node, name, value); + if (prop == NULL) + return VAR_CONFIG_NO_SPACE; + + hv_update_md(guest); + return VAR_CONFIG_SUCCESS; +} + +uint32_t +delete_variable(struct guest *guest, const char *name) +{ + struct md *md = guest->md; + struct md_node *node; + struct md_prop *prop; + + node = md_find_node(md, "variables"); + if (node == NULL) + return VAR_CONFIG_VAR_NOT_PRESENT; + + prop = md_find_prop(md, node, name); + if (prop == NULL) + return VAR_CONFIG_VAR_NOT_PRESENT; + + md_delete_prop(md, node, prop); + + hv_update_md(guest); + return VAR_CONFIG_SUCCESS; +} + +void +var_config_start(struct ldc_conn *lc, uint64_t svc_handle) +{ +} + +void +var_config_rx_data(struct ldc_conn *lc, uint64_t svc_handle, void *data, + size_t len) +{ + struct ds_conn *dc = lc->lc_cookie; + struct var_config_set_req *vr = data; + struct var_config_resp vx; + + switch (vr->cmd) { + case VAR_CONFIG_SET_REQ: + vx.msg_type = DS_DATA; + vx.payload_len = sizeof(vx) - 8; + vx.svc_handle = svc_handle; + vx.result = set_variable(dc->cookie, vr->name, + vr->name + strlen(vr->name) + 1); + ds_send_msg(lc, &vx, sizeof(vx)); + break; + case VAR_CONFIG_DELETE_REQ: + vx.msg_type = DS_DATA; + vx.payload_len = sizeof(vx) - 8; + vx.svc_handle = svc_handle; + vx.result = delete_variable(dc->cookie, vr->name); + ds_send_msg(lc, &vx, sizeof(vx)); + break; + default: + printf("Unknown request 0x%02x\n", vr->cmd); + break; + } +} |