Thanks for changes!

Acked-by: Paul Boca <[email protected]>

> -----Original Message-----
> From: dev [mailto:[email protected]] On Behalf Of Alin Serdean
> Sent: Tuesday, July 26, 2016 6:44 PM
> To: [email protected]
> Subject: [ovs-dev] [PATCH v2 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 <[email protected]>
> ---
> v2: Address comments. Rebase
> ---
>  INSTALL.Windows.md |   73 ++-
>  appveyor.yml       |    2 +-
>  lib/automake.mk    |    4 +-
>  lib/dpif-netlink.c |   21 +
>  lib/wmi.c          | 1279
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/wmi.h          |   51 +++
>  6 files changed, 1389 insertions(+), 41 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..32cef43 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"
> @@ -186,8 +188,7 @@ to work (covered later).
> 
>  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 +282,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
> 
> @@ -302,13 +303,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 +316,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 +372,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 +380,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 0fd003b..1061df6 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 71c9d41..fac4024 100644
> --- a/lib/automake.mk
> +++ b/lib/automake.mk
> @@ -377,7 +377,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 d544072..2fe32ca 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 };
> @@ -849,6 +850,16 @@ dpif_netlink_port_add__(struct dpif_netlink *dpif,
> struct netdev *netdev,
>  #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 +951,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);
> diff --git a/lib/wmi.c b/lib/wmi.c
> new file mode 100644
> index 0000000..b1d1423
> --- /dev/null
> +++ b/lib/wmi.c
> @@ -0,0 +1,1279 @@
> +/*
> + * 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 job_status
> +{
> +    job_starting = 3,
> +    job_running = 4,
> +    job_completed = 7,
> +    job_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_t value from a given class object with
> + * the field name field_name */
> +HRESULT
> +get_uint16_t_value(IWbemClassObject* pcls_obj, wchar_t* field_name,
> +                   uint16_t* value)
> +{
> +    VARIANT vt_prop;
> +    VariantInit(&vt_prop);
> +    HRESULT hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, &vt_prop,
> +                                         0, 0);
> +
> +    if (FAILED(hres)) {
> +        return hres;
> +    }
> +
> +    *value = V_UI2(&vt_prop);
> +    VariantClear(&vt_prop);
> +
> +    return S_OK;
> +}
> +
> +/* This function retrieves the unsigned int values from a given class object
> + * with the field name field_name */
> +HRESULT
> +get_uint_value(IWbemClassObject* pcls_obj, wchar_t* field_name,
> +               unsigned int* value)
> +{
> +    VARIANT vt_prop;
> +    VariantInit(&vt_prop);
> +    HRESULT hres = pcls_obj->lpVtbl->Get(pcls_obj,field_name, 0, &vt_prop,
> +                                         0, 0);
> +
> +    if (FAILED(hres)) {
> +        return hres;
> +    }
> +
> +    *value = V_UI4(&vt_prop);
> +    VariantClear(&vt_prop);
> +
> +    return S_OK;
> +}
> +
> +/* This function retrieves the unsigned short value from a given class object
> + * with the field name field_name */
> +HRESULT
> +get_ushort_value(IWbemClassObject* pcls_obj, wchar_t* field_name,
> +                 unsigned short* value)
> +{
> +    VARIANT vt_prop;
> +    VariantInit(&vt_prop);
> +    HRESULT hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, &vt_prop,
> +                                         0, 0);
> +
> +    if (FAILED(hres)) {
> +        return hres;
> +    }
> +
> +    *value = V_UI2(&vt_prop);
> +    VariantClear(&vt_prop);
> +
> +    return S_OK;
> +}
> +
> +/* 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 */
> +HRESULT
> +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);
> +
> +    if (FAILED(hres)) {
> +        VariantClear(&vt_prop);
> +        return hres;
> +    }
> +
> +    if (wcscpy_s(dest, max_dest_lgth, vt_prop.bstrVal)) {
> +        VariantClear(&vt_prop);
> +        VLOG_WARN("get_str_value, wcscpy_s failed :%s",
> ovs_strerror(errno));
> +        return WBEM_E_FAILED;
> +    }
> +
> +    VariantClear(&vt_prop);
> +
> +    return S_OK;
> +}
> +
> +/* 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 {
> +        if(!check_return_value(psvc->lpVtbl->GetObject(psvc, job_path, 0,
> NULL,
> +                                                       &pcls_obj, NULL))) {
> +            retval = WBEM_E_FAILED;
> +            break;
> +        }
> +
> +        retval = get_uint16_t_value(pcls_obj, L"JobState", &job_state);
> +        if (FAILED(retval)) {
> +            break;
> +        }
> +
> +        if (job_state == job_starting || job_state == job_running) {
> +            Sleep(200);
> +        } else if (job_state == job_completed) {
> +            break;
> +        } else {
> +            /* Error occurred */
> +            retval = get_uint16_t_value(pcls_obj, L"ErrorCode", &error);
> +            if (FAILED(retval)) {
> +                break;
> +            }
> +            VLOG_WARN("Job failed with error: %d", error);
> +            retval = WBEM_E_FAILED;;
> +            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)
> +{
> +    unsigned long 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);
> +
> +
> +    if (!check_return_value(hres) || retval == 0) {
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
> +/* This function is a wrapper that transforms a char* into a wchar_t* */
> +boolean
> +tranform_wide(char* name, wchar_t* wide_name)
> +{
> +    unsigned long size = strlen(name) + 1;
> +    long long ret = 0;
> +
> +    if (wide_name == NULL) {
> +        VLOG_WARN("Provided wide string is NULL");
> +        return false;
> +    }
> +
> +    ret = mbstowcs(wide_name, name, size);
> +
> +    if (ret == -1) {
> +        VLOG_WARN("Invalid multibyte character is encountered");
> +        return false;
> +    } else if (ret == size) {
> +        VLOG_WARN("Returned wide string not NULL terminated");
> +        return false;
> +    }
> +
> +    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);
> +    if (psa == NULL) {
> +        VLOG_WARN("Could not allocate memory for a SAFEARRAY");
> +        retval = false;
> +        goto error;
> +    }
> +
> +    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] = L"SELECT * from "
> +        L"Msvm_EthernetPortAllocationSettingData  WHERE 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;
> +    }
> +
> +    /* 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;
> +    }
> +
> +    unsigned int retvalue = 0;
> +    hres = get_uint_value(pout_params, L"ReturnValue", &retvalue);
> +    if (FAILED(hres)) {
> +        retval = false;
> +        goto error;
> +    }
> +
> +    if (retvalue != 0 && retvalue != job_wait) {
> +        retval = false;
> +        goto error;
> +    }
> +
> +    if (retvalue == job_wait) {
> +        WCHAR job_path[2048];
> +        hres = get_str_value(pout_params, L"Job", job_path,
> +                             sizeof(job_path) / sizeof(WCHAR));
> +        if (FAILED(hres)) {
> +            retval = false;
> +            goto error;
> +    }
> +        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* default_settings_data = NULL;
> +    IWbemClassObject* default_system = 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 (psa == NULL) {
> +        VLOG_WARN("Could not allocate memory for a SAFEARRAY");
> +        retval = false;
> +        goto error;
> +    }
> +
> +    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] = L"SELECT * FROM "
> +    L"Msvm_InternalEthernetPort WHERE 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\" "
> +                                   L"AND EnabledState=2 "
> +                                   L"AND HealthState=5",
> +                                   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 = \"");
> +
> +    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);
> +
> +    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, &default_settings_data)) {
> +        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, &default_system)) {
> +        VLOG_WARN("Could not retrieve default computer system object");
> +        retval = false;
> +        goto error;
> +    }
> +
> +    hres = default_system->lpVtbl->Get(default_system, 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);
> +
> +     if (FAILED(hres)) {
> +        retval = false;
> +        goto error;
> +    }
> +
> +    VariantClear(&vt_prop);
> +    variant_array.vt = VT_ARRAY | VT_BSTR;
> +    variant_array.parray = psa;
> +    hres = default_settings_data->lpVtbl->Put(default_settings_data,
> +                                              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);
> +
> +    if (FAILED(hres)) {
> +        retval = false;
> +        goto error;
> +    }
> +
> +    /* 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 = default_settings_data->lpVtbl->Put(default_settings_data,
> +                                              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,
> +                                        default_settings_data,
> +                                        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 = SafeArrayCreateVector(VT_BSTR, 0, 1);
> +
> +    if (psa == NULL) {
> +        VLOG_WARN("Could not allocate memory for a SAFEARRAY");
> +        retval = false;
> +        goto error;
> +    }
> +
> +    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;
> +    }
> +
> +    unsigned int retvalue = 0;
> +    hres = get_uint_value(pout_params, L"ReturnValue", &retvalue);
> +    if (FAILED(hres)) {
> +        retval = false;
> +        goto error;
> +    }
> +
> +    if (retvalue != 0 && retvalue != job_wait) {
> +        retval = false;
> +        goto error;
> +    }
> +
> +    if (retvalue == job_wait) {
> +        WCHAR job_path[2048];
> +        hres = get_str_value(pout_params, L"Job", job_path,
> +                             sizeof(job_path) / sizeof(WCHAR));
> +        if (FAILED(hres)) {
> +            retval = false;
> +            goto error;
> +        }
> +        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);
> +
> +    if (FAILED(hres)) {
> +        retval = false;
> +        goto error;
> +    }
> +
> +    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 (default_settings_data != NULL) {
> +        default_settings_data->lpVtbl->Release(default_settings_data);
> +        default_settings_data = NULL;
> +    }
> +    if (default_system != NULL) {
> +        default_system->lpVtbl->Release(default_system);
> +        default_system = 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
> [email protected]
> http://openvswitch.org/mailman/listinfo/dev
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev

Reply via email to