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

Reply via email to