Hi Alin! Please see my inlined comments. Other than those comments this patch looks good.
Acked-by: Paul-Daniel Boca <pb...@cloudbasesolutions.com> Tested-by: Paul-Daniel Boca <pb...@cloudbasesolutions.com> Regards, Paul > -----Original Message----- > From: dev [mailto:dev-boun...@openvswitch.org] On Behalf Of Alin Serdean > Sent: Tuesday, May 10, 2016 3:03 AM > To: dev@openvswitch.org > Subject: [ovs-dev] [PATCH 1/4] windows: Add internal switch port per OVS > bridge > > This patch updates the following commands in the vswitch: > ovs-vsctl add-br br-test > ovs-vsctl del-br br-test > > ovs-vsctl add-br br-test: > This command will now create an internal port on the MSFT virtual switch > using the WMI interface from > Msvm_VirtualEthernetSwitchManagementService > leveraging the method AddResourceSettings. > Before creating the actual port, the switch will be queried to see if > there > is not a port already created (good for restarts when restarting the > vswitch daemon). If there is a port defined it will return success and log > a message. > After checking if the port already exists the command will also verify > if the forwarding extension (windows datapath) is enabled and on a single > switch. If it is not activated or if it is activated on multiple switches > it will return an error and a message will be logged. > After the port was created on the switch, we will disable the adapter on > the host and rename to the corresponding OVS bridge name for > consistency. > The user will enable and set the values he wants after creation. > > ovs-vsctl del-br br-test > This command will remove an internal port on the MSFT virtual switch > using the Msvm_VirtualEthernetSwitchManagementService class and > executing > the method RemoveResourceSettings. > > Both commands will be blocking until the WMI job is finished, this allows us > to guarantee that the ports are created and their name are set before issuing > a netlink message to the windows datapath. > > This patch also includes helpers for normal WMI retrievals and > initializations. > Appveyor and documentation has been modified to include the libraries > needed > for COM objects. > > This patch was tested individually using IMallocSpy and CRT heap checks > to ensure no new memory leaks are introduced. > > Tested on the following OS's: > Windows 2012 and Windows 2012r2 > > Signed-off-by: Alin Gabriel Serdean <aserd...@cloudbasesolutions.com> > --- > INSTALL.Windows.md | 76 ++-- > appveyor.yml | 2 +- > lib/automake.mk | 4 +- > lib/dpif-netlink.c | 25 +- > lib/wmi.c | 1197 > ++++++++++++++++++++++++++++++++++++++++++++++++++++ > lib/wmi.h | 51 +++ > 6 files changed, 1309 insertions(+), 46 deletions(-) > create mode 100644 lib/wmi.c > create mode 100644 lib/wmi.h > > diff --git a/INSTALL.Windows.md b/INSTALL.Windows.md > index 6b0f5d8..f86bf98 100644 > --- a/INSTALL.Windows.md > +++ b/INSTALL.Windows.md > @@ -72,9 +72,9 @@ or from a distribution tar ball. > directories, etc. For example, > > % ./configure CC=./build-aux/cccl LD="`which link`" \ > - LIBS="-lws2_32 -liphlpapi" --prefix="C:/openvswitch/usr" \ > - --localstatedir="C:/openvswitch/var" --sysconfdir="C:/openvswitch/etc" > \ > - --with-pthread="C:/pthread" > + LIBS="-lws2_32 -liphlpapi -lwbemuuid -lole32 -loleaut32" \ > + --prefix="C:/openvswitch/usr" --localstatedir="C:/openvswitch/var" \ > + --sysconfdir="C:/openvswitch/etc" --with-pthread="C:/pthread" > > By default, the above enables compiler optimization for fast code. > For default compiler optimization, pass the "--with-debug" configure > @@ -125,9 +125,10 @@ Note down the directory where OpenSSL is installed > (e.g.: C:/OpenSSL-Win32). > For example, > > % ./configure CC=./build-aux/cccl LD="`which link`" \ > - LIBS="-lws2_32 -liphlpapi" --prefix="C:/openvswitch/usr" \ > - --localstatedir="C:/openvswitch/var" --sysconfdir="C:/openvswitch/etc" \ > - --with-pthread="C:/pthread" --enable-ssl --with-openssl="C:/OpenSSL- > Win32" > + LIBS="-lws2_32 -liphlpapi -lwbemuuid -lole32 -loleaut32" \ > + --prefix="C:/openvswitch/usr" --localstatedir="C:/openvswitch/var" \ > + --sysconfdir="C:/openvswitch/etc" --with-pthread="C:/pthread" \ > + --enable-ssl --with-openssl="C:/OpenSSL-Win32" > > * Run make for the ported executables. > > @@ -142,10 +143,11 @@ level 'make' will invoke building the kernel > datapath, if the > For example, > > % ./configure CC=./build-aux/cccl LD="`which link`" \ > - LIBS="-lws2_32 -liphlpapi" --prefix="C:/openvswitch/usr" \ > - --localstatedir="C:/openvswitch/var" --sysconfdir="C:/openvswitch/etc" \ > - --with-pthread="C:/pthread" --enable-ssl \ > - --with-openssl="C:/OpenSSL-Win32" --with-vstudiotarget="<target type>" > + LIBS="-lws2_32 -liphlpapi -lwbemuuid -lole32 -loleaut32" \ > + --prefix="C:/openvswitch/usr" --localstatedir="C:/openvswitch/var" \ > + --sysconfdir="C:/openvswitch/etc" --with-pthread="C:/pthread" \ > + --enable-ssl --with-openssl="C:/OpenSSL-Win32" \ > + --with-vstudiotarget="<target type>" > > Possible values for "<target type>" are: > "Debug" and "Release" > @@ -180,14 +182,11 @@ during boot. The following commands can be > used: > Note: you may have to restart the machine for the settings to take effect. > > 03> In the Virtual Switch Manager configuration you can enable the Open > vSwitch > -Extension on an existing switch or create a new switch. If you are using an > -existing switch, make sure to enable the "Allow Management OS" option for > VXLAN > -to work (covered later). > +Extension on an existing switch or create a new switch. > > The command to create a new switch named 'OVS-Extended-Switch' using a > physical > NIC named 'Ethernet 1' is: > - % New-VMSwitch "OVS-Extended-Switch" -AllowManagementOS $true \ > - -NetAdapterName "Ethernet 1" > + % New-VMSwitch "OVS-Extended-Switch" -NetAdapterName "Ethernet 1" > > Note: you can obtain the list of physical NICs on the host using > 'Get-NetAdapter' command. > @@ -281,20 +280,20 @@ use that name('Ethernet0') as a special name to > refer to that adapter. > Note: Currently, we assume that the Hyper-V switch on which OVS extension > is > enabled has a single physical NIC connected to it. > > -Internal port is the virtual adapter created on the Hyper-V switch using the > -'AllowManagementOS' setting. This has already been setup while creating > the > -switch using the instructions above. In OVS for Hyper-V, we use a the name > of > -that specific adapter as a special name to refer to that adapter. By default > it > -is created under the following rule "vEthernet (<name of the switch>)". > +Internal ports are the virtual adapters created on the Hyper-V switch using > the > +ovs-vsctl add-br <bridge> command. By default they are created under the > +following rule "<name of bridge>" and the adapters are disabled. One > needs to > +enable them and set the corresponding values to it to make them IP-able. > > As a whole example, if we issue the following in a powershell console: > -PS C:\package\binaries> Get-NetAdapter | select > Name,MacAddress,InterfaceDescription > +PS C:\package\binaries> Get-NetAdapter | select Name,InterfaceDescription > > -Name MacAddress InterfaceDescription > ----- ---------- -------------------- > -Ethernet1 00-0C-29-94-05-65 Intel(R) PRO/1000 MT Network > Connection > -vEthernet (external) 00-0C-29-94-05-5B Hyper-V Virtual Ethernet Adapter > #2 > -Ethernet0 00-0C-29-94-05-5B Intel(R) PRO/1000 MT Network > Connection #2 > +Name InterfaceDescription > +---- -------------------- > +Ethernet1 Intel(R) PRO/1000 MT Network Connection > +br-pif Hyper-V Virtual Ethernet Adapter #2 > +Ethernet0 Intel(R) PRO/1000 MT Network Connection #2 > +br-int Hyper-V Virtual Ethernet Adapter #3 > > PS C:\package\binaries> Get-VMSwitch > > @@ -303,12 +302,11 @@ Name SwitchType > NetAdapterInterfaceDescription > external External Intel(R) PRO/1000 MT Network Connection #2 > > > -We can see that we have a switch(external) created upon adapter name > 'Ethernet0' > -with an internal port under name 'vEthernet (external)'. Thus resulting into > the > -following ovs-vsctl commands > +We can see that we have a switch(external) created upon adapter name > +'Ethernet0' with the internal ports under name 'br-pif' and 'br-int'. Thus > +resulting into the following ovs-vsctl commands > > % ovs-vsctl add-port br-pif Ethernet0 > - % ovs-vsctl add-port br-pif "vEthernet (external)" > > * Dumping the ports should show the additional ports that were just added. > Sample output shows up as follows: > @@ -317,18 +315,17 @@ following ovs-vsctl commands > system@ovs-system: > lookups: hit:0 missed:0 lost:0 > flows: 0 > - port 4: vEthernet (external) (internal) <<< 'AllowManagementOS' > - adapter on > - Hyper-V switch > - port 2: br-pif (internal) > - port 1: br-int (internal) > + port 2: br-pif (internal) <<< internal port > + adapter on > + Hyper-V switch > + port 1: br-int (internal) <<< internal port > + adapter on > + Hyper-V switch > port 3: Ethernet0 <<< Physical NIC > > % ovs-vsctl show > a56ec7b5-5b1f-49ec-a795-79f6eb63228b > Bridge br-pif > - Port "vEthernet (external)" > - Interface "vEthernet (external)" > Port br-pif > Interface br-pif > type: internal > @@ -374,8 +371,7 @@ with OVS extension enabled. > system@ovs-system: > lookups: hit:0 missed:0 lost:0 > flows: 0 > - port 4: vEthernet (external) (internal) > - port 5: ovs-port-a > + port 4: ovs-port-a > port 2: br-pif (internal) > port 1: br-int (internal > port 3: Ethernet0 > @@ -383,8 +379,6 @@ with OVS extension enabled. > % ovs-vsctl show > 4cd86499-74df-48bd-a64d-8d115b12a9f2 > Bridge br-pif > - Port "vEthernet (external)" > - Interface "vEthernet (external)" > Port "Ethernet0" > Interface "Ethernet0" > Port br-pif > diff --git a/appveyor.yml b/appveyor.yml > index 422c4af..a152d1e 100644 > --- a/appveyor.yml > +++ b/appveyor.yml > @@ -41,5 +41,5 @@ build_script: > - C:\MinGW\msys\1.0\bin\bash -lc "cp /c/pthreads-win32/Pre- > built.2/dll/x86/*.dll /c/openvswitch/." > - C:\MinGW\msys\1.0\bin\bash -lc "mv /bin/link.exe /bin/link_copy.exe" > - C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./boot.sh" > -- C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./configure > CC=build-aux/cccl LD=\"`which link`\" LIBS=\"-lws2_32 -liphlpapi\" --with- > pthread=C:/pthreads-win32/Pre-built.2 --with-openssl=C:/OpenSSL-Win32 -- > with-vstudiotarget=\"Debug\"" > +- C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./configure > CC=build-aux/cccl LD=\"`which link`\" LIBS=\"-lws2_32 -liphlpapi -lwbemuuid > -lole32 -loleaut32\" --with-pthread=C:/pthreads-win32/Pre-built.2 --with- > openssl=C:/OpenSSL-Win32 --with-vstudiotarget=\"Debug\"" > - C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && make" > diff --git a/lib/automake.mk b/lib/automake.mk > index affbb5c..80369f2 100644 > --- a/lib/automake.mk > +++ b/lib/automake.mk > @@ -369,7 +369,9 @@ lib_libopenvswitch_la_SOURCES += \ > lib/netlink-notifier.h \ > lib/netlink-protocol.h \ > lib/netlink-socket.c \ > - lib/netlink-socket.h > + lib/netlink-socket.h \ > + lib/wmi.c \ > + lib/wmi.h > endif > > if HAVE_POSIX_AIO > diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c > index 015ba20..bcce709 100644 > --- a/lib/dpif-netlink.c > +++ b/lib/dpif-netlink.c > @@ -58,6 +58,7 @@ > > VLOG_DEFINE_THIS_MODULE(dpif_netlink); > #ifdef _WIN32 > +#include "wmi.h" > enum { WINDOWS = 1 }; > #else > enum { WINDOWS = 0 }; > @@ -848,7 +849,15 @@ dpif_netlink_port_add__(struct dpif_netlink *dpif, > struct netdev *netdev, > netdev_linux_ethtool_set_flag(netdev, ETH_FLAG_LRO, "LRO", false); > #endif > } > - > +#ifdef _WIN32 > + if (request.type == OVS_VPORT_TYPE_INTERNAL) { > + if (!create_wmi_port(name)){ > + VLOG_ERR("Could not create wmi internal port with name:%s", > name); > + vport_del_socksp(dpif, socksp); > + return EINVAL; > + }; > + } > +#endif > tnl_cfg = netdev_get_tunnel_config(netdev); > if (tnl_cfg && (tnl_cfg->dst_port != 0 || tnl_cfg->exts)) { > ofpbuf_use_stack(&options, options_stub, sizeof options_stub); > @@ -940,6 +949,16 @@ dpif_netlink_port_del__(struct dpif_netlink *dpif, > odp_port_t port_no) > vport.cmd = OVS_VPORT_CMD_DEL; > vport.dp_ifindex = dpif->dp_ifindex; > vport.port_no = port_no; > +#ifdef _WIN32 > + struct dpif_port temp_dpif_port; > + dpif_netlink_port_query__(dpif, port_no, NULL, &temp_dpif_port); > + if (!strcmp(temp_dpif_port.type, "internal")) { > + if (!delete_wmi_port(temp_dpif_port.name)){ > + VLOG_ERR("Could not delete wmi port with name: %s", > + temp_dpif_port.name); > + }; > + } > +#endif > error = dpif_netlink_vport_transact(&vport, NULL, NULL); > > vport_del_channels(dpif, port_no); > @@ -2442,7 +2461,7 @@ dpif_netlink_is_internal_device(const char *name) > > return reply.type == OVS_VPORT_TYPE_INTERNAL; > } > - > > + > /* Parses the contents of 'buf', which contains a "struct ovs_header" > followed > * by Netlink attributes, into 'vport'. Returns 0 if successful, otherwise a > * positive errno value. > @@ -2946,7 +2965,7 @@ dpif_netlink_flow_get_stats(const struct > dpif_netlink_flow *flow, > stats->used = flow->used ? get_32aligned_u64(flow->used) : 0; > stats->tcp_flags = flow->tcp_flags ? *flow->tcp_flags : 0; > } > - > > + > /* Logs information about a packet that was recently lost in 'ch' (in > * 'dpif_'). */ > static void > diff --git a/lib/wmi.c b/lib/wmi.c > new file mode 100644 > index 0000000..736c424 > --- /dev/null > +++ b/lib/wmi.c > @@ -0,0 +1,1197 @@ > +/* > + * Copyright (c) 2016 Cloudbase Solutions Srl > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#include <config.h> > +#include "wmi.h" > +#include <stdlib.h> > +#include <stdio.h> > +#include <tchar.h> > +#include <Windows.h> > +#include "openvswitch/vlog.h" > + > +VLOG_DEFINE_THIS_MODULE(wmi); > + > +/* WMI Job values */ > +enum JobState > +{ > + starting = 3, > + running = 4, > + completed = 7, > + wait = 4096 > +}; > + > +/* This function will output the appropriate message for a given HRESULT */ > +void > +get_hres_error(HRESULT hres) > +{ > + char *error_msg = NULL; > + > + if (FACILITY_WINDOWS == HRESULT_FACILITY(hres)) { > + hres = HRESULT_CODE(hres); > + } > + > + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | > + FORMAT_MESSAGE_FROM_SYSTEM, > + NULL, hres, 0, error_msg, 0, NULL) != 0) { > + VLOG_WARN("%s", error_msg); > + LocalFree(error_msg); > + } else { > + VLOG_WARN("Could not find HRESULT description for: %#x.", hres); > + } > + > + return; > +} > + > +boolean > +check_return_value(HRESULT hres) > +{ > + if (FAILED(hres)) { > + get_hres_error(hres); > + return false; > + } > + > + return true; > +} > + > +/* This function retrieves the UINT16 value from a given class object with > + * the field name field_name */ > +uint16_t > +get_uint16_t_value(IWbemClassObject* pcls_obj, wchar_t* field_name) > +{ > + uint16_t retval = 0; > + > + VARIANT vt_prop; > + VariantInit(&vt_prop); > + HRESULT hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, &vt_prop, > + 0, 0); > + retval = V_UI2(&vt_prop); > + VariantClear(&vt_prop); > + check_return_value(hres); > + > + return retval; > +} > + > +/* This function retrieves the UINT values from a given class object with > + * the field name field_name */ > +unsigned int > +get_uint_value(IWbemClassObject* pcls_obj, wchar_t* field_name) > +{ > + unsigned retval = 0; > + > + VARIANT vt_prop; > + VariantInit(&vt_prop); > + HRESULT hres = pcls_obj->lpVtbl->Get(pcls_obj,field_name, 0, &vt_prop, > + 0, 0); > + retval = V_UI4(&vt_prop); > + VariantClear(&vt_prop); > + check_return_value(hres); > + > + return retval; > +} > + > +/* This function retrieves the unsigned short value from a given class object > + * with the field name field_name */ > +unsigned short > +get_ushort_value(IWbemClassObject* pcls_obj, wchar_t* field_name) > +{ > + unsigned short retval = 0; > + > + VARIANT vt_prop; > + VariantInit(&vt_prop); > + HRESULT hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, &vt_prop, > + 0, 0); > + retval = V_UI2(&vt_prop); > + VariantClear(&vt_prop); > + check_return_value(hres); > + > + return retval; > +} > + > +/* This function retrieves the BSTR value from a given class object with > + * the field name field_name to a preallocated destination dest and with the > + * maximum length max_dest_lgth */ > +void > +get_str_value(IWbemClassObject* pcls_obj, wchar_t* field_name, wchar_t* > dest, > + int max_dest_lgth) > +{ > + VARIANT vt_prop; > + VariantInit(&vt_prop); > + > + HRESULT hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, &vt_prop, > + 0, 0); > + [Paul Boca] dest field should be set to "" in case wcscpy_s fails and get_str_value should return an error code > + wcscpy_s(dest, max_dest_lgth, vt_prop.bstrVal); > + > + VariantClear(&vt_prop); > + check_return_value(hres); > + > + return; > +} > + > +/* This function waits for a WMI job to finish and retrieves the error code > + * if the job failed */ > +HRESULT > +wait_for_job(IWbemServices* psvc, wchar_t* job_path) > +{ > + IWbemClassObject* pcls_obj = NULL; > + HRESULT retval = 0; > + uint16_t job_state = 0; > + uint16_t error = 0; > + > + do { > + check_return_value(psvc->lpVtbl->GetObject(psvc, job_path, 0, NULL, > + &pcls_obj, NULL)); > + > + job_state = get_uint16_t_value(pcls_obj, L"JobState"); > + > + > + if (job_state == starting || job_state == running) { > + Sleep(200); > + } else if (job_state == completed) { > + break; > + } else { > + /* Error occurred */ > + error = get_uint16_t_value(pcls_obj, L"ErrorCode"); > + VLOG_WARN("Job failed with error: %d", error); > + retval = error; > + break; > + } > + > + if (pcls_obj != NULL) { > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + } > + } while(TRUE); > + > + if (pcls_obj != NULL) { > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + } > + > + return retval; > +} > + > +/* This function will initialize DCOM retrieving the WMI locator's ploc and > + * the context associated to it */ > +boolean > +initialize_wmi(IWbemLocator** ploc, IWbemContext** pcontext) > +{ > + HRESULT hres = 0; > + > + /* Initialize COM */ > + hres = CoInitialize(NULL); > + > + if (FAILED(hres)) { > + return false; > + } > + > + /* Initialize COM security */ > + hres = CoInitializeSecurity(NULL, > + -1, > + NULL, > + NULL, > + RPC_C_AUTHN_LEVEL_DEFAULT, > + RPC_C_IMP_LEVEL_IMPERSONATE, > + NULL, > + EOAC_NONE, > + NULL); > + > + if (FAILED(hres)) { > + return false; > + } > + > + /* Fill context */ > + hres = CoCreateInstance(&CLSID_WbemContext, > + NULL, > + CLSCTX_INPROC_SERVER, > + &IID_IWbemContext, > + (void**)pcontext); > + > + if (FAILED(hres)) { > + return false; > + } > + > + fill_context(*pcontext); > + > + /* Initialize locator's (ploc) to WMI */ > + hres = CoCreateInstance(&CLSID_WbemLocator, > + NULL, > + CLSCTX_INPROC_SERVER, > + &IID_IWbemLocator, > + (LPVOID *)ploc); > + > + if (FAILED(hres)) { > + return false; > + } > + > + return true; > +} > + > +/* This function connects the WMI locator's ploc to a given WMI provider > + * defined in server and also sets the required security levels for a local > + * connection to it */ > +boolean > +connect_set_security(IWbemLocator* ploc, IWbemContext* pcontext, > + wchar_t* server, IWbemServices** psvc) > +{ > + HRESULT hres = 0; > + > + /* Connect to server */ > + hres = ploc->lpVtbl->ConnectServer(ploc, > + server, > + NULL, > + NULL, > + 0, > + 0, > + 0, > + pcontext, > + psvc); > + > + if (FAILED(hres)) { > + return false; > + } > + > + /* Set security levels */ > + hres = CoSetProxyBlanket((IUnknown *) *psvc, > + RPC_C_AUTHN_WINNT, > + RPC_C_AUTHZ_NONE, > + NULL, > + RPC_C_AUTHN_LEVEL_CALL, > + RPC_C_IMP_LEVEL_IMPERSONATE, > + NULL, > + EOAC_NONE); > + > + if (FAILED(hres)) { > + return false; > + } > + > + return true; > +} > + > +/* This function retrieves the first class object of a given enumeration > + * outputted by a query and fails if it could not retrieve the object or > there > + * was no object to retrieve */ > +boolean > +get_first_element(IEnumWbemClassObject* penumerate, > IWbemClassObject** pcls_obj) > +{ > + ULONG retval = 0; > + > + if (penumerate == NULL) { > + VLOG_WARN("Enumeration Class Object is NULL. Cannot get the first > object"); > + return false; > + } > + > + HRESULT hres = penumerate->lpVtbl->Next(penumerate, > WBEM_INFINITE, 1, > + pcls_obj, &retval); [Paul Boca] Maybe here we should check hres instead of retval > + > + > + if (retval == 0) { > + return false; > + } > + > + return true; > +} > + > +/* This function transforms a char* into a wchar_t* */ > +boolean > +tranform_wide(char* name, wchar_t* wide_name) > +{ > + ULONG size = strlen(name) + 1; > + > + if (wide_name == NULL) { > + VLOG_WARN("Parameter invalid"); > + return false; > + } > + > + mbstowcs(wide_name, name, size); [Paul Boca] We should check the return for mbstowcs because there are some corner-cases "If mbstowcs encounters an invalid multibyte character, it returns –1. If the return value is count, the wide-character string is not null-terminated." > + > + return true; > +} > + > +/* This function will delete a switch internal port with a given name as > input > + * executing "RemoveResourceSettings" as per documentation: > + * https://msdn.microsoft.com/en- > us/library/hh850277%28v=vs.85%29.aspx > + * allocating the data and populating the needed fields to execute the > + * method */ > +boolean > +delete_wmi_port(char* name) > +{ > + HRESULT hres = 0; > + boolean retval = true; > + > + IWbemLocator* ploc = NULL; > + IWbemServices* psvc = NULL; > + IWbemContext* pcontext = NULL; > + IWbemClassObject* pclass_instance = NULL; > + IWbemClassObject* pinput_params = NULL; > + IWbemClassObject* pcls_obj = NULL; > + IWbemClassObject* pout_params = NULL; > + IEnumWbemClassObject* penumerate = NULL; > + > + VARIANT vt_prop; > + VARIANT variant_array; > + wchar_t* wide_name = NULL; > + VariantInit(&vt_prop); > + VariantInit(&variant_array); > + > + LONG count[1]; > + SAFEARRAY* psa = SafeArrayCreateVector(VT_BSTR, 0, 1); [Paul Boca] I think here would be safe if a check over psa is done > + > + if (!initialize_wmi(&ploc, &pcontext)) { > + VLOG_WARN("Could not initialize DCOM"); > + retval = false; > + goto error; > + } > + > + if (!connect_set_security(ploc, pcontext, L"Root\\Virtualization\\v2", > + &psvc)) { > + VLOG_WARN("Could not connect and set security for virtualization"); > + retval = false; > + goto error; > + } > + > + > + /* Get the port with the element name equal to the name input */ > + wchar_t internal_port_query[2048]; > + wcscpy_s(internal_port_query, sizeof(internal_port_query), > + L"SELECT * from Msvm_EthernetPortAllocationSettingData WHERE " > + L"ElementName = \""); [Paul Boca] Here you could initialize internal_port_query directly, no need for w wcscpy_s > + > + wide_name = malloc((strlen(name) + 1) * sizeof(wchar_t)); > + if (wide_name == NULL) { > + VLOG_WARN("Could not allocate memory for wide string"); > + retval = false; > + goto error; > + } > + > + if (!tranform_wide(name, wide_name)) { > + retval = false; > + goto error; > + } > + wcscat_s(internal_port_query, sizeof(internal_port_query), wide_name); > + > + wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); > + > + hres = psvc->lpVtbl->ExecQuery(psvc, > + L"WQL", > + internal_port_query, > + WBEM_FLAG_FORWARD_ONLY | > + WBEM_FLAG_RETURN_IMMEDIATELY, > + NULL, > + &penumerate); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + /* Get the element path on the switch which will be deleted */ > + if (!get_first_element(penumerate, &pcls_obj)) { > + retval = false; > + goto error; > + } > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + > + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + > + /* Get the class object and the parameters it can have */ > + hres = psvc->lpVtbl->GetObject(psvc, > L"Msvm_VirtualEthernetSwitchManagementService", > + 0, NULL, &pcls_obj, NULL); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + hres = pcls_obj->lpVtbl->GetMethod(pcls_obj, > L"RemoveResourceSettings", 0, > + &pinput_params, NULL); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + > + hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, > + &pclass_instance); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + count[0] = 0; > + > + hres = SafeArrayPutElement(psa, count, vt_prop.bstrVal); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + VariantClear(&vt_prop); > + VariantInit(&vt_prop); > + variant_array.vt = VT_ARRAY | VT_BSTR; > + variant_array.parray = psa; > + > + hres = pclass_instance->lpVtbl->Put(pclass_instance, L"ResourceSettings", > 0, > + &variant_array, 0); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + /* Get the object of the Msvm_VirtualEthernetSwitchManagementService > which > + * we need to invoke the port deletion */ > + hres = psvc->lpVtbl->ExecQuery(psvc, > + L"WQL", > + L"SELECT * FROM " > + > L"Msvm_VirtualEthernetSwitchManagementService", > + WBEM_FLAG_FORWARD_ONLY | > + WBEM_FLAG_RETURN_IMMEDIATELY, > + NULL, > + &penumerate); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + if (!get_first_element(penumerate, &pcls_obj)) { > + retval = false; > + goto error; > + } > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + > + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + > + /* Invoke the delete port method */ > + hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, > + L"RemoveResourceSettings", 0, > + pcontext, pclass_instance, &pout_params, > + NULL); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + VariantClear(&vt_prop); > + VariantInit(&vt_prop); > + > + hres = pout_params->lpVtbl->Get(pout_params, L"ReturnValue", 0, > + &vt_prop, NULL, 0); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + UINT retvalue = get_uint_value(pout_params, L"ReturnValue"); > + if (retvalue != 0 && retvalue != wait) { > + retval = false; > + goto error; > + } > + > + if (retvalue == wait) { > + WCHAR job_path[2048]; > + get_str_value(pout_params, L"Job", job_path, > + sizeof(job_path) / sizeof(WCHAR)); > + hres = wait_for_job(psvc, job_path); > + if (FAILED(hres)) { > + retval = false; > + } > + } > + > +error: > + VariantClear(&vt_prop); > + > + if (pcontext != NULL) { > + pcontext->lpVtbl->Release(pcontext); > + pcontext = NULL; > + } > + if (psa != NULL) { > + SafeArrayDestroy(psa); > + psa = NULL; > + } > + if (pcls_obj != NULL) { > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + } > + if (wide_name != NULL) { > + free(wide_name); > + wide_name = NULL; > + } > + if (!retval) { > + get_hres_error(hres); > + } > + if (pinput_params != NULL) { > + pinput_params->lpVtbl->Release(pinput_params); > + pinput_params = NULL; > + } > + if (pout_params != NULL) { > + pout_params->lpVtbl->Release(pout_params); > + pout_params = NULL; > + } > + if (psvc != NULL) { > + psvc->lpVtbl->Release(psvc); > + psvc = NULL; > + } > + if (ploc != NULL) { > + ploc->lpVtbl->Release(ploc); > + ploc = NULL; > + } > + if (pclass_instance != NULL) { > + pclass_instance->lpVtbl->Release(pclass_instance); > + pclass_instance = NULL; > + } > + if (penumerate != NULL) { > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + } > + > + CoUninitialize(); > + return retval; > +} > + > +/* This function will create an internal port on the switch given a given > name > + * executing the method AddResourceSettings as per documentation: > + * https://msdn.microsoft.com/en- > us/library/hh850019%28v=vs.85%29.aspx > + * It will verify if the port is already defined, in which case it will use > + * the specific port, and if the forwarding extension "Open vSwitch > Extension" > + * is enabled and running only on a single switch. > + * After the port is created and bound to the switch we will disable the > + * created net adapter and rename it to match the OVS bridge name .*/ > +boolean create_wmi_port(char* name) { > + HRESULT hres = 0; > + boolean retval = true; > + > + BSTR text_object_string = NULL; > + > + IWbemLocator *ploc = NULL; > + IWbemContext *pcontext = NULL; > + IWbemServices *psvc = NULL; > + IEnumWbemClassObject* penumerate = NULL; > + IWbemClassObject* defaultAllocationSettingData = NULL; > + IWbemClassObject* defaultComputerSystem = NULL; > + IWbemClassObject *pcls_obj = NULL; > + IWbemClassObject* pclass = NULL; > + IWbemClassObject* pinput_params = NULL; > + IWbemClassObject* pclass_instance = NULL; > + IWbemObjectTextSrc* text_object = NULL; > + IWbemClassObject* pout_params = NULL; > + > + wchar_t* wide_name = NULL; > + VARIANT vt_prop; > + VARIANT switch_setting_path; > + VARIANT new_name; > + SAFEARRAY* psa = SafeArrayCreateVector(VT_BSTR, 0, 1); > + VARIANT variant_array; > + LONG count[1]; > + > + VariantInit(&vt_prop); > + VariantInit(&switch_setting_path); > + > + if (!initialize_wmi(&ploc, &pcontext)) { > + VLOG_WARN("Could not initialize DCOM"); > + retval = false; > + goto error; > + } > + > + if (!connect_set_security(ploc, pcontext, L"Root\\Virtualization\\v2", > + &psvc)) { > + VLOG_WARN("Could not connect and set security for virtualization"); > + retval = false; > + goto error; > + } > + > + /* Check if the element already exists on the switch */ > + wchar_t internal_port_query[2048]; > + wcscpy_s(internal_port_query, sizeof(internal_port_query), > + L"SELECT * FROM Msvm_InternalEthernetPort WHERE " > + L"ElementName = \""); > + > + wide_name = malloc((strlen(name) + 1) * sizeof(wchar_t)); > + if (wide_name == NULL) { > + VLOG_WARN("Could not allocate memory for wide string"); > + retval = false; > + goto error; > + } > + > + if (!tranform_wide(name, wide_name)) { > + retval = false; > + goto error; > + } > + wcscat_s(internal_port_query, sizeof(internal_port_query), wide_name); > + > + wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); > + hres = psvc->lpVtbl->ExecQuery(psvc, > + L"WQL", > + internal_port_query, > + WBEM_FLAG_FORWARD_ONLY | > + WBEM_FLAG_RETURN_IMMEDIATELY, > + NULL, > + &penumerate); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + if (get_first_element(penumerate, &pcls_obj)) { > + VLOG_WARN("Port with name: %s already defined on the switch", > name); > + goto error; > + } > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + > + /* Check if the extension is enabled and running. Also check if the > + * the extension is enabled on more than one switch */ > + hres = psvc->lpVtbl->ExecQuery(psvc, > + L"WQL", > + L"SELECT * " > + L"FROM Msvm_EthernetSwitchExtension " > + L"WHERE " > + L"ElementName=\"Open vSwitch Extension\"", > + WBEM_FLAG_FORWARD_ONLY | > + WBEM_FLAG_RETURN_IMMEDIATELY, > + NULL, > + &penumerate); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + if (!get_first_element(penumerate, &pcls_obj)) { > + VLOG_WARN("Open vSwitch Extension is not enabled on any switch"); > + retval = false; > + goto error; > + } > + wcscpy_s(internal_port_query, sizeof(internal_port_query), > + L"SELECT * FROM Msvm_VirtualEthernetSwitch WHERE Name = \""); > + > + if (get_ushort_value(pcls_obj, L"EnabledState") == 2 && > + get_ushort_value(pcls_obj, L"HealthState") == 5) { > + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"SystemName", 0, > + &vt_prop, 0, 0); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + wcscat_s(internal_port_query, sizeof(internal_port_query), > + vt_prop.bstrVal); > + } else { > + VLOG_WARN("Open vSwitch Extension is not running on any switch"); > + retval = false; > + goto error; > + } > + VariantClear(&vt_prop); > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + > + if (get_first_element(penumerate, &pcls_obj)) { > + VLOG_WARN("The extension is activated on more than one switch, " > + "aborting operation. Please activate the extension on a " > + "single switch"); > + retval = false; > + goto error; > + } > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + if (pcls_obj != NULL) { > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + } > + > + /* Get the switch object on which the extension is activated*/ > + wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); > + hres = psvc->lpVtbl->ExecQuery(psvc, > + L"WQL", > + internal_port_query, > + WBEM_FLAG_FORWARD_ONLY | > + WBEM_FLAG_RETURN_IMMEDIATELY, > + NULL, > + &penumerate); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + if (!get_first_element(penumerate, &pcls_obj)) { > + VLOG_WARN("Could not get the switch object on which the extension > is" > + "activated"); > + retval = false; > + goto error; > + } > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + > + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"ElementName", 0, &vt_prop, 0, > 0); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + wcscpy_s(internal_port_query, sizeof(internal_port_query), > + L"SELECT * FROM Msvm_VirtualEthernetSwitchSettingData WHERE " > + L"ElementName = \""); > + > + wcscat_s(internal_port_query, sizeof(internal_port_query), > + vt_prop.bstrVal); > + VariantClear(&vt_prop); > + > + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"Name", 0, &vt_prop, 0, 0); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + > + wcscat_s(internal_port_query, sizeof(internal_port_query), > + L"\" AND VirtualSystemIdentifier = \""); > + wcscat_s(internal_port_query, sizeof(internal_port_query), > + vt_prop.bstrVal); > + wcscat_s(internal_port_query, sizeof(internal_port_query), > + L"\" AND InstanceID = \"Microsoft:"); > + wcscat_s(internal_port_query, sizeof(internal_port_query), > + vt_prop.bstrVal); > + wcscat_s(internal_port_query, sizeof(internal_port_query), > + L"\" AND Caption = \"Virtual Ethernet Switch Settings\" AND " > + L"VirtualSystemType = \"DMTF:Virtual Ethernet Switch\""); > + > + VariantClear(&vt_prop); > + > + /* Retrieve the Msvm_VirtualEthernetSwitchSettingData pinned to the > switch > + * object on which the extension is activated */ > + hres = psvc->lpVtbl->ExecQuery(psvc, > + L"WQL", > + internal_port_query, > + WBEM_FLAG_FORWARD_ONLY | > + WBEM_FLAG_RETURN_IMMEDIATELY, > + NULL, > + &penumerate); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + if (!get_first_element(penumerate, &pcls_obj)) { > + VLOG_WARN("Could not get the first " > + "Msvm_VirtualEthernetSwitchSettingData object"); > + retval = false; > + goto error; > + } > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + > + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, > &switch_setting_path, > + 0, 0); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + > + /* Retrieve a default allocation port. This object will be later filled > + * with optional data to create an switch internal port */ > + hres = psvc->lpVtbl->ExecQuery(psvc, > + L"WQL", > + L"SELECT * FROM " > + L"Msvm_EthernetPortAllocationSettingData " > + L"WHERE InstanceID LIKE '%%%%\\\\Default' > " > + L"AND ResourceSubType = " > + L"'Microsoft:Hyper-V:Ethernet > Connection'", > + WBEM_FLAG_FORWARD_ONLY | > + WBEM_FLAG_RETURN_IMMEDIATELY, > + NULL, > + &penumerate); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + if (!get_first_element(penumerate, &defaultAllocationSettingData)) { > + VLOG_WARN("Could not retrieve default allocation port object"); > + retval = false; > + goto error; > + } > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + > + /* Retrieve the default computer system on which the port allocation will > + * be hosted */ > + hres = psvc->lpVtbl->ExecQuery(psvc, > + L"WQL", > + L"SELECT * FROM Msvm_ComputerSystem WHERE > " > + L"Description = \"Microsoft Hosting " > + L"Computer System\"", > + WBEM_FLAG_FORWARD_ONLY | > + WBEM_FLAG_RETURN_IMMEDIATELY, > + NULL, > + &penumerate); > + > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + if (!get_first_element(penumerate, &defaultComputerSystem)) { > + VLOG_WARN("Could not retrieve default computer system object"); > + retval = false; > + goto error; > + } > + > + hres = defaultComputerSystem->lpVtbl->Get(defaultComputerSystem, > L"__PATH", > + 0, &vt_prop, 0, 0); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + > + count[0] = 0; > + hres = SafeArrayPutElement(psa, count, vt_prop.bstrVal); > + VariantClear(&vt_prop); > + variant_array.vt = VT_ARRAY | VT_BSTR; > + variant_array.parray = psa; > + hres = defaultAllocationSettingData->lpVtbl- > >Put(defaultAllocationSettingData, > + L"HostResource", 0, > + &variant_array, 0); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + hres = psvc->lpVtbl->GetObject(psvc, > + > L"Msvm_VirtualEthernetSwitchManagementService", > + 0, NULL, &pclass, NULL); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + hres = pclass->lpVtbl->GetMethod(pclass, L"AddResourceSettings", 0, > + &pinput_params, NULL); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, > + &pclass_instance); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + /* Store the switch setting path retrieved above in the affected > + * configuration field of the class instance */ > + hres = pclass_instance->lpVtbl->Put(pclass_instance, > + L"AffectedConfiguration", 0, > + &switch_setting_path, 0); > + > + /* Store the port name in the ElementName field of the default allocation > + * data */ > + vt_prop.vt = VT_BSTR; > + vt_prop.bstrVal = SysAllocString(wide_name); > + hres = defaultAllocationSettingData->lpVtbl- > >Put(defaultAllocationSettingData, > + L"ElementName", 0, > + &vt_prop, 0); > + VariantClear(&vt_prop); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + /* Retrieve and store the serialized data of the modified default switch > + * settings data */ > + hres = CoCreateInstance(&CLSID_WbemObjectTextSrc, > + NULL, > + CLSCTX_INPROC_SERVER, > + &IID_IWbemObjectTextSrc, > + (void**)&text_object); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + hres = text_object->lpVtbl->GetText(text_object, 0, > + defaultAllocationSettingData, > + WMI_OBJ_TEXT_WMI_DTD_2_0, > + pcontext, > + &text_object_string); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + hres = SafeArrayDestroy(psa); > + if (FAILED(hres)) { > + VLOG_WARN("Could not clear the data of the array"); > + retval = false; > + goto error; > + } > + psa = NULL; > + psa = SafeArrayCreateVector(VT_BSTR, 0, 1); > + > + count[0] = 0; > + variant_array.parray = psa; > + hres = SafeArrayPutElement(psa, count, text_object_string); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + hres = pclass_instance->lpVtbl->Put(pclass_instance, L"ResourceSettings", > + 0, &variant_array, 0); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + /* Get the object of the switch service */ > + hres = psvc->lpVtbl->ExecQuery(psvc, > + L"WQL", > + L"SELECT * FROM " > + > L"Msvm_VirtualEthernetSwitchManagementService", > + WBEM_FLAG_FORWARD_ONLY | > + WBEM_FLAG_RETURN_IMMEDIATELY, > + NULL, > + &penumerate); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + if (!get_first_element(penumerate, &pcls_obj)) { > + VLOG_WARN("Could not get the object of the switch service"); > + retval = false; > + goto error; > + } > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + > + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + > + /* Try to add the port to the switch */ > + hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, > + L"AddResourceSettings", 0, > + pcontext, pclass_instance, &pout_params, > + NULL); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + UINT retvalue = get_uint_value(pout_params, L"ReturnValue"); > + if (retvalue != 0 && retvalue != wait) { > + retval = false; > + goto error; > + } > + > + if (retvalue == wait) { > + WCHAR job_path[2048]; > + get_str_value(pout_params, L"Job", job_path, > + sizeof(job_path) / sizeof(WCHAR)); > + hres = wait_for_job(psvc, job_path); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + } > + > + pclass->lpVtbl->Release(pclass); > + pclass = NULL; > + pclass_instance->lpVtbl->Release(pclass_instance); > + pclass_instance = NULL; > + pinput_params->lpVtbl->Release(pinput_params); > + pinput_params = NULL; > + psvc->lpVtbl->Release(psvc); > + psvc = NULL; > + VariantClear(&vt_prop); > + > + if (!connect_set_security(ploc, pcontext, L"Root\\StandardCimv2", > + &psvc)) { > + VLOG_WARN("Could not connect and set security for CIM"); > + retval = false; > + goto error; > + } > + > + wcscpy_s(internal_port_query, sizeof(internal_port_query), > + L"SELECT * FROM MSFT_NetAdapter WHERE Name LIKE '%%"); > + wcscat_s(internal_port_query, sizeof(internal_port_query), wide_name); > + wcscat_s(internal_port_query, sizeof(internal_port_query), L"%%'"); > + > + /* Get the object with the port name equal to name on the CIM */ > + hres = psvc->lpVtbl->ExecQuery(psvc, > + L"WQL", > + internal_port_query, > + WBEM_FLAG_FORWARD_ONLY | > + WBEM_FLAG_RETURN_IMMEDIATELY, > + NULL, > + &penumerate); > + > + if (!get_first_element(penumerate, &pcls_obj)) { > + VLOG_WARN("Element name: %s not found in CIM", name); > + retval = false; > + goto error; > + } > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + > + /* Disable the adapter with port name equal with name */ > + hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, L"Disable", 0, > + pcontext, NULL, NULL, NULL); > + > + hres = psvc->lpVtbl->GetObject(psvc, L"MSFT_NetAdapter", 0, NULL, > &pclass, > + NULL); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + hres = pclass->lpVtbl->GetMethod(pclass, L"Rename", 0, > &pinput_params, > + NULL); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, > + &pclass_instance); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + > + VariantInit(&new_name); > + new_name.vt = VT_BSTR; > + new_name.bstrVal = wide_name; > + hres = pclass_instance->lpVtbl->Put(pclass_instance, L"NewName", 0, > + &new_name, 0); > + if (FAILED(hres)) { > + retval = false; > + goto error; > + } > + hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, L"Rename", 0, > + pcontext, pclass_instance, NULL, NULL); > + if (FAILED(hres)) { > + retval = false; > + } > + > +error: > + if (text_object_string != NULL) { > + SysFreeString(text_object_string); > + text_object_string = NULL; > + } > + if (psa != NULL) { > + SafeArrayDestroy(psa); > + psa = NULL; > + } > + if (ploc != NULL) { > + ploc->lpVtbl->Release(ploc); > + ploc = NULL; > + } > + if (pcontext != NULL) { > + pcontext->lpVtbl->Release(pcontext); > + pcontext = NULL; > + } > + if (psvc != NULL) { > + psvc->lpVtbl->Release(psvc); > + psvc = NULL; > + } > + if (penumerate != NULL) { > + penumerate->lpVtbl->Release(penumerate); > + penumerate = NULL; > + } > + if (defaultAllocationSettingData != NULL) { > + defaultAllocationSettingData->lpVtbl- > >Release(defaultAllocationSettingData); > + defaultAllocationSettingData = NULL; > + } > + if (defaultComputerSystem != NULL) { > + defaultComputerSystem->lpVtbl->Release(defaultComputerSystem); > + defaultComputerSystem = NULL; > + } > + if (pcls_obj != NULL) { > + pcls_obj->lpVtbl->Release(pcls_obj); > + pcls_obj = NULL; > + } > + if (pclass != NULL) { > + pclass->lpVtbl->Release(pclass); > + pclass = NULL; > + } > + if (pinput_params != NULL) { > + pinput_params->lpVtbl->Release(pinput_params); > + pinput_params = NULL; > + } > + if (pclass_instance != NULL) { > + pclass_instance->lpVtbl->Release(pclass_instance); > + pclass_instance = NULL; > + } > + if (text_object != NULL) { > + text_object->lpVtbl->Release(text_object); > + text_object = NULL; > + } > + if (pout_params != NULL) { > + pout_params->lpVtbl->Release(pout_params); > + pout_params = NULL; > + } > + if (wide_name != NULL) { > + free(wide_name); > + wide_name = NULL; > + } > + VariantClear(&vt_prop); > + VariantClear(&switch_setting_path); > + > + if (!retval) { > + get_hres_error(hres); > + } > + CoUninitialize(); > + return retval; > +} > diff --git a/lib/wmi.h b/lib/wmi.h > new file mode 100644 > index 0000000..0ce50c0 > --- /dev/null > +++ b/lib/wmi.h > @@ -0,0 +1,51 @@ > +/* > + * Copyright (c) 2016 Cloudbase Solutions Srl > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#ifndef WMI_H > +#define WMI_H 1 > + > +#include <windefs.h> > +#include <Wbemidl.h> > + > +static inline void fill_context(IWbemContext *pContext) > +{ > + VARIANT var; > + > + /* IncludeQualifiers */ > + VariantInit(&var); > + var.vt = VT_BOOL; > + var.boolVal = VARIANT_TRUE; > + pContext->lpVtbl->SetValue(pContext, L"IncludeQualifiers", 0, &var); > + VariantClear(&var); > + > + VariantInit(&var); > + var.vt = VT_I4; > + var.lVal = 0; > + pContext->lpVtbl->SetValue(pContext, L"PathLevel", 0, &var); > + VariantClear(&var); > + > + /* ExcludeSystemProperties */ > + VariantInit(&var); > + var.vt = VT_BOOL; > + var.boolVal = VARIANT_FALSE; > + pContext->lpVtbl->SetValue(pContext, L"ExcludeSystemProperties", 0, > &var); > + VariantClear(&var); > +} > + > +boolean create_wmi_port(char* name); > +boolean delete_wmi_port(char* name); > + > +#endif /* wmi.h */ > -- > 1.9.5.msysgit.0 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev