@@ -409,7 +409,7 @@ func (service *SubnetPortService) ResetSubnetTotalIP(path string) {
409409// AllocatePortFromSubnet checks the number of SubnetPorts on the Subnet.
410410// If the Subnet has capacity for the new SubnetPorts, it will increase
411411// the number of SubnetPort under creation and return true.
412- func (service * SubnetPortService ) AllocatePortFromSubnet (subnet * model.VpcSubnet ) (bool , error ) {
412+ func (service * SubnetPortService ) AllocatePortFromSubnet (subnet * model.VpcSubnet , sharedSubnet bool ) (bool , error ) {
413413 dhcpMode := "DHCP_DEACTIVATED"
414414 subnetInfo , _ := servicecommon .ParseVPCResourcePath (* subnet .Path )
415415 if subnet .SubnetDhcpConfig != nil && subnet .SubnetDhcpConfig .Mode != nil {
@@ -435,6 +435,7 @@ func (service *SubnetPortService) AllocatePortFromSubnet(subnet *model.VpcSubnet
435435 info .lock .Lock ()
436436 defer info .lock .Unlock ()
437437
438+ var allocatedIPNumber int
438439 // For DHCP Server mode Subnet, get total IPs from DHCP IP Pool from NSX each time
439440 // since user might update reservedIPRanges for the subnet and it impacts the DHCP Pool size
440441 if dhcpMode == "DHCP_SERVER" {
@@ -446,45 +447,62 @@ func (service *SubnetPortService) AllocatePortFromSubnet(subnet *model.VpcSubnet
446447 if len (dhcpServerStats .IpPoolStats ) > 0 && dhcpServerStats .IpPoolStats [0 ].PoolSize != nil {
447448 info .totalIP = int (* dhcpServerStats .IpPoolStats [0 ].PoolSize )
448449 }
450+ if sharedSubnet && len (dhcpServerStats .IpPoolStats ) > 0 && dhcpServerStats .IpPoolStats [0 ].AllocatedNumber != nil {
451+ allocatedIPNumber = int (* dhcpServerStats .IpPoolStats [0 ].AllocatedNumber )
452+ }
449453 }
450-
451- if ! ok || info .totalIP == 0 {
454+ // When SubnetIPReservation is created/deleted, we will reset the info.totalIP and
455+ // expect the totalIP is updated from NSX ip pool API
456+ // For shared Subnet, user can create IPReservation and SubnetPort from NSX side.
457+ // We call NSX ip pool API to for latest total ip and requested ip.
458+ if (! ok || info .totalIP == 0 || sharedSubnet ) && dhcpMode == "DHCP_DEACTIVATED" {
452459 // For DHCP Deactivated mode Subnet, get total IPs from IP pool static-ipv4-default
453- if dhcpMode == "DHCP_DEACTIVATED" {
454- // only get Subnet total IPs from static IP Pool if staticIpAllocation enabled
455- if staticIpAllocationEnabled {
456- staticIPPool , err := service .NSXClient .IPPoolClient .Get (subnetInfo .OrgID , subnetInfo .ProjectID , subnetInfo .VPCID , subnetInfo .ID , "static-ipv4-default" )
457- if err != nil {
458- log .Error (err , "Failed to get Subnet static IP Pool static-ipv4-default" , "Subnet" , * subnet .Path )
459- return false , err
460- }
461- if staticIPPool .PoolUsage .TotalIps != nil {
462- info .totalIP = int (* staticIPPool .PoolUsage .TotalIps )
463- }
460+ // only get Subnet total IPs from static IP Pool if staticIpAllocation enabled
461+ if staticIpAllocationEnabled {
462+ staticIPPool , err := service .NSXClient .IPPoolClient .Get (subnetInfo .OrgID , subnetInfo .ProjectID , subnetInfo .VPCID , subnetInfo .ID , "static-ipv4-default" )
463+ if err != nil {
464+ log .Error (err , "Failed to get Subnet static IP Pool static-ipv4-default" , "Subnet" , * subnet .Path )
465+ return false , err
464466 }
465- }
466- // For DHCP Relay mode Subnet, assume 4 reserved IPs
467- if dhcpMode == "DHCP_RELAY" {
468- var totalIP int
469- if subnet .Ipv4SubnetSize != nil {
470- totalIP = int (* subnet .Ipv4SubnetSize )
467+ if staticIPPool .PoolUsage != nil && staticIPPool .PoolUsage .TotalIps != nil {
468+ info .totalIP = int (* staticIPPool .PoolUsage .TotalIps )
471469 }
472- if len (subnet .IpAddresses ) > 0 {
473- // totalIP will be overrided if IpAddresses are specified.
474- totalIP , _ = util .CalculateIPFromCIDRs (subnet .IpAddresses )
470+ if sharedSubnet && staticIPPool .PoolUsage != nil && staticIPPool .PoolUsage .RequestedIpAllocations != nil {
471+ allocatedIPNumber = int (* staticIPPool .PoolUsage .RequestedIpAllocations )
475472 }
476- // NSX reserves 4 ip addresses in each subnet for network address, gateway address,
477- // dhcp server address and broadcast address.
478- info .totalIP = totalIP - 4
479473 }
480474 }
475+ if ! ok && dhcpMode == "DHCP_RELAY" {
476+ // For DHCP Relay mode Subnet, assume 4 reserved IPs
477+ var totalIP int
478+ if subnet .Ipv4SubnetSize != nil {
479+ totalIP = int (* subnet .Ipv4SubnetSize )
480+ }
481+ if len (subnet .IpAddresses ) > 0 {
482+ // totalIP will be overrided if IpAddresses are specified.
483+ totalIP , _ = util .CalculateIPFromCIDRs (subnet .IpAddresses )
484+ }
485+ // NSX reserves 4 ip addresses in each subnet for network address, gateway address,
486+ // dhcp server address and broadcast address.
487+ info .totalIP = totalIP - 4
488+ }
481489
482490 if time .Since (info .exhaustedCheckTime ) < IPReleaseTime {
483491 return false , nil
484492 }
493+
494+ existingPortCount := len (service .GetPortsOfSubnet (* subnet .Path ))
495+ // A shared Subnet can be used by other supervisors or other places where SubnetPort
496+ // is created and not in operator cache.
497+ // For DHCPServer Subnet, the allocated IP number wont change before the VM request IP
498+ // from the DHCPServer.
499+ // Thus we use the max number of port record in store and allocated number from API to
500+ // reduce the possibility to create SubnetPort on a Subnet without available IP
501+ if sharedSubnet {
502+ existingPortCount = max (existingPortCount , allocatedIPNumber )
503+ }
485504 // Number of SubnetPorts on the Subnet includes the SubnetPorts under creation
486505 // and the SubnetPorts already created
487- existingPortCount := len (service .GetPortsOfSubnet (* subnet .Path ))
488506 if info .dirtyCount + existingPortCount < info .totalIP {
489507 info .dirtyCount += 1
490508 log .Trace ("Allocate Subnetport to Subnet" , "Subnet" , * subnet .Path , "dirtyPortCount" , info .dirtyCount , "existingPortCount" , existingPortCount )
0 commit comments