diff --git a/ipalloc.go b/ipalloc.go index 22d9700..cf63d2c 100644 --- a/ipalloc.go +++ b/ipalloc.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "net" + "strconv" "strings" ) @@ -39,7 +40,7 @@ type IPRange struct { freeID *Counter fOK bool first uint64 - ident map[IdentKey]struct{} + ident map[IdentKey]int } // IPClusterPool - Holds IP ranges for a cluster @@ -138,8 +139,9 @@ func (ipa *IPAllocator) ReserveIP(cluster string, cidr string, idString string, } } + var retIndex uint64 if idString == "" || !ipr.fOK { - retIndex := diffIPIndex(ipr.ipNet.IP, IP) + retIndex = diffIPIndex(ipr.ipNet.IP, IP) if retIndex <= 0 { if retIndex != 0 || (retIndex == 0 && ipr.first != 0) { return errors.New("ip return index not found") @@ -155,8 +157,11 @@ func (ipa *IPAllocator) ReserveIP(cluster string, cidr string, idString string, } } - ipr.ident[key] = struct{}{} + if idString == "" { + key = getIdentKey(strconv.FormatInt(int64(retIndex), 10)) + } + ipr.ident[key]++ return nil } @@ -206,7 +211,11 @@ func (ipa *IPAllocator) AllocateNewIP(cluster string, cidr string, idString stri newIndex = ipr.first } - ipr.ident[key] = struct{}{} + if idString == "" { + key = getIdentKey(strconv.FormatInt(int64(newIndex), 10)) + } + + ipr.ident[key]++ retIP := addIPIndex(ipn.IP, uint64(newIndex)) @@ -235,9 +244,12 @@ func (ipa *IPAllocator) DeAllocateIP(cluster string, cidr string, idString, IPSt return errors.New("no such IP Range") } - key := getIdentKey(idString) + var key IdentKey + key = getIdentKey(idString) if _, ok := ipr.ident[key]; !ok { - return errors.New("ip Range - Ident not found") + if idString != "" { + return errors.New("ip Range - Ident not found") + } } retIndex := diffIPIndex(ipr.ipNet.IP, IP) @@ -247,9 +259,18 @@ func (ipa *IPAllocator) DeAllocateIP(cluster string, cidr string, idString, IPSt } } - delete(ipr.ident, key) + if idString == "" { + key = getIdentKey(strconv.FormatInt(int64(retIndex), 10)) + } + + if _, ok := ipr.ident[key]; !ok { + return errors.New("ip Range - key not found") + } + + ipr.ident[key]-- - if len(ipr.ident) == 0 { + if ipr.ident[key] <= 0 { + delete(ipr.ident, key) err = ipr.freeID.PutCounter(retIndex) if err != nil { return errors.New("ip Range counter failure") @@ -335,7 +356,7 @@ func (ipa *IPAllocator) AddIPRange(cluster string, cidr string) error { return errors.New("ip pool alloc failed") } - ipr.ident = make(map[IdentKey]struct{}) + ipr.ident = make(map[IdentKey]int) ipCPool.pool[cidr] = ipr return nil diff --git a/lib_test.go b/lib_test.go index 3ad532b..873e4b7 100644 --- a/lib_test.go +++ b/lib_test.go @@ -632,6 +632,135 @@ func TestIPAlloc(t *testing.T) { t.Fatalf("Failed IP Alloc for 192.168.10.252/24: %s:%s", ip.String(), "192.168.10.253") } + err = ipa.AddIPRange(IPClusterDefault, "192.168.82.210/29") + if err != nil { + t.Fatal("Failed to Add IP Range for 100.100.100.1/32") + } + + ipamIdent := MakeIPAMIdent("", 80, "tcp") + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + ipamIdent = IPAMNoIdent + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + t.Fatalf("IP Alloc failed for 192.168.82.210/29:%s", err) + } + } + + ipamIdent = MakeIPAMIdent("", 80, "tcp") + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + ipamIdent = IPAMNoIdent + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + t.Fatalf("IP Alloc failed for 192.168.82.210/29:%s", err) + } + } + + ipamIdent = MakeIPAMIdent("", 80, "tcp") + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + ipamIdent = IPAMNoIdent + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + t.Fatalf("IP Alloc failed for 192.168.82.210/29:%s", err) + } + } + + ipamIdent = MakeIPAMIdent("", 80, "tcp") + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + ipamIdent = IPAMNoIdent + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + t.Fatalf("IP Alloc failed for 192.168.82.210/29:%s", err) + } + } + + ipamIdent = MakeIPAMIdent("", 80, "tcp") + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + ipamIdent = IPAMNoIdent + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + t.Fatalf("IP Alloc failed for 192.168.82.210/29%s", err) + } + } + + ipamIdent = MakeIPAMIdent("", 80, "tcp") + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + ipamIdent = IPAMNoIdent + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err == nil { + t.Fatalf("IP unexpectedly alloced for 192.168.82.210/29:%s", err) + } + } + + err = ipa.DeAllocateIP(IPClusterDefault, "192.168.82.210/29", IPAMNoIdent, "192.168.82.211") + if err != nil { + t.Fatalf("IP DeAlloc failed for %s:%s", "192.168.82.211", err) + } + + ipamIdent = MakeIPAMIdent("", 80, "tcp") + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + ipamIdent = IPAMNoIdent + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + t.Fatalf("IP Alloc failed for 192.168.82.210/29:%s", err) + } + } + + if ip1.String() != "192.168.82.211" { + t.Fatalf("IP alloced is not 192.168.82.211 for 192.168.82.210/29:%s", err) + } + + ipamIdent = MakeIPAMIdent("", 80, "tcp") + err = ipa.DeAllocateIP(IPClusterDefault, "192.168.82.210/29", ipamIdent, "192.168.82.210") + if err != nil { + t.Fatalf("IP DeAlloc failed for %s:%s", "192.168.82.210", err) + } + + err = ipa.DeAllocateIP(IPClusterDefault, "192.168.82.210/29", IPAMNoIdent, "192.168.82.212") + if err != nil { + t.Fatalf("IP DeAlloc failed for %s:%s", "192.168.82.212", err) + } + + err = ipa.DeAllocateIP(IPClusterDefault, "192.168.82.210/29", IPAMNoIdent, "192.168.82.213") + if err != nil { + t.Fatalf("IP DeAlloc failed for %s:%s", "192.168.82.213", err) + } + + err = ipa.DeAllocateIP(IPClusterDefault, "192.168.82.210/29", IPAMNoIdent, "192.168.82.214") + if err != nil { + t.Fatalf("IP DeAlloc failed for %s:%s", "192.168.82.214", err) + } + + err = ipa.DeAllocateIP(IPClusterDefault, "192.168.82.210/29", IPAMNoIdent, "192.168.82.214") + if err == nil { + t.Fatalf("IP DeAlloc success unexpected for %s:%s", "192.168.82.214", err) + } + + err = ipa.DeAllocateIP(IPClusterDefault, "192.168.82.210/29", IPAMNoIdent, "192.168.82.211") + if err != nil { + t.Fatalf("IP DeAlloc failed for %s:%s", "192.168.82.211", err) + } + + ipamIdent = MakeIPAMIdent("", 80, "tcp") + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + ipamIdent = IPAMNoIdent + ip1, err = ipa.AllocateNewIP(IPClusterDefault, "192.168.82.210/29", ipamIdent) + if err != nil { + t.Fatalf("IP Alloc failed for 192.168.82.210/29:%s", err) + } + } + + if ip1.String() != "192.168.82.210" { + t.Fatalf("IP alloced is not 192.168.82.210 for 192.168.82.210/29:%s", err) + } + } func TestProber(t *testing.T) {