[ovs-dev,RFC,v1,3/3] windows: Allow add/delete ports via HNS API

Message ID 20181008232716.28296-1-aserdean@ovn.org
State New
Headers show
Series
  • [ovs-dev,RFC,v1,1/3] datapath-windows: Introduce HNS OVS calls
Related show

Commit Message

Alin Gabriel Serdean Oct. 8, 2018, 11:27 p.m.
On Windows 2016 LTSC(RTM) the Container feature and Hyper-V feature both had
DCOM API to add and delete internal (management) ports on the Hyper-V switch.

Starting from the 1703 release and above, enabling only the Container feature
does not fulfil this requirement anymore.

We need new ways to interact with the host API without the Hyper-V integration.

Unfortunately, there is no C API for it, only golang and .net:
https://github.com/Microsoft/hcsshim (golang)
https://github.com/microsoft/dotnet-computevirtualization (.net)
It is also poorly documented and reserved.

Although not pretty and less performant, this will provide a way to
add/delete and query the new APIs across different versions of Windows,
until new API's or documentation are available.

Signed-off-by: Alin Gabriel Serdean <aserdean@ovn.org>
---
 lib/wmi.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 91 insertions(+), 4 deletions(-)

Comments

Sairam Venugopal Oct. 19, 2018, 9:54 p.m. | #1
Can't you use CreateProcess or _popen to trigger the script/function directly?

Thanks,
Sairam

