Назначить vlan сетевому адаптеру с помощью классов wmi

#c# #wmi #hyper-v

#c# #wmi #hyper-v

Вопрос:

Проблема: не удается назначить vlan виртуальной машине hyper-v с помощью Msvm_VirtualEthernetSwitchManagementService и метода AddFeatureSettings.

Может кто-нибудь указать мне, что я делаю не так?

Также я заметил, что если я использую классы WMI для создания vNIC, я не получаю экземпляр Msvm_EthernetPortAllocationSettingData, но если я назначу vNIC вручную, он будет создан.. У меня возникли проблемы с созданием Msvm_EthernetPortAllocationSettingData также через WMI.

Из приведенного ниже кода я получаю возвращаемое значение 4096, что означает, что этот метод был выполнен.. но vlan не была назначена.

             ManagementPath syntheticAdapterSettingDataC = new ManagementPath("Msvm_EthernetSwitchPortVlanSettingData");
            String syntheticVlanAdapterId = String.Format("{0}\C\952C5004-4465-451C-8CB8-FA9AB382B773\{1}", adapter.GetPropertyValue("InstanceID"), Guid.NewGuid());

            ManagementClass syntheticAdapterClassC =
               new ManagementClass(scope, syntheticAdapterSettingDataC, objectOptions)
               {
                   ["AccessVlanId"] = 55,
                   ["Caption"] = "Ethernet Switch Port VLAN Settings",
                   ["Description"] = "Represents the vlan setting data.",
                   ["ElementName"] = "Ethernet Switch Port VLAN Settings",
                   ["InstanceID"] = syntheticVlanAdapterId,
                   ["NativeVlanId"] = 0,
                   ["OperationMode"] = 1,
                   ["PrimaryVlanId"] = 0,
                   ["PruneVlanIdArray"] = null,
                   ["PvlanMode"] = 0,
                   ["SecondaryVlanId"] = 0,
                   ["SecondaryVlanIdArray"] = null,
                   ["TrunkVlanIdArray"] = null,
               };
            var syntheticAdapterC = syntheticAdapterClassC.CreateInstance();

            ManagementPath VirtualEthernetSwitchManagementServicePath= new ManagementPath("Msvm_VirtualEthernetSwitchManagementService");
            ManagementClass VirtualEthernetSwitchManagementServiceClass = new ManagementClass(scope, VirtualEthernetSwitchManagementServicePath, objectOptions);

            ManagementBaseObject inParams = VirtualEthernetSwitchManagementServiceClass.GetMethodParameters("AddFeatureSettings");


            string queryFeature = string.Format("select * from Msvm_FeatureSettingData Where InstanceID = 'Microsoft:Definition\\952C5004-4465-451C-8CB8-FA9AB382B773\\Default'");

            ManagementObjectSearcher searcherFeature = new ManagementObjectSearcher(scope, new ObjectQuery(queryFeature));

            ManagementObjectCollection features = searcherFeature.Get();

            ManagementObject feature = null;

            foreach (ManagementObject instance in features)
            {
                feature = instance;
                break;
            }

            string[] syntheticAdapterSettingsC = new string[1];
            syntheticAdapterSettingsC[0] = syntheticAdapterC.GetText(TextFormat.CimDtd20);



            inParams["AffectedConfiguration"] = feature.GetText(TextFormat.CimDtd20);

            inParams["FeatureSettings"] = syntheticAdapterSettingsC;

            ManagementObject service = null;

            foreach (ManagementObject instance in VirtualEthernetSwitchManagementServiceClass.GetInstances())
            {
                service = instance;
            }

            ManagementBaseObject vlanOut = service.InvokeMethod("AddFeatureSettings", inParams, null);
 

Ответ №1:

После экспериментов я нашел ответ. Что вам нужно сделать, это создать (или указать на один, если он у вас уже есть) экземпляр Msvm_EthernetPortAllocationSettingData с классом Msvm_VirtualSystemManagementService, используя метод «AddResourceSettings».

Чтобы использовать метод «AddResourceSettings», вам необходимо определить :

  • Свойство AffectedConfiguration, которое является экземпляром класса Msvm_VirtualSystemSettingData
  • Свойство ResourceSettings, которое является экземпляром Msvm_EthernetPortAllocationSettingData, но вам нужно поместить этот экземпляр в массив.

