diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py index d1036a280fb..d7a200616fe 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py @@ -451,9 +451,6 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, if not self.enable_tunneling: return tunnel_ip = kwargs.get('tunnel_ip') - tunnel_ip_hex = self.get_ip_in_hex(tunnel_ip) - if not tunnel_ip_hex: - return tunnel_type = kwargs.get('tunnel_type') if not tunnel_type: LOG.error(_LE("No tunnel_type specified, cannot create tunnels")) @@ -464,7 +461,9 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, return if tunnel_ip == self.local_ip: return - tun_name = '%s-%s' % (tunnel_type, tunnel_ip_hex) + tun_name = self.get_tunnel_name(tunnel_type, self.local_ip, tunnel_ip) + if tun_name is None: + return if not self.l2_pop: self._setup_tunnel_port(self.tun_br, tun_name, tunnel_ip, tunnel_type) @@ -1388,10 +1387,10 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, return ofport def setup_tunnel_port(self, br, remote_ip, network_type): - remote_ip_hex = self.get_ip_in_hex(remote_ip) - if not remote_ip_hex: + port_name = self.get_tunnel_name( + network_type, self.local_ip, remote_ip) + if port_name is None: return 0 - port_name = '%s-%s' % (network_type, remote_ip_hex) ofport = self._setup_tunnel_port(br, port_name, remote_ip, @@ -1408,8 +1407,8 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, items = list(self.tun_br_ofports[tunnel_type].items()) for remote_ip, ofport in items: if ofport == tun_ofport: - port_name = '%s-%s' % (tunnel_type, - self.get_ip_in_hex(remote_ip)) + port_name = self.get_tunnel_name( + tunnel_type, self.local_ip, remote_ip) br.delete_port(port_name) br.cleanup_tunnel_port(ofport) self.tun_br_ofports[tunnel_type].pop(remote_ip, None) @@ -1613,7 +1612,8 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, 'elapsed': time.time() - start}) return failed_devices - def get_ip_in_hex(self, ip_address): + @classmethod + def get_ip_in_hex(cls, ip_address): try: return '%08x' % netaddr.IPAddress(ip_address, version=4) except Exception: @@ -1632,10 +1632,10 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, for tunnel in tunnels: if self.local_ip != tunnel['ip_address']: remote_ip = tunnel['ip_address'] - remote_ip_hex = self.get_ip_in_hex(remote_ip) - if not remote_ip_hex: + tun_name = self.get_tunnel_name( + tunnel_type, self.local_ip, remote_ip) + if tun_name is None: continue - tun_name = '%s-%s' % (tunnel_type, remote_ip_hex) self._setup_tunnel_port(self.tun_br, tun_name, tunnel['ip_address'], @@ -1646,6 +1646,13 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, return True return False + @classmethod + def get_tunnel_name(cls, network_type, local_ip, remote_ip): + remote_ip_hex = cls.get_ip_in_hex(remote_ip) + if not remote_ip_hex: + return None + return '%s-%s' % (network_type, remote_ip_hex) + def _agent_has_updates(self, polling_manager): return (polling_manager.is_polling_required or self.updated_ports or diff --git a/neutron/tests/common/agents/ovs_agent.py b/neutron/tests/common/agents/ovs_agent.py new file mode 100755 index 00000000000..a5c9c2514c0 --- /dev/null +++ b/neutron/tests/common/agents/ovs_agent.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# +# 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 hashlib +import sys + + +from neutron.cmd.eventlet.plugins.ovs_neutron_agent import main as _main +from neutron.common import constants as n_const +from neutron.plugins.ml2.drivers.openvswitch.agent.ovs_neutron_agent \ + import OVSNeutronAgent + + +def get_tunnel_name_full(cls, network_type, local_ip, remote_ip): + network_type = network_type[:3] + remote_ip_hex = cls.get_ip_in_hex(remote_ip) + if not remote_ip_hex: + return None + + # Remove length of network_type and two dashes + hashlen = (n_const.DEVICE_NAME_MAX_LEN - len(network_type) - 2) // 2 + remote_ip_hex = remote_ip_hex.encode('utf-8') + remote_ip_hash = hashlib.sha1(remote_ip_hex).hexdigest()[0:hashlen] + local_ip_hex = cls.get_ip_in_hex(local_ip).encode('utf-8') + source_ip_hash = hashlib.sha1(local_ip_hex).hexdigest()[0:hashlen] + return '%s-%s-%s' % (network_type, source_ip_hash, remote_ip_hash) + +OVSNeutronAgent.get_tunnel_name = get_tunnel_name_full + + +def main(): + _main() + +if __name__ == "__main__": + sys.exit(main()) diff --git a/neutron/tests/fullstack/resources/process.py b/neutron/tests/fullstack/resources/process.py index 3c1a4db6cbf..55bc7c70720 100644 --- a/neutron/tests/fullstack/resources/process.py +++ b/neutron/tests/fullstack/resources/process.py @@ -151,7 +151,9 @@ class OVSAgentFixture(fixtures.Fixture): self.process_fixture = self.useFixture(ProcessFixture( test_name=self.test_name, process_name=self.NEUTRON_OVS_AGENT, - exec_name=self.NEUTRON_OVS_AGENT, + exec_name=spawn.find_executable( + 'ovs_agent.py', + path=os.path.join(base.ROOTDIR, 'common', 'agents')), config_filenames=config_filenames)) @@ -173,7 +175,6 @@ class L3AgentFixture(fixtures.Fixture): config_filenames = [self.neutron_cfg_fixture.filename, self.l3_agent_cfg_fixture.filename] - self.process_fixture = self.useFixture(ProcessFixture( test_name=self.test_name, process_name=self.NEUTRON_L3_AGENT, diff --git a/neutron/tests/fullstack/test_connectivity.py b/neutron/tests/fullstack/test_connectivity.py index a5f8ac3864f..0db5a3c8cd2 100644 --- a/neutron/tests/fullstack/test_connectivity.py +++ b/neutron/tests/fullstack/test_connectivity.py @@ -45,7 +45,7 @@ class TestConnectivitySameNetwork(base.BaseFullStackTestCase): # agent types present on machines. environment.HostDescription( l3_agent=self.l2_pop, - of_interface=self.of_interface) for _ in range(2)] + of_interface=self.of_interface) for _ in range(3)] env = environment.Environment( environment.EnvironmentDescription( network_type=self.network_type, @@ -67,9 +67,11 @@ class TestConnectivitySameNetwork(base.BaseFullStackTestCase): network['id'], tenant_uuid, self.safe_client)) - for i in range(2)] + for i in range(3)] for vm in vms: vm.block_until_boot() vms[0].block_until_ping(vms[1].ip) + vms[0].block_until_ping(vms[2].ip) + vms[1].block_until_ping(vms[2].ip) diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py index 3637142c343..8fde748fd33 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py @@ -107,6 +107,7 @@ class TestOvsNeutronAgent(object): group='SECURITYGROUP') cfg.CONF.set_default('quitting_rpc_timeout', 10, 'AGENT') cfg.CONF.set_default('prevent_arp_spoofing', False, 'AGENT') + cfg.CONF.set_default('local_ip', '127.0.0.1', 'OVS') mock.patch( 'neutron.agent.common.ovs_lib.OVSBridge.get_ports_attributes', return_value=[]).start() @@ -2910,3 +2911,21 @@ class TestValidateTunnelLocalIP(base.BaseTestCase): with testtools.ExpectedException(SystemExit): ovs_agent.validate_local_ip(FAKE_IP1) mock_get_device_by_ip.assert_called_once_with(FAKE_IP1) + + +class TestOvsAgentTunnelName(base.BaseTestCase): + def test_get_ip_in_hex_invalid_address(self): + self.assertIsNone( + ovs_agent.OVSNeutronAgent.get_ip_in_hex('a.b.c.d')) + + def test_get_tunnel_name_vxlan(self): + self.assertEqual( + 'vxlan-7f000002', + ovs_agent.OVSNeutronAgent.get_tunnel_name( + 'vxlan', '127.0.0.1', '127.0.0.2')) + + def test_get_tunnel_name_gre(self): + self.assertEqual( + 'gre-7f000002', + ovs_agent.OVSNeutronAgent.get_tunnel_name( + 'gre', '127.0.0.1', '127.0.0.2'))