diff options
author | mathrock <nathanael.i.burton.work@gmail.com> | 2013-03-06 16:28:50 -0500 |
---|---|---|
committer | mathrock <nathanael.i.burton.work@gmail.com> | 2013-03-12 01:45:25 -0400 |
commit | 26440ae2cd4c8ffe44beecb6bb0cce19cb43bb7b (patch) | |
tree | 6eb892252f9e3a7dc09329d55b5a260c2de4f779 | |
parent | ae251b99a3fb6aa99ec8898152d79dfa2c026a92 (diff) | |
download | nova-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.py | 10 | ||||
-rw-r--r-- | nova/network/manager.py | 23 | ||||
-rw-r--r-- | nova/tests/network/test_manager.py | 201 |
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): |