Skip to content

Commit

Permalink
Merge pull request #208 from loxilb-io/gh-137
Browse files Browse the repository at this point in the history
gh-137 Support for ip-ranges  in IPAM in addition to cidr
  • Loading branch information
UltraInstinct14 authored Nov 23, 2024
2 parents 6774d45 + 25c1223 commit 987368f
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 24 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ The arguments have the following meaning :
| Name | Description |
| ----------- | ----------- |
| loxiURL | API server address of loxilb. This is the docker IP address loxilb docker of Step 1. If unspecified, kube-loxilb assumes loxilb is running in-cluster mode and autoconfigures this. |
| cidrPools | CIDR or IPAddress range to allocate addresses from. By default address allocated are shared for different services(shared Mode). Multiple pools can be defined and any of them can be selected during service creation using "loxilb.io/poolSelect" annotation. |
| cidrPools | CIDR or IPAddress range to allocate addresses from. By default address allocated are shared for different services(shared Mode). Multiple pools can be defined and any of them can be selected during service creation using "loxilb.io/poolSelect" annotation. cidrPools can be specified as ip-cidr e.g 123.123.123.0/23 or as ip-ranges e.g 123.123.123.1-123.123.123.3 |
| cidr6Pools | Ipv6 CIDR or IPAddress range to allocate addresses from. By default address allocated are shared for different services(shared Mode). Multiple pools can be defined and any of them can be selected during service creation using "loxilb.io/poolSelect" annotation. |
| monitor | Enable liveness probe for the LB end-points (default : unset) |
| setBGP | Use specified BGP AS-ID to advertise this service. If not specified BGP will be disabled. Please check [here](https://github.com/loxilb-io/loxilbdocs/blob/main/docs/integrate_bgp_eng.md) how it works. |
Expand Down
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 987368f

Please sign in to comment.