root / lib / network.py @ 84ad6b78
History | View | Annotate | Download (7.3 kB)
1 | 1de1cf25 | Apollon Oikonomopoulos | #
|
---|---|---|---|
2 | 1de1cf25 | Apollon Oikonomopoulos | #
|
3 | 1de1cf25 | Apollon Oikonomopoulos | |
4 | 861a92b4 | Dimitris Aragiorgis | # Copyright (C) 2011, 2012 Google Inc.
|
5 | 1de1cf25 | Apollon Oikonomopoulos | #
|
6 | 1de1cf25 | Apollon Oikonomopoulos | # This program is free software; you can redistribute it and/or modify
|
7 | 1de1cf25 | Apollon Oikonomopoulos | # it under the terms of the GNU General Public License as published by
|
8 | 1de1cf25 | Apollon Oikonomopoulos | # the Free Software Foundation; either version 2 of the License, or
|
9 | 1de1cf25 | Apollon Oikonomopoulos | # (at your option) any later version.
|
10 | 1de1cf25 | Apollon Oikonomopoulos | #
|
11 | 1de1cf25 | Apollon Oikonomopoulos | # This program is distributed in the hope that it will be useful, but
|
12 | 1de1cf25 | Apollon Oikonomopoulos | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 1de1cf25 | Apollon Oikonomopoulos | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | 1de1cf25 | Apollon Oikonomopoulos | # General Public License for more details.
|
15 | 1de1cf25 | Apollon Oikonomopoulos | #
|
16 | 1de1cf25 | Apollon Oikonomopoulos | # You should have received a copy of the GNU General Public License
|
17 | 1de1cf25 | Apollon Oikonomopoulos | # along with this program; if not, write to the Free Software
|
18 | 1de1cf25 | Apollon Oikonomopoulos | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | 1de1cf25 | Apollon Oikonomopoulos | # 02110-1301, USA.
|
20 | 1de1cf25 | Apollon Oikonomopoulos | |
21 | 1de1cf25 | Apollon Oikonomopoulos | |
22 | 5b34cc22 | Michael Hanselmann | """IP address pool management functions.
|
23 | 1de1cf25 | Apollon Oikonomopoulos |
|
24 | 1de1cf25 | Apollon Oikonomopoulos | """
|
25 | 1de1cf25 | Apollon Oikonomopoulos | |
26 | 1de1cf25 | Apollon Oikonomopoulos | import ipaddr |
27 | 1de1cf25 | Apollon Oikonomopoulos | |
28 | 1de1cf25 | Apollon Oikonomopoulos | from bitarray import bitarray |
29 | 1de1cf25 | Apollon Oikonomopoulos | |
30 | 1de1cf25 | Apollon Oikonomopoulos | from ganeti import errors |
31 | 1de1cf25 | Apollon Oikonomopoulos | |
32 | 06c056d3 | Helga Velroyen | |
33 | 06c056d3 | Helga Velroyen | def _ComputeIpv4NumHosts(network_size): |
34 | 06c056d3 | Helga Velroyen | """Derives the number of hosts in an IPv4 network from the size.
|
35 | 06c056d3 | Helga Velroyen |
|
36 | 06c056d3 | Helga Velroyen | """
|
37 | 06c056d3 | Helga Velroyen | return 2 ** (32 - network_size) |
38 | 06c056d3 | Helga Velroyen | |
39 | 06c056d3 | Helga Velroyen | |
40 | 59baad7a | Helga Velroyen | IPV4_NETWORK_MIN_SIZE = 30
|
41 | 06c056d3 | Helga Velroyen | # FIXME: This limit is for performance reasons. Remove when refactoring
|
42 | 06c056d3 | Helga Velroyen | # for performance tuning was successful.
|
43 | 06c056d3 | Helga Velroyen | IPV4_NETWORK_MAX_SIZE = 16
|
44 | 06c056d3 | Helga Velroyen | IPV4_NETWORK_MIN_NUM_HOSTS = _ComputeIpv4NumHosts(IPV4_NETWORK_MIN_SIZE) |
45 | 06c056d3 | Helga Velroyen | IPV4_NETWORK_MAX_NUM_HOSTS = _ComputeIpv4NumHosts(IPV4_NETWORK_MAX_SIZE) |
46 | 59baad7a | Helga Velroyen | |
47 | 3c286190 | Dimitris Aragiorgis | |
48 | 1de1cf25 | Apollon Oikonomopoulos | class AddressPool(object): |
49 | 5b34cc22 | Michael Hanselmann | """Address pool class, wrapping an C{objects.Network} object.
|
50 | 1de1cf25 | Apollon Oikonomopoulos |
|
51 | 1de1cf25 | Apollon Oikonomopoulos | This class provides methods to manipulate address pools, backed by
|
52 | 1de1cf25 | Apollon Oikonomopoulos | L{objects.Network} objects.
|
53 | 1de1cf25 | Apollon Oikonomopoulos |
|
54 | 1de1cf25 | Apollon Oikonomopoulos | """
|
55 | 5b34cc22 | Michael Hanselmann | FREE = bitarray("0")
|
56 | 5b34cc22 | Michael Hanselmann | RESERVED = bitarray("1")
|
57 | 861a92b4 | Dimitris Aragiorgis | |
58 | 1de1cf25 | Apollon Oikonomopoulos | def __init__(self, network): |
59 | 5b34cc22 | Michael Hanselmann | """Initialize a new IPv4 address pool from an L{objects.Network} object.
|
60 | 1de1cf25 | Apollon Oikonomopoulos |
|
61 | 1de1cf25 | Apollon Oikonomopoulos | @type network: L{objects.Network}
|
62 | 1de1cf25 | Apollon Oikonomopoulos | @param network: the network object from which the pool will be generated
|
63 | 1de1cf25 | Apollon Oikonomopoulos |
|
64 | 1de1cf25 | Apollon Oikonomopoulos | """
|
65 | 1de1cf25 | Apollon Oikonomopoulos | self.network = None |
66 | 1de1cf25 | Apollon Oikonomopoulos | self.gateway = None |
67 | 1de1cf25 | Apollon Oikonomopoulos | self.network6 = None |
68 | 1de1cf25 | Apollon Oikonomopoulos | self.gateway6 = None |
69 | 1de1cf25 | Apollon Oikonomopoulos | |
70 | 1de1cf25 | Apollon Oikonomopoulos | self.net = network
|
71 | 1de1cf25 | Apollon Oikonomopoulos | |
72 | 1de1cf25 | Apollon Oikonomopoulos | self.network = ipaddr.IPNetwork(self.net.network) |
73 | 06c056d3 | Helga Velroyen | if self.network.numhosts > IPV4_NETWORK_MAX_NUM_HOSTS: |
74 | 06c056d3 | Helga Velroyen | raise errors.AddressPoolError("A big network with %s host(s) is currently" |
75 | 06c056d3 | Helga Velroyen | " not supported. please specify at most a"
|
76 | 06c056d3 | Helga Velroyen | " /%s network" %
|
77 | 06c056d3 | Helga Velroyen | (str(self.network.numhosts), |
78 | 06c056d3 | Helga Velroyen | IPV4_NETWORK_MAX_SIZE)) |
79 | 06c056d3 | Helga Velroyen | |
80 | 59baad7a | Helga Velroyen | if self.network.numhosts < IPV4_NETWORK_MIN_NUM_HOSTS: |
81 | 59baad7a | Helga Velroyen | raise errors.AddressPoolError("A network with only %s host(s) is too" |
82 | 59baad7a | Helga Velroyen | " small, please specify at least a /%s"
|
83 | 59baad7a | Helga Velroyen | " network" %
|
84 | 59baad7a | Helga Velroyen | (str(self.network.numhosts), |
85 | 59baad7a | Helga Velroyen | IPV4_NETWORK_MIN_SIZE)) |
86 | 1de1cf25 | Apollon Oikonomopoulos | if self.net.gateway: |
87 | 1de1cf25 | Apollon Oikonomopoulos | self.gateway = ipaddr.IPAddress(self.net.gateway) |
88 | 1de1cf25 | Apollon Oikonomopoulos | |
89 | 1de1cf25 | Apollon Oikonomopoulos | if self.net.network6: |
90 | 1de1cf25 | Apollon Oikonomopoulos | self.network6 = ipaddr.IPv6Network(self.net.network6) |
91 | 1de1cf25 | Apollon Oikonomopoulos | if self.net.gateway6: |
92 | 1de1cf25 | Apollon Oikonomopoulos | self.gateway6 = ipaddr.IPv6Address(self.net.gateway6) |
93 | 1de1cf25 | Apollon Oikonomopoulos | |
94 | 1de1cf25 | Apollon Oikonomopoulos | if self.net.reservations: |
95 | 1de1cf25 | Apollon Oikonomopoulos | self.reservations = bitarray(self.net.reservations) |
96 | 1de1cf25 | Apollon Oikonomopoulos | else:
|
97 | 1de1cf25 | Apollon Oikonomopoulos | self.reservations = bitarray(self.network.numhosts) |
98 | beb81ea5 | Dimitris Aragiorgis | # pylint: disable=E1103
|
99 | 1de1cf25 | Apollon Oikonomopoulos | self.reservations.setall(False) |
100 | 1de1cf25 | Apollon Oikonomopoulos | |
101 | 1de1cf25 | Apollon Oikonomopoulos | if self.net.ext_reservations: |
102 | 1de1cf25 | Apollon Oikonomopoulos | self.ext_reservations = bitarray(self.net.ext_reservations) |
103 | 1de1cf25 | Apollon Oikonomopoulos | else:
|
104 | 1de1cf25 | Apollon Oikonomopoulos | self.ext_reservations = bitarray(self.network.numhosts) |
105 | beb81ea5 | Dimitris Aragiorgis | # pylint: disable=E1103
|
106 | 1de1cf25 | Apollon Oikonomopoulos | self.ext_reservations.setall(False) |
107 | 1de1cf25 | Apollon Oikonomopoulos | |
108 | 1de1cf25 | Apollon Oikonomopoulos | assert len(self.reservations) == self.network.numhosts |
109 | 1de1cf25 | Apollon Oikonomopoulos | assert len(self.ext_reservations) == self.network.numhosts |
110 | 1de1cf25 | Apollon Oikonomopoulos | |
111 | beb81ea5 | Dimitris Aragiorgis | def Contains(self, address): |
112 | 1de1cf25 | Apollon Oikonomopoulos | if address is None: |
113 | 1de1cf25 | Apollon Oikonomopoulos | return False |
114 | 1de1cf25 | Apollon Oikonomopoulos | addr = ipaddr.IPAddress(address) |
115 | 1de1cf25 | Apollon Oikonomopoulos | |
116 | 1de1cf25 | Apollon Oikonomopoulos | return addr in self.network |
117 | 1de1cf25 | Apollon Oikonomopoulos | |
118 | 1de1cf25 | Apollon Oikonomopoulos | def _GetAddrIndex(self, address): |
119 | 1de1cf25 | Apollon Oikonomopoulos | addr = ipaddr.IPAddress(address) |
120 | 1de1cf25 | Apollon Oikonomopoulos | |
121 | 1de1cf25 | Apollon Oikonomopoulos | if not addr in self.network: |
122 | 1de1cf25 | Apollon Oikonomopoulos | raise errors.AddressPoolError("%s does not contain %s" % |
123 | 1de1cf25 | Apollon Oikonomopoulos | (self.network, addr))
|
124 | 1de1cf25 | Apollon Oikonomopoulos | |
125 | 1de1cf25 | Apollon Oikonomopoulos | return int(addr) - int(self.network.network) |
126 | 1de1cf25 | Apollon Oikonomopoulos | |
127 | beb81ea5 | Dimitris Aragiorgis | def Update(self): |
128 | 5b34cc22 | Michael Hanselmann | """Write address pools back to the network object.
|
129 | 5b34cc22 | Michael Hanselmann |
|
130 | 5b34cc22 | Michael Hanselmann | """
|
131 | beb81ea5 | Dimitris Aragiorgis | # pylint: disable=E1103
|
132 | 1de1cf25 | Apollon Oikonomopoulos | self.net.ext_reservations = self.ext_reservations.to01() |
133 | 1de1cf25 | Apollon Oikonomopoulos | self.net.reservations = self.reservations.to01() |
134 | 1de1cf25 | Apollon Oikonomopoulos | |
135 | 1de1cf25 | Apollon Oikonomopoulos | def _Mark(self, address, value=True, external=False): |
136 | 1de1cf25 | Apollon Oikonomopoulos | idx = self._GetAddrIndex(address)
|
137 | 1de1cf25 | Apollon Oikonomopoulos | if external:
|
138 | 1de1cf25 | Apollon Oikonomopoulos | self.ext_reservations[idx] = value
|
139 | 1de1cf25 | Apollon Oikonomopoulos | else:
|
140 | 1de1cf25 | Apollon Oikonomopoulos | self.reservations[idx] = value
|
141 | beb81ea5 | Dimitris Aragiorgis | self.Update()
|
142 | 1de1cf25 | Apollon Oikonomopoulos | |
143 | 1de1cf25 | Apollon Oikonomopoulos | def _GetSize(self): |
144 | 3c286190 | Dimitris Aragiorgis | return 2 ** (32 - self.network.prefixlen) |
145 | 1de1cf25 | Apollon Oikonomopoulos | |
146 | 1de1cf25 | Apollon Oikonomopoulos | @property
|
147 | 1de1cf25 | Apollon Oikonomopoulos | def all_reservations(self): |
148 | 5b34cc22 | Michael Hanselmann | """Return a combined map of internal and external reservations.
|
149 | 5b34cc22 | Michael Hanselmann |
|
150 | 5b34cc22 | Michael Hanselmann | """
|
151 | 1de1cf25 | Apollon Oikonomopoulos | return (self.reservations | self.ext_reservations) |
152 | 1de1cf25 | Apollon Oikonomopoulos | |
153 | 1de1cf25 | Apollon Oikonomopoulos | def Validate(self): |
154 | 1de1cf25 | Apollon Oikonomopoulos | assert len(self.reservations) == self._GetSize() |
155 | 1de1cf25 | Apollon Oikonomopoulos | assert len(self.ext_reservations) == self._GetSize() |
156 | 6e8091f9 | Dimitris Aragiorgis | all_res = self.reservations & self.ext_reservations |
157 | 6e8091f9 | Dimitris Aragiorgis | assert not all_res.any() |
158 | 1de1cf25 | Apollon Oikonomopoulos | |
159 | 1de1cf25 | Apollon Oikonomopoulos | if self.gateway is not None: |
160 | 1de1cf25 | Apollon Oikonomopoulos | assert self.gateway in self.network |
161 | 1de1cf25 | Apollon Oikonomopoulos | |
162 | 1de1cf25 | Apollon Oikonomopoulos | if self.network6 and self.gateway6: |
163 | 1de1cf25 | Apollon Oikonomopoulos | assert self.gateway6 in self.network6 |
164 | 1de1cf25 | Apollon Oikonomopoulos | |
165 | 1de1cf25 | Apollon Oikonomopoulos | return True |
166 | 1de1cf25 | Apollon Oikonomopoulos | |
167 | 1de1cf25 | Apollon Oikonomopoulos | def IsFull(self): |
168 | 5b34cc22 | Michael Hanselmann | """Check whether the network is full.
|
169 | 5b34cc22 | Michael Hanselmann |
|
170 | 5b34cc22 | Michael Hanselmann | """
|
171 | 1de1cf25 | Apollon Oikonomopoulos | return self.all_reservations.all() |
172 | 1de1cf25 | Apollon Oikonomopoulos | |
173 | 1de1cf25 | Apollon Oikonomopoulos | def GetReservedCount(self): |
174 | 5b34cc22 | Michael Hanselmann | """Get the count of reserved addresses.
|
175 | 5b34cc22 | Michael Hanselmann |
|
176 | 5b34cc22 | Michael Hanselmann | """
|
177 | 1de1cf25 | Apollon Oikonomopoulos | return self.all_reservations.count(True) |
178 | 1de1cf25 | Apollon Oikonomopoulos | |
179 | 1de1cf25 | Apollon Oikonomopoulos | def GetFreeCount(self): |
180 | 5b34cc22 | Michael Hanselmann | """Get the count of unused addresses.
|
181 | 5b34cc22 | Michael Hanselmann |
|
182 | 5b34cc22 | Michael Hanselmann | """
|
183 | 1de1cf25 | Apollon Oikonomopoulos | return self.all_reservations.count(False) |
184 | 1de1cf25 | Apollon Oikonomopoulos | |
185 | 1de1cf25 | Apollon Oikonomopoulos | def GetMap(self): |
186 | 5b34cc22 | Michael Hanselmann | """Return a textual representation of the network's occupation status.
|
187 | 5b34cc22 | Michael Hanselmann |
|
188 | 5b34cc22 | Michael Hanselmann | """
|
189 | 1de1cf25 | Apollon Oikonomopoulos | return self.all_reservations.to01().replace("1", "X").replace("0", ".") |
190 | 1de1cf25 | Apollon Oikonomopoulos | |
191 | 1de1cf25 | Apollon Oikonomopoulos | def IsReserved(self, address): |
192 | 5b34cc22 | Michael Hanselmann | """Checks if the given IP is reserved.
|
193 | 5b34cc22 | Michael Hanselmann |
|
194 | 5b34cc22 | Michael Hanselmann | """
|
195 | 1de1cf25 | Apollon Oikonomopoulos | idx = self._GetAddrIndex(address)
|
196 | 1de1cf25 | Apollon Oikonomopoulos | return self.all_reservations[idx] |
197 | 1de1cf25 | Apollon Oikonomopoulos | |
198 | 1de1cf25 | Apollon Oikonomopoulos | def Reserve(self, address, external=False): |
199 | 5b34cc22 | Michael Hanselmann | """Mark an address as used.
|
200 | 5b34cc22 | Michael Hanselmann |
|
201 | 5b34cc22 | Michael Hanselmann | """
|
202 | 1de1cf25 | Apollon Oikonomopoulos | if self.IsReserved(address): |
203 | 1de1cf25 | Apollon Oikonomopoulos | raise errors.AddressPoolError("%s is already reserved" % address) |
204 | 1de1cf25 | Apollon Oikonomopoulos | self._Mark(address, external=external)
|
205 | 1de1cf25 | Apollon Oikonomopoulos | |
206 | 1de1cf25 | Apollon Oikonomopoulos | def Release(self, address, external=False): |
207 | 5b34cc22 | Michael Hanselmann | """Release a given address reservation.
|
208 | 5b34cc22 | Michael Hanselmann |
|
209 | 5b34cc22 | Michael Hanselmann | """
|
210 | 1de1cf25 | Apollon Oikonomopoulos | self._Mark(address, value=False, external=external) |
211 | 1de1cf25 | Apollon Oikonomopoulos | |
212 | 1de1cf25 | Apollon Oikonomopoulos | def GetFreeAddress(self): |
213 | 5b34cc22 | Michael Hanselmann | """Returns the first available address.
|
214 | 5b34cc22 | Michael Hanselmann |
|
215 | 5b34cc22 | Michael Hanselmann | """
|
216 | 1de1cf25 | Apollon Oikonomopoulos | if self.IsFull(): |
217 | 1de1cf25 | Apollon Oikonomopoulos | raise errors.AddressPoolError("%s is full" % self.network) |
218 | 1de1cf25 | Apollon Oikonomopoulos | |
219 | 1de1cf25 | Apollon Oikonomopoulos | idx = self.all_reservations.index(False) |
220 | 1de1cf25 | Apollon Oikonomopoulos | address = str(self.network[idx]) |
221 | 1de1cf25 | Apollon Oikonomopoulos | self.Reserve(address)
|
222 | 1de1cf25 | Apollon Oikonomopoulos | return address
|
223 | 1de1cf25 | Apollon Oikonomopoulos | |
224 | 1de1cf25 | Apollon Oikonomopoulos | def GenerateFree(self): |
225 | 5b34cc22 | Michael Hanselmann | """Returns the first free address of the network.
|
226 | 5b34cc22 | Michael Hanselmann |
|
227 | 5b34cc22 | Michael Hanselmann | @raise errors.AddressPoolError: Pool is full
|
228 | 1f1d3bf2 | Dimitris Aragiorgis |
|
229 | 1f1d3bf2 | Dimitris Aragiorgis | """
|
230 | 861a92b4 | Dimitris Aragiorgis | idx = self.all_reservations.search(self.FREE, 1) |
231 | 55f70aef | Dimitris Aragiorgis | if idx:
|
232 | 55f70aef | Dimitris Aragiorgis | return str(self.network[idx[0]]) |
233 | 55f70aef | Dimitris Aragiorgis | else:
|
234 | 55f70aef | Dimitris Aragiorgis | raise errors.AddressPoolError("%s is full" % self.network) |
235 | 1de1cf25 | Apollon Oikonomopoulos | |
236 | 1de1cf25 | Apollon Oikonomopoulos | def GetExternalReservations(self): |
237 | 5b34cc22 | Michael Hanselmann | """Returns a list of all externally reserved addresses.
|
238 | 5b34cc22 | Michael Hanselmann |
|
239 | 5b34cc22 | Michael Hanselmann | """
|
240 | 861a92b4 | Dimitris Aragiorgis | # pylint: disable=E1103
|
241 | 861a92b4 | Dimitris Aragiorgis | idxs = self.ext_reservations.search(self.RESERVED) |
242 | 1de1cf25 | Apollon Oikonomopoulos | return [str(self.network[idx]) for idx in idxs] |
243 | 1de1cf25 | Apollon Oikonomopoulos | |
244 | 1de1cf25 | Apollon Oikonomopoulos | @classmethod
|
245 | 1de1cf25 | Apollon Oikonomopoulos | def InitializeNetwork(cls, net): |
246 | 5b34cc22 | Michael Hanselmann | """Initialize an L{objects.Network} object.
|
247 | 1de1cf25 | Apollon Oikonomopoulos |
|
248 | 5b34cc22 | Michael Hanselmann | Reserve the network, broadcast and gateway IP addresses.
|
249 | 1de1cf25 | Apollon Oikonomopoulos |
|
250 | 1de1cf25 | Apollon Oikonomopoulos | """
|
251 | 1de1cf25 | Apollon Oikonomopoulos | obj = cls(net) |
252 | beb81ea5 | Dimitris Aragiorgis | obj.Update() |
253 | 1de1cf25 | Apollon Oikonomopoulos | for ip in [obj.network[0], obj.network[-1]]: |
254 | 1de1cf25 | Apollon Oikonomopoulos | obj.Reserve(ip, external=True)
|
255 | 1de1cf25 | Apollon Oikonomopoulos | if obj.net.gateway is not None: |
256 | 1de1cf25 | Apollon Oikonomopoulos | obj.Reserve(obj.net.gateway, external=True)
|
257 | 1de1cf25 | Apollon Oikonomopoulos | obj.Validate() |
258 | 1de1cf25 | Apollon Oikonomopoulos | return obj |