Skip to content

Commit

Permalink
backport: fix: add ipv6 port policy in addition to ipv4 policy if no …
Browse files Browse the repository at this point in the history
…host ip and ipv6 enabled (#2852) (#2883)

fix: add ipv6 port policy in addition to ipv4 policy if no host ip and ipv6 enabled (#2852)

* add ipv6 port policy in addition to ipv4 policy if no host ip and ipv6 enabled

* address feedback
  • Loading branch information
QxBytes authored Jul 29, 2024
1 parent 018a323 commit d144c3c
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 25 deletions.
76 changes: 52 additions & 24 deletions cni/network/network_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,18 @@ func getEndpointDNSSettings(nwCfg *cni.NetworkConfig, dns network.DNSInfo, names
return epDNS, nil
}

// getPoliciesFromRuntimeCfg returns network policies from network config.
/*
getPoliciesFromRuntimeCfg returns network policies from network config.
Windows
test-netconnection to ---> to node ipv4 to node ipv6 to localhost ipv4 to localhost ipv6
host port mapping w/
no host ip ok ok fail fail
localhost ipv4 host ip fail fail fail fail
node ipv6 host ip fail ok fail fail
localhost ipv6 host ip fail fail fail fail
node ipv4 host ip ok fail fail fail
*/
func getPoliciesFromRuntimeCfg(nwCfg *cni.NetworkConfig, isIPv6Enabled bool) ([]policy.Policy, error) {
logger.Info("Runtime Info", zap.Any("config", nwCfg.RuntimeConfig))
var policies []policy.Policy
Expand All @@ -261,7 +272,8 @@ func getPoliciesFromRuntimeCfg(nwCfg *cni.NetworkConfig, isIPv6Enabled bool) ([]
// To support hostport policy mapping for ipv6 in dualstack overlay mode
// uint32 NatFlagsIPv6 = 2

flag := hnsv2.NatFlagsLocalRoutedVip
// if host ip is specified, we create a policy to match that ip only (ipv4 or ipv6), or ipv4 if no host ip
flag := hnsv2.NatFlagsLocalRoutedVip // ipv4 flag
if mapping.HostIp != "" {
hostIP, err := netip.ParseAddr(mapping.HostIp)
if err != nil {
Expand All @@ -277,38 +289,54 @@ func getPoliciesFromRuntimeCfg(nwCfg *cni.NetworkConfig, isIPv6Enabled bool) ([]
}
}

rawPolicy, err := json.Marshal(&hnsv2.PortMappingPolicySetting{
ExternalPort: uint16(mapping.HostPort),
InternalPort: uint16(mapping.ContainerPort),
VIP: mapping.HostIp,
Protocol: protocol,
Flags: flag,
})

hnsPortMappingPolicy, err := createPortMappingPolicy(mapping.HostPort, mapping.ContainerPort, mapping.HostIp, protocol, flag)
if err != nil {
return nil, errors.Wrap(err, "failed to marshal HNS portMappingPolicySetting")
return nil, err
}

hnsv2Policy, err := json.Marshal(&hnsv2.EndpointPolicy{
Type: hnsv2.PortMapping,
Settings: rawPolicy,
})
logger.Info("Creating port mapping policy", zap.Any("policy", hnsPortMappingPolicy))
policies = append(policies, *hnsPortMappingPolicy)

if err != nil {
return nil, errors.Wrap(err, "failed to marshal HNS endpointPolicy")
// if no host ip specified and ipv6 enabled, we also create an identical ipv6 policy in addition to the previous ipv4 policy
if mapping.HostIp == "" && isIPv6Enabled {
ipv6HnsPortMappingPolicy, err := createPortMappingPolicy(mapping.HostPort, mapping.ContainerPort, mapping.HostIp, protocol, hnsv2.NatFlagsIPv6)
if err != nil {
return nil, err
}
logger.Info("Creating ipv6 port mapping policy", zap.Any("policy", ipv6HnsPortMappingPolicy))
policies = append(policies, *ipv6HnsPortMappingPolicy)
}
}

hnsPolicy := policy.Policy{
Type: policy.EndpointPolicy,
Data: hnsv2Policy,
}
return policies, nil
}

logger.Info("Creating port mapping policy", zap.Any("policy", hnsPolicy))
func createPortMappingPolicy(hostPort, containerPort int, hostIP string, protocol uint32, flags hnsv2.NatFlags) (*policy.Policy, error) {
rawPolicy, err := json.Marshal(&hnsv2.PortMappingPolicySetting{
ExternalPort: uint16(hostPort),
InternalPort: uint16(containerPort),
VIP: hostIP,
Protocol: protocol,
Flags: flags,
})
if err != nil {
return nil, errors.Wrap(err, "failed to marshal HNS portMappingPolicySetting")
}

policies = append(policies, hnsPolicy)
hnsv2Policy, err := json.Marshal(&hnsv2.EndpointPolicy{
Type: hnsv2.PortMapping,
Settings: rawPolicy,
})
if err != nil {
return nil, errors.Wrap(err, "failed to marshal HNS endpointPolicy")
}

return policies, nil
hnsPolicy := policy.Policy{
Type: policy.EndpointPolicy,
Data: hnsv2Policy,
}

return &hnsPolicy, nil
}

func getEndpointPolicies(args PolicyArgs) ([]policy.Policy, error) {
Expand Down
130 changes: 129 additions & 1 deletion cni/network/network_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package network

import (
"encoding/json"
"fmt"
"net"
"testing"
Expand All @@ -14,6 +15,7 @@ import (
"github.com/Azure/azure-container-networking/network/hnswrapper"
"github.com/Azure/azure-container-networking/network/policy"
"github.com/Azure/azure-container-networking/telemetry"
hnsv2 "github.com/Microsoft/hcsshim/hcn"
"github.com/containernetworking/cni/pkg/skel"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -219,8 +221,10 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
name string
nwCfg cni.NetworkConfig
isIPv6Enabled bool
expected []hnsv2.PortMappingPolicySetting
}{
{
// ipv6 disabled, ipv4 host ip --> ipv4 host ip policy only
name: "Runtime network polices",
nwCfg: cni.NetworkConfig{
RuntimeConfig: cni.RuntimeConfig{
Expand All @@ -235,9 +239,19 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
},
},
isIPv6Enabled: false,
expected: []hnsv2.PortMappingPolicySetting{
{
ExternalPort: uint16(8000),
InternalPort: uint16(80),
VIP: "192.168.0.4",
Protocol: policy.ProtocolTcp,
Flags: hnsv2.NatFlagsLocalRoutedVip,
},
},
},
{
name: "Runtime hostPort mapping polices",
// ipv6 disabled, no host ip --> ipv4 policy only
name: "Runtime hostPort mapping polices without hostIP",
nwCfg: cni.NetworkConfig{
RuntimeConfig: cni.RuntimeConfig{
PortMappings: []cni.PortMapping{
Expand All @@ -250,8 +264,17 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
},
},
isIPv6Enabled: false,
expected: []hnsv2.PortMappingPolicySetting{
{
ExternalPort: uint16(44000),
InternalPort: uint16(80),
Protocol: policy.ProtocolTcp,
Flags: hnsv2.NatFlagsLocalRoutedVip,
},
},
},
{
// ipv6 enabled, ipv6 host ip --> ipv6 host ip policy only
name: "Runtime hostPort mapping polices with ipv6 hostIP",
nwCfg: cni.NetworkConfig{
RuntimeConfig: cni.RuntimeConfig{
Expand All @@ -266,6 +289,99 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
},
},
isIPv6Enabled: true,
expected: []hnsv2.PortMappingPolicySetting{
{
ExternalPort: uint16(44000),
InternalPort: uint16(80),
VIP: "2001:2002:2003::1",
Protocol: policy.ProtocolTcp,
Flags: hnsv2.NatFlagsIPv6,
},
},
},
{
// ipv6 enabled, ipv4 host ip --> ipv4 host ip policy only
name: "Runtime hostPort mapping polices with ipv4 hostIP on ipv6 enabled cluster",
nwCfg: cni.NetworkConfig{
RuntimeConfig: cni.RuntimeConfig{
PortMappings: []cni.PortMapping{
{
Protocol: "tcp",
HostPort: 44000,
ContainerPort: 80,
HostIp: "192.168.0.4",
},
},
},
},
isIPv6Enabled: true,
expected: []hnsv2.PortMappingPolicySetting{
{
ExternalPort: uint16(44000),
InternalPort: uint16(80),
VIP: "192.168.0.4",
Protocol: policy.ProtocolTcp,
Flags: hnsv2.NatFlagsLocalRoutedVip,
},
},
},
{
// ipv6 enabled, no host ip --> ipv4 and ipv6 policies
name: "Runtime hostPort mapping polices with ipv6 without hostIP",
nwCfg: cni.NetworkConfig{
RuntimeConfig: cni.RuntimeConfig{
PortMappings: []cni.PortMapping{
{
Protocol: "tcp",
HostPort: 44000,
ContainerPort: 80,
},
},
},
},
isIPv6Enabled: true,
expected: []hnsv2.PortMappingPolicySetting{
{
ExternalPort: uint16(44000),
InternalPort: uint16(80),
VIP: "",
Protocol: policy.ProtocolTcp,
Flags: hnsv2.NatFlagsLocalRoutedVip,
},
{
ExternalPort: uint16(44000),
InternalPort: uint16(80),
VIP: "",
Protocol: policy.ProtocolTcp,
Flags: hnsv2.NatFlagsIPv6,
},
},
},
{
// ipv6 enabled, ipv6 localhost ip --> ipv6 host ip policy only
name: "Runtime hostPort mapping polices with ipv6 localhost hostIP on ipv6 enabled cluster",
nwCfg: cni.NetworkConfig{
RuntimeConfig: cni.RuntimeConfig{
PortMappings: []cni.PortMapping{
{
Protocol: "tcp",
HostPort: 44000,
ContainerPort: 80,
HostIp: "::1",
},
},
},
},
isIPv6Enabled: true,
expected: []hnsv2.PortMappingPolicySetting{
{
ExternalPort: uint16(44000),
InternalPort: uint16(80),
VIP: "::1",
Protocol: policy.ProtocolTcp,
Flags: hnsv2.NatFlagsIPv6,
},
},
},
}
for _, tt := range tests {
Expand All @@ -276,6 +392,18 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
require.Condition(t, assert.Comparison(func() bool {
return len(policies) > 0 && policies[0].Type == policy.EndpointPolicy
}))
require.Equal(t, len(tt.expected), len(policies), "expected number of policies not equal to actual")
for index, policy := range policies {
var hnsv2Policy hnsv2.EndpointPolicy
err = json.Unmarshal(policy.Data, &hnsv2Policy)
require.NoError(t, err, "failed to unmarshal hnsv2 policy")

var rawPolicy hnsv2.PortMappingPolicySetting
err = json.Unmarshal(hnsv2Policy.Settings, &rawPolicy)
require.NoError(t, err, "failed to unmarshal hnsv2 port mapping policy")

require.Equal(t, tt.expected[index], rawPolicy, "policies are not expected")
}
})
}
}
Expand Down

0 comments on commit d144c3c

Please sign in to comment.