Merge "Revert "DVR: Remove control plane arp updates for DVR"" into stable/ussuri
This commit is contained in:
commit
5489a10d70
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
import collections
|
||||
|
||||
import netaddr
|
||||
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 portbindings
|
||||
@ -50,6 +51,7 @@ from neutron.db import models_v2
|
||||
from neutron.extensions import _admin_state_down_before_update_lib
|
||||
from neutron.ipam import utils as ipam_utils
|
||||
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 router as l3_obj
|
||||
|
||||
@ -475,6 +477,17 @@ class DVRResourceOperationHandler(object):
|
||||
fixed_ip_address))
|
||||
if not addr_pair_active_service_port_list:
|
||||
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])
|
||||
@db_api.retry_if_session_inactive()
|
||||
@ -1111,6 +1124,21 @@ class _DVRAgentInterfaceMixin(object):
|
||||
self._populate_mtu_and_subnets_for_ports(context, [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):
|
||||
"""Returns the subnet_id that matches the fixedip on a network."""
|
||||
filters = {'network_id': [port_dict['network_id']]}
|
||||
@ -1119,6 +1147,78 @@ class _DVRAgentInterfaceMixin(object):
|
||||
if ipam_utils.check_subnet_ip(subnet['cidr'], fixed_ip):
|
||||
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,
|
||||
DVRResourceOperationHandler,
|
||||
|
@ -518,6 +518,19 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin):
|
||||
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):
|
||||
LOG.debug('Received %(resource)s %(event)s', {
|
||||
'resource': resource,
|
||||
@ -530,6 +543,7 @@ def _notify_l3_agent_new_port(resource, event, trigger, **kwargs):
|
||||
l3plugin = directory.get_plugin(plugin_constants.L3)
|
||||
context = kwargs['context']
|
||||
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):
|
||||
@ -537,6 +551,14 @@ def _notify_port_delete(event, resource, trigger, **kwargs):
|
||||
port = kwargs['port']
|
||||
get_related_hosts_info = kwargs.get("get_related_hosts_info", True)
|
||||
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(
|
||||
context, port, get_related_hosts_info)
|
||||
for info in removed_routers:
|
||||
@ -625,7 +647,32 @@ def _notify_l3_agent_port_update(resource, event, trigger, **kwargs):
|
||||
context, new_port,
|
||||
dest_host=dest_host,
|
||||
router_id=fip_router_id)
|
||||
l3plugin.update_arp_entry_for_dvr_service_port(
|
||||
context, new_port)
|
||||
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():
|
||||
|
@ -1024,6 +1024,145 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||
floatingips = router_sync_info[0][constants.FLOATINGIP_KEY]
|
||||
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):
|
||||
router = self._create_router(ha=False)
|
||||
private_net1 = self._make_network(self.fmt, 'net1', True)
|
||||
@ -1058,6 +1197,110 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||
self.assertEqual(self.l3_agent['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):
|
||||
# register l3 agents in dvr mode in addition to existing dvr_snat agent
|
||||
HOST1 = 'host1'
|
||||
|
@ -1136,6 +1136,72 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
||||
port=mock.ANY,
|
||||
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):
|
||||
router_dict = {'name': 'test_router', 'admin_state_up': True,
|
||||
'distributed': True}
|
||||
|
@ -841,12 +841,20 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
|
||||
'device_owner': DEVICE_OWNER_COMPUTE,
|
||||
},
|
||||
}
|
||||
port = kwargs.get('original_port')
|
||||
l3plugin = mock.Mock()
|
||||
directory.add_plugin(plugin_constants.L3, l3plugin)
|
||||
l3_dvrscheduler_db._notify_l3_agent_port_update(
|
||||
'port', 'after_update', mock.ANY, **kwargs)
|
||||
l3plugin._get_allowed_address_pair_fixed_ips.return_value = (
|
||||
['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):
|
||||
port_id = uuidutils.generate_uuid()
|
||||
@ -874,6 +882,8 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
|
||||
directory.add_plugin(plugin_constants.L3, l3plugin)
|
||||
l3_dvrscheduler_db._notify_l3_agent_port_update(
|
||||
'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):
|
||||
port_id = 'fake-port'
|
||||
@ -929,6 +939,8 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
|
||||
directory.add_plugin(plugin_constants.L3, l3plugin)
|
||||
l3_dvrscheduler_db._notify_l3_agent_port_update(
|
||||
'port', 'after_update', plugin, **kwargs)
|
||||
self.assertFalse(
|
||||
l3plugin.update_arp_entry_for_dvr_service_port.called)
|
||||
self.assertFalse(
|
||||
l3plugin.dvr_handle_new_service_port.called)
|
||||
self.assertFalse(l3plugin.remove_router_from_l3_agent.called)
|
||||
@ -946,6 +958,9 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
|
||||
directory.add_plugin(plugin_constants.L3, l3plugin)
|
||||
l3_dvrscheduler_db._notify_l3_agent_new_port(
|
||||
'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(
|
||||
self.adminContext, kwargs.get('port'))
|
||||
|
||||
@ -961,6 +976,8 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
|
||||
directory.add_plugin(plugin_constants.L3, l3plugin)
|
||||
l3_dvrscheduler_db._notify_l3_agent_new_port(
|
||||
'port', 'after_create', mock.ANY, **kwargs)
|
||||
self.assertFalse(
|
||||
l3plugin.update_arp_entry_for_dvr_service_port.called)
|
||||
self.assertFalse(
|
||||
l3plugin.dvr_handle_new_service_port.called)
|
||||
|
||||
@ -987,6 +1004,9 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
|
||||
l3plugin.dvr_handle_new_service_port.assert_called_once_with(
|
||||
self.adminContext, kwargs.get('port'),
|
||||
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):
|
||||
kwargs = {
|
||||
@ -1005,6 +1025,8 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
|
||||
l3_dvrscheduler_db._notify_l3_agent_port_update(
|
||||
'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.remove_router_from_l3_agent.called)
|
||||
@ -1029,6 +1051,10 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
|
||||
directory.add_plugin(plugin_constants.L3, l3plugin)
|
||||
l3_dvrscheduler_db._notify_l3_agent_port_update(
|
||||
'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)
|
||||
|
||||
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(
|
||||
'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)
|
||||
|
||||
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(
|
||||
'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)
|
||||
|
||||
def test__notify_l3_agent_port_binding_change(self):
|
||||
@ -1159,10 +1189,15 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
|
||||
if routers_to_remove:
|
||||
(l3plugin.l3_rpc_notifier.router_removed_from_agent.
|
||||
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
|
||||
fip['router_id'] is routers_to_remove[0]['router_id']):
|
||||
(l3plugin.l3_rpc_notifier.routers_updated_on_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(
|
||||
self.adminContext, kwargs.get('port'),
|
||||
dest_host=None, router_id=router_id)
|
||||
@ -1203,6 +1238,12 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin,
|
||||
l3_dvrscheduler_db._notify_l3_agent_port_update(
|
||||
'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(
|
||||
l3plugin.dvr_handle_new_service_port.called)
|
||||
(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
|
||||
l3_dvrscheduler_db._notify_port_delete(
|
||||
'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.
|
||||
assert_called_once_with(mock.ANY, 'foo_id', 'foo_host'))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user