// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft. All rights reserved. namespace Microsoft.Samples.HyperV.Networking { using System; using System.Management; using System.Globalization; using System.Collections.Generic; using Microsoft.Samples.HyperV.Common; static class NetworkingUtilities { /// /// Advanced port feature type. /// internal enum PortFeatureType { Unknown, Acl, Bandwidth, Offload, Profile, Security, Vlan } /// /// Advanced switch feature type. /// internal enum SwitchFeatureType { Unknown, Bandwidth } /// /// Gets the Msvm_VirtualEthernetSwitchManagementService object. /// /// The scope to use when connecting to WMI. /// The switch management service object. internal static ManagementObject GetEthernetSwitchManagementService( ManagementScope scope) { using (ManagementClass switchServiceClass = new ManagementClass("Msvm_VirtualEthernetSwitchManagementService")) { switchServiceClass.Scope = scope; ManagementObject switchService = WmiUtilities.GetFirstObjectFromCollection( switchServiceClass.GetInstances()); return switchService; } } /// /// Finds the ethernet switch with the specified name. /// /// The name of the switch to find. /// The scope to use when connecting to WMI. /// The ethernet switch object. internal static ManagementObject FindEthernetSwitch( string switchName, ManagementScope scope) { ObjectQuery query = new ObjectQuery(string.Format(CultureInfo.InvariantCulture, "select * from Msvm_VirtualEthernetSwitch where ElementName = \"{0}\"", switchName)); using (ManagementObjectSearcher queryExecute = new ManagementObjectSearcher(scope, query)) using (ManagementObjectCollection queryResults = queryExecute.Get()) { if (queryResults.Count == 0) { throw new ManagementException("There is no switch with name: " + switchName); } return WmiUtilities.GetFirstObjectFromCollection(queryResults); } } /// /// Finds the external adapter with the specified name. /// /// The name of the external adapter. /// The scope to use when connecting to WMI. /// The external adapter. internal static ManagementObject FindExternalAdapter( string externalAdapterName, ManagementScope scope) { ObjectQuery externalAdapterQuery = new ObjectQuery(string.Format(CultureInfo.InvariantCulture, "select * from Msvm_ExternalEthernetPort where Name=\"{0}\"", externalAdapterName)); using (ManagementObjectSearcher externalAdapterExecute = new ManagementObjectSearcher(scope, externalAdapterQuery)) using (ManagementObjectCollection externalAdapterCollection = externalAdapterExecute.Get()) { if (externalAdapterCollection.Count == 0) { throw new ManagementException("There is no external adapter with the name: " + externalAdapterName); } return WmiUtilities.GetFirstObjectFromCollection(externalAdapterCollection); } } /// /// Gets the default connection settings object to use when adding new connection settings. /// /// The scope to use when connecting to WMI. /// The default connection object. internal static ManagementObject GetDefaultEthernetPortAllocationSettingData( ManagementScope scope) { // // First get the resource pool for ethernet connection objects. // ObjectQuery query = new ObjectQuery("select * from Msvm_ResourcePool where ResourceType = 33 and Primordial = True"); using (ManagementObjectSearcher queryExecute = new ManagementObjectSearcher(scope, query)) using (ManagementObject resourcePool = WmiUtilities.GetFirstObjectFromCollection(queryExecute.Get())) { return GetDefaultObjectFromResourcePool(resourcePool, scope); } } /// /// Gets the default synthetic adapter settings object to use when adding a new adapter /// to a virtual machine. /// /// The scope to use when connecting to WMI. /// The default synthetic adapter. internal static ManagementObject GetDefaultSyntheticAdapter( ManagementScope scope) { ObjectQuery query = new ObjectQuery("select * from Msvm_ResourcePool where " + "ResourceSubType = 'Microsoft:Hyper-V:Synthetic Ethernet Port' and Primordial = True"); using (ManagementObjectSearcher queryExecute = new ManagementObjectSearcher(scope, query)) using (ManagementObject resourcePool = WmiUtilities.GetFirstObjectFromCollection(queryExecute.Get())) { return GetDefaultObjectFromResourcePool(resourcePool, scope); } } /// /// Gets the unique ID corresponding to the given port feature type. /// /// An enumeration value representing the desired port feature type. /// The unique ID of the feature. internal static string GetPortFeatureId( PortFeatureType featureType) { string featureId; switch (featureType) { case PortFeatureType.Acl: featureId = "998BEF4A-5D55-492A-9C43-8B2F5EAE9F2B"; break; case PortFeatureType.Bandwidth: featureId = "24AD3CE1-69BD-4978-B2AC-DAAD389D699C"; break; case PortFeatureType.Offload: featureId = "C885BFD1-ABB7-418F-8163-9F379C9F7166"; break; case PortFeatureType.Profile: featureId = "9940CD46-8B06-43BB-B9D5-93D50381FD56"; break; case PortFeatureType.Security: featureId = "776E0BA7-94A1-41C8-8F28-951F524251B5"; break; case PortFeatureType.Vlan: featureId = "952C5004-4465-451C-8CB8-FA9AB382B773"; break; default: throw new ManagementException("The given port feature type is unrecognized."); } return featureId; } /// /// Gets the unique ID corresponding to the given switch feature type. /// /// An enumeration value representing the desired switch feature type. /// The unique ID of the feature. internal static string GetSwitchFeatureId( SwitchFeatureType featureType) { string featureId; switch (featureType) { case SwitchFeatureType.Bandwidth: featureId = "3EB2B8E8-4ABF-4DBF-9071-16DD47481FBE"; break; default: throw new ManagementException("The given switch feature type is unrecognized."); } return featureId; } /// /// Finds the default feature setting object for the specified feature. /// /// The unique identifier of the feature. /// The scope to use when connecting to WMI. /// The default settings for the feature. internal static ManagementObject GetDefaultFeatureSetting( string featureId, ManagementScope scope) { // // Iterate through all features to find the requested feature, then follow the association // to retrieve the default feature setting data for that feature. // string defaultFeatureSettingPath = null; // // Find the features enabled on the switch. // using (ManagementClass featureCapabilitiesClass = new ManagementClass("Msvm_EthernetSwitchFeatureCapabilities")) { featureCapabilitiesClass.Scope = scope; using (ManagementObjectCollection featureCapabilitiesCollection = featureCapabilitiesClass.GetInstances()) foreach (ManagementObject featureCapabilities in featureCapabilitiesCollection) using (featureCapabilities) { // // Find the feature capabilities object for the specified feature by examining the // feature's unique identifier. // if (string.Equals((string)featureCapabilities["FeatureId"], featureId, StringComparison.OrdinalIgnoreCase)) { // // Follow the associations from the feature capabilities object to obtain a copy of the // default feature setting data object. // using (ManagementObjectCollection featureSettingAssociationCollection = featureCapabilities.GetRelationships("Msvm_FeatureSettingsDefineCapabilities")) foreach (ManagementObject featureSettingAssociation in featureSettingAssociationCollection) using (featureSettingAssociation) { if ((ushort)featureSettingAssociation["ValueRole"] == 0) { // // We found the default feature setting association, and its PartComponent // property is the path to the default feature setting. // defaultFeatureSettingPath = (string)featureSettingAssociation["PartComponent"]; break; } } break; } } } if (defaultFeatureSettingPath == null) { throw new ManagementException("Unable to find the default feature settings!"); } ManagementObject defaultFeatureSetting = new ManagementObject(defaultFeatureSettingPath); defaultFeatureSetting.Scope = scope; defaultFeatureSetting.Get(); return defaultFeatureSetting; } /// /// Adds a new synthetic Network Adapter device to the virtual machine. Note that the virtual /// machine must be in the power off state. Also note that the maximum number of Network /// Adapter devices that may be configured on a virtual machine is 8. /// /// The name of the virtual machine. /// The scope to use when connecting to WMI. /// The newly added synthetic adapter. internal static ManagementObject AddSyntheticAdapter( ManagementObject virtualMachine, ManagementScope scope) { using (ManagementObject managementService = WmiUtilities.GetVirtualMachineManagementService(scope)) using (ManagementObject virtualMachineSettings = WmiUtilities.GetVirtualMachineSettings(virtualMachine)) // // Get the default Synthetic Adapter object, then modify its properties. // using (ManagementObject adapterToAdd = GetDefaultSyntheticAdapter(scope)) { adapterToAdd["VirtualSystemIdentifiers"] = new string[] { Guid.NewGuid().ToString("B") }; adapterToAdd["ElementName"] = "Network Adapter"; adapterToAdd["StaticMacAddress"] = false; // // Now add it to the virtual machine. // using (ManagementBaseObject addAdapterInParams = managementService.GetMethodParameters("AddResourceSettings")) { addAdapterInParams["AffectedConfiguration"] = virtualMachineSettings.Path.Path; addAdapterInParams["ResourceSettings"] = new string[] { adapterToAdd.GetText(TextFormat.WmiDtd20) }; using (ManagementBaseObject addAdapterOutParams = managementService.InvokeMethod("AddResourceSettings", addAdapterInParams, null)) { WmiUtilities.ValidateOutput(addAdapterOutParams, scope); // // Get the created network adapter from the output parameters. // ManagementObject addedAdapter; if (addAdapterOutParams["ResultingResourceSettings"] != null) { addedAdapter = new ManagementObject( ((string[])addAdapterOutParams["ResultingResourceSettings"])[0]); addedAdapter.Get(); } else { using (ManagementObject job = new ManagementObject((string)addAdapterOutParams["Job"])) { addedAdapter = WmiUtilities.GetFirstObjectFromCollection(job.GetRelated(null, "Msvm_AffectedJobElement", null, null, null, null, false, null)); } } return addedAdapter; } } } } /// /// Finds all connections of the virtual machine. /// /// The virtual machine. /// The scope to use when connecting to WMI. /// The virtual machine's connection objects. internal static ManagementObjectCollection FindConnections( ManagementObject virtualMachine, ManagementScope scope) { using (ManagementObject virtualMachineSettings = WmiUtilities.GetVirtualMachineSettings(virtualMachine)) { return virtualMachineSettings.GetRelated("Msvm_EthernetPortAllocationSettingData", "Msvm_VirtualSystemSettingDataComponent", null, null, null, null, false, null); } } /// /// Finds any connections of the virtual machine that are connected to the specified switch. /// This includes connections that are configured with a hard-affinity to the specified /// switch as well as connections that are configured to dynamically connect to a switch /// and are currently connected to the specified switch. /// /// The virtual machine. /// The switch to find connections for. /// The scope to use when connecting to WMI. /// The list of the virtual machine's connection objects that are either configured /// to connect to the switch, or are currently connected to the switch. internal static IList FindConnectionsToSwitch( ManagementObject virtualMachine, ManagementObject ethernetSwitch, ManagementScope scope) { List connectionsToSwitch = new List(); // // Get all connection objects for the virtual machine, then filter those that are connected // to the switch. // using (ManagementObjectCollection connectionCollection = FindConnections(virtualMachine, scope)) foreach (ManagementObject connection in connectionCollection) { // // Determine whether this connection has a hard affinity to the switch. // string[] hostResource = (string[])connection["HostResource"]; if (hostResource != null && hostResource.Length > 0 && string.Equals(hostResource[0], ethernetSwitch.Path.Path, StringComparison.OrdinalIgnoreCase)) { // // This connection is set to always connect to this switch. // connectionsToSwitch.Add(connection); continue; } // // If the connection does not have a hard affinity to this switch, it could // still be currently connected to this switch if it is configured to dynamically // connect to a switch and the virtual machine has been started. // using (ManagementObjectCollection connectedPortCollection = connection.GetRelated("Msvm_EthernetSwitchPort", "Msvm_ElementSettingData", null, null, null, null, false, null)) { if (connectedPortCollection.Count > 0) { using (ManagementObject connectedPort = WmiUtilities.GetFirstObjectFromCollection(connectedPortCollection)) { if (string.Equals((string)connectedPort["SystemName"], (string)ethernetSwitch["Name"], StringComparison.OrdinalIgnoreCase)) { // // This connection was configured to dynamically connect to a switch when // the virtual machine was started and is currently connected to the switch // we want to disconnect from. // connectionsToSwitch.Add(connection); } else { connection.Dispose(); } } } } } if (connectionsToSwitch.Count == 0) { throw new ManagementException(string.Format(CultureInfo.CurrentCulture, "The virtual machine '{0}' is not connected to the switch '{1}'.", virtualMachine["ElementName"], ethernetSwitch["ElementName"])); } return connectionsToSwitch; } /// /// Returns a feature capability object that represents the specified switch feature. /// /// The name of the switch feature. /// The scope to use when connecting to WMI. /// The feature capability object that represents the specified feature. internal static ManagementObject FindFeatureByName( string featureName, ManagementScope scope) { ObjectQuery query = new ObjectQuery(string.Format( CultureInfo.InvariantCulture, "select * from Msvm_EthernetSwitchFeatureCapabilities where ElementName = \"{0}\"", featureName)); using (ManagementObjectSearcher queryExecute = new ManagementObjectSearcher(scope, query)) using (ManagementObjectCollection queryResults = queryExecute.Get()) { if (queryResults.Count == 0) { throw new ManagementException(string.Format( CultureInfo.CurrentCulture, "Could not find feature '{0}'", featureName)); } return WmiUtilities.GetFirstObjectFromCollection(queryResults); } } /// /// Follows the associations from the resource pool to get the default object for the /// resource type exposed by this resource pool. /// /// The resource pool. /// The scope to use when connecting to WMI. /// The default settings for the resource type managed by this resource pool. public static ManagementObject GetDefaultObjectFromResourcePool( ManagementObject resourcePool, ManagementScope scope) { // // The default object is associated with the Msvm_AllocationCapabilities object that // is associated to the resource pool. // ManagementObject defaultSettingAssociation = null; using (ManagementObjectCollection capabilitiesCollection = resourcePool.GetRelated("Msvm_AllocationCapabilities", "Msvm_ElementCapabilities", null, null, null, null, false, null)) using (ManagementObject capabilities = WmiUtilities.GetFirstObjectFromCollection(capabilitiesCollection)) { foreach (ManagementObject settingAssociation in capabilities.GetRelationships("Msvm_SettingsDefineCapabilities")) { if ((ushort)settingAssociation["ValueRole"] == 0) { defaultSettingAssociation = settingAssociation; break; } else { settingAssociation.Dispose(); } } } if (defaultSettingAssociation == null) { throw new ManagementException("Unable to find the default settings!"); } string defaultSettingPath = (string)defaultSettingAssociation["PartComponent"]; defaultSettingAssociation.Dispose(); ManagementObject defaultSetting = new ManagementObject(defaultSettingPath); defaultSetting.Scope = scope; defaultSetting.Get(); return defaultSetting; } } }