]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
OFA agent: use hexadecimal IP address in tunnel port name
authorfumihiko kakuma <kakuma@valinux.co.jp>
Tue, 18 Mar 2014 02:36:29 +0000 (11:36 +0900)
committerfumihiko kakuma <kakuma@valinux.co.jp>
Wed, 2 Apr 2014 03:09:24 +0000 (12:09 +0900)
The remote IP address is used to form the tunnel port name
With some OVS/Linux combinations there is a 15 character limit
on port names, so a name like 'gre-192.168.10.10' does not work.
This fix uses the shorter hexadecimal representation of
the IP address instead.
This problem was reported and fixed for OVS agent.

Closes-Bug: 1294474

Change-Id: Ieab1eb8a5c430f69aff61a317cc28f23ba95ad2d

neutron/plugins/ofagent/agent/ofa_neutron_agent.py
neutron/tests/unit/ofagent/test_ofa_neutron_agent.py

index 7c5beee176746d97ac49879a5d112a6307d82a63..0158e87e9f52fd2e2f45e6035c39c5a3b0ac8803 100644 (file)
@@ -19,6 +19,7 @@
 
 import time
 
+import netaddr
 from oslo.config import cfg
 from ryu.app.ofctl import api as ryu_api
 from ryu.base import app_manager
@@ -297,6 +298,14 @@ class OFANeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
         except Exception:
             LOG.exception(_("Failed reporting state!"))
 
+    def _create_tunnel_port_name(self, tunnel_type, ip_address):
+        try:
+            ip_hex = '%08x' % netaddr.IPAddress(ip_address, version=4)
+            return '%s-%s' % (tunnel_type, ip_hex)
+        except Exception:
+            LOG.warn(_("Unable to create tunnel port. Invalid remote IP: %s"),
+                     ip_address)
+
     def ryu_send_msg(self, msg):
         result = ryu_api.send_msg(self.ryuapp, msg)
         LOG.info(_("ryu send_msg() result: %s"), result)
@@ -376,7 +385,6 @@ class OFANeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
         if not self.enable_tunneling:
             return
         tunnel_ip = kwargs.get('tunnel_ip')
-        tunnel_id = kwargs.get('tunnel_id', tunnel_ip)
         tunnel_type = kwargs.get('tunnel_type')
         if not tunnel_type:
             LOG.error(_("No tunnel_type specified, cannot create tunnels"))
@@ -386,7 +394,9 @@ class OFANeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
             return
         if tunnel_ip == self.local_ip:
             return
-        tun_name = '%s-%s' % (tunnel_type, tunnel_id)
+        tun_name = self._create_tunnel_port_name(tunnel_type, tunnel_ip)
+        if not tun_name:
+            return
         self.setup_tunnel_port(tun_name, tunnel_ip, tunnel_type)
 
     def create_rpc_dispatcher(self):
@@ -1050,19 +1060,6 @@ class OFANeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
                     self.ryu_send_msg(msg)
         return ofport
 
-    def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
-        # Check if this tunnel port is still used
-        for lvm in self.local_vlan_map.values():
-            if tun_ofport in lvm.tun_ofports:
-                break
-        # If not, remove it
-        else:
-            for remote_ip, ofport in self.tun_br_ofports[tunnel_type].items():
-                if ofport == tun_ofport:
-                    port_name = '%s-%s' % (tunnel_type, remote_ip)
-                    self.tun_br.delete_port(port_name)
-                    self.tun_br_ofports[tunnel_type].pop(remote_ip, None)
-
     def treat_devices_added(self, devices):
         resync = False
         self.sg_agent.prepare_devices_filter(devices)
@@ -1214,8 +1211,10 @@ class OFANeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
                 tunnels = details['tunnels']
                 for tunnel in tunnels:
                     if self.local_ip != tunnel['ip_address']:
-                        tunnel_id = tunnel.get('id', tunnel['ip_address'])
-                        tun_name = '%s-%s' % (tunnel_type, tunnel_id)
+                        tun_name = self._create_tunnel_port_name(
+                            tunnel_type, tunnel['ip_address'])
+                        if not tun_name:
+                            continue
                         self.setup_tunnel_port(tun_name,
                                                tunnel['ip_address'],
                                                tunnel_type)
index 71afcd213d5b1bbca3ed71410613e0f26ae207f4..34ade5994e844cbc9bc7763f26114944f9b1c0d2 100644 (file)
@@ -19,6 +19,7 @@
 import contextlib
 
 import mock
+import netaddr
 from oslo.config import cfg
 import testtools
 
@@ -42,11 +43,11 @@ class OFAAgentTestCase(base.BaseTestCase):
 
     def setUp(self):
         super(OFAAgentTestCase, self).setUp()
+        self.fake_oflib_of = fake_oflib.patch_fake_oflib_of().start()
+        self.mod_agent = importutils.import_module(self._AGENT_NAME)
         cfg.CONF.set_default('firewall_driver',
                              'neutron.agent.firewall.NoopFirewallDriver',
                              group='SECURITYGROUP')
