/
ipam.go
90 lines (80 loc) · 2.2 KB
/
ipam.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright 2019 Nordix foundation
// Package ipam is a very simple IPAM it administers a single CIDR range, e.g "1000::/124".
//
// The functions are NOT thread safe.
package ipam
import (
"fmt"
"math"
"net"
"github.com/Nordix/simple-ipam/pkg/ipaddr"
)
// IPAM holds the ipam state
type IPAM struct {
// The original CIDR range
CIDR net.IPNet
cidr *ipaddr.Cidr
allocated map[ipaddr.IPv6Int]bool
}
// New creates a new IPAM for the passed CIDR.
// Error if the passed CIDR is invalid.
func New(cidr string) (*IPAM, error) {
c, err := ipaddr.NewCidr(cidr)
if err != nil {
return nil, err
}
_, net, _ := net.ParseCIDR(cidr)
return &IPAM{
CIDR: *net,
cidr: c,
allocated: make(map[ipaddr.IPv6Int]bool),
}, nil
}
// Allocate allocates a new address.
// An error is returned if there is no addresses left.
func (i *IPAM) Allocate() (net.IP, error) {
if i.Unallocated() < 1 {
return nil, fmt.Errorf("No addresses left")
}
for {
p := i.cidr.Current
i.cidr.Step()
if _, ok := i.allocated[p]; !ok {
i.allocated[p] = true
return ipaddr.IP(p), nil
}
}
}
// Free frees an allocated address.
// To free a non-allocated address is a no-op.
func (i *IPAM) Free(a net.IP) {
delete(i.allocated, ipaddr.IPToIPv6Int(a))
}
// Unallocated returns the number of unallocated addresses.
// If the CIDR host-bits are >=64 math.MaxUint64 is always returned.
func (i *IPAM) Unallocated() uint64 {
if i.cidr.Size == math.MaxUint64 {
return math.MaxUint64
}
return i.cidr.Size - uint64(len(i.allocated))
}
// Reserve reserves an address.
// Error if the address is outside the CIDR or if the address is allocated already.
func (i *IPAM) Reserve(a net.IP) error {
if !i.CIDR.Contains(a) {
return fmt.Errorf("Address outside the cidr")
}
ip := ipaddr.IPToIPv6Int(a)
if _, ok := i.allocated[ip]; ok {
return fmt.Errorf("Address already allocated")
}
i.allocated[ip] = true
return nil
}
// ReserveFirstAndLast reserves the first and last address.
// These are valid addresses but some programs may refuse to use them.
// Note that the number of Unallocated addresses may become zero.
func (i *IPAM) ReserveFirstAndLast() {
i.allocated[i.cidr.First] = true
i.allocated[i.cidr.Last] = true
}