]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Add an option to turn off DF for GRE and VXLAN tunnels
authorPierre Rognant <pierre@rognant.fr>
Wed, 28 May 2014 18:18:45 +0000 (14:18 -0400)
committerPierre Rognant <pierre@rognant.fr>
Sun, 8 Jun 2014 17:52:59 +0000 (13:52 -0400)
Modifications included allow to set a new option (dont_fragment) in
the ovs agent configuration file that can be used for (un-)setting the DF
bit on GRE or VXLAN tunnels. The default behaviour is not altered (DF on).

Change-Id: I17ecb00165990b72ab121c2688097139b3f2f157
Implements: blueprint neutron-ovs-agent-df-gre-vxlan

etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini
neutron/agent/linux/ovs_lib.py
neutron/plugins/ofagent/agent/ofa_neutron_agent.py
neutron/plugins/openvswitch/agent/ovs_neutron_agent.py
neutron/plugins/openvswitch/common/config.py
neutron/tests/unit/agent/linux/test_ovs_lib.py
neutron/tests/unit/ofagent/test_ofa_neutron_agent.py
neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py
neutron/tests/unit/openvswitch/test_ovs_tunnel.py

index 1718d4dd60ea460cdbb68df93404aaa0a57b9cfe..4beee58fa8ab31df7f5697d3027314760ba0fb9e 100644 (file)
 #
 # arp_responder = False
 
+# (BoolOpt) Set or un-set the don't fragment (DF) bit on outgoing IP packet
+# carrying GRE/VXLAN tunnel. The default value is True.
+#
+# dont_fragment = True
+
 [securitygroup]
 # Firewall driver for realizing neutron security group function.
 # firewall_driver = neutron.agent.firewall.NoopFirewallDriver
index 36b4faea45baa90c61dee504a2fd578e372aec98..2827dba19443089e9e3500e9ab34c74898c7e963 100644 (file)
@@ -239,7 +239,8 @@ class OVSBridge(BaseOVS):
 
     def add_tunnel_port(self, port_name, remote_ip, local_ip,
                         tunnel_type=p_const.TYPE_GRE,
-                        vxlan_udp_port=constants.VXLAN_UDP_PORT):
+                        vxlan_udp_port=constants.VXLAN_UDP_PORT,
+                        dont_fragment=True):
         vsctl_command = ["--", "--may-exist", "add-port", self.br_name,
                          port_name]
         vsctl_command.extend(["--", "set", "Interface", port_name,
@@ -248,6 +249,8 @@ class OVSBridge(BaseOVS):
             # Only set the VXLAN UDP port if it's not the default
             if vxlan_udp_port != constants.VXLAN_UDP_PORT:
                 vsctl_command.append("options:dst_port=%s" % vxlan_udp_port)
+        vsctl_command.append(("options:df_default=%s" %
+                             bool(dont_fragment)).lower())
         vsctl_command.extend(["options:remote_ip=%s" % remote_ip,
                               "options:local_ip=%s" % local_ip,
                               "options:in_key=flow",
index 16348e20d86e4b9769b724291cedcfeca2da6f87..92f66c81ef56bc3fc073a9c45dc47992c2ea5d4b 100644 (file)
@@ -267,6 +267,7 @@ class OFANeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
         self.local_ip = local_ip
         self.tunnel_count = 0
         self.vxlan_udp_port = cfg.CONF.AGENT.vxlan_udp_port
+        self.dont_fragment = cfg.CONF.AGENT.dont_fragment
         if self.enable_tunneling:
             self.setup_tunnel_br(tun_br)
         # Collect additional bridges to monitor
@@ -1030,7 +1031,8 @@ class OFANeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
                                              remote_ip,
                                              self.local_ip,
                                              tunnel_type,
-                                             self.vxlan_udp_port)
+                                             self.vxlan_udp_port,
+                                             self.dont_fragment)
         ofport_int = -1
         try:
             ofport_int = int(ofport)
index 9c2f146effcac4a041b94e898a2cf0c9aa2e8794..f654bfab1ad500b793e1fc46e822b12dc230b393 100644 (file)
@@ -223,6 +223,7 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin,
         self.local_ip = local_ip
         self.tunnel_count = 0
         self.vxlan_udp_port = cfg.CONF.AGENT.vxlan_udp_port
+        self.dont_fragment = cfg.CONF.AGENT.dont_fragment
         self.tun_br = None
         if self.enable_tunneling:
             self.setup_tunnel_br(tun_br)
@@ -1035,7 +1036,8 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin,
                                              remote_ip,
                                              self.local_ip,
                                              tunnel_type,
-                                             self.vxlan_udp_port)
+                                             self.vxlan_udp_port,
+                                             self.dont_fragment)
         ofport_int = -1
         try:
             ofport_int = int(ofport)
