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'"),