[libvirt] [PATCH 1/2] ESX: Add routines to interface driver

Add following routines to esx_interface_driver: esxNumOfInterfaces, esxNumOfDefinedInterfaces, esxListInterfaces, esxListDefinedInterfaces, esxInterfaceLookupByMACString, esxInterfaceGetXMLDesc, esxInterfaceUndefine, esxInterfaceCreate, esxInterfaceDestroy Signed-off-by: Ata E Husain Bohra <ata.husain@hotmail.com> --- src/esx/esx_interface_driver.c | 506 +++++++++++++++++++++++++++++++++++++++- src/esx/esx_vi.c | 126 ++++++++++ src/esx/esx_vi.h | 10 + src/esx/esx_vi_generator.input | 227 ++++++++++++++++++ src/esx/esx_vi_generator.py | 31 ++- src/esx/esx_vi_types.c | 18 +- 6 files changed, 913 insertions(+), 5 deletions(-) diff --git a/src/esx/esx_interface_driver.c b/src/esx/esx_interface_driver.c index 5713137..b1ba5e2 100644 --- a/src/esx/esx_interface_driver.c +++ b/src/esx/esx_interface_driver.c @@ -23,6 +23,9 @@ */ #include <config.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> #include "internal.h" #include "util.h" @@ -34,6 +37,7 @@ #include "esx_vi.h" #include "esx_vi_methods.h" #include "esx_util.h" +#include "interface_conf.h" #define VIR_FROM_THIS VIR_FROM_ESX @@ -67,10 +71,508 @@ esxInterfaceClose(virConnectPtr conn) +static int +esxNumOfInterfaces(virConnectPtr conn) +{ + esxPrivate *priv = conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL; + int count = 0; + + if (esxVI_EnsureSession(priv->primary) < 0 || + esxVI_LookupVirtualNicList(priv->primary, &virtualNicList) < 0) { + goto cleanup; + } + + if (virtualNicList == NULL) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not retrieve vNic List")); + + goto cleanup; + } + + for (virtualNic = virtualNicList; + virtualNic != NULL; + virtualNic = virtualNic->_next) { + count++; + } + +cleanup: + + esxVI_HostVirtualNic_Free(&virtualNicList); + + return count; +} + + + +static int +esxNumOfDefinedInterfaces(virConnectPtr conn) +{ + conn->interfacePrivateData = NULL; + + // ESX interfaces are always active + return 0; +} + + + +static int +esxListInterfaces(virConnectPtr conn, char **names, int maxnames) +{ + esxPrivate *priv = conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL; + int result = -1; + int i = 0; + + if (esxVI_EnsureSession(priv->primary) < 0 || + esxVI_LookupVirtualNicList(priv->primary, + &virtualNicList) < 0) { + goto cleanup; + } + + if (virtualNicList == NULL) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not retrieve vNIC List")); + goto cleanup; + } + + for (i= 0, virtualNic = virtualNicList; + virtualNic != NULL && i < maxnames; + ++i, virtualNic = virtualNic->_next) { + names[i] = strdup(virtualNic->device); + + if (names[i] == NULL) { + for(;i >=0;--i) { + VIR_FREE(names[i]); + } + virReportOOMError(); + goto cleanup; + } + } + + result = i; + cleanup: + esxVI_HostVirtualNic_Free(&virtualNicList); + + return result; +} + + + +static int +esxListDefinedInterfaces(virConnectPtr conn, char **names, int maxnames) +{ + conn->interfacePrivateData = conn->privateData; + *names = NULL; + + /* keeps compiler happy */ + VIR_DEBUG("max interfaces: %d", maxnames); + + // ESX interfaces are always active + return 0; +} + + + +static virInterfacePtr +esxInterfaceLookupByName(virConnectPtr conn, const char *name) +{ + esxPrivate *priv = conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL; + virInterfacePtr ret = NULL; + + if (esxVI_EnsureSession(priv->primary) < 0 || + esxVI_LookupVirtualNicList(priv->primary, + &virtualNicList) < 0) { + goto cleanup; + } + + if (virtualNicList == 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not retrieve vNIC List")); + goto cleanup; + } + + + for(virtualNic = virtualNicList; + virtualNic != NULL; + virtualNic = virtualNic->_next) { + if (STREQ(virtualNic->device, name)) { + if (virtualNic->spec == NULL || + virtualNic->spec->mac == NULL) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed HostVirtualNicSpec")); + goto cleanup; + } + + ret = virGetInterface(conn, virtualNic->device, virtualNic->spec->mac); + break; + } + } + + cleanup: + esxVI_HostVirtualNic_Free(&virtualNicList); + + return ret; +} + + + +static virInterfacePtr +esxInterfaceLookupByMACString(virConnectPtr conn, const char *mac) +{ + esxPrivate *priv = conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL; + virInterfacePtr ret = NULL; + + if (esxVI_EnsureSession(priv->primary) < 0 || + esxVI_LookupVirtualNicList(priv->primary, + &virtualNicList) < 0) { + goto cleanup; + } + + if (virtualNicList == 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not retrieve vNIC List")); + goto cleanup; + } + + + for(virtualNic = virtualNicList; + virtualNic != NULL; + virtualNic = virtualNic->_next) { + if (virtualNic->spec == NULL || + virtualNic->spec->mac == NULL) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed HostVirtualNicSpec")); + goto cleanup; + } + + if (STREQ(virtualNic->spec->mac, mac)) { + ret = virGetInterface(conn, virtualNic->device, virtualNic->spec->mac); + break; + } + } + + cleanup: + esxVI_HostVirtualNic_Free(&virtualNicList); + + return ret; +} + + + +static char* +esxInterfaceGetXMLDesc(virInterfacePtr iface, unsigned int flags) +{ + esxPrivate *priv = iface->conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL; + esxVI_PhysicalNic *physicalNicList = NULL; + const esxVI_PhysicalNic *physicalNic = NULL; + esxVI_PhysicalNic *matchingPhysicalNicList = NULL; + esxVI_HostIpRouteConfig *ipRouteConfig = NULL; + esxVI_HostPortGroup *portGroupList = NULL; + esxVI_HostVirtualSwitch *virtualSwitchList = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + virInterfaceDefPtr def = NULL; + int use_static = 0; + struct in_addr addr; + uint32_t host_addr = 0; + int zero_count = 0; + int masklen = 0; + int i = 0; + char *ret = NULL; + + if (VIR_INTERFACE_XML_INACTIVE & flags) { + use_static = 1; + } + + if (esxVI_EnsureSession(priv->primary) < 0 || + esxVI_String_AppendValueListToList(&propertyNameList, + "config.network.vnic\0" + "config.network.ipRouteConfig\0" + "config.network.vswitch\0" + "config.network.pnic\0" + "config.network.portgroup\0") < 0 || + esxVI_LookupHostSystemProperties(priv->primary, propertyNameList, + &hostSystem) < 0) { + goto cleanup; + } + + for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "config.network.vnic")) { + if (esxVI_HostVirtualNic_CastListFromAnyType( + dynamicProperty->val, &virtualNicList) < 0) { + goto cleanup; + } + } else if (STREQ(dynamicProperty->name, + "config.network.ipRouteConfig")) { + if (esxVI_HostIpRouteConfig_CastFromAnyType( + dynamicProperty->val, &ipRouteConfig)) { + goto cleanup; + } + } else if (STREQ(dynamicProperty->name, "config.network.vswitch")) { + if (esxVI_HostVirtualSwitch_CastListFromAnyType + (dynamicProperty->val, &virtualSwitchList) < 0) { + goto cleanup; + } + } else if (STREQ(dynamicProperty->name, "config.network.pnic")) { + if (esxVI_PhysicalNic_CastListFromAnyType( + dynamicProperty->val, &physicalNicList) < 0) { + goto cleanup; + } + } else if (STREQ(dynamicProperty->name, "config.network.portgroup")) { + if (esxVI_HostPortGroup_CastListFromAnyType( + dynamicProperty->val, &portGroupList) < 0) { + goto cleanup; + } + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + if (!virtualNicList || + !ipRouteConfig || + !virtualSwitchList || + !portGroupList) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to retrieve network parameters")); + + goto cleanup; + } + + for (virtualNic = virtualNicList; + virtualNic != NULL; + virtualNic = virtualNic->_next) { + if (STREQ(virtualNic->device, iface->name)) { + break; + } + } + + if (virtualNic == NULL) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not find Interface")); + goto cleanup; + } + + if (esxVI_LookupPhysicalNicFromPortGroup(virtualNic->portgroup, + portGroupList, + virtualSwitchList, + physicalNicList, + &matchingPhysicalNicList) < 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("No Physical NIC found matching Virtual NIC's portgroup")); + goto cleanup; + } + + /* + * populate virInterfaceDef object to obtain + * libvirt interface domain xml. + */ + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + goto cleanup; + } + + def->type = VIR_INTERFACE_TYPE_BRIDGE; + def->name = strdup(virtualNic->device); + if (virtualNic->spec->mtu && virtualNic->spec->mtu->value) { + def->mtu = virtualNic->spec->mtu->value; + } else { + def->mtu = 1500; + } + + def->startmode = VIR_INTERFACE_START_ONBOOT; + + if (!use_static && virtualNic->spec->mac) { + def->mac = strdup(virtualNic->spec->mac); + } + + /* TODO - Handle VLAN (via portgroup?) */ + if (virtualNic->spec->ip->subnetMask && + *virtualNic->spec->ip->subnetMask && + inet_aton(virtualNic->spec->ip->subnetMask, &addr) == 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Error parsing netmask")); + goto cleanup; + } + + host_addr = ntohl(addr.s_addr); + /* Calculate masklen */ + for (i = 0; i < 32; ++i) { + if (host_addr & 0x01) { + break; + } + zero_count++; + host_addr >>= 1; + } + masklen = 32 - zero_count; + + /* append protocol field */ + def->nprotos = 1; + if (VIR_ALLOC_N(def->protos, def->nprotos) < 0) { + virReportOOMError(); + goto cleanup; + } + + /* TODO - Add IPv6 Support */ + for (i = 0; i < def->nprotos; ++i) { + if (VIR_ALLOC(def->protos[i]) < 0) { + goto cleanup; + } + + def->protos[i]->family = strdup("ipv4"); + if (virtualNic->spec->ip->dhcp == 1) { + def->protos[i]->dhcp = 1; + } + def->protos[i]->nips = 1; + if (virtualNic->spec->ip->dhcp != 1 || !use_static) { + if (virtualNic->spec->ip->ipAddress && + *virtualNic->spec->ip->ipAddress) { + int j =0; + if (VIR_ALLOC_N(def->protos[i]->ips, def->protos[i]->nips) + < 0) { + virReportOOMError(); + goto cleanup; + } + + for (j=0; j < def->protos[i]->nips; ++j) { + if (VIR_ALLOC(def->protos[i]->ips[j]) < 0) { + virReportOOMError(); + goto cleanup; + } + def->protos[i]->ips[0]->address = + strdup(virtualNic->spec->ip->ipAddress); + def->protos[i]->ips[0]->prefix = masklen; + def->protos[i]->gateway = + strdup(ipRouteConfig->defaultGateway); + } + } + } + } + + /* Add bridge information */ + def->data.bridge.stp = 0; /* off */ + + /** + * traversing physical nic list twice, first to get total + * interfaces and second to populate interface items. + * Total Complexity ~= O(N); also total physical nics + * cannot be that large number + */ + for (physicalNic = matchingPhysicalNicList, i = 0; physicalNic != NULL; + physicalNic = physicalNic->_next, ++i) { + } + + if ( i > 0) { + if (VIR_ALLOC_N(def->data.bridge.itf, i) < 0) { + virReportOOMError(); + goto cleanup; + } + def->data.bridge.nbItf = i; + for (physicalNic = matchingPhysicalNicList, i = 0; physicalNic != NULL; + physicalNic = physicalNic->_next, ++i) { + virInterfaceDefPtr itf = NULL; + if (VIR_ALLOC(itf) < 0) { + virReportOOMError(); + goto cleanup; + } + itf->type = VIR_INTERFACE_TYPE_ETHERNET; + itf->name = strdup(physicalNic->device); + itf->mac = strdup(physicalNic->mac); + + def->data.bridge.itf[i] = itf; + } + } + + ret = virInterfaceDefFormat(def); + if (!ret) { + goto cleanup; + } + + cleanup: + esxVI_HostVirtualNic_Free(&virtualNicList); + esxVI_PhysicalNic_Free(&physicalNicList); + esxVI_PhysicalNic_Free(&matchingPhysicalNicList); + esxVI_HostPortGroup_Free(&portGroupList); + esxVI_HostVirtualSwitch_Free(&virtualSwitchList); + esxVI_HostIpRouteConfig_Free(&ipRouteConfig); + esxVI_ObjectContent_Free(&hostSystem); + esxVI_String_Free(&propertyNameList); + virInterfaceDefFree(def); + + return ret; +} + + + +static int +esxInterfaceUndefine(virInterfacePtr iface) +{ + esxPrivate *priv = iface->conn->interfacePrivateData; + + if (esxVI_RemoveVirtualNic( + priv->primary, + priv->primary->hostSystem->configManager->networkSystem, + iface->name) < 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Error deleting interface")); + return -1; + } + + return 0; +} + + + +static int +esxInterfaceCreate(virInterfacePtr iface, unsigned int flags) +{ + iface->conn->interfacePrivateData = NULL; + + virCheckFlags(0, -1); + + /* ESX interfaces are always active */ + return 0; +} + + + +static int +esxInterfaceDestroy(virInterfacePtr iface, unsigned int flags) +{ + iface->conn->interfacePrivateData = NULL; + + virCheckFlags(0, -1); + + /* ESX interfaces can not be deactivated */ + return 1; +} + + + static virInterfaceDriver esxInterfaceDriver = { .name = "ESX", - .open = esxInterfaceOpen, /* 0.7.6 */ - .close = esxInterfaceClose, /* 0.7.6 */ + .open = esxInterfaceOpen, /* 0.7.6 */ + .close = esxInterfaceClose, /* 0.7.6 */ + .numOfInterfaces = esxNumOfInterfaces, /* 0.9.x */ + .numOfDefinedInterfaces = esxNumOfDefinedInterfaces, /* 0.9.x */ + .listInterfaces = esxListInterfaces, /* 0.9.x */ + .listDefinedInterfaces = esxListDefinedInterfaces, /* 0.9.x */ + .interfaceLookupByName = esxInterfaceLookupByName, /* 0.9.x */ + .interfaceLookupByMACString = esxInterfaceLookupByMACString, /* 0.9.x */ + .interfaceGetXMLDesc = esxInterfaceGetXMLDesc, /* 0.9.x */ + .interfaceUndefine = esxInterfaceUndefine, /* 0.9.x */ + .interfaceCreate = esxInterfaceCreate, /* 0.9.x */ + .interfaceDestroy = esxInterfaceDestroy, /* 0.9.x */ }; diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 48718b6..80ddb76 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -4523,6 +4523,132 @@ esxVI_LookupManagedObjectHelper(esxVI_Context *ctx, return result; } +int +esxVI_LookupVirtualNicList(esxVI_Context* ctx, + esxVI_HostVirtualNic** virtualNicList) +{ + int result = -1; + esxVI_String *propertyNameList = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_ObjectContent* hostSystem = NULL; + + if (esxVI_String_AppendValueListToList( + &propertyNameList, "config.network.vnic\0") < 0 || + esxVI_LookupHostSystemProperties(ctx, propertyNameList, &hostSystem) < 0) { + goto cleanup; + } + if (hostSystem == NULL) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not retrieve the HostSystem object")); + + goto cleanup; + } + + for (dynamicProperty = hostSystem->propSet; + dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "config.network.vnic")) { + if (esxVI_HostVirtualNic_CastListFromAnyType(dynamicProperty->val, + virtualNicList) < 0) { + goto cleanup; + } + break; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + result = 0; + +cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&hostSystem); + + return result; +} + +int +esxVI_LookupPhysicalNicFromPortGroup( + const char *portgroup, + const esxVI_HostPortGroup *portGroupList, + const esxVI_HostVirtualSwitch *virtualSwitchList, + const esxVI_PhysicalNic *physicalNicList, + esxVI_PhysicalNic **ret_physicalNicList) +{ + int result = -1; + const esxVI_HostPortGroup *portGroup = NULL; + const esxVI_HostVirtualSwitch *virtualSwitch = NULL; + esxVI_PhysicalNic *matchingPhysicalNicList = NULL; + const esxVI_PhysicalNic *physicalNic = NULL; + esxVI_PhysicalNic *tempPhysicalNic = NULL; + const esxVI_String *pnicKey = NULL; + + if (portgroup == NULL) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("No Portgroup found!")); + goto cleanup; + } + + /* Go through all the port groups to find the one that matches. */ + for (portGroup = portGroupList; + portGroup != NULL; + portGroup = portGroup->_next) { + if (STREQ(portGroup->spec->name, portgroup)) { + break; + } + } + + if (portGroup == NULL) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not find Host port group")); + goto cleanup; + } + + /* Go through all the virtual switches to find the one that matches */ + for (virtualSwitch = virtualSwitchList; + virtualSwitch != NULL; + virtualSwitch = virtualSwitch->_next) { + if (STREQ(portGroup->spec->vswitchName, virtualSwitch->name)) { + break; + } + } + + if (virtualSwitch == NULL) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not find Virtual Switch")); + goto cleanup; + } + + /* Go through all physical nics */ + for (pnicKey = virtualSwitch->pnic; + pnicKey != NULL; + pnicKey = pnicKey->_next) { + /* O(n^2), but probably faster than a hash due to small N */ + for (physicalNic = physicalNicList; + physicalNic != NULL; + physicalNic = physicalNic->_next) { + + if (STREQ(pnicKey->value, physicalNic->key)) { + if (esxVI_PhysicalNic_DeepCopy(&tempPhysicalNic, + (esxVI_PhysicalNic *)physicalNic) < 0 || + esxVI_PhysicalNic_AppendToList(&matchingPhysicalNicList, + tempPhysicalNic) < 0) { + goto cleanup; + } + tempPhysicalNic = NULL; + } + } + } + + *ret_physicalNicList = matchingPhysicalNicList; + matchingPhysicalNicList = NULL; /* no cleanup needed */ + tempPhysicalNic = NULL; /* no cleanup needed */ + result = 0; + cleanup: + esxVI_PhysicalNic_Free(&matchingPhysicalNicList); + esxVI_PhysicalNic_Free(&tempPhysicalNic); + return result; +} #include "esx_vi.generated.c" diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h index 9560bd2..9b694b5 100644 --- a/src/esx/esx_vi.h +++ b/src/esx/esx_vi.h @@ -505,6 +505,16 @@ int esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedHostCpuIdInfo, int esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductVersion productVersion); +int esxVI_LookupVirtualNicList(esxVI_Context* ctx, + esxVI_HostVirtualNic** virtualNicList); + +int esxVI_LookupPhysicalNicFromPortGroup( + const char *portgroup, + const esxVI_HostPortGroup *portGroupList, + const esxVI_HostVirtualSwitch *virtualSwitchList, + const esxVI_PhysicalNic *physicalNicList, + esxVI_PhysicalNic **ret_physicalNicList); + # include "esx_vi.generated.h" #endif /* __ESX_VI_H__ */ diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input index 1a67a8c..64f8389 100644 --- a/src/esx/esx_vi_generator.input +++ b/src/esx/esx_vi_generator.input @@ -57,6 +57,29 @@ enum AutoStartWaitHeartbeatSetting systemDefault end +enum HostConfigChangeOperation + add + edit + remove +end + +enum HostIpConfigIpV6AdressStatus + deprecated + duplicate + inaccessible + invalid + preferred + tentative + unknown +end + +enum HostIpConfigV6AdressConfigType + dhcp + linklayer + manual + other + random +end enum ManagedEntityStatus gray @@ -197,6 +220,12 @@ object DeviceBackedVirtualDiskSpec extends VirtualDiskSpec String device r end +object DistributedVirtualSwitchPortConnection + Int connectionCookie o + String portgroupKey o + String portKey o + String switchUuid r +end object DynamicProperty String name r @@ -316,6 +345,34 @@ object HostFileSystemVolume Long capacity r end +object HostIpConfig + Boolean dhcp r + String ipAddress o + HostIpConfigIpV6AddressConfiguration ipV6Config o + String subnetMask o +end + +object HostIpConfigIpV6Address + String dadState o + String ipAddress r + DateTime lifetime o + String operation o + String origin o + Int prefixLength r +end + +object HostIpConfigIpV6AddressConfiguration + Boolean autoConfigurationEnabled o + Boolean dhcpV6Enabled o + HostIpConfigIpV6Address ipV6Address ol +end + +object HostIpRouteConfig + String defaultGateway o + String gatewayDevice o + String ipV6DefaultGateway o + String ipV6GatewayDevice o +end object HostMountInfo String path o @@ -331,11 +388,131 @@ object HostNasVolume extends HostFileSystemVolume end +object HostNicTeamingPolicy + String policy o + Boolean reversePolicy o + Boolean notifySwitches o + Boolean rollingOrder o + HostNicFailureCriteria failureCriteria o + HostNicOrderPolicy nicOrder o +end + +object HostNetOffloadCapabilities + Boolean csumOffload o + Boolean tcpSegmentation o + Boolean zeroCopyXmit o +end + +object HostNetworkSecurityPolicy + Boolean allowPromiscuous o + Boolean macChanges o + Boolean forgedTransmits o +end + +object HostNetworkPolicy + HostNetworkSecurityPolicy security o + HostNicTeamingPolicy nicTeaming o + HostNetOffloadCapabilities offloadPolicy o + HostNetworkTrafficShapingPolicy shapingPolicy o +end + +object HostNetworkTrafficShapingPolicy + Boolean enabled o +end + +object HostNicFailureCriteria + String checkSpeed o + Int speed o + Boolean checkDuplex o + Boolean fullDuplex o + Boolean checkErrorPercent o + Int percentage o + Boolean checkBeacon o +end + +object HostNicOrderPolicy + String activeNic ol + String standbyNic ol +end + +object HostPortGroup + String key r + HostPortGroupPort port ol + String vswitch r + HostNetworkPolicy computedPolicy r + HostPortGroupSpec spec r +end + +object HostPortGroupPort + String key o + String mac ol + String type r +end + +object HostPortGroupSpec + String name r + Int vlanId r + String vswitchName r + HostNetworkPolicy policy r +end + object HostScsiDiskPartition String diskName r Int partition r end +object HostVirtualNic + String device r + String key r + String port o + String portgroup r + HostVirtualNicSpec spec r +end + +object HostVirtualNicSpec + DistributedVirtualSwitchPortConnection distributedVirtualPort o + HostIpConfig ip o + String mac o + Int mtu o + String portgroup o + Boolean tsoEnabled o +end + + +object HostVirtualSwitch + String key r + Int mtu o + String name r + Int numPorts r + Int numPortsAvailable r + String pnic ol + String portgroup ol + HostVirtualSwitchSpec spec r +end + +object HostVirtualSwitchBridge +end + +object HostVirtualSwitchAutoBridge extends HostVirtualSwitchBridge + String excludedNicDevice ol +end + +object HostVirtualSwitchBeaconBridge extends HostVirtualSwitchBridge + Int interval r +end + +object HostVirtualSwitchBondBridge extends HostVirtualSwitchBridge + HostVirtualSwitchBeaconBridge beacon o + LinkDiscoveryProtocolConfig linkDiscoveryProtocolConfig o + String nicDevice rl +end + +object HostVirtualSwitchSpec + HostVirtualSwitchBridge bridge o + Int mtu o + Int numPorts r + HostNetworkPolicy policy o +end object HostVmfsVolume extends HostFileSystemVolume Int blockSizeMb r @@ -355,6 +532,10 @@ end object IsoImageFileQuery extends FileQuery end +object LinkDiscoveryProtocolConfig + String operation r + String protocol r +end object LocalDatastoreInfo extends DatastoreInfo String path o @@ -398,6 +579,10 @@ object OptionType Boolean valueIsReadonly o end +object OptionValue + String key r + AnyType value r +end object PerfCounterInfo Int key r @@ -454,6 +639,27 @@ object PerfSampleInfo Int interval r end +object PhysicalNic + String device r + String driver o + String key o + PhysicalNicInfo linkSpeed o + String mac r + String pci r + PhysicalNicSpec spec r + PhysicalNicInfo validLinkSpecification ol + Boolean wakeOnLanSupported r +end + +object PhysicalNicInfo + Boolean duplex r + Int speedMb r +end + +object PhysicalNicSpec + HostIpConfig ip o + PhysicalNicInfo linkSpeed o +end object PropertyChange String name r @@ -773,6 +979,13 @@ end # Methods # +method AddVirtualNic returns String r + ManagedObjectReference _this r + String portgroup r + HostVirtualNicSpec nic r +end + + method AnswerVM ManagedObjectReference _this r String questionId r @@ -954,6 +1167,10 @@ method RemoveSnapshot_Task returns ManagedObjectReference r Boolean removeChildren r end +method RemoveVirtualNic + ManagedObjectReference _this r + String device r +end method RetrieveProperties returns ObjectContent ol ManagedObjectReference _this:propertyCollector r @@ -1002,6 +1219,16 @@ method UnregisterVM ManagedObjectReference _this r end +method UpdateIpRouteConfig + ManagedObjectReference _this r + HostIpRouteConfig config r +end + +method UpdateVirtualNic + ManagedObjectReference _this r + String device r + HostVirtualNicSpec nic r +end method WaitForUpdates returns UpdateSet r ManagedObjectReference _this:propertyCollector r diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py index 8a128df..f4e4a11 100755 --- a/src/esx/esx_vi_generator.py +++ b/src/esx/esx_vi_generator.py @@ -371,8 +371,12 @@ class Property(Member): % self.name elif self.occurrence in [OCCURRENCE__REQUIRED_LIST, OCCURRENCE__OPTIONAL_LIST]: - return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(%s, %s)\n" \ - % (self.type, self.name) + if self.type == "String": + return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_STRING_LIST(%s, %s)\n" \ + % (self.type, self.name) + else: + return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(%s, %s)\n" \ + % (self.type, self.name) elif self.type == "String": return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, %s)\n" \ % self.name @@ -1519,8 +1523,31 @@ additional_object_features = { "AutoStartDefaults" : Object.FEATURE__AN Object.FEATURE__ANY_TYPE, "HostDatastoreBrowserSearchResults" : Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE, + "HostIpConfig" : Object.FEATURE__DEEP_COPY, + "HostIpRouteConfig" : Object.FEATURE__ANY_TYPE, + "HostIpConfigIpV6Address" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE | + Object.FEATURE__DEEP_COPY, + "HostIpConfigIpV6AddressConfiguration" : Object.FEATURE__DEEP_COPY, + "HostPortGroup" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE, + "HostVirtualNic" : Object.FEATURE__ANY_TYPE | + Object.FEATURE__LIST, + "HostVirtualSwitch" : Object.FEATURE__ANY_TYPE | + Object.FEATURE__LIST, + "KeyValue" : Object.FEATURE__ANY_TYPE, "ManagedObjectReference" : Object.FEATURE__ANY_TYPE, + "PhysicalNic" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE | + Object.FEATURE__DEEP_COPY, "ObjectContent" : Object.FEATURE__DEEP_COPY, + "OptionValue" : Object.FEATURE__ANY_TYPE | + Object.FEATURE__LIST, + "PhysicalNic" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE | + Object.FEATURE__DEEP_COPY, + "PhysicalNicSpec" : Object.FEATURE__DEEP_COPY, + "PhysicalNicLinkInfo" : Object.FEATURE__LIST, "ResourcePoolResourceUsage" : Object.FEATURE__ANY_TYPE, "ServiceContent" : Object.FEATURE__DESERIALIZE, "SharesInfo" : Object.FEATURE__ANY_TYPE, diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c index bcc310f..f23af8d 100644 --- a/src/esx/esx_vi_types.c +++ b/src/esx/esx_vi_types.c @@ -475,7 +475,23 @@ continue; \ } - +#define ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_STRING_LIST(_type, _name) \ + if (xmlStrEqual(childNode->name, BAD_CAST #_name)) { \ + char *value = NULL; \ + \ + if (esxVI_String_DeserializeValue(childNode, &value) < 0 || \ + value == NULL) { \ + goto failure; \ + } \ + \ + if (esxVI_##_type##_AppendValueToList(&(*ptrptr)->_name, \ + value) < 0) { \ + VIR_FREE(value); \ + goto failure; \ + } \ + \ + continue; \ + } /* * A required property must be != 0 (NULL for pointers, "undefined" == 0 for -- 1.7.9.5

