From 6c91134de46ea481fa36c008c0a3667cbd088f1c Mon Sep 17 00:00:00 2001 From: Roman Bogorodskiy Date: Sat, 15 Mar 2014 16:30:01 +0400 Subject: [PATCH] bhyve: add console support through nmdm device nmdm is a FreeBSD driver which allows to create a pair of tty devices one of which is passed to the guest and second is used by the client. This patch adds new 'nmdm' character device type. Its definition looks this way: Master is passed to the hypervisior and slave is used for client connection. Also implement domainOpenConsole() for bhyve driver based on that. --- src/bhyve/bhyve_command.c | 34 +++++++++++++++++++++ src/bhyve/bhyve_driver.c | 45 +++++++++++++++++++++++++++ src/conf/domain_audit.c | 1 + src/conf/domain_conf.c | 59 +++++++++++++++++++++++++++++++++++- src/conf/domain_conf.h | 5 +++ src/qemu/qemu_command.c | 1 + src/qemu/qemu_monitor_json.c | 1 + 7 files changed, 145 insertions(+), 1 deletion(-) diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c index 139c7e2c57..a2da34ac2a 100644 --- a/src/bhyve/bhyve_command.c +++ b/src/bhyve/bhyve_command.c @@ -115,6 +115,38 @@ bhyveBuildNetArgStr(const virDomainDef *def, virCommandPtr cmd) return 0; } +static int +bhyveBuildConsoleArgStr(const virDomainDef *def, virCommandPtr cmd) +{ + + virDomainChrDefPtr chr = NULL; + + if (!def->nserials) + return 0; + + chr = def->serials[0]; + + if (chr->source.type != VIR_DOMAIN_CHR_TYPE_NMDM) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("only nmdm console types are supported")); + return -1; + } + + /* bhyve supports only two ports: com1 and com2 */ + if (chr->target.port > 2) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("only two serial ports are supported")); + return -1; + } + + virCommandAddArgList(cmd, "-s", "31,lpc", NULL); + virCommandAddArg(cmd, "-l"); + virCommandAddArgFormat(cmd, "com%d,%s", + chr->target.port + 1, chr->source.data.file.path); + + return 0; +} + static int bhyveBuildDiskArgStr(const virDomainDef *def, virCommandPtr cmd) { @@ -210,6 +242,8 @@ virBhyveProcessBuildBhyveCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED, goto error; if (bhyveBuildDiskArgStr(vm->def, cmd) < 0) goto error; + if (bhyveBuildConsoleArgStr(vm->def, cmd) < 0) + goto error; virCommandAddArg(cmd, vm->def->name); return cmd; diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index eec598dd15..461a0707a9 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -22,6 +22,7 @@ #include +#include #include #include "virerror.h" @@ -748,6 +749,49 @@ bhyveDomainDestroy(virDomainPtr dom) return ret; } +static int +bhyveDomainOpenConsole(virDomainPtr dom, + const char *dev_name ATTRIBUTE_UNUSED, + virStreamPtr st, + unsigned int flags) +{ + virDomainObjPtr vm = NULL; + virDomainChrDefPtr chr = NULL; + int ret = -1; + + virCheckFlags(0, -1); + + if (!(vm = bhyveDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + if (!vm->def->nserials) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("no console devices available")); + goto cleanup; + } + + chr = vm->def->serials[0]; + + if (virFDStreamOpenPTY(st, chr->source.data.nmdm.slave, + 0, 0, O_RDWR) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virObjectUnlock(vm); + return ret; +} + static int bhyveNodeGetCPUStats(virConnectPtr conn, int cpuNum, @@ -964,6 +1008,7 @@ static virDriver bhyveDriver = { .domainIsPersistent = bhyveDomainIsPersistent, /* 1.2.2 */ .domainGetAutostart = bhyveDomainGetAutostart, /* 1.2.4 */ .domainSetAutostart = bhyveDomainSetAutostart, /* 1.2.4 */ + .domainOpenConsole = bhyveDomainOpenConsole, /* 1.2.4 */ .nodeGetCPUStats = bhyveNodeGetCPUStats, /* 1.2.2 */ .nodeGetMemoryStats = bhyveNodeGetMemoryStats, /* 1.2.2 */ .nodeGetInfo = bhyveNodeGetInfo, /* 1.2.3 */ diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c index 5b97b82b3a..e26b8db364 100644 --- a/src/conf/domain_audit.c +++ b/src/conf/domain_audit.c @@ -72,6 +72,7 @@ virDomainAuditChardevPath(virDomainChrSourceDefPtr chr) case VIR_DOMAIN_CHR_TYPE_DEV: case VIR_DOMAIN_CHR_TYPE_FILE: case VIR_DOMAIN_CHR_TYPE_PIPE: + case VIR_DOMAIN_CHR_TYPE_NMDM: return chr->data.file.path; case VIR_DOMAIN_CHR_TYPE_UNIX: diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 0c5c7abfb5..2620257235 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -413,7 +413,8 @@ VIR_ENUM_IMPL(virDomainChr, VIR_DOMAIN_CHR_TYPE_LAST, "tcp", "unix", "spicevmc", - "spiceport") + "spiceport", + "nmdm") VIR_ENUM_IMPL(virDomainChrTcpProtocol, VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST, "raw", @@ -1403,6 +1404,11 @@ virDomainChrSourceDefClear(virDomainChrSourceDefPtr def) VIR_FREE(def->data.file.path); break; + case VIR_DOMAIN_CHR_TYPE_NMDM: + VIR_FREE(def->data.nmdm.master); + VIR_FREE(def->data.nmdm.slave); + break; + case VIR_DOMAIN_CHR_TYPE_UDP: VIR_FREE(def->data.udp.bindHost); VIR_FREE(def->data.udp.bindService); @@ -1471,6 +1477,14 @@ virDomainChrSourceDefCopy(virDomainChrSourceDefPtr dest, if (VIR_STRDUP(dest->data.nix.path, src->data.nix.path) < 0) return -1; break; + + case VIR_DOMAIN_CHR_TYPE_NMDM: + if (VIR_STRDUP(dest->data.nmdm.master, src->data.nmdm.master) < 0) + return -1; + if (VIR_STRDUP(dest->data.nmdm.slave, src->data.nmdm.slave) < 0) + return -1; + + break; } dest->type = src->type; @@ -1509,6 +1523,10 @@ virDomainChrSourceDefIsEqual(const virDomainChrSourceDef *src, case VIR_DOMAIN_CHR_TYPE_PIPE: return STREQ_NULLABLE(src->data.file.path, tgt->data.file.path); break; + case VIR_DOMAIN_CHR_TYPE_NMDM: + return STREQ_NULLABLE(src->data.nmdm.master, tgt->data.nmdm.master) && + STREQ_NULLABLE(src->data.nmdm.slave, tgt->data.nmdm.slave); + break; case VIR_DOMAIN_CHR_TYPE_UDP: return STREQ_NULLABLE(src->data.udp.bindHost, tgt->data.udp.bindHost) && STREQ_NULLABLE(src->data.udp.bindService, tgt->data.udp.bindService) && @@ -7148,6 +7166,8 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, char *mode = NULL; char *protocol = NULL; char *channel = NULL; + char *master = NULL; + char *slave = NULL; int remaining = 0; while (cur != NULL) { @@ -7197,6 +7217,13 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, channel = virXMLPropString(cur, "channel"); break; + case VIR_DOMAIN_CHR_TYPE_NMDM: + if (!master) + master = virXMLPropString(cur, "master"); + if (!slave) + slave = virXMLPropString(cur, "slave"); + break; + case VIR_DOMAIN_CHR_TYPE_LAST: case VIR_DOMAIN_CHR_TYPE_NULL: case VIR_DOMAIN_CHR_TYPE_VC: @@ -7253,6 +7280,25 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, path = NULL; break; + case VIR_DOMAIN_CHR_TYPE_NMDM: + if (!master) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing master path attribute for nmdm device")); + goto error; + } + + if (!slave) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing slave path attribute for nmdm device")); + goto error; + } + + def->data.nmdm.master = master; + def->data.nmdm.slave = slave; + master = NULL; + slave = NULL; + break; + case VIR_DOMAIN_CHR_TYPE_TCP: if (!mode || STREQ(mode, "connect")) { if (!connectHost) { @@ -7423,6 +7469,11 @@ virDomainChrDefNew(void) * * * + * + * + * + * + * */ static virDomainChrDefPtr virDomainChrDefParseXML(xmlXPathContextPtr ctxt, @@ -15760,6 +15811,12 @@ virDomainChrSourceDefFormat(virBufferPtr buf, } break; + case VIR_DOMAIN_CHR_TYPE_NMDM: + virBufferAsprintf(buf, "\n", + def->data.nmdm.master, + def->data.nmdm.slave); + break; + case VIR_DOMAIN_CHR_TYPE_UDP: if (def->data.udp.bindService && def->data.udp.bindHost) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 2f874c5797..c01f482e30 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -980,6 +980,7 @@ enum virDomainChrType { VIR_DOMAIN_CHR_TYPE_UNIX, VIR_DOMAIN_CHR_TYPE_SPICEVMC, VIR_DOMAIN_CHR_TYPE_SPICEPORT, + VIR_DOMAIN_CHR_TYPE_NMDM, VIR_DOMAIN_CHR_TYPE_LAST }; @@ -1011,6 +1012,10 @@ struct _virDomainChrSourceDef { struct { char *path; } file; /* pty, file, pipe, or device */ + struct { + char *master; + char *slave; + } nmdm; struct { char *host; char *service; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 37841d1596..1723ebfeeb 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6095,6 +6095,7 @@ qemuBuildChrArgStr(virDomainChrSourceDefPtr dev, const char *prefix) case VIR_DOMAIN_CHR_TYPE_SPICEVMC: case VIR_DOMAIN_CHR_TYPE_SPICEPORT: + case VIR_DOMAIN_CHR_TYPE_NMDM: case VIR_DOMAIN_CHR_TYPE_LAST: break; } diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index a692a07e51..f8ab975695 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -5423,6 +5423,7 @@ qemuMonitorJSONAttachCharDevCommand(const char *chrID, case VIR_DOMAIN_CHR_TYPE_SPICEPORT: case VIR_DOMAIN_CHR_TYPE_PIPE: case VIR_DOMAIN_CHR_TYPE_STDIO: + case VIR_DOMAIN_CHR_TYPE_NMDM: case VIR_DOMAIN_CHR_TYPE_LAST: virReportError(VIR_ERR_OPERATION_FAILED, _("Unsupported char device type '%d'"),