提交 02e11b83 编写于 作者: M Matthias Bolte

esx: Add support for virtual serial device network backing

Since version 4.1 ESX(i) can expose virtual serial devices over TCP.

Add support in the VMX handling code for this, add test cases to cover
it and add links to some documentation.

ESX supports two additional protocols: TELNETS and TLS. Add them to
the list of serial-over-TCP protocols.
上级 62a50a0b
......@@ -1469,7 +1469,9 @@ qemu-kvm -net nic,model=? /dev/null
...</pre>
<p>
Alternatively you can use telnet instead of raw TCP.
Alternatively you can use <code>telnet</code> instead of <code>raw</code> TCP.
<span class="since">Since 0.8.5</span> you can also use <code>telnets</code>
(secure telnet) and <code>tls</code>.
<p>
<pre>
......
......@@ -203,6 +203,12 @@ VIR_ENUM_IMPL(virDomainChr, VIR_DOMAIN_CHR_TYPE_LAST,
"tcp",
"unix")
VIR_ENUM_IMPL(virDomainChrTcpProtocol, VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST,
"raw",
"telnet",
"telnets",
"tls")
VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
"sb16",
"es1370",
......@@ -2748,12 +2754,10 @@ virDomainChrDefParseXML(virCapsPtr caps,
def->data.tcp.listen = 1;
}
if (protocol == NULL ||
STREQ(protocol, "raw"))
if (protocol == NULL)
def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
else if (STREQ(protocol, "telnet"))
def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
else {
else if ((def->data.tcp.protocol =
virDomainChrTcpProtocolTypeFromString(protocol)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("Unknown protocol '%s'"), protocol);
goto error;
......@@ -5848,9 +5852,7 @@ virDomainChrDefFormat(virBufferPtr buf,
def->data.tcp.host,
def->data.tcp.service);
virBufferVSprintf(buf, " <protocol type='%s'/>\n",
def->data.tcp.protocol ==
VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET
? "telnet" : "raw");
virDomainChrTcpProtocolTypeToString(def->data.tcp.protocol));
break;
case VIR_DOMAIN_CHR_TYPE_UNIX:
......
......@@ -357,6 +357,8 @@ enum virDomainChrType {
enum virDomainChrTcpProtocol {
VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW,
VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET,
VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS, /* secure telnet */
VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS,
VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST,
};
......@@ -1172,6 +1174,7 @@ VIR_ENUM_DECL(virDomainChrDevice)
VIR_ENUM_DECL(virDomainChrChannelTarget)
VIR_ENUM_DECL(virDomainChrConsoleTarget)
VIR_ENUM_DECL(virDomainChr)
VIR_ENUM_DECL(virDomainChrTcpProtocol)
VIR_ENUM_DECL(virDomainSoundModel)
VIR_ENUM_DECL(virDomainMemballoonModel)
VIR_ENUM_DECL(virDomainWatchdogModel)
......
......@@ -3,13 +3,24 @@ Some links to relevant documentation
====================================
VI/vSphere API: http://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/
http://www.vmware.com/support/developer/vc-sdk/visdk400pubs/ReferenceGuide/
VMX config: http://www.sanbarrow.com/vmx.html
CPUID: http://www.sandpile.org/ia32/cpuid.htm
Memory model: http://www.vmware.com/pdf/esx3_memory.pdf
http://www.vmware.com/pdf/usenix_resource_mgmt.pdf
VI/vSphere API:
http://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/
http://www.vmware.com/support/developer/vc-sdk/visdk400pubs/ReferenceGuide/
http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/
VMX config:
http://www.sanbarrow.com/vmx.html
CPUID:
http://www.sandpile.org/ia32/cpuid.htm
Memory model:
http://www.vmware.com/pdf/esx3_memory.pdf
http://www.vmware.com/pdf/usenix_resource_mgmt.pdf
Virtual serial port (network backed):
http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.device.VirtualSerialPort.URIBackingInfo.html
http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/vsp41_usingproxy_virtual_serial_ports.pdf
......
......@@ -379,6 +379,36 @@ def->serials[0]...
??? <=> serial0.yieldOnMsrRead = "true" # defaults to "false", FIXME: not representable
## serials: network, server (since vSphere 4.1) ################################
->type = _CHR_TYPE_TCP <=> serial0.fileType = "network"
->data.tcp.host = <host> <=> serial0.fileName = "<protocol>://<host>:<service>"
->data.tcp.service = <service> # e.g. "telnet://0.0.0.0:42001"
->data.tcp.protocol = <protocol>
->data.tcp.listen = 1 <=> serial0.network.endPoint = "server" # defaults to "server"
??? <=> serial0.vspc = "foobar" # defaults to <not present>, FIXME: not representable
??? <=> serial0.tryNoRxLoss = "false" # defaults to "false", FIXME: not representable
??? <=> serial0.yieldOnMsrRead = "true" # defaults to "false", FIXME: not representable
## serials: network, client (since vSphere 4.1) ################################
->type = _CHR_TYPE_TCP <=> serial0.fileType = "network"
->data.tcp.host = <host> <=> serial0.fileName = "<protocol>://<host>:<service>"
->data.tcp.service = <service> # e.g. "telnet://192.168.0.17:42001"
->data.tcp.protocol = <protocol>
->data.tcp.listen = 0 <=> serial0.network.endPoint = "client" # defaults to "server"
??? <=> serial0.vspc = "foobar" # defaults to <not present>, FIXME: not representable
??? <=> serial0.tryNoRxLoss = "false" # defaults to "false", FIXME: not representable
??? <=> serial0.yieldOnMsrRead = "true" # defaults to "false", FIXME: not representable
################################################################################
## parallels ###################################################################
......@@ -424,8 +454,11 @@ def->parallels[0]...
#define VIR_FROM_THIS VIR_FROM_ESX
#define ESX_BUILD_VMX_NAME_EXTRA(_suffix, _extra) \
snprintf(_suffix##_name, sizeof(_suffix##_name), "%s."_extra, prefix);
#define ESX_BUILD_VMX_NAME(_suffix) \
snprintf(_suffix##_name, sizeof(_suffix##_name), "%s."#_suffix, prefix);
ESX_BUILD_VMX_NAME_EXTRA(_suffix, #_suffix)
/* directly map the virDomainControllerModel to esxVMX_SCSIControllerModel,
* this is good enough for now because all virDomainControllerModel values
......@@ -2113,6 +2146,11 @@ esxVMX_ParseSerial(esxVMX_Context *ctx, virConfPtr conf, int port,
char fileName_name[48] = "";
char *fileName = NULL;
char network_endPoint_name[48] = "";
char *network_endPoint = NULL;
xmlURIPtr parsedUri = NULL;
if (def == NULL || *def != NULL) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
return -1;
......@@ -2137,6 +2175,7 @@ esxVMX_ParseSerial(esxVMX_Context *ctx, virConfPtr conf, int port,
ESX_BUILD_VMX_NAME(startConnected);
ESX_BUILD_VMX_NAME(fileType);
ESX_BUILD_VMX_NAME(fileName);
ESX_BUILD_VMX_NAME_EXTRA(network_endPoint, "network.endPoint");
/* vmx:present */
if (esxUtil_GetConfigBoolean(conf, present_name, &present, false,
......@@ -2165,6 +2204,12 @@ esxVMX_ParseSerial(esxVMX_Context *ctx, virConfPtr conf, int port,
goto cleanup;
}
/* vmx:network.endPoint -> def:data.tcp.listen */
if (esxUtil_GetConfigString(conf, network_endPoint_name, &network_endPoint,
true) < 0) {
goto cleanup;
}
/* Setup virDomainChrDef */
if (STRCASEEQ(fileType, "device")) {
(*def)->target.port = port;
......@@ -2190,10 +2235,72 @@ esxVMX_ParseSerial(esxVMX_Context *ctx, virConfPtr conf, int port,
(*def)->data.file.path = fileName;
fileName = NULL;
} else if (STRCASEEQ(fileType, "network")) {
(*def)->target.port = port;
(*def)->type = VIR_DOMAIN_CHR_TYPE_TCP;
parsedUri = xmlParseURI(fileName);
if (parsedUri == NULL) {
virReportOOMError();
goto cleanup;
}
if (parsedUri->port == 0) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("VMX entry '%s' doesn't contain a port part"),
fileName_name);
goto cleanup;
}
(*def)->data.tcp.host = strdup(parsedUri->server);
if ((*def)->data.tcp.host == NULL) {
virReportOOMError();
goto cleanup;
}
if (virAsprintf(&(*def)->data.tcp.service, "%d", parsedUri->port) < 0) {
virReportOOMError();
goto cleanup;
}
/* See vSphere API documentation about VirtualSerialPortURIBackingInfo */
if (parsedUri->scheme == NULL ||
STRCASEEQ(parsedUri->scheme, "tcp") ||
STRCASEEQ(parsedUri->scheme, "tcp4") ||
STRCASEEQ(parsedUri->scheme, "tcp6")) {
(*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
} else if (STRCASEEQ(parsedUri->scheme, "telnet")) {
(*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
} else if (STRCASEEQ(parsedUri->scheme, "telnets")) {
(*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS;
} else if (STRCASEEQ(parsedUri->scheme, "ssl") ||
STRCASEEQ(parsedUri->scheme, "tcp+ssl") ||
STRCASEEQ(parsedUri->scheme, "tcp4+ssl") ||
STRCASEEQ(parsedUri->scheme, "tcp6+ssl")) {
(*def)->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS;
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("VMX entry '%s' contains unsupported scheme '%s'"),
fileName_name, parsedUri->scheme);
goto cleanup;
}
if (network_endPoint == NULL || STRCASEEQ(network_endPoint, "server")) {
(*def)->data.tcp.listen = 1;
} else if (STRCASEEQ(network_endPoint, "client")) {
(*def)->data.tcp.listen = 0;
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Expecting VMX entry '%s' to be 'server' or 'client' "
"but found '%s'"), network_endPoint_name, network_endPoint);
goto cleanup;
}
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Expecting VMX entry '%s' to be 'device', 'file' or 'pipe' "
"but found '%s'"), fileType_name, fileType);
"or 'network' but found '%s'"), fileType_name, fileType);
goto cleanup;
}
......@@ -2207,6 +2314,8 @@ esxVMX_ParseSerial(esxVMX_Context *ctx, virConfPtr conf, int port,
VIR_FREE(fileType);
VIR_FREE(fileName);
VIR_FREE(network_endPoint);
xmlFreeURI(parsedUri);
return result;
......@@ -3069,6 +3178,7 @@ esxVMX_FormatSerial(esxVMX_Context *ctx, virDomainChrDefPtr def,
virBufferPtr buffer)
{
char *fileName = NULL;
const char *protocol;
if (def->target.port < 0 || def->target.port > 3) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
......@@ -3077,13 +3187,6 @@ esxVMX_FormatSerial(esxVMX_Context *ctx, virDomainChrDefPtr def,
return -1;
}
if (def->data.file.path == NULL) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
_("Expecting domain XML attribute 'path' of entry "
"'devices/serial/source' to be present"));
return -1;
}
virBufferVSprintf(buffer, "serial%d.present = \"true\"\n", def->target.port);
/* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
......@@ -3124,6 +3227,41 @@ esxVMX_FormatSerial(esxVMX_Context *ctx, virDomainChrDefPtr def,
def->target.port, def->data.file.path);
break;
case VIR_DOMAIN_CHR_TYPE_TCP:
switch (def->data.tcp.protocol) {
case VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW:
protocol = "tcp";
break;
case VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET:
protocol = "telnet";
break;
case VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS:
protocol = "telnets";
break;
case VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS:
protocol = "ssl";
break;
default:
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Unsupported character device TCP protocol '%s'"),
virDomainChrTcpProtocolTypeToString(def->data.tcp.protocol));
return -1;
}
virBufferVSprintf(buffer, "serial%d.fileType = \"network\"\n",
def->target.port);
virBufferVSprintf(buffer, "serial%d.fileName = \"%s://%s:%s\"\n",
def->target.port, protocol, def->data.tcp.host,
def->data.tcp.service);
virBufferVSprintf(buffer, "serial%d.network.endPoint = \"%s\"\n",
def->target.port,
def->data.tcp.listen ? "server" : "client");
break;
default:
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Unsupported character device type '%s'"),
......@@ -3154,13 +3292,6 @@ esxVMX_FormatParallel(esxVMX_Context *ctx, virDomainChrDefPtr def,
return -1;
}
if (def->data.file.path == NULL) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
_("Expecting domain XML attribute 'path' of entry "
"'devices/parallel/source' to be present"));
return -1;
}
virBufferVSprintf(buffer, "parallel%d.present = \"true\"\n",
def->target.port);
......
config.version = "8"
virtualHW.version = "4"
serial0.present = "true"
serial0.fileType = "network"
serial0.fileName = "tcp://192.168.0.17:42001"
serial0.network.endPoint = "client"
<domain type='vmware'>
<uuid>00000000-0000-0000-0000-000000000000</uuid>
<memory>32768</memory>
<currentMemory>32768</currentMemory>
<vcpu>1</vcpu>
<os>
<type arch='i686'>hvm</type>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<serial type='tcp'>
<source mode='connect' host='192.168.0.17' service='42001'/>
<protocol type='raw'/>
<target port='0'/>
</serial>
<console type='tcp'>
<source mode='connect' host='192.168.0.17' service='42001'/>
<protocol type='raw'/>
<target type='serial' port='0'/>
</console>
</devices>
</domain>
config.version = "8"
virtualHW.version = "4"
serial0.present = "true"
serial0.fileType = "network"
serial0.fileName = "telnets://0.0.0.0:42001"
serial0.network.endPoint = "server"
<domain type='vmware'>
<uuid>00000000-0000-0000-0000-000000000000</uuid>
<memory>32768</memory>
<currentMemory>32768</currentMemory>
<vcpu>1</vcpu>
<os>
<type arch='i686'>hvm</type>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<serial type='tcp'>
<source mode='bind' host='0.0.0.0' service='42001'/>
<protocol type='telnets'/>
<target port='0'/>
</serial>
<console type='tcp'>
<source mode='bind' host='0.0.0.0' service='42001'/>
<protocol type='telnets'/>
<target type='serial' port='0'/>
</console>
</devices>
</domain>
......@@ -266,6 +266,8 @@ mymain(int argc, char **argv)
DO_TEST("serial-pipe-server-vm", "serial-pipe", esxVI_ProductVersion_ESX35);
DO_TEST("serial-pipe-client-app", "serial-pipe", esxVI_ProductVersion_ESX35);
DO_TEST("serial-pipe-server-vm", "serial-pipe", esxVI_ProductVersion_ESX35);
DO_TEST("serial-network-server", "serial-network-server", esxVI_ProductVersion_ESX41);
DO_TEST("serial-network-client", "serial-network-client", esxVI_ProductVersion_ESX41);
DO_TEST("parallel-file", "parallel-file", esxVI_ProductVersion_ESX35);
DO_TEST("parallel-device", "parallel-device", esxVI_ProductVersion_ESX35);
......
config.version = "8"
virtualHW.version = "7"
guestOS = "other"
uuid.bios = "56 4d 9b ef ac d9 b4 e0-c8 f0 ae a8 b9 10 35 15"
displayName = "serial-network"
memsize = "4"
numvcpus = "1"
floppy0.present = "false"
floppy1.present = "false"
serial0.present = "true"
serial0.fileType = "network"
serial0.fileName = "tcp://192.168.0.17:42001"
serial0.network.endPoint = "client"
serial0.yieldOnMsrRead = "true"
<domain type='vmware'>
<name>serial-network</name>
<uuid>564d9bef-acd9-b4e0-c8f0-aea8b9103515</uuid>
<memory>4096</memory>
<os>
<type>hvm</type>
</os>
<devices>
<serial type='tcp'>
<source mode="connect" host="192.168.0.17" service="42001"/>
<protocol type="raw"/>
<target port='0'/>
</serial>
</devices>
</domain>
config.version = "8"
virtualHW.version = "7"
guestOS = "other"
uuid.bios = "56 4d 9b ef ac d9 b4 e0-c8 f0 ae a8 b9 10 35 15"
displayName = "serial-network"
memsize = "4"
numvcpus = "1"
floppy0.present = "false"
floppy1.present = "false"
serial0.present = "true"
serial0.fileType = "network"
serial0.fileName = "ssl://0.0.0.0:42001"
serial0.network.endPoint = "server"
serial0.yieldOnMsrRead = "true"
<domain type='vmware'>
<name>serial-network</name>
<uuid>564d9bef-acd9-b4e0-c8f0-aea8b9103515</uuid>
<memory>4096</memory>
<os>
<type>hvm</type>
</os>
<devices>
<serial type='tcp'>
<source mode="bind" host="0.0.0.0" service="42001"/>
<protocol type="tls"/>
<target port='0'/>
</serial>
</devices>
</domain>
......@@ -259,6 +259,8 @@ mymain(int argc, char **argv)
DO_TEST("serial-file", "serial-file", esxVI_ProductVersion_ESX35);
DO_TEST("serial-device", "serial-device", esxVI_ProductVersion_ESX35);
DO_TEST("serial-pipe", "serial-pipe", esxVI_ProductVersion_ESX35);
DO_TEST("serial-network-server", "serial-network-server", esxVI_ProductVersion_ESX41);
DO_TEST("serial-network-client", "serial-network-client", esxVI_ProductVersion_ESX41);
DO_TEST("parallel-file", "parallel-file", esxVI_ProductVersion_ESX35);
DO_TEST("parallel-device", "parallel-device", esxVI_ProductVersion_ESX35);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册