diff mbox

[ovs-dev,v4,1/3] Windows: Add internal switch port per OVS bridge

Message ID 20160813010606.13668-1-aserdean@cloudbasesolutions.com
State Superseded
Delegated to: Guru Shetty
Headers show

Commit Message

Alin Serdean Aug. 13, 2016, 1:06 a.m. UTC
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 <aserdean@cloudbasesolutions.com>
Acked-by: Paul Boca <pboca@cloudbasesolutions.com>
---
v4: address comments (sanitize input, short refactor)
    use full stop on comments
    update coding style
v3: rebase, add acked
v2: Address comments. Rebase
---
 appveyor.yml       |    2 +-
 lib/automake.mk    |    4 +-
 lib/dpif-netlink.c |   21 +
 lib/wmi.c          | 1276 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/wmi.h          |   51 +++
 5 files changed, 1352 insertions(+), 2 deletions(-)
 create mode 100644 lib/wmi.c
 create mode 100644 lib/wmi.h

Comments

Sairam Venugopal Oct. 10, 2016, 10:47 p.m. UTC | #1
Sorry for the delay in the review.

Acked-by: Sairam Venugopal <vsairam@vmware.com>



On 8/12/16, 6:06 PM, "Alin Serdean" <aserdean@cloudbasesolutions.com>
wrote:

>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 <aserdean@cloudbasesolutions.com>
>Acked-by: Paul Boca <pboca@cloudbasesolutions.com>
>---
>v4: address comments (sanitize input, short refactor)
>    use full stop on comments
>    update coding style
>v3: rebase, add acked
>v2: Address comments. Rebase
>---
> appveyor.yml       |    2 +-
> lib/automake.mk    |    4 +-
> lib/dpif-netlink.c |   21 +
> lib/wmi.c          | 1276
>++++++++++++++++++++++++++++++++++++++++++++++++++++
> lib/wmi.h          |   51 +++
> 5 files changed, 1352 insertions(+), 2 deletions(-)
> create mode 100644 lib/wmi.c
> create mode 100644 lib/wmi.h
>
>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 2faaeac..99bbdc0 100644
>--- a/lib/automake.mk
>+++ b/lib/automake.mk
>@@ -387,7 +387,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 a39faa2..c8b0e37 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..67f0873
>--- /dev/null
>+++ b/lib/wmi.c
>@@ -0,0 +1,1276 @@
>+/*
>+ * 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
>+ *
>+ *     
>https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_license
>s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=D
>cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=1NgcutJOUfLwjikmUhz6W0zVXDR35
>T75FV8sqiZ8ki8&s=6YJXIuUkmHpuGcJw64GoPVKdYVnqhnBsGxStg7axmxs&e=
>+ *
>+ * 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
>+};
>+
>+static char *
>+sanitize_port_name(char *name)
>+{
>+    char *p1, *p2;
>+    p1 = p2 = name;
>+
>+    while (*p1) {
>+        if ((*p1) == '\'' || (*p1) == '\"') {
>+            p1++;
>+        } else {
>+            *p2 = *p1;
>+            p2++;
>+            p1++;
>+        }
>+    }
>+    *p2 = '\0';
>+    return name;
>+}
>+
>+/* This function will output the appropriate message for a given
>HRESULT.*/
>+static void
>+get_hres_error(HRESULT hres)
>+{
>+    char *error_msg = NULL;
>+
>+    if (FACILITY_WINDOWS == HRESULT_FACILITY(hres)) {
>+        hres = HRESULT_CODE(hres);
>+    }
>+
>+    VLOG_ERR("%s", ovs_format_message(hres));
>+}
>+
>+static boolean
>+check_return_value(HRESULT hres)
>+{
>+    if (FAILED(hres)) {
>+        get_hres_error(hres);
>+        return false;
>+    }
>+
>+    return true;
>+}
>+
>+static HRESULT
>+get_variant_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
>+                  VARIANT *value)
>+{
>+    HRESULT hres;
>+
>+    VariantInit(value);
>+
>+    hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, value, 0, 0);
>+
>+    if (FAILED(hres)) {
>+        VariantClear(value);
>+    }
>+
>+    return hres;
>+}
>+
>+/* This function retrieves the uint16_t value from a given class object
>with
>+ * the field name field_name. */
>+static HRESULT
>+get_uint16_t_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
>+                   uint16_t *value)
>+{
>+    VARIANT vt_prop;
>+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
>+    *value = V_UI2(&vt_prop);
>+
>+    return hres;
>+}
>+
>+/* This function retrieves the unsigned int values from a given class
>object
>+ * with the field name field_name. */
>+static HRESULT
>+get_uint_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
>+               unsigned int *value)
>+{
>+    VARIANT vt_prop;
>+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
>+    *value = V_UI4(&vt_prop);
>+
>+    return hres;
>+}
>+
>+/* This function retrieves the unsigned short value from a given class
>object
>+ * with the field name field_name. */
>+static HRESULT
>+get_ushort_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
>+                 unsigned short *value)
>+{
>+    VARIANT vt_prop;
>+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
>+    *value = V_UI2(&vt_prop);
>+
>+    return hres;
>+}
>+
>+/* 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. */
>+static HRESULT
>+get_str_value(IWbemClassObject *pcls_obj, wchar_t *field_name, wchar_t
>*dest,
>+              int max_dest_lgth)
>+{
>+    VARIANT vt_prop;
>+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
>+
>+    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 */
>+static 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. */
>+static 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. */
>+static 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 */
>+static 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 *
>*/
>+static 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://urldefense.proofpoint.com/v2/url?u=https-3A__msdn.microsoft.com_en
>-2Dus_library_hh850277-2528v-3Dvs.85-2529.aspx&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM6
>7LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dcruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&
>m=1NgcutJOUfLwjikmUhz6W0zVXDR35T75FV8sqiZ8ki8&s=tLEsQhF14PQ5LahGIKh2T8Z5h-
>JPdlzvoU3ecWYc9hg&e=
>+ * 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;
>+
>+    sanitize_port_name(name);
>+    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://urldefense.proofpoint.com/v2/url?u=https-3A__msdn.microsoft.com_en
>-2Dus_library_hh850019-2528v-3Dvs.85-2529.aspx&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM6
>7LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dcruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&
>m=1NgcutJOUfLwjikmUhz6W0zVXDR35T75FV8sqiZ8ki8&s=KtkOaMFPsRkI7S8YEFN7XDLQgu
>UWKnLJ-moHTsCF8Mo&e= .
>+ * 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);
>+    sanitize_port_name(name);
>+
>+    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..28910e7
>--- /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
>+ *
>+ *     
>https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_license
>s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=D
>cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=1NgcutJOUfLwjikmUhz6W0zVXDR35
>T75FV8sqiZ8ki8&s=6YJXIuUkmHpuGcJw64GoPVKdYVnqhnBsGxStg7axmxs&e= 
>+ *
>+ * 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 */
>-- 
>2.9.2.windows.1
>
>_______________________________________________
>dev mailing list
>dev@openvswitch.org
>https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailma
>n_listinfo_dev&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dc
>ruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=1NgcutJOUfLwjikmUhz6W0zVXDR35T
>75FV8sqiZ8ki8&s=YMq7EI4iHIjlQKCYB1Lil7Pq3-80pelN7ZKYA4JvBb4&e=
Gurucharan Shetty Nov. 4, 2016, 2:55 p.m. UTC | #2
On 10 October 2016 at 15:47, Sairam Venugopal <vsairam@vmware.com> wrote:

