Skip to content

Commit f6977d7

Browse files
committed
added secondary ips field to CNS response for swiftv1 multitenancy
1 parent ab1c159 commit f6977d7

File tree

2 files changed

+83
-6
lines changed

2 files changed

+83
-6
lines changed

cni/network/multitenancy.go

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,59 @@ func (m *Multitenancy) GetAllNetworkContainers(
220220
ipamResult.interfaceInfo = make(map[string]network.InterfaceInfo)
221221

222222
for i := 0; i < len(ncResponses); i++ {
223+
// Validate SecondaryIPConfigurations contains at most one IPv6
224+
ipv6Config, err := validateAndGetIPv6FromSecondaryIPs(ncResponses[i].SecondaryIPConfigurations)
225+
if err != nil {
226+
logger.Error("Failed to validate SecondaryIPConfigurations",
227+
zap.Int("ncResponseIndex", i),
228+
zap.String("ncID", ncResponses[i].NetworkContainerID),
229+
zap.Error(err))
230+
return IPAMAddResult{}, fmt.Errorf("validation failed for NC %s: %w", ncResponses[i].NetworkContainerID, err)
231+
}
232+
223233
// one ncResponse gets you one interface info in the returned IPAMAddResult
224234
ifInfo := network.InterfaceInfo{
225235
NCResponse: &ncResponses[i],
226236
HostSubnetPrefix: hostSubnetPrefixes[i],
227237
}
228238

239+
// Process primary IPv4 configuration
229240
ipconfig, routes := convertToIPConfigAndRouteInfo(ifInfo.NCResponse)
230241
ifInfo.IPConfigs = append(ifInfo.IPConfigs, ipconfig)
231242
ifInfo.Routes = routes
243+
244+
// Process secondary IPv6 configuration if present
245+
if ipv6Config != nil {
246+
logger.Info("Processing IPv6 from SecondaryIPConfigurations",
247+
zap.String("ipv6Address", ipv6Config.IPSubnet.IPAddress),
248+
zap.String("ncID", ncResponses[i].NetworkContainerID))
249+
250+
ipv6Addr := net.ParseIP(ipv6Config.IPSubnet.IPAddress)
251+
ipv6IPConfig := &network.IPConfig{
252+
Address: net.IPNet{
253+
IP: ipv6Addr,
254+
Mask: net.CIDRMask(int(ipv6Config.IPSubnet.PrefixLength), ipv6FullMask),
255+
},
256+
}
257+
258+
// Set IPv6 gateway if provided
259+
if ipv6Config.GatewayIPAddress != "" {
260+
ipv6IPConfig.Gateway = net.ParseIP(ipv6Config.GatewayIPAddress)
261+
} else if ipv6Config.GatewayIPv6Address != "" {
262+
ipv6IPConfig.Gateway = net.ParseIP(ipv6Config.GatewayIPv6Address)
263+
}
264+
265+
// Add IPv6 configuration to the interface
266+
ifInfo.IPConfigs = append(ifInfo.IPConfigs, ipv6IPConfig)
267+
268+
// Add IPv6 routes if gateway is specified
269+
if ipv6IPConfig.Gateway != nil {
270+
_, defaultIPv6Net, _ := net.ParseCIDR("::/0")
271+
dstIPv6 := net.IPNet{IP: net.ParseIP("::"), Mask: defaultIPv6Net.Mask}
272+
ifInfo.Routes = append(ifInfo.Routes, network.RouteInfo{Dst: dstIPv6, Gw: ipv6IPConfig.Gateway})
273+
}
274+
}
275+
232276
ifInfo.NICType = cns.InfraNIC
233277
ifInfo.SkipDefaultRoutes = ncResponses[i].SkipDefaultRoutes
234278

@@ -299,7 +343,7 @@ func convertToCniResult(networkConfig *cns.GetNetworkContainerResponse, ifName s
299343
resultIpconfig.Gateway = net.ParseIP(ipconfig.GatewayIPAddress)
300344
result.IPs = append(result.IPs, resultIpconfig)
301345

302-
if networkConfig.Routes != nil && len(networkConfig.Routes) > 0 {
346+
if len(networkConfig.Routes) > 0 {
303347
for _, route := range networkConfig.Routes {
304348
_, routeIPnet, _ := net.ParseCIDR(route.IPAddress)
305349
gwIP := net.ParseIP(route.GatewayIPAddress)
@@ -319,7 +363,37 @@ func convertToCniResult(networkConfig *cns.GetNetworkContainerResponse, ifName s
319363
return result
320364
}
321365

366+
// validateAndGetIPv6FromSecondaryIPs validates that SecondaryIPConfigurations contains at most one IPv6
367+
// and returns it if present. Returns nil if no IPv6 is found, or an error if validation fails.
368+
func validateAndGetIPv6FromSecondaryIPs(secondaryIPConfigs []cns.IPConfiguration) (*cns.IPConfiguration, error) {
369+
if len(secondaryIPConfigs) == 0 {
370+
return nil, nil
371+
}
372+
373+
var ipv6Config *cns.IPConfiguration
374+
ipv6Count := 0
375+
376+
for i := range secondaryIPConfigs {
377+
ipAddr := net.ParseIP(secondaryIPConfigs[i].IPSubnet.IPAddress)
378+
if ipAddr == nil {
379+
return nil, fmt.Errorf("%w: %s", errInvalidIPv6InSecondaryIPs, secondaryIPConfigs[i].IPSubnet.IPAddress)
380+
}
381+
382+
// Check if this is an IPv6 address
383+
if ipAddr.To4() == nil && ipAddr.To16() != nil {
384+
ipv6Count++
385+
if ipv6Count > 1 {
386+
return nil, errMultipleIPv6InSecondaryIPs
387+
}
388+
ipv6Config = &secondaryIPConfigs[i]
389+
}
390+
}
391+
392+
return ipv6Config, nil
393+
}
394+
322395
func convertToIPConfigAndRouteInfo(networkConfig *cns.GetNetworkContainerResponse) (*network.IPConfig, []network.RouteInfo) {
396+
// Process primary IPv4 configuration
323397
ipconfig := &network.IPConfig{}
324398
cnsIPConfig := networkConfig.IPConfiguration
325399
ipAddr := net.ParseIP(cnsIPConfig.IPSubnet.IPAddress)
@@ -333,7 +407,7 @@ func convertToIPConfigAndRouteInfo(networkConfig *cns.GetNetworkContainerRespons
333407
ipconfig.Gateway = net.ParseIP(cnsIPConfig.GatewayIPAddress)
334408

335409
routes := make([]network.RouteInfo, 0)
336-
if networkConfig.Routes != nil && len(networkConfig.Routes) > 0 {
410+
if len(networkConfig.Routes) > 0 {
337411
for _, route := range networkConfig.Routes {
338412
_, routeIPnet, _ := net.ParseCIDR(route.IPAddress)
339413
gwIP := net.ParseIP(route.GatewayIPAddress)
@@ -372,8 +446,10 @@ func (m *Multitenancy) getInterfaceInfoKey(nicType cns.NICType, i int) string {
372446
}
373447

374448
var (
375-
errSnatIP = errors.New("Snat IP not populated")
376-
errInfraVnet = errors.New("infravnet not populated")
377-
errSubnetOverlap = errors.New("subnet overlap error")
378-
errIfaceNotFound = errors.New("Interface not found for this ip")
449+
errSnatIP = errors.New("Snat IP not populated")
450+
errInfraVnet = errors.New("infravnet not populated")
451+
errSubnetOverlap = errors.New("subnet overlap error")
452+
errIfaceNotFound = errors.New("Interface not found for this ip")
453+
errMultipleIPv6InSecondaryIPs = errors.New("SecondaryIPConfigurations contains more than one IPv6")
454+
errInvalidIPv6InSecondaryIPs = errors.New("SecondaryIPConfigurations contains invalid IPv6 address")
379455
)

cns/NetworkContainerContract.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ type GetNetworkContainerResponse struct {
504504
AllowNCToHostCommunication bool
505505
SkipDefaultRoutes bool
506506
NetworkInterfaceInfo NetworkInterfaceInfo
507+
SecondaryIPConfigurations []IPConfiguration // Secondary IPs for dual-stack support (e.g., IPv6)
507508
}
508509

509510
type PodIpInfo struct {

0 commit comments

Comments
 (0)