[PATCH 03/12] hyperv: XML parsing of Ethernet adapters

Matt Coleman mcoleman at datto.com
Fri Jan 22 20:18:34 UTC 2021


Co-authored-by: Sri Ramanujam <sramanujam at datto.com>
Signed-off-by: Matt Coleman <matt at datto.com>
---
 src/hyperv/hyperv_driver.c            | 113 ++++++++++++++++++++++++++
 src/hyperv/hyperv_wmi.c               |  20 +++++
 src/hyperv/hyperv_wmi.h               |   8 ++
 src/hyperv/hyperv_wmi_classes.h       |  12 +++
 src/hyperv/hyperv_wmi_generator.input | 109 +++++++++++++++++++++++++
 5 files changed, 262 insertions(+)

diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
index 9394794c8f..ca75de98a9 100644
--- a/src/hyperv/hyperv_driver.c
+++ b/src/hyperv/hyperv_driver.c
@@ -1388,6 +1388,107 @@ hypervDomainDefParseSerial(virDomainDefPtr def, Msvm_ResourceAllocationSettingDa
 }
 
 
+static int
+hypervDomainDefParseEthernetAdapter(virDomainDefPtr def,
+                                    Msvm_EthernetPortAllocationSettingData *net,
+                                    hypervPrivate *priv)
+{
+    virDomainNetDefPtr ndef = NULL;
+    g_autoptr(Msvm_SyntheticEthernetPortSettingData) sepsd = NULL;
+    g_autoptr(Msvm_VirtualEthernetSwitch) vSwitch = NULL;
+    char **switchConnection = NULL;
+    g_autofree char *switchConnectionEscaped = NULL;
+    char *sepsdPATH = NULL;
+    g_autofree char *sepsdEscaped = NULL;
+    g_auto(virBuffer) query = VIR_BUFFER_INITIALIZER;
+
+    VIR_DEBUG("Parsing ethernet adapter '%s'", net->data->InstanceID);
+
+    ndef = g_new0(virDomainNetDef, 1);
+
+    ndef->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
+
+    /*
+     * If there's no switch port connection or the EnabledState is disabled,
+     * then the adapter isn't hooked up to anything and we don't have to
+     * do anything more.
+     */
+    switchConnection = net->data->HostResource.data;
+    if (net->data->HostResource.count < 1 || !*switchConnection ||
+        net->data->EnabledState == MSVM_ETHERNETPORTALLOCATIONSETTINGDATA_ENABLEDSTATE_DISABLED) {
+        VIR_DEBUG("Adapter not connected to switch");
+        return 0;
+    }
+
+    /*
+     * Now we retrieve the associated Msvm_SyntheticEthernetPortSettingData and
+     * Msvm_VirtualEthernetSwitch objects and use them to build the XML definition.
+     */
+
+    /* begin by getting the Msvm_SyntheticEthernetPortSettingData object */
+    sepsdPATH = net->data->Parent;
+    sepsdEscaped = virStringReplace(sepsdPATH, "\\", "\\\\");
+    virBufferAsprintf(&query,
+                      MSVM_SYNTHETICETHERNETPORTSETTINGDATA_WQL_SELECT "WHERE __PATH = '%s'",
+                      sepsdEscaped);
+
+    if (hypervGetWmiClass(Msvm_SyntheticEthernetPortSettingData, &sepsd) < 0)
+        return -1;
+
+    if (!sepsd) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not retrieve NIC settings"));
+        return -1;
+    }
+
+    /* set mac address */
+    if (virMacAddrParseHex(sepsd->data->Address, &ndef->mac) < 0)
+        return -1;
+
+    /* now we get the Msvm_VirtualEthernetSwitch */
+    virBufferFreeAndReset(&query);
+    switchConnectionEscaped = virStringReplace(*switchConnection, "\\", "\\\\");
+    virBufferAsprintf(&query,
+                      MSVM_VIRTUALETHERNETSWITCH_WQL_SELECT "WHERE __PATH = '%s'",
+                      switchConnectionEscaped);
+
+    if (hypervGetWmiClass(Msvm_VirtualEthernetSwitch, &vSwitch) < 0)
+        return -1;
+
+    if (!vSwitch) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not retrieve virtual switch"));
+        return -1;
+    }
+
+    /* get bridge name */
+    ndef->data.bridge.brname = g_strdup(vSwitch->data->Name);
+
+    if (VIR_APPEND_ELEMENT(def->nets, def->nnets, ndef) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not append definition to domain"));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+hypervDomainDefParseEthernet(virDomainPtr domain,
+                             virDomainDefPtr def,
+                             Msvm_EthernetPortAllocationSettingData *nets)
+{
+    Msvm_EthernetPortAllocationSettingData *entry = nets;
+    hypervPrivate *priv = domain->conn->privateData;
+
+    while (entry) {
+        if (hypervDomainDefParseEthernetAdapter(def, entry, priv) < 0)
+            return -1;
+
+        entry = entry->next;
+    }
+
+    return 0;
+}
+
+
 /*
  * Driver functions
  */
