Skip to content

Commit

Permalink
Merge pull request #69 from wusendong/feat/descending_order
Browse files Browse the repository at this point in the history
Support descending search order
  • Loading branch information
thebsdbox authored Dec 2, 2023
2 parents 5078dda + 255e0fb commit e11cc57
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 33 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The `kube-vip-cloud-provider` will only implement the `loadBalancer` functionali
- Setting of static addresses through `--load-balancer-ip=x.x.x.x` or through annotations `kube-vip.io/loadbalancerIPs: x.x.x.x`
- Setting the special IP `0.0.0.0` for DHCP workflow.
- Support single stack IPv6 or IPv4
- Support ascending and descending search order by setting search-order=desc

## Installing the `kube-vip-cloud-provider`

Expand Down Expand Up @@ -66,12 +67,24 @@ data:
kubectl create configmap --namespace kube-system kubevip --from-literal cidr-global=192.168.0.220/29
```

## Create an IP pool using a CIDR and descending search order

```
kubectl create configmap --namespace kube-system kubevip --from-literal cidr-global=192.168.0.220/29 --from-literal search-order=desc
```

## Create an IP range

```
kubectl create configmap --namespace kube-system kubevip --from-literal range-global=192.168.0.200-192.168.0.202
```

## Create an IP range and descending search order

```
kubectl create configmap --namespace kube-system kubevip --from-literal range-global=192.168.0.200-192.168.0.202 --from-literal search-order=desc
```

## Multiple pools or ranges

We can apply multiple pools or ranges by seperating them with commas.. i.e. `192.168.0.200/30,192.168.0.200/29` or `2001::12/127,2001::10/127` or `192.168.0.10-192.168.0.11,192.168.0.10-192.168.0.13` or `2001::10-2001::14,2001::20-2001::24`
Expand Down
19 changes: 18 additions & 1 deletion pkg/ipam/addressbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,24 @@ func buildHostsFromCidr(cidr string) (*netipx.IPSet, error) {
if err != nil {
return nil, err
}
builder.AddPrefix(prefix)
if prefix.IsSingleIP() {
builder.Add(prefix.Addr())
continue
}
if !prefix.Addr().Is4() {
builder.AddPrefix(prefix)
continue
}

if r := netipx.RangeOfPrefix(prefix); r.IsValid() {
if prefix.Bits() == 31 {
// rfc3021 Using 31-Bit Prefixes on IPv4 Point-to-Point Links
builder.AddRange(netipx.IPRangeFrom(r.From(), r.To()))
continue
}
// For 192.168.0.200/23, 192.168.0.206 is the BroadcastIP, and 192.168.0.201 is the NetworkID
builder.AddRange(netipx.IPRangeFrom(r.From().Next(), r.To().Prev()))
}
}
return builder.IPSet()
}
Expand Down
51 changes: 32 additions & 19 deletions pkg/ipam/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type ipManager struct {
}

// FindAvailableHostFromRange - will look through the cidr and the address Manager and find a free address (if possible)
func FindAvailableHostFromRange(namespace, ipRange string, inUseIPSet *netipx.IPSet) (string, error) {
func FindAvailableHostFromRange(namespace, ipRange string, inUseIPSet *netipx.IPSet, descOrder bool) (string, error) {

// Look through namespaces and update one if it exists
for x := range Manager {
Expand All @@ -44,8 +44,7 @@ func FindAvailableHostFromRange(namespace, ipRange string, inUseIPSet *netipx.IP
Manager[x].ipRange = ipRange
}

// TODO - currently we search (incrementally) through the list of hosts
addr, err := FindFreeAddress(Manager[x].poolIPSet, inUseIPSet)
addr, err := FindFreeAddress(Manager[x].poolIPSet, inUseIPSet, descOrder)
if err != nil {
return "", fmt.Errorf("no addresses available in [%s] range [%s]", namespace, ipRange)
}
Expand All @@ -66,16 +65,15 @@ func FindAvailableHostFromRange(namespace, ipRange string, inUseIPSet *netipx.IP

Manager = append(Manager, newManager)

// TODO - currently we search (incrementally) through the list of hosts
addr, err := FindFreeAddress(poolIPSet, inUseIPSet)
addr, err := FindFreeAddress(poolIPSet, inUseIPSet, descOrder)
if err != nil {
return "", fmt.Errorf("no addresses available in [%s] range [%s]", namespace, ipRange)
}
return addr.String(), nil
}

// FindAvailableHostFromCidr - will look through the cidr and the address Manager and find a free address (if possible)
func FindAvailableHostFromCidr(namespace, cidr string, inUseIPSet *netipx.IPSet) (string, error) {
func FindAvailableHostFromCidr(namespace, cidr string, inUseIPSet *netipx.IPSet, descOrder bool) (string, error) {

// Look through namespaces and update one if it exists
for x := range Manager {
Expand All @@ -91,8 +89,7 @@ func FindAvailableHostFromCidr(namespace, cidr string, inUseIPSet *netipx.IPSet)
Manager[x].cidr = cidr

}
// TODO - currently we search (incrementally) through the list of hosts
addr, err := FindFreeAddress(Manager[x].poolIPSet, inUseIPSet)
addr, err := FindFreeAddress(Manager[x].poolIPSet, inUseIPSet, descOrder)
if err != nil {
return "", fmt.Errorf("no addresses available in [%s] cidr [%s]", namespace, cidr)
}
Expand All @@ -112,8 +109,7 @@ func FindAvailableHostFromCidr(namespace, cidr string, inUseIPSet *netipx.IPSet)
}
Manager = append(Manager, newManager)

// TODO - currently we search (incrementally) through the list of hosts
addr, err := FindFreeAddress(poolIPSet, inUseIPSet)
addr, err := FindFreeAddress(poolIPSet, inUseIPSet, descOrder)
if err != nil {
return "", fmt.Errorf("no addresses available in [%s] cidr [%s]", namespace, cidr)
}
Expand Down Expand Up @@ -144,17 +140,34 @@ func FindAvailableHostFromCidr(namespace, cidr string, inUseIPSet *netipx.IPSet)

// FindFreeAddress returns the next free IP Address in a range based on a set of existing addresses.
// It will skip assumed gateway ip or broadcast ip for IPv4 address
func FindFreeAddress(poolIPSet *netipx.IPSet, inUseIPSet *netipx.IPSet) (netip.Addr, error) {
for _, iprange := range poolIPSet.Ranges() {
ip := iprange.From()
for {
if !inUseIPSet.Contains(ip) && (!ip.Is4() || !isNetworkIDOrBroadcastIP(ip.As4())) {
return ip, nil
func FindFreeAddress(poolIPSet *netipx.IPSet, inUseIPSet *netipx.IPSet, descOrder bool) (netip.Addr, error) {
if descOrder {
ipranges := poolIPSet.Ranges()
for i := len(ipranges) - 1; i >= 0; i-- {
iprange := ipranges[i]
ip := iprange.To()
for {
if !inUseIPSet.Contains(ip) && (!ip.Is4() || !isNetworkIDOrBroadcastIP(ip.As4())) {
return ip, nil
}
if ip == iprange.From() {
break
}
ip = ip.Prev()
}
if ip == iprange.To() {
break
}
} else {
for _, iprange := range poolIPSet.Ranges() {
ip := iprange.From()
for {
if !inUseIPSet.Contains(ip) && (!ip.Is4() || !isNetworkIDOrBroadcastIP(ip.As4())) {
return ip, nil
}
if ip == iprange.To() {
break
}
ip = ip.Next()
}
ip = ip.Next()
}
}
return netip.Addr{}, errors.New("no address available")
Expand Down
Loading

0 comments on commit e11cc57

Please sign in to comment.