[ovs-dev] [PATCH 1/3 v7] Windows: Add internal switch port per OVS bridge
Sairam Venugopal
vsairam at vmware.com
Tue Dec 20 05:56:08 UTC 2016
Thanks for the patch!
Acked-by: Sairam Venugopal <vsairam at vmware.com>
On 12/15/16, 11:37 AM, "Alin Serdean" <aserdean at 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, 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_license
>s_LICENSE-2D2.0&d=DgICAg&c=uilaK90D4TOVoH58JNXRgQ&r=Z6vowHUOjP5ysP_g372c49
>Nqc1vEKqHKNBkR5Q5Z7uo&m=bdxpwofizlzMhsYoOZoiq0yLJLSasRgmPwO00fUs_FY&s=wMJX
>-nHXxCR4etVk9vFL5012RjwlTwObSTej5EdAIj8&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=uilaK90D4TOVoH58
>JNXRgQ&r=Z6vowHUOjP5ysP_g372c49Nqc1vEKqHKNBkR5Q5Z7uo&m=bdxpwofizlzMhsYoOZo
>iq0yLJLSasRgmPwO00fUs_FY&s=5cNHlXFRz5CeSD8wnl8KO5qKM4zkrvWQEmWVetfmHXc&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=uilaK90D4TOVoH58
>JNXRgQ&r=Z6vowHUOjP5ysP_g372c49Nqc1vEKqHKNBkR5Q5Z7uo&m=bdxpwofizlzMhsYoOZo
>iq0yLJLSasRgmPwO00fUs_FY&s=zo6KU4Q0m2GJznJY9FUdNwGV8t0bOMMVIg0v5hl3nCE&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_license
>s_LICENSE-2D2.0&d=DgICAg&c=uilaK90D4TOVoH58JNXRgQ&r=Z6vowHUOjP5ysP_g372c49
>Nqc1vEKqHKNBkR5Q5Z7uo&m=bdxpwofizlzMhsYoOZoiq0yLJLSasRgmPwO00fUs_FY&s=wMJX
>-nHXxCR4etVk9vFL5012RjwlTwObSTej5EdAIj8&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=Z6vowHUOjP5
>ysP_g372c49Nqc1vEKqHKNBkR5Q5Z7uo&m=bdxpwofizlzMhsYoOZoiq0yLJLSasRgmPwO00fU
>s_FY&s=JM_StZiIrKaEqKV_MWk7SV-gvsyILF64dom-_br1dKk&e=
More information about the dev
mailing list