@@ -2249,6 +2350,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
     g_autoptr(Msvm_StorageAllocationSettingData) sasd = NULL;
     g_autoptr(Msvm_SerialPortSettingData) spsd = NULL;
     Msvm_ResourceAllocationSettingData *serialDevices = NULL;
+    g_autoptr(Msvm_EthernetPortAllocationSettingData) nets = NULL;
 
     virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
 
@@ -2290,6 +2392,10 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
     if (hypervGetSerialPortSD(priv, virtualSystemSettingData->data->InstanceID, &spsd) < 0)
         return NULL;
 
+    if (hypervGetEthernetPortAllocationSD(priv,
+                                          virtualSystemSettingData->data->InstanceID, &nets) < 0)
+        return NULL;
+
     /* Fill struct */
     def->virtType = VIR_DOMAIN_VIRT_HYPERV;
 
@@ -2351,6 +2457,10 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
     def->controllers = g_new0(virDomainControllerDefPtr, 5);
     def->ncontrollers = 0;
 
+    /* 8 synthetic + 4 legacy NICs */
+    def->nets = g_new0(virDomainNetDefPtr, 12);
+    def->nnets = 0;
+
     if (hypervDomainDefParseStorage(priv, def, rasd, sasd) < 0)
         return NULL;
 
@@ -2362,6 +2472,9 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
     if (hypervDomainDefParseSerial(def, serialDevices) < 0)
         return NULL;
 
+    if (hypervDomainDefParseEthernet(domain, def, nets) < 0)
+        return NULL;
+
     /* XXX xmlopts must be non-NULL */
     return virDomainDefFormat(def, NULL, virDomainDefFormatConvertXMLFlags(flags));
 }
diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c
index f5f0797605..4c1bd5e0d2 100644
--- a/src/hyperv/hyperv_wmi.c
+++ b/src/hyperv/hyperv_wmi.c
@@ -1498,6 +1498,26 @@ hypervGetSerialPortSD(hypervPrivate *priv,
 }
 
 
+int
+hypervGetSyntheticEthernetPortSD(hypervPrivate *priv,
+                                 const char *id,
+                                 Msvm_SyntheticEthernetPortSettingData **data)
+{
+    hypervGetSettingData(Msvm_SyntheticEthernetPortSettingData, id, data);
+    return 0;
+}
+
+
+int
+hypervGetEthernetPortAllocationSD(hypervPrivate *priv,
+                                  const char *id,
+                                  Msvm_EthernetPortAllocationSettingData **data)
+{
+    hypervGetSettingData(Msvm_EthernetPortAllocationSettingData, id, data);
+    return 0;
+}
+
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * Msvm_VirtualSystemManagementService
  */
diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h
index 2b0d0e4a3f..6021a46f3e 100644
--- a/src/hyperv/hyperv_wmi.h
+++ b/src/hyperv/hyperv_wmi.h
@@ -258,6 +258,14 @@ int hypervGetSerialPortSD(hypervPrivate *priv,
                           const char *id,
                           Msvm_SerialPortSettingData **data);
 
+int hypervGetSyntheticEthernetPortSD(hypervPrivate *priv,
+                                     const char *id,
+                                     Msvm_SyntheticEthernetPortSettingData **data);
+
+int hypervGetEthernetPortAllocationSD(hypervPrivate *priv,
+                                      const char *id,
+                                      Msvm_EthernetPortAllocationSettingData **data);
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * Msvm_VirtualSystemManagementService
  */
diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h
index 2f813bedb3..eea24235a5 100644
--- a/src/hyperv/hyperv_wmi_classes.h
+++ b/src/hyperv/hyperv_wmi_classes.h
@@ -119,6 +119,18 @@ enum _Msvm_ResourceAllocationSettingData_ResourceType {
 
 
 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Msvm_EthernetPortAllocationSettingData
+ */
+
+/* https://docs.microsoft.com/en-us/windows/win32/hyperv_v2/msvm-ethernetportallocationsettingdata#enabled */
+enum _Msvm_EthernetPortAllocationSettingData_EnabledState {
+    MSVM_ETHERNETPORTALLOCATIONSETTINGDATA_ENABLEDSTATE_ENABLED = 2,
+    MSVM_ETHERNETPORTALLOCATIONSETTINGDATA_ENABLEDSTATE_DISABLED = 3,
+};
+
+
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * WMI
  */
diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input
index 765ffba169..df240361e6 100644
--- a/src/hyperv/hyperv_wmi_generator.input
+++ b/src/hyperv/hyperv_wmi_generator.input
@@ -827,3 +827,112 @@ class Msvm_StorageAllocationSettingData
     string  IOPSAllocationUnits
     boolean PersistentReservationsSupported
 end
+
+
+class Msvm_SyntheticEthernetPortSettingData
+    string   InstanceID
+    string   Caption
+    string   Description
+    string   ElementName
+    uint16   ResourceType
+    string   OtherResourceType
+    string   ResourceSubType
+    string   PoolID
+    uint16   ConsumerVisibility
+    string   HostResource[]
+    string   AllocationUnits
+    uint64   VirtualQuantity
+    uint64   Reservation
+    uint64   Limit
+    uint32   Weight
+    boolean  AutomaticAllocation
+    boolean  AutomaticDeallocation
+    string   Parent
+    string   Connection[]
+    string   Address
+    uint16   MappingBehavior
+    string   AddressOnParent
+    string   VirtualQuantityUnits
+    uint16   DesiredVLANEndpointMode
+    string   OtherEndpointMode
+    string   VirtualSystemIdentifiers[]
+# DeviceNamingEnabled and AllowPacketDirect are not present in Windows Server 2012R2.
+# They were added in Windows 10 and Windows Server 2016.
+# They have been omitted to retain compatibility with Windows Server 2012R2.
+#   boolean  DeviceNamingEnabled
+#   boolean  AllowPacketDirect
+    boolean  StaticMacAddress
+    boolean  ClusterMonitored
+end
+
+
+class Msvm_EthernetPortAllocationSettingData
+    string   InstanceID
+    string   Caption
+    string   Description
+    string   ElementName
+    uint16   ResourceType
+    string   OtherResourceType
+    string   ResourceSubType
+    string   PoolID
+    uint16   ConsumerVisibility
+    string   HostResource[]
+    string   AllocationUnits
+    uint64   VirtualQuantity
+    uint64   Reservation
+    uint64   Limit
+    uint32   Weight
+    boolean  AutomaticAllocation
+    boolean  AutomaticDeallocation
+    string   Parent
+    string   Connection[]
+    string   Address
+    uint16   MappingBehavior
+    string   AddressOnParent
+    string   VirtualQuantityUnits
+    uint16   DesiredVLANEndpointMode
+    string   OtherEndpointMode
+    uint16   EnabledState
+    string   RequiredFeatures[]
+    string   RequiredFeatureHints[]
+    string   TestReplicaPoolID
+    string   TestReplicaSwitchName
+end
+
+
+class Msvm_VirtualEthernetSwitch
+    string   InstanceID
+    string   Caption
+    string   Description
+    string   ElementName
+    datetime InstallDate
+    uint16   OperationalStatus[]
+    string   StatusDescriptions[]
+    string   Status
+    uint16   HealthState
+    uint16   CommunicationStatus
+    uint16   DetailedStatus
+    uint16   OperatingStatus
+    uint16   PrimaryStatus
+    uint16   EnabledState
+    string   OtherEnabledState
+    uint16   RequestedState
+    uint16   EnabledDefault
+    datetime TimeOfLastStateChange
+    uint16   AvailableRequestedStates[]
+    uint16   TransitioningToState
+    string   CreationClassName
+    string   Name
+    string   PrimaryOwnerName
+    string   PrimaryOwnerContact
+    string   Roles[]
+    string   NameFormat
+    string   OtherIdentifyingInfo[]
+    string   IdentifyingDescriptions[]
+    uint16   Dedicated[]
+    string   OtherDedicatedDescriptions[]
+    uint16   ResetCapability
+    uint16   PowerManagementCapabilities[]
+    uint32   MaxVMQOffloads
+    uint32   MaxIOVOffloads
+end
-- 
2.30.0





More information about the libvir-list mailing list