OFA agent: use hexadecimal IP address in tunnel port name

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
This commit is contained in:
fumihiko kakuma 2014-03-18 11:36:29 +09:00
parent d232f5ba28
commit 7cdd3b4d74
2 changed files with 88 additions and 24 deletions

View 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)

View 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):