diff --git a/neutron/agent/common/ovs_lib.py b/neutron/agent/common/ovs_lib.py index 99cbf488de4..15f68f043da 100644 --- a/neutron/agent/common/ovs_lib.py +++ b/neutron/agent/common/ovs_lib.py @@ -71,6 +71,9 @@ _SENTINEL = object() CTRL_RATE_LIMIT_MIN = 100 CTRL_BURST_LIMIT_MIN = 25 +# TODO(slaweq): move this to neutron_lib.constants +TYPE_GRE_IP6 = 'ip6gre' + def _ovsdb_result_pending(result): """Return True if ovsdb indicates the result is still pending.""" @@ -97,6 +100,13 @@ def _ovsdb_retry(fn): return wrapped +def get_gre_tunnel_port_type(remote_ip, local_ip): + if (common_utils.get_ip_version(remote_ip) == p_const.IP_VERSION_6 or + common_utils.get_ip_version(local_ip) == p_const.IP_VERSION_6): + return TYPE_GRE_IP6 + return p_const.TYPE_GRE + + class VifPort(object): def __init__(self, port_name, ofport, vif_id, vif_mac, switch): self.port_name = port_name @@ -514,6 +524,8 @@ class OVSBridge(BaseOVS): dont_fragment=True, tunnel_csum=False, tos=None): + if tunnel_type == p_const.TYPE_GRE: + tunnel_type = get_gre_tunnel_port_type(remote_ip, local_ip) attrs = [('type', tunnel_type)] # TODO(twilson) This is an OrderedDict solely to make a test happy options = collections.OrderedDict() @@ -537,6 +549,10 @@ class OVSBridge(BaseOVS): options['csum'] = str(tunnel_csum).lower() if tos: options['tos'] = str(tos) + if tunnel_type == TYPE_GRE_IP6: + # NOTE(slaweq) According to the OVS documentation L3 GRE tunnels + # over IPv6 are not supported. + options['packet_type'] = 'legacy' attrs.append(('options', options)) return self.add_port(port_name, *attrs) diff --git a/neutron/tests/functional/agent/common/test_ovs_lib.py b/neutron/tests/functional/agent/common/test_ovs_lib.py index b39f7d219b9..81bb1f38d6c 100644 --- a/neutron/tests/functional/agent/common/test_ovs_lib.py +++ b/neutron/tests/functional/agent/common/test_ovs_lib.py @@ -16,6 +16,7 @@ import functools import mock +from neutron_lib import constants as p_const from neutron_lib.services.qos import constants as qos_constants from oslo_utils import uuidutils import six @@ -437,3 +438,30 @@ class BaseOVSTestCase(base.BaseSudoTestCase): self.assertEqual(8000, self.ovs.db_get_val('Controller', self.br_name, 'inactivity_probe')) + + def test_add_gre_tunnel_port(self): + ipv4_tunnel_port = "test-ipv4-port" + ipv6_tunnel_port = "test-ipv6-port" + self._create_bridge() + self.ovs.add_tunnel_port( + ipv4_tunnel_port, "10.0.0.1", "10.0.0.2", + tunnel_type=p_const.TYPE_GRE) + self.ovs.add_tunnel_port( + ipv6_tunnel_port, "2001:db8::1", "2001:db8:2", + tunnel_type=p_const.TYPE_GRE) + interfaces = self.ovs.get_ports_attributes( + "Interface", columns=["name", "type", "options"], + if_exists=True) + + ipv4_port_type = None + ipv6_port_type = None + ipv6_port_options = {} + for interface in interfaces: + if interface['name'] == ipv4_tunnel_port: + ipv4_port_type = interface['type'] + elif interface['name'] == ipv6_tunnel_port: + ipv6_port_type = interface['type'] + ipv6_port_options = interface['options'] + self.assertEqual(p_const.TYPE_GRE, ipv4_port_type) + self.assertEqual(ovs_lib.TYPE_GRE_IP6, ipv6_port_type) + self.assertEqual('legacy', ipv6_port_options.get('packet_type')) diff --git a/neutron/tests/functional/agent/test_ovs_lib.py b/neutron/tests/functional/agent/test_ovs_lib.py index c48ca9947c6..d7605d420b5 100644 --- a/neutron/tests/functional/agent/test_ovs_lib.py +++ b/neutron/tests/functional/agent/test_ovs_lib.py @@ -212,11 +212,12 @@ class OVSBridgeTestCase(OVSBridgeTestBase): self.br.br_name, 'datapath_id', dpid) self.assertIn(dpid, self.br.get_datapath_id()) - def _test_add_tunnel_port(self, attrs): + def _test_add_tunnel_port(self, attrs, + expected_tunnel_type=const.TYPE_GRE): port_name = utils.get_rand_device_name(net_helpers.PORT_PREFIX) self.br.add_tunnel_port(port_name, attrs['remote_ip'], attrs['local_ip']) - self.assertEqual('gre', + self.assertEqual(expected_tunnel_type, self.ovs.db_get_val('Interface', port_name, 'type')) options = self.ovs.db_get_val('Interface', port_name, 'options') for attr, val in attrs.items(): @@ -234,7 +235,8 @@ class OVSBridgeTestCase(OVSBridgeTestBase): 'remote_ip': '2001:db8:200::1', 'local_ip': '2001:db8:100::1', } - self._test_add_tunnel_port(attrs) + self._test_add_tunnel_port( + attrs, expected_tunnel_type=ovs_lib.TYPE_GRE_IP6) def test_add_tunnel_port_custom_port(self): port_name = utils.get_rand_device_name(net_helpers.PORT_PREFIX)