@@ -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+
322395func 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
374448var (
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)
0 commit comments