plugins/ipam: round robin ip allocation for host-local ipam

This changes the ip allocation logic to round robin. Before this, host-local IPAM searched for available IPs from start of subnet. Hence it tends to allocate IPs that had been used recently. This is not ideal since it may cause collisions.
This commit is contained in:
Minhan Xia
2016-06-02 11:37:05 -07:00
committed by Stefan Junker
parent 5c3c171642
commit 2445a960a9
8 changed files with 296 additions and 4 deletions

View File

@ -16,6 +16,7 @@ package main
import (
"fmt"
"log"
"net"
"github.com/containernetworking/cni/pkg/ip"
@ -57,7 +58,6 @@ func NewIPAllocator(conf *IPAMConfig, store backend.Store) (*IPAllocator, error)
// RangeEnd is inclusive
end = ip.NextIP(conf.RangeEnd)
}
return &IPAllocator{start, end, conf, store}, nil
}
@ -112,7 +112,8 @@ func (a *IPAllocator) Get(id string) (*types.IPConfig, error) {
return nil, fmt.Errorf("requested IP address %q is not available in network: %s", requestedIP, a.conf.Name)
}
for cur := a.start; !cur.Equal(a.end); cur = ip.NextIP(cur) {
startIP, endIP := a.getSearchRange()
for cur := startIP; !cur.Equal(endIP); cur = a.nextIP(cur) {
// don't allocate gateway IP
if gw != nil && cur.Equal(gw) {
continue
@ -163,3 +164,39 @@ func networkRange(ipnet *net.IPNet) (net.IP, net.IP, error) {
}
return ipnet.IP, end, nil
}
// nextIP returns the next ip of curIP within ipallocator's subnet
func (a *IPAllocator) nextIP(curIP net.IP) net.IP {
if curIP.Equal(a.end) {
return a.start
}
return ip.NextIP(curIP)
}
// getSearchRange returns the start and end ip based on the last reserved ip
func (a *IPAllocator) getSearchRange() (net.IP, net.IP) {
var startIP net.IP
var endIP net.IP
startFromLastReservedIP := false
lastReservedIP, err := a.store.LastReservedIP()
if err != nil {
log.Printf("Error retriving last reserved ip: %v", err)
} else if lastReservedIP != nil {
subnet := net.IPNet{
IP: a.conf.Subnet.IP,
Mask: a.conf.Subnet.Mask,
}
err := validateRangeIP(lastReservedIP, &subnet)
if err == nil {
startFromLastReservedIP = true
}
}
if startFromLastReservedIP {
startIP = a.nextIP(lastReservedIP)
endIP = lastReservedIP
} else {
startIP = a.start
endIP = a.end
}
return startIP, endIP
}