Message ID | 20181008232602.30924-1-aserdean@ovn.org |
---|---|
State | Changes Requested |
Headers | show |
Series | [ovs-dev,RFC,v1,1/3] datapath-windows: Introduce HNS OVS calls | expand |
Hi Alin,
Since the hns.psm1 isn't officially supported by Microsoft, is it safe to use the script as part of the OVS repo? Also, "Invoke-HNSRequest" isn't officially documented at this time. I understand that this is an RFC, but do you know if Microsoft plans to finalize this api? If not, I would suggest keeping hns.psm1 out of the OVS repo and instead assume that the end-user has access to it. Otherwise, OVS will need to keep parity with the script in Microsoft's project.
Thanks,
Sairam
On 10/8/18, 4:26 PM, "ovs-dev-bounces@openvswitch.org on behalf of Alin Gabriel Serdean" <ovs-dev-bounces@openvswitch.org on behalf of aserdean@ovn.org> wrote:
We introduce a new powershell module for interacting with HNS (host network service):
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FMicrosoft%2FSDN%2Fblob%2Fmaster%2FKubernetes%2Fwindows%2Fhns.psm1&data=02%7C01%7Cvsairam%40vmware.com%7Cd3d913f61b40483be5c808d62d757f34%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C1%7C0%7C636746380042797946&sdata=rh%2FrirPPKSOUGvrHUhV36M2f83JUFX%2FkbGSCy%2FBvb%2BM%3D&reserved=0
In our repository this shall be named HNSHelper.psm1.
We also add five new commandlets in our OVS powershell module:
Disable-OVSOnHNSNetwork - disable OVS extension on a given HNS network.
Enable-OVSOnHNSNetwork - enable OVS extension on a given HNS network.
Get-OVSEnabledHNSNetworks - return the HNS network on which OVS is enabled.
Add-OVSHNSInternalPort - will add a new internal port with he name: `name`, on
the HNS network, which has OVS enabled. This port
shall use the host compartment.
Delete-OVSHNSInternalPort - will delete an internal port with name: `name` on a
HNS network which has OVS enabled.
Signed-off-by: Alin Gabriel Serdean <aserdean@ovn.org>
---
datapath-windows/automake.mk | 1 +
datapath-windows/misc/HNSHelper.psm1 | 499 +++++++++++++++++++++++++++++++++++
datapath-windows/misc/OVS.psm1 | 79 +++++-
3 files changed, 578 insertions(+), 1 deletion(-)
create mode 100644 datapath-windows/misc/HNSHelper.psm1
diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk
index 3820041f6..d98ab3c60 100644
--- a/datapath-windows/automake.mk
+++ b/datapath-windows/automake.mk
@@ -3,6 +3,7 @@ EXTRA_DIST += \
datapath-windows/Package/package.VcxProj.user \
datapath-windows/include/OvsDpInterfaceExt.h \
datapath-windows/include/OvsDpInterfaceCtExt.h \
+ datapath-windows/misc/HNSHelper.psm1 \
datapath-windows/misc/OVS.psm1 \
datapath-windows/misc/install.cmd \
datapath-windows/misc/uninstall.cmd \
diff --git a/datapath-windows/misc/HNSHelper.psm1 b/datapath-windows/misc/HNSHelper.psm1
new file mode 100644
index 000000000..ac99889cf
--- /dev/null
+++ b/datapath-windows/misc/HNSHelper.psm1
@@ -0,0 +1,499 @@
+# SDN Sample Scripts v.1.0
+#
+# Copyright (c) Microsoft Corporation
+#
+# All rights reserved.
+#
+# MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the ""Software""), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+#########################################################################
+# Global Initialize
+function Get-VmComputeNativeMethods()
+{
+ $signature = @'
+ [DllImport("vmcompute.dll")]
+ public static extern void HNSCall([MarshalAs(UnmanagedType.LPWStr)] string method, [MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPWStr)] string request, [MarshalAs(UnmanagedType.LPWStr)] out string response);
+'@
+
+ # Compile into runtime type
+ try { return [VmCompute.PrivatePInvoke.NativeMethods] }
+ catch { return (Add-Type -MemberDefinition $signature -Namespace VmCompute.PrivatePInvoke -Name NativeMethods -PassThru) }
+}
+
+#########################################################################
+# Configuration
+#########################################################################
+function Get-HnsSwitchExtensions
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [string] $NetworkId
+ )
+
+ return (Get-HNSNetwork $NetworkId).Extensions
+}
+
+function Set-HnsSwitchExtension
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [string] $NetworkId,
+ [parameter(Mandatory=$true)] [string] $ExtensionId,
+ [parameter(Mandatory=$true)] [bool] $state
+ )
+
+ # { "Extensions": [ { "Id": "...", "IsEnabled": true|false } ] }
+ $req = @{
+ "Extensions"=@(@{
+ "Id"=$ExtensionId;
+ "IsEnabled"=$state;
+ };)
+ }
+ Invoke-HNSRequest -Method POST -Type networks -Id $NetworkId -Data (ConvertTo-Json $req)
+}
+
+#########################################################################
+# Activities
+#########################################################################
+function Get-HNSActivities
+{
+ [cmdletbinding()]Param()
+ return Invoke-HNSRequest -Type activities -Method GET
+}
+
+#########################################################################
+# PolicyLists
+#########################################################################
+function Get-HNSPolicyList {
+ [cmdletbinding()]Param()
+ return Invoke-HNSRequest -Type policylists -Method GET
+}
+
+function Remove-HnsPolicyList
+{
+ [CmdletBinding()]
+ param
+ (
+ [parameter(Mandatory=$true,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
+ [Object[]] $InputObjects
+ )
+ begin {$Objects = @()}
+ process {$Objects += $InputObjects; }
+ end {
+ $Objects | foreach { Invoke-HNSRequest -Method DELETE -Type policylists -Id $_.Id }
+ }
+}
+
+function New-HnsRoute {
+ param
+ (
+ [parameter(Mandatory = $false)] [Guid[]] $Endpoints = $null,
+ [parameter(Mandatory = $true)] [string] $DestinationPrefix,
+ [parameter(Mandatory = $false)] [switch] $EncapEnabled
+ )
+
+ $policyLists = @{
+ References = @(
+ get-endpointReferences $Endpoints;
+ );
+ Policies = @(
+ @{
+ Type = "ROUTE";
+ DestinationPrefix = $DestinationPrefix;
+ NeedEncap = $EncapEnabled.IsPresent;
+ }
+ );
+ }
+
+ Invoke-HNSRequest -Method POST -Type policylists -Data (ConvertTo-Json $policyLists -Depth 10)
+}
+
+function New-HnsLoadBalancer {
+ param
+ (
+ [parameter(Mandatory = $false)] [Guid[]] $Endpoints = $null,
+ [parameter(Mandatory = $true)] [int] $InternalPort,
+ [parameter(Mandatory = $true)] [int] $ExternalPort,
+ [parameter(Mandatory = $false)] [string] $Vip
+ )
+
+ $policyLists = @{
+ References = @(
+ get-endpointReferences $Endpoints;
+ );
+ Policies = @(
+ @{
+ Type = "ELB";
+ InternalPort = $InternalPort;
+ ExternalPort = $ExternalPort;
+ VIPs = @($Vip);
+ }
+ );
+ }
+
+ Invoke-HNSRequest -Method POST -Type policylists -Data ( ConvertTo-Json $policyLists -Depth 10)
+}
+
+
+function get-endpointReferences {
+ param
+ (
+ [parameter(Mandatory = $true)] [Guid[]] $Endpoints = $null
+ )
+ if ($Endpoints ) {
+ $endpointReference = @()
+ foreach ($endpoint in $Endpoints)
+ {
+ $endpointReference += "/endpoints/$endpoint"
+ }
+ return $endpointReference
+ }
+ return @()
+}
+
+#########################################################################
+# Networks
+#########################################################################
+function New-HnsNetwork
+{
+ param
+ (
+ [parameter(Mandatory=$false, Position=0)]
+ [string] $JsonString,
+ [ValidateSet('ICS', 'Internal', 'Transparent', 'NAT', 'Overlay', 'L2Bridge', 'L2Tunnel', 'Layered', 'Private')]
+ [parameter(Mandatory = $false, Position = 0)]
+ [string] $Type,
+ [parameter(Mandatory = $false)] [string] $Name,
+ [parameter(Mandatory = $false)] [string] $AddressPrefix,
+ [parameter(Mandatory = $false)] [string] $Gateway,
+ [parameter(Mandatory = $false)] [string] $DNSServer,
+ [parameter(Mandatory = $false)] [string] $AdapterName
+ )
+
+ Begin {
+ if (!$JsonString) {
+ $netobj = @{
+ Type = $Type;
+ };
+
+ if ($Name) {
+ $netobj += @{
+ Name = $Name;
+ }
+ }
+
+ if ($AddressPrefix -and $Gateway) {
+ $netobj += @{
+ Subnets = @(
+ @{
+ AddressPrefix = $AddressPrefix;
+ GatewayAddress = $Gateway;
+ }
+ );
+ }
+ }
+
+ if ($DNSServerName) {
+ $netobj += @{
+ DNSServerList = $DNSServer
+ }
+ }
+
+ if ($AdapterName) {
+ $netobj += @{
+ NetworkAdapterName = $AdapterName;
+ }
+ }
+
+ $JsonString = ConvertTo-Json $netobj -Depth 10
+ }
+
+ }
+ Process{
+ return Invoke-HNSRequest -Method POST -Type networks -Data $JsonString
+ }
+}
+
+#########################################################################
+# Endpoints
+#########################################################################
+function New-HnsEndpoint
+{
+ param
+ (
+ [parameter(Mandatory=$false, Position = 0)] [string] $JsonString = $null,
+ [parameter(Mandatory = $false, Position = 0)] [Guid] $NetworkId,
+ [parameter(Mandatory = $false)] [string] $Name,
+ [parameter(Mandatory = $false)] [string] $IPAddress,
+ [parameter(Mandatory = $false)] [string] $Gateway,
+ [parameter(Mandatory = $false)] [string] $MacAddress,
+ [parameter(Mandatory = $false)] [switch] $EnableOutboundNat
+ )
+
+ begin
+ {
+ if ($JsonString)
+ {
+ $EndpointData = $JsonString | ConvertTo-Json | ConvertFrom-Json
+ }
+ else
+ {
+ $endpoint = @{
+ VirtualNetwork = $NetworkId;
+ Policies = @();
+ }
+
+ if ($Name) {
+ $endpoint += @{
+ Name = $Name;
+ }
+ }
+
+ if ($MacAddress) {
+ $endpoint += @{
+ MacAddress = $MacAddress;
+ }
+ }
+
+ if ($IPAddress) {
+ $endpoint += @{
+ IPAddress = $IPAddress;
+ }
+ }
+
+ if ($Gateway) {
+ $endpoint += @{
+ GatewayAddress = $Gateway;
+ }
+ }
+
+ if ($EnableOutboundNat) {
+ $endpoint.Policies += @{
+ Type = "OutBoundNAT";
+ }
+
+ }
+ # Try to Generate the data
+ $EndpointData = convertto-json $endpoint
+ }
+ }
+
+ Process
+ {
+ return Invoke-HNSRequest -Method POST -Type endpoints -Data $EndpointData
+ }
+}
+
+
+function New-HnsRemoteEndpoint
+{
+ param
+ (
+ [parameter(Mandatory = $true)] [Guid] $NetworkId,
+ [parameter(Mandatory = $false)] [string] $IPAddress,
+ [parameter(Mandatory = $false)] [string] $MacAddress
+ )
+
+ $remoteEndpoint = @{
+ ID = [Guid]::NewGuid();
+ VirtualNetwork = $NetworkId;
+ IPAddress = $IPAddress;
+ MacAddress = $MacAddress;
+ IsRemoteEndpoint = $true;
+ }
+
+ return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $remoteEndpoint -Depth 10)
+
+}
+
+
+function Attach-HnsHostEndpoint
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [Guid] $EndpointID,
+ [parameter(Mandatory=$true)] [int] $CompartmentID
+ )
+ $request = @{
+ SystemType = "Host";
+ CompartmentId = $CompartmentID;
+ };
+
+ return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request) -Action "attach" -Id $EndpointID
+}
+
+function Attach-HNSVMEndpoint
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [Guid] $EndpointID,
+ [parameter(Mandatory=$true)] [string] $VMNetworkAdapterName
+ )
+
+ $request = @{
+ VirtualNicName = $VMNetworkAdapterName;
+ SystemType = "VirtualMachine";
+ };
+ return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request ) -Action "attach" -Id $EndpointID
+
+}
+
+function Attach-HNSEndpoint
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [Guid] $EndpointID,
+ [parameter(Mandatory=$true)] [int] $CompartmentID,
+ [parameter(Mandatory=$true)] [string] $ContainerID
+ )
+ $request = @{
+ ContainerId = $ContainerID;
+ SystemType="Container";
+ CompartmentId = $CompartmentID;
+ };
+
+ return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request) -Action "attach" -Id $EndpointID
+}
+
+function Detach-HNSVMEndpoint
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [Guid] $EndpointID
+ )
+ $request = @{
+ SystemType = "VirtualMachine";
+ };
+
+ return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request ) -Action "detach" -Id $EndpointID
+}
+
+function Detach-HNSHostEndpoint
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [Guid] $EndpointID
+ )
+ $request = @{
+ SystemType = "Host";
+ };
+
+ return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request ) -Action "detach" -Id $EndpointID
+}
+
+function Detach-HNSEndpoint
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [Guid] $EndpointID,
+ [parameter(Mandatory=$true)] [string] $ContainerID
+ )
+
+ $request = @{
+ ContainerId = $ContainerID;
+ SystemType="Container";
+ };
+
+ return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request ) -Action "detach" -Id $EndpointID
+}
+#########################################################################
+
+function Invoke-HNSRequest
+{
+ param
+ (
+ [ValidateSet('GET', 'POST', 'DELETE')]
+ [parameter(Mandatory=$true)] [string] $Method,
+ [ValidateSet('networks', 'endpoints', 'activities', 'policylists', 'endpointstats', 'plugins')]
+ [parameter(Mandatory=$true)] [string] $Type,
+ [parameter(Mandatory=$false)] [string] $Action = $null,
+ [parameter(Mandatory=$false)] [string] $Data = $null,
+ [parameter(Mandatory=$false)] [Guid] $Id = [Guid]::Empty
+ )
+
+ $hnsPath = "/$Type"
+
+ if ($id -ne [Guid]::Empty)
+ {
+ $hnsPath += "/$id";
+ }
+
+ if ($Action)
+ {
+ $hnsPath += "/$Action";
+ }
+
+ $request = "";
+ if ($Data)
+ {
+ $request = $Data
+ }
+
+ $output = "";
+ $response = "";
+ Write-Verbose "Invoke-HNSRequest Method[$Method] Path[$hnsPath] Data[$request]"
+
+ $hnsApi = Get-VmComputeNativeMethods
+ $hnsApi::HNSCall($Method, $hnsPath, "$request", [ref] $response);
+
+ Write-Verbose "Result : $response"
+ if ($response)
+ {
+ try {
+ $output = ($response | ConvertFrom-Json);
+ } catch {
+ Write-Error $_.Exception.Message
+ return ""
+ }
+ if ($output.Error)
+ {
+ Write-Error $output;
+ }
+ $output = $output.Output;
+ }
+
+ return $output;
+}
+
+#########################################################################
+
+Export-ModuleMember -Function Get-HNSActivities
+Export-ModuleMember -Function Get-HnsSwitchExtensions
+Export-ModuleMember -Function Set-HnsSwitchExtension
+
+Export-ModuleMember -Function New-HNSNetwork
+
+Export-ModuleMember -Function New-HNSEndpoint
+Export-ModuleMember -Function New-HnsRemoteEndpoint
+
+Export-ModuleMember -Function Attach-HNSHostEndpoint
+Export-ModuleMember -Function Attach-HNSVMEndpoint
+Export-ModuleMember -Function Attach-HNSEndpoint
+Export-ModuleMember -Function Detach-HNSHostEndpoint
+Export-ModuleMember -Function Detach-HNSVMEndpoint
+Export-ModuleMember -Function Detach-HNSEndpoint
+
+Export-ModuleMember -Function Get-HNSPolicyList
+Export-ModuleMember -Function Remove-HnsPolicyList
+Export-ModuleMember -Function New-HnsRoute
+Export-ModuleMember -Function New-HnsLoadBalancer
+
+Export-ModuleMember -Function Invoke-HNSRequest
diff --git a/datapath-windows/misc/OVS.psm1 b/datapath-windows/misc/OVS.psm1
index a8ffcaefd..1cc347bc6 100644
--- a/datapath-windows/misc/OVS.psm1
+++ b/datapath-windows/misc/OVS.psm1
@@ -207,4 +207,81 @@ function Set-VMNetworkAdapterOVSPortDirect
}
}
-Export-ModuleMember -function Set-*, Get-*
+function Get-OVSEnabledHNSNetworks
+{
+ return (Get-HNSNetwork) | Where-Object {($_.Extensions.Id -eq '583cc151-73ec-4a6a-8b47-578297ad7623') -and ($_.Extensions.IsEnabled -eq 'True')}
+}
+
+function Add-OVSHNSInternalPort
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [string] $PortName
+ )
+ $test = [array](Get-NetAdapter -IncludeHidden -InterfaceAlias "$PortName" -ErrorAction SilentlyContinue)
+ if (!($test -eq $null))
+ {
+ return
+ }
+ $test = [array]((Get-HnsEndpoint) | Where-Object {($_.Name -eq "$PortName")})
+ if (!($test -eq $null))
+ {
+ return
+ }
+ $a = [array](Get-OVSEnabledHNSNetworks).Id
+ if ($a.count -eq 0)
+ {
+ # If we did not find any OVS enabled switches try to find the ID via
+ # environment variable
+ $a = [array]$env:OVS_ENABLED_NETWORK_ID
+ if ($a.count -eq 0)
+ {
+ # Bypass 1803 listing bug and assumed that the first transparent
+ # network is OVS enabled
+ $a = [array](Get-HNSNetwork | where {$_.type -eq "transparent"}).ID
+ if ($a.count -eq 0)
+ {
+ return
+ }
+ }
+ }
+ $temp = New-HnsEndpoint -NetworkId $a[0] -Name "$PortName"
+ Attach-HnsHostEndpoint $temp.Id 1
+ Rename-NetAdapter -IncludeHidden -InterfaceAlias "vEthernet ($PortName)" -NewName "$PortName" -ErrorAction SilentlyContinue
+ Remove-NetRoute -InterfaceAlias "$PortName" -Confirm:$false -ErrorAction SilentlyContinue
+ Disable-NetAdapter -Confirm:$false -IncludeHidden -InterfaceAlias "$PortName" -ErrorAction SilentlyContinue
+}
+
+function Delete-OVSHNSInternalPort
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [string] $PortName
+ )
+ $a = [array]((Get-HnsEndpoint) | Where-Object {($_.Name -eq "$PortName")})
+ $request = @{
+ SystemType = "Host";
+ };
+
+ return Invoke-HNSRequest -Method DELETE -Type endpoints -Data (ConvertTo-Json $request ) -Id $a[0].ID
+}
+
+function Enable-OVSOnHNSNetwork
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [string] $NetworkId
+ )
+ return Set-HnsSwitchExtension -NetworkId $NetworkId -ExtensionId 583cc151-73ec-4a6a-8b47-578297ad7623 -state $True
+}
+
+function Disable-OVSOnHNSNetwork
+{
+ param
+ (
+ [parameter(Mandatory=$true)] [string] $NetworkId
+ )
+ return Set-HnsSwitchExtension -NetworkId $NetworkId -ExtensionId 583cc151-73ec-4a6a-8b47-578297ad7623 -state $False
+}
+
+Export-ModuleMember -function Set-*, Get-*, Enable-*, Disable-*, Add-*, Delete-*
--
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&data=02%7C01%7Cvsairam%40vmware.com%7Cd3d913f61b40483be5c808d62d757f34%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C1%7C0%7C636746380042797946&sdata=psUPrew%2FaWKLte7V9Kb361XUWouYCGB3ufcYo24m0FU%3D&reserved=0
> -----Original Message----- > From: ovs-dev-bounces@openvswitch.org <ovs-dev- > bounces@openvswitch.org> On Behalf Of Alin Gabriel Serdean > Sent: Tuesday, October 9, 2018 2:26 AM > To: dev@openvswitch.org > Cc: Alin Gabriel Serdean <aserdean@ovn.org> > Subject: [ovs-dev] [RFC PATCH v1 1/3] datapath-windows: Introduce HNS OVS > calls > > We introduce a new powershell module for interacting with HNS (host network > service): > https://github.com/Microsoft/SDN/blob/master/Kubernetes/windows/hns.psm > 1 > > In our repository this shall be named HNSHelper.psm1. > > We also add five new commandlets in our OVS powershell module: > Disable-OVSOnHNSNetwork - disable OVS extension on a given HNS network. > Enable-OVSOnHNSNetwork - enable OVS extension on a given HNS network. > Get-OVSEnabledHNSNetworks - return the HNS network on which OVS is > enabled. > Add-OVSHNSInternalPort - will add a new internal port with he name: `name`, on > the HNS network, which has OVS enabled. This port > shall use the host compartment. > Delete-OVSHNSInternalPort - will delete an internal port with name: `name` on a > HNS network which has OVS enabled. > > Signed-off-by: Alin Gabriel Serdean <aserdean@ovn.org> > --- [Alin Serdean] For future references: HNS API has been renamed to HCN (host compute networking). An API schema has been released and documented under: https://docs.microsoft.com/en-us/windows-server/networking/technologies/hcn/hcn-top#features-of-the-hcn-service-api The patchset was using an undocumented version of the V1 HNS API via the official Microsoft repository: https://github.com/microsoft/SDN/blob/710cad6fc9025c86e04ef5daa6eb53f577802448/Kubernetes/windows/hns.psm1
diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk index 3820041f6..d98ab3c60 100644 --- a/datapath-windows/automake.mk +++ b/datapath-windows/automake.mk @@ -3,6 +3,7 @@ EXTRA_DIST += \ datapath-windows/Package/package.VcxProj.user \ datapath-windows/include/OvsDpInterfaceExt.h \ datapath-windows/include/OvsDpInterfaceCtExt.h \ + datapath-windows/misc/HNSHelper.psm1 \ datapath-windows/misc/OVS.psm1 \ datapath-windows/misc/install.cmd \ datapath-windows/misc/uninstall.cmd \ diff --git a/datapath-windows/misc/HNSHelper.psm1 b/datapath-windows/misc/HNSHelper.psm1 new file mode 100644 index 000000000..ac99889cf --- /dev/null +++ b/datapath-windows/misc/HNSHelper.psm1 @@ -0,0 +1,499 @@ +# SDN Sample Scripts v.1.0 +# +# Copyright (c) Microsoft Corporation +# +# All rights reserved. +# +# MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the ""Software""), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +######################################################################### +# Global Initialize +function Get-VmComputeNativeMethods() +{ + $signature = @' + [DllImport("vmcompute.dll")] + public static extern void HNSCall([MarshalAs(UnmanagedType.LPWStr)] string method, [MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPWStr)] string request, [MarshalAs(UnmanagedType.LPWStr)] out string response); +'@ + + # Compile into runtime type + try { return [VmCompute.PrivatePInvoke.NativeMethods] } + catch { return (Add-Type -MemberDefinition $signature -Namespace VmCompute.PrivatePInvoke -Name NativeMethods -PassThru) } +} + +######################################################################### +# Configuration +######################################################################### +function Get-HnsSwitchExtensions +{ + param + ( + [parameter(Mandatory=$true)] [string] $NetworkId + ) + + return (Get-HNSNetwork $NetworkId).Extensions +} + +function Set-HnsSwitchExtension +{ + param + ( + [parameter(Mandatory=$true)] [string] $NetworkId, + [parameter(Mandatory=$true)] [string] $ExtensionId, + [parameter(Mandatory=$true)] [bool] $state + ) + + # { "Extensions": [ { "Id": "...", "IsEnabled": true|false } ] } + $req = @{ + "Extensions"=@(@{ + "Id"=$ExtensionId; + "IsEnabled"=$state; + };) + } + Invoke-HNSRequest -Method POST -Type networks -Id $NetworkId -Data (ConvertTo-Json $req) +} + +######################################################################### +# Activities +######################################################################### +function Get-HNSActivities +{ + [cmdletbinding()]Param() + return Invoke-HNSRequest -Type activities -Method GET +} + +######################################################################### +# PolicyLists +######################################################################### +function Get-HNSPolicyList { + [cmdletbinding()]Param() + return Invoke-HNSRequest -Type policylists -Method GET +} + +function Remove-HnsPolicyList +{ + [CmdletBinding()] + param + ( + [parameter(Mandatory=$true,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] + [Object[]] $InputObjects + ) + begin {$Objects = @()} + process {$Objects += $InputObjects; } + end { + $Objects | foreach { Invoke-HNSRequest -Method DELETE -Type policylists -Id $_.Id } + } +} + +function New-HnsRoute { + param + ( + [parameter(Mandatory = $false)] [Guid[]] $Endpoints = $null, + [parameter(Mandatory = $true)] [string] $DestinationPrefix, + [parameter(Mandatory = $false)] [switch] $EncapEnabled + ) + + $policyLists = @{ + References = @( + get-endpointReferences $Endpoints; + ); + Policies = @( + @{ + Type = "ROUTE"; + DestinationPrefix = $DestinationPrefix; + NeedEncap = $EncapEnabled.IsPresent; + } + ); + } + + Invoke-HNSRequest -Method POST -Type policylists -Data (ConvertTo-Json $policyLists -Depth 10) +} + +function New-HnsLoadBalancer { + param + ( + [parameter(Mandatory = $false)] [Guid[]] $Endpoints = $null, + [parameter(Mandatory = $true)] [int] $InternalPort, + [parameter(Mandatory = $true)] [int] $ExternalPort, + [parameter(Mandatory = $false)] [string] $Vip + ) + + $policyLists = @{ + References = @( + get-endpointReferences $Endpoints; + ); + Policies = @( + @{ + Type = "ELB"; + InternalPort = $InternalPort; + ExternalPort = $ExternalPort; + VIPs = @($Vip); + } + ); + } + + Invoke-HNSRequest -Method POST -Type policylists -Data ( ConvertTo-Json $policyLists -Depth 10) +} + + +function get-endpointReferences { + param + ( + [parameter(Mandatory = $true)] [Guid[]] $Endpoints = $null + ) + if ($Endpoints ) { + $endpointReference = @() + foreach ($endpoint in $Endpoints) + { + $endpointReference += "/endpoints/$endpoint" + } + return $endpointReference + } + return @() +} + +######################################################################### +# Networks +######################################################################### +function New-HnsNetwork +{ + param + ( + [parameter(Mandatory=$false, Position=0)] + [string] $JsonString, + [ValidateSet('ICS', 'Internal', 'Transparent', 'NAT', 'Overlay', 'L2Bridge', 'L2Tunnel', 'Layered', 'Private')] + [parameter(Mandatory = $false, Position = 0)] + [string] $Type, + [parameter(Mandatory = $false)] [string] $Name, + [parameter(Mandatory = $false)] [string] $AddressPrefix, + [parameter(Mandatory = $false)] [string] $Gateway, + [parameter(Mandatory = $false)] [string] $DNSServer, + [parameter(Mandatory = $false)] [string] $AdapterName + ) + + Begin { + if (!$JsonString) { + $netobj = @{ + Type = $Type; + }; + + if ($Name) { + $netobj += @{ + Name = $Name; + } + } + + if ($AddressPrefix -and $Gateway) { + $netobj += @{ + Subnets = @( + @{ + AddressPrefix = $AddressPrefix; + GatewayAddress = $Gateway; + } + ); + } + } + + if ($DNSServerName) { + $netobj += @{ + DNSServerList = $DNSServer + } + } + + if ($AdapterName) { + $netobj += @{ + NetworkAdapterName = $AdapterName; + } + } + + $JsonString = ConvertTo-Json $netobj -Depth 10 + } + + } + Process{ + return Invoke-HNSRequest -Method POST -Type networks -Data $JsonString + } +} + +######################################################################### +# Endpoints +######################################################################### +function New-HnsEndpoint +{ + param + ( + [parameter(Mandatory=$false, Position = 0)] [string] $JsonString = $null, + [parameter(Mandatory = $false, Position = 0)] [Guid] $NetworkId, + [parameter(Mandatory = $false)] [string] $Name, + [parameter(Mandatory = $false)] [string] $IPAddress, + [parameter(Mandatory = $false)] [string] $Gateway, + [parameter(Mandatory = $false)] [string] $MacAddress, + [parameter(Mandatory = $false)] [switch] $EnableOutboundNat + ) + + begin + { + if ($JsonString) + { + $EndpointData = $JsonString | ConvertTo-Json | ConvertFrom-Json + } + else + { + $endpoint = @{ + VirtualNetwork = $NetworkId; + Policies = @(); + } + + if ($Name) { + $endpoint += @{ + Name = $Name; + } + } + + if ($MacAddress) { + $endpoint += @{ + MacAddress = $MacAddress; + } + } + + if ($IPAddress) { + $endpoint += @{ + IPAddress = $IPAddress; + } + } + + if ($Gateway) { + $endpoint += @{ + GatewayAddress = $Gateway; + } + } + + if ($EnableOutboundNat) { + $endpoint.Policies += @{ + Type = "OutBoundNAT"; + } + + } + # Try to Generate the data + $EndpointData = convertto-json $endpoint + } + } + + Process + { + return Invoke-HNSRequest -Method POST -Type endpoints -Data $EndpointData + } +} + + +function New-HnsRemoteEndpoint +{ + param + ( + [parameter(Mandatory = $true)] [Guid] $NetworkId, + [parameter(Mandatory = $false)] [string] $IPAddress, + [parameter(Mandatory = $false)] [string] $MacAddress + ) + + $remoteEndpoint = @{ + ID = [Guid]::NewGuid(); + VirtualNetwork = $NetworkId; + IPAddress = $IPAddress; + MacAddress = $MacAddress; + IsRemoteEndpoint = $true; + } + + return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $remoteEndpoint -Depth 10) + +} + + +function Attach-HnsHostEndpoint +{ + param + ( + [parameter(Mandatory=$true)] [Guid] $EndpointID, + [parameter(Mandatory=$true)] [int] $CompartmentID + ) + $request = @{ + SystemType = "Host"; + CompartmentId = $CompartmentID; + }; + + return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request) -Action "attach" -Id $EndpointID +} + +function Attach-HNSVMEndpoint +{ + param + ( + [parameter(Mandatory=$true)] [Guid] $EndpointID, + [parameter(Mandatory=$true)] [string] $VMNetworkAdapterName + ) + + $request = @{ + VirtualNicName = $VMNetworkAdapterName; + SystemType = "VirtualMachine"; + }; + return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request ) -Action "attach" -Id $EndpointID + +} + +function Attach-HNSEndpoint +{ + param + ( + [parameter(Mandatory=$true)] [Guid] $EndpointID, + [parameter(Mandatory=$true)] [int] $CompartmentID, + [parameter(Mandatory=$true)] [string] $ContainerID + ) + $request = @{ + ContainerId = $ContainerID; + SystemType="Container"; + CompartmentId = $CompartmentID; + }; + + return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request) -Action "attach" -Id $EndpointID +} + +function Detach-HNSVMEndpoint +{ + param + ( + [parameter(Mandatory=$true)] [Guid] $EndpointID + ) + $request = @{ + SystemType = "VirtualMachine"; + }; + + return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request ) -Action "detach" -Id $EndpointID +} + +function Detach-HNSHostEndpoint +{ + param + ( + [parameter(Mandatory=$true)] [Guid] $EndpointID + ) + $request = @{ + SystemType = "Host"; + }; + + return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request ) -Action "detach" -Id $EndpointID +} + +function Detach-HNSEndpoint +{ + param + ( + [parameter(Mandatory=$true)] [Guid] $EndpointID, + [parameter(Mandatory=$true)] [string] $ContainerID + ) + + $request = @{ + ContainerId = $ContainerID; + SystemType="Container"; + }; + + return Invoke-HNSRequest -Method POST -Type endpoints -Data (ConvertTo-Json $request ) -Action "detach" -Id $EndpointID +} +######################################################################### + +function Invoke-HNSRequest +{ + param + ( + [ValidateSet('GET', 'POST', 'DELETE')] + [parameter(Mandatory=$true)] [string] $Method, + [ValidateSet('networks', 'endpoints', 'activities', 'policylists', 'endpointstats', 'plugins')] + [parameter(Mandatory=$true)] [string] $Type, + [parameter(Mandatory=$false)] [string] $Action = $null, + [parameter(Mandatory=$false)] [string] $Data = $null, + [parameter(Mandatory=$false)] [Guid] $Id = [Guid]::Empty + ) + + $hnsPath = "/$Type" + + if ($id -ne [Guid]::Empty) + { + $hnsPath += "/$id"; + } + + if ($Action) + { + $hnsPath += "/$Action"; + } + + $request = ""; + if ($Data) + { + $request = $Data + } + + $output = ""; + $response = ""; + Write-Verbose "Invoke-HNSRequest Method[$Method] Path[$hnsPath] Data[$request]" + + $hnsApi = Get-VmComputeNativeMethods + $hnsApi::HNSCall($Method, $hnsPath, "$request", [ref] $response); + + Write-Verbose "Result : $response" + if ($response) + { + try { + $output = ($response | ConvertFrom-Json); + } catch { + Write-Error $_.Exception.Message + return "" + } + if ($output.Error) + { + Write-Error $output; + } + $output = $output.Output; + } + + return $output; +} + +######################################################################### + +Export-ModuleMember -Function Get-HNSActivities +Export-ModuleMember -Function Get-HnsSwitchExtensions +Export-ModuleMember -Function Set-HnsSwitchExtension + +Export-ModuleMember -Function New-HNSNetwork + +Export-ModuleMember -Function New-HNSEndpoint +Export-ModuleMember -Function New-HnsRemoteEndpoint + +Export-ModuleMember -Function Attach-HNSHostEndpoint +Export-ModuleMember -Function Attach-HNSVMEndpoint +Export-ModuleMember -Function Attach-HNSEndpoint +Export-ModuleMember -Function Detach-HNSHostEndpoint +Export-ModuleMember -Function Detach-HNSVMEndpoint +Export-ModuleMember -Function Detach-HNSEndpoint + +Export-ModuleMember -Function Get-HNSPolicyList +Export-ModuleMember -Function Remove-HnsPolicyList +Export-ModuleMember -Function New-HnsRoute +Export-ModuleMember -Function New-HnsLoadBalancer + +Export-ModuleMember -Function Invoke-HNSRequest diff --git a/datapath-windows/misc/OVS.psm1 b/datapath-windows/misc/OVS.psm1 index a8ffcaefd..1cc347bc6 100644 --- a/datapath-windows/misc/OVS.psm1 +++ b/datapath-windows/misc/OVS.psm1 @@ -207,4 +207,81 @@ function Set-VMNetworkAdapterOVSPortDirect } } -Export-ModuleMember -function Set-*, Get-* +function Get-OVSEnabledHNSNetworks +{ + return (Get-HNSNetwork) | Where-Object {($_.Extensions.Id -eq '583cc151-73ec-4a6a-8b47-578297ad7623') -and ($_.Extensions.IsEnabled -eq 'True')} +} + +function Add-OVSHNSInternalPort +{ + param + ( + [parameter(Mandatory=$true)] [string] $PortName + ) + $test = [array](Get-NetAdapter -IncludeHidden -InterfaceAlias "$PortName" -ErrorAction SilentlyContinue) + if (!($test -eq $null)) + { + return + } + $test = [array]((Get-HnsEndpoint) | Where-Object {($_.Name -eq "$PortName")}) + if (!($test -eq $null)) + { + return + } + $a = [array](Get-OVSEnabledHNSNetworks).Id + if ($a.count -eq 0) + { + # If we did not find any OVS enabled switches try to find the ID via + # environment variable + $a = [array]$env:OVS_ENABLED_NETWORK_ID + if ($a.count -eq 0) + { + # Bypass 1803 listing bug and assumed that the first transparent + # network is OVS enabled + $a = [array](Get-HNSNetwork | where {$_.type -eq "transparent"}).ID + if ($a.count -eq 0) + { + return + } + } + } + $temp = New-HnsEndpoint -NetworkId $a[0] -Name "$PortName" + Attach-HnsHostEndpoint $temp.Id 1 + Rename-NetAdapter -IncludeHidden -InterfaceAlias "vEthernet ($PortName)" -NewName "$PortName" -ErrorAction SilentlyContinue + Remove-NetRoute -InterfaceAlias "$PortName" -Confirm:$false -ErrorAction SilentlyContinue + Disable-NetAdapter -Confirm:$false -IncludeHidden -InterfaceAlias "$PortName" -ErrorAction SilentlyContinue +} + +function Delete-OVSHNSInternalPort +{ + param + ( + [parameter(Mandatory=$true)] [string] $PortName + ) + $a = [array]((Get-HnsEndpoint) | Where-Object {($_.Name -eq "$PortName")}) + $request = @{ + SystemType = "Host"; + }; + + return Invoke-HNSRequest -Method DELETE -Type endpoints -Data (ConvertTo-Json $request ) -Id $a[0].ID +} + +function Enable-OVSOnHNSNetwork +{ + param + ( + [parameter(Mandatory=$true)] [string] $NetworkId + ) + return Set-HnsSwitchExtension -NetworkId $NetworkId -ExtensionId 583cc151-73ec-4a6a-8b47-578297ad7623 -state $True +} + +function Disable-OVSOnHNSNetwork +{ + param + ( + [parameter(Mandatory=$true)] [string] $NetworkId + ) + return Set-HnsSwitchExtension -NetworkId $NetworkId -ExtensionId 583cc151-73ec-4a6a-8b47-578297ad7623 -state $False +} + +Export-ModuleMember -function Set-*, Get-*, Enable-*, Disable-*, Add-*, Delete-*
We introduce a new powershell module for interacting with HNS (host network service): https://github.com/Microsoft/SDN/blob/master/Kubernetes/windows/hns.psm1 In our repository this shall be named HNSHelper.psm1. We also add five new commandlets in our OVS powershell module: Disable-OVSOnHNSNetwork - disable OVS extension on a given HNS network. Enable-OVSOnHNSNetwork - enable OVS extension on a given HNS network. Get-OVSEnabledHNSNetworks - return the HNS network on which OVS is enabled. Add-OVSHNSInternalPort - will add a new internal port with he name: `name`, on the HNS network, which has OVS enabled. This port shall use the host compartment. Delete-OVSHNSInternalPort - will delete an internal port with name: `name` on a HNS network which has OVS enabled. Signed-off-by: Alin Gabriel Serdean <aserdean@ovn.org> --- datapath-windows/automake.mk | 1 + datapath-windows/misc/HNSHelper.psm1 | 499 +++++++++++++++++++++++++++++++++++ datapath-windows/misc/OVS.psm1 | 79 +++++- 3 files changed, 578 insertions(+), 1 deletion(-) create mode 100644 datapath-windows/misc/HNSHelper.psm1