Skip to content

Commit d144c3c

Browse files
authored
backport: fix: add ipv6 port policy in addition to ipv4 policy if no 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
1 parent 018a323 commit d144c3c

File tree

2 files changed

+181
-25
lines changed

2 files changed

+181
-25
lines changed

cni/network/network_windows.go

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,18 @@ func getEndpointDNSSettings(nwCfg *cni.NetworkConfig, dns network.DNSInfo, names
240240
return epDNS, nil
241241
}
242242

243-
// getPoliciesFromRuntimeCfg returns network policies from network config.
243+
/*
244+
getPoliciesFromRuntimeCfg returns network policies from network config.
245+
246+
Windows
247+
test-netconnection to ---> to node ipv4 to node ipv6 to localhost ipv4 to localhost ipv6
248+
host port mapping w/
249+
no host ip ok ok fail fail
250+
localhost ipv4 host ip fail fail fail fail
251+
node ipv6 host ip fail ok fail fail
252+
localhost ipv6 host ip fail fail fail fail
253+
node ipv4 host ip ok fail fail fail
254+
*/
244255
func getPoliciesFromRuntimeCfg(nwCfg *cni.NetworkConfig, isIPv6Enabled bool) ([]policy.Policy, error) {
245256
logger.Info("Runtime Info", zap.Any("config", nwCfg.RuntimeConfig))
246257
var policies []policy.Policy
@@ -261,7 +272,8 @@ func getPoliciesFromRuntimeCfg(nwCfg *cni.NetworkConfig, isIPv6Enabled bool) ([]
261272
// To support hostport policy mapping for ipv6 in dualstack overlay mode
262273
// uint32 NatFlagsIPv6 = 2
263274

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

280-
rawPolicy, err := json.Marshal(&hnsv2.PortMappingPolicySetting{
281-
ExternalPort: uint16(mapping.HostPort),
282-
InternalPort: uint16(mapping.ContainerPort),
283-
VIP: mapping.HostIp,
284-
Protocol: protocol,
285-
Flags: flag,
286-
})
287-
292+
hnsPortMappingPolicy, err := createPortMappingPolicy(mapping.HostPort, mapping.ContainerPort, mapping.HostIp, protocol, flag)
288293
if err != nil {
289-
return nil, errors.Wrap(err, "failed to marshal HNS portMappingPolicySetting")
294+
return nil, err
290295
}
291296

292-
hnsv2Policy, err := json.Marshal(&hnsv2.EndpointPolicy{
293-
Type: hnsv2.PortMapping,
294-
Settings: rawPolicy,
295-
})
297+
logger.Info("Creating port mapping policy", zap.Any("policy", hnsPortMappingPolicy))
298+
policies = append(policies, *hnsPortMappingPolicy)
296299

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

301-
hnsPolicy := policy.Policy{
302-
Type: policy.EndpointPolicy,
303-
Data: hnsv2Policy,
304-
}
311+
return policies, nil
312+
}
305313

306-
logger.Info("Creating port mapping policy", zap.Any("policy", hnsPolicy))
314+
func createPortMappingPolicy(hostPort, containerPort int, hostIP string, protocol uint32, flags hnsv2.NatFlags) (*policy.Policy, error) {
315+
rawPolicy, err := json.Marshal(&hnsv2.PortMappingPolicySetting{
316+
ExternalPort: uint16(hostPort),
317+
InternalPort: uint16(containerPort),
318+
VIP: hostIP,
319+
Protocol: protocol,
320+
Flags: flags,
321+
})
322+
if err != nil {
323+
return nil, errors.Wrap(err, "failed to marshal HNS portMappingPolicySetting")
324+
}
307325

308-
policies = append(policies, hnsPolicy)
326+
hnsv2Policy, err := json.Marshal(&hnsv2.EndpointPolicy{
327+
Type: hnsv2.PortMapping,
328+
Settings: rawPolicy,
329+
})
330+
if err != nil {
331+
return nil, errors.Wrap(err, "failed to marshal HNS endpointPolicy")
309332
}
310333

311-
return policies, nil
334+
hnsPolicy := policy.Policy{
335+
Type: policy.EndpointPolicy,
336+
Data: hnsv2Policy,
337+
}
338+
339+
return &hnsPolicy, nil
312340
}
313341

314342
func getEndpointPolicies(args PolicyArgs) ([]policy.Policy, error) {

cni/network/network_windows_test.go

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package network
55

66
import (
7+
"encoding/json"
78
"fmt"
89
"net"
910
"testing"
@@ -14,6 +15,7 @@ import (
1415
"github.com/Azure/azure-container-networking/network/hnswrapper"
1516
"github.com/Azure/azure-container-networking/network/policy"
1617
"github.com/Azure/azure-container-networking/telemetry"
18+
hnsv2 "github.com/Microsoft/hcsshim/hcn"
1719
"github.com/containernetworking/cni/pkg/skel"
1820
"github.com/stretchr/testify/assert"
1921
"github.com/stretchr/testify/require"
@@ -219,8 +221,10 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
219221
name string
220222
nwCfg cni.NetworkConfig
221223
isIPv6Enabled bool
224+
expected []hnsv2.PortMappingPolicySetting
222225
}{
223226
{
227+
// ipv6 disabled, ipv4 host ip --> ipv4 host ip policy only
224228
name: "Runtime network polices",
225229
nwCfg: cni.NetworkConfig{
226230
RuntimeConfig: cni.RuntimeConfig{
@@ -235,9 +239,19 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
235239
},
236240
},
237241
isIPv6Enabled: false,
242+
expected: []hnsv2.PortMappingPolicySetting{
243+
{
244+
ExternalPort: uint16(8000),
245+
InternalPort: uint16(80),
246+
VIP: "192.168.0.4",
247+
Protocol: policy.ProtocolTcp,
248+
Flags: hnsv2.NatFlagsLocalRoutedVip,
249+
},
250+
},
238251
},
239252
{
240-
name: "Runtime hostPort mapping polices",
253+
// ipv6 disabled, no host ip --> ipv4 policy only
254+
name: "Runtime hostPort mapping polices without hostIP",
241255
nwCfg: cni.NetworkConfig{
242256
RuntimeConfig: cni.RuntimeConfig{
243257
PortMappings: []cni.PortMapping{
@@ -250,8 +264,17 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
250264
},
251265
},
252266
isIPv6Enabled: false,
267+
expected: []hnsv2.PortMappingPolicySetting{
268+
{
269+
ExternalPort: uint16(44000),
270+
InternalPort: uint16(80),
271+
Protocol: policy.ProtocolTcp,
272+
Flags: hnsv2.NatFlagsLocalRoutedVip,
273+
},
274+
},
253275
},
254276
{
277+
// ipv6 enabled, ipv6 host ip --> ipv6 host ip policy only
255278
name: "Runtime hostPort mapping polices with ipv6 hostIP",
256279
nwCfg: cni.NetworkConfig{
257280
RuntimeConfig: cni.RuntimeConfig{
@@ -266,6 +289,99 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
266289
},
267290
},
268291
isIPv6Enabled: true,
292+
expected: []hnsv2.PortMappingPolicySetting{
293+
{
294+
ExternalPort: uint16(44000),
295+
InternalPort: uint16(80),
296+
VIP: "2001:2002:2003::1",
297+
Protocol: policy.ProtocolTcp,
298+
Flags: hnsv2.NatFlagsIPv6,
299+
},
300+
},
301+
},
302+
{
303+
// ipv6 enabled, ipv4 host ip --> ipv4 host ip policy only
304+
name: "Runtime hostPort mapping polices with ipv4 hostIP on ipv6 enabled cluster",
305+
nwCfg: cni.NetworkConfig{
306+
RuntimeConfig: cni.RuntimeConfig{
307+
PortMappings: []cni.PortMapping{
308+
{
309+
Protocol: "tcp",
310+
HostPort: 44000,
311+
ContainerPort: 80,
312+
HostIp: "192.168.0.4",
313+
},
314+
},
315+
},
316+
},
317+
isIPv6Enabled: true,
318+
expected: []hnsv2.PortMappingPolicySetting{
319+
{
320+
ExternalPort: uint16(44000),
321+
InternalPort: uint16(80),
322+
VIP: "192.168.0.4",
323+
Protocol: policy.ProtocolTcp,
324+
Flags: hnsv2.NatFlagsLocalRoutedVip,
325+
},
326+
},
327+
},
328+
{
329+
// ipv6 enabled, no host ip --> ipv4 and ipv6 policies
330+
name: "Runtime hostPort mapping polices with ipv6 without hostIP",
331+
nwCfg: cni.NetworkConfig{
332+
RuntimeConfig: cni.RuntimeConfig{
333+
PortMappings: []cni.PortMapping{
334+
{
335+
Protocol: "tcp",
336+
HostPort: 44000,
337+
ContainerPort: 80,
338+
},
339+
},
340+
},
341+
},
342+
isIPv6Enabled: true,
343+
expected: []hnsv2.PortMappingPolicySetting{
344+
{
345+
ExternalPort: uint16(44000),
346+
InternalPort: uint16(80),
347+
VIP: "",
348+
Protocol: policy.ProtocolTcp,
349+
Flags: hnsv2.NatFlagsLocalRoutedVip,
350+
},
351+
{
352+
ExternalPort: uint16(44000),
353+
InternalPort: uint16(80),
354+
VIP: "",
355+
Protocol: policy.ProtocolTcp,
356+
Flags: hnsv2.NatFlagsIPv6,
357+
},
358+
},
359+
},
360+
{
361+
// ipv6 enabled, ipv6 localhost ip --> ipv6 host ip policy only
362+
name: "Runtime hostPort mapping polices with ipv6 localhost hostIP on ipv6 enabled cluster",
363+
nwCfg: cni.NetworkConfig{
364+
RuntimeConfig: cni.RuntimeConfig{
365+
PortMappings: []cni.PortMapping{
366+
{
367+
Protocol: "tcp",
368+
HostPort: 44000,
369+
ContainerPort: 80,
370+
HostIp: "::1",
371+
},
372+
},
373+
},
374+
},
375+
isIPv6Enabled: true,
376+
expected: []hnsv2.PortMappingPolicySetting{
377+
{
378+
ExternalPort: uint16(44000),
379+
InternalPort: uint16(80),
380+
VIP: "::1",
381+
Protocol: policy.ProtocolTcp,
382+
Flags: hnsv2.NatFlagsIPv6,
383+
},
384+
},
269385
},
270386
}
271387
for _, tt := range tests {
@@ -276,6 +392,18 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
276392
require.Condition(t, assert.Comparison(func() bool {
277393
return len(policies) > 0 && policies[0].Type == policy.EndpointPolicy
278394
}))
395+
require.Equal(t, len(tt.expected), len(policies), "expected number of policies not equal to actual")
396+
for index, policy := range policies {
397+
var hnsv2Policy hnsv2.EndpointPolicy
398+
err = json.Unmarshal(policy.Data, &hnsv2Policy)
399+
require.NoError(t, err, "failed to unmarshal hnsv2 policy")
400+
401+
var rawPolicy hnsv2.PortMappingPolicySetting
402+
err = json.Unmarshal(hnsv2Policy.Settings, &rawPolicy)
403+
require.NoError(t, err, "failed to unmarshal hnsv2 port mapping policy")
404+
405+
require.Equal(t, tt.expected[index], rawPolicy, "policies are not expected")
406+
}
279407
})
280408
}
281409
}

0 commit comments

Comments
 (0)