diff mbox series

[ovs-dev,RFC,v1,1/3] datapath-windows: Introduce HNS OVS calls

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

Commit Message

Alin-Gabriel Serdean Oct. 8, 2018, 11:26 p.m. UTC
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

Comments

Sairam Venugopal Oct. 19, 2018, 9:53 p.m. UTC | #1
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&amp;data=02%7C01%7Cvsairam%40vmware.com%7Cd3d913f61b40483be5c808d62d757f34%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C1%7C0%7C636746380042797946&amp;sdata=rh%2FrirPPKSOUGvrHUhV36M2f83JUFX%2FkbGSCy%2FBvb%2BM%3D&amp;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&amp;data=02%7C01%7Cvsairam%40vmware.com%7Cd3d913f61b40483be5c808d62d757f34%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C1%7C0%7C636746380042797946&amp;sdata=psUPrew%2FaWKLte7V9Kb361XUWouYCGB3ufcYo24m0FU%3D&amp;reserved=0
Alin Serdean Feb. 24, 2020, 4:38 p.m. UTC | #2
> -----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 mbox series

Patch

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-*