Теперь вы готовы назначить vlan. Вам нужно будет создать экземпляр Msvm_EthernetSwitchPortVlanSettingData с классом Msvm_VirtualSystemManagementService и методом «AddFeatureSettings».

Чтобы использовать метод «AddFeatureSettings», вам необходимо определить :

  • Затронутая конфигурация, которая является экземпляром Msvm_EthernetPortAllocationSettingData
  • FeatureSettings , который является экземпляром Msvm_EthernetSwitchPortVlanSettingData, который также является массивом

И это все..

Приветствия!

Ответ №2:

я. знаю, что это довольно старое, но давайте избавим от головной боли других людей, пытающихся это реализовать. Следующий код назначит сетевой адаптер виртуальной машине и установит VLAN. Имейте в виду, что мои _dataFields — это структура с данными виртуальной машины, поэтому здесь вам придется кое-что изменить.

Добавьте новый сетевой адаптер и установите VLAN

     /// <summary>
    /// For the given virtual machine, this sample adds a new Network Adapter device and 
    /// connects it to the specified switch. Note that in order to add a new Network Adapter 
    /// device to the virtual machine, 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.
    /// </summary>
    public void ConnectVmToSwitch()
    {
        using (ManagementObject managementService = WmiUtils.GetVirtualMachineManagementService(_dataFields._scope))

        //
        // Find the Ethernet switch we want to connect to.
        //
        using (ManagementObject ethernetSwitch = NetworkUtils.FindEthernetSwitch(_dataFields.SwitchName, _dataFields._scope))

        //
        // Find the virtual machine we want to connect.
        //
        using (ManagementObject virtualMachine = WmiUtils.GetVirtualMachine(_dataFields.VmName, _dataFields._scope))

        //
        // Get the virtual machine's settings object which is used to make configuration changes.
        //
        using (ManagementObject virtualMachineSettings = WmiUtils.GetVirtualMachineSettings(virtualMachine))

        //
        // Add a new synthetic Network Adapter device to the virtual machine.
        //
        using (ManagementObject syntheticAdapter = NetworkUtils.AddSyntheticAdapter(virtualMachine, _dataFields._scope))

        //
        // Now that we have added a network adapter to the virtual machine we can configure its
        // connection settings.
        //
        using (ManagementObject connectionSettingsToAdd = NetworkUtils.GetDefaultEthernetPortAllocationSettingData(_dataFields._scope))
        {
            connectionSettingsToAdd["Parent"] = syntheticAdapter.Path.Path;
            connectionSettingsToAdd["HostResource"] = new string[] { ethernetSwitch.Path.Path };

            //
            // Now add the connection settings.
            //
            using (ManagementBaseObject addConnectionInParams = managementService.GetMethodParameters("AddResourceSettings"))
            {
                addConnectionInParams["AffectedConfiguration"] = virtualMachineSettings.Path.Path;
                addConnectionInParams["ResourceSettings"] = new string[] { connectionSettingsToAdd.GetText(TextFormat.WmiDtd20) };

                using (ManagementBaseObject addConnectionOutParams = managementService.InvokeMethod("AddResourceSettings", addConnectionInParams, null))
                {
                    WmiUtils.ValidateOutput(addConnectionOutParams, _dataFields._scope);

                    if (_dataFields.VlanID > 0)
                    {
                        string[] syntheticAdapterResult = (string[])addConnectionOutParams["ResultingResourceSettings"]; // Msvm_EthernetPortAllocationSettingData return object
                        string syntheticAdapterPath = syntheticAdapterResult[0]; // Msvm_EthernetPortAllocationSettingData path

                        using (ManagementClass vlanSettingsData = new ManagementClass("Msvm_EthernetSwitchPortVlanSettingData"))
                        {
                            vlanSettingsData.Scope = _dataFields._scope;
                            using (ManagementObject vlanData = vlanSettingsData.CreateInstance())
                            {
                                vlanData["AccessVlanId"] = _dataFields.VlanID;
                                vlanData["OperationMode"] = (uint)_dataFields.VLANOperationalModes;

                                // Modify the VM settings.
                                using (ManagementBaseObject inParams = managementService.GetMethodParameters("AddFeatureSettings"))
                                {
                                    inParams["AffectedConfiguration"] = syntheticAdapterPath;
                                    inParams["FeatureSettings"] = new string[] { vlanData.GetText(TextFormat.CimDtd20) };

                                    using (ManagementBaseObject outParams = managementService.InvokeMethod("AddFeatureSettings", inParams, null))
                                    {
                                        WmiUtils.ValidateOutput(outParams, _dataFields._scope);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
 

Исходный код для назначения коммутатора виртуальной машине взят из https://github.com/microsoft/Windows-classic-samples/blob/1d363ff4bd17d8e20415b92e2ee989d615cc0d91/Samples/Hyper-V/Networking/cs/ConnectVmToSwitch.cs я только что расширил его для поддержки использования VLAN. У меня нет никаких параметров в call, поскольку все данные находятся в struct .

Добавление / изменение VLAN на существующем сетевом адаптере виртуальной машины

     /// <summary>
    /// Gets any virtual machine's management object
    /// </summary>
    /// <param name="managementObject">Any management object</param>
    /// <returns>Any virtual machine's management object.</returns>
    public static ManagementObject
    GetVirtualMachineManagementObject(ManagementObject managementObject, string className)
    {
        using (ManagementObjectCollection settingsCollection = managementObject.GetRelated(className))
        {
            ManagementObject virtualMachineSettings = GetFirstObjectFromCollection(settingsCollection);
            return virtualMachineSettings;
        }
    }

    /// <summary>
    /// For the given virtual machine, this sample will add / modfiy VLAN on existing network adapter
    /// </summary>
    public void SetVLANToVMNetworkAdapter()
    {
        ManagementObject syntheticAdapter = null;
        bool vlanAlreadySet = false;

        using (ManagementObject managementService = WmiUtils.GetVirtualMachineManagementService(_dataFields._scope))

        //
        // Find the virtual machine we want to connect.
        //
        using (ManagementObject virtualMachine = WmiUtils.GetVirtualMachine(_dataFields.VmName, _dataFields._scope))

        //
        // Now that we have added a network adapter to the virtual machine we can configure its
        // connection settings.
        //
        using (ManagementObjectCollection findConnections = NetworkUtils.FindConnections(virtualMachine, _dataFields._scope))
        {
            if (findConnections.Count > 0)
            {
                foreach (ManagementObject connection in findConnections)
                {
                    using (ManagementObjectCollection vmSwitches = connection.GetRelated("Msvm_SyntheticEthernetPortSettingData"))
                    {
                        if (vmSwitches.Count > 0)
                        {
                            foreach (ManagementObject vmSwitch in vmSwitches)
                            {
                                if (vmSwitch["ElementName"].ToString() == _dataFields.NetworkAdapterName)
                                {
                                    //
                                    // Got adapter on VM, lock it to connection object since we need connection path
                                    // for vlan modifications
                                    //
                                    syntheticAdapter = connection;

                                    //
                                    // Got VLAN defiinition based on connection lock for vlan modifications
                                    //
                                    using (ManagementObjectCollection vmSwitcheVLANs = syntheticAdapter.GetRelated("Msvm_EthernetSwitchPortVlanSettingData"))
                                    {
                                        if (vmSwitcheVLANs.Count > 0)
                                            vlanAlreadySet = true;
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            if (syntheticAdapter != null amp;amp; _dataFields.VlanID > 0)
            {
                string syntheticAdapterPath = syntheticAdapter.Path.Path;
                if (vlanAlreadySet)
                {
                    // VLAN is already set on adapter, change operation
                    // Modify the VM settings.
                    using (ManagementObject vlanData = WmiUtils.GetVirtualMachineManagementObject(syntheticAdapter, "Msvm_EthernetSwitchPortVlanSettingData"))
                    {
                        vlanData["AccessVlanId"] = _dataFields.VlanID;
                        vlanData["OperationMode"] = (uint)_dataFields.VLANOperationalModes;
                        using (ManagementBaseObject inParams = managementService.GetMethodParameters("ModifyFeatureSettings"))
                        {
                            inParams["FeatureSettings"] = new string[] { vlanData.GetText(TextFormat.CimDtd20) };
                            using (ManagementBaseObject outParams = managementService.InvokeMethod("ModifyFeatureSettings", inParams, null))
                            {
                                WmiUtils.ValidateOutput(outParams, _dataFields._scope);
                            }
                        }
                    }
                }
                else
                {
                    using (ManagementClass vlanSettingsData = new ManagementClass("Msvm_EthernetSwitchPortVlanSettingData"))
                    {
                        vlanSettingsData.Scope = _dataFields._scope;
                        using (ManagementObject vlanData = vlanSettingsData.CreateInstance())
                        {
                            vlanData["AccessVlanId"] = _dataFields.VlanID;
                            vlanData["OperationMode"] = (uint)_dataFields.VLANOperationalModes;

                            using (ManagementBaseObject inParams = managementService.GetMethodParameters("AddFeatureSettings"))
                            {
                                inParams["AffectedConfiguration"] = syntheticAdapterPath;
                                inParams["FeatureSettings"] = new string[] { vlanData.GetText(TextFormat.CimDtd20) };

                                using (ManagementBaseObject outParams = managementService.InvokeMethod("AddFeatureSettings", inParams, null))
                                {
                                    WmiUtils.ValidateOutput(outParams, _dataFields._scope);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
 

Удалить VLAN из сетевого адаптера на виртуальной машине

     /// <summary>
    /// For the given virtual machine, this sample will delete VLAN on existing network adapter 
    /// </summary>
    public void RemoveVLANFromVMNetworkAdapter()
    {
        using (ManagementObject managementService = WmiUtils.GetVirtualMachineManagementService(_dataFields._scope))

        //
        // Find the virtual machine we want to connect.
        //
        using (ManagementObject virtualMachine = WmiUtils.GetVirtualMachine(_dataFields.VmName, _dataFields._scope))

        //
        // Now that we have added a network adapter to the virtual machine we can configure its
        // connection settings.
        //
        using (ManagementObjectCollection findConnections = NetworkUtils.FindConnections(virtualMachine, _dataFields._scope))
        {
            if (findConnections.Count > 0)
            {
                foreach (ManagementObject connection in findConnections)
                {
                    // Get network adapter on virtual machine
                    using (ManagementObjectCollection vmSwitches = connection.GetRelated("Msvm_SyntheticEthernetPortSettingData"))
                    {
                        if (vmSwitches.Count > 0)
                        {
                            foreach (ManagementObject vmSwitch in vmSwitches)
                            {
                                if (vmSwitch["ElementName"].ToString() == _dataFields.NetworkAdapterName)
                                {
                                    // Get vlan settings data from network adapter
                                    using (ManagementObjectCollection vmSwitcheVLANs = connection.GetRelated("Msvm_EthernetSwitchPortVlanSettingData"))
                                    {
                                        if (vmSwitcheVLANs.Count > 0)
                                        {
                                            // Get first objecz
                                            using (ManagementObject vlanData = WmiUtils.GetFirstObjectFromCollection(vmSwitcheVLANs))
                                            {
                                                using (ManagementBaseObject inParams = managementService.GetMethodParameters("RemoveFeatureSettings"))
                                                {
                                                    // Remove it
                                                    inParams["FeatureSettings"] = new string[] { vlanData.Path.Path };
                                                    using (ManagementBaseObject outParams = managementService.InvokeMethod("RemoveFeatureSettings", inParams, null))
                                                    {
                                                        WmiUtils.ValidateOutput(outParams, _dataFields._scope);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
 

Имейте в виду, я не использую общее имя сетевого адаптера, я использую персонализированные при создании виртуальной машины. Таким образом, я могу легко получить данные адаптера, когда это необходимо.

Те, кто хочет добавить персонализированные имена для адаптеров, могут отредактировать функцию AddSyntheticAdapter(ManagementObject VirtualMachine, ManagementScope scope) и включить другое имя в объект adapterToAdd[«ElementName»].

Надеюсь, это поможет смельчакам, которые разрабатывают через WMI! 🙂