Merge "Configure floating IPs addresses after NAT rules"

This commit is contained in:
Jenkins 2014-02-06 07:05:54 +00:00 committed by Gerrit Code Review
commit 44649bd7c9
2 changed files with 91 additions and 32 deletions

View File

@ -428,14 +428,18 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, manager.Manager):
ri.perform_snat_action(self._handle_router_snat_rules, ri.perform_snat_action(self._handle_router_snat_rules,
internal_cidrs, interface_name) internal_cidrs, interface_name)
# Process DNAT rules for floating IPs # Process SNAT/DNAT rules for floating IPs
if ex_gw_port: if ex_gw_port:
self.process_router_floating_ips(ri, ex_gw_port) self.process_router_floating_ip_nat_rules(ri)
ri.ex_gw_port = ex_gw_port ri.ex_gw_port = ex_gw_port
ri.enable_snat = ri.router.get('enable_snat') ri.enable_snat = ri.router.get('enable_snat')
self.routes_updated(ri) self.routes_updated(ri)
ri.iptables_manager.defer_apply_off() ri.iptables_manager.defer_apply_off()
# Once NAT rules for floating IPs are safely in place
# configure their addresses on the external gateway port
if ex_gw_port:
self.process_router_floating_ip_addresses(ri, ex_gw_port)
def _handle_router_snat_rules(self, ri, ex_gw_port, internal_cidrs, def _handle_router_snat_rules(self, ri, ex_gw_port, internal_cidrs,
interface_name, action): interface_name, action):
@ -459,19 +463,34 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, manager.Manager):
ri.iptables_manager.ipv4['nat'].add_rule(*rule) ri.iptables_manager.ipv4['nat'].add_rule(*rule)
ri.iptables_manager.apply() ri.iptables_manager.apply()
def process_router_floating_ips(self, ri, ex_gw_port): def process_router_floating_ip_nat_rules(self, ri):
"""Configure the router's floating IPs """Configure NAT rules for the router's floating IPs.
Configures floating ips in iptables and on the router's gateway device.
Cleans up floating ips that should not longer be configured. Configures iptables rules for the floating ips of the given router
"""
# Clear out all iptables rules for floating ips
ri.iptables_manager.ipv4['nat'].clear_rules_by_tag('floating_ip')
# Loop once to ensure that floating ips are configured.
for fip in ri.router.get(l3_constants.FLOATINGIP_KEY, []):
# Rebuild iptables rules for the floating ip.
fixed = fip['fixed_ip_address']
fip_ip = fip['floating_ip_address']
for chain, rule in self.floating_forward_rules(fip_ip, fixed):
ri.iptables_manager.ipv4['nat'].add_rule(chain, rule,
tag='floating_ip')
ri.iptables_manager.apply()
def process_router_floating_ip_addresses(self, ri, ex_gw_port):
"""Configure IP addresses on router's external gateway interface.
Ensures addresses for existing floating IPs and cleans up
those that should not longer be configured.
""" """
interface_name = self.get_external_device_name(ex_gw_port['id']) interface_name = self.get_external_device_name(ex_gw_port['id'])
device = ip_lib.IPDevice(interface_name, self.root_helper, device = ip_lib.IPDevice(interface_name, self.root_helper,
namespace=ri.ns_name()) namespace=ri.ns_name())
# Clear out all iptables rules for floating ips
ri.iptables_manager.ipv4['nat'].clear_rules_by_tag('floating_ip')
existing_cidrs = set([addr['cidr'] for addr in device.addr.list()]) existing_cidrs = set([addr['cidr'] for addr in device.addr.list()])
new_cidrs = set() new_cidrs = set()
@ -487,14 +506,6 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, manager.Manager):
device.addr.add(net.version, ip_cidr, str(net.broadcast)) device.addr.add(net.version, ip_cidr, str(net.broadcast))
self._send_gratuitous_arp_packet(ri, interface_name, fip_ip) self._send_gratuitous_arp_packet(ri, interface_name, fip_ip)
# Rebuild iptables rules for the floating ip.
fixed = fip['fixed_ip_address']
for chain, rule in self.floating_forward_rules(fip_ip, fixed):
ri.iptables_manager.ipv4['nat'].add_rule(chain, rule,
tag='floating_ip')
ri.iptables_manager.apply()
# Clean up addresses that no longer belong on the gateway interface. # Clean up addresses that no longer belong on the gateway interface.
for ip_cidr in existing_cidrs - new_cidrs: for ip_cidr in existing_cidrs - new_cidrs:
if ip_cidr.endswith(FLOATING_IP_CIDR_SUFFIX): if ip_cidr.endswith(FLOATING_IP_CIDR_SUFFIX):

