1515package allocator
1616
1717import (
18- "encoding/base64"
1918 "fmt"
2019 "log"
2120 "net"
2221 "os"
22+ "strconv"
2323
2424 "github.com/containernetworking/cni/pkg/types/current"
2525 "github.com/containernetworking/plugins/pkg/ip"
2626 "github.com/containernetworking/plugins/plugins/ipam/host-local/backend"
2727)
2828
2929type IPAllocator struct {
30- netName string
31- ipRange Range
32- store backend.Store
33- rangeID string // Used for tracking last reserved ip
30+ rangeset * RangeSet
31+ store backend.Store
32+ rangeID string // Used for tracking last reserved ip
3433}
3534
36- type RangeIter struct {
37- low net.IP
38- high net.IP
39- cur net.IP
40- start net.IP
41- }
42-
43- func NewIPAllocator (netName string , r Range , store backend.Store ) * IPAllocator {
44- // The range name (last allocated ip suffix) is just the base64
45- // encoding of the bytes of the first IP
46- rangeID := base64 .URLEncoding .EncodeToString (r .RangeStart )
47-
35+ func NewIPAllocator (s * RangeSet , store backend.Store , id int ) * IPAllocator {
4836 return & IPAllocator {
49- netName : netName ,
50- ipRange : r ,
51- store : store ,
52- rangeID : rangeID ,
37+ rangeset : s ,
38+ store : store ,
39+ rangeID : strconv .Itoa (id ),
5340 }
5441}
5542
@@ -58,67 +45,66 @@ func (a *IPAllocator) Get(id string, requestedIP net.IP) (*current.IPConfig, err
5845 a .store .Lock ()
5946 defer a .store .Unlock ()
6047
61- gw := a .ipRange .Gateway
62-
63- var reservedIP net.IP
48+ var reservedIP * net.IPNet
49+ var gw net.IP
6450
6551 if requestedIP != nil {
66- if gw != nil && gw . Equal ( requestedIP ) {
67- return nil , fmt . Errorf ( "requested IP must differ from gateway IP" )
52+ if err := canonicalizeIP ( & requestedIP ); err != nil {
53+ return nil , err
6854 }
6955
70- if err := a .ipRange .IPInRange (requestedIP ); err != nil {
56+ r , err := a .rangeset .RangeFor (requestedIP )
57+ if err != nil {
7158 return nil , err
7259 }
7360
61+ if requestedIP .Equal (r .Gateway ) {
62+ return nil , fmt .Errorf ("requested ip %s is subnet's gateway" , requestedIP .String ())
63+ }
64+
7465 reserved , err := a .store .Reserve (id , requestedIP , a .rangeID )
7566 if err != nil {
7667 return nil , err
7768 }
7869 if ! reserved {
79- return nil , fmt .Errorf ("requested IP address %q is not available in network: %s %s" , requestedIP , a .netName , ( * net . IPNet )( & a . ipRange . Subnet ) .String ())
70+ return nil , fmt .Errorf ("requested IP address %s is not available in range set %s" , requestedIP , a .rangeset .String ())
8071 }
81- reservedIP = requestedIP
72+ reservedIP = & net.IPNet {IP : requestedIP , Mask : r .Subnet .Mask }
73+ gw = r .Gateway
8274
8375 } else {
8476 iter , err := a .GetIter ()
8577 if err != nil {
8678 return nil , err
8779 }
8880 for {
89- cur : = iter .Next ()
90- if cur == nil {
81+ reservedIP , gw = iter .Next ()
82+ if reservedIP == nil {
9183 break
9284 }
9385
94- // don't allocate gateway IP
95- if gw != nil && cur .Equal (gw ) {
96- continue
97- }
98-
99- reserved , err := a .store .Reserve (id , cur , a .rangeID )
86+ reserved , err := a .store .Reserve (id , reservedIP .IP , a .rangeID )
10087 if err != nil {
10188 return nil , err
10289 }
10390
10491 if reserved {
105- reservedIP = cur
10692 break
10793 }
10894 }
10995 }
11096
11197 if reservedIP == nil {
112- return nil , fmt .Errorf ("no IP addresses available in network : %s %s " , a .netName , ( * net . IPNet )( & a . ipRange . Subnet ) .String ())
98+ return nil , fmt .Errorf ("no IP addresses available in range set : %s" , a .rangeset .String ())
11399 }
114100 version := "4"
115- if reservedIP .To4 () == nil {
101+ if reservedIP .IP . To4 () == nil {
116102 version = "6"
117103 }
118104
119105 return & current.IPConfig {
120106 Version : version ,
121- Address : net. IPNet { IP : reservedIP , Mask : a . ipRange . Subnet . Mask } ,
107+ Address : * reservedIP ,
122108 Gateway : gw ,
123109 }, nil
124110}
@@ -131,15 +117,28 @@ func (a *IPAllocator) Release(id string) error {
131117 return a .store .ReleaseByID (id )
132118}
133119
120+ type RangeIter struct {
121+ rangeset * RangeSet
122+
123+ // The current range id
124+ rangeIdx int
125+
126+ // Our current position
127+ cur net.IP
128+
129+ // The IP and range index where we started iterating; if we hit this again, we're done.
130+ startIP net.IP
131+ startRange int
132+ }
133+
134134// GetIter encapsulates the strategy for this allocator.
135- // We use a round-robin strategy, attempting to evenly use the whole subnet .
135+ // We use a round-robin strategy, attempting to evenly use the whole set .
136136// More specifically, a crash-looping container will not see the same IP until
137137// the entire range has been run through.
138138// We may wish to consider avoiding recently-released IPs in the future.
139139func (a * IPAllocator ) GetIter () (* RangeIter , error ) {
140- i := RangeIter {
141- low : a .ipRange .RangeStart ,
142- high : a .ipRange .RangeEnd ,
140+ iter := RangeIter {
141+ rangeset : a .rangeset ,
143142 }
144143
145144 // Round-robin by trying to allocate from the last reserved IP + 1
@@ -151,39 +150,68 @@ func (a *IPAllocator) GetIter() (*RangeIter, error) {
151150 if err != nil && ! os .IsNotExist (err ) {
152151 log .Printf ("Error retrieving last reserved ip: %v" , err )
153152 } else if lastReservedIP != nil {
154- startFromLastReservedIP = a .ipRange . IPInRange (lastReservedIP ) == nil
153+ startFromLastReservedIP = a .rangeset . Contains (lastReservedIP )
155154 }
156155
156+ // Find the range in the set with this IP
157157 if startFromLastReservedIP {
158- if i .high .Equal (lastReservedIP ) {
159- i .start = i .low
160- } else {
161- i .start = ip .NextIP (lastReservedIP )
158+ for i , r := range * a .rangeset {
159+ if r .Contains (lastReservedIP ) {
160+ iter .rangeIdx = i
161+ iter .startRange = i
162+
163+ // We advance the cursor on every Next(), so the first call
164+ // to next() will return lastReservedIP + 1
165+ iter .cur = lastReservedIP
166+ break
167+ }
162168 }
163169 } else {
164- i .start = a .ipRange .RangeStart
170+ iter .rangeIdx = 0
171+ iter .startRange = 0
172+ iter .startIP = (* a .rangeset )[0 ].RangeStart
165173 }
166- return & i , nil
174+ return & iter , nil
167175}
168176
169- // Next returns the next IP in the iterator, or nil if end is reached
170- func (i * RangeIter ) Next () net.IP {
171- // If we're at the beginning, time to start
177+ // Next returns the next IP, its mask, and its gateway. Returns nil
178+ // if the iterator has been exhausted
179+ func (i * RangeIter ) Next () (* net.IPNet , net.IP ) {
180+ r := (* i .rangeset )[i .rangeIdx ]
181+
182+ // If this is the first time iterating and we're not starting in the middle
183+ // of the range, then start at rangeStart, which is inclusive
172184 if i .cur == nil {
173- i .cur = i .start
174- return i .cur
185+ i .cur = r .RangeStart
186+ i .startIP = i .cur
187+ if i .cur .Equal (r .Gateway ) {
188+ return i .Next ()
189+ }
190+ return & net.IPNet {IP : i .cur , Mask : r .Subnet .Mask }, r .Gateway
175191 }
176- // we returned .high last time, since we're inclusive
177- if i .cur .Equal (i .high ) {
178- i .cur = i .low
192+
193+ // If we've reached the end of this range, we need to advance the range
194+ // RangeEnd is inclusive as well
195+ if i .cur .Equal (r .RangeEnd ) {
196+ i .rangeIdx += 1
197+ i .rangeIdx %= len (* i .rangeset )
198+ r = (* i .rangeset )[i .rangeIdx ]
199+
200+ i .cur = r .RangeStart
179201 } else {
180202 i .cur = ip .NextIP (i .cur )
181203 }
182204
183- // If we've looped back to where we started, exit
184- if i .cur .Equal (i .start ) {
185- return nil
205+ if i .startIP == nil {
206+ i .startIP = i .cur
207+ } else if i .rangeIdx == i .startRange && i .cur .Equal (i .startIP ) {
208+ // IF we've looped back to where we started, give up
209+ return nil , nil
210+ }
211+
212+ if i .cur .Equal (r .Gateway ) {
213+ return i .Next ()
186214 }
187215
188- return i .cur
216+ return & net. IPNet { IP : i .cur , Mask : r . Subnet . Mask }, r . Gateway
189217}
0 commit comments