DVR: when updating port's fixed_ips, update arp

Currently, when updating a port's fixed_ips, the l3 agents fail to
update the arp tables of this change, which can lead to east-west
connectivity issues when a router is connected to more than one tenant
network.

Closes-Bug: #1512199
Change-Id: Ic7a4bbfca8b477c41b233235d2e2a2864f7af411
This commit is contained in:
John Schwarz 2016-01-05 17:21:30 +02:00 committed by Brian Haley
parent 6576b7061e
commit 5535a71e75
3 changed files with 43 additions and 25 deletions

View File

@ -684,6 +684,24 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
self._populate_subnets_for_ports(context, port_list)
return port_list
def _generate_arp_table_and_notify_agent(
self, context, fixed_ip, mac_address, notifier):
"""Generates the arp table entry and notifies the l3 agent."""
ip_address = fixed_ip['ip_address']
subnet = fixed_ip['subnet_id']
filters = {'fixed_ips': {'subnet_id': [subnet]}}
ports = self._core_plugin.get_ports(context, filters=filters)
for port in ports:
if port['device_owner'] == l3_const.DEVICE_OWNER_DVR_INTERFACE:
router_id = port['device_id']
router_dict = self._get_router(context, router_id)
if router_dict.extra_attributes.distributed:
arp_table = {'ip_address': ip_address,
'mac_address': mac_address,
'subnet_id': subnet}
notifier(context, router_id, arp_table)
return
def update_arp_entry_for_dvr_service_port(
self, context, port_dict, action):
"""Notify L3 agents of ARP table entry for dvr service port.
@ -697,24 +715,17 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
if not (n_utils.is_dvr_serviced(port_dict['device_owner']) and
port_dict['fixed_ips']):
return
ip_address = port_dict['fixed_ips'][0]['ip_address']
subnet = port_dict['fixed_ips'][0]['subnet_id']
filters = {'fixed_ips': {'subnet_id': [subnet]}}
ports = self._core_plugin.get_ports(context, filters=filters)
for port in ports:
if port['device_owner'] == l3_const.DEVICE_OWNER_DVR_INTERFACE:
router_id = port['device_id']
router_dict = self._get_router(context, router_id)
if router_dict.extra_attributes.distributed:
arp_table = {'ip_address': ip_address,
'mac_address': port_dict['mac_address'],
'subnet_id': subnet}
if action == "add":
notify_action = self.l3_rpc_notifier.add_arp_entry
elif action == "del":
notify_action = self.l3_rpc_notifier.del_arp_entry
notify_action(context, router_id, arp_table)
return
changed_fixed_ips = port_dict['fixed_ips']
for fixed_ip in changed_fixed_ips:
if action == "add":
notifier = self.l3_rpc_notifier.add_arp_entry
elif action == "del":
notifier = self.l3_rpc_notifier.del_arp_entry
else:
return
self._generate_arp_table_and_notify_agent(
context, fixed_ip, port_dict['mac_address'], notifier)
def delete_csnat_router_interface_ports(self, context,
router, subnet_id=None):

View File

@ -496,6 +496,10 @@ def _notify_l3_agent_port_update(resource, event, trigger, **kwargs):
event, resource, trigger, **removed_router_args)
if not n_utils.is_dvr_serviced(new_device_owner):
return
is_fixed_ips_changed = (
'fixed_ips' in new_port and
'fixed_ips' in original_port and
new_port['fixed_ips'] != original_port['fixed_ips'])
is_new_port_binding_changed = (
new_port[portbindings.HOST_ID] and
(original_port[portbindings.HOST_ID] !=
@ -505,7 +509,7 @@ def _notify_l3_agent_port_update(resource, event, trigger, **kwargs):
l3plugin.dvr_handle_new_service_port(context, new_port)
l3plugin.update_arp_entry_for_dvr_service_port(
context, new_port, "add")
elif kwargs.get('mac_address_updated'):
elif kwargs.get('mac_address_updated') or is_fixed_ips_changed:
l3plugin.update_arp_entry_for_dvr_service_port(
context, new_port, "add")

View File

@ -593,10 +593,13 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
gp.return_value = plugin
port = {
'id': 'my_port_id',
'fixed_ips': [{
'ip_address': 'my_ip',
'subnet_id': 'my_subnet_id',
}],
'fixed_ips': [
{'subnet_id': '51edc9e0-24f9-47f2-8e1e-2a41cb691323',
'ip_address': '10.0.0.11'},
{'subnet_id': '2b7c8a07-6f8e-4937-8701-f1d5da1a807c',
'ip_address': '10.0.0.21'},
{'subnet_id': '48534187-f077-4e81-93ff-81ec4cc0ad3b',
'ip_address': 'fd45:1515:7e0:0:f816:3eff:fe1a:1111'}],
'mac_address': 'my_mac',
'device_owner': device_owner
}
@ -612,9 +615,9 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
self.mixin.update_arp_entry_for_dvr_service_port(
self.ctx, port, action)
if action == 'add':
self.assertTrue(l3_notify.add_arp_entry.called)
self.assertEqual(3, l3_notify.add_arp_entry.call_count)
elif action == 'del':
self.assertTrue(l3_notify.del_arp_entry.called)
self.assertTrue(3, l3_notify.del_arp_entry.call_count)
def test_update_arp_entry_for_dvr_service_port_added(self):
action = 'add'