> Sorry for the delay in the review.
>
> Acked-by: Sairam Venugopal <vsairam@vmware.com>
>

There is a v5 of this series. Would you mind looking at that.


>
>
>
> On 8/12/16, 6:06 PM, "Alin Serdean" <aserdean@cloudbasesolutions.com>
> wrote:
>
> >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_VirtualEthernetSwitchManagemen
> tService
> >  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 <aserdean@cloudbasesolutions.com>
> >Acked-by: Paul Boca <pboca@cloudbasesolutions.com>
> >---
> >v4: address comments (sanitize input, short refactor)
> >    use full stop on comments
> >    update coding style
> >v3: rebase, add acked
> >v2: Address comments. Rebase
> >---
> > appveyor.yml       |    2 +-
> > lib/automake.mk    |    4 +-
> > lib/dpif-netlink.c |   21 +
> > lib/wmi.c          | 1276
> >++++++++++++++++++++++++++++++++++++++++++++++++++++
> > lib/wmi.h          |   51 +++
> > 5 files changed, 1352 insertions(+), 2 deletions(-)
> > create mode 100644 lib/wmi.c
> > create mode 100644 lib/wmi.h
> >
> >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 2faaeac..99bbdc0 100644
> >--- a/lib/automake.mk
> >+++ b/lib/automake.mk
> >@@ -387,7 +387,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 a39faa2..c8b0e37 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..67f0873
> >--- /dev/null
> >+++ b/lib/wmi.c
> >@@ -0,0 +1,1276 @@
> >+/*
> >+ * 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
> >+ *
> >+ *
> >https://urldefense.proofpoint.com/v2/url?u=http-
> 3A__www.apache.org_license
> >s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-
> YihVMNtXt-uEs&r=D
> >cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=
> 1NgcutJOUfLwjikmUhz6W0zVXDR35
> >T75FV8sqiZ8ki8&s=6YJXIuUkmHpuGcJw64GoPVKdYVnqhnBsGxStg7axmxs&e=
> >+ *
> >+ * 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
> >+};
> >+
> >+static char *
> >+sanitize_port_name(char *name)
> >+{
> >+    char *p1, *p2;
> >+    p1 = p2 = name;
> >+
> >+    while (*p1) {
> >+        if ((*p1) == '\'' || (*p1) == '\"') {
> >+            p1++;
> >+        } else {
> >+            *p2 = *p1;
> >+            p2++;
> >+            p1++;
> >+        }
> >+    }
> >+    *p2 = '\0';
> >+    return name;
> >+}
> >+
> >+/* This function will output the appropriate message for a given
> >HRESULT.*/
> >+static void
> >+get_hres_error(HRESULT hres)
> >+{
> >+    char *error_msg = NULL;
> >+
> >+    if (FACILITY_WINDOWS == HRESULT_FACILITY(hres)) {
> >+        hres = HRESULT_CODE(hres);
> >+    }
> >+
> >+    VLOG_ERR("%s", ovs_format_message(hres));
> >+}
> >+
> >+static boolean
> >+check_return_value(HRESULT hres)
> >+{
> >+    if (FAILED(hres)) {
> >+        get_hres_error(hres);
> >+        return false;
> >+    }
> >+
> >+    return true;
> >+}
> >+
> >+static HRESULT
> >+get_variant_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
> >+                  VARIANT *value)
> >+{
> >+    HRESULT hres;
> >+
> >+    VariantInit(value);
> >+
> >+    hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, value, 0, 0);
> >+
> >+    if (FAILED(hres)) {
> >+        VariantClear(value);
> >+    }
> >+
> >+    return hres;
> >+}
> >+
> >+/* This function retrieves the uint16_t value from a given class object
> >with
> >+ * the field name field_name. */
> >+static HRESULT
> >+get_uint16_t_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
> >+                   uint16_t *value)
> >+{
> >+    VARIANT vt_prop;
> >+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
> >+    *value = V_UI2(&vt_prop);
> >+
> >+    return hres;
> >+}
> >+
> >+/* This function retrieves the unsigned int values from a given class
> >object
> >+ * with the field name field_name. */
> >+static HRESULT
> >+get_uint_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
> >+               unsigned int *value)
> >+{
> >+    VARIANT vt_prop;
> >+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
> >+    *value = V_UI4(&vt_prop);
> >+
> >+    return hres;
> >+}
> >+
> >+/* This function retrieves the unsigned short value from a given class
> >object
> >+ * with the field name field_name. */
> >+static HRESULT
> >+get_ushort_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
> >+                 unsigned short *value)
> >+{
> >+    VARIANT vt_prop;
> >+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
> >+    *value = V_UI2(&vt_prop);
> >+
> >+    return hres;
> >+}
> >+
> >+/* 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. */
> >+static HRESULT
> >+get_str_value(IWbemClassObject *pcls_obj, wchar_t *field_name, wchar_t
> >*dest,
> >+              int max_dest_lgth)
> >+{
> >+    VARIANT vt_prop;
> >+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
> >+
> >+    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 */
> >+static 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. */
> >+static 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. */
> >+static 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 */
> >+static 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 *
> >*/
> >+static 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://urldefense.proofpoint.com/v2/url?u=https-
> 3A__msdn.microsoft.com_en
> >-2Dus_library_hh850277-2528v-3Dvs.85-2529.aspx&d=CwIGaQ&c=
> Sqcl0Ez6M0X8aeM6
> >7LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dcruz40PROJ40ROzSpxyQSLw6fcrOW
> pJgEcEmNR3JEQ&
> >m=1NgcutJOUfLwjikmUhz6W0zVXDR35T75FV8sqiZ8ki8&s=
> tLEsQhF14PQ5LahGIKh2T8Z5h-
> >JPdlzvoU3ecWYc9hg&e=
> >+ * 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;
> >+
> >+    sanitize_port_name(name);
> >+    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://urldefense.proofpoint.com/v2/url?u=https-
> 3A__msdn.microsoft.com_en
> >-2Dus_library_hh850019-2528v-3Dvs.85-2529.aspx&d=CwIGaQ&c=
> Sqcl0Ez6M0X8aeM6
> >7LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dcruz40PROJ40ROzSpxyQSLw6fcrOW
> pJgEcEmNR3JEQ&
> >m=1NgcutJOUfLwjikmUhz6W0zVXDR35T75FV8sqiZ8ki8&s=
> KtkOaMFPsRkI7S8YEFN7XDLQgu
> >UWKnLJ-moHTsCF8Mo&e= .
> >+ * 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);
> >+    sanitize_port_name(name);
> >+
> >+    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..28910e7
> >--- /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
> >+ *
> >+ *
> >https://urldefense.proofpoint.com/v2/url?u=http-
> 3A__www.apache.org_license
> >s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-
> YihVMNtXt-uEs&r=D
> >cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=
> 1NgcutJOUfLwjikmUhz6W0zVXDR35
> >T75FV8sqiZ8ki8&s=6YJXIuUkmHpuGcJw64GoPVKdYVnqhnBsGxStg7axmxs&e=
> >+ *
> >+ * 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 */
> >--
> >2.9.2.windows.1
> >
> >_______________________________________________
> >dev mailing list
> >dev@openvswitch.org
> >https://urldefense.proofpoint.com/v2/url?u=http-
> 3A__openvswitch.org_mailma
> >n_listinfo_dev&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-
> YihVMNtXt-uEs&r=Dc
> >ruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=
> 1NgcutJOUfLwjikmUhz6W0zVXDR35T
> >75FV8sqiZ8ki8&s=YMq7EI4iHIjlQKCYB1Lil7Pq3-80pelN7ZKYA4JvBb4&e=
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>
diff mbox

