From 5cb05ffad81859b3803f432cbaa3a2b0ff1567fc Mon Sep 17 00:00:00 2001 From: Thomas Goirand Date: Tue, 3 Jun 2014 00:08:25 +0800 Subject: [PATCH] Adds Install_SNAT_rules_for_ipv4_only.patch. Note that without this patch, it's possible to destroy an OpenStack cloud network, which is why I'm putting urgency=high in this upload. Change-Id: I34aa3c656f0218a1986ef6b78f7e28132d6172a6 --- debian/changelog | 8 + .../Install_SNAT_rules_for_ipv4_only.patch | 204 ++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 213 insertions(+) create mode 100644 debian/patches/Install_SNAT_rules_for_ipv4_only.patch diff --git a/debian/changelog b/debian/changelog index dcc13dfdd..98e50a5dc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +neutron (2014.1-6) unstable; urgency=high + + * Adds Install_SNAT_rules_for_ipv4_only.patch. Note that without this patch, + it's possible to destroy an OpenStack cloud network, which is why I'm + putting urgency=high in this upload. + + -- Thomas Goirand Tue, 03 Jun 2014 00:07:08 +0800 + neutron (2014.1-5) unstable; urgency=medium * Switched from restarting daemons to copytruncate for logrotate. diff --git a/debian/patches/Install_SNAT_rules_for_ipv4_only.patch b/debian/patches/Install_SNAT_rules_for_ipv4_only.patch new file mode 100644 index 000000000..a86f5c050 --- /dev/null +++ b/debian/patches/Install_SNAT_rules_for_ipv4_only.patch @@ -0,0 +1,204 @@ +Description: Install SNAT rules for ipv4 only +Author: Baodong Li +Date: Thu, 24 Apr 2014 01:47:13 +0000 (+0000) +X-Git-Url: https://review.openstack.org/gitweb?p=openstack%2Fneutron.git;a=commitdiff_plain;h=28a26dbfd7e95ad84e8c9eeac1e5aba0b111a16c +Origin: https://review.openstack.org/95938/ +Change-Id: I37bd770aa0d54a985ac2bec708c571785084e0ec +Bug-Ubuntu: https://launchpad.net/bugs/1309195 +Last-Update: 2014-06-02 + +diff --git a/neutron/agent/l3_agent.py b/neutron/agent/l3_agent.py +index f335da7..e9854fd 100644 +--- a/neutron/agent/l3_agent.py ++++ b/neutron/agent/l3_agent.py +@@ -451,7 +451,9 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, manager.Manager): + namespace=ri.ns_name, + prefix=INTERNAL_DEV_PREFIX) + +- internal_cidrs = [p['ip_cidr'] for p in ri.internal_ports] ++ # Get IPv4 only internal CIDRs ++ internal_cidrs = [p['ip_cidr'] for p in ri.internal_ports ++ if netaddr.IPNetwork(p['ip_cidr']).version == 4] + # TODO(salv-orlando): RouterInfo would be a better place for + # this logic too + ex_gw_port_id = (ex_gw_port and ex_gw_port['id'] or +@@ -530,11 +532,16 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, manager.Manager): + # And add them back if the action if add_rules + if action == 'add_rules' and ex_gw_port: + # ex_gw_port should not be None in this case +- ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address'] +- for rule in self.external_gateway_nat_rules(ex_gw_ip, +- internal_cidrs, +- interface_name): +- ri.iptables_manager.ipv4['nat'].add_rule(*rule) ++ # NAT rules are added only if ex_gw_port has an IPv4 address ++ for ip_addr in ex_gw_port['fixed_ips']: ++ ex_gw_ip = ip_addr['ip_address'] ++ if netaddr.IPAddress(ex_gw_ip).version == 4: ++ rules = self.external_gateway_nat_rules(ex_gw_ip, ++ internal_cidrs, ++ interface_name) ++ for rule in rules: ++ ri.iptables_manager.ipv4['nat'].add_rule(*rule) ++ break + ri.iptables_manager.apply() + + def process_router_floating_ip_nat_rules(self, ri): +diff --git a/neutron/tests/unit/test_l3_agent.py b/neutron/tests/unit/test_l3_agent.py +index d1dffff..ec272ef 100644 +--- a/neutron/tests/unit/test_l3_agent.py ++++ b/neutron/tests/unit/test_l3_agent.py +@@ -17,6 +17,7 @@ import contextlib + import copy + + import mock ++import netaddr + from oslo.config import cfg + from testtools import matchers + +@@ -331,24 +332,37 @@ class TestBasicRouterOperations(base.BaseTestCase): + '! -i %s ! -o %s -m conntrack ! --ctstate DNAT -j ACCEPT' % + (interface_name, interface_name)] + for source_cidr in source_cidrs: +- value_dict = {'source_cidr': source_cidr, +- 'source_nat_ip': source_nat_ip} +- expected_rules.append('-s %(source_cidr)s -j SNAT --to-source ' +- '%(source_nat_ip)s' % value_dict) ++ # Create SNAT rules for IPv4 only ++ if (netaddr.IPNetwork(source_cidr).version == 4 and ++ netaddr.IPNetwork(source_nat_ip).version == 4): ++ value_dict = {'source_cidr': source_cidr, ++ 'source_nat_ip': source_nat_ip} ++ expected_rules.append('-s %(source_cidr)s -j SNAT --to-source ' ++ '%(source_nat_ip)s' % value_dict) + for r in rules: + if negate: + self.assertNotIn(r.rule, expected_rules) + else: + self.assertIn(r.rule, expected_rules) + +- def _prepare_router_data(self, enable_snat=None, num_internal_ports=1): ++ def _prepare_router_data(self, ip_version=4, ++ enable_snat=None, num_internal_ports=1): ++ if ip_version == 4: ++ ip_addr = '19.4.4.4' ++ cidr = '19.4.4.0/24' ++ gateway_ip = '19.4.4.1' ++ elif ip_version == 6: ++ ip_addr = 'fd00::4' ++ cidr = 'fd00::/64' ++ gateway_ip = 'fd00::1' ++ + router_id = _uuid() + ex_gw_port = {'id': _uuid(), + 'network_id': _uuid(), +- 'fixed_ips': [{'ip_address': '19.4.4.4', ++ 'fixed_ips': [{'ip_address': ip_addr, + 'subnet_id': _uuid()}], +- 'subnet': {'cidr': '19.4.4.0/24', +- 'gateway_ip': '19.4.4.1'}} ++ 'subnet': {'cidr': cidr, ++ 'gateway_ip': gateway_ip}} + int_ports = [] + for i in range(num_internal_ports): + int_ports.append({'id': _uuid(), +@@ -635,6 +649,99 @@ class TestBasicRouterOperations(base.BaseTestCase): + self._verify_snat_rules(nat_rules_delta, router) + self.send_arp.assert_called_once() + ++ def test_process_ipv6_only_gw(self): ++ agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) ++ router = self._prepare_router_data(ip_version=6) ++ # Get NAT rules without the gw_port ++ gw_port = router['gw_port'] ++ router['gw_port'] = None ++ ri = l3_agent.RouterInfo(router['id'], self.conf.root_helper, ++ self.conf.use_namespaces, router=router) ++ agent.external_gateway_added = mock.Mock() ++ agent.process_router(ri) ++ orig_nat_rules = ri.iptables_manager.ipv4['nat'].rules[:] ++ ++ # Get NAT rules with the gw_port ++ router['gw_port'] = gw_port ++ ri = l3_agent.RouterInfo(router['id'], self.conf.root_helper, ++ self.conf.use_namespaces, router=router) ++ with mock.patch.object( ++ agent, ++ 'external_gateway_nat_rules') as external_gateway_nat_rules: ++ agent.process_router(ri) ++ new_nat_rules = ri.iptables_manager.ipv4['nat'].rules[:] ++ ++ # There should be no change with the NAT rules ++ self.assertFalse(external_gateway_nat_rules.called) ++ self.assertEqual(orig_nat_rules, new_nat_rules) ++ ++ def test_process_router_ipv6_interface_added(self): ++ agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) ++ router = self._prepare_router_data() ++ ri = l3_agent.RouterInfo(router['id'], self.conf.root_helper, ++ self.conf.use_namespaces, router=router) ++ agent.external_gateway_added = mock.Mock() ++ # Process with NAT ++ agent.process_router(ri) ++ orig_nat_rules = ri.iptables_manager.ipv4['nat'].rules[:] ++ # Add an IPv6 interface and reprocess ++ router[l3_constants.INTERFACE_KEY].append( ++ {'id': _uuid(), ++ 'network_id': _uuid(), ++ 'admin_state_up': True, ++ 'fixed_ips': [{'ip_address': 'fd00::2', ++ 'subnet_id': _uuid()}], ++ 'mac_address': 'ca:fe:de:ad:be:ef', ++ 'subnet': {'cidr': 'fd00::/64', ++ 'gateway_ip': 'fd00::1'}}) ++ # Reassign the router object to RouterInfo ++ ri.router = router ++ agent.process_router(ri) ++ # For some reason set logic does not work well with ++ # IpTablesRule instances ++ nat_rules_delta = [r for r in ri.iptables_manager.ipv4['nat'].rules ++ if r not in orig_nat_rules] ++ self.assertFalse(nat_rules_delta) ++ ++ def test_process_router_ipv6v4_interface_added(self): ++ agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) ++ router = self._prepare_router_data() ++ ri = l3_agent.RouterInfo(router['id'], self.conf.root_helper, ++ self.conf.use_namespaces, router=router) ++ agent.external_gateway_added = mock.Mock() ++ # Process with NAT ++ agent.process_router(ri) ++ orig_nat_rules = ri.iptables_manager.ipv4['nat'].rules[:] ++ # Add an IPv4 and IPv6 interface and reprocess ++ router[l3_constants.INTERFACE_KEY].append( ++ {'id': _uuid(), ++ 'network_id': _uuid(), ++ 'admin_state_up': True, ++ 'fixed_ips': [{'ip_address': '35.4.1.4', ++ 'subnet_id': _uuid()}], ++ 'mac_address': 'ca:fe:de:ad:be:ef', ++ 'subnet': {'cidr': '35.4.1.0/24', ++ 'gateway_ip': '35.4.1.1'}}) ++ ++ router[l3_constants.INTERFACE_KEY].append( ++ {'id': _uuid(), ++ 'network_id': _uuid(), ++ 'admin_state_up': True, ++ 'fixed_ips': [{'ip_address': 'fd00::2', ++ 'subnet_id': _uuid()}], ++ 'mac_address': 'ca:fe:de:ad:be:ef', ++ 'subnet': {'cidr': 'fd00::/64', ++ 'gateway_ip': 'fd00::1'}}) ++ # Reassign the router object to RouterInfo ++ ri.router = router ++ agent.process_router(ri) ++ # For some reason set logic does not work well with ++ # IpTablesRule instances ++ nat_rules_delta = [r for r in ri.iptables_manager.ipv4['nat'].rules ++ if r not in orig_nat_rules] ++ self.assertEqual(1, len(nat_rules_delta)) ++ self._verify_snat_rules(nat_rules_delta, router) ++ + def test_process_router_interface_removed(self): + agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) + router = self._prepare_router_data(num_internal_ports=2) diff --git a/debian/patches/series b/debian/patches/series index ee7bdf346..40d6ae75f 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -4,3 +4,4 @@ OVS_lib_defer_apply_doesn_t_handle_concurrency.patch 0001-Add-parameter-and-iptables-rules-to-protect-dnsmasq-.patch 0004-Fix-Metering-doesn-t-respect-the-l3-agent-binding.patch Properly_apply_column_default_in_migration_pool_monitor_status.patch +Install_SNAT_rules_for_ipv4_only.patch -- 2.45.2