On 07/20/2012 05:20 PM, Ata E Husain Bohra wrote:
Add following routines to esx_interface_driver: esxNumOfInterfaces, esxNumOfDefinedInterfaces, esxListInterfaces, esxListDefinedInterfaces, esxInterfaceLookupByMACString, esxInterfaceGetXMLDesc, esxInterfaceUndefine, esxInterfaceCreate, esxInterfaceDestroy
Signed-off-by: Ata E Husain Bohra <ata.husain@hotmail.com> --- src/esx/esx_interface_driver.c | 506 +++++++++++++++++++++++++++++++++++++++- src/esx/esx_vi.c | 126 ++++++++++ src/esx/esx_vi.h | 10 + src/esx/esx_vi_generator.input | 227 ++++++++++++++++++ src/esx/esx_vi_generator.py | 31 ++- src/esx/esx_vi_types.c | 18 +- 6 files changed, 913 insertions(+), 5 deletions(-)
diff --git a/src/esx/esx_interface_driver.c b/src/esx/esx_interface_driver.c index 5713137..b1ba5e2 100644 --- a/src/esx/esx_interface_driver.c +++ b/src/esx/esx_interface_driver.c @@ -23,6 +23,9 @@ */
#include <config.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h>
#include "internal.h" #include "util.h" @@ -34,6 +37,7 @@ #include "esx_vi.h" #include "esx_vi_methods.h" #include "esx_util.h" +#include "interface_conf.h"
#define VIR_FROM_THIS VIR_FROM_ESX
@@ -67,10 +71,508 @@ esxInterfaceClose(virConnectPtr conn)
+static int +esxNumOfInterfaces(virConnectPtr conn) +{ + esxPrivate *priv = conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL;
It's a bit disconcerting to see these called "virtual" NICs, when virInterface is all about configuring interfaces on the *physical* host. Being unfamiliar with the vmware API, I'm not sure which of these functions are things you've added to libvirt and which are part of vmware, but please rename any that are defined in libvirt to use "physical" or "host" or "p/h" as appropriate, rather than "virtual" and/or "v". We want to make sure nobody gets the wrong idea about these functions.
+ int count = 0; + + if (esxVI_EnsureSession(priv->primary) < 0 || + esxVI_LookupVirtualNicList(priv->primary, &virtualNicList) < 0) { + goto cleanup; + } + + if (virtualNicList == NULL) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not retrieve vNic List")); + + goto cleanup; + } + + for (virtualNic = virtualNicList; + virtualNic != NULL; + virtualNic = virtualNic->_next) { + count++; + } + +cleanup: + + esxVI_HostVirtualNic_Free(&virtualNicList); + + return count; +} + + + +static int +esxNumOfDefinedInterfaces(virConnectPtr conn) +{ + conn->interfacePrivateData = NULL;
Setting interfacePrivateData to NULL is equivalent to closing the driver. I don't think you really want to do this. Possibly it was an error in cut/paste from somewhere else (esxInterfaceClose()?).
+ + // ESX interfaces are always active + return 0; +} + + + +static int +esxListInterfaces(virConnectPtr conn, char **names, int maxnames) +{ + esxPrivate *priv = conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL; + int result = -1; + int i = 0; + + if (esxVI_EnsureSession(priv->primary) < 0 || + esxVI_LookupVirtualNicList(priv->primary, + &virtualNicList) < 0) { + goto cleanup; + } + + if (virtualNicList == NULL) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not retrieve vNIC List")); + goto cleanup; + } + + for (i= 0, virtualNic = virtualNicList; + virtualNic != NULL && i < maxnames; + ++i, virtualNic = virtualNic->_next) { + names[i] = strdup(virtualNic->device); + + if (names[i] == NULL) { + for(;i >=0;--i) { + VIR_FREE(names[i]); + } + virReportOOMError(); + goto cleanup; + } + } + + result = i; + cleanup: + esxVI_HostVirtualNic_Free(&virtualNicList); + + return result; +} + + + +static int +esxListDefinedInterfaces(virConnectPtr conn, char **names, int maxnames) +{ + conn->interfacePrivateData = conn->privateData; + *names = NULL; + + /* keeps compiler happy */ + VIR_DEBUG("max interfaces: %d", maxnames); + + // ESX interfaces are always active + return 0; +}
As I'll be mentioning in PATCH 2/2, just do this right the first time, rather than having a followup patch to fix code you've just added.
+ + + +static virInterfacePtr +esxInterfaceLookupByName(virConnectPtr conn, const char *name) +{ + esxPrivate *priv = conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL; + virInterfacePtr ret = NULL; + + if (esxVI_EnsureSession(priv->primary) < 0 || + esxVI_LookupVirtualNicList(priv->primary, + &virtualNicList) < 0) { + goto cleanup; + } + + if (virtualNicList == 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not retrieve vNIC List")); + goto cleanup; + } + + + for(virtualNic = virtualNicList; + virtualNic != NULL; + virtualNic = virtualNic->_next) { + if (STREQ(virtualNic->device, name)) { + if (virtualNic->spec == NULL || + virtualNic->spec->mac == NULL) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed HostVirtualNicSpec")); + goto cleanup; + } + + ret = virGetInterface(conn, virtualNic->device, virtualNic->spec->mac); + break; + } + } + + cleanup: + esxVI_HostVirtualNic_Free(&virtualNicList); + + return ret; +} + + + +static virInterfacePtr +esxInterfaceLookupByMACString(virConnectPtr conn, const char *mac) +{ + esxPrivate *priv = conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL; + virInterfacePtr ret = NULL; + + if (esxVI_EnsureSession(priv->primary) < 0 || + esxVI_LookupVirtualNicList(priv->primary, + &virtualNicList) < 0) { + goto cleanup; + } + + if (virtualNicList == 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not retrieve vNIC List")); + goto cleanup; + } + + + for(virtualNic = virtualNicList; + virtualNic != NULL; + virtualNic = virtualNic->_next) { + if (virtualNic->spec == NULL || + virtualNic->spec->mac == NULL) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed HostVirtualNicSpec")); + goto cleanup; + } + + if (STREQ(virtualNic->spec->mac, mac)) { + ret = virGetInterface(conn, virtualNic->device, virtualNic->spec->mac); + break; + } + } + + cleanup: + esxVI_HostVirtualNic_Free(&virtualNicList); + + return ret; +} + + + +static char* +esxInterfaceGetXMLDesc(virInterfacePtr iface, unsigned int flags) +{ + esxPrivate *priv = iface->conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL; + esxVI_PhysicalNic *physicalNicList = NULL; + const esxVI_PhysicalNic *physicalNic = NULL; + esxVI_PhysicalNic *matchingPhysicalNicList = NULL; + esxVI_HostIpRouteConfig *ipRouteConfig = NULL; + esxVI_HostPortGroup *portGroupList = NULL; + esxVI_HostVirtualSwitch *virtualSwitchList = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + virInterfaceDefPtr def = NULL; + int use_static = 0; + struct in_addr addr; + uint32_t host_addr = 0; + int zero_count = 0; + int masklen = 0; + int i = 0; + char *ret = NULL; + + if (VIR_INTERFACE_XML_INACTIVE & flags) { + use_static = 1; + } + + if (esxVI_EnsureSession(priv->primary) < 0 || + esxVI_String_AppendValueListToList(&propertyNameList, + "config.network.vnic\0" + "config.network.ipRouteConfig\0" + "config.network.vswitch\0" + "config.network.pnic\0" + "config.network.portgroup\0") < 0 || + esxVI_LookupHostSystemProperties(priv->primary, propertyNameList, + &hostSystem) < 0) { + goto cleanup; + } + + for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "config.network.vnic")) { + if (esxVI_HostVirtualNic_CastListFromAnyType( + dynamicProperty->val, &virtualNicList) < 0) { + goto cleanup; + } + } else if (STREQ(dynamicProperty->name, + "config.network.ipRouteConfig")) { + if (esxVI_HostIpRouteConfig_CastFromAnyType( + dynamicProperty->val, &ipRouteConfig)) { + goto cleanup; + } + } else if (STREQ(dynamicProperty->name, "config.network.vswitch")) { + if (esxVI_HostVirtualSwitch_CastListFromAnyType + (dynamicProperty->val, &virtualSwitchList) < 0) { + goto cleanup; + } + } else if (STREQ(dynamicProperty->name, "config.network.pnic")) { + if (esxVI_PhysicalNic_CastListFromAnyType( + dynamicProperty->val, &physicalNicList) < 0) { + goto cleanup; + } + } else if (STREQ(dynamicProperty->name, "config.network.portgroup")) { + if (esxVI_HostPortGroup_CastListFromAnyType( + dynamicProperty->val, &portGroupList) < 0) { + goto cleanup; + } + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + if (!virtualNicList || + !ipRouteConfig || + !virtualSwitchList || + !portGroupList) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to retrieve network parameters")); + + goto cleanup; + } + + for (virtualNic = virtualNicList; + virtualNic != NULL; + virtualNic = virtualNic->_next) { + if (STREQ(virtualNic->device, iface->name)) { + break; + } + } + + if (virtualNic == NULL) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not find Interface")); + goto cleanup; + } + + if (esxVI_LookupPhysicalNicFromPortGroup(virtualNic->portgroup, + portGroupList, + virtualSwitchList, + physicalNicList, + &matchingPhysicalNicList) < 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("No Physical NIC found matching Virtual NIC's portgroup")); + goto cleanup; + } + + /* + * populate virInterfaceDef object to obtain + * libvirt interface domain xml. + */ + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + goto cleanup; + } + + def->type = VIR_INTERFACE_TYPE_BRIDGE; + def->name = strdup(virtualNic->device); + if (virtualNic->spec->mtu && virtualNic->spec->mtu->value) { + def->mtu = virtualNic->spec->mtu->value; + } else { + def->mtu = 1500; + } + + def->startmode = VIR_INTERFACE_START_ONBOOT; + + if (!use_static && virtualNic->spec->mac) { + def->mac = strdup(virtualNic->spec->mac); + } + + /* TODO - Handle VLAN (via portgroup?) */ + if (virtualNic->spec->ip->subnetMask && + *virtualNic->spec->ip->subnetMask && + inet_aton(virtualNic->spec->ip->subnetMask, &addr) == 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Error parsing netmask")); + goto cleanup; + } + + host_addr = ntohl(addr.s_addr); + /* Calculate masklen */ + for (i = 0; i < 32; ++i) { + if (host_addr & 0x01) { + break; + } + zero_count++; + host_addr >>= 1; + } + masklen = 32 - zero_count; + + /* append protocol field */ + def->nprotos = 1; + if (VIR_ALLOC_N(def->protos, def->nprotos) < 0) { + virReportOOMError(); + goto cleanup; + } + + /* TODO - Add IPv6 Support */ + for (i = 0; i < def->nprotos; ++i) { + if (VIR_ALLOC(def->protos[i]) < 0) { + goto cleanup; + } + + def->protos[i]->family = strdup("ipv4"); + if (virtualNic->spec->ip->dhcp == 1) { + def->protos[i]->dhcp = 1; + } + def->protos[i]->nips = 1; + if (virtualNic->spec->ip->dhcp != 1 || !use_static) { + if (virtualNic->spec->ip->ipAddress && + *virtualNic->spec->ip->ipAddress) { + int j =0; + if (VIR_ALLOC_N(def->protos[i]->ips, def->protos[i]->nips) + < 0) { + virReportOOMError(); + goto cleanup; + } + + for (j=0; j < def->protos[i]->nips; ++j) { + if (VIR_ALLOC(def->protos[i]->ips[j]) < 0) { + virReportOOMError(); + goto cleanup; + } + def->protos[i]->ips[0]->address = + strdup(virtualNic->spec->ip->ipAddress); + def->protos[i]->ips[0]->prefix = masklen; + def->protos[i]->gateway = + strdup(ipRouteConfig->defaultGateway); + } + } + } + } + + /* Add bridge information */ + def->data.bridge.stp = 0; /* off */ + + /** + * traversing physical nic list twice, first to get total + * interfaces and second to populate interface items. + * Total Complexity ~= O(N); also total physical nics + * cannot be that large number + */ + for (physicalNic = matchingPhysicalNicList, i = 0; physicalNic != NULL; + physicalNic = physicalNic->_next, ++i) { + } + + if ( i > 0) { + if (VIR_ALLOC_N(def->data.bridge.itf, i) < 0) { + virReportOOMError(); + goto cleanup; + } + def->data.bridge.nbItf = i; + for (physicalNic = matchingPhysicalNicList, i = 0; physicalNic != NULL; + physicalNic = physicalNic->_next, ++i) { + virInterfaceDefPtr itf = NULL; + if (VIR_ALLOC(itf) < 0) { + virReportOOMError(); + goto cleanup; + } + itf->type = VIR_INTERFACE_TYPE_ETHERNET; + itf->name = strdup(physicalNic->device); + itf->mac = strdup(physicalNic->mac); + + def->data.bridge.itf[i] = itf; + } + } + + ret = virInterfaceDefFormat(def); + if (!ret) { + goto cleanup; + } + + cleanup: + esxVI_HostVirtualNic_Free(&virtualNicList); + esxVI_PhysicalNic_Free(&physicalNicList); + esxVI_PhysicalNic_Free(&matchingPhysicalNicList); + esxVI_HostPortGroup_Free(&portGroupList); + esxVI_HostVirtualSwitch_Free(&virtualSwitchList); + esxVI_HostIpRouteConfig_Free(&ipRouteConfig); + esxVI_ObjectContent_Free(&hostSystem); + esxVI_String_Free(&propertyNameList); + virInterfaceDefFree(def); + + return ret; +} + + + +static int +esxInterfaceUndefine(virInterfacePtr iface) +{ + esxPrivate *priv = iface->conn->interfacePrivateData; + + if (esxVI_RemoveVirtualNic( + priv->primary, + priv->primary->hostSystem->configManager->networkSystem, + iface->name) < 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Error deleting interface")); + return -1; + } + + return 0; +} + + + +static int +esxInterfaceCreate(virInterfacePtr iface, unsigned int flags) +{ + iface->conn->interfacePrivateData = NULL;
Again - you don't want to NULL this out - it's the same as closing the driver.
+ + virCheckFlags(0, -1); + + /* ESX interfaces are always active */ + return 0; +} + + + +static int +esxInterfaceDestroy(virInterfacePtr iface, unsigned int flags) +{ + iface->conn->interfacePrivateData = NULL;
And again - don't NULL this.
+ + virCheckFlags(0, -1); + + /* ESX interfaces can not be deactivated */ + return 1; +} + + + static virInterfaceDriver esxInterfaceDriver = { .name = "ESX", - .open = esxInterfaceOpen, /* 0.7.6 */ - .close = esxInterfaceClose, /* 0.7.6 */ + .open = esxInterfaceOpen, /* 0.7.6 */ + .close = esxInterfaceClose, /* 0.7.6 */ + .numOfInterfaces = esxNumOfInterfaces, /* 0.9.x */ + .numOfDefinedInterfaces = esxNumOfDefinedInterfaces, /* 0.9.x */ + .listInterfaces = esxListInterfaces, /* 0.9.x */ + .listDefinedInterfaces = esxListDefinedInterfaces, /* 0.9.x */ + .interfaceLookupByName = esxInterfaceLookupByName, /* 0.9.x */ + .interfaceLookupByMACString = esxInterfaceLookupByMACString, /* 0.9.x */ + .interfaceGetXMLDesc = esxInterfaceGetXMLDesc, /* 0.9.x */ + .interfaceUndefine = esxInterfaceUndefine, /* 0.9.x */ + .interfaceCreate = esxInterfaceCreate, /* 0.9.x */ + .interfaceDestroy = esxInterfaceDestroy, /* 0.9.x */ };
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 48718b6..80ddb76 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -4523,6 +4523,132 @@ esxVI_LookupManagedObjectHelper(esxVI_Context *ctx, return result; }
+int +esxVI_LookupVirtualNicList(esxVI_Context* ctx, + esxVI_HostVirtualNic** virtualNicList) +{ + int result = -1; + esxVI_String *propertyNameList = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_ObjectContent* hostSystem = NULL; + + if (esxVI_String_AppendValueListToList( + &propertyNameList, "config.network.vnic\0") < 0 || + esxVI_LookupHostSystemProperties(ctx, propertyNameList, &hostSystem) < 0) { + goto cleanup; + }
+ if (hostSystem == NULL) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not retrieve the HostSystem object")); + + goto cleanup; + } + + for (dynamicProperty = hostSystem->propSet; + dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "config.network.vnic")) { + if (esxVI_HostVirtualNic_CastListFromAnyType(dynamicProperty->val, + virtualNicList) < 0) { + goto cleanup; + } + break; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + result = 0; + +cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&hostSystem); + + return result; +} + +int +esxVI_LookupPhysicalNicFromPortGroup( + const char *portgroup, + const esxVI_HostPortGroup *portGroupList, + const esxVI_HostVirtualSwitch *virtualSwitchList, + const esxVI_PhysicalNic *physicalNicList, + esxVI_PhysicalNic **ret_physicalNicList) +{ + int result = -1; + const esxVI_HostPortGroup *portGroup = NULL; + const esxVI_HostVirtualSwitch *virtualSwitch = NULL; + esxVI_PhysicalNic *matchingPhysicalNicList = NULL; + const esxVI_PhysicalNic *physicalNic = NULL; + esxVI_PhysicalNic *tempPhysicalNic = NULL; + const esxVI_String *pnicKey = NULL; + + if (portgroup == NULL) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("No Portgroup found!")); + goto cleanup; + } + + /* Go through all the port groups to find the one that matches. */ + for (portGroup = portGroupList; + portGroup != NULL; + portGroup = portGroup->_next) { + if (STREQ(portGroup->spec->name, portgroup)) { + break; + } + } + + if (portGroup == NULL) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not find Host port group")); + goto cleanup; + } + + /* Go through all the virtual switches to find the one that matches */ + for (virtualSwitch = virtualSwitchList; + virtualSwitch != NULL; + virtualSwitch = virtualSwitch->_next) { + if (STREQ(portGroup->spec->vswitchName, virtualSwitch->name)) { + break; + } + } + + if (virtualSwitch == NULL) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not find Virtual Switch")); + goto cleanup; + } + + /* Go through all physical nics */ + for (pnicKey = virtualSwitch->pnic; + pnicKey != NULL; + pnicKey = pnicKey->_next) { + /* O(n^2), but probably faster than a hash due to small N */ + for (physicalNic = physicalNicList; + physicalNic != NULL; + physicalNic = physicalNic->_next) { + + if (STREQ(pnicKey->value, physicalNic->key)) { + if (esxVI_PhysicalNic_DeepCopy(&tempPhysicalNic, + (esxVI_PhysicalNic *)physicalNic) < 0 || + esxVI_PhysicalNic_AppendToList(&matchingPhysicalNicList, + tempPhysicalNic) < 0) { + goto cleanup; + } + tempPhysicalNic = NULL; + } + } + } + + *ret_physicalNicList = matchingPhysicalNicList; + matchingPhysicalNicList = NULL; /* no cleanup needed */ + tempPhysicalNic = NULL; /* no cleanup needed */ + result = 0; + cleanup: + esxVI_PhysicalNic_Free(&matchingPhysicalNicList); + esxVI_PhysicalNic_Free(&tempPhysicalNic); + return result; +}
#include "esx_vi.generated.c" diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h index 9560bd2..9b694b5 100644 --- a/src/esx/esx_vi.h +++ b/src/esx/esx_vi.h @@ -505,6 +505,16 @@ int esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedHostCpuIdInfo,
int esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductVersion productVersion);
+int esxVI_LookupVirtualNicList(esxVI_Context* ctx, + esxVI_HostVirtualNic** virtualNicList); + +int esxVI_LookupPhysicalNicFromPortGroup( + const char *portgroup, + const esxVI_HostPortGroup *portGroupList, + const esxVI_HostVirtualSwitch *virtualSwitchList, + const esxVI_PhysicalNic *physicalNicList, + esxVI_PhysicalNic **ret_physicalNicList); + # include "esx_vi.generated.h"
#endif /* __ESX_VI_H__ */ diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input index 1a67a8c..64f8389 100644 --- a/src/esx/esx_vi_generator.input +++ b/src/esx/esx_vi_generator.input @@ -57,6 +57,29 @@ enum AutoStartWaitHeartbeatSetting systemDefault end
+enum HostConfigChangeOperation + add + edit + remove +end + +enum HostIpConfigIpV6AdressStatus + deprecated + duplicate + inaccessible + invalid + preferred + tentative + unknown +end + +enum HostIpConfigV6AdressConfigType + dhcp + linklayer + manual + other + random +end
enum ManagedEntityStatus gray @@ -197,6 +220,12 @@ object DeviceBackedVirtualDiskSpec extends VirtualDiskSpec String device r end
+object DistributedVirtualSwitchPortConnection + Int connectionCookie o + String portgroupKey o + String portKey o + String switchUuid r +end
object DynamicProperty String name r @@ -316,6 +345,34 @@ object HostFileSystemVolume Long capacity r end
+object HostIpConfig + Boolean dhcp r + String ipAddress o + HostIpConfigIpV6AddressConfiguration ipV6Config o + String subnetMask o +end + +object HostIpConfigIpV6Address + String dadState o + String ipAddress r + DateTime lifetime o + String operation o + String origin o + Int prefixLength r +end + +object HostIpConfigIpV6AddressConfiguration + Boolean autoConfigurationEnabled o + Boolean dhcpV6Enabled o + HostIpConfigIpV6Address ipV6Address ol +end + +object HostIpRouteConfig + String defaultGateway o + String gatewayDevice o + String ipV6DefaultGateway o + String ipV6GatewayDevice o +end
object HostMountInfo String path o @@ -331,11 +388,131 @@ object HostNasVolume extends HostFileSystemVolume end
+object HostNicTeamingPolicy + String policy o + Boolean reversePolicy o + Boolean notifySwitches o + Boolean rollingOrder o + HostNicFailureCriteria failureCriteria o + HostNicOrderPolicy nicOrder o +end + +object HostNetOffloadCapabilities + Boolean csumOffload o + Boolean tcpSegmentation o + Boolean zeroCopyXmit o +end + +object HostNetworkSecurityPolicy + Boolean allowPromiscuous o + Boolean macChanges o + Boolean forgedTransmits o +end + +object HostNetworkPolicy + HostNetworkSecurityPolicy security o + HostNicTeamingPolicy nicTeaming o + HostNetOffloadCapabilities offloadPolicy o + HostNetworkTrafficShapingPolicy shapingPolicy o +end + +object HostNetworkTrafficShapingPolicy + Boolean enabled o +end + +object HostNicFailureCriteria + String checkSpeed o + Int speed o + Boolean checkDuplex o + Boolean fullDuplex o + Boolean checkErrorPercent o + Int percentage o + Boolean checkBeacon o +end + +object HostNicOrderPolicy + String activeNic ol + String standbyNic ol +end + +object HostPortGroup + String key r + HostPortGroupPort port ol + String vswitch r + HostNetworkPolicy computedPolicy r + HostPortGroupSpec spec r +end + +object HostPortGroupPort + String key o + String mac ol + String type r +end + +object HostPortGroupSpec + String name r + Int vlanId r + String vswitchName r + HostNetworkPolicy policy r +end + object HostScsiDiskPartition String diskName r Int partition r end
+object HostVirtualNic + String device r + String key r + String port o + String portgroup r + HostVirtualNicSpec spec r +end + +object HostVirtualNicSpec + DistributedVirtualSwitchPortConnection distributedVirtualPort o + HostIpConfig ip o + String mac o + Int mtu o + String portgroup o + Boolean tsoEnabled o +end + + +object HostVirtualSwitch + String key r + Int mtu o + String name r + Int numPorts r + Int numPortsAvailable r + String pnic ol + String portgroup ol + HostVirtualSwitchSpec spec r +end + +object HostVirtualSwitchBridge +end + +object HostVirtualSwitchAutoBridge extends HostVirtualSwitchBridge + String excludedNicDevice ol +end + +object HostVirtualSwitchBeaconBridge extends HostVirtualSwitchBridge + Int interval r +end + +object HostVirtualSwitchBondBridge extends HostVirtualSwitchBridge + HostVirtualSwitchBeaconBridge beacon o + LinkDiscoveryProtocolConfig linkDiscoveryProtocolConfig o + String nicDevice rl +end + +object HostVirtualSwitchSpec + HostVirtualSwitchBridge bridge o + Int mtu o + Int numPorts r + HostNetworkPolicy policy o +end
object HostVmfsVolume extends HostFileSystemVolume Int blockSizeMb r @@ -355,6 +532,10 @@ end object IsoImageFileQuery extends FileQuery end
+object LinkDiscoveryProtocolConfig + String operation r + String protocol r +end
object LocalDatastoreInfo extends DatastoreInfo String path o @@ -398,6 +579,10 @@ object OptionType Boolean valueIsReadonly o end
+object OptionValue + String key r + AnyType value r +end
object PerfCounterInfo Int key r @@ -454,6 +639,27 @@ object PerfSampleInfo Int interval r end
+object PhysicalNic + String device r + String driver o + String key o + PhysicalNicInfo linkSpeed o + String mac r + String pci r + PhysicalNicSpec spec r + PhysicalNicInfo validLinkSpecification ol + Boolean wakeOnLanSupported r +end + +object PhysicalNicInfo + Boolean duplex r + Int speedMb r +end + +object PhysicalNicSpec + HostIpConfig ip o + PhysicalNicInfo linkSpeed o +end
object PropertyChange String name r @@ -773,6 +979,13 @@ end # Methods #
+method AddVirtualNic returns String r + ManagedObjectReference _this r + String portgroup r + HostVirtualNicSpec nic r +end + + method AnswerVM ManagedObjectReference _this r String questionId r @@ -954,6 +1167,10 @@ method RemoveSnapshot_Task returns ManagedObjectReference r Boolean removeChildren r end
+method RemoveVirtualNic + ManagedObjectReference _this r + String device r +end
method RetrieveProperties returns ObjectContent ol ManagedObjectReference _this:propertyCollector r @@ -1002,6 +1219,16 @@ method UnregisterVM ManagedObjectReference _this r end
+method UpdateIpRouteConfig + ManagedObjectReference _this r + HostIpRouteConfig config r +end + +method UpdateVirtualNic + ManagedObjectReference _this r + String device r + HostVirtualNicSpec nic r +end
method WaitForUpdates returns UpdateSet r ManagedObjectReference _this:propertyCollector r diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py index 8a128df..f4e4a11 100755 --- a/src/esx/esx_vi_generator.py +++ b/src/esx/esx_vi_generator.py @@ -371,8 +371,12 @@ class Property(Member): % self.name elif self.occurrence in [OCCURRENCE__REQUIRED_LIST, OCCURRENCE__OPTIONAL_LIST]: - return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(%s, %s)\n" \ - % (self.type, self.name) + if self.type == "String": + return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_STRING_LIST(%s, %s)\n" \ + % (self.type, self.name) + else: + return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(%s, %s)\n" \ + % (self.type, self.name) elif self.type == "String": return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, %s)\n" \ % self.name @@ -1519,8 +1523,31 @@ additional_object_features = { "AutoStartDefaults" : Object.FEATURE__AN Object.FEATURE__ANY_TYPE, "HostDatastoreBrowserSearchResults" : Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE, + "HostIpConfig" : Object.FEATURE__DEEP_COPY, + "HostIpRouteConfig" : Object.FEATURE__ANY_TYPE, + "HostIpConfigIpV6Address" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE | + Object.FEATURE__DEEP_COPY, + "HostIpConfigIpV6AddressConfiguration" : Object.FEATURE__DEEP_COPY, + "HostPortGroup" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE, + "HostVirtualNic" : Object.FEATURE__ANY_TYPE | + Object.FEATURE__LIST, + "HostVirtualSwitch" : Object.FEATURE__ANY_TYPE | + Object.FEATURE__LIST, + "KeyValue" : Object.FEATURE__ANY_TYPE, "ManagedObjectReference" : Object.FEATURE__ANY_TYPE, + "PhysicalNic" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE | + Object.FEATURE__DEEP_COPY, "ObjectContent" : Object.FEATURE__DEEP_COPY, + "OptionValue" : Object.FEATURE__ANY_TYPE | + Object.FEATURE__LIST, + "PhysicalNic" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE | + Object.FEATURE__DEEP_COPY, + "PhysicalNicSpec" : Object.FEATURE__DEEP_COPY, + "PhysicalNicLinkInfo" : Object.FEATURE__LIST, "ResourcePoolResourceUsage" : Object.FEATURE__ANY_TYPE, "ServiceContent" : Object.FEATURE__DESERIALIZE, "SharesInfo" : Object.FEATURE__ANY_TYPE, diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c index bcc310f..f23af8d 100644 --- a/src/esx/esx_vi_types.c +++ b/src/esx/esx_vi_types.c @@ -475,7 +475,23 @@ continue; \ }
- +#define ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_STRING_LIST(_type, _name) \ + if (xmlStrEqual(childNode->name, BAD_CAST #_name)) { \ + char *value = NULL; \ + \ + if (esxVI_String_DeserializeValue(childNode, &value) < 0 || \ + value == NULL) { \ + goto failure; \ + } \ + \ + if (esxVI_##_type##_AppendValueToList(&(*ptrptr)->_name, \ + value) < 0) { \ + VIR_FREE(value); \ + goto failure; \ + } \ + \ + continue; \ + }
/* * A required property must be != 0 (NULL for pointers, "undefined" == 0 for
A general comment - I didn't see any kind of mutexes in here. Is this code really threadsafe? (it looks like the toplevel functions just call into your utility functions to get a snapshot of the current state of interfaces in vmware, then work with that snapshot during the rest of the call; I didn't look into the utility functions in detail, because the chance of me understanding them is fairly low anyway :-)

2012/7/23 Laine Stump <laine@laine.org>:
On 07/20/2012 05:20 PM, Ata E Husain Bohra wrote:
Add following routines to esx_interface_driver: esxNumOfInterfaces, esxNumOfDefinedInterfaces, esxListInterfaces, esxListDefinedInterfaces, esxInterfaceLookupByMACString, esxInterfaceGetXMLDesc, esxInterfaceUndefine, esxInterfaceCreate, esxInterfaceDestroy
Signed-off-by: Ata E Husain Bohra <ata.husain@hotmail.com> --- src/esx/esx_interface_driver.c | 506 +++++++++++++++++++++++++++++++++++++++- src/esx/esx_vi.c | 126 ++++++++++ src/esx/esx_vi.h | 10 + src/esx/esx_vi_generator.input | 227 ++++++++++++++++++ src/esx/esx_vi_generator.py | 31 ++- src/esx/esx_vi_types.c | 18 +- 6 files changed, 913 insertions(+), 5 deletions(-)
diff --git a/src/esx/esx_interface_driver.c b/src/esx/esx_interface_driver.c index 5713137..b1ba5e2 100644 --- a/src/esx/esx_interface_driver.c +++ b/src/esx/esx_interface_driver.c @@ -23,6 +23,9 @@ */
#include <config.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h>
#include "internal.h" #include "util.h" @@ -34,6 +37,7 @@ #include "esx_vi.h" #include "esx_vi_methods.h" #include "esx_util.h" +#include "interface_conf.h"
#define VIR_FROM_THIS VIR_FROM_ESX
@@ -67,10 +71,508 @@ esxInterfaceClose(virConnectPtr conn)
+static int +esxNumOfInterfaces(virConnectPtr conn) +{ + esxPrivate *priv = conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL;
It's a bit disconcerting to see these called "virtual" NICs, when virInterface is all about configuring interfaces on the *physical* host.
This i my biggest concern here too, and also that's the reason why I didn't implement the network driver yet. Because I'm not sure what is the proper mapping between libvirt and vSphere API here. As far as I understand this, a HostVirtualNic seems to be the best match for a virInterface. A HostVirtualNic is connected to HostVirtualSwitch, that is connected to the physical network via a PhysicalNic. There is not much one can do about the PhysicalNic. It just sits there and is connected to the HostVirtualSwitch. The HostVirtualNic is also the one that has the external IP address of the ESX server assigned. Also a HostVirtualNic is not part of the virtual hardware of a VM. A VirtualEthernetCard is the type in the vSphere API representing the virtual network interface of a virtual machine
Being unfamiliar with the vmware API, I'm not sure which of these functions are things you've added to libvirt and which are part of vmware, but please rename any that are defined in libvirt to use "physical" or "host" or "p/h" as appropriate, rather than "virtual" and/or "v". We want to make sure nobody gets the wrong idea about these functions.
I don't think that this is a good idea, we should really stick exactly to the naming of things in the vSphere API otherwise there will be much more confusion. Therefore, esxVI_HostVirtualNic *virtualNicList = NULL; should be esxVI_HostVirtualNic *hostVirtualNicList = NULL; Apart from that I'll do a more detailed review soon. -- Matthias Bolte http://photron.blogspot.com

On 07/24/2012 03:26 PM, Matthias Bolte wrote:
On 07/20/2012 05:20 PM, Ata E Husain Bohra wrote:
Add following routines to esx_interface_driver: esxNumOfInterfaces, esxNumOfDefinedInterfaces, esxListInterfaces, esxListDefinedInterfaces, esxInterfaceLookupByMACString, esxInterfaceGetXMLDesc, esxInterfaceUndefine, esxInterfaceCreate, esxInterfaceDestroy
Signed-off-by: Ata E Husain Bohra <ata.husain@hotmail.com> --- src/esx/esx_interface_driver.c | 506 +++++++++++++++++++++++++++++++++++++++- src/esx/esx_vi.c | 126 ++++++++++ src/esx/esx_vi.h | 10 + src/esx/esx_vi_generator.input | 227 ++++++++++++++++++ src/esx/esx_vi_generator.py | 31 ++- src/esx/esx_vi_types.c | 18 +- 6 files changed, 913 insertions(+), 5 deletions(-)
diff --git a/src/esx/esx_interface_driver.c b/src/esx/esx_interface_driver.c index 5713137..b1ba5e2 100644 --- a/src/esx/esx_interface_driver.c +++ b/src/esx/esx_interface_driver.c @@ -23,6 +23,9 @@ */
#include <config.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h>
#include "internal.h" #include "util.h" @@ -34,6 +37,7 @@ #include "esx_vi.h" #include "esx_vi_methods.h" #include "esx_util.h" +#include "interface_conf.h"
#define VIR_FROM_THIS VIR_FROM_ESX
@@ -67,10 +71,508 @@ esxInterfaceClose(virConnectPtr conn)
+static int +esxNumOfInterfaces(virConnectPtr conn) +{ + esxPrivate *priv = conn->interfacePrivateData; + esxVI_HostVirtualNic *virtualNicList = NULL; + const esxVI_HostVirtualNic *virtualNic = NULL;
It's a bit disconcerting to see these called "virtual" NICs, when virInterface is all about configuring interfaces on the *physical* host. This i my biggest concern here too, and also that's the reason why I didn't implement the network driver yet. Because I'm not sure what is
2012/7/23 Laine Stump <laine@laine.org>: the proper mapping between libvirt and vSphere API here.
As far as I understand this, a HostVirtualNic seems to be the best match for a virInterface. A HostVirtualNic is connected to HostVirtualSwitch, that is connected to the physical network via a PhysicalNic. There is not much one can do about the PhysicalNic. It just sits there and is connected to the HostVirtualSwitch. The HostVirtualNic is also the one that has the external IP address of the ESX server assigned.
Ah, okay. So if I understand correctly, a PhysicalNic is just the bare hardware, and any configuration applied to that hardware is abstracted as a separate VirtualNic. Strange, but.. okay.
Also a HostVirtualNic is not part of the virtual hardware of a VM. A VirtualEthernetCard is the type in the vSphere API representing the virtual network interface of a virtual machine
Clear as mud! :-) Anyway, at least people using libvirt to manage their vSphere nodes won't have to deal with that confusion.
Being unfamiliar with the vmware API, I'm not sure which of these functions are things you've added to libvirt and which are part of vmware, but please rename any that are defined in libvirt to use "physical" or "host" or "p/h" as appropriate, rather than "virtual" and/or "v". We want to make sure nobody gets the wrong idea about these functions. I don't think that this is a good idea, we should really stick exactly to the naming of things in the vSphere API otherwise there will be much more confusion.
After reading your explanation, I agree.
Therefore,
esxVI_HostVirtualNic *virtualNicList = NULL;
should be
esxVI_HostVirtualNic *hostVirtualNicList = NULL;
Apart from that I'll do a more detailed review soon.

-----Original Message----- From: libvir-list-bounces@redhat.com [mailto:libvir-list-bounces@redhat.com] On Behalf Of Laine Stump Sent: Monday, July 23, 2012 12:43 PM To: libvir-list@redhat.com Subject: Re: [libvirt] [PATCH 1/2] ESX: Add routines to interface driver On 07/20/2012 05:20 PM, Ata E Husain Bohra wrote:
Add following routines to esx_interface_driver:
esxNumOfInterfaces,
esxNumOfDefinedInterfaces,
esxListInterfaces,
esxListDefinedInterfaces,
esxInterfaceLookupByMACString,
esxInterfaceGetXMLDesc,
esxInterfaceUndefine,
esxInterfaceCreate,
esxInterfaceDestroy
Signed-off-by: Ata E Husain Bohra <ata.husain@hotmail.com>
---
src/esx/esx_interface_driver.c | 506 +++++++++++++++++++++++++++++++++++++++-
src/esx/esx_vi.c | 126 ++++++++++
src/esx/esx_vi.h | 10 +
src/esx/esx_vi_generator.input | 227 ++++++++++++++++++
src/esx/esx_vi_generator.py | 31 ++-
src/esx/esx_vi_types.c | 18 +-
6 files changed, 913 insertions(+), 5 deletions(-)
diff --git a/src/esx/esx_interface_driver.c
b/src/esx/esx_interface_driver.c index 5713137..b1ba5e2 100644
--- a/src/esx/esx_interface_driver.c
+++ b/src/esx/esx_interface_driver.c
@@ -23,6 +23,9 @@
*/
+static int
+esxNumOfInterfaces(virConnectPtr conn) {
+ esxPrivate *priv = conn->interfacePrivateData;
+ esxVI_HostVirtualNic *virtualNicList = NULL;
+ const esxVI_HostVirtualNic *virtualNic = NULL;
It's a bit disconcerting to see these called "virtual" NICs, when
virInterface is all about configuring interfaces on the *physical* host.
This i my biggest concern here too, and also that's the reason why I didn't implement the network driver yet. Because I'm not sure what is the proper mapping between libvirt and vSphere API here.
As far as I understand this, a HostVirtualNic seems to be the best match for a virInterface. A HostVirtualNic is connected to HostVirtualSwitch, that is connected to the physical network via a PhysicalNic. >There is not much one can do about the PhysicalNic. It just sits there and is connected to the HostVirtualSwitch. The HostVirtualNic is also the one that has the external IP address of the ESX server >assigned.
Also a HostVirtualNic is not part of the virtual hardware of a VM. A VirtualEthernetCard is the type in the vSphere API representing the virtual network interface of a virtual machine
[AB]: I have developed the driver based on the same understanding; the only thing that I could not map vSphere API <--> Libvirt API was how to allow user application to configure end-end networking on ESX server that includes: creating vSwitches, attaching them to physical network and then configuring HostVirtual Nics. I am still working on the "interfaceCreateXML" that would allow addition of HostVirutalNic and associated portGroup if not present, but could not find any mapping API to add vSwitches.
Being unfamiliar with the vmware API, I'm not sure which of these
functions are things you've added to libvirt and which are part of
vmware, but please rename any that are defined in libvirt to use
"physical" or "host" or "p/h" as appropriate, rather than "virtual"
and/or "v". We want to make sure nobody gets the wrong idea about
these functions.
I don't think that this is a good idea, we should really stick exactly to the naming of things in the vSphere API otherwise there will be much more confusion.
Therefore,
esxVI_HostVirtualNic *virtualNicList = NULL;
should be
esxVI_HostVirtualNic *hostVirtualNicList = NULL;
Apart from that I'll do a more detailed review soon.
[AB]: Will modify the names such that HostVirtualNic should read same in vSphere API documentation.
+static int
+esxNumOfDefinedInterfaces(virConnectPtr conn) {
+ conn->interfacePrivateData = NULL;
Setting interfacePrivateData to NULL is equivalent to closing the driver. I don't think you really want to do this. Possibly it was an error in cut/paste from somewhere else (esxInterfaceClose()?).
[AB]: Patch 2/2 rectified this issue.
+
+ // ESX interfaces are always active
+ return 0;
+}
+
+
+
+static int
+esxListDefinedInterfaces(virConnectPtr conn, char **names, int
+maxnames) {
+ conn->interfacePrivateData = conn->privateData;
+ *names = NULL;
+
+ /* keeps compiler happy */
+ VIR_DEBUG("max interfaces: %d", maxnames);
+
+ // ESX interfaces are always active
+ return 0;
+}
As I'll be mentioning in PATCH 2/2, just do this right the first time, rather than having a followup patch to fix code you've just added.
[AB]: I will be more careful in the future to avoid such mistakes. Thanks for the advice.
+
+static int
+esxInterfaceCreate(virInterfacePtr iface, unsigned int flags) {
+ iface->conn->interfacePrivateData = NULL;
Again - you don't want to NULL this out - it's the same as closing the driver.
[AB]: Will remove it.
+
+ virCheckFlags(0, -1);
+
+ /* ESX interfaces are always active */
+ return 0;
+}
+
+
+
+static int
+esxInterfaceDestroy(virInterfacePtr iface, unsigned int flags) {
+ iface->conn->interfacePrivateData = NULL;
And again - don't NULL this.
[AB]: Ditto.
* A required property must be != 0 (NULL for pointers, "undefined"
== 0 for
A general comment - I didn't see any kind of mutexes in here. Is this code really threadsafe? (it looks like the toplevel functions just call into your utility functions to get a snapshot of the current state of >interfaces in vmware, then work with that snapshot during the rest of the call; I didn't look into the utility functions in detail, because the chance of me understanding them is fairly low anyway :-)
[AB]: I do not think mutex is needed to protect the routines, as ESX server can be operated from multiple vSphere Client interface (management console using vCenter or standalone) and best I know it allows the operation simultaneously. As said this is something I would also like to be discussed in the community, so far reading ESX storage driver where the workflow and driver model remains the same, I do not see any use of mutex to protect such operations. The only places mutexes are used are while using CURL sessions. -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
participants (4)
-
Ata E Husain
-
Ata E Husain Bohra
-
Laine Stump
-
Matthias Bolte