Skip to content

Commit

Permalink
gh-137 - Support for range based IPAM
Browse files Browse the repository at this point in the history
  • Loading branch information
TrekkieCoder committed Nov 23, 2024
1 parent 6774d45 commit 6d9852b
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 23 deletions.
52 changes: 44 additions & 8 deletions cmd/loxilb-agent/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,28 @@ func (o *Options) validate(args []string) error {
return fmt.Errorf("externalCIDR %s config is invalid", o.config.ExternalCIDRPoolDefs)
}
if _, _, err := net.ParseCIDR(poolStrSlice[1]); err != nil {
return fmt.Errorf("externalCIDR %s config is invalid", poolStrSlice[1])
}
if !lib.IsNetIPv4(poolStrSlice[1]) {
return fmt.Errorf("externalCIDR %s config is invalid", poolStrSlice[1])
if strings.Contains(poolStrSlice[1], "-") {
ipBlock := strings.Split(poolStrSlice[1], "-")
if len(ipBlock) != 2 {
return fmt.Errorf("invalid ip-range")
}

startIP := net.ParseIP(ipBlock[0])
lastIP := net.ParseIP(ipBlock[1])
if startIP == nil || lastIP == nil {
return fmt.Errorf("invalid ip-range ips")
}
if lib.IsNetIPv4(startIP.String()) && lib.IsNetIPv6(lastIP.String()) ||
lib.IsNetIPv6(startIP.String()) && lib.IsNetIPv4(lastIP.String()) {
return fmt.Errorf("invalid ip-types ips")
}
} else {
return fmt.Errorf("externalCIDR %s config is invalid", poolStrSlice[1])
}
} else {
if !lib.IsNetIPv4(poolStrSlice[1]) {
return fmt.Errorf("externalCIDR %s config is invalid", poolStrSlice[1])
}
}
}
}
Expand All @@ -131,10 +149,28 @@ func (o *Options) validate(args []string) error {
return fmt.Errorf("externalCIDR6 %s config is invalid", o.config.ExternalCIDR6PoolDefs)
}
if _, _, err := net.ParseCIDR(poolStrSlice[1]); err != nil {
return fmt.Errorf("externalCIDR6 %s config is invalid", poolStrSlice[1])
}
if !lib.IsNetIPv6(poolStrSlice[1]) {
return fmt.Errorf("externalCIDR6 %s config is invalid", poolStrSlice[1])
if strings.Contains(poolStrSlice[1], "-") {
ipBlock := strings.Split(poolStrSlice[1], "-")
if len(ipBlock) != 2 {
return fmt.Errorf("invalid ip-range")
}

startIP := net.ParseIP(ipBlock[0])
lastIP := net.ParseIP(ipBlock[1])
if startIP == nil || lastIP == nil {
return fmt.Errorf("invalid ip-range ips")
}
if lib.IsNetIPv4(startIP.String()) && lib.IsNetIPv6(lastIP.String()) ||
lib.IsNetIPv6(startIP.String()) && lib.IsNetIPv4(lastIP.String()) {
return fmt.Errorf("invalid ip-types ips")
}
} else {
return fmt.Errorf("externalCIDR6 %s config is invalid", poolStrSlice[1])
}
} else {
if !lib.IsNetIPv6(poolStrSlice[1]) {
return fmt.Errorf("externalCIDR6 %s config is invalid", poolStrSlice[1])
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/loxilb-io/kube-loxilb
go 1.23.0

require (
github.com/loxilb-io/loxilib v0.8.9-0.20240315085933-0925d8a579ed
github.com/loxilb-io/loxilib v0.8.9-0.20241122154322-9908d97c825d
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
gopkg.in/yaml.v2 v2.4.0
Expand Down Expand Up @@ -40,7 +40,7 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/loxilb-io/sctp v0.0.0-20230519081703-6d1baec82fd4 // indirect
github.com/loxilb-io/sctp v0.0.0-20240912025756-01894eac308b // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/loxilb-io/loxilib v0.8.9-0.20240315085933-0925d8a579ed h1:+JQ/l/sOI7KB9OxarKwRQxj5TjGgdia2UtQQRfvVa20=
github.com/loxilb-io/loxilib v0.8.9-0.20240315085933-0925d8a579ed/go.mod h1:LoQCxBz+N0fO9rGwRmPHrQPHol/jUf4MNpph63Cydkg=
github.com/loxilb-io/sctp v0.0.0-20230519081703-6d1baec82fd4 h1:oDc2lsbfuQEcVP3k+Pw4v6Xdm3t4M9vBc1Y9egszv6g=
github.com/loxilb-io/sctp v0.0.0-20230519081703-6d1baec82fd4/go.mod h1:1a6hv8ISVQhnW5IVpW9o+OL6BAFlWiVpC0O4d19g+wQ=
github.com/loxilb-io/loxilib v0.8.9-0.20241122154322-9908d97c825d h1:BE/A/Qq69ijTswOi8KJw+bI3E8ucVYHQO+a3wfwZ2js=
github.com/loxilb-io/loxilib v0.8.9-0.20241122154322-9908d97c825d/go.mod h1:72c3DmIKC53G5f4eNhTElemB08S64Xm/4QsDtwc66vw=
github.com/loxilb-io/sctp v0.0.0-20240912025756-01894eac308b h1:QZHlUZTWMpghNQW/OzdKFY2PhhPFMPAjsfRSLZkAONU=
github.com/loxilb-io/sctp v0.0.0-20240912025756-01894eac308b/go.mod h1:g3xKRvSWoeijv487mRGw3sLDacD9bC+wRQ4QebiafiQ=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
Expand Down
42 changes: 38 additions & 4 deletions pkg/agent/manager/loadbalancer/loadbalancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2422,8 +2422,25 @@ func (m *Manager) AddLoxiCIDRPool(poolName string, cidr string) error {

addr, _, err := net.ParseCIDR(cidr)
if err != nil {
klog.Errorf("failed to parse (CIDR: %s)", cidr)
return err
if strings.Contains(cidr, "-") {
ipBlock := strings.Split(cidr, "-")
if len(ipBlock) != 2 {
return fmt.Errorf("invalid ip-range")
}

startIP := net.ParseIP(ipBlock[0])
lastIP := net.ParseIP(ipBlock[1])
if startIP == nil || lastIP == nil {
return fmt.Errorf("invalid ip-range ips")
}
if tk.IsNetIPv4(startIP.String()) && tk.IsNetIPv6(lastIP.String()) ||
tk.IsNetIPv6(startIP.String()) && tk.IsNetIPv4(lastIP.String()) {
return fmt.Errorf("invalid ip-types ips")
}
} else {
klog.Errorf("failed to parse (CIDR: %s)", cidr)
return err
}
}

newIPPoolTbl := make(map[string]*ippool.IPPool)
Expand Down Expand Up @@ -2478,8 +2495,25 @@ func (m *Manager) DeleteLoxiCIDRPool(poolName string, cidr string) error {

addr, _, err := net.ParseCIDR(cidr)
if err != nil {
klog.Errorf("failed to parse (CIDR: %s)", cidr)
return err
if strings.Contains(cidr, "-") {
ipBlock := strings.Split(cidr, "-")
if len(ipBlock) != 2 {
return fmt.Errorf("invalid ip-range")
}

startIP := net.ParseIP(ipBlock[0])
lastIP := net.ParseIP(ipBlock[1])
if startIP == nil || lastIP == nil {
return fmt.Errorf("invalid ip-range ips")
}
if tk.IsNetIPv4(startIP.String()) && tk.IsNetIPv6(lastIP.String()) ||
tk.IsNetIPv6(startIP.String()) && tk.IsNetIPv4(lastIP.String()) {
return fmt.Errorf("invalid ip-types ips")
}
} else {
klog.Errorf("failed to parse (CIDR: %s)", cidr)
return err
}
}

newIPPoolTbl := make(map[string]*ippool.IPPool)
Expand Down
81 changes: 76 additions & 5 deletions pkg/ippool/ippool.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@ package ippool

import (
"errors"
"k8s.io/klog/v2"
"net"
"strings"
"sync"

"k8s.io/klog/v2"

tk "github.com/loxilb-io/loxilib"
)

type IPPool struct {
CIDR string
isRange bool
startIP net.IP
lastIP net.IP
NetCIDR *net.IPNet
IPAlloc *tk.IPAllocator
mutex sync.Mutex
Expand All @@ -35,16 +38,41 @@ type IPPool struct {

// Initailize IP Pool
func NewIPPool(ipa *tk.IPAllocator, CIDR string, Shared bool) (*IPPool, error) {
var startIP net.IP
var lastIP net.IP
isRange := false

ipa.AddIPRange(tk.IPClusterDefault, CIDR)

_, ipn, err := net.ParseCIDR(CIDR)
if err != nil {
return nil, errors.New("CIDR parse failed")
if strings.Contains(CIDR, "-") {
ipBlock := strings.Split(CIDR, "-")
if len(ipBlock) != 2 {
return nil, errors.New("invalid ip-range")
}

startIP = net.ParseIP(ipBlock[0])
lastIP = net.ParseIP(ipBlock[1])
if startIP == nil || lastIP == nil {
return nil, errors.New("invalid ip-range ips")
}
if tk.IsNetIPv4(startIP.String()) && tk.IsNetIPv6(lastIP.String()) ||
tk.IsNetIPv6(startIP.String()) && tk.IsNetIPv4(lastIP.String()) {
return nil, errors.New("invalid ip-types ips")
}
isRange = true
} else {
return nil, errors.New("CIDR parse failed")
}
}

return &IPPool{
CIDR: CIDR,
isRange: isRange,
NetCIDR: ipn,
startIP: startIP,
lastIP: lastIP,
IPAlloc: ipa,
mutex: sync.Mutex{},
Shared: Shared,
Expand Down Expand Up @@ -90,7 +118,7 @@ func (i *IPPool) ReturnIPAddr(ip string, identStr string) {
defer i.mutex.Unlock()

IP := net.ParseIP(ip)
if IP == nil || !i.NetCIDR.Contains(IP) {
if IP == nil || !i.Contains(IP) {
return
}

Expand Down Expand Up @@ -122,10 +150,53 @@ func (i *IPPool) ReserveIPAddr(ip string, name string, sIdent uint32, proto stri

}

func diffIPIndex(baseIP net.IP, IP net.IP) uint64 {
index := uint64(0)
iplen := 0
if tk.IsNetIPv4(baseIP.String()) {
iplen = 4
} else {
iplen = 16
}

arrIndex := len(baseIP) - iplen
arrIndex1 := len(IP) - iplen

for i := 0; i < 4 && arrIndex < len(baseIP) && arrIndex1 < len(IP); i++ {

basev := uint8(baseIP[arrIndex])
ipv := uint8(IP[arrIndex1])

if basev > ipv {
return ^uint64(0)
}

index = uint64(ipv - basev)
arrIndex++
arrIndex1++
index |= index << (8 * (iplen - i - 1))
}

return index
}

func (i *IPPool) Contains(IP net.IP) bool {
if i.isRange {
d1 := diffIPIndex(i.startIP, i.lastIP)
d2 := diffIPIndex(i.startIP, IP)
if d2 > d1 {
return false
}
return true
} else {
return i.NetCIDR.Contains(IP)
}
}

// CheckAndReserveIP check and reserve this IPaddress in IP Pool
func (i *IPPool) CheckAndReserveIP(ip string, name string, sIdent uint32, proto string) (bool, bool, string) {
IP := net.ParseIP(ip)
if IP != nil && i.NetCIDR.Contains(IP) {
if IP != nil && i.Contains(IP) {
err, idStr := i.ReserveIPAddr(ip, name, sIdent, proto)
if err != nil {
return true, false, idStr
Expand Down

0 comments on commit 6d9852b

Please sign in to comment.