Patch

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 2faaeac..99bbdc0 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -387,7 +387,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 a39faa2..c8b0e37 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..67f0873
--- /dev/null
+++ b/lib/wmi.c
@@ -0,0 +1,1276 @@ 
+/*
+ * 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
+};
+
+static char *
+sanitize_port_name(char *name)
+{
+    char *p1, *p2;
+    p1 = p2 = name;
+
+    while (*p1) {
+        if ((*p1) == '\'' || (*p1) == '\"') {
+            p1++;
+        } else {
+            *p2 = *p1;
+            p2++;
+            p1++;
+        }
+    }
+    *p2 = '\0';
+    return name;
+}
+
+/* This function will output the appropriate message for a given HRESULT.*/
+static void
+get_hres_error(HRESULT hres)
+{
+    char *error_msg = NULL;
+
+    if (FACILITY_WINDOWS == HRESULT_FACILITY(hres)) {
+        hres = HRESULT_CODE(hres);
+    }
+
+    VLOG_ERR("%s", ovs_format_message(hres));
+}
+
+static boolean
+check_return_value(HRESULT hres)
+{
+    if (FAILED(hres)) {
+        get_hres_error(hres);
+        return false;
+    }
+
+    return true;
+}
+
+static HRESULT
+get_variant_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
+                  VARIANT *value)
+{
+    HRESULT hres;
+
+    VariantInit(value);
+
+    hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, value, 0, 0);
+
+    if (FAILED(hres)) {
+        VariantClear(value);
+    }
+
+    return hres;
+}
+
+/* This function retrieves the uint16_t value from a given class object with
+ * the field name field_name. */
+static HRESULT
+get_uint16_t_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
+                   uint16_t *value)
+{
+    VARIANT vt_prop;
+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
+    *value = V_UI2(&vt_prop);
+
+    return hres;
+}
+
+/* This function retrieves the unsigned int values from a given class object
+ * with the field name field_name. */
+static HRESULT
+get_uint_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
+               unsigned int *value)
+{
+    VARIANT vt_prop;
+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
+    *value = V_UI4(&vt_prop); 
+
+    return hres;
+}
+
+/* This function retrieves the unsigned short value from a given class object
+ * with the field name field_name. */
+static HRESULT
+get_ushort_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
+                 unsigned short *value)
+{
+    VARIANT vt_prop;
+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
+    *value = V_UI2(&vt_prop);
+
+    return hres;
+}
+
+/* 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. */
+static HRESULT
+get_str_value(IWbemClassObject *pcls_obj, wchar_t *field_name, wchar_t *dest,
+              int max_dest_lgth)
+{
+    VARIANT vt_prop;
+    HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
+
+    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 */
+static 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. */
+static 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. */
+static 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 */
+static 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 * */
+static 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;
+
+    sanitize_port_name(name);
+    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);
+    sanitize_port_name(name);
+
+    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..28910e7
--- /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 */