index f27be19b17cff36f9c3d1e71eade08fe4f7ade36..07ba94168921c5e7aa43cba78cc54c69e6bc0fea 100644 (file)
@@ -82,6 +82,9 @@ agent_opts = [
                        "remote mac and IPs and improve tunnel scalability")),
     cfg.BoolOpt('arp_responder', default=False,
                 help=_("Enable local ARP responder if it is supported")),
+    cfg.BoolOpt('dont_fragment', default=True,
+                help=_("Set or un-set the don't fragment (DF) bit on "
+                       "outgoing IP packet carrying GRE/VXLAN tunnel")),
 ]
 
 
index 951dd27bd98cef17d3979f5ea94e844940fda61e..81671bc011b7e661f5e59ae8acd75e862a82e7e6 100644 (file)
@@ -22,6 +22,7 @@ from neutron.agent.linux import utils
 from neutron.common import exceptions
 from neutron.openstack.common import jsonutils
 from neutron.openstack.common import uuidutils
+from neutron.plugins.common import constants as p_const
 from neutron.plugins.openvswitch.common import constants as const
 from neutron.tests import base
 from neutron.tests import tools
@@ -496,7 +497,8 @@ class OVS_Lib_Test(base.BaseTestCase):
         command = ["ovs-vsctl", self.TO, '--', "--may-exist", "add-port",
                    self.BR_NAME, pname]
         command.extend(["--", "set", "Interface", pname])
-        command.extend(["type=gre", "options:remote_ip=" + remote_ip,
+        command.extend(["type=gre", "options:df_default=true",
+                        "options:remote_ip=" + remote_ip,
                         "options:local_ip=" + local_ip,
                         "options:in_key=flow",
                         "options:out_key=flow"])
@@ -516,6 +518,41 @@ class OVS_Lib_Test(base.BaseTestCase):
 
         tools.verify_mock_calls(self.execute, expected_calls_and_values)
 
+    def test_add_vxlan_fragmented_tunnel_port(self):
+        pname = "tap99"
+        local_ip = "1.1.1.1"
+        remote_ip = "9.9.9.9"
+        ofport = "6"
+        vxlan_udp_port = "9999"
+        dont_fragment = False
+        command = ["ovs-vsctl", self.TO, '--', "--may-exist", "add-port",
+                   self.BR_NAME, pname]
+        command.extend(["--", "set", "Interface", pname])
+        command.extend(["type=" + p_const.TYPE_VXLAN,
+                        "options:dst_port=" + vxlan_udp_port,
+                        "options:df_default=false",
+                        "options:remote_ip=" + remote_ip,
+                        "options:local_ip=" + local_ip,
+                        "options:in_key=flow",
+                        "options:out_key=flow"])
+        # Each element is a tuple of (expected mock call, return_value)
+        expected_calls_and_values = [
+            (mock.call(command, root_helper=self.root_helper), None),
+            (mock.call(["ovs-vsctl", self.TO, "get",
+                        "Interface", pname, "ofport"],
+                       root_helper=self.root_helper),
+             ofport),
+        ]
+        tools.setup_mock_calls(self.execute, expected_calls_and_values)
+
+        self.assertEqual(
+            self.br.add_tunnel_port(pname, remote_ip, local_ip,
+                                    p_const.TYPE_VXLAN, vxlan_udp_port,
+                                    dont_fragment),
+            ofport)
+
+        tools.verify_mock_calls(self.execute, expected_calls_and_values)
+
     def test_add_patch_port(self):
         pname = "tap99"
         peer = "bar10"
index 97b48d45b35de72163664f485c4733cf876b2b68..b8d8569f5d16c66dae741961028e9d87c4cf1389 100644 (file)
@@ -643,7 +643,7 @@ class TestOFANeutronAgent(OFAAgentTestCase):
                 'gre-1', 'remote_ip', p_const.TYPE_GRE)
             add_tunnel_port_fn.assert_called_once_with(
                 'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
-                self.agent.vxlan_udp_port)
+                self.agent.vxlan_udp_port, self.agent.dont_fragment)
             log_error_fn.assert_called_once_with(
                 _("Failed to set-up %(type)s tunnel port to %(ip)s"),
                 {'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
@@ -660,7 +660,7 @@ class TestOFANeutronAgent(OFAAgentTestCase):
                 'gre-1', 'remote_ip', p_const.TYPE_GRE)
             add_tunnel_port_fn.assert_called_once_with(
                 'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
-                self.agent.vxlan_udp_port)
+                self.agent.vxlan_udp_port, self.agent.dont_fragment)
             log_exc_fn.assert_called_once_with(
                 _("ofport should have a value that can be "
                   "interpreted as an integer"))
