From f08725014a44084f94e04a011f0143abb4736d24 Mon Sep 17 00:00:00 2001 From: Jakub Rozek Date: Mon, 27 Nov 2023 17:22:26 +0100 Subject: [PATCH 1/3] MPTCPRecipe: Fix disabling rp_filter rp_filter (reverse path filtering) is responsible for not allowing responding to packets on a different interface than the packet appeared on. It has to be disabled for MPTCP on IPv4. IPv6 doesn't have rp_filter on sysfs, but firewalld or ip6tables might configure it themselves. We do not run testing on machines where firewalld is enabled, nor do we use ip6tables so no issues should appear. --- lnst/Recipes/ENRT/MPTCPRecipe.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/lnst/Recipes/ENRT/MPTCPRecipe.py b/lnst/Recipes/ENRT/MPTCPRecipe.py index 02ab9e626..6361af5f1 100644 --- a/lnst/Recipes/ENRT/MPTCPRecipe.py +++ b/lnst/Recipes/ENRT/MPTCPRecipe.py @@ -102,8 +102,13 @@ def test_wide_configuration(self): f"ip route add {self.params.net1_ipv4} dev {host1.eth1.name}" f" via {save_addrs[host2.eth1][AF_INET]} prio 10000" ) - # Need to disable rp_filter on server side - host2.run("sysctl -w net.ipv4.conf.all.rp_filter=0") + + # allow hosts to respond to packets on a different interface + # than the one the packet originated from + for host in hosts: + host.run("sysctl -w net.ipv4.conf.all.rp_filter=0") + host.run(f"sysctl -w net.ipv4.conf.{host.eth0.name}.rp_filter=0") + host.run(f"sysctl -w net.ipv4.conf.{host.eth1.name}.rp_filter=0") if "ipv6" in self.params.ip_versions: host1.mptcp.add_endpoints(config.ips_for_device(host1.eth1, family=AF_INET6), flags=MPTCPFlags.MPTCP_PM_ADDR_FLAG_SUBFLOW) @@ -111,9 +116,11 @@ def test_wide_configuration(self): f"ip route add {self.params.net1_ipv6} dev {host1.eth1.name}" f" via {save_addrs[host2.eth1][AF_INET6]} prio 10000" ) - # ipv6 doesnt have rp_filter - # Configure limits + # TODO: For IPv6, rp_filter should be disabled via firewalld or ip6tables + # see https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-securing_network_access#sect-Security_Guide-Server_Security-Reverse_Path_Forwarding + + # set additional mptcp subflows to 1 host1.mptcp.subflows = 1 host2.mptcp.subflows = 1 @@ -136,17 +143,15 @@ def generate_test_wide_description(self, config: EnrtConfiguration): return desc - def test_wide_deconfiguration(self, config: EnrtConfiguration): - """ - - :param config: - :return: - """ + def test_wide_deconfiguration(self, config: EnrtConfiguration) -> None: for ep_dev in config.configured_devices: ep_dev.netns.mptcp.delete_all() - #reset rp_filter - self.matched.host2.run("sysctl -w net.ipv4.conf.all.rp_filter=1") + # use strict mode + for host in [self.matched.host1, self.matched.host2]: + host.run("sysctl -w net.ipv4.conf.all.rp_filter=1") + host.run(f"sysctl -w net.ipv4.conf.{host.eth0.name}.rp_filter=1") + host.run(f"sysctl -w net.ipv4.conf.{host.eth1.name}.rp_filter=1") super().test_wide_deconfiguration(config) From 2ddc0463ccfa278951e531ba496c45983aa017cd Mon Sep 17 00:00:00 2001 From: Jakub Rozek Date: Tue, 28 Nov 2023 15:43:40 +0100 Subject: [PATCH 2/3] Use dev in mptcp endpoint add Apparently there's a difference between "adding an mptcp endpoint" and "adding an mptcp endpoint to a device". pyroute doesn't support dev in the `mptcp endpoint add` call so we have to use a shell command. (https://github.com/svinota/pyroute2/issues/782) --- lnst/Recipes/ENRT/MPTCPRecipe.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lnst/Recipes/ENRT/MPTCPRecipe.py b/lnst/Recipes/ENRT/MPTCPRecipe.py index 6361af5f1..e8c29f442 100644 --- a/lnst/Recipes/ENRT/MPTCPRecipe.py +++ b/lnst/Recipes/ENRT/MPTCPRecipe.py @@ -6,7 +6,7 @@ from lnst.Common.IpAddress import interface_addresses from lnst.Controller import HostReq, DeviceReq, RecipeParam from lnst.Controller.Host import Host -from lnst.RecipeCommon.MPTCPManager import MPTCPManager, MPTCPFlags +from lnst.RecipeCommon.MPTCPManager import MPTCPManager from lnst.RecipeCommon.Ping.PingEndpoints import PingEndpoints from lnst.RecipeCommon.endpoints import EndpointPair, IPEndpoint from lnst.Recipes.ENRT.helpers import ip_endpoint_pairs @@ -96,7 +96,11 @@ def test_wide_configuration(self): # Configure endpoints only host1.eth1 if "ipv4" in self.params.ip_versions: - host1.mptcp.add_endpoints(config.ips_for_device(host1.eth1, family=AF_INET), flags=MPTCPFlags.MPTCP_PM_ADDR_FLAG_SUBFLOW) + host1.run( + f"ip mptcp endpoint add {save_addrs[host1.eth1][AF_INET]}" + f" dev {host1.eth1.name} subflow" + ) + # Need route on client side to populate forwarding table host1.run( f"ip route add {self.params.net1_ipv4} dev {host1.eth1.name}" @@ -111,7 +115,10 @@ def test_wide_configuration(self): host.run(f"sysctl -w net.ipv4.conf.{host.eth1.name}.rp_filter=0") if "ipv6" in self.params.ip_versions: - host1.mptcp.add_endpoints(config.ips_for_device(host1.eth1, family=AF_INET6), flags=MPTCPFlags.MPTCP_PM_ADDR_FLAG_SUBFLOW) + host1.run( + f"ip mptcp endpoint add {save_addrs[host1.eth1][AF_INET6]}" + f" dev {host1.eth1.name} subflow" + ) host1.run( f"ip route add {self.params.net1_ipv6} dev {host1.eth1.name}" f" via {save_addrs[host2.eth1][AF_INET6]} prio 10000" From c063c331f0a17de493a8046f198404ccb922c777 Mon Sep 17 00:00:00 2001 From: Jakub Rozek Date: Sat, 13 Jan 2024 14:36:52 +0100 Subject: [PATCH 3/3] BaseFlowMeasurementGenerator: Do not use client port in mptcp We are binding the client port to be consistent in multi-flow scenarios. However, our mptcp scenario opens 2 additional ports and not one. Only the first one binds to the specified client port, the second one is random. This would be fine, but there's a bug where mptcp doesn't close ports immediately (RHEL-21492). This raises an "Address already in use" error when the client attempts to bind the client port. We don't bind the client port to mitigate this issue, but also because, as specified before, it doesn't matter whether it's bound or not. --- .../MeasurementGenerators/BaseFlowMeasurementGenerator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lnst/Recipes/ENRT/MeasurementGenerators/BaseFlowMeasurementGenerator.py b/lnst/Recipes/ENRT/MeasurementGenerators/BaseFlowMeasurementGenerator.py index 20a788564..7a4c51b00 100644 --- a/lnst/Recipes/ENRT/MeasurementGenerators/BaseFlowMeasurementGenerator.py +++ b/lnst/Recipes/ENRT/MeasurementGenerators/BaseFlowMeasurementGenerator.py @@ -147,16 +147,16 @@ def _create_perf_flows( for endpoint_pair in endpoint_pairs: client, server = endpoint_pair for i in range(self.params.perf_parallel_processes): - port = next(port_iter) + server_port = client_port = next(port_iter) flows.append( self._create_perf_flow( perf_test, client.device, client.address, - port, + client_port if perf_test != "mptcp_stream" else None, server.device, server.address, - port, + server_port, msg_size, self.generator_cpupin(i), self.receiver_cpupin(i),