Skip to content

Commit a1550f2

Browse files
NihaNallappagarikadevunihanMicrosoft
authored
Prefix on nicv6 support (#3658)
* Prefix on NIC v6 support * update dedup comment in ipam * add log for a gatway error scenario * handle synchostversion sync on pon swiftv2 nic * handle gatewayip parse failure or nil scenario * remove unused code Address PR comments remove unnecessary logger update synhost skip test scenario fix linting error updated lint error fix linting error . update synhost skip test scenario fix linting error updated lint error fix linting error . * add test scenario * update test to handle gatway nil case * remove synchost skip and single ip skip . . * Add missing test scenarios * fix ipam_test conflicts * fix conflits small fixes fix lint errors lint fix . Delete examples/imds_nc_lookup.go Signed-off-by: NihaNallappagari <69693983+NihaNallappagari@users.noreply.github.com> fix lint . * fix linting * add todo and remove multiple interface scenario * Skip add primary ip's to secondary config for swiftv2 pon scenarios fix lint error . * code review comment * Update gateway ipv6 to use default value, that auto detects and adds to neigh table * remove unwanted changes * address ipfamily comment * fix test failure * Handle nilgateway scenario * remove unnedded else block * comments changes --------- Co-authored-by: Kaushik Vuligonda <kadevu@microsoft.com> Co-authored-by: nn052161 <nihan@microsoft.com>
1 parent d09fdf0 commit a1550f2

File tree

16 files changed

+1012
-328
lines changed

16 files changed

+1012
-328
lines changed

azure-ipam/ipam.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ func (p *IPAMPlugin) CmdAdd(args *cniSkel.CmdArgs) error {
115115
p.logger.Debug("Received CNS IP config response", zap.Any("response", resp))
116116

117117
// Get Pod IP and gateway IP from ip config response
118-
podIPNet, err := ipconfig.ProcessIPConfigsResp(resp)
118+
podIPNet, gatewayIP, err := ipconfig.ProcessIPConfigsResp(resp)
119119
if err != nil {
120120
p.logger.Error("Failed to interpret CNS IPConfigResponse", zap.Error(err), zap.Any("response", resp))
121121
return cniTypes.NewError(ErrProcessIPConfigResponse, err.Error(), "failed to interpret CNS IPConfigResponse")
@@ -136,9 +136,33 @@ func (p *IPAMPlugin) CmdAdd(args *cniSkel.CmdArgs) error {
136136
Mask: net.CIDRMask(ipNet.Bits(), 128), // nolint
137137
}
138138
}
139+
ipConfig.Gateway = (*gatewayIP)[i]
139140
cniResult.IPs[i] = ipConfig
140141
}
141142

143+
cniResult.Interfaces = []*types100.Interface{}
144+
seenInterfaces := map[string]bool{}
145+
146+
for _, podIPInfo := range resp.PodIPInfo {
147+
// Skip if interface already seen
148+
// This is to avoid duplicate interfaces in the result
149+
// Deduplication is necessary because there is one podIPInfo entry for each IP family(IPv4 and IPv6), and both may point to the same interface
150+
if podIPInfo.MacAddress == "" || seenInterfaces[podIPInfo.MacAddress] {
151+
continue
152+
}
153+
154+
infMac, err := net.ParseMAC(podIPInfo.MacAddress)
155+
if err != nil {
156+
p.logger.Error("Failed to parse interface MAC address", zap.Error(err), zap.String("macAddress", podIPInfo.MacAddress))
157+
return cniTypes.NewError(cniTypes.ErrUnsupportedField, err.Error(), "failed to parse interface MAC address")
158+
}
159+
160+
cniResult.Interfaces = append(cniResult.Interfaces, &types100.Interface{
161+
Mac: infMac.String(),
162+
})
163+
seenInterfaces[podIPInfo.MacAddress] = true
164+
}
165+
142166
// Get versioned result
143167
versionedCniResult, err := cniResult.GetAsVersion(nwCfg.CNIVersion)
144168
if err != nil {

azure-ipam/ipam_test.go

Lines changed: 146 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,68 @@ func (c *MockCNSClient) RequestIPAddress(ctx context.Context, ipconfig cns.IPCon
5858
},
5959
}
6060
return result, nil
61+
case "nilGateway":
62+
result := &cns.IPConfigResponse{
63+
PodIpInfo: cns.PodIpInfo{
64+
PodIPConfig: cns.IPSubnet{
65+
IPAddress: "10.0.1.10",
66+
PrefixLength: 24,
67+
},
68+
NetworkContainerPrimaryIPConfig: cns.IPConfiguration{
69+
IPSubnet: cns.IPSubnet{
70+
IPAddress: "10.0.1.0",
71+
PrefixLength: 24,
72+
},
73+
DNSServers: nil,
74+
GatewayIPAddress: "", // nil/empty gateway
75+
},
76+
HostPrimaryIPInfo: cns.HostIPInfo{
77+
Gateway: "",
78+
PrimaryIP: "10.0.0.1",
79+
Subnet: "10.0.0.0/24",
80+
},
81+
},
82+
Response: cns.Response{
83+
ReturnCode: 0,
84+
Message: "",
85+
},
86+
}
87+
return result, nil
88+
case "invalidGateway":
89+
result := &cns.IPConfigResponse{
90+
PodIpInfo: cns.PodIpInfo{
91+
PodIPConfig: cns.IPSubnet{
92+
IPAddress: "10.0.1.10",
93+
PrefixLength: 24,
94+
},
95+
NetworkContainerPrimaryIPConfig: cns.IPConfiguration{
96+
IPSubnet: cns.IPSubnet{
97+
IPAddress: "10.0.1.0",
98+
PrefixLength: 24,
99+
},
100+
DNSServers: nil,
101+
GatewayIPAddress: "invalidgatewayip",
102+
},
103+
HostPrimaryIPInfo: cns.HostIPInfo{
104+
Gateway: "invalidgatewayip",
105+
PrimaryIP: "10.0.0.1",
106+
Subnet: "10.0.0.0/24",
107+
},
108+
},
109+
Response: cns.Response{
110+
ReturnCode: 0,
111+
Message: "",
112+
},
113+
}
114+
return result, nil
61115
default:
62116
result := &cns.IPConfigResponse{
63117
PodIpInfo: cns.PodIpInfo{
64118
PodIPConfig: cns.IPSubnet{
65119
IPAddress: "10.0.1.10",
66120
PrefixLength: 24,
67121
},
122+
MacAddress: "00:11:22:33:44:55",
68123
NetworkContainerPrimaryIPConfig: cns.IPConfiguration{
69124
IPSubnet: cns.IPSubnet{
70125
IPAddress: "10.0.1.0",
@@ -92,11 +147,60 @@ func (c *MockCNSClient) RequestIPs(ctx context.Context, ipconfig cns.IPConfigsRe
92147
switch ipconfig.InfraContainerID {
93148
case "failRequestCNSArgs":
94149
return nil, errFoo
95-
case "happyArgsSingle", "failProcessCNSRespSingleIP", "failRequestCNSArgsSingleIP":
150+
case "happyArgsSingle", "failProcessCNSRespSingleIP", "failRequestCNSArgsSingleIP", "nilGateway", "invalidGateway":
96151
e := &client.CNSClientError{}
97152
e.Code = types.UnsupportedAPI
98153
e.Err = errUnsupportedAPI
99154
return nil, e
155+
case "happyArgsDual":
156+
result := &cns.IPConfigsResponse{
157+
PodIPInfo: []cns.PodIpInfo{
158+
{
159+
PodIPConfig: cns.IPSubnet{
160+
IPAddress: "10.0.1.10",
161+
PrefixLength: 24,
162+
},
163+
MacAddress: "00:11:22:33:44:55",
164+
NetworkContainerPrimaryIPConfig: cns.IPConfiguration{
165+
IPSubnet: cns.IPSubnet{
166+
IPAddress: "10.0.1.0",
167+
PrefixLength: 24,
168+
},
169+
DNSServers: nil,
170+
GatewayIPAddress: "10.0.0.1",
171+
},
172+
HostPrimaryIPInfo: cns.HostIPInfo{
173+
Gateway: "10.0.0.1",
174+
PrimaryIP: "10.0.0.1",
175+
Subnet: "10.0.0.0/24",
176+
},
177+
},
178+
{
179+
PodIPConfig: cns.IPSubnet{
180+
IPAddress: "fd11:1234::1",
181+
PrefixLength: 120,
182+
},
183+
MacAddress: "00:11:22:33:44:55", // Same MAC for dual-stack scenario
184+
NetworkContainerPrimaryIPConfig: cns.IPConfiguration{
185+
IPSubnet: cns.IPSubnet{
186+
IPAddress: "fd11:1234::",
187+
PrefixLength: 120,
188+
},
189+
DNSServers: nil,
190+
},
191+
HostPrimaryIPInfo: cns.HostIPInfo{
192+
Gateway: "fe80::1234:5678:9abc",
193+
PrimaryIP: "fe80::1234:5678:9abc",
194+
Subnet: "fd11:1234::/120",
195+
},
196+
},
197+
},
198+
Response: cns.Response{
199+
ReturnCode: 0,
200+
Message: "",
201+
},
202+
}
203+
return result, nil
100204
case "failProcessCNSResp":
101205
result := &cns.IPConfigsResponse{
102206
PodIPInfo: []cns.PodIpInfo{
@@ -129,8 +233,7 @@ func (c *MockCNSClient) RequestIPs(ctx context.Context, ipconfig cns.IPConfigsRe
129233
IPAddress: "fd11:1234::",
130234
PrefixLength: 112,
131235
},
132-
DNSServers: nil,
133-
GatewayIPAddress: "fe80::1234:5678:9abc",
236+
DNSServers: nil,
134237
},
135238
HostPrimaryIPInfo: cns.HostIPInfo{
136239
Gateway: "fe80::1234:5678:9abc",
@@ -153,6 +256,7 @@ func (c *MockCNSClient) RequestIPs(ctx context.Context, ipconfig cns.IPConfigsRe
153256
IPAddress: "10.0.1.10",
154257
PrefixLength: 24,
155258
},
259+
MacAddress: "00:11:22:33:44:55",
156260
NetworkContainerPrimaryIPConfig: cns.IPConfiguration{
157261
IPSubnet: cns.IPSubnet{
158262
IPAddress: "10.0.1.0",
@@ -172,13 +276,13 @@ func (c *MockCNSClient) RequestIPs(ctx context.Context, ipconfig cns.IPConfigsRe
172276
IPAddress: "fd11:1234::1",
173277
PrefixLength: 120,
174278
},
279+
MacAddress: "00:11:22:33:44:55", // Same MAC for dual-stack scenario
175280
NetworkContainerPrimaryIPConfig: cns.IPConfiguration{
176281
IPSubnet: cns.IPSubnet{
177282
IPAddress: "fd11:1234::",
178283
PrefixLength: 120,
179284
},
180-
DNSServers: nil,
181-
GatewayIPAddress: "fe80::1234:5678:9abc",
285+
DNSServers: nil,
182286
},
183287
HostPrimaryIPInfo: cns.HostIPInfo{
184288
Gateway: "fe80::1234:5678:9abc",
@@ -281,12 +385,18 @@ func TestCmdAdd(t *testing.T) {
281385
args: buildArgs("happyArgsSingle", happyPodArgs, happyNetConfByteArr),
282386
want: &types100.Result{
283387
CNIVersion: "1.0.0",
388+
Interfaces: []*types100.Interface{
389+
{
390+
Mac: "00:11:22:33:44:55",
391+
},
392+
},
284393
IPs: []*types100.IPConfig{
285394
{
286395
Address: net.IPNet{
287396
IP: net.IPv4(10, 0, 1, 10),
288397
Mask: net.CIDRMask(24, 32),
289398
},
399+
Gateway: net.IPv4(10, 0, 0, 1),
290400
},
291401
},
292402
DNS: cniTypes.DNS{},
@@ -298,24 +408,55 @@ func TestCmdAdd(t *testing.T) {
298408
args: buildArgs("happyArgsDual", happyPodArgs, happyNetConfByteArr),
299409
want: &types100.Result{
300410
CNIVersion: "1.0.0",
411+
Interfaces: []*types100.Interface{
412+
{
413+
Mac: "00:11:22:33:44:55", // Single interface for dual-stack
414+
},
415+
},
301416
IPs: []*types100.IPConfig{
302417
{
303418
Address: net.IPNet{
304419
IP: net.IPv4(10, 0, 1, 10),
305420
Mask: net.CIDRMask(24, 32),
306421
},
422+
Gateway: net.IPv4(10, 0, 0, 1),
307423
},
308424
{
309425
Address: net.IPNet{
310426
IP: net.ParseIP("fd11:1234::1"),
311427
Mask: net.CIDRMask(120, 128),
312428
},
429+
Gateway: net.ParseIP("fe80::1234:5678:9abc"),
313430
},
314431
},
315432
DNS: cniTypes.DNS{},
316433
},
317434
wantErr: false,
318435
},
436+
{
437+
name: "CNI add with nil gateway IP",
438+
args: buildArgs("nilGateway", happyPodArgs, happyNetConfByteArr),
439+
want: &types100.Result{
440+
CNIVersion: "1.0.0",
441+
Interfaces: nil,
442+
IPs: []*types100.IPConfig{
443+
{
444+
Address: net.IPNet{
445+
IP: net.IPv4(10, 0, 1, 10),
446+
Mask: net.CIDRMask(24, 32),
447+
},
448+
Gateway: nil, // No gateway
449+
},
450+
},
451+
DNS: cniTypes.DNS{},
452+
},
453+
wantErr: false,
454+
},
455+
{
456+
name: "CNI add with invalid gateway IP",
457+
args: buildArgs("invalidGateway", happyPodArgs, happyNetConfByteArr),
458+
wantErr: true,
459+
},
319460
{
320461
name: "Fail request CNS ipconfig during CmdAdd",
321462
args: buildArgs("failRequestCNSArgs", happyPodArgs, happyNetConfByteArr),

azure-ipam/ipconfig/ipconfig.go

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package ipconfig
33
import (
44
"encoding/json"
55
"fmt"
6+
"net"
67
"net/netip"
78

89
"github.com/Azure/azure-container-networking/cns"
@@ -11,6 +12,10 @@ import (
1112
"github.com/pkg/errors"
1213
)
1314

15+
const (
16+
defaultV6Gateway = "fe80::1234:5678:9abc"
17+
)
18+
1419
func CreateOrchestratorContext(args *cniSkel.CmdArgs) ([]byte, error) {
1520
podConf, err := parsePodConf(args.Args)
1621
if err != nil {
@@ -63,23 +68,41 @@ func CreateIPConfigsReq(args *cniSkel.CmdArgs) (cns.IPConfigsRequest, error) {
6368
return req, nil
6469
}
6570

66-
func ProcessIPConfigsResp(resp *cns.IPConfigsResponse) (*[]netip.Prefix, error) {
71+
func ProcessIPConfigsResp(resp *cns.IPConfigsResponse) (*[]netip.Prefix, *[]net.IP, error) {
6772
podIPNets := make([]netip.Prefix, len(resp.PodIPInfo))
73+
gatewaysIPs := make([]net.IP, len(resp.PodIPInfo))
6874

6975
for i := range resp.PodIPInfo {
76+
var gatewayIP net.IP
77+
7078
podCIDR := fmt.Sprintf(
7179
"%s/%d",
7280
resp.PodIPInfo[i].PodIPConfig.IPAddress,
7381
resp.PodIPInfo[i].NetworkContainerPrimaryIPConfig.IPSubnet.PrefixLength,
7482
)
7583
podIPNet, err := netip.ParsePrefix(podCIDR)
7684
if err != nil {
77-
return nil, errors.Wrapf(err, "cns returned invalid pod CIDR %q", podCIDR)
85+
return nil, nil, errors.Wrapf(err, "cns returned invalid pod CIDR %q", podCIDR)
7886
}
7987
podIPNets[i] = podIPNet
88+
89+
var gatewayStr string
90+
if podIPNet.Addr().Is4() {
91+
gatewayStr = resp.PodIPInfo[i].NetworkContainerPrimaryIPConfig.GatewayIPAddress
92+
} else if podIPNet.Addr().Is6() {
93+
gatewayStr = defaultV6Gateway
94+
}
95+
96+
if gatewayStr != "" {
97+
gatewayIP = net.ParseIP(gatewayStr)
98+
if gatewayIP == nil {
99+
return nil, nil, errors.Errorf("failed to parse gateway IP %q for pod ip %s", gatewayStr, resp.PodIPInfo[i].PodIPConfig.IPAddress)
100+
}
101+
}
102+
gatewaysIPs[i] = gatewayIP
80103
}
81104

82-
return &podIPNets, nil
105+
return &podIPNets, &gatewaysIPs, nil
83106
}
84107

85108
type k8sPodEnvArgs struct {

cns/NetworkContainerContract.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,9 +398,10 @@ type NetworkInterfaceInfo struct {
398398

399399
// IPConfiguration contains details about ip config to provision in the VM.
400400
type IPConfiguration struct {
401-
IPSubnet IPSubnet
402-
DNSServers []string
403-
GatewayIPAddress string
401+
IPSubnet IPSubnet
402+
DNSServers []string
403+
GatewayIPAddress string
404+
GatewayIPv6Address string
404405
}
405406

406407
// SecondaryIPConfig contains IP info of SecondaryIP
@@ -755,3 +756,11 @@ type NodeRegisterRequest struct {
755756
NumCores int
756757
NmAgentSupportedApis []string
757758
}
759+
760+
// IPFamily - Enum for determining IPFamily when retrieving IPs from network containers
761+
type IPFamily string
762+
763+
const (
764+
IPv4 IPFamily = "ipv4"
765+
IPv6 IPFamily = "ipv6"
766+
)

cns/kubecontroller/nodenetworkconfig/conversion.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func CreateNCRequestFromDynamicNC(nc v1alpha.NetworkContainer) (*cns.CreateNetwo
7373
// CreateNCRequestFromStaticNC generates a CreateNetworkContainerRequest from a static NetworkContainer.
7474
//
7575
//nolint:gocritic //ignore hugeparam
76-
func CreateNCRequestFromStaticNC(nc v1alpha.NetworkContainer) (*cns.CreateNetworkContainerRequest, error) {
76+
func CreateNCRequestFromStaticNC(nc v1alpha.NetworkContainer, isSwiftV2 bool) (*cns.CreateNetworkContainerRequest, error) {
7777
if nc.Type == v1alpha.Overlay {
7878
nc.Version = 0 // fix for NMA always giving us version 0 for Overlay NCs
7979
}
@@ -97,7 +97,7 @@ func CreateNCRequestFromStaticNC(nc v1alpha.NetworkContainer) (*cns.CreateNetwor
9797
subnet.IPAddress = primaryPrefix.Addr().String()
9898
}
9999

100-
req, err := createNCRequestFromStaticNCHelper(nc, primaryPrefix, subnet)
100+
req, err := createNCRequestFromStaticNCHelper(nc, primaryPrefix, subnet, isSwiftV2)
101101
if err != nil {
102102
return nil, errors.Wrapf(err, "error while creating NC request from static NC")
103103
}

0 commit comments

Comments
 (0)