-        self.fake_oflib_of = fake_oflib.patch_fake_oflib_of().start()
-        self.mod_agent = importutils.import_module(self._AGENT_NAME)
         self.ryuapp = mock.Mock()
         cfg.CONF.register_cli_opts([
             cfg.StrOpt('ofp-listen-host', default='',
@@ -375,17 +376,14 @@ class TestOFANeutronAgent(OFAAgentTestCase):
             )
 
     def test_network_delete(self):
-        with contextlib.nested(
-            mock.patch.object(self.agent, "reclaim_local_vlan"),
-            mock.patch.object(self.agent.tun_br, "cleanup_tunnel_port")
-        ) as (recl_fn, clean_tun_fn):
+        with mock.patch.object(self.agent,
+                               "reclaim_local_vlan") as recl_fn:
             self.agent.network_delete("unused_context",
                                       network_id="123")
             self.assertFalse(recl_fn.called)
             self.agent.local_vlan_map["123"] = "LVM object"
             self.agent.network_delete("unused_context",
                                       network_id="123")
-            self.assertFalse(clean_tun_fn.called)
             recl_fn.assert_called_with("123")
 
     def test_port_update(self):
@@ -616,6 +614,73 @@ class TestOFANeutronAgent(OFAAgentTestCase):
                 {'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
             self.assertEqual(ofport, 0)
 
+    def _create_tunnel_port_name(self, tunnel_ip, tunnel_type):
+        tunnel_ip_hex = '%08x' % netaddr.IPAddress(tunnel_ip, version=4)
+        return '%s-%s' % (tunnel_type, tunnel_ip_hex)
+
+    def test_tunnel_sync_with_valid_ip_address_and_gre_type(self):
+        tunnel_ip = '100.101.102.103'
+        self.agent.tunnel_types = ['gre']
+        tun_name = self._create_tunnel_port_name(tunnel_ip,
+                                                 self.agent.tunnel_types[0])
+        fake_tunnel_details = {'tunnels': [{'ip_address': tunnel_ip}]}
+        with contextlib.nested(
+            mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
+                              return_value=fake_tunnel_details),
+            mock.patch.object(self.agent, 'setup_tunnel_port')
+        ) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
+            self.agent.tunnel_sync()
+            expected_calls = [mock.call(tun_name, tunnel_ip,
+                                        self.agent.tunnel_types[0])]
+            setup_tunnel_port_fn.assert_has_calls(expected_calls)
+
+    def test_tunnel_sync_with_valid_ip_address_and_vxlan_type(self):
+        tunnel_ip = '100.101.31.15'
+        self.agent.tunnel_types = ['vxlan']
+        tun_name = self._create_tunnel_port_name(tunnel_ip,
+                                                 self.agent.tunnel_types[0])
+        fake_tunnel_details = {'tunnels': [{'ip_address': tunnel_ip}]}
+        with contextlib.nested(
+            mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
+                              return_value=fake_tunnel_details),
+            mock.patch.object(self.agent, 'setup_tunnel_port')
+        ) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
+            self.agent.tunnel_sync()
+            expected_calls = [mock.call(tun_name, tunnel_ip,
+                                        self.agent.tunnel_types[0])]
+            setup_tunnel_port_fn.assert_has_calls(expected_calls)
+
+    def test_tunnel_sync_invalid_ip_address(self):
+        tunnel_ip = '100.100.100.100'
+        self.agent.tunnel_types = ['vxlan']
+        tun_name = self._create_tunnel_port_name(tunnel_ip,
+                                                 self.agent.tunnel_types[0])
+        fake_tunnel_details = {'tunnels': [{'ip_address': '300.300.300.300'},
+                                           {'ip_address': tunnel_ip}]}
+        with contextlib.nested(
+            mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
+                              return_value=fake_tunnel_details),
+            mock.patch.object(self.agent, 'setup_tunnel_port')
+        ) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
+            self.agent.tunnel_sync()
+            setup_tunnel_port_fn.assert_called_once_with(
+                tun_name, tunnel_ip, self.agent.tunnel_types[0])
+
+    def test_tunnel_update(self):
+        tunnel_ip = '10.10.10.10'
+        self.agent.tunnel_types = ['gre']
+        tun_name = self._create_tunnel_port_name(tunnel_ip,
+                                                 self.agent.tunnel_types[0])
+        kwargs = {'tunnel_ip': tunnel_ip,
+                  'tunnel_type': self.agent.tunnel_types[0]}
+        self.agent.setup_tunnel_port = mock.Mock()
+        self.agent.enable_tunneling = True
+        self.agent.l2_pop = False
+        self.agent.tunnel_update(context=None, **kwargs)
+        expected_calls = [mock.call(tun_name, tunnel_ip,
+                                    self.agent.tunnel_types[0])]
+        self.agent.setup_tunnel_port.assert_has_calls(expected_calls)
+
 
 class AncillaryBridgesTest(OFAAgentTestCase):