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

Shashank Ram rams at vmware.com
Thu Dec 15 19:45:36 UTC 2016


Hi Alin, please find my comments inline.

Thanks,
Shashank

________________________________
From: ovs-dev-bounces at openvswitch.org <ovs-dev-bounces at openvswitch.org> on behalf of Alin Serdean <aserdean at cloudbasesolutions.com>
Sent: Thursday, December 15, 2016 11:36 AM
To: dev at openvswitch.org
Subject: [ovs-dev] [PATCH 1/3 v7] Windows: Add internal switch port per OVS bridge

This patch updates the following commands in the vswitch:
 ovs-vsctl add-br br-test
 ovs-vsctl del-br br-test

ovs-vsctl add-br br-test:
---> Shashank: This command should not change its current behavior. Internal ports should only be created if "--set interface type=internal" is set for the port in the interface table.

    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
--> Shashank: The MSFT internal port should only be removed if the interface type=internal.

    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, Windows 2012r2, Windows 2016

Signed-off-by: Alin Gabriel Serdean <aserdean at cloudbasesolutions.com>
Acked-by: Paul Boca <pboca at cloudbasesolutions.com>
---
v7: rebase
v6: rebase
v5: rebase
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          | 1277 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/wmi.h          |   51 +++
 5 files changed, 1353 insertions(+), 2 deletions(-)
 create mode 100644 lib/wmi.c
 create mode 100644 lib/wmi.h

diff --git a/appveyor.yml b/appveyor.yml
index 8a6694b..51bae11 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 9345cee..88344a3 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -388,7 +388,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..e38b482
--- /dev/null
+++ b/lib/wmi.c
@@ -0,0 +1,1277 @@
+/*
+ * 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_licenses_LICENSE-2D2.0&d=DgICAg&c=uilaK90D4TOVoH58JNXRgQ&r=6OuVHk-mnufSWzkKa74UkQ&m=C1ytHFQ6khqvTL5ztfCvNDaZn3b5bl9HB5UYIBGx81o&s=bJkum8IoOFlI_xbzzQMSJfZdHUFHoXeQyLwnPa6djOU&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 "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=DgICAg&c=uilaK90D4TOVoH58JNXRgQ&r=6OuVHk-mnufSWzkKa74UkQ&m=C1ytHFQ6khqvTL5ztfCvNDaZn3b5bl9HB5UYIBGx81o&s=-n5mqz8qriq--jPE_R8otTOcjDOnnft8beYmi27IO4M&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=DgICAg&c=uilaK90D4TOVoH58JNXRgQ&r=6OuVHk-mnufSWzkKa74UkQ&m=C1ytHFQ6khqvTL5ztfCvNDaZn3b5bl9HB5UYIBGx81o&s=xwnSYaCmIX5HfuMQbxK_YWdEvX9X_lAn8z8YZXTvE0I&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;
+
+    /* Should be enough to give the InstanceID, from msdn documentation:
+     * Uniquely identifies an instance of this class. This property is
+     * inherited from CIM_SettingData and is always
+     * set to "Microsoft:GUID\DeviceSpecificData". */
+    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"\"");
+
+    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.
+     * Instead of querying using Description, we can query using InstallDate.
+     * From MSDN documentation regarding InstallDate:
+     * The date and time the virtual machine configuration was created for
+     * a virtual machine, or Null, for a management operating system. */
+    hres = psvc->lpVtbl->ExecQuery(psvc,
+                                   L"WQL",
+                                   L"SELECT * FROM Msvm_ComputerSystem WHERE "
+                                   L"InstallDate is NULL",
+                                   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_licenses_LICENSE-2D2.0&d=DgICAg&c=uilaK90D4TOVoH58JNXRgQ&r=6OuVHk-mnufSWzkKa74UkQ&m=C1ytHFQ6khqvTL5ztfCvNDaZn3b5bl9HB5UYIBGx81o&s=bJkum8IoOFlI_xbzzQMSJfZdHUFHoXeQyLwnPa6djOU&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.10.2.windows.1

_______________________________________________
dev mailing list
dev at openvswitch.org
https://urldefense.proofpoint.com/v2/url?u=https-3A__mail.openvswitch.org_mailman_listinfo_ovs-2Ddev&d=DgICAg&c=uilaK90D4TOVoH58JNXRgQ&r=6OuVHk-mnufSWzkKa74UkQ&m=C1ytHFQ6khqvTL5ztfCvNDaZn3b5bl9HB5UYIBGx81o&s=UQ1ymPSH4d6DjlawSgm5AJeRnsoKpIc8IQvgZxVRLKo&e=


More information about the dev mailing list