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 return True
173
174 - def IsFull(self):
175 """Check whether the network is full. 176 177 """ 178 return self.all_reservations.all()
179
180 - def GetReservedCount(self):
181 """Get the count of reserved addresses. 182 183 """ 184 return self.all_reservations.count(True)
185
186 - def GetFreeCount(self):
187 """Get the count of unused addresses. 188 189 """ 190 return self.all_reservations.count(False)
191
192 - def GetMap(self):
193 """Return a textual representation of the network's occupation status. 194 195 """ 196 return self.all_reservations.to01().replace("1", "X").replace("0", ".")
197
198 - def IsReserved(self, address, external=False):
199 """Checks if the given IP is reserved. 200 201 """ 202 idx = self._GetAddrIndex(address) 203 if external: 204 return self.ext_reservations[idx] 205 else: 206 return self.reservations[idx]
207
208 - def Reserve(self, address, external=False):
209 """Mark an address as used. 210 211 """ 212 if self.IsReserved(address, external): 213 if external: 214 msg = "IP %s is already externally reserved" % address 215 else: 216 msg = "IP %s is already used by an instance" % address 217 raise errors.AddressPoolError(msg) 218 219 self._Mark(address, external=external)
220
221 - def Release(self, address, external=False):
222 """Release a given address reservation. 223 224 """ 225 if not self.IsReserved(address, external): 226 if external: 227 msg = "IP %s is not externally reserved" % address 228 else: 229 msg = "IP %s is not used by an instance" % address 230 raise errors.AddressPoolError(msg) 231 232 self._Mark(address, value=False, external=external)
233
234 - def GetFreeAddress(self):
235 """Returns the first available address. 236 237 """ 238 if self.IsFull(): 239 raise errors.AddressPoolError("%s is full" % self.network) 240 241 idx = self.all_reservations.index(False) 242 address = str(self.network[idx]) 243 self.Reserve(address) 244 return address
245
246 - def GenerateFree(self):
247 """Returns the first free address of the network. 248 249 @raise errors.AddressPoolError: Pool is full 250 251 """ 252 idx = self.all_reservations.search(self.FREE, 1) 253 if idx: 254 return str(self.network[idx[0]]) 255 else: 256 raise errors.AddressPoolError("%s is full" % self.network)
257
258 - def GetExternalReservations(self):
259 """Returns a list of all externally reserved addresses. 260 261 """ 262 # pylint: disable=E1103 263 idxs = self.ext_reservations.search(self.RESERVED) 264 return [str(self.network[idx]) for idx in idxs]
265 266 @classmethod
267 - def InitializeNetwork(cls, net):
268 """Initialize an L{objects.Network} object. 269 270 Reserve the network, broadcast and gateway IP addresses. 271 272 """ 273 obj = cls(net) 274 obj.Update() 275 for ip in [obj.network[0], obj.network[-1]]: 276 obj.Reserve(ip, external=True) 277 if obj.net.gateway is not None: 278 obj.Reserve(obj.net.gateway, external=True) 279 obj.Validate() 280 return obj
281