Merge "Revert "DVR: Remove control plane arp updates for DVR"" into stable/train

This commit is contained in:
Zuul 2021-03-15 21:37:07 +00:00 committed by Gerrit Code Review
commit 6691b9c5bc
5 changed files with 500 additions and 0 deletions

View File

@ -13,6 +13,7 @@
# under the License. # under the License.
import collections import collections
import netaddr
from neutron_lib.api.definitions import external_net as extnet_apidef from neutron_lib.api.definitions import external_net as extnet_apidef
from neutron_lib.api.definitions import l3 as l3_apidef from neutron_lib.api.definitions import l3 as l3_apidef
from neutron_lib.api.definitions import portbindings from neutron_lib.api.definitions import portbindings
@ -50,6 +51,7 @@ from neutron.db import models_v2
from neutron.extensions import _admin_state_down_before_update_lib from neutron.extensions import _admin_state_down_before_update_lib
from neutron.ipam import utils as ipam_utils from neutron.ipam import utils as ipam_utils
from neutron.objects import agent as ag_obj from neutron.objects import agent as ag_obj
from neutron.objects import base as base_obj
from neutron.objects import l3agent as rb_obj from neutron.objects import l3agent as rb_obj
from neutron.objects import router as l3_obj from neutron.objects import router as l3_obj
@ -457,6 +459,17 @@ class DVRResourceOperationHandler(object):
fixed_ip_address)) fixed_ip_address))
if not addr_pair_active_service_port_list: if not addr_pair_active_service_port_list:
return return
self._inherit_service_port_and_arp_update(
context, addr_pair_active_service_port_list[0])
def _inherit_service_port_and_arp_update(self, context, service_port):
"""Function inherits port host bindings for allowed_address_pair."""
service_port_dict = self.l3plugin._core_plugin._make_port_dict(
service_port)
address_pair_list = service_port_dict.get('allowed_address_pairs')
for address_pair in address_pair_list:
self.update_arp_entry_for_dvr_service_port(context,
service_port_dict)
@registry.receives(resources.ROUTER_INTERFACE, [events.BEFORE_CREATE]) @registry.receives(resources.ROUTER_INTERFACE, [events.BEFORE_CREATE])
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
@ -1079,6 +1092,21 @@ class _DVRAgentInterfaceMixin(object):
self._populate_mtu_and_subnets_for_ports(context, [agent_port]) self._populate_mtu_and_subnets_for_ports(context, [agent_port])
return agent_port return agent_port
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']
arp_table = {'ip_address': ip_address,
'mac_address': mac_address,
'subnet_id': subnet}
filters = {'fixed_ips': {'subnet_id': [subnet]},
'device_owner': [const.DEVICE_OWNER_DVR_INTERFACE]}
ports = self._core_plugin.get_ports(context, filters=filters)
routers = [port['device_id'] for port in ports]
for router_id in routers:
notifier(context, router_id, arp_table)
def _get_subnet_id_for_given_fixed_ip(self, context, fixed_ip, port_dict): def _get_subnet_id_for_given_fixed_ip(self, context, fixed_ip, port_dict):
"""Returns the subnet_id that matches the fixedip on a network.""" """Returns the subnet_id that matches the fixedip on a network."""
filters = {'network_id': [port_dict['network_id']]} filters = {'network_id': [port_dict['network_id']]}
@ -1087,6 +1115,78 @@ class _DVRAgentInterfaceMixin(object):
if ipam_utils.check_subnet_ip(subnet['cidr'], fixed_ip): if ipam_utils.check_subnet_ip(subnet['cidr'], fixed_ip):
return subnet['id'] return subnet['id']
def _get_allowed_address_pair_fixed_ips(self, context, port_dict):
"""Returns all fixed_ips associated with the allowed_address_pair."""
aa_pair_fixed_ips = []
if port_dict.get('allowed_address_pairs'):
for address_pair in port_dict['allowed_address_pairs']:
aap_ip_cidr = address_pair['ip_address'].split("/")
if len(aap_ip_cidr) == 1 or int(aap_ip_cidr[1]) == 32:
subnet_id = self._get_subnet_id_for_given_fixed_ip(
context, aap_ip_cidr[0], port_dict)
if subnet_id is not None:
fixed_ip = {'subnet_id': subnet_id,
'ip_address': aap_ip_cidr[0]}
aa_pair_fixed_ips.append(fixed_ip)
else:
LOG.debug("Subnet does not match for the given "
"fixed_ip %s for arp update", aap_ip_cidr[0])
return aa_pair_fixed_ips
def update_arp_entry_for_dvr_service_port(self, context, port_dict):
"""Notify L3 agents of ARP table entry for dvr service port.
When a dvr service port goes up, look for the DVR router on
the port's subnet, and send the ARP details to all
L3 agents hosting the router to add it.
If there are any allowed_address_pairs associated with the port
those fixed_ips should also be updated in the ARP table.
"""
fixed_ips = port_dict['fixed_ips']
if not fixed_ips:
return
allowed_address_pair_fixed_ips = (
self._get_allowed_address_pair_fixed_ips(context, port_dict))
changed_fixed_ips = fixed_ips + allowed_address_pair_fixed_ips
for fixed_ip in changed_fixed_ips:
self._generate_arp_table_and_notify_agent(
context, fixed_ip, port_dict['mac_address'],
self.l3_rpc_notifier.add_arp_entry)
def delete_arp_entry_for_dvr_service_port(self, context, port_dict,
fixed_ips_to_delete=None):
"""Notify L3 agents of ARP table entry for dvr service port.
When a dvr service port goes down, look for the DVR
router on the port's subnet, and send the ARP details to all
L3 agents hosting the router to delete it.
If there are any allowed_address_pairs associated with the
port, those fixed_ips should be removed from the ARP table.
"""
fixed_ips = port_dict['fixed_ips']
if not fixed_ips:
return
if not fixed_ips_to_delete:
allowed_address_pair_fixed_ips = (
self._get_allowed_address_pair_fixed_ips(context, port_dict))
fixed_ips_to_delete = fixed_ips + allowed_address_pair_fixed_ips
for fixed_ip in fixed_ips_to_delete:
self._generate_arp_table_and_notify_agent(
context, fixed_ip, port_dict['mac_address'],
self.l3_rpc_notifier.del_arp_entry)
def _get_address_pair_active_port_with_fip(
self, context, port_dict, port_addr_pair_ip):
port_valid_state = (port_dict['admin_state_up'] or
port_dict['status'] == const.PORT_STATUS_ACTIVE)
if not port_valid_state:
return
fips = l3_obj.FloatingIP.get_objects(
context, _pager=base_obj.Pager(limit=1),
fixed_ip_address=netaddr.IPAddress(port_addr_pair_ip))
return self._core_plugin.get_port(
context, fips[0].fixed_port_id) if fips else None
class L3_NAT_with_dvr_db_mixin(_DVRAgentInterfaceMixin, class L3_NAT_with_dvr_db_mixin(_DVRAgentInterfaceMixin,
DVRResourceOperationHandler, DVRResourceOperationHandler,

View File

@ -518,6 +518,19 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin):
return any([r in dvr_routers for r in related_routers]) return any([r in dvr_routers for r in related_routers])
def _dvr_handle_unbound_allowed_addr_pair_add(
plugin, context, port, allowed_address_pair):
plugin.update_arp_entry_for_dvr_service_port(context, port)
def _dvr_handle_unbound_allowed_addr_pair_del(
plugin, context, port, allowed_address_pair):
aa_fixed_ips = plugin._get_allowed_address_pair_fixed_ips(context, port)
if aa_fixed_ips:
plugin.delete_arp_entry_for_dvr_service_port(
context, port, fixed_ips_to_delete=aa_fixed_ips)
def _notify_l3_agent_new_port(resource, event, trigger, **kwargs): def _notify_l3_agent_new_port(resource, event, trigger, **kwargs):
LOG.debug('Received %(resource)s %(event)s', { LOG.debug('Received %(resource)s %(event)s', {
'resource': resource, 'resource': resource,
@ -530,6 +543,7 @@ def _notify_l3_agent_new_port(resource, event, trigger, **kwargs):
l3plugin = directory.get_plugin(plugin_constants.L3) l3plugin = directory.get_plugin(plugin_constants.L3)
context = kwargs['context'] context = kwargs['context']
l3plugin.dvr_handle_new_service_port(context, port) l3plugin.dvr_handle_new_service_port(context, port)
l3plugin.update_arp_entry_for_dvr_service_port(context, port)
def _notify_port_delete(event, resource, trigger, **kwargs): def _notify_port_delete(event, resource, trigger, **kwargs):
@ -537,6 +551,14 @@ def _notify_port_delete(event, resource, trigger, **kwargs):
port = kwargs['port'] port = kwargs['port']
get_related_hosts_info = kwargs.get("get_related_hosts_info", True) get_related_hosts_info = kwargs.get("get_related_hosts_info", True)
l3plugin = directory.get_plugin(plugin_constants.L3) l3plugin = directory.get_plugin(plugin_constants.L3)
if port:
port_host = port.get(portbindings.HOST_ID)
allowed_address_pairs_list = port.get('allowed_address_pairs')
if allowed_address_pairs_list and port_host:
for address_pair in allowed_address_pairs_list:
_dvr_handle_unbound_allowed_addr_pair_del(
l3plugin, context, port, address_pair)
l3plugin.delete_arp_entry_for_dvr_service_port(context, port)
removed_routers = l3plugin.get_dvr_routers_to_remove( removed_routers = l3plugin.get_dvr_routers_to_remove(
context, port, get_related_hosts_info) context, port, get_related_hosts_info)
for info in removed_routers: for info in removed_routers:
@ -625,7 +647,32 @@ def _notify_l3_agent_port_update(resource, event, trigger, **kwargs):
context, new_port, context, new_port,
dest_host=dest_host, dest_host=dest_host,
router_id=fip_router_id) router_id=fip_router_id)
l3plugin.update_arp_entry_for_dvr_service_port(
context, new_port)
return return
# Check for allowed_address_pairs and port state
new_port_host = new_port.get(portbindings.HOST_ID)
allowed_address_pairs_list = new_port.get('allowed_address_pairs')
if allowed_address_pairs_list and new_port_host:
new_port_state = new_port.get('admin_state_up')
original_port_state = original_port.get('admin_state_up')
if new_port_state:
# Case were we activate the port from inactive state,
# or the same port has additional address_pairs added.
for address_pair in allowed_address_pairs_list:
_dvr_handle_unbound_allowed_addr_pair_add(
l3plugin, context, new_port, address_pair)
return
elif original_port_state:
# Case were we deactivate the port from active state.
for address_pair in allowed_address_pairs_list:
_dvr_handle_unbound_allowed_addr_pair_del(
l3plugin, context, original_port, address_pair)
return
if kwargs.get('mac_address_updated') or is_fixed_ips_changed:
l3plugin.update_arp_entry_for_dvr_service_port(
context, new_port)
def subscribe(): def subscribe():

View File

@ -1024,6 +1024,145 @@ class L3DvrTestCase(L3DvrTestCaseBase):
floatingips = router_sync_info[0][constants.FLOATINGIP_KEY] floatingips = router_sync_info[0][constants.FLOATINGIP_KEY]
self.assertTrue(floatingips[0][constants.DVR_SNAT_BOUND]) self.assertTrue(floatingips[0][constants.DVR_SNAT_BOUND])
def test_allowed_addr_pairs_delayed_fip_and_update_arp_entry(self):
HOST1 = 'host1'
helpers.register_l3_agent(
host=HOST1, agent_mode=constants.L3_AGENT_MODE_DVR)
HOST2 = 'host2'
helpers.register_l3_agent(
host=HOST2, agent_mode=constants.L3_AGENT_MODE_DVR)
router = self._create_router(ha=False)
private_net1 = self._make_network(self.fmt, 'net1', True)
test_allocation_pools = [{'start': '10.1.0.2',
'end': '10.1.0.20'}]
fixed_vrrp_ip = [{'ip_address': '10.1.0.201'}]
kwargs = {'arg_list': (extnet_apidef.EXTERNAL,),
extnet_apidef.EXTERNAL: True}
ext_net = self._make_network(self.fmt, '', True, **kwargs)
self._make_subnet(
self.fmt, ext_net, '10.20.0.1', '10.20.0.0/24',
ip_version=constants.IP_VERSION_4, enable_dhcp=True)
self.l3_plugin.schedule_router(self.context,
router['id'],
candidates=[self.l3_agent])
# Set gateway to router
self.l3_plugin._update_router_gw_info(
self.context, router['id'],
{'network_id': ext_net['network']['id']})
private_subnet1 = self._make_subnet(
self.fmt,
private_net1,
'10.1.0.1',
cidr='10.1.0.0/24',
ip_version=constants.IP_VERSION_4,
allocation_pools=test_allocation_pools,
enable_dhcp=True)
vrrp_port = self._make_port(
self.fmt,
private_net1['network']['id'],
fixed_ips=fixed_vrrp_ip)
allowed_address_pairs = [
{'ip_address': '10.1.0.201',
'mac_address': vrrp_port['port']['mac_address']}]
with self.port(
subnet=private_subnet1,
device_owner=DEVICE_OWNER_COMPUTE) as int_port,\
self.port(subnet=private_subnet1,
device_owner=DEVICE_OWNER_COMPUTE) as int_port2:
self.l3_plugin.add_router_interface(
self.context, router['id'],
{'subnet_id': private_subnet1['subnet']['id']})
router_handle = (
self.l3_plugin.list_active_sync_routers_on_active_l3_agent(
self.context, self.l3_agent['host'], [router['id']]))
self.assertEqual(self.l3_agent['host'],
router_handle[0]['gw_port_host'])
with mock.patch.object(self.l3_plugin,
'_l3_rpc_notifier') as l3_notifier:
vm_port = self.core_plugin.update_port(
self.context, int_port['port']['id'],
{'port': {portbindings.HOST_ID: HOST1}})
vm_port_mac = vm_port['mac_address']
vm_port_fixed_ips = vm_port['fixed_ips']
vm_port_subnet_id = vm_port_fixed_ips[0]['subnet_id']
vm_arp_table = {
'ip_address': vm_port_fixed_ips[0]['ip_address'],
'mac_address': vm_port_mac,
'subnet_id': vm_port_subnet_id}
vm_port2 = self.core_plugin.update_port(
self.context, int_port2['port']['id'],
{'port': {portbindings.HOST_ID: HOST2}})
# Now update the VM port with the allowed_address_pair
self.core_plugin.update_port(
self.context, vm_port['id'],
{'port': {
'allowed_address_pairs': allowed_address_pairs}})
self.core_plugin.update_port(
self.context, vm_port2['id'],
{'port': {
'allowed_address_pairs': allowed_address_pairs}})
self.assertEqual(
2, l3_notifier.routers_updated_on_host.call_count)
updated_vm_port1 = self.core_plugin.get_port(
self.context, vm_port['id'])
updated_vm_port2 = self.core_plugin.get_port(
self.context, vm_port2['id'])
expected_allowed_address_pairs = updated_vm_port1.get(
'allowed_address_pairs')
self.assertEqual(expected_allowed_address_pairs,
allowed_address_pairs)
expected_allowed_address_pairs_2 = updated_vm_port2.get(
'allowed_address_pairs')
self.assertEqual(expected_allowed_address_pairs_2,
allowed_address_pairs)
# Now the VRRP port is attached to the VM port. At this
# point, the VRRP port should not have inherited the
# port host bindings from the parent VM port.
cur_vrrp_port_db = self.core_plugin.get_port(
self.context, vrrp_port['port']['id'])
self.assertNotEqual(
cur_vrrp_port_db[portbindings.HOST_ID], HOST1)
self.assertNotEqual(
cur_vrrp_port_db[portbindings.HOST_ID], HOST2)
# Next we can try to associate the floatingip to the
# VRRP port that is already attached to the VM port
floating_ip = {'floating_network_id': ext_net['network']['id'],
'router_id': router['id'],
'port_id': vrrp_port['port']['id'],
'tenant_id': vrrp_port['port']['tenant_id']}
floating_ip = self.l3_plugin.create_floatingip(
self.context, {'floatingip': floating_ip})
post_update_vrrp_port_db = self.core_plugin.get_port(
self.context, vrrp_port['port']['id'])
vrrp_port_fixed_ips = post_update_vrrp_port_db['fixed_ips']
vrrp_port_subnet_id = vrrp_port_fixed_ips[0]['subnet_id']
vrrp_arp_table1 = {
'ip_address': vrrp_port_fixed_ips[0]['ip_address'],
'mac_address': vm_port_mac,
'subnet_id': vrrp_port_subnet_id}
expected_calls = [
mock.call(self.context,
router['id'], vm_arp_table),
mock.call(self.context,
router['id'], vrrp_arp_table1)]
l3_notifier.add_arp_entry.assert_has_calls(
expected_calls)
expected_routers_updated_calls = [
mock.call(self.context, mock.ANY, HOST1),
mock.call(self.context, mock.ANY, HOST2),
mock.call(self.context, mock.ANY, 'host0')]
l3_notifier.routers_updated_on_host.assert_has_calls(
expected_routers_updated_calls, any_order=True)
self.assertFalse(l3_notifier.routers_updated.called)
router_info = (
self.l3_plugin.list_active_sync_routers_on_active_l3_agent(
self.context, self.l3_agent['host'], [router['id']]))
floatingips = router_info[0][constants.FLOATINGIP_KEY]
self.assertTrue(floatingips[0][constants.DVR_SNAT_BOUND])
def test_dvr_gateway_host_binding_is_set(self): def test_dvr_gateway_host_binding_is_set(self):
router = self._create_router(ha=False) router = self._create_router(ha=False)
private_net1 = self._make_network(self.fmt, 'net1', True) private_net1 = self._make_network(self.fmt, 'net1', True)
@ -1058,6 +1197,110 @@ class L3DvrTestCase(L3DvrTestCaseBase):
self.assertEqual(self.l3_agent['host'], self.assertEqual(self.l3_agent['host'],
router_handle[0]['gw_port_host']) router_handle[0]['gw_port_host'])
def test_allowed_address_pairs_update_arp_entry(self):
HOST1 = 'host1'
helpers.register_l3_agent(
host=HOST1, agent_mode=constants.L3_AGENT_MODE_DVR)
router = self._create_router(ha=False)
private_net1 = self._make_network(self.fmt, 'net1', True)
test_allocation_pools = [{'start': '10.1.0.2',
'end': '10.1.0.20'}]
fixed_vrrp_ip = [{'ip_address': '10.1.0.201'}]
kwargs = {'arg_list': (extnet_apidef.EXTERNAL,),
extnet_apidef.EXTERNAL: True}
ext_net = self._make_network(self.fmt, '', True, **kwargs)
self._make_subnet(
self.fmt, ext_net, '10.20.0.1', '10.20.0.0/24',
ip_version=constants.IP_VERSION_4, enable_dhcp=True)
self.l3_plugin.schedule_router(self.context,
router['id'],
candidates=[self.l3_agent])
# Set gateway to router
self.l3_plugin._update_router_gw_info(
self.context, router['id'],
{'network_id': ext_net['network']['id']})
private_subnet1 = self._make_subnet(
self.fmt,
private_net1,
'10.1.0.1',
cidr='10.1.0.0/24',
ip_version=constants.IP_VERSION_4,
allocation_pools=test_allocation_pools,
enable_dhcp=True)
vrrp_port = self._make_port(
self.fmt,
private_net1['network']['id'],
fixed_ips=fixed_vrrp_ip)
allowed_address_pairs = [
{'ip_address': '10.1.0.201',
'mac_address': vrrp_port['port']['mac_address']}]
with self.port(
subnet=private_subnet1,
device_owner=DEVICE_OWNER_COMPUTE) as int_port:
self.l3_plugin.add_router_interface(
self.context, router['id'],
{'subnet_id': private_subnet1['subnet']['id']})
router_handle = (
self.l3_plugin.list_active_sync_routers_on_active_l3_agent(
self.context, self.l3_agent['host'], [router['id']]))
self.assertEqual(self.l3_agent['host'],
router_handle[0]['gw_port_host'])
with mock.patch.object(self.l3_plugin,
'_l3_rpc_notifier') as l3_notifier:
vm_port = self.core_plugin.update_port(
self.context, int_port['port']['id'],
{'port': {portbindings.HOST_ID: HOST1}})
vm_port_mac = vm_port['mac_address']
vm_port_fixed_ips = vm_port['fixed_ips']
vm_port_subnet_id = vm_port_fixed_ips[0]['subnet_id']
vm_arp_table = {
'ip_address': vm_port_fixed_ips[0]['ip_address'],
'mac_address': vm_port_mac,
'subnet_id': vm_port_subnet_id}
self.assertEqual(1, l3_notifier.add_arp_entry.call_count)
floating_ip = {'floating_network_id': ext_net['network']['id'],
'router_id': router['id'],
'port_id': vrrp_port['port']['id'],
'tenant_id': vrrp_port['port']['tenant_id']}
floating_ip = self.l3_plugin.create_floatingip(
self.context, {'floatingip': floating_ip})
vrrp_port_db = self.core_plugin.get_port(
self.context, vrrp_port['port']['id'])
self.assertNotEqual(vrrp_port_db[portbindings.HOST_ID], HOST1)
# Now update the VM port with the allowed_address_pair
self.core_plugin.update_port(
self.context, vm_port['id'],
{'port': {
'allowed_address_pairs': allowed_address_pairs}})
updated_vm_port = self.core_plugin.get_port(
self.context, vm_port['id'])
expected_allowed_address_pairs = updated_vm_port.get(
'allowed_address_pairs')
self.assertEqual(expected_allowed_address_pairs,
allowed_address_pairs)
cur_vrrp_port_db = self.core_plugin.get_port(
self.context, vrrp_port['port']['id'])
vrrp_port_fixed_ips = cur_vrrp_port_db['fixed_ips']
vrrp_port_subnet_id = vrrp_port_fixed_ips[0]['subnet_id']
vrrp_arp_table1 = {
'ip_address': vrrp_port_fixed_ips[0]['ip_address'],
'mac_address': vm_port_mac,
'subnet_id': vrrp_port_subnet_id}
expected_calls = [
mock.call(self.context,
router['id'], vm_arp_table),
mock.call(self.context,
router['id'], vrrp_arp_table1)]
l3_notifier.add_arp_entry.assert_has_calls(
expected_calls)
expected_routers_updated_calls = [
mock.call(self.context, mock.ANY, HOST1),
mock.call(self.context, mock.ANY, 'host0')]
l3_notifier.routers_updated_on_host.assert_has_calls(
expected_routers_updated_calls)
self.assertFalse(l3_notifier.routers_updated.called)
def test_update_vm_port_host_router_update(self): def test_update_vm_port_host_router_update(self):
# register l3 agents in dvr mode in addition to existing dvr_snat agent # register l3 agents in dvr mode in addition to existing dvr_snat agent
HOST1 = 'host1' HOST1 = 'host1'

View File

@ -1035,6 +1035,72 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
port=mock.ANY, port=mock.ANY,
interface_info=interface_info) interface_info=interface_info)
def test__generate_arp_table_and_notify_agent(self):
fixed_ip = {
'ip_address': '1.2.3.4',
'subnet_id': _uuid()}
mac_address = "00:11:22:33:44:55"
expected_arp_table = {
'ip_address': fixed_ip['ip_address'],
'subnet_id': fixed_ip['subnet_id'],
'mac_address': mac_address}
notifier = mock.Mock()
ports = [{'id': _uuid(), 'device_id': 'router_1'},
{'id': _uuid(), 'device_id': 'router_2'}]
with mock.patch.object(self.core_plugin, "get_ports",
return_value=ports):
self.mixin._generate_arp_table_and_notify_agent(
self.ctx, fixed_ip, mac_address, notifier)
notifier.assert_has_calls([
mock.call(self.ctx, "router_1", expected_arp_table),
mock.call(self.ctx, "router_2", expected_arp_table)])
def _test_update_arp_entry_for_dvr_service_port(
self, device_owner, action):
router_dict = {'name': 'test_router', 'admin_state_up': True,
'distributed': True}
router = self._create_router(router_dict)
plugin = mock.Mock()
directory.add_plugin(plugin_constants.CORE, plugin)
l3_notify = self.mixin.l3_rpc_notifier = mock.Mock()
port = {
'id': 'my_port_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
}
dvr_port = {
'id': 'dvr_port_id',
'fixed_ips': mock.ANY,
'device_owner': const.DEVICE_OWNER_DVR_INTERFACE,
'device_id': router['id']
}
plugin.get_ports.return_value = [dvr_port]
if action == 'add':
self.mixin.update_arp_entry_for_dvr_service_port(
self.ctx, port)
self.assertEqual(3, l3_notify.add_arp_entry.call_count)
elif action == 'del':
self.mixin.delete_arp_entry_for_dvr_service_port(
self.ctx, port)
self.assertEqual(3, l3_notify.del_arp_entry.call_count)
def test_update_arp_entry_for_dvr_service_port_added(self):
action = 'add'
device_owner = const.DEVICE_OWNER_LOADBALANCER
self._test_update_arp_entry_for_dvr_service_port(device_owner, action)
def test_update_arp_entry_for_dvr_service_port_deleted(self):
action = 'del'
device_owner = const.DEVICE_OWNER_LOADBALANCER
self._test_update_arp_entry_for_dvr_service_port(device_owner, action)
def test_add_router_interface_csnat_ports_failure(self): def test_add_router_interface_csnat_ports_failure(self):
router_dict = {'name': 'test_router', 'admin_state_up': True, router_dict = {'name': 'test_router', 'admin_state_up': True,
'distributed': True} 'distributed': True}

View File

@ -841,12 +841,20 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
'device_owner': DEVICE_OWNER_COMPUTE, 'device_owner': DEVICE_OWNER_COMPUTE,
}, },
} }
port = kwargs.get('original_port')
l3plugin = mock.Mock() l3plugin = mock.Mock()
directory.add_plugin(plugin_constants.L3, l3plugin) directory.add_plugin(plugin_constants.L3, l3plugin)
l3_dvrscheduler_db._notify_l3_agent_port_update( l3_dvrscheduler_db._notify_l3_agent_port_update(
'port', 'after_update', mock.ANY, **kwargs) 'port', 'after_update', mock.ANY, **kwargs)
l3plugin._get_allowed_address_pair_fixed_ips.return_value = ( l3plugin._get_allowed_address_pair_fixed_ips.return_value = (
['10.1.0.21']) ['10.1.0.21'])
self.assertFalse(
l3plugin.update_arp_entry_for_dvr_service_port.called)
l3plugin.delete_arp_entry_for_dvr_service_port.\
assert_called_once_with(
self.adminContext,
port,
fixed_ips_to_delete=mock.ANY)
def test__notify_l3_agent_update_port_with_allowed_address_pairs(self): def test__notify_l3_agent_update_port_with_allowed_address_pairs(self):
port_id = uuidutils.generate_uuid() port_id = uuidutils.generate_uuid()
@ -874,6 +882,8 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
directory.add_plugin(plugin_constants.L3, l3plugin) directory.add_plugin(plugin_constants.L3, l3plugin)
l3_dvrscheduler_db._notify_l3_agent_port_update( l3_dvrscheduler_db._notify_l3_agent_port_update(
'port', 'after_update', mock.ANY, **kwargs) 'port', 'after_update', mock.ANY, **kwargs)
self.assertTrue(
l3plugin.update_arp_entry_for_dvr_service_port.called)
def test__notify_l3_agent_when_unbound_port_migrates_to_bound_host(self): def test__notify_l3_agent_when_unbound_port_migrates_to_bound_host(self):
port_id = 'fake-port' port_id = 'fake-port'
@ -929,6 +939,8 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
directory.add_plugin(plugin_constants.L3, l3plugin) directory.add_plugin(plugin_constants.L3, l3plugin)
l3_dvrscheduler_db._notify_l3_agent_port_update( l3_dvrscheduler_db._notify_l3_agent_port_update(
'port', 'after_update', plugin, **kwargs) 'port', 'after_update', plugin, **kwargs)
self.assertFalse(
l3plugin.update_arp_entry_for_dvr_service_port.called)
self.assertFalse( self.assertFalse(
l3plugin.dvr_handle_new_service_port.called) l3plugin.dvr_handle_new_service_port.called)
self.assertFalse(l3plugin.remove_router_from_l3_agent.called) self.assertFalse(l3plugin.remove_router_from_l3_agent.called)
@ -946,6 +958,9 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
directory.add_plugin(plugin_constants.L3, l3plugin) directory.add_plugin(plugin_constants.L3, l3plugin)
l3_dvrscheduler_db._notify_l3_agent_new_port( l3_dvrscheduler_db._notify_l3_agent_new_port(
'port', 'after_create', mock.ANY, **kwargs) 'port', 'after_create', mock.ANY, **kwargs)
l3plugin.update_arp_entry_for_dvr_service_port.\
assert_called_once_with(
self.adminContext, kwargs.get('port'))
l3plugin.dvr_handle_new_service_port.assert_called_once_with( l3plugin.dvr_handle_new_service_port.assert_called_once_with(
self.adminContext, kwargs.get('port')) self.adminContext, kwargs.get('port'))
@ -961,6 +976,8 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
directory.add_plugin(plugin_constants.L3, l3plugin) directory.add_plugin(plugin_constants.L3, l3plugin)
l3_dvrscheduler_db._notify_l3_agent_new_port( l3_dvrscheduler_db._notify_l3_agent_new_port(
'port', 'after_create', mock.ANY, **kwargs) 'port', 'after_create', mock.ANY, **kwargs)
self.assertFalse(
l3plugin.update_arp_entry_for_dvr_service_port.called)
self.assertFalse( self.assertFalse(
l3plugin.dvr_handle_new_service_port.called) l3plugin.dvr_handle_new_service_port.called)
@ -987,6 +1004,9 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
l3plugin.dvr_handle_new_service_port.assert_called_once_with( l3plugin.dvr_handle_new_service_port.assert_called_once_with(
self.adminContext, kwargs.get('port'), self.adminContext, kwargs.get('port'),
dest_host='vm-host2', router_id=None) dest_host='vm-host2', router_id=None)
l3plugin.update_arp_entry_for_dvr_service_port.\
assert_called_once_with(
self.adminContext, kwargs.get('port'))
def test__notify_l3_agent_update_port_no_action(self): def test__notify_l3_agent_update_port_no_action(self):
kwargs = { kwargs = {
@ -1005,6 +1025,8 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
l3_dvrscheduler_db._notify_l3_agent_port_update( l3_dvrscheduler_db._notify_l3_agent_port_update(
'port', 'after_update', mock.ANY, **kwargs) 'port', 'after_update', mock.ANY, **kwargs)
self.assertFalse(
l3plugin.update_arp_entry_for_dvr_service_port.called)
self.assertFalse( self.assertFalse(
l3plugin.dvr_handle_new_service_port.called) l3plugin.dvr_handle_new_service_port.called)
self.assertFalse(l3plugin.remove_router_from_l3_agent.called) self.assertFalse(l3plugin.remove_router_from_l3_agent.called)
@ -1029,6 +1051,10 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
directory.add_plugin(plugin_constants.L3, l3plugin) directory.add_plugin(plugin_constants.L3, l3plugin)
l3_dvrscheduler_db._notify_l3_agent_port_update( l3_dvrscheduler_db._notify_l3_agent_port_update(
'port', 'after_update', mock.ANY, **kwargs) 'port', 'after_update', mock.ANY, **kwargs)
l3plugin.update_arp_entry_for_dvr_service_port.\
assert_called_once_with(
self.adminContext, kwargs.get('port'))
self.assertFalse(l3plugin.dvr_handle_new_service_port.called) self.assertFalse(l3plugin.dvr_handle_new_service_port.called)
def test__notify_l3_agent_update_port_with_ip_update(self): def test__notify_l3_agent_update_port_with_ip_update(self):
@ -1053,6 +1079,9 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
l3_dvrscheduler_db._notify_l3_agent_port_update( l3_dvrscheduler_db._notify_l3_agent_port_update(
'port', 'after_update', mock.ANY, **kwargs) 'port', 'after_update', mock.ANY, **kwargs)
l3plugin.update_arp_entry_for_dvr_service_port.\
assert_called_once_with(
self.adminContext, kwargs.get('port'))
self.assertFalse(l3plugin.dvr_handle_new_service_port.called) self.assertFalse(l3plugin.dvr_handle_new_service_port.called)
def test__notify_l3_agent_update_port_without_ip_change(self): def test__notify_l3_agent_update_port_without_ip_change(self):
@ -1074,6 +1103,7 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
l3_dvrscheduler_db._notify_l3_agent_port_update( l3_dvrscheduler_db._notify_l3_agent_port_update(
'port', 'after_update', mock.ANY, **kwargs) 'port', 'after_update', mock.ANY, **kwargs)
self.assertFalse(l3plugin.update_arp_entry_for_dvr_service_port.called)
self.assertFalse(l3plugin.dvr_handle_new_service_port.called) self.assertFalse(l3plugin.dvr_handle_new_service_port.called)
def test__notify_l3_agent_port_binding_change(self): def test__notify_l3_agent_port_binding_change(self):
@ -1159,10 +1189,15 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
if routers_to_remove: if routers_to_remove:
(l3plugin.l3_rpc_notifier.router_removed_from_agent. (l3plugin.l3_rpc_notifier.router_removed_from_agent.
assert_called_once_with(mock.ANY, 'foo_id', source_host)) assert_called_once_with(mock.ANY, 'foo_id', source_host))
self.assertEqual(
1,
l3plugin.delete_arp_entry_for_dvr_service_port.call_count)
if fip and is_distributed and not (routers_to_remove and if fip and is_distributed and not (routers_to_remove and
fip['router_id'] is routers_to_remove[0]['router_id']): fip['router_id'] is routers_to_remove[0]['router_id']):
(l3plugin.l3_rpc_notifier.routers_updated_on_host. (l3plugin.l3_rpc_notifier.routers_updated_on_host.
assert_called_once_with(mock.ANY, ['router_id'], source_host)) assert_called_once_with(mock.ANY, ['router_id'], source_host))
self.assertEqual(
1, l3plugin.update_arp_entry_for_dvr_service_port.call_count)
l3plugin.dvr_handle_new_service_port.assert_called_once_with( l3plugin.dvr_handle_new_service_port.assert_called_once_with(
self.adminContext, kwargs.get('port'), self.adminContext, kwargs.get('port'),
dest_host=None, router_id=router_id) dest_host=None, router_id=router_id)
@ -1203,6 +1238,12 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
l3_dvrscheduler_db._notify_l3_agent_port_update( l3_dvrscheduler_db._notify_l3_agent_port_update(
'port', 'after_update', plugin, **kwargs) 'port', 'after_update', plugin, **kwargs)
self.assertEqual(
1, l3plugin.delete_arp_entry_for_dvr_service_port.call_count)
l3plugin.delete_arp_entry_for_dvr_service_port.\
assert_called_once_with(
self.adminContext, mock.ANY)
self.assertFalse( self.assertFalse(
l3plugin.dvr_handle_new_service_port.called) l3plugin.dvr_handle_new_service_port.called)
(l3plugin.l3_rpc_notifier.router_removed_from_agent. (l3plugin.l3_rpc_notifier.router_removed_from_agent.
@ -1236,6 +1277,9 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
l3plugin.get_dvr_routers_to_remove.return_value = removed_routers l3plugin.get_dvr_routers_to_remove.return_value = removed_routers
l3_dvrscheduler_db._notify_port_delete( l3_dvrscheduler_db._notify_port_delete(
'port', 'after_delete', plugin, **kwargs) 'port', 'after_delete', plugin, **kwargs)
l3plugin.delete_arp_entry_for_dvr_service_port.\
assert_called_once_with(
self.adminContext, mock.ANY)
(l3plugin.l3_rpc_notifier.router_removed_from_agent. (l3plugin.l3_rpc_notifier.router_removed_from_agent.
assert_called_once_with(mock.ANY, 'foo_id', 'foo_host')) assert_called_once_with(mock.ANY, 'foo_id', 'foo_host'))