Skip to content

Commit

Permalink
feat: use never used address first to reduce conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
oilbeater committed Jun 17, 2020
1 parent 0bd4762 commit 8d7045b
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 4 deletions.
19 changes: 16 additions & 3 deletions pkg/ipam/subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type Subnet struct {
mutex sync.RWMutex
CIDR *net.IPNet
FreeIPList IPRangeList
ReleasedIPList IPRangeList
ReservedIPList IPRangeList
PodToIP map[string]IP
IPToPod map[IP]string
Expand All @@ -32,6 +33,7 @@ func NewSubnet(name, cidrStr string, excludeIps []string) (*Subnet, error) {
mutex: sync.RWMutex{},
CIDR: cidr,
FreeIPList: IPRangeList{&IPRange{Start: IP(firstIP), End: IP(lastIP)}},
ReleasedIPList: IPRangeList{},
ReservedIPList: convertExcludeIps(excludeIps),
PodToIP: map[string]IP{},
IPToPod: map[IP]string{},
Expand Down Expand Up @@ -72,7 +74,12 @@ func (subnet *Subnet) GetRandomAddress(podName string) (IP, string, error) {
return ip, subnet.PodToMac[podName], nil
}
if len(subnet.FreeIPList) == 0 {
return "", "", NoAvailableError
if len(subnet.ReleasedIPList) != 0 {
subnet.FreeIPList = subnet.ReleasedIPList
subnet.ReleasedIPList = IPRangeList{}
} else {
return "", "", NoAvailableError
}
}
freeList := subnet.FreeIPList
ipr := freeList[0]
Expand Down Expand Up @@ -128,6 +135,12 @@ func (subnet *Subnet) GetStaticAddress(podName string, ip IP, mac string, force
subnet.IPToPod[ip] = podName
return ip, mac, nil
} else {
if split, newReleasedList := splitIPRangeList(subnet.ReleasedIPList, ip); split {
subnet.ReleasedIPList = newReleasedList
subnet.PodToIP[podName] = ip
subnet.IPToPod[ip] = podName
return ip, mac, nil
}
return ip, mac, NoAvailableError
}
}
Expand All @@ -153,8 +166,8 @@ func (subnet *Subnet) ReleaseAddress(podName string) (IP, string) {
return ip, mac
}

if merged, newFreeList := mergeIPRangeList(subnet.FreeIPList, ip); merged {
subnet.FreeIPList = newFreeList
if merged, newFreeList := mergeIPRangeList(subnet.ReleasedIPList, ip); merged {
subnet.ReleasedIPList = newFreeList
return ip, mac
}
}
Expand Down
19 changes: 19 additions & 0 deletions test/e2e/ip/static_ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,25 @@ var _ = Describe("[IP Allocation]", func() {
Expect([]string{"12.10.0.20", "12.10.0.21", "12.10.0.22"}).To(ContainElement(pod1.Status.PodIP))
Expect([]string{"12.10.0.20", "12.10.0.21", "12.10.0.22"}).To(ContainElement(pod2.Status.PodIP))
Expect([]string{"12.10.0.20", "12.10.0.21", "12.10.0.22"}).To(ContainElement(pod3.Status.PodIP))

By("Delete pods and recreate")
err = f.KubeClientSet.CoreV1().Pods(namespace).DeleteCollection(&metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: labels.SelectorFromSet(deployment.Spec.Template.Labels).String()})
Expect(err).NotTo(HaveOccurred())

err = f.WaitDeploymentReady(name, namespace)
Expect(err).NotTo(HaveOccurred())

pods, err = f.KubeClientSet.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: labels.SelectorFromSet(deployment.Spec.Template.Labels).String()})
Expect(err).NotTo(HaveOccurred())
Expect(pods.Items).To(HaveLen(3))

pod1, pod2, pod3 = pods.Items[0], pods.Items[1], pods.Items[2]
Expect(pod1.Status.PodIP).NotTo(Equal(pod2.Status.PodIP))
Expect(pod2.Status.PodIP).NotTo(Equal(pod3.Status.PodIP))
Expect(pod1.Status.PodIP).NotTo(Equal(pod3.Status.PodIP))
Expect([]string{"12.10.0.20", "12.10.0.21", "12.10.0.22"}).To(ContainElement(pod1.Status.PodIP))
Expect([]string{"12.10.0.20", "12.10.0.21", "12.10.0.22"}).To(ContainElement(pod2.Status.PodIP))
Expect([]string{"12.10.0.20", "12.10.0.21", "12.10.0.22"}).To(ContainElement(pod3.Status.PodIP))
})

It("statefulset with ippool", func() {
Expand Down
24 changes: 23 additions & 1 deletion test/unittest/ipam/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,27 @@ var _ = Describe("[IPAM]", func() {
Expect(ip).To(Equal("10.17.0.2"))

})

It("reuse released address when no unused address", func() {
im := ipam.NewIPAM()
err := im.AddOrUpdateSubnet("test", "10.16.0.0/30", []string{})
Expect(err).ShouldNot(HaveOccurred())

ip, _, err := im.GetRandomAddress("pod1.ns", "test")
Expect(err).ShouldNot(HaveOccurred())
Expect(ip).To(Equal("10.16.0.1"))

im.ReleaseAddressByPod("pod1.ns")
ip, _, err = im.GetRandomAddress("pod1.ns", "test")
Expect(err).ShouldNot(HaveOccurred())
Expect(ip).To(Equal("10.16.0.2"))

im.ReleaseAddressByPod("pod1.ns")
ip, _, err = im.GetRandomAddress("pod1.ns", "test")
Expect(err).ShouldNot(HaveOccurred())
Expect(ip).To(Equal("10.16.0.1"))

})
})

Describe("[IP]", func() {
Expand Down Expand Up @@ -141,7 +162,6 @@ var _ = Describe("[IPAM]", func() {
subnet.ReleaseAddress("pod3.ns")
Expect(subnet.FreeIPList).To(Equal(
ipam.IPRangeList{
&ipam.IPRange{Start: "10.16.0.2", End: "10.16.0.3"},
&ipam.IPRange{Start: "10.16.0.5", End: "10.16.0.9"},
&ipam.IPRange{Start: "10.16.0.24", End: "10.16.255.254"},
}))
Expand Down Expand Up @@ -177,6 +197,8 @@ var _ = Describe("[IPAM]", func() {
subnet.ReleaseAddress("pod1.ns")
subnet.ReleaseAddress("pod2.ns")
Expect(subnet.FreeIPList).To(Equal(
ipam.IPRangeList{}))
Expect(subnet.ReleasedIPList).To(Equal(
ipam.IPRangeList{
&ipam.IPRange{Start: "10.16.0.1", End: "10.16.0.2"},
}))
Expand Down

0 comments on commit 8d7045b

Please sign in to comment.