diff --git a/pkg/controller/subnet.go b/pkg/controller/subnet.go index 62b156207c2..6ae02aad1a0 100644 --- a/pkg/controller/subnet.go +++ b/pkg/controller/subnet.go @@ -2079,7 +2079,7 @@ func (c *Controller) calcDualSubnetStatusIP(subnet *kubeovnv1.Subnet) (*kubeovnv v6availableIPs = 0 } - v4UsingIPStr, v6UsingIPStr, v4AvailableIPStr, v6AvailableIPStr := c.ipam.GetSubnetIPRangeString(subnet.Name) + v4UsingIPStr, v6UsingIPStr, v4AvailableIPStr, v6AvailableIPStr := c.ipam.GetSubnetIPRangeString(subnet.Name, subnet.Spec.ExcludeIps) if subnet.Status.V4AvailableIPs == v4availableIPs && subnet.Status.V6AvailableIPs == v6availableIPs && @@ -2168,7 +2168,7 @@ func (c *Controller) calcSubnetStatusIP(subnet *kubeovnv1.Subnet) (*kubeovnv1.Su availableIPs = 0 } - v4UsingIPStr, v6UsingIPStr, v4AvailableIPStr, v6AvailableIPStr := c.ipam.GetSubnetIPRangeString(subnet.Name) + v4UsingIPStr, v6UsingIPStr, v4AvailableIPStr, v6AvailableIPStr := c.ipam.GetSubnetIPRangeString(subnet.Name, subnet.Spec.ExcludeIps) cachedFloatFields := [4]float64{ subnet.Status.V4AvailableIPs, subnet.Status.V4UsingIPs, diff --git a/pkg/ipam/ipam.go b/pkg/ipam/ipam.go index 73f7ce64f2f..e2c548cd111 100644 --- a/pkg/ipam/ipam.go +++ b/pkg/ipam/ipam.go @@ -380,16 +380,23 @@ func (ipam *IPAM) GetSubnetV4Mask(subnetName string) (string, error) { return "", ErrNoAvailable } -func (ipam *IPAM) GetSubnetIPRangeString(subnetName string) (string, string, string, string) { +func (ipam *IPAM) GetSubnetIPRangeString(subnetName string, excludeIps []string) (string, string, string, string) { ipam.mutex.RLock() defer ipam.mutex.RUnlock() + // subnet.Spec.ExcludeIps contains both v4 and v6 addresses + v4ExcludeIps, v6ExcludeIps := util.SplitIpsByProtocol(excludeIps) + var v4UsingIPStr, v6UsingIPStr, v4AvailableIPStr, v6AvailableIPStr string if subnet, ok := ipam.Subnets[subnetName]; ok { - v4UsingIPStr = subnet.V4Using.String() - v6UsingIPStr = subnet.V6Using.String() - v4AvailableIPStr = subnet.V4Available.String() - v6AvailableIPStr = subnet.V6Available.String() + v4Reserved, _ := NewIPRangeListFrom(v4ExcludeIps...) + v6Reserved, _ := NewIPRangeListFrom(v6ExcludeIps...) + + // do not count ips in excludeIPs as available and using IPs + v4AvailableIPStr = subnet.V4Available.Separate(v4Reserved).String() + v6AvailableIPStr = subnet.V6Available.Separate(v6Reserved).String() + v4UsingIPStr = subnet.V4Using.Separate(v4Reserved).String() + v6UsingIPStr = subnet.V6Using.Separate(v6Reserved).String() } return v4UsingIPStr, v6UsingIPStr, v4AvailableIPStr, v6AvailableIPStr diff --git a/pkg/ipam/subnet.go b/pkg/ipam/subnet.go index b02c4e78c71..db28c7ded86 100644 --- a/pkg/ipam/subnet.go +++ b/pkg/ipam/subnet.go @@ -396,6 +396,8 @@ func (s *Subnet) GetStaticAddress(podName, nicName string, ip IP, mac *string, f if pool.V4Reserved.Contains(ip) { s.V4NicToIP[nicName] = ip s.V4IPToPod[ip.String()] = podName + // ip allocated from excludeIPs should be recorded in usingIPs since when the ip is removed from excludeIPs, there's no way to update usingIPs + isAllocated = true return ip, macStr, nil } @@ -431,6 +433,7 @@ func (s *Subnet) GetStaticAddress(podName, nicName string, ip IP, mac *string, f if pool.V6Reserved.Contains(ip) { s.V6NicToIP[nicName] = ip s.V6IPToPod[ip.String()] = podName + isAllocated = true return ip, macStr, nil } diff --git a/test/unittest/ipam/ipam.go b/test/unittest/ipam/ipam.go index 3fea864f98c..efad75ab342 100644 --- a/test/unittest/ipam/ipam.go +++ b/test/unittest/ipam/ipam.go @@ -193,6 +193,26 @@ var _ = Describe("[IPAM]", func() { _, _, _, err = im.GetRandomAddress("pod1.ns", "pod1.ns", nil, subnetName, "", nil, true) Expect(err).Should(MatchError(ipam.ErrNoAvailable)) }) + + It("do not count excludedIps as subnet's v4availableIPs and v4usingIPs", func() { + im := ipam.NewIPAM() + err := im.AddOrUpdateSubnet(subnetName, "10.16.10.0/28", "10.16.10.1", []string{"10.16.10.1", "10.16.10.10"}) + Expect(err).ShouldNot(HaveOccurred()) + + ip, _, _, err := im.GetStaticAddress("pod1.ns", "pod1.ns", "10.16.10.10", nil, subnetName, true) + Expect(err).ShouldNot(HaveOccurred()) + Expect(ip).To(Equal("10.16.10.10")) + + v4UsingIPStr, _, v4AvailableIPStr, _ := im.GetSubnetIPRangeString(subnetName, []string{"10.16.10.10"}) + Expect(v4UsingIPStr).To(Equal("")) + Expect(v4AvailableIPStr).To(Equal("10.16.10.2-10.16.10.9,10.16.10.11-10.16.10.14")) + + err = im.AddOrUpdateSubnet(subnetName, "10.16.10.0/28", "10.16.10.1", []string{"10.16.10.1"}) + Expect(err).ShouldNot(HaveOccurred()) + v4UsingIPStr, _, v4AvailableIPStr, _ = im.GetSubnetIPRangeString(subnetName, nil) + Expect(v4UsingIPStr).To(Equal("10.16.10.10")) + Expect(v4AvailableIPStr).To(Equal("10.16.10.2-10.16.10.9,10.16.10.11-10.16.10.14")) + }) }) Context("[IPv6]", func() {