summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormathrock <nathanael.i.burton.work@gmail.com>2013-03-06 16:28:50 -0500
committermathrock <nathanael.i.burton.work@gmail.com>2013-03-12 01:45:25 -0400
commit26440ae2cd4c8ffe44beecb6bb0cce19cb43bb7b (patch)
tree6eb892252f9e3a7dc09329d55b5a260c2de4f779
parentae251b99a3fb6aa99ec8898152d79dfa2c026a92 (diff)
downloadnova-26440ae2cd4c8ffe44beecb6bb0cce19cb43bb7b.tar.gz
nova-26440ae2cd4c8ffe44beecb6bb0cce19cb43bb7b.tar.xz
nova-26440ae2cd4c8ffe44beecb6bb0cce19cb43bb7b.zip
Deprecate CONF.fixed_range, do dynamic setup
Do dynamic fixed_range setup by pulling the networks that should exist on the host and making the appropriate calls to set up the NAT entries for each network. This allows for non-contiguous subnets to be configured in the fixed_ip space and only configures the NAT rules as they are needed. This also restricts the NAT range to the smallest range required preventing the NAT from impacting subnets that might exist on the external network. DocImpact: For backwards compatibility, Grizzly will still support the CONF.fixed_range option and if set will perform the default logic from Folsom and earlier releases. To use the new dynamic fixed_range setup in Grizzly, set fixed_range='' in your nova.conf. The intention is to remove the CONF.fixed_range option entirely early in the Havana cycle and use the dynamic fixed_range setup from Havana going forward. Change-Id: I4ec111079f7a1d253190e6a6008048f992a53f68 Fixes: bug #741626 bug #966175
-rw-r--r--nova/network/l3.py10
-rw-r--r--nova/network/manager.py23
-rw-r--r--nova/tests/network/test_manager.py201
3 files changed, 229 insertions, 5 deletions
diff --git a/nova/network/l3.py b/nova/network/l3.py
index 9ca6b6a43..7511f7ba4 100644
--- a/nova/network/l3.py
+++ b/nova/network/l3.py
@@ -79,7 +79,13 @@ class LinuxNetL3(L3Driver):
if self.initialized:
return
LOG.debug("Initializing linux_net L3 driver")
- linux_net.init_host()
+ fixed_range = kwargs.get('fixed_range', False)
+ networks = kwargs.get('networks', None)
+ if not fixed_range and networks is not None:
+ for network in networks:
+ self.initialize_network(network['cidr'])
+ else:
+ linux_net.init_host()
linux_net.ensure_metadata_ip()
linux_net.metadata_forward()
self.initialized = True
@@ -88,7 +94,7 @@ class LinuxNetL3(L3Driver):
return self.initialized
def initialize_network(self, cidr):
- linux_net.add_snat_rule(cidr)
+ linux_net.init_host(cidr)
def initialize_gateway(self, network_ref):
mac_address = utils.generate_mac_address()
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 482744a8b..f1a3c45d2 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -106,9 +106,12 @@ network_opts = [
cfg.IntOpt('network_size',
default=256,
help='Number of addresses in each private subnet'),
+ # TODO(mathrock): Deprecate in Grizzly, remove in Havana
cfg.StrOpt('fixed_range',
default='10.0.0.0/8',
- help='Fixed IP address block'),
+ help='DEPRECATED - Fixed IP address block.'
+ 'If set to an empty string, the subnet range(s) will be '
+ 'automatically determined and configured.'),
cfg.StrOpt('fixed_range_v6',
default='fd00::/48',
help='Fixed IPv6 address block'),
@@ -1559,7 +1562,12 @@ class FlatDHCPManager(RPCAllocateFixedIP, floating_ips.FloatingIP,
"""Do any initialization that needs to be run if this is a
standalone service.
"""
- self.l3driver.initialize()
+ if not CONF.fixed_range:
+ ctxt = context.get_admin_context()
+ networks = self.db.network_get_all_by_host(ctxt, self.host)
+ self.l3driver.initialize(fixed_range=False, networks=networks)
+ else:
+ self.l3driver.initialize(fixed_range=CONF.fixed_range)
super(FlatDHCPManager, self).init_host()
self.init_host_floating_ips()
@@ -1567,6 +1575,8 @@ class FlatDHCPManager(RPCAllocateFixedIP, floating_ips.FloatingIP,
"""Sets up network on this host."""
network['dhcp_server'] = self._get_dhcp_ip(context, network)
+ if not CONF.fixed_range:
+ self.l3driver.initialize_network(network.get('cidr'))
self.l3driver.initialize_gateway(network)
if not CONF.fake_network:
@@ -1630,7 +1640,12 @@ class VlanManager(RPCAllocateFixedIP, floating_ips.FloatingIP, NetworkManager):
standalone service.
"""
- self.l3driver.initialize()
+ if not CONF.fixed_range:
+ ctxt = context.get_admin_context()
+ networks = self.db.network_get_all_by_host(ctxt, self.host)
+ self.l3driver.initialize(fixed_range=False, networks=networks)
+ else:
+ self.l3driver.initialize(fixed_range=CONF.fixed_range)
NetworkManager.init_host(self)
self.init_host_floating_ips()
@@ -1773,6 +1788,8 @@ class VlanManager(RPCAllocateFixedIP, floating_ips.FloatingIP, NetworkManager):
address = network['vpn_public_address']
network['dhcp_server'] = self._get_dhcp_ip(context, network)
+ if not CONF.fixed_range:
+ self.l3driver.initialize_network(network.get('cidr'))
self.l3driver.initialize_gateway(network)
# NOTE(vish): only ensure this forward if the address hasn't been set
diff --git a/nova/tests/network/test_manager.py b/nova/tests/network/test_manager.py
index 92b8e1d91..6121ae8ac 100644
--- a/nova/tests/network/test_manager.py
+++ b/nova/tests/network/test_manager.py
@@ -1601,6 +1601,207 @@ class CommonNetworkTestCase(test.TestCase):
self.assertRaises(exception.NetworkNotFound,
manager.disassociate_network, fake_context, uuid)
+ def _test_init_host_static_fixed_range(self, net_manager):
+ self.flags(fake_network=True,
+ fixed_range='10.0.0.0/22',
+ routing_source_ip='192.168.0.1',
+ metadata_host='192.168.0.1',
+ public_interface='eth1',
+ dmz_cidr=['10.0.3.0/24'])
+ binary_name = linux_net.get_binary_name()
+
+ # Stub out calls we don't want to really run
+ self.stubs.Set(linux_net.iptables_manager, '_apply', lambda: None)
+ self.stubs.Set(floating_ips.FloatingIP, 'init_host_floating_ips',
+ lambda *args: None)
+
+ # Call the network manager init code to configure the fixed_range
+ net_manager.init_host()
+
+ # Get the iptables rules that got created
+ current_lines = []
+ new_lines = linux_net.iptables_manager._modify_rules(current_lines,
+ linux_net.iptables_manager.ipv4['nat'],
+ table_name='nat')
+
+ # The expected rules that should be configured based on the fixed_range
+ expected_lines = ['[0:0] -A %s-snat -s %s -j SNAT --to-source %s -o %s'
+ % (binary_name, CONF.fixed_range,
+ CONF.routing_source_ip,
+ CONF.public_interface),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s/32 -j ACCEPT'
+ % (binary_name, CONF.fixed_range,
+ CONF.metadata_host),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s -j ACCEPT'
+ % (binary_name, CONF.fixed_range, CONF.dmz_cidr[0]),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s -m conntrack ! '
+ '--ctstate DNAT -j ACCEPT' % (binary_name,
+ CONF.fixed_range,
+ CONF.fixed_range)]
+
+ # Finally, compare the expected rules against the actual ones
+ for line in expected_lines:
+ self.assertTrue(line in new_lines)
+
+ def _test_init_host_dynamic_fixed_range(self, net_manager):
+ self.flags(fake_network=True,
+ fixed_range='',
+ routing_source_ip='172.16.0.1',
+ metadata_host='172.16.0.1',
+ public_interface='eth1',
+ dmz_cidr=['10.0.3.0/24'])
+ binary_name = linux_net.get_binary_name()
+
+ # Stub out calls we don't want to really run, mock the db
+ self.stubs.Set(linux_net.iptables_manager, '_apply', lambda: None)
+ self.stubs.Set(floating_ips.FloatingIP, 'init_host_floating_ips',
+ lambda *args: None)
+ self.stubs.Set(net_manager.l3driver, 'initialize_gateway',
+ lambda *args: None)
+ self.mox.StubOutWithMock(db, 'network_get_all_by_host')
+ db.network_get_all_by_host(mox.IgnoreArg(),
+ mox.IgnoreArg()).MultipleTimes().AndReturn(networks)
+ self.mox.ReplayAll()
+
+ # Call the network manager init code to configure the fixed_range
+ net_manager.init_host()
+
+ # Get the iptables rules that got created
+ current_lines = []
+ new_lines = linux_net.iptables_manager._modify_rules(current_lines,
+ linux_net.iptables_manager.ipv4['nat'],
+ table_name='nat')
+
+ # The expected rules that should be configured based on the fixed_range
+ expected_lines = ['[0:0] -A %s-snat -s %s -j SNAT --to-source %s -o %s'
+ % (binary_name, networks[0]['cidr'],
+ CONF.routing_source_ip,
+ CONF.public_interface),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s/32 -j ACCEPT'
+ % (binary_name, networks[0]['cidr'],
+ CONF.metadata_host),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s -j ACCEPT'
+ % (binary_name, networks[0]['cidr'],
+ CONF.dmz_cidr[0]),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s -m conntrack ! '
+ '--ctstate DNAT -j ACCEPT' % (binary_name,
+ networks[0]['cidr'],
+ networks[0]['cidr']),
+ '[0:0] -A %s-snat -s %s -j SNAT --to-source %s -o %s'
+ % (binary_name, networks[1]['cidr'],
+ CONF.routing_source_ip,
+ CONF.public_interface),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s/32 -j ACCEPT'
+ % (binary_name, networks[1]['cidr'],
+ CONF.metadata_host),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s -j ACCEPT'
+ % (binary_name, networks[1]['cidr'],
+ CONF.dmz_cidr[0]),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s -m conntrack ! '
+ '--ctstate DNAT -j ACCEPT' % (binary_name,
+ networks[1]['cidr'],
+ networks[1]['cidr'])]
+
+ # Compare the expected rules against the actual ones
+ for line in expected_lines:
+ self.assertTrue(line in new_lines)
+
+ # Add an additional network and ensure the rules get configured
+ new_network = {'id': 2,
+ 'uuid': 'cccccccc-cccc-cccc-cccc-cccccccc',
+ 'label': 'test2',
+ 'injected': False,
+ 'multi_host': False,
+ 'cidr': '192.168.2.0/24',
+ 'cidr_v6': '2001:dba::/64',
+ 'gateway_v6': '2001:dba::1',
+ 'netmask_v6': '64',
+ 'netmask': '255.255.255.0',
+ 'bridge': 'fa1',
+ 'bridge_interface': 'fake_fa1',
+ 'gateway': '192.168.2.1',
+ 'broadcast': '192.168.2.255',
+ 'dns1': '192.168.2.1',
+ 'dns2': '192.168.2.2',
+ 'vlan': None,
+ 'host': HOST,
+ 'project_id': 'fake_project',
+ 'vpn_public_address': '192.168.2.2',
+ 'vpn_public_port': '22',
+ 'vpn_private_address': '10.0.0.2'}
+
+ # Call the network manager init code to configure the fixed_range
+ ctxt = context.get_admin_context()
+ net_manager._setup_network_on_host(ctxt, new_network)
+
+ # Get the new iptables rules that got created from adding a new network
+ current_lines = []
+ new_lines = linux_net.iptables_manager._modify_rules(current_lines,
+ linux_net.iptables_manager.ipv4['nat'],
+ table_name='nat')
+
+ # Add the new expected rules to the old ones
+ expected_lines += ['[0:0] -A %s-snat -s %s -j SNAT --to-source %s -o '
+ '%s' % (binary_name, new_network['cidr'],
+ CONF.routing_source_ip,
+ CONF.public_interface),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s/32 -j ACCEPT'
+ % (binary_name, new_network['cidr'],
+ CONF.metadata_host),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s -j ACCEPT'
+ % (binary_name, new_network['cidr'],
+ CONF.dmz_cidr[0]),
+ '[0:0] -A %s-POSTROUTING -s %s -d %s -m conntrack '
+ '! --ctstate DNAT -j ACCEPT' % (binary_name,
+ new_network['cidr'],
+ new_network['cidr'])]
+
+ # Compare the expected rules (with new network) against the actual ones
+ for line in expected_lines:
+ self.assertTrue(line in new_lines)
+
+ def test_flatdhcpmanager_static_fixed_range(self):
+ """Test FlatDHCPManager NAT rules for fixed_range."""
+ # Set the network manager
+ self.network = network_manager.FlatDHCPManager(host=HOST)
+ self.network.db = db
+
+ # Test existing behavior:
+ # CONF.fixed_range is set, NAT based on CONF.fixed_range
+ self._test_init_host_static_fixed_range(self.network)
+
+ def test_flatdhcpmanager_dynamic_fixed_range(self):
+ """Test FlatDHCPManager NAT rules for fixed_range."""
+ # Set the network manager
+ self.network = network_manager.FlatDHCPManager(host=HOST)
+ self.network.db = db
+
+ # Test new behavior:
+ # CONF.fixed_range is not set, defaults to None
+ # Determine networks to NAT based on lookup
+ self._test_init_host_dynamic_fixed_range(self.network)
+
+ def test_vlanmanager_static_fixed_range(self):
+ """Test VlanManager NAT rules for fixed_range."""
+ # Set the network manager
+ self.network = network_manager.VlanManager(host=HOST)
+ self.network.db = db
+
+ # Test existing behavior:
+ # CONF.fixed_range is set, NAT based on CONF.fixed_range
+ self._test_init_host_static_fixed_range(self.network)
+
+ def test_vlanmanager_dynamic_fixed_range(self):
+ """Test VlanManager NAT rules for fixed_range."""
+ # Set the network manager
+ self.network = network_manager.VlanManager(host=HOST)
+ self.network.db = db
+
+ # Test new behavior:
+ # CONF.fixed_range is not set, defaults to None
+ # Determine networks to NAT based on lookup
+ self._test_init_host_dynamic_fixed_range(self.network)
+
class TestRPCFixedManager(network_manager.RPCAllocateFixedIP,
network_manager.NetworkManager):