[libvirt] [PATCH] esx: Implement network driver

Matthias Bolte matthias.bolte at googlemail.com
Sun Aug 5 20:11:32 UTC 2012


An ESX server has one or more PhysicalNics that represent the actual
hardware NICs. Those can be listed via the interface driver.

A libvirt virtual network is mapped to a HostVirtualSwitch. On the
physical side a HostVirtualSwitch can be connected to PhysicalNics.
On the virtual side a HostVirtualSwitch has HostPortGroups that are
mapped to libvirt virtual network's portgroups. Typically there is
HostPortGroups named 'VM Network' that is used to connect virtual
machines to a HostVirtualSwitch. A second HostPortGroup typically
named 'Management Network' is used to connect the hypervisor itself
to the HostVirtualSwitch. This one is not mapped to a libvirt virtual
network's portgroup. There can be more HostPortGroups than those
typical two on a HostVirtualSwitch.

         +---------------+-------------------+
   ...---|               |                   |   +-------------+
         | HostPortGroup |                   |---| PhysicalNic |
         |   VM Network  |                   |   |    vmnic0   |
   ...---|               |                   |   +-------------+
         +---------------+ HostVirtualSwitch |
                         |     vSwitch0      |
         +---------------+                   |
         | HostPortGroup |                   |
   ...---|   Management  |                   |
         |    Network    |                   |
         +---------------+-------------------+

The virtual counterparts of the PhysicalNic is the HostVirtualNic for
the hypervisor and the VirtualEthernetCard for the virtual machines
that are grouped into HostPortGroups.

   +---------------------+   +---------------+---...
   | VirtualEthernetCard |---|               |
   +---------------------+   | HostPortGroup |
   +---------------------+   |   VM Network  |
   | VirtualEthernetCard |---|               |
   +---------------------+   +---------------+
                                             |
                             +---------------+
   +---------------------+   | HostPortGroup |
   |    HostVirtualNic   |---|   Management  |
   +---------------------+   |    Network    |
                             +---------------+---...

The currently implemented network driver can list, define and undefine
HostVirtualSwitches including HostPortGroups for virtual machines.
Existing HostVirtualSwitches cannot be edited yet. This will be added
in a followup patch.
---
 po/POTFILES.in                 |    1 +
 src/conf/network_conf.c        |    3 +-
 src/conf/network_conf.h        |    3 +
 src/esx/esx_network_driver.c   |  867 +++++++++++++++++++++++++++++++++++++++-
 src/esx/esx_vi.c               |  171 ++++++++
 src/esx/esx_vi.h               |   14 +
 src/esx/esx_vi_generator.input |  151 +++++++
 src/esx/esx_vi_generator.py    |    5 +
 8 files changed, 1212 insertions(+), 3 deletions(-)

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 37a00ee..e617952 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -27,6 +27,7 @@ src/cpu/cpu_x86.c
 src/datatypes.c
 src/driver.c
 src/esx/esx_driver.c
+src/esx/esx_network_driver.c
 src/esx/esx_storage_driver.c
 src/esx/esx_util.c
 src/esx/esx_vi.c
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index eb92d93..a3714d9 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -47,8 +47,6 @@
 #define MAX_BRIDGE_ID 256
 #define VIR_FROM_THIS VIR_FROM_NETWORK
 
-VIR_ENUM_DECL(virNetworkForward)
-
 VIR_ENUM_IMPL(virNetworkForward,
               VIR_NETWORK_FORWARD_LAST,
               "none", "nat", "route", "bridge", "private", "vepa", "passthrough" )
@@ -967,6 +965,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
             goto error;
         }
         VIR_FREE(tmp);