´╗┐On 10/8/18, 4:28 PM, "ovs-dev-bounces@openvswitch.org on behalf of Alin Gabriel Serdean" <ovs-dev-bounces@openvswitch.org on behalf of aserdean@ovn.org> wrote:

    On Windows 2016 LTSC(RTM) the Container feature and Hyper-V feature both had
    DCOM API to add and delete internal (management) ports on the Hyper-V switch.
    
    Starting from the 1703 release and above, enabling only the Container feature
    does not fulfil this requirement anymore.
    
    We need new ways to interact with the host API without the Hyper-V integration.
    
    Unfortunately, there is no C API for it, only golang and .net:
    https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FMicrosoft%2Fhcsshim&amp;data=02%7C01%7Cvsairam%40vmware.com%7C1601769abfd64a60b41708d62d75af52%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C1%7C0%7C636746380831225713&amp;sdata=pvCJPIt%2FOhVeth4fC22%2BlawFM0jvFPOQBFL6xMdvV6o%3D&amp;reserved=0 (golang)
    https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fmicrosoft%2Fdotnet-computevirtualization&amp;data=02%7C01%7Cvsairam%40vmware.com%7C1601769abfd64a60b41708d62d75af52%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C1%7C0%7C636746380831225713&amp;sdata=hVO%2B6%2BwjL8ZpklKGb6Ti2WA4dS2p20%2Bwy%2BfqS%2BPPCC0%3D&amp;reserved=0 (.net)
    It is also poorly documented and reserved.
    
    Although not pretty and less performant, this will provide a way to
    add/delete and query the new APIs across different versions of Windows,
    until new API's or documentation are available.
    
    Signed-off-by: Alin Gabriel Serdean <aserdean@ovn.org>
    ---
     lib/wmi.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
     1 file changed, 91 insertions(+), 4 deletions(-)
    
    diff --git a/lib/wmi.c b/lib/wmi.c
    index e6dc63cde..14451d591 100644
    --- a/lib/wmi.c
    +++ b/lib/wmi.c
    @@ -203,6 +203,93 @@ wait_for_job(IWbemServices *psvc, wchar_t *job_path)
         return retval;
     }
     
    +static boolean
    +hns_delete(char *name)
    +{
    +    VLOG_DBG("Trying to delete port via HNS API");
    +    char buffer[10000];
    +    int count;
    +    count = snprintf(buffer, 10000, "-NoLogo -NoProfile -NonInteractive"
    +                     "-Command \"try {Delete-OVSHNSInternalPort '%s'}"
    +                     "catch { exit 1 }; exit 0; \"", name);
    +    if (count < 0 || count > 10000) {
    +        VLOG_WARN("Could not allocate memory for powershell delete command");
    +        return false;
    +    }
    +    VLOG_DBG("command = %s", buffer);
    +    DWORD res = 0;
    +    SHELLEXECUTEINFOA ShExecInfo;
    +    ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
    +    ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
    +    ShExecInfo.hwnd = NULL;
    +    ShExecInfo.lpVerb = NULL;
    +    ShExecInfo.lpFile = "powershell.exe";
    +    ShExecInfo.lpParameters = buffer;
    +    ShExecInfo.lpDirectory = NULL;
    +    ShExecInfo.nShow = SW_HIDE;
    +    ShExecInfo.hInstApp = NULL;
    +    ShellExecuteExA(&ShExecInfo);
    +    WaitForSingleObject(ShExecInfo.hProcess, 50000);
    +    if (GetExitCodeProcess(ShExecInfo.hProcess, &res)) {
    +        if (res != 0) {
    +            VLOG_ERR("Powershell delete command failed with exit code: %d",
    +                     res);
    +            CloseHandle(ShExecInfo.hProcess);
    +            return false;
    +        }
    +    } else {
    +        VLOG_ERR("Failed to get exit code for powershell delete command."
    +                 "Last Error: %s", ovs_lasterror_to_string());
    +        CloseHandle(ShExecInfo.hProcess);
    +        return false;
    +    }
    +    CloseHandle(ShExecInfo.hProcess);
    +    return true;
    +}
    +
    +static boolean
    +hns_add(char *name)
    +{
    +    VLOG_WARN("Trying to add port via HNS API");
    +    char buffer[10000];
    +    int count;
    +    count = snprintf(buffer, 10000, "-NoLogo -NoProfile -NonInteractive"
    +                     "-Command \"try {Add-OVSHNSInternalPort '%s'}"
    +                     "catch { exit 1 }; exit 0; \"", name);
    +    if (count < 0 || count > 10000) {
    +        VLOG_WARN("Could not allocate memory for powershell add command");
    +        return false;
    +    }
    +    VLOG_WARN("command = %s", buffer);
    +    DWORD res = 0;
    +    SHELLEXECUTEINFOA ShExecInfo;
    +    ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
    +    ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
    +    ShExecInfo.hwnd = NULL;
    +    ShExecInfo.lpVerb = NULL;
    +    ShExecInfo.lpFile = "powershell.exe";
    +    ShExecInfo.lpParameters = buffer;
    +    ShExecInfo.lpDirectory = NULL;
    +    ShExecInfo.nShow = SW_HIDE;
    +    ShExecInfo.hInstApp = NULL;
    +    ShellExecuteExA(&ShExecInfo);
    +    WaitForSingleObject(ShExecInfo.hProcess, 50000);
    +    if (GetExitCodeProcess(ShExecInfo.hProcess, &res)) {
    +        if (res != 0) {
    +            VLOG_ERR("Powershell add command failed with exit code: %d", res);
    +            CloseHandle(ShExecInfo.hProcess);
    +            return false;
    +        }
    +    } else {
    +        VLOG_ERR("Failed to get exit code for powershell add command."
    +                 "Last Error: %s", ovs_lasterror_to_string());
    +        CloseHandle(ShExecInfo.hProcess);
    +        return false;
    +    }
    +    CloseHandle(ShExecInfo.hProcess);
    +    return true;
    +}
    +
     /* This function will initialize DCOM retrieving the WMI locator's ploc and
      * the context associated to it. */
     static boolean
    @@ -390,14 +477,14 @@ delete_wmi_port(char *name)
     
         if (!initialize_wmi(&ploc, &pcontext)) {
             VLOG_WARN("Could not initialize DCOM");
    -        retval = false;
    +        retval = hns_delete(name);
             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;
    +        retval = hns_delete(name);
             goto error;
         }
     
    @@ -673,14 +760,14 @@ create_wmi_port(char *name) {
     
         if (!initialize_wmi(&ploc, &pcontext)) {
             VLOG_WARN("Could not initialize DCOM");
    -        retval = false;
    +        retval = hns_add(name);
             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;
    +        retval = hns_add(name);
             goto error;
         }
     
    -- 
    2.16.1.windows.1
    
    _______________________________________________
    dev mailing list
    dev@openvswitch.org
    https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.openvswitch.org%2Fmailman%2Flistinfo%2Fovs-dev&amp;data=02%7C01%7Cvsairam%40vmware.com%7C1601769abfd64a60b41708d62d75af52%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C1%7C0%7C636746380831225713&amp;sdata=ENIy91c7o4BLQvdG9%2BacFlBs5%2FUJFm%2FJmI081nu6SSg%3D&amp;reserved=0

Patch

diff --git a/lib/wmi.c b/lib/wmi.c
index e6dc63cde..14451d591 100644
--- a/lib/wmi.c
+++ b/lib/wmi.c
@@ -203,6 +203,93 @@  wait_for_job(IWbemServices *psvc, wchar_t *job_path)
     return retval;
 }
 
