summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/network/manager.py48
-rw-r--r--nova/tests/test_network.py102
2 files changed, 150 insertions, 0 deletions
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 4a3791d8a..fafb75c9e 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -609,6 +609,54 @@ class NetworkManager(manager.SchedulerDependentManager):
network_ref = self.db.fixed_ip_get_network(context, address)
self._setup_network(context, network_ref)
+ def _validate_cidrs(self, context, cidr, num_networks, network_size):
+ significant_bits = 32 - int(math.log(network_size, 2))
+ req_net = netaddr.IPNetwork(cidr)
+ req_net_ip = str(req_net.ip)
+ req_size = network_size * num_networks
+ if req_size > req_net.size:
+ raise ValueError(_("network_size * num_networks exceeds cidr size"))
+ adjusted_cidr = netaddr.IPNetwork(req_net_ip+'/'+str(significant_bits))
+ all_req_nets = [adjusted_cidr]
+ try:
+ used_nets = self.db.network_get_all(context)
+ except exception.NoNetworksFound:
+ used_nets = []
+ used_cidrs = [netaddr.IPNetwork(net['cidr']) for net in used_nets]
+ if adjusted_cidr in used_cidrs:
+ raise ValueError(_("cidr already in use"))
+ for adjusted_cidr_supernet in adjusted_cidr.supernet():
+ if adjusted_cidr_supernet in used_cidrs:
+ raise ValueError(_("requested cidr (%s) conflicts with existing supernet (%s)" % (str(adjusted_cidr), str(adjusted_cidr_supernet))))
+ # split supernet into subnets
+ if num_networks >= 2:
+ next_cidr = adjusted_cidr
+ for used_cidr in used_cidrs:
+ # watch for smaller subnets conflicting
+ if used_cidr.size < next_cidr.size:
+ for ucsupernet in used_cidr.supernet():
+ if ucsupernet.size == next_cidr.size:
+ used_cidrs.append(ucsupernet)
+ for index in range(1, num_networks):
+ while True:
+ next_cidr = next_cidr.next()
+ if next_cidr in used_cidrs:
+ continue
+ else:
+ all_req_nets.append(next_cidr)
+ break
+ all_req_nets = list(set(all_req_nets))
+ if not used_nets:
+ return all_req_nets
+ # after splitting ensure there were enough to satisfy the num_networks
+ if len(all_req_nets) < num_networks:
+ raise ValueError(_("Not enough subnets avail to satisfy requested num_networks"))
+ # if one of the split subnets were already defined, remove from create list
+ for req_cidr in all_req_nets:
+ if req_cidr in used_cidrs:
+ all_req_nets.remove(req_cidr)
+ return all_req_nets
+
def create_networks(self, context, label, cidr, multi_host, num_networks,
network_size, cidr_v6, gateway_v6, bridge,
bridge_interface, dns1=None, dns2=None, **kwargs):
diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py
index 28f50d328..8a851cf76 100644
--- a/nova/tests/test_network.py
+++ b/nova/tests/test_network.py
@@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from nova import context
from nova import db
from nova import exception
from nova import flags
@@ -249,6 +250,15 @@ class CommonNetworkTestCase(test.TestCase):
return [dict(address='10.0.0.0'), dict(address='10.0.0.1'),
dict(address='10.0.0.2')]
+ def network_get_by_cidr(self, context, cidr):
+ raise exception.NetworkNotFoundForCidr()
+
+ def network_create_safe(self, context, net):
+ return {'foo': 'bar'}
+
+ def network_get_all(self, context):
+ raise exception.NoNetworksFound()
+
def __init__(self):
self.db = self.FakeDB()
self.deallocate_called = None
@@ -267,3 +277,95 @@ class CommonNetworkTestCase(test.TestCase):
self.assertRaises(exception.FixedIpNotFoundForSpecificInstance,
manager.remove_fixed_ip_from_instance,
None, 99, 'bad input')
+
+ def test__validate_cidrs(self):
+ manager = self.FakeNetworkManager()
+ nets = manager._validate_cidrs(None, '192.168.0.0/24', 1, 256)
+ self.assertEqual(1, len(nets))
+ cidrs = [str(net) for net in nets]
+ self.assertTrue('192.168.0.0/24' in cidrs)
+
+ def test__validate_cidrs_split_exact_in_half(self):
+ manager = self.FakeNetworkManager()
+ nets = manager._validate_cidrs(None, '192.168.0.0/24', 2, 128)
+ self.assertEqual(2, len(nets))
+ cidrs = [str(net) for net in nets]
+ self.assertTrue('192.168.0.0/25' in cidrs)
+ self.assertTrue('192.168.0.128/25' in cidrs)
+
+ def test__validate_cidrs_split_cidr_in_use_middle_of_range(self):
+ manager = self.FakeNetworkManager()
+ self.mox.StubOutWithMock(manager.db, 'network_get_all')
+ ctxt = mox.IgnoreArg()
+ manager.db.network_get_all(ctxt).AndReturn([{'id': 1, 'cidr': '192.168.2.0/24'}])
+ self.mox.ReplayAll()
+ nets = manager._validate_cidrs(None, '192.168.0.0/16', 4, 256)
+ self.assertEqual(4, len(nets))
+ cidrs = [str(net) for net in nets]
+ exp_cidrs = ['192.168.0.0', '192.168.1.0', '192.168.3.0', '192.168.4.0']
+ for exp_cidr in exp_cidrs:
+ self.assertTrue(exp_cidr+'/24' in cidrs)
+ self.assertFalse('192.168.2.0/24' in cidrs)
+
+ def test__validate_cidrs_split_cidr_smaller_subnet_in_use_middle_of_range(self):
+ manager = self.FakeNetworkManager()
+ self.mox.StubOutWithMock(manager.db, 'network_get_all')
+ ctxt = mox.IgnoreArg()
+ manager.db.network_get_all(ctxt).AndReturn([{'id': 1, 'cidr': '192.168.2.0/25'}])
+ self.mox.ReplayAll()
+ nets = manager._validate_cidrs(None, '192.168.0.0/16', 4, 256)
+ self.assertEqual(4, len(nets))
+ cidrs = [str(net) for net in nets]
+ exp_cidrs = ['192.168.0.0', '192.168.1.0', '192.168.3.0', '192.168.4.0']
+ for exp_cidr in exp_cidrs:
+ self.assertTrue(exp_cidr+'/24' in cidrs)
+ self.assertFalse('192.168.2.0/24' in cidrs)
+
+ def test__validate_cidrs_one_in_use(self):
+ manager = self.FakeNetworkManager()
+ args = [None, '192.168.0.0/24', 2, 256]
+ # ValueError: network_size * num_networks exceeds cidr size
+ self.assertRaises(ValueError, manager._validate_cidrs, *args)
+
+ def test__validate_cidrs_already_used(self):
+ manager = self.FakeNetworkManager()
+ self.mox.StubOutWithMock(manager.db, 'network_get_all')
+ ctxt = mox.IgnoreArg()
+ manager.db.network_get_all(ctxt).AndReturn([{'id': 1, 'cidr': '192.168.0.0/24'}])
+ self.mox.ReplayAll()
+ # ValueError: cidr already in use
+ args = [None, '192.168.0.0/24', 1, 256]
+ self.assertRaises(ValueError, manager._validate_cidrs, *args)
+
+ def test__validate_cidrs_too_many(self):
+ manager = self.FakeNetworkManager()
+ args = [None, '192.168.0.0/24', 200, 256]
+ # ValueError: Not enough subnets avail to satisfy requested num_networks
+ self.assertRaises(ValueError, manager._validate_cidrs, *args)
+
+ def test__validate_cidrs_split_partial(self):
+ manager = self.FakeNetworkManager()
+ nets = manager._validate_cidrs(None, '192.168.0.0/16', 2, 256)
+ returned_cidrs = [str(net) for net in nets]
+ print returned_cidrs
+ self.assertTrue('192.168.0.0/24' in returned_cidrs)
+ self.assertTrue('192.168.1.0/24' in returned_cidrs)
+
+ def test__validate_cidrs_conflict_existing_supernet(self):
+ manager = self.FakeNetworkManager()
+ self.mox.StubOutWithMock(manager.db, 'network_get_all')
+ ctxt = mox.IgnoreArg()
+ manager.db.network_get_all(ctxt).AndReturn([{'id': 1, 'cidr': '192.168.0.0/8'}])
+ self.mox.ReplayAll()
+ args = [None, '192.168.0.0/24', 1, 256]
+ # ValueError: requested cidr (192.168.0.0/24) conflicts with existing supernet (192.0.0.0/8)
+ self.assertRaises(ValueError, manager._validate_cidrs, *args)
+#
+# def test_create_networks_cidr_already_used(self):
+# mockany = self.mox.CreateMockAnything()
+# manager = self.FakeNetworkManager()
+# self.mox.StubOutWithMock(manager.db, 'network_get_by_cidr')
+# manager.db.network_get_by_cidr(mox.IgnoreArg(), '192.168.0.0/24').AndReturn(mockany)
+# self.mox.ReplayAll()
+# args = [None, 'foo', '192.168.0.0/24', None, 1, 256, 'fd00::/48', None, None, None]
+# self.assertRaises(ValueError, manager.create_networks, *args)