Skip to content

Commit 9a73a52

Browse files
committed
fix port forward with strict RPF and multi networks
As it turns out our routing setup doesn't play nice with strict Reverse Path Forwarding. The issue is that the incoming packages are routed in via one bridge but may be routed out from the container via another bridge and thus get dropped by strict filtering. The fix is simple, set the filter to loose mode. From the sysctl doc: If using asymmetric routing or other complicated routing, then loose mode is recommended. This applies to us so it seems like the proper fix. Added tests to ensure it works. Fixes https://issues.redhat.com/browse/RHEL-32500 Signed-off-by: Paul Holzinger <pholzing@redhat.com>
1 parent 3ca4655 commit 9a73a52

File tree

4 files changed

+52
-1
lines changed

4 files changed

+52
-1
lines changed

src/network/bridge.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,17 @@ fn create_interfaces(
570570
CoreUtils::apply_sysctl_value(br_accept_ra, "0")?;
571571
}
572572

573+
// Disable strict reverse path search validation. On RHEL it is set to strict mode
574+
// which breaks port forwarding when multiple networks are attached as the package
575+
// may be routed over a different interface on the reverse path.
576+
// As documented for the sysctl for complicated or asymmetric routing loose mode (2)
577+
// is recommended.
578+
let br_rp_filter = format!(
579+
"/proc/sys/net/ipv4/conf/{}/rp_filter",
580+
&data.bridge_interface_name
581+
);
582+
CoreUtils::apply_sysctl_value(br_rp_filter, "2")?;
583+
573584
let link = host
574585
.get_link(netlink::LinkID::Name(
575586
data.bridge_interface_name.to_string(),
@@ -690,6 +701,13 @@ fn create_veth_pair<'fd>(
690701
&data.container_interface_name
691702
);
692703
core_utils::CoreUtils::apply_sysctl_value(enable_arp_notify, "1")?;
704+
705+
// disable strict reverse path search validation
706+
let rp_filter = format!(
707+
"/proc/sys/net/ipv4/conf/{}/rp_filter",
708+
&data.container_interface_name
709+
);
710+
CoreUtils::apply_sysctl_value(rp_filter, "2")?;
693711
Ok::<(), NetavarkError>(())
694712
});
695713
// check the result and return error

test/100-bridge-iptables.bats

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,35 @@ fw_driver=iptables
554554
test_port_fw ip=6 proto=udp hostip="fd65:8371:648b:0c06::1"
555555
}
556556

557+
# Test that port forwarding works with strict Reverse Path Forwarding enabled on the host
558+
@test "$fw_driver - port forwarding with two networks and RPF - tcp" {
559+
# First, enable strict RPF on host/container ns.
560+
run_in_host_netns sysctl -w net.ipv4.conf.all.rp_filter=1
561+
run_in_host_netns sysctl -w net.ipv4.conf.default.rp_filter=1
562+
run_in_container_netns sysctl -w net.ipv4.conf.all.rp_filter=1
563+
run_in_container_netns sysctl -w net.ipv4.conf.default.rp_filter=1
564+
565+
# We need a dummy interface with a host ip,
566+
# if we connect directly to the bridge ip it doesn't reproduce.
567+
add_dummy_interface_on_host dummy0 "10.0.0.1/24"
568+
569+
run_netavark --file ${TESTSDIR}/testfiles/two-networks.json setup $(get_container_netns_path)
570+
result="$output"
571+
572+
run_in_host_netns cat /proc/sys/net/ipv4/conf/podman2/rp_filter
573+
assert "2" "rp_filter podman2 bridge"
574+
run_in_host_netns cat /proc/sys/net/ipv4/conf/podman3/rp_filter
575+
assert "2" "rp_filter podman3 bridge"
576+
577+
run_in_container_netns cat /proc/sys/net/ipv4/conf/eth0/rp_filter
578+
assert "2" "rp_filter eth0 interface"
579+
run_in_container_netns cat /proc/sys/net/ipv4/conf/eth1/rp_filter
580+
assert "2" "rp_filter eth1 interface"
581+
582+
# Important: Use the "host" ip here and not localhost or bridge ip.
583+
run_nc_test "0" "tcp" 8080 "10.0.0.1" 8080
584+
}
585+
557586
@test "bridge ipam none" {
558587
read -r -d '\0' config <<EOF
559588
{
@@ -789,6 +818,8 @@ EOF
789818
# when the sysctl value is already set correctly we should not error
790819
run_in_host_netns sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
791820
run_in_container_netns sh -c "echo 1 > /proc/sys/net/ipv4/conf/default/arp_notify"
821+
run_in_host_netns sh -c "echo 2 > /proc/sys/net/ipv4/conf/default/rp_filter"
822+
run_in_container_netns sh -c "echo 2 > /proc/sys/net/ipv4/conf/default/rp_filter"
792823
run_in_host_netns mount -t proc -o ro,nosuid,nodev,noexec proc /proc
793824

794825
run_netavark --file ${TESTSDIR}/testfiles/simplebridge.json setup $(get_container_netns_path)

test/250-bridge-nftables.bats

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,8 @@ EOF
696696
# when the sysctl value is already set correctly we should not error
697697
run_in_host_netns sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
698698
run_in_container_netns sh -c "echo 1 > /proc/sys/net/ipv4/conf/default/arp_notify"
699+
run_in_host_netns sh -c "echo 2 > /proc/sys/net/ipv4/conf/default/rp_filter"
700+
run_in_container_netns sh -c "echo 2 > /proc/sys/net/ipv4/conf/default/rp_filter"
699701
run_in_host_netns mount -t proc -o ro,nosuid,nodev,noexec proc /proc
700702

701703
run_netavark --file ${TESTSDIR}/testfiles/simplebridge.json setup $(get_container_netns_path)

test/testfiles/two-networks.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"container_name": "heuristic_archimedes",
44
"port_mappings": [
55
{
6-
"host_ip": "127.0.0.1",
6+
"host_ip": "",
77
"container_port": 8080,
88
"host_port": 8080,
99
"range": 1,

0 commit comments

Comments
 (0)