+        def->uuid_specified = true;
     }
 
     /* Parse network domain information */
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 1c640a9..a95b382 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -148,6 +148,7 @@ typedef struct _virNetworkDef virNetworkDef;
 typedef virNetworkDef *virNetworkDefPtr;
 struct _virNetworkDef {
     unsigned char uuid[VIR_UUID_BUFLEN];
+    bool uuid_specified;
     char *name;
 
     char *bridge;       /* Name of bridge device */
@@ -289,4 +290,6 @@ int virNetworkObjIsDuplicate(virNetworkObjListPtr doms,
 void virNetworkObjLock(virNetworkObjPtr obj);
 void virNetworkObjUnlock(virNetworkObjPtr obj);
 
+VIR_ENUM_DECL(virNetworkForward)
+
 #endif /* __NETWORK_CONF_H__ */
diff --git a/src/esx/esx_network_driver.c b/src/esx/esx_network_driver.c
index 2e0e40b..b42f1d8 100644
--- a/src/esx/esx_network_driver.c
+++ b/src/esx/esx_network_driver.c
@@ -4,7 +4,7 @@
  *                       host networks
  *
  * Copyright (C) 2010-2011 Red Hat, Inc.
- * Copyright (C) 2010 Matthias Bolte <matthias.bolte at googlemail.com>
+ * Copyright (C) 2010-2012 Matthias Bolte <matthias.bolte at googlemail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,11 +24,13 @@
 
 #include <config.h>
 
+#include "md5.h"
 #include "internal.h"
 #include "util.h"
 #include "memory.h"
 #include "logging.h"
 #include "uuid.h"
+#include "network_conf.h"
 #include "esx_private.h"
 #include "esx_network_driver.h"
 #include "esx_vi.h"
@@ -37,6 +39,12 @@
 
 #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
@@ -67,10 +75,867 @@ esxNetworkClose(virConnectPtr conn)
 
 
 
+static int
+esxNumberOfNetworks(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
+esxListNetworks(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
+esxNumberOfDefinedNetworks(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    /* ESX networks are always active */
+    return 0;
+}
+
+
+
+static int
+esxListDefinedNetworks(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->forwardType != VIR_NETWORK_FORWARD_NONE &&
+        def->forwardType != VIR_NETWORK_FORWARD_BRIDGE) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Unsupported forward mode '%s'"),
+                       virNetworkForwardTypeToString(def->forwardType));
+        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->forwardType != VIR_NETWORK_FORWARD_NONE && def->nForwardIfs > 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->nForwardIfs; ++i) {
+            bool found = false;
+
+            for (physicalNic = physicalNicList; physicalNic != NULL;
+                 physicalNic = physicalNic->_next) {
+                if (STREQ(def->forwardIfs[i].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->forwardIfs[i].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->forwardType = VIR_NETWORK_FORWARD_NONE;
+
+    /* Count PhysicalNics on HostVirtualSwitch */
+    count = 0;
+
+    for (physicalNicKey = hostVirtualSwitch->pnic;
+         physicalNicKey != NULL; physicalNicKey = physicalNicKey->_next) {
+        ++count;
+    }
+
+    if (count > 0) {
+        def->forwardType = VIR_NETWORK_FORWARD_BRIDGE;
+
+        if (VIR_ALLOC_N(def->forwardIfs, 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->forwardIfs[def->nForwardIfs].dev = strdup(physicalNic->device);
+
+                    if (def->forwardIfs[def->nForwardIfs].dev == NULL) {
+                        virReportOOMError();
+                        goto cleanup;
+                    }
+
+                    ++def->nForwardIfs;
+
+                    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",
     .open = esxNetworkOpen, /* 0.7.6 */
     .close = esxNetworkClose, /* 0.7.6 */
+    .numOfNetworks = esxNumberOfNetworks, /* 0.10.0 */
+    .listNetworks = esxListNetworks, /* 0.10.0 */
+    .numOfDefinedNetworks = esxNumberOfDefinedNetworks, /* 0.10.0 */
+    .listDefinedNetworks = esxListDefinedNetworks, /* 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 */
 };
 
 
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index f3a9e91..65e1d9a 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -783,6 +783,7 @@ ESX_VI__TEMPLATE__FREE(Context,
     esxVI_SelectionSpec_Free(&item->selectSet_hostSystemToDatastore);
     esxVI_SelectionSpec_Free(&item->selectSet_computeResourceToHost);
     esxVI_SelectionSpec_Free(&item->selectSet_computeResourceToParentToParent);
+    esxVI_SelectionSpec_Free(&item->selectSet_datacenterToNetwork);
 })
 
 int
@@ -1927,6 +1928,13 @@ esxVI_BuildSelectSetCollection(esxVI_Context *ctx)
         return -1;
     }
 
+    /* Datacenter -> network (Network) */
+    if (esxVI_BuildSelectSet(&ctx->selectSet_datacenterToNetwork,
+                             "datacenterToNetwork",
+                             "Datacenter", "network", NULL) < 0) {
+        return -1;
+    }
+
     return 0;
 }
 
@@ -2094,6 +2102,15 @@ esxVI_LookupObjectContentByType(esxVI_Context *ctx,
                                type, root->type);
                 goto cleanup;
             }
+        } else if (STREQ(root->type, "Datacenter")) {
+            if (STREQ(type, "Network")) {
+                objectSpec->selectSet = ctx->selectSet_datacenterToNetwork;
+            } else {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("Invalid lookup of '%s' from '%s'"),
+                               type, root->type);
+                goto cleanup;
+            }
         } else {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Invalid lookup from '%s'"), root->type);
@@ -4091,6 +4108,160 @@ esxVI_LookupPhysicalNicByMACAddress(esxVI_Context *ctx, const char *mac,
 
 
 int
+esxVI_LookupHostVirtualSwitchList(esxVI_Context *ctx,
+                                  esxVI_HostVirtualSwitch **hostVirtualSwitchList)
+{
+    int result = -1;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *hostSystem = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+
+    if (hostVirtualSwitchList == NULL || *hostVirtualSwitchList != NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (esxVI_String_AppendValueToList(&propertyNameList,
+                                       "config.network.vswitch") < 0 ||
+        esxVI_LookupHostSystemProperties(ctx, propertyNameList,
+                                         &hostSystem) < 0) {
+        goto cleanup;
+    }
+
+    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "config.network.vswitch")) {
+            if (esxVI_HostVirtualSwitch_CastListFromAnyType
+                 (dynamicProperty->val, hostVirtualSwitchList) < 0) {
+                goto cleanup;
+            }
+        } else {
+            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+        }
+    }
+
+    result = 0;
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&hostSystem);
+
+    return result;
+}
+
+
+
+int
+esxVI_LookupHostVirtualSwitchByName(esxVI_Context *ctx, const char *name,
+                                    esxVI_HostVirtualSwitch **hostVirtualSwitch,
+                                    esxVI_Occurrence occurrence)
+{
+    int result = -1;
+    esxVI_HostVirtualSwitch *hostVirtualSwitchList = NULL;
+    esxVI_HostVirtualSwitch *candidate = NULL;
+
+    if (hostVirtualSwitch == NULL || *hostVirtualSwitch != NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (esxVI_LookupHostVirtualSwitchList(ctx, &hostVirtualSwitchList) < 0) {
+        goto cleanup;
+    }
+
+    /* Search for a matching HostVirtualSwitch */
+    for (candidate = hostVirtualSwitchList; candidate != NULL;
+         candidate = candidate->_next) {
+        if (STREQ(candidate->name, name)) {
+            if (esxVI_HostVirtualSwitch_DeepCopy(hostVirtualSwitch,
+                                                 candidate) < 0) {
+                goto cleanup;
+            }
+
+            /* Found HostVirtualSwitch with matching name */
+            result = 0;
+
+            goto cleanup;
+        }
+    }
+
+    if (*hostVirtualSwitch == NULL &&
+        occurrence != esxVI_Occurrence_OptionalItem) {
+        virReportError(VIR_ERR_NO_NETWORK,
+                       _("Could not find HostVirtualSwitch with name '%s'"),
+                       name);
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+    esxVI_HostVirtualSwitch_Free(&hostVirtualSwitchList);
+
+    return result;
+}
+
+
+
+int
+esxVI_LookupHostPortGroupList(esxVI_Context *ctx,
+                              esxVI_HostPortGroup **hostPortGroupList)
+{
+    int result = -1;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *hostSystem = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+
+    if (hostPortGroupList == NULL || *hostPortGroupList != NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (esxVI_String_AppendValueToList(&propertyNameList,
+                                       "config.network.portgroup") < 0 ||
+        esxVI_LookupHostSystemProperties(ctx, propertyNameList,
+                                         &hostSystem) < 0) {
+        goto cleanup;
+    }
+
+    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "config.network.portgroup")) {
+            if (esxVI_HostPortGroup_CastListFromAnyType
+                  (dynamicProperty->val, hostPortGroupList) < 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_LookupNetworkList(esxVI_Context *ctx, esxVI_String *propertyNameList,
+                        esxVI_ObjectContent **networkList)
+{
+    return esxVI_LookupObjectContentByType(ctx, ctx->datacenter->_reference,
+                                           "Network", propertyNameList,
+                                           networkList,
+                                           esxVI_Occurrence_OptionalList);
+}
+
+
+
+int
 esxVI_HandleVirtualMachineQuestion
   (esxVI_Context *ctx, esxVI_ManagedObjectReference *virtualMachine,
    esxVI_VirtualMachineQuestionInfo *questionInfo, bool autoAnswer,
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 597013c..12394e7 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -227,6 +227,7 @@ struct _esxVI_Context {
     esxVI_SelectionSpec *selectSet_hostSystemToDatastore;
     esxVI_SelectionSpec *selectSet_computeResourceToHost;
     esxVI_SelectionSpec *selectSet_computeResourceToParentToParent;
+    esxVI_SelectionSpec *selectSet_datacenterToNetwork;
     bool hasQueryVirtualDiskUuid;
     bool hasSessionIsActive;
 };
@@ -492,6 +493,19 @@ int esxVI_LookupPhysicalNicByMACAddress(esxVI_Context *ctx, const char *mac,
                                         esxVI_PhysicalNic **physicalNic,
                                         esxVI_Occurrence occurrence);
 
+int esxVI_LookupHostVirtualSwitchList
+      (esxVI_Context *ctx, esxVI_HostVirtualSwitch **hostVirtualSwitchList);
+
+int esxVI_LookupHostVirtualSwitchByName(esxVI_Context *ctx, const char *name,
+                                        esxVI_HostVirtualSwitch **hostVirtualSwitch,
+                                        esxVI_Occurrence occurrence);
+
+int esxVI_LookupHostPortGroupList(esxVI_Context *ctx,
+                                  esxVI_HostPortGroup **hostPortGroupList);
+
+int esxVI_LookupNetworkList(esxVI_Context *ctx, esxVI_String *propertyNameList,
+                            esxVI_ObjectContent **networkList);
+
 int esxVI_HandleVirtualMachineQuestion
       (esxVI_Context *ctx, esxVI_ManagedObjectReference *virtualMachine,
        esxVI_VirtualMachineQuestionInfo *questionInfo, bool autoAnswer,
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index 5572b36..c4a3e56 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -338,12 +338,138 @@ object HostNasVolume                 extends HostFileSystemVolume
 end
 
 
+object HostNetOffloadCapabilities
+    Boolean                                  csumOffload                    o
+    Boolean                                  tcpSegmentation                o
+    Boolean                                  zeroCopyXmit                   o
+end
+
+
+object HostNetworkPolicy
+    HostNetworkSecurityPolicy                security                       o
+    HostNicTeamingPolicy                     nicTeaming                     o
+    HostNetOffloadCapabilities               offloadPolicy                  o
+    HostNetworkTrafficShapingPolicy          shapingPolicy                  o
+end
+
+
+object HostNetworkSecurityPolicy
+    Boolean                                  allowPromiscuous               o
+    Boolean                                  macChanges                     o
+    Boolean                                  forgedTransmits                o
+end
+
+
+object HostNetworkTrafficShapingPolicy
+    Boolean                                  enabled                        o
+    Long                                     averageBandwidth               o
+    Long                                     peakBandwidth                  o
+    Long                                     burstSize                      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 HostNicTeamingPolicy
+    String                                   policy                         o
+    Boolean                                  reversePolicy                  o
+    Boolean                                  notifySwitches                 o
+    Boolean                                  rollingOrder                   o
+    HostNicFailureCriteria                   failureCriteria                o
+    HostNicOrderPolicy                       nicOrder                       o
+end
+
+
+object HostPortGroup
+    String                                   key                            o
+    HostPortGroupPort                        port                           ol
+    String                                   vswitch                        o
+    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 HostVirtualSwitch
+    String                                   name                           r
+    String                                   key                            r
+    Int                                      numPorts                       r
+    Int                                      numPortsAvailable              r
+    Int                                      mtu                            o
+    String                                   portgroup                      ol
+    String                                   pnic                           ol
+    HostVirtualSwitchSpec                    spec                           r
+end
+
+
+object HostVirtualSwitchAutoBridge   extends HostVirtualSwitchBridge
+    String                                   excludedNicDevice              ol
+end
+
+
+object HostVirtualSwitchBeaconConfig
+    Int                                      interval                       r
+end
+
+
+object HostVirtualSwitchBondBridge   extends HostVirtualSwitchBridge
+    String                                   nicDevice                      rl
+    HostVirtualSwitchBeaconConfig            beacon                         o
+end
+
+
+object HostVirtualSwitchBridge
+end
+
+
+object HostVirtualSwitchSimpleBridge extends HostVirtualSwitchBridge
+    String                                   nicDevice                      r
+end
+
+
+object HostVirtualSwitchSpec
+    Int                                      numPorts                       r
+    HostVirtualSwitchBridge                  bridge                         o
+    HostNetworkPolicy                        policy                         o
+    Int                                      mtu                            o
+end
+
+
 object HostVmfsVolume                extends HostFileSystemVolume
     Int                                      blockSizeMb                    r
     Int                                      maxBlocks                      r
@@ -805,6 +931,19 @@ end
 # Methods
 #
 
+method AddPortGroup
+    ManagedObjectReference                   _this                          r
+    HostPortGroupSpec                        portgrp                        r
+end
+
+
+method AddVirtualSwitch
+    ManagedObjectReference                   _this                          r
+    String                                   vswitchName                    r
+    HostVirtualSwitchSpec                    spec                           o
+end
+
+
 method AnswerVM
     ManagedObjectReference                   _this                          r
     String                                   questionId                     r
@@ -981,12 +1120,24 @@ method RegisterVM_Task               returns ManagedObjectReference         r
 end
 
 
+method RemovePortGroup
+    ManagedObjectReference                   _this                          r
+    String                                   pgName                         r
+end
+
+
 method RemoveSnapshot_Task           returns ManagedObjectReference         r
     ManagedObjectReference                   _this                          r
     Boolean                                  removeChildren                 r
 end
 
 
+method RemoveVirtualSwitch
+    ManagedObjectReference                   _this                          r
+    String                                   vswitchName                    r
+end
+
+
 method RetrieveProperties            returns ObjectContent                  ol
     ManagedObjectReference                   _this:propertyCollector        r
     PropertyFilterSpec                       specSet                        rl
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index 596bd16..b49db70 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -1520,6 +1520,11 @@ additional_object_features = { "AutoStartDefaults"          : Object.FEATURE__AN
                                                               Object.FEATURE__ANY_TYPE,
                                "HostDatastoreBrowserSearchResults" : Object.FEATURE__LIST |
                                                               Object.FEATURE__ANY_TYPE,
+                               "HostPortGroup"              : Object.FEATURE__LIST |
+                                                              Object.FEATURE__ANY_TYPE,
+                               "HostVirtualSwitch"          : Object.FEATURE__DEEP_COPY |
+                                                              Object.FEATURE__LIST |
+                                                              Object.FEATURE__ANY_TYPE,
                                "ManagedObjectReference"     : Object.FEATURE__ANY_TYPE,
                                "ObjectContent"              : Object.FEATURE__DEEP_COPY,
                                "PhysicalNic"                : Object.FEATURE__DEEP_COPY |
-- 
1.7.4.1




More information about the libvir-list mailing list