libvirt/src/esx/esx_network_driver.c
Daniel P. Berrange 90430791ae Make driver method names consistent with public APIs
Ensure that all drivers implementing public APIs use a
naming convention for their implementation that matches
the public API name.

eg for the public API   virDomainCreate make sure QEMU
uses qemuDomainCreate and not qemuDomainStart

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-24 11:00:18 +01:00

960 lines
30 KiB
C

/*
* esx_network_driver.c: network driver functions for managing VMware ESX
* host networks
*
* Copyright (C) 2010-2012 Red Hat, Inc.
* Copyright (C) 2010-2012 Matthias Bolte <matthias.bolte@googlemail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
#include <config.h>
#include "md5.h"
#include "internal.h"
#include "virutil.h"
#include "viralloc.h"
#include "virlog.h"
#include "viruuid.h"
#include "network_conf.h"
#include "esx_private.h"
#include "esx_network_driver.h"
#include "esx_vi.h"
#include "esx_vi_methods.h"
#include "esx_util.h"
#define VIR_FROM_THIS VIR_FROM_ESX
/*
* The UUID of a network is the MD5 sum of it's key. Therefore, verify that
* UUID and MD5 sum match in size, because we rely on that.
*/
verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN);
static virDrvOpenStatus
esxNetworkOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
unsigned int flags)
{
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
if (conn->driver->no != VIR_DRV_ESX) {
return VIR_DRV_OPEN_DECLINED;
}
conn->networkPrivateData = conn->privateData;
return VIR_DRV_OPEN_SUCCESS;
}
static int
esxNetworkClose(virConnectPtr conn)
{
conn->networkPrivateData = NULL;
return 0;
}
static int
esxConnectNumOfNetworks(virConnectPtr conn)
{
esxPrivate *priv = conn->networkPrivateData;
esxVI_HostVirtualSwitch *hostVirtualSwitchList = NULL;
esxVI_HostVirtualSwitch *hostVirtualSwitch = NULL;
int count = 0;
if (esxVI_EnsureSession(priv->primary) < 0 ||
esxVI_LookupHostVirtualSwitchList(priv->primary,
&hostVirtualSwitchList) < 0) {
return -1;
}
for (hostVirtualSwitch = hostVirtualSwitchList; hostVirtualSwitch != NULL;
hostVirtualSwitch = hostVirtualSwitch->_next) {
++count;
}
esxVI_HostVirtualSwitch_Free(&hostVirtualSwitchList);
return count;
}
static int
esxConnectListNetworks(virConnectPtr conn, char **const names, int maxnames)
{
bool success = false;
esxPrivate *priv = conn->networkPrivateData;
esxVI_HostVirtualSwitch *hostVirtualSwitchList = NULL;
esxVI_HostVirtualSwitch *hostVirtualSwitch = NULL;
int count = 0;
int i;
if (maxnames == 0) {
return 0;
}
if (esxVI_EnsureSession(priv->primary) < 0 ||
esxVI_LookupHostVirtualSwitchList(priv->primary,
&hostVirtualSwitchList) < 0) {
return -1;
}
for (hostVirtualSwitch = hostVirtualSwitchList; hostVirtualSwitch != NULL;
hostVirtualSwitch = hostVirtualSwitch->_next) {
names[count] = strdup(hostVirtualSwitch->name);
if (names[count] == NULL) {
virReportOOMError();
goto cleanup;
}
++count;
}
success = true;
cleanup:
if (! success) {
for (i = 0; i < count; ++i) {
VIR_FREE(names[i]);
}
count = -1;
}
esxVI_HostVirtualSwitch_Free(&hostVirtualSwitchList);
return count;
}
static int
esxConnectNumOfDefinedNetworks(virConnectPtr conn ATTRIBUTE_UNUSED)
{
/* ESX networks are always active */
return 0;
}
static int
esxConnectListDefinedNetworks(virConnectPtr conn ATTRIBUTE_UNUSED,
char **const names ATTRIBUTE_UNUSED,
int maxnames ATTRIBUTE_UNUSED)
{
/* ESX networks are always active */
return 0;
}
static virNetworkPtr
esxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
virNetworkPtr network = NULL;
esxPrivate *priv = conn->networkPrivateData;
esxVI_HostVirtualSwitch *hostVirtualSwitchList = NULL;
esxVI_HostVirtualSwitch *hostVirtualSwitch = NULL;
unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
if (esxVI_EnsureSession(priv->primary) < 0 ||
esxVI_LookupHostVirtualSwitchList(priv->primary,
&hostVirtualSwitchList) < 0) {
return NULL;
}
for (hostVirtualSwitch = hostVirtualSwitchList; hostVirtualSwitch != NULL;
hostVirtualSwitch = hostVirtualSwitch->_next) {
md5_buffer(hostVirtualSwitch->key, strlen(hostVirtualSwitch->key), md5);
if (memcmp(uuid, md5, VIR_UUID_BUFLEN) == 0) {
break;
}
}
if (hostVirtualSwitch == NULL) {
virUUIDFormat(uuid, uuid_string);
virReportError(VIR_ERR_NO_NETWORK,
_("Could not find HostVirtualSwitch with UUID '%s'"),
uuid_string);
goto cleanup;
}
network = virGetNetwork(conn, hostVirtualSwitch->name, uuid);
cleanup:
esxVI_HostVirtualSwitch_Free(&hostVirtualSwitchList);
return network;
}
static virNetworkPtr
esxNetworkLookupByName(virConnectPtr conn, const char *name)
{
virNetworkPtr network = NULL;
esxPrivate *priv = conn->networkPrivateData;
esxVI_HostVirtualSwitch *hostVirtualSwitch = NULL;
unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
if (esxVI_EnsureSession(priv->primary) < 0 ||
esxVI_LookupHostVirtualSwitchByName(priv->primary, name,
&hostVirtualSwitch,
esxVI_Occurrence_RequiredItem) < 0) {
return NULL;
}
/*
* HostVirtualSwitch doesn't have a UUID, but we can use the key property
* as source for a UUID. The key is unique per host and cannot change
* during the lifetime of the HostVirtualSwitch.
*
* The MD5 sum of the key can be used as UUID, assuming MD5 is considered
* to be collision-free enough for this use case.
*/
md5_buffer(hostVirtualSwitch->key, strlen(hostVirtualSwitch->key), md5);
network = virGetNetwork(conn, hostVirtualSwitch->name, md5);
esxVI_HostVirtualSwitch_Free(&hostVirtualSwitch);
return network;
}
static int
esxBandwidthToShapingPolicy(virNetDevBandwidthPtr bandwidth,
esxVI_HostNetworkTrafficShapingPolicy **shapingPolicy)
{
int result = -1;
if (shapingPolicy == NULL || *shapingPolicy != NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
return -1;
}
if (bandwidth->in == NULL || bandwidth->out == NULL ||
bandwidth->in->average != bandwidth->out->average ||
bandwidth->in->peak != bandwidth->out->peak ||
bandwidth->in->burst != bandwidth->out->burst) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Different inbound and outbound bandwidth is unsupported"));
return -1;
}
if (bandwidth->in->average == 0 && bandwidth->in->peak == 0 &&
bandwidth->in->burst == 0) {
return 0;
}
if (esxVI_HostNetworkTrafficShapingPolicy_Alloc(shapingPolicy) < 0) {
goto cleanup;
}
(*shapingPolicy)->enabled = esxVI_Boolean_True;
if (bandwidth->in->average > 0) {
if (esxVI_Long_Alloc(&(*shapingPolicy)->averageBandwidth) < 0) {
goto cleanup;
}
/* Scale kilobytes per second to bits per second */
(*shapingPolicy)->averageBandwidth->value = bandwidth->in->average * 8 * 1000;
}
if (bandwidth->in->peak > 0) {
if (esxVI_Long_Alloc(&(*shapingPolicy)->peakBandwidth) < 0) {
goto cleanup;
}
/* Scale kilobytes per second to bits per second */
(*shapingPolicy)->peakBandwidth->value = bandwidth->in->peak * 8 * 1000;
}
if (bandwidth->in->burst > 0) {
if (esxVI_Long_Alloc(&(*shapingPolicy)->burstSize) < 0) {
goto cleanup;
}
/* Scale kilobytes to bytes */
(*shapingPolicy)->burstSize->value = bandwidth->in->burst * 1024;
}
result = 0;
cleanup:
if (result < 0) {
esxVI_HostNetworkTrafficShapingPolicy_Free(shapingPolicy);
}
return result;
}
static virNetworkPtr
esxNetworkDefineXML(virConnectPtr conn, const char *xml)
{
virNetworkPtr network = NULL;
esxPrivate *priv = conn->networkPrivateData;
virNetworkDefPtr def = NULL;
esxVI_HostVirtualSwitch *hostVirtualSwitch = NULL;
esxVI_HostPortGroup *hostPortGroupList = NULL;
esxVI_HostPortGroup *hostPortGroup = NULL;
esxVI_HostVirtualSwitchSpec *hostVirtualSwitchSpec = NULL;
esxVI_HostVirtualSwitchBondBridge *hostVirtualSwitchBondBridge = NULL;
esxVI_PhysicalNic *physicalNicList = NULL;
esxVI_PhysicalNic *physicalNic = NULL;
esxVI_HostPortGroupSpec *hostPortGroupSpec = NULL;
int i;
unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
if (esxVI_EnsureSession(priv->primary) < 0) {
return NULL;
}
/* Parse network XML */
def = virNetworkDefParseString(xml);
if (def == NULL) {
return NULL;
}
/* Check if an existing HostVirtualSwitch should be edited */
if (esxVI_LookupHostVirtualSwitchByName(priv->primary, def->name,
&hostVirtualSwitch,
esxVI_Occurrence_OptionalItem) < 0) {
goto cleanup;
}
if (hostVirtualSwitch != NULL) {
/* FIXME */
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("HostVirtualSwitch already exists, editing existing "
"ones is not supported yet"));
goto cleanup;
}
/* UUID is derived from the HostVirtualSwitch's key and cannot be specified */
if (def->uuid_specified) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Cannot use predefined UUID"));
goto cleanup;
}
/* FIXME: Add support for NAT */
if (def->forward.type != VIR_NETWORK_FORWARD_NONE &&
def->forward.type != VIR_NETWORK_FORWARD_BRIDGE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported forward mode '%s'"),
virNetworkForwardTypeToString(def->forward.type));
goto cleanup;
}
/* Verify that specified HostPortGroups don't exist already */
if (def->nPortGroups > 0) {
if (esxVI_LookupHostPortGroupList(priv->primary, &hostPortGroupList) < 0) {
goto cleanup;
}
for (i = 0; i < def->nPortGroups; ++i) {
for (hostPortGroup = hostPortGroupList; hostPortGroup != NULL;
hostPortGroup = hostPortGroup->_next) {
if (STREQ(def->portGroups[i].name, hostPortGroup->spec->name)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("HostPortGroup with name '%s' exists already"),
def->portGroups[i].name);
goto cleanup;
}
}
}
}
/* Create HostVirtualSwitch */
if (esxVI_HostVirtualSwitchSpec_Alloc(&hostVirtualSwitchSpec) < 0 ||
esxVI_Int_Alloc(&hostVirtualSwitchSpec->numPorts) < 0) {
goto cleanup;
}
if (def->forward.type != VIR_NETWORK_FORWARD_NONE && def->forward.nifs > 0) {
if (esxVI_HostVirtualSwitchBondBridge_Alloc
(&hostVirtualSwitchBondBridge) < 0) {
goto cleanup;
}
hostVirtualSwitchSpec->bridge =
(esxVI_HostVirtualSwitchBridge *)hostVirtualSwitchBondBridge;
/* Lookup PhysicalNic list and match by name to get key */
if (esxVI_LookupPhysicalNicList(priv->primary, &physicalNicList) < 0) {
goto cleanup;
}
for (i = 0; i < def->forward.nifs; ++i) {
bool found = false;
if (def->forward.ifs[i].type !=
VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unsupported device type in network %s "
"interface pool"),
def->name);
goto cleanup;
}
for (physicalNic = physicalNicList; physicalNic != NULL;
physicalNic = physicalNic->_next) {
if (STREQ(def->forward.ifs[i].device.dev, physicalNic->device)) {
if (esxVI_String_AppendValueToList
(&hostVirtualSwitchBondBridge->nicDevice,
physicalNic->key) < 0) {
goto cleanup;
}
found = true;
break;
}
}
if (! found) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Could not find PhysicalNic with name '%s'"),
def->forward.ifs[i].device.dev);
goto cleanup;
}
}
}
hostVirtualSwitchSpec->numPorts->value = 128;
if (def->bandwidth != NULL) {
if (esxVI_HostNetworkPolicy_Alloc(&hostVirtualSwitchSpec->policy) < 0) {
goto cleanup;
}
if (esxBandwidthToShapingPolicy
(def->bandwidth,
&hostVirtualSwitchSpec->policy->shapingPolicy) < 0) {
goto cleanup;
}
}
if (esxVI_AddVirtualSwitch
(priv->primary,
priv->primary->hostSystem->configManager->networkSystem,
def->name, hostVirtualSwitchSpec) < 0) {
goto cleanup;
}
/* Create HostPortGroup(s) */
for (i = 0; i < def->nPortGroups; ++i) {
esxVI_HostPortGroupSpec_Free(&hostPortGroupSpec);
if (esxVI_HostPortGroupSpec_Alloc(&hostPortGroupSpec) < 0 ||
esxVI_HostNetworkPolicy_Alloc(&hostPortGroupSpec->policy) < 0 ||
esxVI_Int_Alloc(&hostPortGroupSpec->vlanId) < 0 ||
esxVI_String_DeepCopyValue(&hostPortGroupSpec->name,
def->portGroups[i].name) < 0 ||
esxVI_String_DeepCopyValue(&hostPortGroupSpec->vswitchName,
def->name) < 0) {
goto cleanup;
}
hostPortGroupSpec->vlanId->value = 0;
if (def->portGroups[i].bandwidth != NULL) {
if (esxBandwidthToShapingPolicy
(def->portGroups[i].bandwidth,
&hostPortGroupSpec->policy->shapingPolicy) < 0) {
goto cleanup;
}
}
if (esxVI_AddPortGroup
(priv->primary,
priv->primary->hostSystem->configManager->networkSystem,
hostPortGroupSpec) < 0) {
goto cleanup;
}
}
/* Lookup created HostVirtualSwitch to get the UUID */
if (esxVI_LookupHostVirtualSwitchByName(priv->primary, def->name,
&hostVirtualSwitch,
esxVI_Occurrence_RequiredItem) < 0) {
goto cleanup;
}
md5_buffer(hostVirtualSwitch->key, strlen(hostVirtualSwitch->key), md5);
network = virGetNetwork(conn, hostVirtualSwitch->name, md5);
cleanup:
virNetworkDefFree(def);
esxVI_HostVirtualSwitch_Free(&hostVirtualSwitch);
esxVI_HostPortGroup_Free(&hostPortGroupList);
esxVI_HostVirtualSwitchSpec_Free(&hostVirtualSwitchSpec);
esxVI_PhysicalNic_Free(&physicalNicList);
esxVI_HostPortGroupSpec_Free(&hostPortGroupSpec);
return network;
}
static int
esxNetworkUndefine(virNetworkPtr network)
{
int result = -1;
esxPrivate *priv = network->conn->networkPrivateData;
esxVI_HostVirtualSwitch *hostVirtualSwitch = NULL;
esxVI_HostPortGroup *hostPortGroupList = NULL;
esxVI_String *hostPortGroupKey = NULL;
esxVI_HostPortGroup *hostPortGroup = NULL;
esxVI_HostPortGroupPort *hostPortGroupPort = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
return -1;
}
/* Lookup HostVirtualSwitch and HostPortGroup list*/
if (esxVI_LookupHostVirtualSwitchByName(priv->primary, network->name,
&hostVirtualSwitch,
esxVI_Occurrence_RequiredItem) < 0 ||
esxVI_LookupHostPortGroupList(priv->primary, &hostPortGroupList) < 0) {
goto cleanup;
}
/* Verify that the HostVirtualSwitch is connected to virtual machines only */
for (hostPortGroupKey = hostVirtualSwitch->portgroup;
hostPortGroupKey != NULL; hostPortGroupKey = hostPortGroupKey->_next) {
bool found = false;
for (hostPortGroup = hostPortGroupList; hostPortGroup != NULL;
hostPortGroup = hostPortGroup->_next) {
if (STREQ(hostPortGroupKey->value, hostPortGroup->key)) {
for (hostPortGroupPort = hostPortGroup->port;
hostPortGroupPort != NULL;
hostPortGroupPort = hostPortGroupPort->_next) {
if (STRNEQ(hostPortGroupPort->type, "virtualMachine")) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("Cannot undefine HostVirtualSwitch that has a '%s' port"),
hostPortGroupPort->type);
goto cleanup;
}
}
found = true;
break;
}
}
if (! found) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Could not find HostPortGroup for key '%s'"),
hostPortGroupKey->value);
goto cleanup;
}
}
/* Remove all HostPortGroups from the HostVirtualSwitch */
for (hostPortGroupKey = hostVirtualSwitch->portgroup;
hostPortGroupKey != NULL; hostPortGroupKey = hostPortGroupKey->_next) {
bool found = false;
for (hostPortGroup = hostPortGroupList; hostPortGroup != NULL;
hostPortGroup = hostPortGroup->_next) {
if (STREQ(hostPortGroupKey->value, hostPortGroup->key)) {
if (esxVI_RemovePortGroup
(priv->primary,
priv->primary->hostSystem->configManager->networkSystem,
hostPortGroup->spec->name) < 0) {
goto cleanup;
}
found = true;
break;
}
}
if (! found) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Could not find HostPortGroup for key '%s'"),
hostPortGroupKey->value);
goto cleanup;
}
}
/* Finally, remove HostVirtualSwitch itself */
if (esxVI_RemoveVirtualSwitch
(priv->primary,
priv->primary->hostSystem->configManager->networkSystem,
network->name) < 0) {
goto cleanup;
}
result = 0;
cleanup:
esxVI_HostVirtualSwitch_Free(&hostVirtualSwitch);
esxVI_HostPortGroup_Free(&hostPortGroupList);
return result;
}
static int
esxShapingPolicyToBandwidth(esxVI_HostNetworkTrafficShapingPolicy *shapingPolicy,
virNetDevBandwidthPtr *bandwidth)
{
if (bandwidth == NULL || *bandwidth != NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
return -1;
}
if (shapingPolicy == NULL || shapingPolicy->enabled != esxVI_Boolean_True) {
return 0;
}
if (VIR_ALLOC(*bandwidth) < 0 ||
VIR_ALLOC((*bandwidth)->in) < 0 ||
VIR_ALLOC((*bandwidth)->out) < 0) {
virReportOOMError();
return -1;
}
if (shapingPolicy->averageBandwidth != NULL) {
/* Scale bits per second to kilobytes per second */
(*bandwidth)->in->average = shapingPolicy->averageBandwidth->value / 8 / 1000;
(*bandwidth)->out->average = shapingPolicy->averageBandwidth->value / 8 / 1000;
}
if (shapingPolicy->peakBandwidth != NULL) {
/* Scale bits per second to kilobytes per second */
(*bandwidth)->in->peak = shapingPolicy->peakBandwidth->value / 8 / 1000;
(*bandwidth)->out->peak = shapingPolicy->peakBandwidth->value / 8 / 1000;
}
if (shapingPolicy->burstSize != NULL) {
/* Scale bytes to kilobytes */
(*bandwidth)->in->burst = shapingPolicy->burstSize->value / 1024;
(*bandwidth)->out->burst = shapingPolicy->burstSize->value / 1024;
}
return 0;
}
static char *
esxNetworkGetXMLDesc(virNetworkPtr network_, unsigned int flags)
{
char *xml = NULL;
esxPrivate *priv = network_->conn->networkPrivateData;
esxVI_HostVirtualSwitch *hostVirtualSwitch = NULL;
int count = 0;
esxVI_PhysicalNic *physicalNicList = NULL;
esxVI_PhysicalNic *physicalNic = NULL;
esxVI_String *physicalNicKey = NULL;
esxVI_HostPortGroup *hostPortGroupList = NULL;
esxVI_HostPortGroup *hostPortGroup = NULL;
esxVI_String *propertyNameList = NULL;
esxVI_ObjectContent *networkList = NULL;
esxVI_ObjectContent *network = NULL;
esxVI_String *networkNameList = NULL;
esxVI_String *hostPortGroupKey = NULL;
esxVI_String *networkName = NULL;
virNetworkDefPtr def;
if (esxVI_EnsureSession(priv->primary) < 0) {
return NULL;
}
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
goto cleanup;
}
/* Lookup HostVirtualSwitch */
if (esxVI_LookupHostVirtualSwitchByName(priv->primary, network_->name,
&hostVirtualSwitch,
esxVI_Occurrence_RequiredItem) < 0) {
goto cleanup;
}
md5_buffer(hostVirtualSwitch->key, strlen(hostVirtualSwitch->key), def->uuid);
def->name = strdup(hostVirtualSwitch->name);
if (def->name == NULL) {
virReportOOMError();
goto cleanup;
}
def->forward.type = VIR_NETWORK_FORWARD_NONE;
/* Count PhysicalNics on HostVirtualSwitch */
count = 0;
for (physicalNicKey = hostVirtualSwitch->pnic;
physicalNicKey != NULL; physicalNicKey = physicalNicKey->_next) {
++count;
}
if (count > 0) {
def->forward.type = VIR_NETWORK_FORWARD_BRIDGE;
if (VIR_ALLOC_N(def->forward.ifs, count) < 0) {
virReportOOMError();
goto cleanup;
}
/* Find PhysicalNic by key */
if (esxVI_LookupPhysicalNicList(priv->primary, &physicalNicList) < 0) {
goto cleanup;
}
for (physicalNicKey = hostVirtualSwitch->pnic;
physicalNicKey != NULL; physicalNicKey = physicalNicKey->_next) {
bool found = false;
for (physicalNic = physicalNicList; physicalNic != NULL;
physicalNic = physicalNic->_next) {
if (STREQ(physicalNicKey->value, physicalNic->key)) {
def->forward.ifs[def->forward.nifs].type
= VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV;
def->forward.ifs[def->forward.nifs].device.dev
= strdup(physicalNic->device);
if (def->forward.ifs[def->forward.nifs].device.dev == NULL) {
virReportOOMError();
goto cleanup;
}
++def->forward.nifs;
found = true;
break;
}
}
if (! found) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Could not find PhysicalNic with key '%s'"),
physicalNicKey->value);
goto cleanup;
}
}
}
/* Count HostPortGroups on HostVirtualSwitch */
count = 0;
for (hostPortGroupKey = hostVirtualSwitch->portgroup;
hostPortGroupKey != NULL; hostPortGroupKey = hostPortGroupKey->_next) {
++count;
}
if (count > 0) {
if (VIR_ALLOC_N(def->portGroups, count) < 0) {
virReportOOMError();
goto cleanup;
}
/* Lookup Network list and create name list */
if (esxVI_String_AppendValueToList(&propertyNameList, "name") < 0 ||
esxVI_LookupNetworkList(priv->primary, propertyNameList,
&networkList) < 0) {
goto cleanup;
}
for (network = networkList; network != NULL; network = network->_next) {
char *tmp = NULL;
if (esxVI_GetStringValue(network, "name", &tmp,
esxVI_Occurrence_RequiredItem) < 0 ||
esxVI_String_AppendValueToList(&networkNameList, tmp) < 0) {
goto cleanup;
}
}
/* Find HostPortGroup by key */
if (esxVI_LookupHostPortGroupList(priv->primary, &hostPortGroupList) < 0) {
goto cleanup;
}
for (hostPortGroupKey = hostVirtualSwitch->portgroup;
hostPortGroupKey != NULL; hostPortGroupKey = hostPortGroupKey->_next) {
bool found = false;
for (hostPortGroup = hostPortGroupList; hostPortGroup != NULL;
hostPortGroup = hostPortGroup->_next) {
if (STREQ(hostPortGroupKey->value, hostPortGroup->key)) {
/* Find Network for HostPortGroup, there might be none */
for (networkName = networkNameList; networkName != NULL;
networkName = networkName->_next) {
if (STREQ(networkName->value, hostPortGroup->spec->name)) {
def->portGroups[def->nPortGroups].name = strdup(networkName->value);
if (def->portGroups[def->nPortGroups].name == NULL) {
virReportOOMError();
goto cleanup;
}
if (hostPortGroup->spec->policy != NULL) {
if (esxShapingPolicyToBandwidth
(hostPortGroup->spec->policy->shapingPolicy,
&def->portGroups[def->nPortGroups].bandwidth) < 0) {
++def->nPortGroups;
goto cleanup;
}
}
++def->nPortGroups;
break;
}
}
found = true;
break;
}
}
if (! found) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Could not find HostPortGroup with key '%s'"),
hostPortGroupKey->value);
goto cleanup;
}
}
}
if (hostVirtualSwitch->spec->policy != NULL) {
if (esxShapingPolicyToBandwidth
(hostVirtualSwitch->spec->policy->shapingPolicy,
&def->bandwidth) < 0) {
goto cleanup;
}
}
xml = virNetworkDefFormat(def, flags);
cleanup:
esxVI_HostVirtualSwitch_Free(&hostVirtualSwitch);
esxVI_PhysicalNic_Free(&physicalNicList);
esxVI_HostPortGroup_Free(&hostPortGroupList);
esxVI_String_Free(&propertyNameList);
esxVI_ObjectContent_Free(&networkList);
esxVI_String_Free(&networkNameList);
virNetworkDefFree(def);
return xml;
}
static int
esxNetworkGetAutostart(virNetworkPtr network ATTRIBUTE_UNUSED,
int *autostart)
{
/* ESX networks are always active */
*autostart = 1;
return 0;
}
static int
esxNetworkSetAutostart(virNetworkPtr network ATTRIBUTE_UNUSED,
int autostart)
{
/* Just accept autostart activation, but fail on autostart deactivation */
autostart = (autostart != 0);
if (! autostart) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot deactivate network autostart"));
return -1;
}
return 0;
}
static int
esxNetworkIsActive(virNetworkPtr network ATTRIBUTE_UNUSED)
{
/* ESX networks are always active */
return 1;
}
static int
esxNetworkIsPersistent(virNetworkPtr network ATTRIBUTE_UNUSED)
{
/* ESX has no concept of transient networks, so all of them are persistent */
return 1;
}
static virNetworkDriver esxNetworkDriver = {
.name = "ESX",
.networkOpen = esxNetworkOpen, /* 0.7.6 */
.networkClose = esxNetworkClose, /* 0.7.6 */
.connectNumOfNetworks = esxConnectNumOfNetworks, /* 0.10.0 */
.connectListNetworks = esxConnectListNetworks, /* 0.10.0 */
.connectNumOfDefinedNetworks = esxConnectNumOfDefinedNetworks, /* 0.10.0 */
.connectListDefinedNetworks = esxConnectListDefinedNetworks, /* 0.10.0 */
.networkLookupByUUID = esxNetworkLookupByUUID, /* 0.10.0 */
.networkLookupByName = esxNetworkLookupByName, /* 0.10.0 */
.networkDefineXML = esxNetworkDefineXML, /* 0.10.0 */
.networkUndefine = esxNetworkUndefine, /* 0.10.0 */
.networkGetXMLDesc = esxNetworkGetXMLDesc, /* 0.10.0 */
.networkGetAutostart = esxNetworkGetAutostart, /* 0.10.0 */
.networkSetAutostart = esxNetworkSetAutostart, /* 0.10.0 */
.networkIsActive = esxNetworkIsActive, /* 0.10.0 */
.networkIsPersistent = esxNetworkIsPersistent, /* 0.10.0 */
};
int
esxNetworkRegister(void)
{
return virRegisterNetworkDriver(&esxNetworkDriver);
}