index eb2b536be83e1b38831d434392ba8b046d475caa..7dc65bb20ac90db63325f98e488a0e8947690c28 100644 (file)
@@ -729,7 +729,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
                 'gre-1', 'remote_ip', p_const.TYPE_GRE)
             add_tunnel_port_fn.assert_called_once_with(
                 'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
-                self.agent.vxlan_udp_port)
+                self.agent.vxlan_udp_port, self.agent.dont_fragment)
             log_error_fn.assert_called_once_with(
                 _("Failed to set-up %(type)s tunnel port to %(ip)s"),
                 {'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
@@ -746,7 +746,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
                 'gre-1', 'remote_ip', p_const.TYPE_GRE)
             add_tunnel_port_fn.assert_called_once_with(
                 'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
-                self.agent.vxlan_udp_port)
+                self.agent.vxlan_udp_port, self.agent.dont_fragment)
             log_exc_fn.assert_called_once_with(
                 _("ofport should have a value that can be "
                   "interpreted as an integer"))
@@ -755,6 +755,23 @@ class TestOvsNeutronAgent(base.BaseTestCase):
                 {'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
             self.assertEqual(ofport, 0)
 
+    def test_setup_tunnel_port_error_negative_df_disabled(self):
+        with contextlib.nested(
+            mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
+                              return_value='-1'),
+            mock.patch.object(ovs_neutron_agent.LOG, 'error')
+        ) as (add_tunnel_port_fn, log_error_fn):
+            self.agent.dont_fragment = False
+            ofport = self.agent.setup_tunnel_port(
+                'gre-1', 'remote_ip', p_const.TYPE_GRE)
+            add_tunnel_port_fn.assert_called_once_with(
+                'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
+                self.agent.vxlan_udp_port, self.agent.dont_fragment)
+            log_error_fn.assert_called_once_with(
+                _("Failed to set-up %(type)s tunnel port to %(ip)s"),
+                {'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
+            self.assertEqual(ofport, 0)
+
     def test_tunnel_sync_with_ovs_plugin(self):
         fake_tunnel_details = {'tunnels': [{'id': '42',
                                             'ip_address': '100.101.102.103'}]}
index 55afce3aa79c1dd5059af4f0fe78f7f932ad5a97..c192cae650b38287ffe57d8b0d2e7305d9dc3d18 100644 (file)
@@ -508,7 +508,7 @@ class TunnelTest(base.BaseTestCase):
         self.mock_tun_bridge.add_tunnel_port.return_value = tunnel_port
         self.mock_tun_bridge_expected += [
             mock.call.add_tunnel_port('gre-1', '10.0.10.1', '10.0.0.1',
-                                      'gre', 4789),
+                                      'gre', 4789, True),
             mock.call.add_flow(priority=1, in_port=tunnel_port,
                                actions='resubmit(,2)')
         ]