Package ganeti :: Module network
[hide private]
[frames] | no frames]

Source Code for Module ganeti.network

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2011, 2012 Google Inc. 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions are 
  9  # met: 
 10  # 
 11  # 1. Redistributions of source code must retain the above copyright notice, 
 12  # this list of conditions and the following disclaimer. 
 13  # 
 14  # 2. Redistributions in binary form must reproduce the above copyright 
 15  # notice, this list of conditions and the following disclaimer in the 
 16  # documentation and/or other materials provided with the distribution. 
 17  # 
 18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 19  # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 20  # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 21  # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 22  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 23  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 24  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 25  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 26  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 27  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 28  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29   
 30   
 31  """IP address pool management functions. 
 32   
 33  """ 
 34   
 35  import ipaddr 
 36   
 37  from bitarray import bitarray 
 38   
 39  from ganeti import errors 
40 41 42 -def _ComputeIpv4NumHosts(network_size):
43 """Derives the number of hosts in an IPv4 network from the size. 44 45 """ 46 return 2 ** (32 - network_size)
47 48 49 IPV4_NETWORK_MIN_SIZE = 30 50 # FIXME: This limit is for performance reasons. Remove when refactoring 51 # for performance tuning was successful. 52 IPV4_NETWORK_MAX_SIZE = 16 53 IPV4_NETWORK_MIN_NUM_HOSTS = _ComputeIpv4NumHosts(IPV4_NETWORK_MIN_SIZE) 54 IPV4_NETWORK_MAX_NUM_HOSTS = _ComputeIpv4NumHosts(IPV4_NETWORK_MAX_SIZE)
55 56 57 -class AddressPool(object):
58 """Address pool class, wrapping an C{objects.Network} object. 59 60 This class provides methods to manipulate address pools, backed by 61 L{objects.Network} objects. 62 63 """ 64 FREE = bitarray("0") 65 RESERVED = bitarray("1") 66
67 - def __init__(self, network):
68 """Initialize a new IPv4 address pool from an L{objects.Network} object. 69 70 @type network: L{objects.Network} 71 @param network: the network object from which the pool will be generated 72 73 """ 74 self.network = None 75 self.gateway = None 76 self.network6 = None 77 self.gateway6 = None 78 79 self.net = network 80 81 self.network = ipaddr.IPNetwork(self.net.network) 82 if self.network.numhosts > IPV4_NETWORK_MAX_NUM_HOSTS: 83 raise errors.AddressPoolError("A big network with %s host(s) is currently" 84 " not supported. please specify at most a" 85 " /%s network" % 86 (str(self.network.numhosts), 87 IPV4_NETWORK_MAX_SIZE)) 88 89 if self.network.numhosts < IPV4_NETWORK_MIN_NUM_HOSTS: 90 raise errors.AddressPoolError("A network with only %s host(s) is too" 91 " small, please specify at least a /%s" 92 " network" % 93 (str(self.network.numhosts), 94 IPV4_NETWORK_MIN_SIZE)) 95 if self.net.gateway: 96 self.gateway = ipaddr.IPAddress(self.net.gateway) 97 98 if self.net.network6: 99 self.network6 = ipaddr.IPv6Network(self.net.network6) 100 if self.net.gateway6: 101 self.gateway6 = ipaddr.IPv6Address(self.net.gateway6) 102 103 if self.net.reservations: 104 self.reservations = bitarray(self.net.reservations) 105 else: 106 self.reservations = bitarray(self.network.numhosts) 107 # pylint: disable=E1103 108 self.reservations.setall(False) 109 110 if self.net.ext_reservations: 111 self.ext_reservations = bitarray(self.net.ext_reservations) 112 else: 113 self.ext_reservations = bitarray(self.network.numhosts) 114 # pylint: disable=E1103 115 self.ext_reservations.setall(False) 116 117 assert len(self.reservations) == self.network.numhosts 118 assert len(self.ext_reservations) == self.network.numhosts
119
120 - def Contains(self, address):
121 if address is None: 122 return False 123 addr = ipaddr.IPAddress(address) 124 125 return addr in self.network
126
127 - def _GetAddrIndex(self, address):
128 addr = ipaddr.IPAddress(address) 129 130 if not addr in self.network: 131 raise errors.AddressPoolError("%s does not contain %s" % 132 (self.network, addr)) 133 134 return int(addr) - int(self.network.network)
135
136 - def Update(self):
137 """Write address pools back to the network object. 138 139 """ 140 # pylint: disable=E1103 141 self.net.ext_reservations = self.ext_reservations.to01() 142 self.net.reservations = self.reservations.to01()
143
144 - def _Mark(self, address, value=True, external=False):
145 idx = self._GetAddrIndex(address) 146 if external: 147 self.ext_reservations[idx] = value 148 else: 149 self.reservations[idx] = value 150 self.Update()
151
152 - def _GetSize(self):
153 return 2 ** (32 - self.network.prefixlen)
154 155 @property
156 - def all_reservations(self):
157 """Return a combined map of internal and external reservations. 158 159 """ 160 return (self.reservations | self.ext_reservations)
161
162 - def Validate(self):
163 assert len(self.reservations) == self._GetSize() 164 assert len(self.ext_reservations) == self._GetSize() 165 166 if self.gateway is not None: 167 assert self.gateway in self.network 168 169 if self.network6 and self.gateway6: 170 assert self.gateway6 in self.network6 or self.gateway6.is_link_local
171
172 - def IsFull(self):
173 """Check whether the network is full. 174 175 """ 176 return self.all_reservations.all()
177
178 - def GetReservedCount(self):
179 """Get the count of reserved addresses. 180 181 """ 182 return self.all_reservations.count(True)
183
184 - def GetFreeCount(self):
185 """Get the count of unused addresses. 186 187 """ 188 return self.all_reservations.count(False)
189
190 - def GetMap(self):
191 """Return a textual representation of the network's occupation status. 192 193 """ 194 return self.all_reservations.to01().replace("1", "X").replace("0", ".")
195
196 - def IsReserved(self, address, external=False):
197 """Checks if the given IP is reserved. 198 199 """ 200 idx = self._GetAddrIndex(address) 201 if external: 202 return self.ext_reservations[idx] 203 else: 204 return self.reservations[idx]
205
206 - def Reserve(self, address, external=False):
207 """Mark an address as used. 208 209 """ 210 if self.IsReserved(address, external): 211 if external: 212 msg = "IP %s is already externally reserved" % address 213 else: 214 msg = "IP %s is already used by an instance" % address 215 raise errors.AddressPoolError(msg) 216 217 self._Mark(address, external=external)
218
219 - def Release(self, address, external=False):
220 """Release a given address reservation. 221 222 """ 223 if not self.IsReserved(address, external): 224 if external: 225 msg = "IP %s is not externally reserved" % address 226 else: 227 msg = "IP %s is not used by an instance" % address 228 raise errors.AddressPoolError(msg) 229 230 self._Mark(address, value=False, external=external)
231
232 - def GetFreeAddress(self):
233 """Returns the first available address. 234 235 """ 236 if self.IsFull(): 237 raise errors.AddressPoolError("%s is full" % self.network) 238 239 idx = self.all_reservations.index(False) 240 address = str(self.network[idx]) 241 self.Reserve(address) 242 return address
243
244 - def GenerateFree(self):
245 """Returns the first free address of the network. 246 247 @raise errors.AddressPoolError: Pool is full 248 249 """ 250 idx = self.all_reservations.search(self.FREE, 1) 251 if idx: 252 return str(self.network[idx[0]]) 253 else: 254 raise errors.AddressPoolError("%s is full" % self.network)
255
256 - def GetExternalReservations(self):
257 """Returns a list of all externally reserved addresses. 258 259 """ 260 # pylint: disable=E1103 261 idxs = self.ext_reservations.search(self.RESERVED) 262 return [str(self.network[idx]) for idx in idxs]
263 264 @classmethod
265 - def InitializeNetwork(cls, net):
266 """Initialize an L{objects.Network} object. 267 268 Reserve the network, broadcast and gateway IP addresses. 269 270 """ 271 obj = cls(net) 272 obj.Update() 273 for ip in [obj.network[0], obj.network[-1]]: 274 obj.Reserve(ip, external=True) 275 if obj.net.gateway is not None: 276 obj.Reserve(obj.net.gateway, external=True) 277 obj.Validate() 278 return obj
279