Skip to content

Commit

Permalink
refactor IPAM
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangzujian committed Jun 3, 2023
1 parent efe3ee3 commit 91f76ed
Show file tree
Hide file tree
Showing 7 changed files with 661 additions and 628 deletions.
49 changes: 21 additions & 28 deletions pkg/controller/subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -2039,69 +2039,62 @@ func isOvnSubnet(subnet *kubeovnv1.Subnet) bool {

func checkAndFormatsExcludeIps(subnet *kubeovnv1.Subnet) bool {
var excludeIps []string
mapIps := make(map[string]ipam.IPRange, len(subnet.Spec.ExcludeIps))

mapIps := make(map[string]*ipam.IPRange, len(subnet.Spec.ExcludeIps))
for _, excludeIP := range subnet.Spec.ExcludeIps {
ips := strings.Split(excludeIP, "..")
if len(ips) == 1 {
if _, ok := mapIps[excludeIP]; !ok {
ipr := ipam.IPRange{Start: ipam.IP(ips[0]), End: ipam.IP(ips[0])}
mapIps[excludeIP] = ipr
}
} else {
if _, ok := mapIps[excludeIP]; !ok {
ipr := ipam.IPRange{Start: ipam.IP(ips[0]), End: ipam.IP(ips[1])}
mapIps[excludeIP] = ipr
if _, ok := mapIps[excludeIP]; !ok {
ips := strings.Split(excludeIP, "..")
if len(ips) == 1 {
mapIps[excludeIP] = ipam.NewIPRange(ipam.NewIP(ips[0]), ipam.NewIP(ips[0]))
} else {
mapIps[excludeIP] = ipam.NewIPRange(ipam.NewIP(ips[0]), ipam.NewIP(ips[1]))
}
}
}
newMap := filterRepeatIPRange(mapIps)
for _, v := range newMap {
if v.Start == v.End {
excludeIps = append(excludeIps, string(v.Start))
if v.Start().Equal(v.End()) {
excludeIps = append(excludeIps, string(v.Start()))
} else {
excludeIps = append(excludeIps, string(v.Start)+".."+string(v.End))
excludeIps = append(excludeIps, v.Start().String()+".."+v.End().String())
}
}
sort.Strings(excludeIps)
klog.V(3).Infof("excludeips before format is %v, after format is %v", subnet.Spec.ExcludeIps, excludeIps)
if !reflect.DeepEqual(subnet.Spec.ExcludeIps, excludeIps) {
klog.V(3).Infof("excludeips before format is %v, after format is %v", subnet.Spec.ExcludeIps, excludeIps)
subnet.Spec.ExcludeIps = excludeIps
return true
}
return false
}

func filterRepeatIPRange(mapIps map[string]ipam.IPRange) map[string]ipam.IPRange {
func filterRepeatIPRange(mapIps map[string]*ipam.IPRange) map[string]*ipam.IPRange {
for ka, a := range mapIps {
for kb, b := range mapIps {
if ka == kb && a == b {
continue
}

if b.End.LessThan(a.Start) || b.Start.GreaterThan(a.End) {
if b.End().LessThan(a.Start()) || b.Start().GreaterThan(a.End()) {
continue
}

if (a.Start.Equal(b.Start) || a.Start.GreaterThan(b.Start)) &&
(a.End.Equal(b.End) || a.End.LessThan(b.End)) {
if (a.Start().Equal(b.Start()) || a.Start().GreaterThan(b.Start())) &&
(a.End().Equal(b.End()) || a.End().LessThan(b.End())) {
delete(mapIps, ka)
continue
}

if (a.Start.Equal(b.Start) || a.Start.GreaterThan(b.Start)) &&
a.End.GreaterThan(b.End) {
ipr := ipam.IPRange{Start: b.Start, End: a.End}
if (a.Start().Equal(b.Start()) || a.Start().GreaterThan(b.Start())) &&
a.End().GreaterThan(b.End()) {
delete(mapIps, ka)
mapIps[kb] = ipr
mapIps[kb] = ipam.NewIPRange(b.Start(), a.End())
continue
}

if (a.End.Equal(b.End) || a.End.LessThan(b.End)) &&
a.Start.LessThan(b.Start) {
ipr := ipam.IPRange{Start: a.Start, End: b.End}
if (a.End().Equal(b.End()) || a.End().LessThan(b.End())) &&
a.Start().LessThan(b.Start()) {
delete(mapIps, ka)
mapIps[kb] = ipr
mapIps[kb] = ipam.NewIPRange(a.Start(), b.End())
continue
}

Expand Down
191 changes: 13 additions & 178 deletions pkg/ipam/ip.go
Original file line number Diff line number Diff line change
@@ -1,201 +1,36 @@
package ipam

import (
"fmt"
"math/big"
"strings"

"github.com/kubeovn/kube-ovn/pkg/util"
"net"
)

type IP string
type IP net.IP

type IPRange struct {
Start IP
End IP
func NewIP(s string) IP {
return IP(net.ParseIP(s))
}

func (a IP) Equal(b IP) bool {
return a == b
return net.IP(a).Equal(net.IP(b))
}

func (a IP) LessThan(b IP) bool {
return util.Ip2BigInt(string(a)).Cmp(util.Ip2BigInt(string(b))) == -1
return big.NewInt(0).SetBytes([]byte(a)).Cmp(big.NewInt(0).SetBytes([]byte(b))) < 0
}

func (a IP) GreaterThan(b IP) bool {
return util.Ip2BigInt(string(a)).Cmp(util.Ip2BigInt(string(b))) == 1
}

func (a IP) Add(num int64) IP {
return IP(util.BigInt2Ip(big.NewInt(0).Add(util.Ip2BigInt(string(a)), big.NewInt(num))))
}

func (a IP) Sub(num int64) IP {
return IP(util.BigInt2Ip(big.NewInt(0).Sub(util.Ip2BigInt(string(a)), big.NewInt(num))))
}

func (ipr IPRange) IPExist(ip IP) bool {
return (ipr.Start.LessThan(ip) || ipr.Start.Equal(ip)) &&
(ipr.End.GreaterThan(ip) || ipr.End.Equal(ip))
}

type IPRangeList []*IPRange

func (iprl IPRangeList) Contains(ip IP) bool {
for _, ipr := range iprl {
if ipr.IPExist(ip) {
return true
}
}
return false
}

func (iprl IPRangeList) Equal(iprl2 IPRangeList) bool {
if len(iprl) != len(iprl2) {
return false
}

for i, range1 := range iprl {
range2 := iprl2[i]
if !range1.Start.Equal(range2.Start) || !range1.End.Equal(range2.End) {
return false
}
}

return true
}

func (iprl IPRangeList) IpRangetoString() string {
var ipRangeString []string
for _, ipr := range iprl {
if ipr.Start.Equal(ipr.End) {
ipRangeString = append(ipRangeString, string(ipr.Start))
} else {
ipRangeString = append(ipRangeString, fmt.Sprintf("%s-%s", ipr.Start, ipr.End))
}
}
return strings.Join(ipRangeString, ",")
return big.NewInt(0).SetBytes([]byte(a)).Cmp(big.NewInt(0).SetBytes([]byte(b))) > 0
}

func splitIPRangeList(iprl IPRangeList, ip IP) (bool, IPRangeList) {
newIPRangeList := []*IPRange{}
split := false
for _, ipr := range iprl {
if split {
newIPRangeList = append(newIPRangeList, ipr)
continue
}

if ipr.Start.Equal(ipr.End) && ipr.Start.Equal(ip) {
split = true
continue
}

if ipr.Start.Equal(ip) {
newIPRangeList = append(newIPRangeList, &IPRange{Start: ip.Add(1), End: ipr.End})
split = true
continue
}

if ipr.End.Equal(ip) {
newIPRangeList = append(newIPRangeList, &IPRange{Start: ipr.Start, End: ip.Add(-1)})
split = true
continue
}

if ipr.IPExist(ip) {
newIpr1 := IPRange{Start: ipr.Start, End: ip.Add(-1)}
newIpr2 := IPRange{Start: ip.Add(1), End: ipr.End}
newIPRangeList = append(newIPRangeList, &newIpr1, &newIpr2)
split = true
continue
}

newIPRangeList = append(newIPRangeList, ipr)
}
return split, newIPRangeList
}

func mergeIPRangeList(iprl IPRangeList, ip IP) (bool, IPRangeList) {
insertIPRangeList := []*IPRange{}
inserted := false
if iprl.Contains(ip) {
return false, nil
}

for _, ipr := range iprl {
if inserted || ipr.Start.LessThan(ip) {
insertIPRangeList = append(insertIPRangeList, ipr)
continue
}

if ipr.Start.GreaterThan(ip) {
insertIPRangeList = append(insertIPRangeList, &IPRange{Start: ip, End: ip}, ipr)
inserted = true
continue
}
}
if !inserted {
newIpr := IPRange{Start: ip, End: ip}
insertIPRangeList = append(insertIPRangeList, &newIpr)
}

mergedIPRangeList := []*IPRange{}
for _, ipr := range insertIPRangeList {
if len(mergedIPRangeList) == 0 {
mergedIPRangeList = append(mergedIPRangeList, ipr)
continue
}

if mergedIPRangeList[len(mergedIPRangeList)-1].End.Add(1).Equal(ipr.Start) {
mergedIPRangeList[len(mergedIPRangeList)-1].End = ipr.End
} else {
mergedIPRangeList = append(mergedIPRangeList, ipr)
}
}

return true, mergedIPRangeList
func (a IP) Add(n int64) IP {
return IP(big.NewInt(0).Add(big.NewInt(0).SetBytes([]byte(a)), big.NewInt(n)).Bytes())
}

func convertExcludeIps(excludeIps []string) IPRangeList {
newIPRangeList := make([]*IPRange, 0, len(excludeIps))
for _, ex := range excludeIps {
ips := strings.Split(ex, "..")
if len(ips) == 1 {
ipr := IPRange{Start: IP(ips[0]), End: IP(ips[0])}
newIPRangeList = append(newIPRangeList, &ipr)
} else {
ipr := IPRange{Start: IP(ips[0]), End: IP(ips[1])}
newIPRangeList = append(newIPRangeList, &ipr)
}
}
return newIPRangeList
func (a IP) Sub(n int64) IP {
return IP(big.NewInt(0).Sub(big.NewInt(0).SetBytes([]byte(a)), big.NewInt(n)).Bytes())
}

func splitRange(a, b *IPRange) IPRangeList {
if b.End.LessThan(a.Start) || b.Start.GreaterThan(a.End) {
return IPRangeList{a}
}

if (a.Start.Equal(b.Start) || a.Start.GreaterThan(b.Start)) &&
(a.End.Equal(b.End) || a.End.LessThan(b.End)) {
return nil
}

if (a.Start.Equal(b.Start) || a.Start.GreaterThan(b.Start)) &&
a.End.GreaterThan(b.End) {
ipr := IPRange{Start: b.End.Add(1), End: a.End}
return IPRangeList{&ipr}
}

if (a.End.Equal(b.End) || a.End.LessThan(b.End)) &&
a.Start.LessThan(b.Start) {
ipr := IPRange{Start: a.Start, End: b.Start.Add(-1)}
return IPRangeList{&ipr}
}

ipr1 := IPRange{Start: a.Start, End: b.Start.Add(-1)}
ipr2 := IPRange{Start: b.End.Add(1), End: a.End}
return IPRangeList{&ipr1, &ipr2}
func (a IP) String() string {
return net.IP(a).String()
}
76 changes: 76 additions & 0 deletions pkg/ipam/ip_range.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package ipam

import (
"fmt"
)

// IPRange represents an IP range of [start, end]
type IPRange struct {
start, end IP
}

func NewIPRange(start, end IP) *IPRange {
return &IPRange{start, end}
}

func (r *IPRange) Clone() *IPRange {
return NewIPRange(r.start, r.end)
}

func (r *IPRange) Start() IP {
return r.start
}

func (r *IPRange) End() IP {
return r.end
}

func (r *IPRange) SetStart(ip IP) {
r.start = ip
}

func (r *IPRange) SetEnd(ip IP) {
r.end = ip
}

func (r *IPRange) Contains(ip IP) bool {
return !r.start.GreaterThan(ip) && !r.end.LessThan(ip)
}

func (r *IPRange) Add(ip IP) bool {
if newStart := r.start.Sub(1); newStart.Equal(ip) {
r.start = newStart
return true
}
if newEnd := r.end.Add(1); newEnd.Equal(ip) {
r.end = newEnd
return true
}

return false
}

func (r *IPRange) Remove(ip IP) ([]*IPRange, bool) {
if !r.Contains(ip) {
return nil, false
}

ret := make([]*IPRange, 0, 2)
r1 := NewIPRange(r.start, ip.Sub(1))
r2 := NewIPRange(ip.Add(1), r.end)
if !r1.start.GreaterThan(r1.end) {
ret = append(ret, r1)
}
if !r2.start.GreaterThan(r2.end) {
ret = append(ret, r2)
}

return ret, true
}

func (r *IPRange) String() string {
if r.start.Equal(r.end) {
return string(r.start)
}
return fmt.Sprintf("%s..%s", r.start, r.end)
}

0 comments on commit 91f76ed

Please sign in to comment.