Extend and cleanup the VMX to domain XML mapping. Add the domain XML to VMX mapping functions. * src/esx/esx_driver.c: add esxDomainXMLToNative() * src/esx/esx_vmx.[ch]: add esxVMX_SCSIDiskNameToControllerAndID(), esxVMX_IDEDiskNameToControllerAndID(), esxVMX_FloppyDiskNameToController(), esxVMX_GatherSCSIControllers(), add basic handling for the VMX guestOS entry to distinguish between i686 and x86_64, make SCSI virtualDev VMX entry optional as it should be, map the VMX networkName entry to the domain XML interface bridge name, add basic mapping for serial devices in pipe mode, add several esxVMX_Format*() functions
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index fb4edbc..3f3ee30 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -2224,6 +2224,42 @@ esxDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat, +static char * +esxDomainXMLToNative(virConnectPtr conn, const char *nativeFormat, + const char *domainXml, + unsigned int flags ATTRIBUTE_UNUSED) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + virDomainDefPtr def = NULL; + char *vmx = NULL; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + return NULL; + } + + if (STRNEQ(nativeFormat, "vmware-vmx")) { + ESX_ERROR(conn, VIR_ERR_INVALID_ARG, + "Unsupported config format '%s'", nativeFormat); + return NULL; + } + + def = virDomainDefParseString(conn, priv->caps, domainXml, 0); + + if (def == NULL) { + return NULL; + } + + vmx = esxVMX_FormatConfig(conn, def, priv->host->apiVersion); + + virDomainDefFree(def); + + return vmx; +} + + + static int esxListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) { @@ -3085,7 +3121,7 @@ static virDriver esxDriver = { NULL, /* nodeGetSecurityModel */ esxDomainDumpXML, /* domainDumpXML */ esxDomainXMLFromNative, /* domainXmlFromNative */ - NULL, /* domainXmlToNative */ + esxDomainXMLToNative, /* domainXmlToNative */ esxListDefinedDomains, /* listDefinedDomains */ esxNumberOfDefinedDomains, /* numOfDefinedDomains */ esxDomainCreate, /* domainCreate */ diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c index 70e9305..68a986f 100644 --- a/src/esx/esx_vmx.c +++ b/src/esx/esx_vmx.c @@ -58,7 +58,7 @@ def->cpumask = <uint list> <=> sched.cpu.affinity = "<uint list>" def->os ->type = "hvm" -->arch +->arch = <arch> <=> guestOS = "<value>" # if <value> ends with -64 than <arch> is x86_64, otherwise <arch> is i686 ->machine ->nBootDevs ->bootDevs @@ -98,7 +98,7 @@ def->disks[0]... ->device = _DISK_DEVICE_DISK <=> scsi0:0.deviceType = "scsi-hardDisk" # defaults to ? ->bus = _DISK_BUS_SCSI ->src = <value>.vmdk <=> scsi0:0.fileName = "<value>.vmdk" -->dst = sd[<controller> * 16 + <id> mapped to [a-z]+] +->dst = sd[<controller> * 15 + <id> mapped to [a-z]+] ->driverName = <driver> <=> scsi0.virtualDev = "<driver>" # default depends on guestOS value ->driverType ->cachemode <=> scsi0:0.writeThrough = "<value>" # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT @@ -109,7 +109,6 @@ def->disks[0]... ## disks: ide hard drive from .vmdk image ###################################### - ide0.present = "true" # defaults to "false" ide0:0.present = "true" # defaults to "false" ide0:0.startConnected = "true" # defaults to "true" @@ -143,7 +142,7 @@ def->disks[0]... ->device = _DISK_DEVICE_CDROM <=> scsi0:0.deviceType = "cdrom-image" # defaults to ? ->bus = _DISK_BUS_SCSI ->src = <value>.iso <=> scsi0:0.fileName = "<value>.iso" -->dst = sd[<controller> * 16 + <id> mapped to [a-z]+] +->dst = sd[<controller> * 15 + <id> mapped to [a-z]+] ->driverName = <driver> <=> scsi0.virtualDev = "<driver>" # default depends on guestOS value ->driverType ->cachemode @@ -154,7 +153,6 @@ def->disks[0]... ## disks: ide cdrom from .iso image ############################################ - ide0.present = "true" # defaults to "false" ide0:0.present = "true" # defaults to "false" ide0:0.startConnected = "true" # defaults to "true" @@ -194,7 +192,6 @@ def->disks[0]... ## disks: ide cdrom from host device ########################################### - ide0.present = "true" # defaults to "false" ide0:0.present = "true" # defaults to "false" ide0:0.startConnected = "true" # defaults to "true" ide0:0.clientDevice = "false" # defaults to "false" @@ -289,17 +286,18 @@ def->nets[0]... ... ->type = _NET_TYPE_BRIDGE <=> ethernet0.connectionType = "bridged" # defaults to "bridged" +->data.bridge.brname = <value> <=> ethernet0.networkName = "<value>" ## nets: hostonly ############################################################## -... # FIXME: maybe not supported by ESX? +... # FIXME: Investigate if ESX supports this ->type = _NET_TYPE_NETWORK <=> ethernet0.connectionType = "hostonly" # defaults to "bridged" ## nets: nat ################################################################### -... # FIXME: maybe not supported by ESX? +... # FIXME: Investigate if ESX supports this ->type = _NET_TYPE_USER <=> ethernet0.connectionType = "nat" # defaults to "bridged" @@ -307,7 +305,8 @@ def->nets[0]... ... ->type = _NET_TYPE_BRIDGE <=> ethernet0.connectionType = "custom" # defaults to "bridged" -->data.bridge.brname = <value> <=> ethernet0.vnet = "<value>" +->data.bridge.brname = <value> <=> ethernet0.networkName = "<value>" +->ifname = <value> <=> ethernet0.vnet = "<value>" @@ -328,6 +327,7 @@ def->serials[0]... ->type = _CHR_TYPE_DEV <=> serial0.fileType = "device" ->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "/dev/ttyS0" ??? <=> serial0.tryNoRxLoss = "false" # defaults to "false", FIXME: not representable +??? <=> serial0.yieldOnMsrRead = "true" # defaults to "false", FIXME: not representable ## serials: file ############################################################### @@ -335,32 +335,37 @@ def->serials[0]... ->type = _CHR_TYPE_FILE <=> serial0.fileType = "file" ->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "serial0.file" ??? <=> serial0.tryNoRxLoss = "false" # defaults to "false", FIXME: not representable +??? <=> serial0.yieldOnMsrRead = "true" # defaults to "false", FIXME: not representable ## serials: pipe, far end -> app ############################################### ->type = _CHR_TYPE_PIPE <=> serial0.fileType = "pipe" ->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "serial0.pipe" -??? <=> serial0.pipe.endPoint = "client" # defaults to "server", FIXME: not representable +??? <=> serial0.pipe.endPoint = "client" # defaults to ?, FIXME: not representable ??? <=> serial0.tryNoRxLoss = "true" # defaults to "false", FIXME: not representable +??? <=> serial0.yieldOnMsrRead = "true" # defaults to "false", FIXME: not representable ->type = _CHR_TYPE_PIPE <=> serial0.fileType = "pipe" ->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "serial0.pipe" -??? <=> serial0.pipe.endPoint = "server" # defaults to "server", FIXME: not representable +??? <=> serial0.pipe.endPoint = "server" # defaults to ?, FIXME: not representable ??? <=> serial0.tryNoRxLoss = "true" # defaults to "false", FIXME: not representable +??? <=> serial0.yieldOnMsrRead = "true" # defaults to "false", FIXME: not representable ## serials: pipe, far end -> vm ################################################ ->type = _CHR_TYPE_PIPE <=> serial0.fileType = "pipe" ->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "serial0.pipe" -??? <=> serial0.pipe.endPoint = "client" # defaults to "server", FIXME: not representable +??? <=> serial0.pipe.endPoint = "client" # defaults to ?, FIXME: not representable ??? <=> serial0.tryNoRxLoss = "false" # defaults to "false", FIXME: not representable +??? <=> serial0.yieldOnMsrRead = "true" # defaults to "false", FIXME: not representable ->type = _CHR_TYPE_PIPE <=> serial0.fileType = "pipe" ->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "serial0.pipe" -??? <=> serial0.pipe.endPoint = "server" # defaults to "server", FIXME: not representable +??? <=> serial0.pipe.endPoint = "server" # defaults to ?, FIXME: not representable ??? <=> serial0.tryNoRxLoss = "false" # defaults to "false", FIXME: not representable +??? <=> serial0.yieldOnMsrRead = "true" # defaults to "false", FIXME: not representable @@ -389,6 +394,21 @@ def->parallels[0]... ->data.file.path = <value> <=> parallel0.fileName = "<value>" # e.g. "parallel0.file" ??? <=> parallel0.bidirectional = "<value>" # must be "false" for fileType = "file", FIXME: not representable + + +################################################################################ +## sound ####################################################################### + + sound.present = "true" # defaults to "false" + sound.startConnected = "true" # defaults to "true" + sound.autodetect = "true" + sound.fileName = "-1" + + FIXME: Investigate if ESX supports this, + at least the VI Client GUI has no + options to add a sound device, but + the VI API contains a VirtualSoundCard + */ #define VIR_FROM_THIS VIR_FROM_ESX @@ -404,6 +424,208 @@ def->parallels[0]... +char * +esxVMX_IndexToDiskName(virConnectPtr conn, int idx, const char *prefix) +{ + char buffer[32] = ""; + char *name = NULL; + size_t length = strlen(prefix); + + if (length > sizeof (buffer) - 2 - 1) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Disk name prefix '%s' is too long", prefix); + return NULL; + } + + strncpy(buffer, prefix, sizeof (buffer) - 1); + buffer[sizeof (buffer) - 1] = '\0'; + + if (idx < 26) { + buffer[length] = 'a' + idx; + } else if (idx < 702) { + buffer[length] = 'a' + idx / 26 - 1; + buffer[length + 1] = 'a' + idx % 26; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Disk index %d is too large", idx); + return NULL; + } + + name = strdup(buffer); + + if (name == NULL) { + virReportOOMError(conn); + return NULL; + } + + return name; +} + + + +int +esxVMX_SCSIDiskNameToControllerAndID(virConnectPtr conn, const char *name, + int *controller, int *id) +{ + int idx; + + if (! STRPREFIX(name, "sd")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML attribute 'dev' of entry " + "'devices/disk/target' to start with 'sd'"); + return -1; + } + + idx = virDiskNameToIndex(name); + + if (idx < 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not parse valid disk index from '%s'", name); + return -1; + } + + /* Each of the 4 SCSI controllers offers 15 IDs for devices */ + if (idx >= (4 * 15)) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "SCSI disk index (parsed from '%s') is too large", name); + return -1; + } + + *controller = idx / 15; + *id = idx % 15; + + /* Skip the controller ifself with ID 7 */ + if (*id >= 7) { + ++(*id); + } + + return 0; +} + + + +int +esxVMX_IDEDiskNameToControllerAndID(virConnectPtr conn, const char *name, + int *controller, int *id) +{ + int idx; + + if (! STRPREFIX(name, "hd")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML attribute 'dev' of entry " + "'devices/disk/target' to start with 'hd'"); + return -1; + } + + idx = virDiskNameToIndex(name); + + if (idx < 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not parse valid disk index from '%s'", name); + return -1; + } + + /* Each of the 2 IDE controllers offers 2 IDs for devices */ + if (idx >= (2 * 2)) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "IDE disk index (parsed from '%s') is too large", name); + return -1; + } + + *controller = idx / 2; + *id = idx % 2; + + return 0; +} + + + +int +esxVMX_FloppyDiskNameToController(virConnectPtr conn, const char *name, + int *controller) +{ + int idx; + + if (! STRPREFIX(name, "fd")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML attribute 'dev' of entry " + "'devices/disk/target' to start with 'fd'"); + return -1; + } + + idx = virDiskNameToIndex(name); + + if (idx < 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not parse valid disk index from '%s'", name); + return -1; + } + + if (idx >= 2) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Floppy disk index (parsed from '%s') is too large", name); + return -1; + } + + *controller = idx; + + return 0; +} + + + +int +esxVMX_GatherSCSIControllers(virConnectPtr conn, virDomainDefPtr def, + char *virtualDev[4], int present[4]) +{ + virDomainDiskDefPtr disk; + int i, controller, id; + + /* Check for continuous use of the same virtualDev per SCSI controller */ + for (i = 0; i < def->ndisks; ++i) { + disk = def->disks[i]; + + if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) { + continue; + } + + if (disk->driverName != NULL && + STRCASENEQ(disk->driverName, "buslogic") && + STRCASENEQ(disk->driverName, "lsilogic")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML entry 'devices/disk/target' to be " + "'buslogic' or 'lsilogic' but found '%s'", + disk->driverName); + return -1; + } + + if (esxVMX_SCSIDiskNameToControllerAndID(conn, disk->dst, + &controller, &id) < 0) { + return -1; + } + + present[controller] = 1; + + if (virtualDev[controller] == NULL) { + virtualDev[controller] = disk->driverName; + } else if (STRCASENEQ(virtualDev[controller], disk->driverName)) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Inconsistent driver usage ('%s' is not '%s') on SCSI " + "controller index %d", virtualDev[controller], + disk->driverName, controller); + return -1; + } + } + + return 0; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VMX -> Domain XML + */ + virDomainDefPtr esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, esxVI_APIVersion apiVersion) @@ -416,6 +638,7 @@ esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, long long memory = 0; long long numvcpus = 0; char *sched_cpu_affinity = NULL; + char *guestOS = NULL; int controller; int port; int present; @@ -436,6 +659,7 @@ esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, def->virtType = VIR_DOMAIN_VIRT_VMWARE; /* FIXME: maybe add VIR_DOMAIN_VIRT_ESX ? */ def->id = -1; + /* vmx:config.version */ if (esxUtil_GetConfigLong(conn, conf, "config.version", &config_version, 0, 0) < 0) { goto failure; @@ -448,6 +672,7 @@ esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, goto failure; } + /* vmx:virtualHW.version */ if (esxUtil_GetConfigLong(conn, conf, "virtualHW.version", &virtualHW_version, 0, 0) < 0) { goto failure; @@ -490,19 +715,19 @@ esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, goto failure; } - /* def:uuid */ + /* vmx:uuid.bios -> def:uuid */ /* FIXME: Need to handle 'uuid.action = "create"' */ if (esxUtil_GetConfigUUID(conn, conf, "uuid.bios", def->uuid, 1) < 0) { goto failure; } - /* def:name */ + /* vmx:displayName -> def:name */ if (esxUtil_GetConfigString(conn, conf, "displayName", &def->name, 1) < 0) { goto failure; } - /* def:maxmem */ + /* vmx:memsize -> def:maxmem */ if (esxUtil_GetConfigLong(conn, conf, "memsize", &memsize, 32, 1) < 0) { goto failure; } @@ -516,7 +741,7 @@ esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, def->maxmem = memsize * 1024; /* Scale from megabytes to kilobytes */ - /* def:memory */ + /* vmx:sched.mem.max -> def:memory */ if (esxUtil_GetConfigLong(conn, conf, "sched.mem.max", &memory, memsize, 1) < 0) { goto failure; @@ -532,7 +757,7 @@ esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, def->memory = def->maxmem; } - /* def:vcpus */ + /* vmx:numvcpus -> def:vcpus */ if (esxUtil_GetConfigLong(conn, conf, "numvcpus", &numvcpus, 1, 1) < 0) { goto failure; } @@ -546,7 +771,7 @@ esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, def->vcpus = numvcpus; - /* def:cpumask */ + /* vmx:sched.cpu.affinity -> def:cpumask */ // VirtualMachine:config.cpuAffinity.affinitySet if (esxUtil_GetConfigString(conn, conf, "sched.cpu.affinity", &sched_cpu_affinity, 1) < 0) { @@ -630,6 +855,22 @@ esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, goto failure; } + /* vmx:guestOS -> def:os.arch */ + if (esxUtil_GetConfigString(conn, conf, "guestOS", &guestOS, 1) < 0) { + goto failure; + } + + if (guestOS != NULL && esxUtil_EqualSuffix(guestOS, "-64")) { + def->os.arch = strdup("x86_64"); + } else { + def->os.arch = strdup("i686"); + } + + if (def->os.arch == NULL) { + virReportOOMError(conn); + goto failure; + } + /* def->emulator def->features*/ @@ -640,8 +881,8 @@ esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, /* def:graphics */ /* FIXME */ - /* def:disks: 4 * 16 scsi + 2 * 2 ide + 2 floppy = 70 */ - if (VIR_ALLOC_N(def->disks, 72) < 0) { + /* def:disks: 4 * 15 scsi + 2 * 2 ide + 2 floppy = 66 */ + if (VIR_ALLOC_N(def->disks, 66) < 0) { virReportOOMError(conn); goto failure; } @@ -803,14 +1044,15 @@ esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, } } -cleanup: + cleanup: virConfFree(conf); VIR_FREE(sched_cpu_affinity); + VIR_FREE(guestOS); VIR_FREE(scsi_virtualDev); return def; -failure: + failure: virDomainDefFree(def); def = NULL; @@ -851,7 +1093,7 @@ esxVMX_ParseSCSIController(virConnectPtr conn, virConfPtr conf, int controller, } if (esxUtil_GetConfigString(conn, conf, virtualDev_name, - virtualDev, 0) < 0) { + virtualDev, 1) < 0) { goto failure; } @@ -866,7 +1108,7 @@ esxVMX_ParseSCSIController(virConnectPtr conn, virConfPtr conf, int controller, return 0; -failure: + failure: VIR_FREE(*virtualDev); return -1; @@ -874,45 +1116,6 @@ failure: -char * -esxVMX_IndexToDiskName(virConnectPtr conn, int idx, const char *prefix) -{ - char buffer[32] = ""; - char *name = NULL; - size_t length = strlen(prefix); - - if (length > sizeof (buffer) - 2 - 1) { - ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "Disk name prefix '%s' is too long", prefix); - return NULL; - } - - strncpy(buffer, prefix, sizeof (buffer) - 1); - buffer[sizeof (buffer) - 1] = '\0'; - - if (idx < 26) { - buffer[length] = 'a' + idx; - } else if (idx < 702) { - buffer[length] = 'a' + idx / 26 - 1; - buffer[length + 1] = 'a' + idx % 26; - } else { - ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "Disk index %d is too large", idx); - return NULL; - } - - name = strdup(buffer); - - if (name == NULL) { - virReportOOMError(conn); - return NULL; - } - - return name; -} - - - /* struct _virDomainDiskDef { int type; // partly done @@ -1012,8 +1215,9 @@ esxVMX_ParseDisk(virConnectPtr conn, virConfPtr conf, int device, int bus, goto failure; } - (*def)->dst = esxVMX_IndexToDiskName(conn, controller * 16 + id, - "sd"); + (*def)->dst = + esxVMX_IndexToDiskName + (conn, controller * 15 + (id < 7 ? id : id - 1), "sd"); if ((*def)->dst == NULL) { goto failure; @@ -1054,9 +1258,9 @@ esxVMX_ParseDisk(virConnectPtr conn, virConfPtr conf, int device, int bus, } } else { ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "Unsupported bus type '%s' for '%s' device type", - virDomainDiskBusTypeToString (bus), - virDomainDiskDeviceTypeToString (device)); + "Unsupported bus type '%s' for device type '%s'", + virDomainDiskBusTypeToString(bus), + virDomainDiskDeviceTypeToString(device)); goto failure; } } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) { @@ -1080,15 +1284,15 @@ esxVMX_ParseDisk(virConnectPtr conn, virConfPtr conf, int device, int bus, } } else { ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "Unsupported bus type '%s' for '%s' device type", - virDomainDiskBusTypeToString (bus), - virDomainDiskDeviceTypeToString (device)); + "Unsupported bus type '%s' for device type '%s'", + virDomainDiskBusTypeToString(bus), + virDomainDiskDeviceTypeToString(device)); goto failure; } } else { ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Unsupported device type '%s'", - virDomainDiskDeviceTypeToString (device)); + virDomainDiskDeviceTypeToString(device)); goto failure; } @@ -1132,7 +1336,7 @@ esxVMX_ParseDisk(virConnectPtr conn, virConfPtr conf, int device, int bus, if (clientDevice) { /* * Just ignore devices in client mode, because I have no clue how to - * handle them (e.g. assign an image) without the VI client GUI. + * handle them (e.g. assign an image) without the VI Client GUI. */ goto ignore; } @@ -1174,6 +1378,16 @@ esxVMX_ParseDisk(virConnectPtr conn, virConfPtr conf, int device, int bus, } } + if (writeThrough && virtualDev == NULL) { + /* + * FIXME: If no virtualDev is explicit specified need to get + * the default based on the guestOS. The mechanism to + * obtain the default is currently missing + */ + VIR_WARN0("No explicit SCSI driver specified in VMX config, " + "cannot represent explicit specified cachemode"); + } + (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE; (*def)->src = fileName; (*def)->cachemode = writeThrough ? VIR_DOMAIN_DISK_CACHE_WRITETHRU @@ -1258,11 +1472,11 @@ esxVMX_ParseDisk(virConnectPtr conn, virConfPtr conf, int device, int bus, } else { ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Unsupported device type '%s'", - virDomainDiskDeviceTypeToString (device)); + virDomainDiskDeviceTypeToString(device)); goto failure; } -cleanup: + cleanup: VIR_FREE(prefix); VIR_FREE(deviceType); VIR_FREE(fileType); @@ -1270,10 +1484,10 @@ cleanup: return result; -failure: + failure: result = -1; -ignore: + ignore: virDomainDiskDefFree(*def); *def = NULL; @@ -1313,6 +1527,9 @@ esxVMX_ParseEthernet(virConnectPtr conn, virConfPtr conf, int controller, char vnet_name[48] = ""; char *vnet = NULL; + char networkName_name[48] = ""; + char *networkName = NULL; + if (def == NULL || *def != NULL) { ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); return -1; @@ -1339,6 +1556,7 @@ esxVMX_ParseEthernet(virConnectPtr conn, virConfPtr conf, int controller, ESX_BUILD_VMX_NAME(generatedAddress); ESX_BUILD_VMX_NAME(address); ESX_BUILD_VMX_NAME(virtualDev); + ESX_BUILD_VMX_NAME(networkName); ESX_BUILD_VMX_NAME(vnet); /* vmx:present */ @@ -1416,7 +1634,16 @@ esxVMX_ParseEthernet(virConnectPtr conn, virConfPtr conf, int controller, goto failure; } - /* vmx:vnet -> def:data.bridge.brname */ + /* vmx:networkName -> def:data.bridge.brname */ + if ((connectionType == NULL || + STRCASEEQ(connectionType, "bridged") || + STRCASEEQ(connectionType, "custom")) && + esxUtil_GetConfigString(conn, conf, networkName_name, + &networkName, 0) < 0) { + goto failure; + } + + /* vmx:vnet -> def:data.ifname */ if (connectionType != NULL && STRCASEEQ(connectionType, "custom") && esxUtil_GetConfigString(conn, conf, vnet_name, &vnet, 0) < 0) { goto failure; @@ -1426,8 +1653,10 @@ esxVMX_ParseEthernet(virConnectPtr conn, virConfPtr conf, int controller, if (connectionType == NULL || STRCASEEQ(connectionType, "bridged")) { (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE; (*def)->model = virtualDev; + (*def)->data.bridge.brname = networkName; virtualDev = NULL; + networkName = NULL; } else if (STRCASEEQ(connectionType, "hostonly")) { /* FIXME */ ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, @@ -1443,9 +1672,11 @@ esxVMX_ParseEthernet(virConnectPtr conn, virConfPtr conf, int controller, } else if (STRCASEEQ(connectionType, "custom")) { (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE; (*def)->model = virtualDev; - (*def)->data.bridge.brname = vnet; + (*def)->data.bridge.brname = networkName; + (*def)->ifname = vnet; virtualDev = NULL; + networkName = NULL; vnet = NULL; } else { ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, @@ -1454,7 +1685,7 @@ esxVMX_ParseEthernet(virConnectPtr conn, virConfPtr conf, int controller, goto failure; } -cleanup: + cleanup: VIR_FREE(connectionType); VIR_FREE(addressType); VIR_FREE(generatedAddress); @@ -1464,10 +1695,10 @@ cleanup: return result; -failure: + failure: result = -1; -ignore: + ignore: virDomainNetDefFree(*def); *def = NULL; @@ -1559,10 +1790,15 @@ esxVMX_ParseSerial(virConnectPtr conn, virConfPtr conf, int port, fileName = NULL; } else if (STRCASEEQ(fileType, "pipe")) { - /* FIXME */ - VIR_WARN("Serial port %d has currently unsupported type '%s', " - "ignoring it", port, fileType); - goto ignore; + /* + * FIXME: Differences between client/server and VM/application pipes + * not representable in domain XML form + */ + (*def)->dstPort = port; + (*def)->type = VIR_DOMAIN_CHR_TYPE_PIPE; + (*def)->data.file.path = fileName; + + fileName = NULL; } else { ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Expecting VMX entry '%s' to be 'device', 'file' or 'pipe' " @@ -1570,16 +1806,16 @@ esxVMX_ParseSerial(virConnectPtr conn, virConfPtr conf, int port, goto failure; } -cleanup: + cleanup: VIR_FREE(fileType); VIR_FREE(fileName); return result; -failure: + failure: result = -1; -ignore: + ignore: virDomainChrDefFree(*def); *def = NULL; @@ -1677,18 +1913,667 @@ esxVMX_ParseParallel(virConnectPtr conn, virConfPtr conf, int port, goto failure; } -cleanup: + cleanup: VIR_FREE(fileType); VIR_FREE(fileName); return result; -failure: + failure: result = -1; -ignore: + ignore: virDomainChrDefFree(*def); *def = NULL; goto cleanup; } + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Domain XML -> VMX + */ + +char * +esxVMX_FormatConfig(virConnectPtr conn, virDomainDefPtr def, + esxVI_APIVersion apiVersion) +{ + int i; + int sched_cpu_affinity_length; + unsigned char zero[VIR_UUID_BUFLEN]; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + char *vmx = NULL; + + memset(zero, 0, VIR_UUID_BUFLEN); + + if (def->virtType != VIR_DOMAIN_VIRT_VMWARE) { /* FIXME: maybe add VIR_DOMAIN_VIRT_ESX ? */ + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting virt type to be '%s' but found '%s'", + virDomainVirtTypeToString(VIR_DOMAIN_VIRT_VMWARE), + virDomainVirtTypeToString(def->virtType)); + return NULL; + } + + /* vmx:config.version */ + virBufferAddLit(&buffer, "config.version = \"8\"\n"); + + /* vmx:virtualHW.version */ + switch (apiVersion) { + case esxVI_APIVersion_25: + virBufferAddLit(&buffer, "virtualHW.version = \"4\"\n"); + break; + + case esxVI_APIVersion_40: + virBufferAddLit(&buffer, "virtualHW.version = \"7\"\n"); + break; + + default: + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VI API version 2.5 or 4.0"); + goto failure; + } + + /* def:arch -> vmx:guestOS */ + if (def->os.arch == NULL || STRCASEEQ(def->os.arch, "i686")) { + virBufferAddLit(&buffer, "guestOS = \"other\"\n"); + } else if (STRCASEEQ(def->os.arch, "x86_64")) { + virBufferAddLit(&buffer, "guestOS = \"other-64\"\n"); + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML attribute 'arch' of entry 'os/type' " + "to be 'i686' or 'x86_64' but found '%s'", def->os.arch); + goto failure; + } + + /* def:uuid -> vmx:uuid.action, vmx:uuid.bios */ + if (memcmp(def->uuid, zero, VIR_UUID_BUFLEN) == 0) { + virBufferAddLit(&buffer, "uuid.action = \"create\"\n"); + } else { + virBufferVSprintf(&buffer, "uuid.bios = \"%02x %02x %02x %02x %02x %02x " + "%02x %02x-%02x %02x %02x %02x %02x %02x %02x %02x\"\n", + def->uuid[0], def->uuid[1], def->uuid[2], def->uuid[3], + def->uuid[4], def->uuid[5], def->uuid[6], def->uuid[7], + def->uuid[8], def->uuid[9], def->uuid[10], def->uuid[11], + def->uuid[12], def->uuid[13], def->uuid[14], + def->uuid[15]); + } + + /* def:name -> vmx:displayName */ + virBufferVSprintf(&buffer, "displayName = \"%s\"\n", def->name); + + /* def:maxmem -> vmx:memsize */ + if (def->maxmem <= 0 || def->maxmem % 4096 != 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML entry 'memory' to be an unsigned " + "integer (multiple of 4096) but found %lld", + (unsigned long long)def->maxmem); + goto failure; + } + + /* Scale from kilobytes to megabytes */ + virBufferVSprintf(&buffer, "memsize = \"%d\"\n", + (int)(def->maxmem / 1024)); + + /* def:memory -> vmx:sched.mem.max */ + if (def->memory < def->maxmem) { + if (def->memory <= 0 || def->memory % 1024 != 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML entry 'currentMemory' to be an " + "unsigned integer (multiple of 1024) but found %lld", + (unsigned long long)def->memory); + goto failure; + } + + /* Scale from kilobytes to megabytes */ + virBufferVSprintf(&buffer, "sched.mem.max = \"%d\"\n", + (int)(def->memory / 1024)); + } + + /* vmx:numvcpus -> def:vcpus */ + if (def->vcpus <= 0 || (def->vcpus % 2 != 0 && def->vcpus != 1)) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML entry 'vcpu' to be an unsigned " + "integer (1 or a multiple of 2) but found %d", + (int)def->vcpus); + goto failure; + } + + virBufferVSprintf(&buffer, "numvcpus = \"%d\"\n", (int)def->vcpus); + + /* def:cpumask -> vmx:sched.cpu.affinity */ + if (def->cpumasklen > 0) { + virBufferAddLit(&buffer, "sched.cpu.affinity = \""); + + sched_cpu_affinity_length = 0; + + for (i = 0; i < def->cpumasklen; ++i) { + if (def->cpumask[i]) { + ++sched_cpu_affinity_length; + } + } + + if (sched_cpu_affinity_length < def->vcpus) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML attribute 'cpuset' of entry " + "'vcpu' to contains at least %d CPU(s)", + (int)def->vcpus); + goto failure; + } + + for (i = 0; i < def->cpumasklen; ++i) { + if (def->cpumask[i]) { + virBufferVSprintf(&buffer, "%d", i); + + if (sched_cpu_affinity_length > 1) { + virBufferAddChar(&buffer, ','); + } + + --sched_cpu_affinity_length; + } + } + + virBufferAddLit(&buffer, "\"\n"); + } + + /* def:disks */ + int scsi_present[4] = { 0, 0, 0, 0 }; + char *scsi_virtualDev[4] = { NULL, NULL, NULL, NULL }; + + if (esxVMX_GatherSCSIControllers(conn, def, scsi_virtualDev, + scsi_present) < 0) { + goto failure; + } + + for (i = 0; i < 4; ++i) { + if (scsi_present[i]) { + virBufferVSprintf(&buffer, "scsi%d.present = \"true\"\n", i); + + if (scsi_virtualDev[i] != NULL) { + virBufferVSprintf(&buffer, "scsi%d.virtualDev = \"%s\"\n", i, + scsi_virtualDev[i]); + } + } + } + + for (i = 0; i < def->ndisks; ++i) { + switch (def->disks[i]->device) { + case VIR_DOMAIN_DISK_DEVICE_DISK: + if (esxVMX_FormatHardDisk(conn, def->disks[i], &buffer) < 0) { + goto failure; + } + + break; + + case VIR_DOMAIN_DISK_DEVICE_CDROM: + if (esxVMX_FormatCDROM(conn, def->disks[i], &buffer) < 0) { + goto failure; + } + + break; + + case VIR_DOMAIN_DISK_DEVICE_FLOPPY: + if (esxVMX_FormatFloppy(conn, def->disks[i], &buffer) < 0) { + goto failure; + } + + break; + + default: + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unsuppotred disk device type '%s'", + virDomainDiskDeviceTypeToString(def->disks[i]->device)); + goto failure; + } + } + + /* def:fss */ + /* FIXME */ + + /* def:nets */ + for (i = 0; i < def->nnets; ++i) { + if (esxVMX_FormatEthernet(conn, def->nets[i], i, &buffer) < 0) { + goto failure; + } + } + + /* def:inputs */ + /* FIXME */ + + /* def:sounds */ + /* FIXME */ + + /* def:hostdevs */ + /* FIXME */ + + /* def:serials */ + for (i = 0; i < def->nserials; ++i) { + if (esxVMX_FormatSerial(conn, def->serials[i], &buffer) < 0) { + goto failure; + } + } + + /* def:parallels */ + for (i = 0; i < def->nparallels; ++i) { + if (esxVMX_FormatParallel(conn, def->parallels[i], &buffer) < 0) { + goto failure; + } + } + + /* Get final VMX output */ + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + vmx = virBufferContentAndReset(&buffer); + + return vmx; + + failure: + if (vmx == NULL) { + vmx = virBufferContentAndReset(&buffer); + } + + VIR_FREE(vmx); + + return NULL; +} + + + +int +esxVMX_FormatHardDisk(virConnectPtr conn, virDomainDiskDefPtr def, + virBufferPtr buffer) +{ + int controller, id; + const char *busName = NULL; + const char *entryPrefix = NULL; + const char *deviceTypePrefix = NULL; + + if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) { + busName = "SCSI"; + entryPrefix = "scsi"; + deviceTypePrefix = "scsi"; + + if (esxVMX_SCSIDiskNameToControllerAndID(conn, def->dst, + &controller, &id) < 0) { + return -1; + } + } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) { + busName = "IDE"; + entryPrefix = "ide"; + deviceTypePrefix = "ata"; + + if (esxVMX_IDEDiskNameToControllerAndID(conn, def->dst, + &controller, &id) < 0) { + return -1; + } + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unsupported bus type '%s' for harddisk", + virDomainDiskBusTypeToString(def->bus)); + return -1; + } + + if (def->type != VIR_DOMAIN_DISK_TYPE_FILE) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "%s harddisk '%s' has unsupported type '%s', expecting '%s'", + busName, def->dst, virDomainDiskTypeToString(def->type), + virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE)); + return -1; + } + + virBufferVSprintf(buffer, "%s%d:%d.present = \"true\"\n", + entryPrefix, controller, id); + virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"%s-hardDisk\"\n", + entryPrefix, controller, id, deviceTypePrefix); + + if (def->src != NULL) { + if (! esxUtil_EqualSuffix(def->src, ".vmdk")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Image file for %s harddisk '%s' has unsupported suffix, " + "expecting '.vmdk'", busName, def->dst); + return -1; + } + + virBufferVSprintf(buffer, "%s%d:%d.fileName = \"%s\"\n", + entryPrefix, controller, id, def->src); + } + + if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) { + if (def->cachemode == VIR_DOMAIN_DISK_CACHE_WRITETHRU) { + virBufferVSprintf(buffer, "%s%d:%d.writeThrough = \"true\"\n", + entryPrefix, controller, id); + } else if (def->cachemode != VIR_DOMAIN_DISK_CACHE_DEFAULT) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "%s harddisk '%s' has unsupported cache mode '%s'", + busName, def->dst, + virDomainDiskCacheTypeToString(def->cachemode)); + return -1; + } + } + + return 0; +} + + + +int +esxVMX_FormatCDROM(virConnectPtr conn, virDomainDiskDefPtr def, + virBufferPtr buffer) +{ + int controller, id; + const char *busName = NULL; + const char *entryPrefix = NULL; + + if (def->device != VIR_DOMAIN_DISK_DEVICE_CDROM) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) { + busName = "SCSI"; + entryPrefix = "scsi"; + + if (esxVMX_SCSIDiskNameToControllerAndID(conn, def->dst, + &controller, &id) < 0) { + return -1; + } + } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) { + busName = "IDE"; + entryPrefix = "ide"; + + if (esxVMX_IDEDiskNameToControllerAndID(conn, def->dst, + &controller, &id) < 0) { + return -1; + } + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unsupported bus type '%s' for cdrom", + virDomainDiskBusTypeToString(def->bus)); + return -1; + } + + virBufferVSprintf(buffer, "%s%d:%d.present = \"true\"\n", + entryPrefix, controller, id); + + if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) { + virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"cdrom-image\"\n", + entryPrefix, controller, id); + } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) { + virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"atapi-cdrom\"\n", + entryPrefix, controller, id); + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "%s cdrom '%s' has unsupported type '%s', expecting '%s' " + "or '%s'", busName, def->dst, + virDomainDiskTypeToString(def->type), + virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE), + virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_BLOCK)); + return -1; + } + + if (def->src != NULL) { + if (def->type == VIR_DOMAIN_DISK_TYPE_FILE && + ! esxUtil_EqualSuffix(def->src, ".iso")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Image file for %s cdrom '%s' has unsupported suffix, " + "expecting '.iso'", busName, def->dst); + return -1; + } + + virBufferVSprintf(buffer, "%s%d:%d.fileName = \"%s\"\n", + entryPrefix, controller, id, def->src); + } + + return 0; +} + + + +int +esxVMX_FormatFloppy(virConnectPtr conn, virDomainDiskDefPtr def, + virBufferPtr buffer) +{ + int controller; + + if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (esxVMX_FloppyDiskNameToController(conn, def->dst, &controller) < 0) { + return -1; + } + + virBufferVSprintf(buffer, "floppy%d.present = \"true\"\n", controller); + + if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) { + virBufferVSprintf(buffer, "floppy%d.fileType = \"file\"\n", + controller); + } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) { + virBufferVSprintf(buffer, "floppy%d.fileType = \"device\"\n", + controller); + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Floppy '%s' has unsupported type '%s', expecting '%s' " + "or '%s'", def->dst, + virDomainDiskTypeToString(def->type), + virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE), + virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_BLOCK)); + return -1; + } + + if (def->src != NULL) { + if (def->type == VIR_DOMAIN_DISK_TYPE_FILE && + ! esxUtil_EqualSuffix(def->src, ".flp")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Image file for floppy '%s' has unsupported suffix, " + "expecting '.flp'", def->dst); + return -1; + } + + virBufferVSprintf(buffer, "floppy%d.fileName = \"%s\"\n", controller, + def->src); + } + + return 0; +} + + + +int +esxVMX_FormatEthernet(virConnectPtr conn, virDomainNetDefPtr def, + int controller, virBufferPtr buffer) +{ + char mac_string[VIR_MAC_STRING_BUFLEN]; + + if (controller < 0 || controller > 3) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Ethernet controller index %d out of [0..3] range", + controller); + return -1; + } + + virBufferVSprintf(buffer, "ethernet%d.present = \"true\"\n", controller); + + /* def:model -> vmx:virtualDev */ + if (def->model != NULL) { + if (STRCASENEQ(def->model, "vlance") && + STRCASENEQ(def->model, "vmxnet") && + STRCASENEQ(def->model, "e1000")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML entry 'devices/interfase/model' " + "to be 'vlance' or 'vmxnet' or 'e1000' but found '%s'", + def->model); + return -1; + } + + virBufferVSprintf(buffer, "ethernet%d.virtualDev = \"%s\"\n", + controller, def->model); + } + + /* def:type, def:ifname -> vmx:connectionType */ + switch (def->type) { + case VIR_DOMAIN_NET_TYPE_BRIDGE: + virBufferVSprintf(buffer, "ethernet%d.networkName = \"%s\"\n", + controller, def->data.bridge.brname); + + if (def->ifname != NULL) { + virBufferVSprintf(buffer, "ethernet%d.connectionType = \"custom\"\n", + controller); + virBufferVSprintf(buffer, "ethernet%d.vnet = \"%s\"\n", + controller, def->ifname); + } else { + virBufferVSprintf(buffer, "ethernet%d.connectionType = \"bridged\"\n", + controller); + } + + break; + + default: + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unsupported net type '%s'", + virDomainNetTypeToString(def->type)); + return -1; + } + + virFormatMacAddr(def->mac, mac_string); + + if (def->mac[0] == 0x00 && def->mac[1] == 0x0c && def->mac[2] == 0x29) { + virBufferVSprintf(buffer, "ethernet%d.addressType = \"generated\"\n", + controller); + virBufferVSprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n", + controller, mac_string); + } else if (def->mac[0] == 0x00 && def->mac[1] == 0x50 && + def->mac[2] == 0x56) { + virBufferVSprintf(buffer, "ethernet%d.addressType = \"static\"\n", + controller); + virBufferVSprintf(buffer, "ethernet%d.address = \"%s\"\n", + controller, mac_string); + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unsupported MAC address prefix '%02X:%02X:%02X', expecting " + "'00:0c:29' or '00:50:56'", + def->mac[0], def->mac[1], def->mac[2]); + return -1; + } + + return 0; +} + + + +int +esxVMX_FormatSerial(virConnectPtr conn, virDomainChrDefPtr def, + virBufferPtr buffer) +{ + if (def->dstPort < 0 || def->dstPort > 3) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Serial port index %d out of [0..3] range", def->dstPort); + return -1; + } + + if (def->data.file.path == NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML attribute 'path' of entry " + "'devices/serial/source' to be present"); + return -1; + } + + virBufferVSprintf(buffer, "serial%d.present = \"true\"\n", def->dstPort); + + /* def:type -> vmx:fileType */ + switch (def->type) { + case VIR_DOMAIN_CHR_TYPE_DEV: + virBufferVSprintf(buffer, "serial%d.fileType = \"device\"\n", + def->dstPort); + break; + + case VIR_DOMAIN_CHR_TYPE_FILE: + virBufferVSprintf(buffer, "serial%d.fileType = \"file\"\n", + def->dstPort); + break; + + case VIR_DOMAIN_CHR_TYPE_PIPE: + virBufferVSprintf(buffer, "serial%d.fileType = \"pipe\"\n", + def->dstPort); + /* FIXME: Based on VI Client GUI default */ + virBufferVSprintf(buffer, "serial%d.pipe.endPoint = \"client\"\n", + def->dstPort); + /* FIXME: Based on VI Client GUI default */ + virBufferVSprintf(buffer, "serial%d.tryNoRxLoss = \"false\"\n", + def->dstPort); + break; + + default: + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unsupported character device type '%s'", + virDomainChrTypeToString(def->type)); + return -1; + } + + /* def:data.file.path -> vmx:fileName */ + virBufferVSprintf(buffer, "serial%d.fileName = \"%s\"\n", + def->dstPort, def->data.file.path); + + /* vmx:yieldOnMsrRead */ + /* FIXME: Based on VI Client GUI default */ + virBufferVSprintf(buffer, "serial%d.yieldOnMsrRead = \"true\"\n", + def->dstPort); + + return 0; +} + + + +int +esxVMX_FormatParallel(virConnectPtr conn, virDomainChrDefPtr def, + virBufferPtr buffer) +{ + if (def->dstPort < 0 || def->dstPort > 2) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Parallel port index %d out of [0..2] range", def->dstPort); + return -1; + } + + if (def->data.file.path == NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting domain XML attribute 'path' of entry " + "'devices/parallel/source' to be present"); + return -1; + } + + virBufferVSprintf(buffer, "parallel%d.present = \"true\"\n", def->dstPort); + + /* def:type -> vmx:fileType */ + switch (def->type) { + case VIR_DOMAIN_CHR_TYPE_DEV: + virBufferVSprintf(buffer, "parallel%d.fileType = \"device\"\n", + def->dstPort); + break; + + case VIR_DOMAIN_CHR_TYPE_FILE: + virBufferVSprintf(buffer, "parallel%d.fileType = \"file\"\n", + def->dstPort); + break; + + default: + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unsupported character device type '%s'", + virDomainChrTypeToString(def->type)); + return -1; + } + + /* def:data.file.path -> vmx:fileName */ + virBufferVSprintf(buffer, "parallel%d.fileName = \"%s\"\n", + def->dstPort, def->data.file.path); + + return 0; +} diff --git a/src/esx/esx_vmx.h b/src/esx/esx_vmx.h index 8288003..1d77232 100644 --- a/src/esx/esx_vmx.h +++ b/src/esx/esx_vmx.h @@ -24,9 +24,33 @@ #define __ESX_VMX_H__ #include "internal.h" +#include "conf.h" #include "domain_conf.h" #include "esx_vi.h" +char * +esxVMX_IndexToDiskName(virConnectPtr conn, int idx, const char *prefix); + +int +esxVMX_SCSIDiskNameToControllerAndID(virConnectPtr conn, const char *name, + int *controller, int *id); +int +esxVMX_IDEDiskNameToControllerAndID(virConnectPtr conn, const char *name, + int *controller, int *id); +int +esxVMX_FloppyDiskNameToController(virConnectPtr conn, const char *name, + int *controller); + +int +esxVMX_GatherSCSIControllers(virConnectPtr conn, virDomainDefPtr conf, + char *virtualDev[4], int present[4]); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VMX -> Domain XML + */ + virDomainDefPtr esxVMX_ParseConfig(virConnectPtr conn, const char *vmx, esxVI_APIVersion apiVersion); @@ -35,9 +59,6 @@ int esxVMX_ParseSCSIController(virConnectPtr conn, virConfPtr conf, int controller, int *present, char **virtualDev); -char * -esxVMX_IndexToDiskName(virConnectPtr conn, int idx, const char *prefix); - int esxVMX_ParseDisk(virConnectPtr conn, virConfPtr conf, int device, int bus, int controller, int id, const char *virtualDev, @@ -54,4 +75,38 @@ int esxVMX_ParseParallel(virConnectPtr conn, virConfPtr conf, int port, virDomainChrDefPtr *def); + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Domain XML -> VMX + */ + +char * +esxVMX_FormatConfig(virConnectPtr conn, virDomainDefPtr def, + esxVI_APIVersion apiVersion); + +int +esxVMX_FormatHardDisk(virConnectPtr conn, virDomainDiskDefPtr def, + virBufferPtr buffer); + +int +esxVMX_FormatCDROM(virConnectPtr conn, virDomainDiskDefPtr def, + virBufferPtr buffer); + +int +esxVMX_FormatFloppy(virConnectPtr conn, virDomainDiskDefPtr def, + virBufferPtr buffer); + +int +esxVMX_FormatEthernet(virConnectPtr conn, virDomainNetDefPtr def, + int controller, virBufferPtr buffer); + +int +esxVMX_FormatSerial(virConnectPtr conn, virDomainChrDefPtr def, + virBufferPtr buffer); + +int +esxVMX_FormatParallel(virConnectPtr conn, virDomainChrDefPtr def, + virBufferPtr buffer); + #endif /* __ESX_VMX_H__ */
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list