# Copyright (c) 2012 OpenStack Foundation. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import contextlib import mock from oslo_config import cfg import oslo_messaging from neutron.agent.linux import utils from neutron.common import constants as n_const from neutron.plugins.common import constants as p_const from neutron.plugins.openvswitch.agent import ovs_neutron_agent from neutron.plugins.openvswitch.common import constants from neutron.tests import base NOTIFIER = 'neutron.plugins.ml2.rpc.AgentNotifierApi' OVS_LINUX_KERN_VERS_WITHOUT_VXLAN = "3.12.0" FAKE_MAC = '00:11:22:33:44:55' FAKE_IP1 = '10.0.0.1' FAKE_IP2 = '10.0.0.2' class TestOvsDvrNeutronAgent(base.BaseTestCase): def setUp(self): super(TestOvsDvrNeutronAgent, self).setUp() notifier_p = mock.patch(NOTIFIER) notifier_cls = notifier_p.start() self.notifier = mock.Mock() notifier_cls.return_value = self.notifier cfg.CONF.set_default('firewall_driver', 'neutron.agent.firewall.NoopFirewallDriver', group='SECURITYGROUP') kwargs = ovs_neutron_agent.create_agent_config_map(cfg.CONF) class MockFixedIntervalLoopingCall(object): def __init__(self, f): self.f = f def start(self, interval=0): self.f() with contextlib.nested( mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.' 'OVSNeutronAgent.setup_integration_br'), mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.' 'OVSNeutronAgent.setup_ancillary_bridges', return_value=[]), mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'create'), mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_secure_mode'), mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'get_local_port_mac', return_value='00:00:00:00:00:01'), mock.patch('neutron.agent.linux.utils.get_interface_mac', return_value='00:00:00:00:00:01'), mock.patch('neutron.agent.common.ovs_lib.BaseOVS.get_bridges'), mock.patch('neutron.openstack.common.loopingcall.' 'FixedIntervalLoopingCall', new=MockFixedIntervalLoopingCall)): self.agent = ovs_neutron_agent.OVSNeutronAgent(**kwargs) # set back to true because initial report state will succeed due # to mocked out RPC calls self.agent.use_call = True self.agent.tun_br = mock.Mock() self.agent.sg_agent = mock.Mock() def _setup_for_dvr_test(self, ofport=10): self._port = mock.Mock() self._port.ofport = ofport self._port.vif_id = "1234-5678-90" self._physical_network = 'physeth1' self._old_local_vlan = None self._segmentation_id = 2001 self.agent.enable_distributed_routing = True self.agent.enable_tunneling = True self.agent.patch_tun_ofport = 1 self.agent.patch_int_ofport = 2 self.agent.dvr_agent.local_ports = {} self.agent.local_vlan_map = {} self.agent.dvr_agent.enable_distributed_routing = True self.agent.dvr_agent.enable_tunneling = True self.agent.dvr_agent.patch_tun_ofport = 1 self.agent.dvr_agent.patch_int_ofport = 2 self.agent.dvr_agent.tun_br = mock.Mock() self.agent.dvr_agent.phys_brs[self._physical_network] = mock.Mock() self.agent.dvr_agent.bridge_mappings = {self._physical_network: 'br-eth1'} self.agent.dvr_agent.int_ofports[self._physical_network] = 30 self.agent.dvr_agent.phys_ofports[self._physical_network] = 40 self.agent.dvr_agent.local_dvr_map = {} self.agent.dvr_agent.registered_dvr_macs = set() self.agent.dvr_agent.dvr_mac_address = 'aa:22:33:44:55:66' self._net_uuid = 'my-net-uuid' self._fixed_ips = [{'subnet_id': 'my-subnet-uuid', 'ip_address': '1.1.1.1'}] self._compute_port = mock.Mock() self._compute_port.ofport = 20 self._compute_port.vif_id = "1234-5678-91" self._compute_fixed_ips = [{'subnet_id': 'my-subnet-uuid', 'ip_address': '1.1.1.3'}] def _test_port_bound_for_dvr_on_vlan_network(self, device_owner, ip_version=4): self._setup_for_dvr_test() if ip_version == 4: gateway_ip = '1.1.1.1' cidr = '1.1.1.0/24' else: gateway_ip = '2001:100::1' cidr = '2001:100::0/64' self._port.vif_mac = gateway_mac = 'aa:bb:cc:11:22:33' self._compute_port.vif_mac = '77:88:99:00:11:22' physical_network = self._physical_network segmentation_id = self._segmentation_id network_type = p_const.TYPE_VLAN with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr', return_value={ 'gateway_ip': gateway_ip, 'cidr': cidr, 'ip_version': ip_version, 'gateway_mac': gateway_mac}), mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_ports_on_host_by_subnet', return_value=[]), mock.patch.object(self.agent.dvr_agent.int_br, 'get_vif_port_by_id', return_value=self._port), mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'), mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows'), mock.patch.object( self.agent.dvr_agent.phys_brs[physical_network], 'add_flow'), mock.patch.object( self.agent.dvr_agent.phys_brs[physical_network], 'delete_flows') ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn, get_vif_fn, add_flow_int_fn, delete_flows_int_fn, add_flow_tun_fn, delete_flows_tun_fn, add_flow_phys_fn, delete_flows_phys_fn): self.agent.port_bound( self._port, self._net_uuid, network_type, physical_network, segmentation_id, self._fixed_ips, n_const.DEVICE_OWNER_DVR_INTERFACE, False) lvm = self.agent.local_vlan_map[self._net_uuid] phy_ofp = self.agent.dvr_agent.phys_ofports[physical_network] int_ofp = self.agent.dvr_agent.int_ofports[physical_network] expected_on_phys_br = [ mock.call(table=constants.LOCAL_VLAN_TRANSLATION, priority=4, in_port=phy_ofp, dl_vlan=lvm.vlan, actions="mod_vlan_vid:%s,normal" % (lvm.segmentation_id)), mock.call(table=constants.DVR_PROCESS_VLAN, priority=2, dl_vlan=lvm.vlan, dl_dst=self._port.vif_mac, actions="drop"), mock.call(table=constants.DVR_PROCESS_VLAN, priority=1, dl_vlan=lvm.vlan, dl_src=self._port.vif_mac, actions="mod_dl_src:%s,resubmit(,%s)" % (self.agent.dvr_agent.dvr_mac_address, constants.LOCAL_VLAN_TRANSLATION)) ] if ip_version == 4: expected_on_phys_br.insert(1, mock.call( proto='arp', nw_dst=gateway_ip, actions='drop', priority=3, table=constants.DVR_PROCESS_VLAN, dl_vlan=lvm.vlan)) else: expected_on_phys_br.insert(1, mock.call( icmp_type=n_const.ICMPV6_TYPE_RA, proto='icmp6', dl_src=self._port.vif_mac, actions='drop', priority=3, table=constants.DVR_PROCESS_VLAN, dl_vlan=lvm.vlan)) self.assertEqual(expected_on_phys_br, add_flow_phys_fn.call_args_list) self.agent.port_bound(self._compute_port, self._net_uuid, network_type, physical_network, segmentation_id, self._compute_fixed_ips, device_owner, False) expected_on_int_br = [ mock.call(priority=3, in_port=int_ofp, dl_vlan=lvm.segmentation_id, actions="mod_vlan_vid:%s,normal" % lvm.vlan), mock.call(table=constants.DVR_TO_SRC_MAC_VLAN, priority=4, dl_dst=self._compute_port.vif_mac, dl_vlan=lvm.segmentation_id, actions="strip_vlan,mod_dl_src:%s," "output:%s" % (gateway_mac, self._compute_port.ofport)) ] self.assertEqual(expected_on_int_br, add_flow_int_fn.call_args_list) expected_on_int_br = [ mock.call(in_port=self._port.ofport), mock.call(in_port=self._compute_port.ofport) ] self.assertEqual(expected_on_int_br, delete_flows_int_fn.call_args_list) self.assertFalse(add_flow_tun_fn.called) self.assertFalse(delete_flows_tun_fn.called) self.assertFalse(delete_flows_phys_fn.called) def _test_port_bound_for_dvr_on_vxlan_network(self, device_owner, ip_version=4): self._setup_for_dvr_test() if ip_version == 4: gateway_ip = '1.1.1.1' cidr = '1.1.1.0/24' else: gateway_ip = '2001:100::1' cidr = '2001:100::0/64' network_type = p_const.TYPE_VXLAN self._port.vif_mac = gateway_mac = 'aa:bb:cc:11:22:33' self._compute_port.vif_mac = '77:88:99:00:11:22' physical_network = self._physical_network segmentation_id = self._segmentation_id with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr', return_value={ 'gateway_ip': gateway_ip, 'cidr': cidr, 'ip_version': ip_version, 'gateway_mac': gateway_mac}), mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_ports_on_host_by_subnet', return_value=[]), mock.patch.object(self.agent.dvr_agent.int_br, 'get_vif_port_by_id', return_value=self._port), mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'), mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows'), mock.patch.object( self.agent.dvr_agent.phys_brs[physical_network], 'add_flow'), mock.patch.object( self.agent.dvr_agent.phys_brs[physical_network], 'delete_flows') ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn, get_vif_fn, add_flow_int_fn, delete_flows_int_fn, add_flow_tun_fn, delete_flows_tun_fn, add_flow_phys_fn, delete_flows_phys_fn): self.agent.port_bound( self._port, self._net_uuid, network_type, physical_network, segmentation_id, self._fixed_ips, n_const.DEVICE_OWNER_DVR_INTERFACE, False) lvm = self.agent.local_vlan_map[self._net_uuid] expected_on_tun_br = [ mock.call( table=constants.TUN_TABLE['vxlan'], priority=1, tun_id=lvm.segmentation_id, actions="mod_vlan_vid:%s," "resubmit(,%s)" % (lvm.vlan, constants.DVR_NOT_LEARN)), mock.call( table=constants.DVR_PROCESS, priority=2, dl_vlan=lvm.vlan, dl_dst=self._port.vif_mac, actions='drop'), mock.call( table=constants.DVR_PROCESS, priority=1, dl_vlan=lvm.vlan, dl_src=self._port.vif_mac, actions="mod_dl_src:%s,resubmit(,%s)" % ( self.agent.dvr_agent.dvr_mac_address, constants.PATCH_LV_TO_TUN))] if ip_version == 4: expected_on_tun_br.insert(1, mock.call( proto='arp', nw_dst=gateway_ip, actions='drop', priority=3, table=constants.DVR_PROCESS, dl_vlan=lvm.vlan)) else: expected_on_tun_br.insert(1, mock.call( icmp_type=n_const.ICMPV6_TYPE_RA, proto='icmp6', dl_src=self._port.vif_mac, actions='drop', priority=3, table=constants.DVR_PROCESS, dl_vlan=lvm.vlan)) self.assertEqual(expected_on_tun_br, add_flow_tun_fn.call_args_list) self.agent.port_bound(self._compute_port, self._net_uuid, network_type, physical_network, segmentation_id, self._compute_fixed_ips, device_owner, False) expected_on_int_br = [ mock.call(table=constants.DVR_TO_SRC_MAC, priority=4, dl_dst=self._compute_port.vif_mac, dl_vlan=lvm.vlan, actions="strip_vlan,mod_dl_src:%s," "output:%s" % (gateway_mac, self._compute_port.ofport)) ] self.assertEqual(expected_on_int_br, add_flow_int_fn.call_args_list) self.assertFalse(add_flow_phys_fn.called) expected_on_int_br = [ mock.call(in_port=self._port.ofport), mock.call(in_port=self._compute_port.ofport) ] self.assertEqual(expected_on_int_br, delete_flows_int_fn.call_args_list) self.assertFalse(add_flow_phys_fn.called) self.assertFalse(delete_flows_tun_fn.called) self.assertFalse(delete_flows_phys_fn.called) def test_port_bound_for_dvr_with_compute_ports(self): self._test_port_bound_for_dvr_on_vlan_network( device_owner="compute:None") self._test_port_bound_for_dvr_on_vlan_network( device_owner="compute:None", ip_version=6) self._test_port_bound_for_dvr_on_vxlan_network( device_owner="compute:None") self._test_port_bound_for_dvr_on_vxlan_network( device_owner="compute:None", ip_version=6) def test_port_bound_for_dvr_with_lbaas_vip_ports(self): self._test_port_bound_for_dvr_on_vlan_network( device_owner=n_const.DEVICE_OWNER_LOADBALANCER) self._test_port_bound_for_dvr_on_vlan_network( device_owner=n_const.DEVICE_OWNER_LOADBALANCER, ip_version=6) self._test_port_bound_for_dvr_on_vxlan_network( device_owner=n_const.DEVICE_OWNER_LOADBALANCER) self._test_port_bound_for_dvr_on_vxlan_network( device_owner=n_const.DEVICE_OWNER_LOADBALANCER, ip_version=6) def test_port_bound_for_dvr_with_dhcp_ports(self): self._test_port_bound_for_dvr_on_vlan_network( device_owner=n_const.DEVICE_OWNER_DHCP) self._test_port_bound_for_dvr_on_vlan_network( device_owner=n_const.DEVICE_OWNER_DHCP, ip_version=6) self._test_port_bound_for_dvr_on_vxlan_network( device_owner=n_const.DEVICE_OWNER_DHCP) self._test_port_bound_for_dvr_on_vxlan_network( device_owner=n_const.DEVICE_OWNER_DHCP, ip_version=6) def test_port_bound_for_dvr_with_csnat_ports(self, ofport=10): self._setup_for_dvr_test() with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object( self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr', return_value={'gateway_ip': '1.1.1.1', 'cidr': '1.1.1.0/24', 'ip_version': 4, 'gateway_mac': 'aa:bb:cc:11:22:33'}), mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_ports_on_host_by_subnet', return_value=[]), mock.patch.object(self.agent.dvr_agent.int_br, 'get_vif_port_by_id', return_value=self._port), mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'), mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows') ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn, get_vif_fn, add_flow_int_fn, delete_flows_int_fn, add_flow_tun_fn, delete_flows_tun_fn): self.agent.port_bound( self._port, self._net_uuid, 'vxlan', None, None, self._fixed_ips, n_const.DEVICE_OWNER_ROUTER_SNAT, False) self.assertTrue(add_flow_int_fn.called) self.assertTrue(delete_flows_int_fn.called) def test_treat_devices_removed_for_dvr_interface(self, ofport=10): self._test_treat_devices_removed_for_dvr_interface(ofport) self._test_treat_devices_removed_for_dvr_interface( ofport, ip_version=6) def _test_treat_devices_removed_for_dvr_interface(self, ofport=10, ip_version=4): self._setup_for_dvr_test() if ip_version == 4: gateway_ip = '1.1.1.1' cidr = '1.1.1.0/24' else: gateway_ip = '2001:100::1' cidr = '2001:100::0/64' with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object( self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr', return_value={'gateway_ip': gateway_ip, 'cidr': cidr, 'ip_version': ip_version, 'gateway_mac': 'aa:bb:cc:11:22:33'}), mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_ports_on_host_by_subnet', return_value=[]), mock.patch.object(self.agent.dvr_agent.int_br, 'get_vif_port_by_id', return_value=self._port), mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'), mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows') ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn, get_vif_fn, add_flow_int_fn, delete_flows_int_fn, add_flow_tun_fn, delete_flows_tun_fn): self.agent.port_bound( self._port, self._net_uuid, 'vxlan', None, None, self._fixed_ips, n_const.DEVICE_OWNER_DVR_INTERFACE, False) self.assertTrue(add_flow_tun_fn.called) self.assertTrue(delete_flows_int_fn.called) with contextlib.nested( mock.patch.object(self.agent, 'reclaim_local_vlan'), mock.patch.object(self.agent.plugin_rpc, 'update_device_down', return_value=None), mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'), mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')) as (reclaim_vlan_fn, update_dev_down_fn, delete_flows_int_fn, delete_flows_tun_fn): self.agent.treat_devices_removed([self._port.vif_id]) if ip_version == 4: expected = [mock.call( proto='arp', nw_dst=gateway_ip, table=constants.DVR_PROCESS, dl_vlan=( self.agent.local_vlan_map[self._net_uuid].vlan))] else: expected = [mock.call( icmp_type=n_const.ICMPV6_TYPE_RA, proto='icmp6', dl_src='aa:bb:cc:11:22:33', table=constants.DVR_PROCESS, dl_vlan=( self.agent.local_vlan_map[self._net_uuid].vlan))] expected.extend([ mock.call( table=constants.DVR_PROCESS, dl_dst=self._port.vif_mac, dl_vlan=( self.agent.local_vlan_map[self._net_uuid].vlan)), mock.call( table=constants.DVR_PROCESS, dl_vlan=( self.agent.local_vlan_map[self._net_uuid].vlan), dl_src=self._port.vif_mac) ]) self.assertEqual(expected, delete_flows_tun_fn.call_args_list) def _test_treat_devices_removed_for_dvr(self, device_owner, ip_version=4): self._setup_for_dvr_test() if ip_version == 4: gateway_ip = '1.1.1.1' cidr = '1.1.1.0/24' else: gateway_ip = '2001:100::1' cidr = '2001:100::0/64' with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object( self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr', return_value={'gateway_ip': gateway_ip, 'cidr': cidr, 'ip_version': ip_version, 'gateway_mac': 'aa:bb:cc:11:22:33'}), mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_ports_on_host_by_subnet', return_value=[]), mock.patch.object(self.agent.dvr_agent.int_br, 'get_vif_port_by_id', return_value=self._port), mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'), mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows') ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn, get_vif_fn, add_flow_int_fn, delete_flows_int_fn, add_flow_tun_fn, delete_flows_tun_fn): self.agent.port_bound( self._port, self._net_uuid, 'vxlan', None, None, self._fixed_ips, n_const.DEVICE_OWNER_DVR_INTERFACE, False) self.agent.port_bound(self._compute_port, self._net_uuid, 'vxlan', None, None, self._compute_fixed_ips, device_owner, False) self.assertTrue(add_flow_tun_fn.called) self.assertTrue(add_flow_int_fn.called) self.assertTrue(delete_flows_int_fn.called) with contextlib.nested( mock.patch.object(self.agent, 'reclaim_local_vlan'), mock.patch.object(self.agent.plugin_rpc, 'update_device_down', return_value=None), mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows')) as (reclaim_vlan_fn, update_dev_down_fn, delete_flows_int_fn): self.agent.treat_devices_removed([self._compute_port.vif_id]) expected = [ mock.call( table=constants.DVR_TO_SRC_MAC, dl_dst=self._compute_port.vif_mac, dl_vlan=( self.agent.local_vlan_map[self._net_uuid].vlan))] self.assertEqual(expected, delete_flows_int_fn.call_args_list) def test_treat_devices_removed_for_dvr_with_compute_ports(self): self._test_treat_devices_removed_for_dvr( device_owner="compute:None") self._test_treat_devices_removed_for_dvr( device_owner="compute:None", ip_version=6) def test_treat_devices_removed_for_dvr_with_lbaas_vip_ports(self): self._test_treat_devices_removed_for_dvr( device_owner=n_const.DEVICE_OWNER_LOADBALANCER) self._test_treat_devices_removed_for_dvr( device_owner=n_const.DEVICE_OWNER_LOADBALANCER, ip_version=6) def test_treat_devices_removed_for_dvr_with_dhcp_ports(self): self._test_treat_devices_removed_for_dvr( device_owner=n_const.DEVICE_OWNER_DHCP) self._test_treat_devices_removed_for_dvr( device_owner=n_const.DEVICE_OWNER_DHCP, ip_version=6) def test_treat_devices_removed_for_dvr_csnat_port(self, ofport=10): self._setup_for_dvr_test() with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object( self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr', return_value={'gateway_ip': '1.1.1.1', 'cidr': '1.1.1.0/24', 'ip_version': 4, 'gateway_mac': 'aa:bb:cc:11:22:33'}), mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_ports_on_host_by_subnet', return_value=[]), mock.patch.object(self.agent.dvr_agent.int_br, 'get_vif_port_by_id', return_value=self._port), mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'), mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows') ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn, get_vif_fn, add_flow_int_fn, delete_flows_int_fn, add_flow_tun_fn, delete_flows_tun_fn): self.agent.port_bound( self._port, self._net_uuid, 'vxlan', None, None, self._fixed_ips, n_const.DEVICE_OWNER_ROUTER_SNAT, False) self.assertTrue(add_flow_int_fn.called) self.assertTrue(delete_flows_int_fn.called) with contextlib.nested( mock.patch.object(self.agent, 'reclaim_local_vlan'), mock.patch.object(self.agent.plugin_rpc, 'update_device_down', return_value=None), mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows')) as (reclaim_vlan_fn, update_dev_down_fn, delete_flows_int_fn): self.agent.treat_devices_removed([self._port.vif_id]) self.assertTrue(delete_flows_int_fn.called) def test_setup_dvr_flows_on_int_br(self): self._setup_for_dvr_test() with contextlib.nested( mock.patch.object(self.agent.dvr_agent.int_br, 'remove_all_flows'), mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'), mock.patch.object( self.agent.dvr_agent.plugin_rpc, 'get_dvr_mac_address_list', return_value=[{'host': 'cn1', 'mac_address': 'aa:bb:cc:dd:ee:ff'}, {'host': 'cn2', 'mac_address': '11:22:33:44:55:66'}])) as \ (remove_flows_fn, add_int_flow_fn, add_tun_flow_fn, get_mac_list_fn): self.agent.dvr_agent.setup_dvr_flows_on_integ_br() self.assertTrue(self.agent.dvr_agent.in_distributed_mode()) physical_networks = self.agent.dvr_agent.bridge_mappings.keys() ioport = self.agent.dvr_agent.int_ofports[physical_networks[0]] expected = [ mock.call(table=constants.CANARY_TABLE, priority=0, actions="drop"), mock.call(table=constants.DVR_TO_SRC_MAC, priority=1, actions="drop"), mock.call(table=constants.DVR_TO_SRC_MAC_VLAN, priority=1, actions="drop"), mock.call(table=constants.LOCAL_SWITCHING, priority=1, actions="normal"), mock.call( table=constants.LOCAL_SWITCHING, priority=2, actions="drop", in_port=ioport)] self.assertTrue(remove_flows_fn.called) self.assertEqual(expected, add_int_flow_fn.call_args_list) self.assertEqual(add_int_flow_fn.call_count, 5) def test_get_dvr_mac_address(self): self._setup_for_dvr_test() self.agent.dvr_agent.dvr_mac_address = None with mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_dvr_mac_address_by_host', return_value={'host': 'cn1', 'mac_address': 'aa:22:33:44:55:66'}): self.agent.dvr_agent.get_dvr_mac_address() self.assertEqual('aa:22:33:44:55:66', self.agent.dvr_agent.dvr_mac_address) self.assertTrue(self.agent.dvr_agent.in_distributed_mode()) def test_get_dvr_mac_address_exception(self): self._setup_for_dvr_test() self.agent.dvr_agent.dvr_mac_address = None with contextlib.nested( mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_dvr_mac_address_by_host', side_effect=oslo_messaging.RemoteError), mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow')) as (gd_mac, add_int_flow_fn): self.agent.dvr_agent.get_dvr_mac_address() self.assertIsNone(self.agent.dvr_agent.dvr_mac_address) self.assertFalse(self.agent.dvr_agent.in_distributed_mode()) self.assertEqual(add_int_flow_fn.call_count, 1) def test_get_dvr_mac_address_retried(self): valid_entry = {'host': 'cn1', 'mac_address': 'aa:22:33:44:55:66'} raise_timeout = oslo_messaging.MessagingTimeout() # Raise a timeout the first 2 times it calls get_dvr_mac_address() self._setup_for_dvr_test() self.agent.dvr_agent.dvr_mac_address = None with mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_dvr_mac_address_by_host', side_effect=(raise_timeout, raise_timeout, valid_entry)): self.agent.dvr_agent.get_dvr_mac_address() self.assertEqual('aa:22:33:44:55:66', self.agent.dvr_agent.dvr_mac_address) self.assertTrue(self.agent.dvr_agent.in_distributed_mode()) self.assertEqual(self.agent.dvr_agent.plugin_rpc. get_dvr_mac_address_by_host.call_count, 3) def test_get_dvr_mac_address_retried_max(self): raise_timeout = oslo_messaging.MessagingTimeout() # Raise a timeout every time until we give up, currently 5 tries self._setup_for_dvr_test() self.agent.dvr_agent.dvr_mac_address = None with contextlib.nested( mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_dvr_mac_address_by_host', side_effect=raise_timeout), mock.patch.object(utils, "execute"), ) as (rpc_mock, execute_mock): self.agent.dvr_agent.get_dvr_mac_address() self.assertIsNone(self.agent.dvr_agent.dvr_mac_address) self.assertFalse(self.agent.dvr_agent.in_distributed_mode()) self.assertEqual(self.agent.dvr_agent.plugin_rpc. get_dvr_mac_address_by_host.call_count, 5) def test_dvr_mac_address_update(self): self._setup_for_dvr_test() newhost = 'cn2' newmac = 'aa:bb:cc:dd:ee:ff' int_ofport = self.agent.dvr_agent.int_ofports['physeth1'] patch_int_ofport = self.agent.dvr_agent.patch_int_ofport patch_tun_ofport = self.agent.dvr_agent.patch_tun_ofport with contextlib.nested( mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'), mock.patch.object(self.agent.dvr_agent.phys_brs['physeth1'], 'add_flow') ) as (add_flow_fn, add_flow_tn_fn, del_flows_fn, add_flow_phys_fn): self.agent.dvr_agent.\ dvr_mac_address_update( dvr_macs=[{'host': newhost, 'mac_address': newmac}]) expected = [ mock.call(table=constants.LOCAL_SWITCHING, priority=4, in_port=int_ofport, dl_src=newmac, actions="resubmit(,%s)" % constants.DVR_TO_SRC_MAC_VLAN), mock.call(table=constants.LOCAL_SWITCHING, priority=2, in_port=patch_tun_ofport, dl_src=newmac, actions="resubmit(,%s)" % constants.DVR_TO_SRC_MAC)] self.assertEqual(expected, add_flow_fn.call_args_list) add_flow_phys_fn.assert_called_with( table=constants.DVR_NOT_LEARN_VLAN, priority=2, dl_src=newmac, actions="output:%s" % self.agent.dvr_agent.phys_ofports['physeth1']) add_flow_tn_fn.assert_called_with(table=constants.DVR_NOT_LEARN, priority=1, dl_src=newmac, actions="output:%s" % patch_int_ofport) self.assertFalse(del_flows_fn.called) with contextlib.nested( mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'), mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows'), mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'), mock.patch.object(self.agent.dvr_agent.phys_brs['physeth1'], 'delete_flows'), ) as (add_flow_fn, del_flows_tn_fn, del_flows_fn, del_flows_phys_fn): self.agent.dvr_agent.dvr_mac_address_update(dvr_macs=[]) ioport = self.agent.dvr_agent.int_ofports['physeth1'] expected = [ mock.call(table=constants.LOCAL_SWITCHING, in_port=ioport, dl_src=newmac), mock.call(table=constants.LOCAL_SWITCHING, in_port=patch_tun_ofport, dl_src=newmac)] self.assertEqual(expected, del_flows_fn.call_args_list) del_flows_phys_fn.asert_called_with( table=constants.DVR_NOT_LEARN_VLAN, dl_src=newmac) del_flows_tn_fn.assert_called_with(table=constants.DVR_NOT_LEARN, dl_src=newmac) self.assertFalse(add_flow_fn.called)