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
->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
## 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"
->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
## 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"
## 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"
...
->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"
...
->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>"
->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 ###############################################################
->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
->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
+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)
long long memory = 0;
long long numvcpus = 0;
char *sched_cpu_affinity = NULL;
+ char *guestOS = NULL;
int controller;
int port;
int present;
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;
goto failure;
}
+ /* vmx:virtualHW.version */
if (esxUtil_GetConfigLong(conn, conf, "virtualHW.version",
&virtualHW_version, 0, 0) < 0) {
goto failure;
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;
}
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;
def->memory = def->maxmem;
}
- /* def:vcpus */
+ /* vmx:numvcpus -> def:vcpus */
if (esxUtil_GetConfigLong(conn, conf, "numvcpus", &numvcpus, 1, 1) < 0) {
goto failure;
}
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) {
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*/
/* 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;
}
}
}
-cleanup:
+ cleanup:
virConfFree(conf);
VIR_FREE(sched_cpu_affinity);
+ VIR_FREE(guestOS);
VIR_FREE(scsi_virtualDev);
return def;
-failure:
+ failure:
virDomainDefFree(def);
def = NULL;
}
if (esxUtil_GetConfigString(conn, conf, virtualDev_name,
- virtualDev, 0) < 0) {
+ virtualDev, 1) < 0) {
goto failure;
}
return 0;
-failure:
+ failure:
VIR_FREE(*virtualDev);
return -1;
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;
}
} 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) {
}
} 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;
}
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;
}
}
}
+ 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
} 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);
return result;
-failure:
+ failure:
result = -1;
-ignore:
+ ignore:
virDomainDiskDefFree(*def);
*def = NULL;
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;
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 */
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;
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,
} 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,
goto failure;
}
-cleanup:
+ cleanup:
VIR_FREE(connectionType);
VIR_FREE(addressType);
VIR_FREE(generatedAddress);
return result;
-failure:
+ failure:
result = -1;
-ignore:
+ ignore:
virDomainNetDefFree(*def);
*def = NULL;
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' "
goto failure;
}
-cleanup:
+ cleanup:
VIR_FREE(fileType);
VIR_FREE(fileName);
return result;
-failure:
+ failure:
result = -1;
-ignore:
+ ignore:
virDomainChrDefFree(*def);
*def = NULL;
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;
+}