diff --git a/pkg/hns/endpoint_windows.go b/pkg/hns/endpoint_windows.go index 85a0f64e..cd3025e1 100644 --- a/pkg/hns/endpoint_windows.go +++ b/pkg/hns/endpoint_windows.go @@ -77,6 +77,9 @@ func GenerateHnsEndpoint(epInfo *EndpointInfo, n *NetConf) (*hcsshim.HNSEndpoint } } + if n.LoopbackDSR { + n.ApplyLoopbackDSR(&epInfo.IpAddress) + } if hnsEndpoint == nil { hnsEndpoint = &hcsshim.HNSEndpoint{ Name: epInfo.EndpointName, @@ -117,14 +120,8 @@ func GenerateHcnEndpoint(epInfo *EndpointInfo, n *NetConf) (*hcn.HostComputeEndp if hcnEndpoint == nil { routes := []hcn.Route{ { - NextHop: GetIpString(&epInfo.Gateway), - DestinationPrefix: func() string { - destinationPrefix := "0.0.0.0/0" - if ipv6 := epInfo.Gateway.To4(); ipv6 == nil { - destinationPrefix = "::/0" - } - return destinationPrefix - }(), + NextHop: GetIpString(&epInfo.Gateway), + DestinationPrefix: GetDefaultDestinationPrefix(&epInfo.Gateway), }, } @@ -138,6 +135,9 @@ func GenerateHcnEndpoint(epInfo *EndpointInfo, n *NetConf) (*hcn.HostComputeEndp } ipConfigs := []hcn.IpConfig{hcnIpConfig} + if n.LoopbackDSR { + n.ApplyLoopbackDSR(&epInfo.IpAddress) + } hcnEndpoint = &hcn.HostComputeEndpoint{ SchemaVersion: hcn.Version{Major: 2}, Name: epInfo.EndpointName, diff --git a/pkg/hns/netconf_windows.go b/pkg/hns/netconf_windows.go index eabd37cb..c0b0c316 100644 --- a/pkg/hns/netconf_windows.go +++ b/pkg/hns/netconf_windows.go @@ -17,6 +17,9 @@ package hns import ( "bytes" "encoding/json" + "fmt" + "net" + "github.com/Microsoft/hcsshim/hcn" "github.com/buger/jsonparser" "github.com/containernetworking/cni/pkg/types" @@ -26,9 +29,16 @@ import ( // NetConf is the CNI spec type NetConf struct { types.NetConf + // ApiVersion is either 1 or 2, which specifies which hns APIs to call + ApiVersion int `json:"ApiVersion"` + // V2 Api Policies HcnPolicyArgs []hcn.EndpointPolicy `json:"HcnPolicyArgs,omitempty"` - Policies []policy `json:"policies,omitempty"` - RuntimeConfig RuntimeConfig `json:"runtimeConfig"` + // V1 Api Policies + Policies []policy `json:"policies,omitempty"` + // Options to be passed in by the runtime + RuntimeConfig RuntimeConfig `json:"runtimeConfig"` + // If true, adds a policy to endpoints to support loopback direct server return + LoopbackDSR bool `json:"loopbackDSR"` } type RuntimeDNS struct { @@ -45,6 +55,31 @@ type policy struct { Value json.RawMessage `json:"value"` } +func GetDefaultDestinationPrefix(ip *net.IP) string { + destinationPrefix := "0.0.0.0/0" + if ipv6 := ip.To4(); ipv6 == nil { + destinationPrefix = "::/0" + } + return destinationPrefix +} + +func (n *NetConf) ApplyLoopbackDSR(ip *net.IP) { + value := fmt.Sprintf(`"Destinations" : ["%s"]`, ip.String()) + if n.ApiVersion == 2 { + hcnLoopbackRoute := hcn.EndpointPolicy{ + Type: "OutBoundNAT", + Settings: []byte(fmt.Sprintf("{%s}", value)), + } + n.HcnPolicyArgs = append(n.HcnPolicyArgs, hcnLoopbackRoute) + } else { + hnsLoopbackRoute := policy{ + Name: "EndpointPolicy", + Value: []byte(fmt.Sprintf(`{"Type": "OutBoundNAT", %s}`, value)), + } + n.Policies = append(n.Policies, hnsLoopbackRoute) + } +} + // If runtime dns values are there use that else use cni conf supplied dns func (n *NetConf) GetDNS() types.DNS { dnsResult := n.DNS diff --git a/plugins/main/windows/win-bridge/README.md b/plugins/main/windows/win-bridge/README.md index 024ce48c..0bd8fb2d 100644 --- a/plugins/main/windows/win-bridge/README.md +++ b/plugins/main/windows/win-bridge/README.md @@ -32,7 +32,8 @@ With win-bridge plugin, all containers (on the same host) are plugged into an L2 "NeedEncap": true } } - ]. + ], + "loopbackDSR": true, "capabilities": { "dns": true } @@ -51,5 +52,6 @@ With win-bridge plugin, all containers (on the same host) are plugged into an L2 * `ipam` (dictionary, optional): IPAM configuration to be used for this network. * `Policies` (list, optional): List of hns policies to be used (only used when ApiVersion is < 2). * `HcnPolicyArgs` (list, optional): List of hcn policies to be used (only used when ApiVersion is 2). -* `capabilities` (dictionary, optional): runtime capabilities to enable. - * `dns` (boolean, optional): if true will take the dns config supplied by the runtime and override other settings. \ No newline at end of file +* `loopbackDSR` (bool, optional): If true, will add a policy to allow the interface to support loopback direct server return. +* `capabilities` (dictionary, optional): Runtime capabilities to enable. + * `dns` (boolean, optional): If true, will take the dns config supplied by the runtime and override other settings. \ No newline at end of file diff --git a/plugins/main/windows/win-bridge/sample.conf b/plugins/main/windows/win-bridge/sample.conf index 319d555e..df8abff8 100755 --- a/plugins/main/windows/win-bridge/sample.conf +++ b/plugins/main/windows/win-bridge/sample.conf @@ -39,6 +39,7 @@ "NeedEncap":true } } - ] + ], + "loopbackDSR": true } } \ No newline at end of file diff --git a/plugins/main/windows/win-bridge/win-bridge_windows.go b/plugins/main/windows/win-bridge/win-bridge_windows.go index d8a2d81b..db18e37f 100644 --- a/plugins/main/windows/win-bridge/win-bridge_windows.go +++ b/plugins/main/windows/win-bridge/win-bridge_windows.go @@ -17,6 +17,7 @@ package main import ( "encoding/json" "fmt" + "os" "runtime" "strings" @@ -38,7 +39,6 @@ type NetConf struct { hns.NetConf IPMasqNetwork string `json:"ipMasqNetwork,omitempty"` - ApiVersion int `json:"ApiVersion"` } func init() { @@ -103,7 +103,7 @@ func cmdHnsAdd(args *skel.CmdArgs, n *NetConf) (*current.Result, error) { return nil, fmt.Errorf("network %v not found", networkName) } - if !strings.EqualFold(hnsNetwork.Type, "L2Bridge") { + if !strings.EqualFold(hnsNetwork.Type, "L2Bridge") && !strings.EqualFold(hnsNetwork.Type, "L2Tunnel") { return nil, fmt.Errorf("network %v is of an unexpected type: %v", networkName, hnsNetwork.Type) } @@ -145,7 +145,7 @@ func cmdHcnAdd(args *skel.CmdArgs, n *NetConf) (*current.Result, error) { return nil, fmt.Errorf("network %v not found", networkName) } - if hcnNetwork.Type != hcn.L2Bridge { + if hcnNetwork.Type != hcn.L2Bridge && hcnNetwork.Type != hcn.L2Tunnel { return nil, fmt.Errorf("network %v is of unexpected type: %v", networkName, hcnNetwork.Type) } diff --git a/plugins/main/windows/win-overlay/README.md b/plugins/main/windows/win-overlay/README.md index d963fc7e..c2ee9f4b 100644 --- a/plugins/main/windows/win-overlay/README.md +++ b/plugins/main/windows/win-overlay/README.md @@ -14,11 +14,11 @@ With win-overlay plugin, all containers (on the same host) are plugged into an O "ipam": { "type": "host-local", "subnet": "10.10.0.0/16" - } + }, + "loopbackDSR": true, "capabilites": { "dns": true } - } ``` @@ -33,5 +33,6 @@ With win-overlay plugin, all containers (on the same host) are plugged into an O * `endpointMacPrefix` (string, optional): set to the MAC prefix configured for Flannel. * `Policies` (list, optional): List of hns policies to be used. * `ipam` (dictionary, required): IPAM configuration to be used for this network. +* `loopbackDSR` (bool, optional): If true, will add a policy to allow the interface to support loopback direct server return. * `capabilities` (dictionary, optional): runtime capabilities to be parsed and injected by runtime. - * `dns` (boolean, optional): if true will take the dns config supplied by the runtime and override other settings. \ No newline at end of file + * `dns` (boolean, optional): If true, will take the dns config supplied by the runtime and override other settings. \ No newline at end of file diff --git a/plugins/main/windows/win-overlay/win-overlay_windows.go b/plugins/main/windows/win-overlay/win-overlay_windows.go index 0b6fa61f..83e92d36 100644 --- a/plugins/main/windows/win-overlay/win-overlay_windows.go +++ b/plugins/main/windows/win-overlay/win-overlay_windows.go @@ -17,6 +17,7 @@ package main import ( "encoding/json" "fmt" + "os" "runtime" "strings" @@ -118,7 +119,9 @@ func cmdAdd(args *skel.CmdArgs) error { } result.DNS = n.GetDNS() - + if n.LoopbackDSR { + n.ApplyLoopbackDSR(&ipAddr) + } hnsEndpoint := &hcsshim.HNSEndpoint{ Name: epName, VirtualNetwork: hnsNetwork.Id,