From patchwork Mon Oct 8 23:26:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alin-Gabriel Serdean X-Patchwork-Id: 980924 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42Tc224P07z9vZs for ; Tue, 9 Oct 2018 10:26:33 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id D1FD07261; Mon, 8 Oct 2018 23:26:30 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id DE09D6FFE for ; Mon, 8 Oct 2018 23:26:15 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 1E812784 for ; Mon, 8 Oct 2018 23:26:13 +0000 (UTC) X-Originating-IP: 89.46.161.178 Received: from localhost.localdomain (unknown [89.46.161.178]) (Authenticated sender: aserdean@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 3CF38FF802; Mon, 8 Oct 2018 23:26:11 +0000 (UTC) From: Alin Gabriel Serdean To: dev@openvswitch.org Date: Tue, 9 Oct 2018 02:26:02 +0300 Message-Id: <20181008232602.30924-1-aserdean@ovn.org> X-Mailer: git-send-email 2.16.1.windows.1 X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, WEIRD_QUOTING autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Alin Gabriel Serdean Subject: [ovs-dev] [RFC PATCH v1 1/3] datapath-windows: Introduce HNS OVS calls X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org 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 --- 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-*