From c203eb143dcdb30f208d1f22cd63f663df4a7a5b Mon Sep 17 00:00:00 2001 From: Adelina Tuvenie Date: Thu, 1 Oct 2020 14:06:43 +0300 Subject: [PATCH] Use PortMappingPolicySetting In order to support VIPs for container Port Mappings, we should use PortMappingPolicySetting type from HNSv2 instead of the old NatPolicy from HNSv1. --- cni/network/network_windows.go | 26 +++++++-- network/policy/policy_windows.go | 97 ++++++++++++++++++-------------- 2 files changed, 76 insertions(+), 47 deletions(-) diff --git a/cni/network/network_windows.go b/cni/network/network_windows.go index 9107987b41..02db7a7356 100644 --- a/cni/network/network_windows.go +++ b/cni/network/network_windows.go @@ -15,6 +15,7 @@ import ( "github.com/Azure/azure-container-networking/network" "github.com/Azure/azure-container-networking/network/policy" "github.com/Microsoft/hcsshim" + hnsv2 "github.com/Microsoft/hcsshim/hcn" "golang.org/x/sys/windows/registry" cniSkel "github.com/containernetworking/cni/pkg/skel" @@ -239,17 +240,32 @@ func getEndpointDNSSettings(nwCfg *cni.NetworkConfig, result *cniTypesCurr.Resul func getPoliciesFromRuntimeCfg(nwCfg *cni.NetworkConfig) []policy.Policy { log.Printf("[net] RuntimeConfigs: %+v", nwCfg.RuntimeConfig) var policies []policy.Policy + var protocol uint32 for _, mapping := range nwCfg.RuntimeConfig.PortMappings { - rawPolicy, _ := json.Marshal(&hcsshim.NatPolicy{ - Type: "NAT", + + cfgProto := strings.ToUpper(strings.TrimSpace(mapping.Protocol)) + switch cfgProto { + case "TCP": + protocol = policy.ProtocolTcp + case "UDP": + protocol = policy.ProtocolUdp + } + + rawPolicy, _ := json.Marshal(&hnsv2.PortMappingPolicySetting{ ExternalPort: uint16(mapping.HostPort), InternalPort: uint16(mapping.ContainerPort), - Protocol: mapping.Protocol, + VIP: mapping.HostIp, + Protocol: protocol, + }) + + hnsv2Policy, _ := json.Marshal(&hnsv2.EndpointPolicy{ + Type: hnsv2.PortMapping, + Settings: rawPolicy, }) policy := policy.Policy{ Type: policy.EndpointPolicy, - Data: rawPolicy, + Data: hnsv2Policy, } log.Printf("[net] Creating port mapping policy: %+v", policy) @@ -268,7 +284,7 @@ func addIPV6EndpointPolicy(nwInfo network.NetworkInfo) (policy.Policy, error) { return eppolicy, fmt.Errorf("network state doesn't have ipv6 subnet") } - // Everything should be snat'd except podcidr + // Everything should be snat'd except podcidr exceptionList := []string{nwInfo.Subnets[1].Prefix.String()} rawPolicy, _ := json.Marshal(&hcsshim.OutboundNatPolicy{ Policy: hcsshim.Policy{Type: hcsshim.OutboundNat}, diff --git a/network/policy/policy_windows.go b/network/policy/policy_windows.go index abd092881d..ab1e44401f 100644 --- a/network/policy/policy_windows.go +++ b/network/policy/policy_windows.go @@ -3,7 +3,6 @@ package policy import ( "encoding/json" "fmt" - "strings" "github.com/Azure/azure-container-networking/log" "github.com/Microsoft/hcsshim" @@ -11,11 +10,11 @@ import ( ) const ( - // protocolTcp indicates tcp protocol id for portmapping - protocolTcp = 6 + // ProtocolTcp indicates tcp protocol id for portmapping + ProtocolTcp = 6 - // protocolUdp indicates udp protocol id for portmapping - protocolUdp = 17 + // ProtocolUdp indicates udp protocol id for portmapping + ProtocolUdp = 17 // CnetAddressSpace indicates constant for the key string CnetAddressSpace = "cnetAddressSpace" @@ -27,13 +26,6 @@ type KVPairRoutePolicy struct { NeedEncap json.RawMessage `json:"NeedEncap"` } -type KVPairPortMapping struct { - Type CNIPolicyType `json:"Type"` - ExternalPort uint16 `json:"ExternalPort"` - InternalPort uint16 `json:"InternalPort"` - Protocol string `json:"Protocol"` -} - type KVPairOutBoundNAT struct { Type CNIPolicyType `json:"Type"` ExceptionList json.RawMessage `json:"ExceptionList"` @@ -64,6 +56,13 @@ func SerializePolicies(policyType CNIPolicyType, policies []Policy, epInfoData m jsonPolicies = append(jsonPolicies, serializedOutboundNatPolicy) } } + } else if isPolicyTypeNAT := IsPolicyTypeNAT(policy); isPolicyTypeNAT { + // NATPolicy comes as a HNSv2 type, it needs to be converted to HNSv1 + if serializedNatPolicy, err := SerializeNATPolicy(policy); err != nil { + log.Printf("Failed to serialize NatPolicy") + } else { + jsonPolicies = append(jsonPolicies, serializedNatPolicy) + } } else { jsonPolicies = append(jsonPolicies, policy.Data) } @@ -117,6 +116,45 @@ func IsPolicyTypeOutBoundNAT(policy Policy) bool { return false } +// IsPolicyTypeNAT returns true if the policy type is NAT +func IsPolicyTypeNAT(policy Policy) bool { + if policy.Type == EndpointPolicy { + var endpointPolicy hcn.EndpointPolicy + if err := json.Unmarshal(policy.Data, &endpointPolicy); err != nil { + return false + } + if endpointPolicy.Type == hcn.PortMapping { + return true + } + } + return false +} + +func SerializeNATPolicy(policy Policy) (json.RawMessage, error) { + var ( + endpointPolicy hcn.EndpointPolicy + portMappingPolicy hcn.PortMappingPolicySetting + ) + if err := json.Unmarshal(policy.Data, &endpointPolicy); err != nil { + return nil, err + } + if err := json.Unmarshal(endpointPolicy.Settings, &portMappingPolicy); err != nil { + return nil, err + } + natPolicy := hcsshim.NatPolicy{ + Type: "NAT", + InternalPort: portMappingPolicy.InternalPort, + ExternalPort: portMappingPolicy.ExternalPort, + } + switch portMappingPolicy.Protocol { + case ProtocolTcp: + natPolicy.Protocol = "TCP" + case ProtocolUdp: + natPolicy.Protocol = "UDP" + } + return json.Marshal(natPolicy) +} + // SerializeOutBoundNATPolicy formulates OutBoundNAT policy and returns serialized json func SerializeOutBoundNATPolicy(policy Policy, epInfoData map[string]interface{}) (json.RawMessage, error) { outBoundNatPolicy := hcsshim.OutboundNatPolicy{} @@ -169,9 +207,9 @@ func GetPolicyType(policy Policy) CNIPolicyType { } // Check if the type if Port mapping / NAT - var dataPortMapping KVPairPortMapping + var dataPortMapping hcn.EndpointPolicy if err := json.Unmarshal(policy.Data, &dataPortMapping); err == nil { - if dataPortMapping.Type == PortMappingPolicy { + if dataPortMapping.Type == hcn.PortMapping { return PortMappingPolicy } } @@ -308,37 +346,12 @@ func GetHcnRoutePolicy(policy Policy) (hcn.EndpointPolicy, error) { // GetHcnPortMappingPolicy returns port mapping policy. func GetHcnPortMappingPolicy(policy Policy) (hcn.EndpointPolicy, error) { - portMappingPolicy := hcn.EndpointPolicy{ - Type: hcn.PortMapping, - } - - var dataPortMapping KVPairPortMapping - if err := json.Unmarshal(policy.Data, &dataPortMapping); err != nil { + var portMappingPolicy hcn.EndpointPolicy + if err := json.Unmarshal(policy.Data, &portMappingPolicy); err != nil { return portMappingPolicy, fmt.Errorf("Invalid policy: %+v. Expecting PortMapping policy. Error: %v", policy, err) } - - portMappingPolicySetting := &hcn.PortMappingPolicySetting{ - InternalPort: dataPortMapping.InternalPort, - ExternalPort: dataPortMapping.ExternalPort, - } - - protocol := strings.ToUpper(strings.TrimSpace(dataPortMapping.Protocol)) - switch protocol { - case "TCP": - portMappingPolicySetting.Protocol = protocolTcp - case "UDP": - portMappingPolicySetting.Protocol = protocolUdp - default: - return portMappingPolicy, fmt.Errorf("Invalid protocol: %s for port mapping", protocol) - } - - portMappingPolicySettingBytes, err := json.Marshal(portMappingPolicySetting) - if err != nil { - return portMappingPolicy, err - } - - portMappingPolicy.Settings = portMappingPolicySettingBytes + portMappingPolicy.Type = hcn.PortMapping return portMappingPolicy, nil }