From c426f7336c8f8fe765bf8ba208e7747132e9a8f7 Mon Sep 17 00:00:00 2001 From: Slawek Kaplonski Date: Wed, 18 Nov 2020 16:30:33 +0100 Subject: [PATCH] [GRE] Add possibility to create GRE tunnels over IPv6 In case when IPv6 addresses are used for GRE tunnels, tunnel type set for the openvswitch interface should be "ip6gre" instead of "gre" which was set so far. This patch changes that so now Neutron configures correct GRE tunnel types. Change-Id: I557af0bcafac4583ad9726c9bf707cf1fb92ffc5 Closes-Bug: #1904564 (cherry picked from commit 80e6781bc2d2b39e547e80996743d29ec090c816) --- neutron/agent/common/ovs_lib.py | 16 +++++++++++ .../functional/agent/common/test_ovs_lib.py | 28 +++++++++++++++++++ .../tests/functional/agent/test_ovs_lib.py | 8 ++++-- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/neutron/agent/common/ovs_lib.py b/neutron/agent/common/ovs_lib.py index ca192a9f8d3..ab2119b2514 100644 --- a/neutron/agent/common/ovs_lib.py +++ b/neutron/agent/common/ovs_lib.py @@ -74,6 +74,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.""" @@ -100,6 +103,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 @@ -490,6 +500,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() @@ -513,6 +525,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 31698fb2714..69c396238da 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 from unittest 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 @@ -442,3 +443,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 392d387c48b..4de5f03a57c 100644 --- a/neutron/tests/functional/agent/test_ovs_lib.py +++ b/neutron/tests/functional/agent/test_ovs_lib.py @@ -211,11 +211,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(): @@ -233,7 +234,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)