+static boolean
+hns_delete(char *name)
+{
+    VLOG_DBG("Trying to delete port via HNS API");
+    char buffer[10000];
+    int count;
+    count = snprintf(buffer, 10000, "-NoLogo -NoProfile -NonInteractive"
+                     "-Command \"try {Delete-OVSHNSInternalPort '%s'}"
+                     "catch { exit 1 }; exit 0; \"", name);
+    if (count < 0 || count > 10000) {
+        VLOG_WARN("Could not allocate memory for powershell delete command");
+        return false;
+    }
+    VLOG_DBG("command = %s", buffer);
+    DWORD res = 0;
+    SHELLEXECUTEINFOA ShExecInfo;
+    ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
+    ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
+    ShExecInfo.hwnd = NULL;
+    ShExecInfo.lpVerb = NULL;
+    ShExecInfo.lpFile = "powershell.exe";
+    ShExecInfo.lpParameters = buffer;
+    ShExecInfo.lpDirectory = NULL;
+    ShExecInfo.nShow = SW_HIDE;
+    ShExecInfo.hInstApp = NULL;
+    ShellExecuteExA(&ShExecInfo);
+    WaitForSingleObject(ShExecInfo.hProcess, 50000);
+    if (GetExitCodeProcess(ShExecInfo.hProcess, &res)) {
+        if (res != 0) {
+            VLOG_ERR("Powershell delete command failed with exit code: %d",
+                     res);
+            CloseHandle(ShExecInfo.hProcess);
+            return false;
+        }
+    } else {
+        VLOG_ERR("Failed to get exit code for powershell delete command."
+                 "Last Error: %s", ovs_lasterror_to_string());
+        CloseHandle(ShExecInfo.hProcess);
+        return false;
+    }
+    CloseHandle(ShExecInfo.hProcess);
+    return true;
+}
+
+static boolean
+hns_add(char *name)
+{
+    VLOG_WARN("Trying to add port via HNS API");
+    char buffer[10000];
+    int count;
+    count = snprintf(buffer, 10000, "-NoLogo -NoProfile -NonInteractive"
+                     "-Command \"try {Add-OVSHNSInternalPort '%s'}"
+                     "catch { exit 1 }; exit 0; \"", name);
+    if (count < 0 || count > 10000) {
+        VLOG_WARN("Could not allocate memory for powershell add command");
+        return false;
+    }
+    VLOG_WARN("command = %s", buffer);
+    DWORD res = 0;
+    SHELLEXECUTEINFOA ShExecInfo;
+    ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
+    ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
+    ShExecInfo.hwnd = NULL;
+    ShExecInfo.lpVerb = NULL;
+    ShExecInfo.lpFile = "powershell.exe";
+    ShExecInfo.lpParameters = buffer;
+    ShExecInfo.lpDirectory = NULL;
+    ShExecInfo.nShow = SW_HIDE;
+    ShExecInfo.hInstApp = NULL;
+    ShellExecuteExA(&ShExecInfo);
+    WaitForSingleObject(ShExecInfo.hProcess, 50000);
+    if (GetExitCodeProcess(ShExecInfo.hProcess, &res)) {
+        if (res != 0) {
+            VLOG_ERR("Powershell add command failed with exit code: %d", res);
+            CloseHandle(ShExecInfo.hProcess);
+            return false;
+        }
+    } else {
+        VLOG_ERR("Failed to get exit code for powershell add command."
+                 "Last Error: %s", ovs_lasterror_to_string());
+        CloseHandle(ShExecInfo.hProcess);
+        return false;
+    }
+    CloseHandle(ShExecInfo.hProcess);
+    return true;
+}
+
 /* This function will initialize DCOM retrieving the WMI locator's ploc and
  * the context associated to it. */
 static boolean
@@ -390,14 +477,14 @@  delete_wmi_port(char *name)
 
     if (!initialize_wmi(&ploc, &pcontext)) {
         VLOG_WARN("Could not initialize DCOM");
-        retval = false;
+        retval = hns_delete(name);
         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;
+        retval = hns_delete(name);
         goto error;
     }
 
@@ -673,14 +760,14 @@  create_wmi_port(char *name) {
 
     if (!initialize_wmi(&ploc, &pcontext)) {
         VLOG_WARN("Could not initialize DCOM");
-        retval = false;
+        retval = hns_add(name);
         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;
+        retval = hns_add(name);
         goto error;
     }