Statistics
| Branch: | Tag: | Revision:

root / lib / network.py @ 5349519d

History | View | Annotate | Download (7.7 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 1de1cf25 Apollon Oikonomopoulos
157 1de1cf25 Apollon Oikonomopoulos
    if self.gateway is not None:
158 1de1cf25 Apollon Oikonomopoulos
      assert self.gateway in self.network
159 1de1cf25 Apollon Oikonomopoulos
160 1de1cf25 Apollon Oikonomopoulos
    if self.network6 and self.gateway6:
161 62810f07 Thomas Thrainer
      assert self.gateway6 in self.network6 or self.gateway6.is_link_local
162 1de1cf25 Apollon Oikonomopoulos
163 1de1cf25 Apollon Oikonomopoulos
    return True
164 1de1cf25 Apollon Oikonomopoulos
165 1de1cf25 Apollon Oikonomopoulos
  def IsFull(self):
166 5b34cc22 Michael Hanselmann
    """Check whether the network is full.
167 5b34cc22 Michael Hanselmann

168 5b34cc22 Michael Hanselmann
    """
169 1de1cf25 Apollon Oikonomopoulos
    return self.all_reservations.all()
170 1de1cf25 Apollon Oikonomopoulos
171 1de1cf25 Apollon Oikonomopoulos
  def GetReservedCount(self):
172 5b34cc22 Michael Hanselmann
    """Get the count of reserved addresses.
173 5b34cc22 Michael Hanselmann

174 5b34cc22 Michael Hanselmann
    """
175 1de1cf25 Apollon Oikonomopoulos
    return self.all_reservations.count(True)
176 1de1cf25 Apollon Oikonomopoulos
177 1de1cf25 Apollon Oikonomopoulos
  def GetFreeCount(self):
178 5b34cc22 Michael Hanselmann
    """Get the count of unused addresses.
179 5b34cc22 Michael Hanselmann

180 5b34cc22 Michael Hanselmann
    """
181 1de1cf25 Apollon Oikonomopoulos
    return self.all_reservations.count(False)
182 1de1cf25 Apollon Oikonomopoulos
183 1de1cf25 Apollon Oikonomopoulos
  def GetMap(self):
184 5b34cc22 Michael Hanselmann
    """Return a textual representation of the network's occupation status.
185 5b34cc22 Michael Hanselmann

186 5b34cc22 Michael Hanselmann
    """
187 1de1cf25 Apollon Oikonomopoulos
    return self.all_reservations.to01().replace("1", "X").replace("0", ".")
188 1de1cf25 Apollon Oikonomopoulos
189 031d2db1 Dimitris Aragiorgis
  def IsReserved(self, address, external=False):
190 5b34cc22 Michael Hanselmann
    """Checks if the given IP is reserved.
191 5b34cc22 Michael Hanselmann

192 5b34cc22 Michael Hanselmann
    """
193 1de1cf25 Apollon Oikonomopoulos
    idx = self._GetAddrIndex(address)
194 031d2db1 Dimitris Aragiorgis
    if external:
195 031d2db1 Dimitris Aragiorgis
      return self.ext_reservations[idx]
196 031d2db1 Dimitris Aragiorgis
    else:
197 031d2db1 Dimitris Aragiorgis
      return self.reservations[idx]
198 1de1cf25 Apollon Oikonomopoulos
199 1de1cf25 Apollon Oikonomopoulos
  def Reserve(self, address, external=False):
200 5b34cc22 Michael Hanselmann
    """Mark an address as used.
201 5b34cc22 Michael Hanselmann

202 5b34cc22 Michael Hanselmann
    """
203 031d2db1 Dimitris Aragiorgis
    if self.IsReserved(address, external):
204 031d2db1 Dimitris Aragiorgis
      if external:
205 031d2db1 Dimitris Aragiorgis
        msg = "IP %s is already externally reserved" % address
206 031d2db1 Dimitris Aragiorgis
      else:
207 031d2db1 Dimitris Aragiorgis
        msg = "IP %s is already used by an instance" % address
208 031d2db1 Dimitris Aragiorgis
      raise errors.AddressPoolError(msg)
209 031d2db1 Dimitris Aragiorgis
210 1de1cf25 Apollon Oikonomopoulos
    self._Mark(address, external=external)
211 1de1cf25 Apollon Oikonomopoulos
212 1de1cf25 Apollon Oikonomopoulos
  def Release(self, address, external=False):
213 5b34cc22 Michael Hanselmann
    """Release a given address reservation.
214 5b34cc22 Michael Hanselmann

215 5b34cc22 Michael Hanselmann
    """
216 031d2db1 Dimitris Aragiorgis
    if not self.IsReserved(address, external):
217 031d2db1 Dimitris Aragiorgis
      if external:
218 031d2db1 Dimitris Aragiorgis
        msg = "IP %s is not externally reserved" % address
219 031d2db1 Dimitris Aragiorgis
      else:
220 031d2db1 Dimitris Aragiorgis
        msg = "IP %s is not used by an instance" % address
221 031d2db1 Dimitris Aragiorgis
      raise errors.AddressPoolError(msg)
222 031d2db1 Dimitris Aragiorgis
223 1de1cf25 Apollon Oikonomopoulos
    self._Mark(address, value=False, external=external)
224 1de1cf25 Apollon Oikonomopoulos
225 1de1cf25 Apollon Oikonomopoulos
  def GetFreeAddress(self):
226 5b34cc22 Michael Hanselmann
    """Returns the first available address.
227 5b34cc22 Michael Hanselmann

228 5b34cc22 Michael Hanselmann
    """
229 1de1cf25 Apollon Oikonomopoulos
    if self.IsFull():
230 1de1cf25 Apollon Oikonomopoulos
      raise errors.AddressPoolError("%s is full" % self.network)
231 1de1cf25 Apollon Oikonomopoulos
232 1de1cf25 Apollon Oikonomopoulos
    idx = self.all_reservations.index(False)
233 1de1cf25 Apollon Oikonomopoulos
    address = str(self.network[idx])
234 1de1cf25 Apollon Oikonomopoulos
    self.Reserve(address)
235 1de1cf25 Apollon Oikonomopoulos
    return address
236 1de1cf25 Apollon Oikonomopoulos
237 1de1cf25 Apollon Oikonomopoulos
  def GenerateFree(self):
238 5b34cc22 Michael Hanselmann
    """Returns the first free address of the network.
239 5b34cc22 Michael Hanselmann

240 5b34cc22 Michael Hanselmann
    @raise errors.AddressPoolError: Pool is full
241 1f1d3bf2 Dimitris Aragiorgis

242 1f1d3bf2 Dimitris Aragiorgis
    """
243 861a92b4 Dimitris Aragiorgis
    idx = self.all_reservations.search(self.FREE, 1)
244 55f70aef Dimitris Aragiorgis
    if idx:
245 55f70aef Dimitris Aragiorgis
      return str(self.network[idx[0]])
246 55f70aef Dimitris Aragiorgis
    else:
247 55f70aef Dimitris Aragiorgis
      raise errors.AddressPoolError("%s is full" % self.network)
248 1de1cf25 Apollon Oikonomopoulos
249 1de1cf25 Apollon Oikonomopoulos
  def GetExternalReservations(self):
250 5b34cc22 Michael Hanselmann
    """Returns a list of all externally reserved addresses.
251 5b34cc22 Michael Hanselmann

252 5b34cc22 Michael Hanselmann
    """
253 861a92b4 Dimitris Aragiorgis
    # pylint: disable=E1103
254 861a92b4 Dimitris Aragiorgis
    idxs = self.ext_reservations.search(self.RESERVED)
255 1de1cf25 Apollon Oikonomopoulos
    return [str(self.network[idx]) for idx in idxs]
256 1de1cf25 Apollon Oikonomopoulos
257 1de1cf25 Apollon Oikonomopoulos
  @classmethod
258 1de1cf25 Apollon Oikonomopoulos
  def InitializeNetwork(cls, net):
259 5b34cc22 Michael Hanselmann
    """Initialize an L{objects.Network} object.
260 1de1cf25 Apollon Oikonomopoulos

261 5b34cc22 Michael Hanselmann
    Reserve the network, broadcast and gateway IP addresses.
262 1de1cf25 Apollon Oikonomopoulos

263 1de1cf25 Apollon Oikonomopoulos
    """
264 1de1cf25 Apollon Oikonomopoulos
    obj = cls(net)
265 beb81ea5 Dimitris Aragiorgis
    obj.Update()
266 1de1cf25 Apollon Oikonomopoulos
    for ip in [obj.network[0], obj.network[-1]]:
267 1de1cf25 Apollon Oikonomopoulos
      obj.Reserve(ip, external=True)
268 1de1cf25 Apollon Oikonomopoulos
    if obj.net.gateway is not None:
269 1de1cf25 Apollon Oikonomopoulos
      obj.Reserve(obj.net.gateway, external=True)
270 1de1cf25 Apollon Oikonomopoulos
    obj.Validate()
271 1de1cf25 Apollon Oikonomopoulos
    return obj