View File

@ -382,7 +382,8 @@ class TestBasicRouterOperations(base.BaseTestCase):
def test_process_router(self): def test_process_router(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.process_router_floating_ips = mock.Mock() agent.process_router_floating_ip_addresses = mock.Mock()
agent.process_router_floating_ip_nat_rules = mock.Mock()
router = self._prepare_router_data() router = self._prepare_router_data()
fake_floatingips1 = {'floatingips': [ fake_floatingips1 = {'floatingips': [
{'id': _uuid(), {'id': _uuid(),
@ -393,8 +394,11 @@ class TestBasicRouterOperations(base.BaseTestCase):
self.conf.use_namespaces, router=router) self.conf.use_namespaces, router=router)
agent.process_router(ri) agent.process_router(ri)
ex_gw_port = agent._get_ex_gw_port(ri) ex_gw_port = agent._get_ex_gw_port(ri)
agent.process_router_floating_ips.assert_called_with(ri, ex_gw_port) agent.process_router_floating_ip_addresses.assert_called_with(
agent.process_router_floating_ips.reset_mock() ri, ex_gw_port)
agent.process_router_floating_ip_addresses.reset_mock()
agent.process_router_floating_ip_nat_rules.assert_called_with(ri)
agent.process_router_floating_ip_nat_rules.reset_mock()
# remap floating IP to a new fixed ip # remap floating IP to a new fixed ip
fake_floatingips2 = copy.deepcopy(fake_floatingips1) fake_floatingips2 = copy.deepcopy(fake_floatingips1)
@ -403,25 +407,32 @@ class TestBasicRouterOperations(base.BaseTestCase):
router[l3_constants.FLOATINGIP_KEY] = fake_floatingips2['floatingips'] router[l3_constants.FLOATINGIP_KEY] = fake_floatingips2['floatingips']
agent.process_router(ri) agent.process_router(ri)
ex_gw_port = agent._get_ex_gw_port(ri) ex_gw_port = agent._get_ex_gw_port(ri)
agent.process_router_floating_ips.assert_called_with(ri, ex_gw_port) agent.process_router_floating_ip_addresses.assert_called_with(
agent.process_router_floating_ips.reset_mock() ri, ex_gw_port)
agent.process_router_floating_ip_addresses.reset_mock()
agent.process_router_floating_ip_nat_rules.assert_called_with(ri)
agent.process_router_floating_ip_nat_rules.reset_mock()
# remove just the floating ips # remove just the floating ips
del router[l3_constants.FLOATINGIP_KEY] del router[l3_constants.FLOATINGIP_KEY]
agent.process_router(ri) agent.process_router(ri)
ex_gw_port = agent._get_ex_gw_port(ri) ex_gw_port = agent._get_ex_gw_port(ri)
agent.process_router_floating_ips.assert_called_with(ri, ex_gw_port) agent.process_router_floating_ip_addresses.assert_called_with(
agent.process_router_floating_ips.reset_mock() ri, ex_gw_port)
agent.process_router_floating_ip_addresses.reset_mock()
agent.process_router_floating_ip_nat_rules.assert_called_with(ri)
agent.process_router_floating_ip_nat_rules.reset_mock()
# now no ports so state is torn down # now no ports so state is torn down
del router[l3_constants.INTERFACE_KEY] del router[l3_constants.INTERFACE_KEY]
del router['gw_port'] del router['gw_port']
agent.process_router(ri) agent.process_router(ri)
self.send_arp.assert_called_once() self.send_arp.assert_called_once()
self.assertFalse(agent.process_router_floating_ips.called) self.assertFalse(agent.process_router_floating_ip_addresses.called)
self.assertFalse(agent.process_router_floating_ip_nat_rules.called)
@mock.patch('neutron.agent.linux.ip_lib.IPDevice') @mock.patch('neutron.agent.linux.ip_lib.IPDevice')
def test_process_router_floating_ip_add(self, IPDevice): def test_process_router_floating_ip_addresses_add(self, IPDevice):
fip = { fip = {
'id': _uuid(), 'port_id': _uuid(), 'id': _uuid(), 'port_id': _uuid(),
'floating_ip_address': '15.1.2.3', 'floating_ip_address': '15.1.2.3',
@ -436,10 +447,24 @@ class TestBasicRouterOperations(base.BaseTestCase):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.process_router_floating_ips(ri, {'id': _uuid()}) agent.process_router_floating_ip_addresses(ri, {'id': _uuid()})
device.addr.add.assert_called_once_with(4, '15.1.2.3/32', '15.1.2.3') device.addr.add.assert_called_once_with(4, '15.1.2.3/32', '15.1.2.3')
def test_process_router_floating_ip_nat_rules_add(self):
fip = {
'id': _uuid(), 'port_id': _uuid(),
'floating_ip_address': '15.1.2.3',
'fixed_ip_address': '192.168.0.1'
}
ri = mock.MagicMock()
ri.router.get.return_value = [fip]
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.process_router_floating_ip_nat_rules(ri)
nat = ri.iptables_manager.ipv4['nat'] nat = ri.iptables_manager.ipv4['nat']
nat.clear_rules_by_tag.assert_called_once_with('floating_ip') nat.clear_rules_by_tag.assert_called_once_with('floating_ip')
rules = agent.floating_forward_rules('15.1.2.3', '192.168.0.1') rules = agent.floating_forward_rules('15.1.2.3', '192.168.0.1')
@ -447,7 +472,7 @@ class TestBasicRouterOperations(base.BaseTestCase):
nat.add_rule.assert_any_call(chain, rule, tag='floating_ip') nat.add_rule.assert_any_call(chain, rule, tag='floating_ip')
@mock.patch('neutron.agent.linux.ip_lib.IPDevice') @mock.patch('neutron.agent.linux.ip_lib.IPDevice')
def test_process_router_floating_ip_remove(self, IPDevice): def test_process_router_floating_ip_addresses_remove(self, IPDevice):
IPDevice.return_value = device = mock.Mock() IPDevice.return_value = device = mock.Mock()
device.addr.list.return_value = [{'cidr': '15.1.2.3/32'}] device.addr.list.return_value = [{'cidr': '15.1.2.3/32'}]
@ -456,16 +481,24 @@ class TestBasicRouterOperations(base.BaseTestCase):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.process_router_floating_ips(ri, {'id': _uuid()}) agent.process_router_floating_ip_addresses(ri, {'id': _uuid()})
device.addr.delete.assert_called_once_with(4, '15.1.2.3/32') device.addr.delete.assert_called_once_with(4, '15.1.2.3/32')
def test_process_router_floating_ip_nat_rules_remove(self):
ri = mock.MagicMock()
ri.router.get.return_value = []
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.process_router_floating_ip_nat_rules(ri)
nat = ri.iptables_manager.ipv4['nat'] nat = ri.iptables_manager.ipv4['nat']
nat = ri.iptables_manager.ipv4['nat'] nat = ri.iptables_manager.ipv4['nat']
nat.clear_rules_by_tag.assert_called_once_with('floating_ip') nat.clear_rules_by_tag.assert_called_once_with('floating_ip')
@mock.patch('neutron.agent.linux.ip_lib.IPDevice') @mock.patch('neutron.agent.linux.ip_lib.IPDevice')
def test_process_router_floating_ip_remap(self, IPDevice): def test_process_router_floating_ip_addresses_remap(self, IPDevice):
fip = { fip = {
'id': _uuid(), 'port_id': _uuid(), 'id': _uuid(), 'port_id': _uuid(),
'floating_ip_address': '15.1.2.3', 'floating_ip_address': '15.1.2.3',
@ -480,11 +513,26 @@ class TestBasicRouterOperations(base.BaseTestCase):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.process_router_floating_ips(ri, {'id': _uuid()}) agent.process_router_floating_ip_addresses(ri, {'id': _uuid()})
self.assertFalse(device.addr.add.called) self.assertFalse(device.addr.add.called)
self.assertFalse(device.addr.delete.called) self.assertFalse(device.addr.delete.called)
def test_process_router_floating_ip_nat_rules_remap(self):
fip = {
'id': _uuid(), 'port_id': _uuid(),
'floating_ip_address': '15.1.2.3',
'fixed_ip_address': '192.168.0.2'
}
ri = mock.MagicMock()
ri.router.get.return_value = [fip]
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.process_router_floating_ip_nat_rules(ri)
nat = ri.iptables_manager.ipv4['nat'] nat = ri.iptables_manager.ipv4['nat']
nat.clear_rules_by_tag.assert_called_once_with('floating_ip') nat.clear_rules_by_tag.assert_called_once_with('floating_ip')
rules = agent.floating_forward_rules('15.1.2.3', '192.168.0.2') rules = agent.floating_forward_rules('15.1.2.3', '192.168.0.2')