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