2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 18:07:40 +00:00
ovs/lib/wmi.c

1273 lines
37 KiB
C
Raw Normal View History

Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
/*
* 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 "openvswitch/vlog.h"
#include "util.h"
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
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;
}
#define WMI_QUERY_COUNT 2048
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
/* 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[WMI_QUERY_COUNT] = L"SELECT * from "
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
L"Msvm_EthernetPortAllocationSettingData WHERE ElementName = \"" ;
wide_name = xmalloc((strlen(name) + 1) * sizeof(wchar_t));
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
if (!tranform_wide(name, wide_name)) {
retval = false;
goto error;
}
wcscat_s(internal_port_query, WMI_QUERY_COUNT, wide_name);
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
wcscat_s(internal_port_query, WMI_QUERY_COUNT, L"\"");
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
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;
}
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
/* 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[WMI_QUERY_COUNT] = L"SELECT * FROM "
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
L"Msvm_InternalEthernetPort WHERE ElementName = \"";
wide_name = xmalloc((strlen(name) + 1) * sizeof(wchar_t));
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
if (!tranform_wide(name, wide_name)) {
retval = false;
goto error;
}
wcscat_s(internal_port_query, WMI_QUERY_COUNT, wide_name);
wcscat_s(internal_port_query, WMI_QUERY_COUNT, L"\"");
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
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, WMI_QUERY_COUNT,
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
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, WMI_QUERY_COUNT,
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
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, WMI_QUERY_COUNT, L"\"");
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
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, WMI_QUERY_COUNT,
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
L"SELECT * FROM Msvm_VirtualEthernetSwitchSettingData WHERE "
L"ElementName = \"");
wcscat_s(internal_port_query, WMI_QUERY_COUNT,
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
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, WMI_QUERY_COUNT,
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
L"\" AND InstanceID = \"Microsoft:");
wcscat_s(internal_port_query, WMI_QUERY_COUNT,
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
vt_prop.bstrVal);
wcscat_s(internal_port_query, WMI_QUERY_COUNT,
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
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, WMI_QUERY_COUNT,
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
L"SELECT * FROM MSFT_NetAdapter WHERE Name LIKE '%%");
wcscat_s(internal_port_query, WMI_QUERY_COUNT, wide_name);
wcscat_s(internal_port_query, WMI_QUERY_COUNT, L"%%'");
Windows: Add internal switch port per OVS bridge This patch updates the following commands in the vswitch: ovs-vsctl add-br br-test ovs-vsctl del-br br-test ovs-vsctl add-br br-test: This command will now create an internal port on the MSFT virtual switch using the WMI interface from Msvm_VirtualEthernetSwitchManagementService leveraging the method AddResourceSettings. Before creating the actual port, the switch will be queried to see if there is not a port already created (good for restarts when restarting the vswitch daemon). If there is a port defined it will return success and log a message. After checking if the port already exists the command will also verify if the forwarding extension (windows datapath) is enabled and on a single switch. If it is not activated or if it is activated on multiple switches it will return an error and a message will be logged. After the port was created on the switch, we will disable the adapter on the host and rename to the corresponding OVS bridge name for consistency. The user will enable and set the values he wants after creation. ovs-vsctl del-br br-test This command will remove an internal port on the MSFT virtual switch using the Msvm_VirtualEthernetSwitchManagementService class and executing the method RemoveResourceSettings. Both commands will be blocking until the WMI job is finished, this allows us to guarantee that the ports are created and their name are set before issuing a netlink message to the windows datapath. This patch also includes helpers for normal WMI retrievals and initializations. Appveyor and documentation has been modified to include the libraries needed for COM objects. This patch was tested individually using IMallocSpy and CRT heap checks to ensure no new memory leaks are introduced. Tested on the following OS's: Windows 2012, Windows 2012r2, Windows 2016 Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Paul Boca <pboca@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
2016-12-20 19:41:22 +00:00
/* 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;
}