summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2012-10-27 18:34:04 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2012-10-27 18:34:04 +0000
commita1ce5fd60b5bd673846b158bf5be6128178aba37 (patch)
tree5fae1930b001c927114b1641721a65845636be1c
parent484332caaf7eae3f6ad6ccff18e72c7a259efeae (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/Makefile4
-rw-r--r--usr.sbin/ldomd/ds.c725
-rw-r--r--usr.sbin/ldomd/ds.h231
-rw-r--r--usr.sbin/ldomd/ldomd.c172
-rw-r--r--usr.sbin/ldomd/ldomd.h14
-rw-r--r--usr.sbin/ldomd/var-config.c147
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;
+ }
+}