Message ID | 20211130004905.4146-1-yepeilin.cs@gmail.com |
---|---|
State | New |
Headers | show |
Series | [net,v2] selftests/fib_tests: ping from dummy0 in fib_rp_filter_test() | expand |
On 11/30/21 5:47 PM, Peilin Ye wrote: > From: Peilin Ye <peilin.ye@bytedance.com> > > Currently rp_filter tests in fib_tests.sh:fib_rp_filter_test() are > failing. ping sockets are bound to dummy1 using the "-I" option > (SO_BINDTODEVICE), but socket lookup is failing when receiving ping > replies, since the routing table thinks they belong to dummy0. > > For example, suppose ping is using a SOCK_RAW socket for ICMP messages. > When receiving ping replies, in __raw_v4_lookup(), sk->sk_bound_dev_if > is 3 (dummy1), but dif (skb_rtable(skb)->rt_iif) says 2 (dummy0), so the > raw_sk_bound_dev_eq() check fails. Similar things happen in > ping_lookup() for SOCK_DGRAM sockets. > > These tests used to pass due to a bug [1] in iputils, where "ping -I" > actually did not bind ICMP message sockets to device. The bug has been > fixed by iputils commit f455fee41c07 ("ping: also bind the ICMP socket > to the specific device") in 2016, which is why our rp_filter tests > started to fail. See [2] . > > Fixing the tests while keeping everything in one netns turns out to be > nontrivial. Rework the tests and build the following topology: > > ┌─────────────────────────────┐ ┌─────────────────────────────┐ > │ network namespace 1 (ns1) │ │ network namespace 2 (ns2) │ > │ │ │ │ > │ ┌────┐ ┌─────┐ │ │ ┌─────┐ ┌────┐ │ > │ │ lo │<───>│veth1│<────────┼────┼─>│veth2│<──────────>│ lo │ │ > │ └────┘ ├─────┴──────┐ │ │ ├─────┴──────┐ └────┘ │ > │ │192.0.2.1/24│ │ │ │192.0.2.1/24│ │ > │ └────────────┘ │ │ └────────────┘ │ > └─────────────────────────────┘ └─────────────────────────────┘ > if the intention of the tests is to validate that rp_filter = 1 works as designed, then I suggest a simpler test. 2 namespaces, 2 veth pairs. Request goes through one interface, and the response comes in the other via routing in ns2. ns1 would see the response coming in the 'wrong' interface and drops it.
Hi David, On Wed, Dec 01, 2021 at 11:00:26AM -0700, David Ahern wrote: > On 11/30/21 5:47 PM, Peilin Ye wrote: > > ┌─────────────────────────────┐ ┌─────────────────────────────┐ > > │ network namespace 1 (ns1) │ │ network namespace 2 (ns2) │ > > │ │ │ │ > > │ ┌────┐ ┌─────┐ │ │ ┌─────┐ ┌────┐ │ > > │ │ lo │<───>│veth1│<────────┼────┼─>│veth2│<──────────>│ lo │ │ > > │ └────┘ ├─────┴──────┐ │ │ ├─────┴──────┐ └────┘ │ > > │ │192.0.2.1/24│ │ │ │192.0.2.1/24│ │ > > │ └────────────┘ │ │ └────────────┘ │ > > └─────────────────────────────┘ └─────────────────────────────┘ > > if the intention of the tests is to validate that rp_filter = 1 works as > designed, then I suggest a simpler test. 2 namespaces, 2 veth pairs. > Request goes through one interface, and the response comes in the other > via routing in ns2. ns1 would see the response coming in the 'wrong' > interface and drops it. Quite the opposite - the goal is to make sure that commit 66f8209547cc ("fib: relax source validation check for loopback packets") _prevents_ packets from being dropped when rp_filter = 1 in this corner case, as I mentioned in the commit message. In order to test this corner case, I need a packet that: 1. was received on lo; 2. has a local source IP address (other than lo's 127.0.0.1/8, which is 192.0.2.1 in this case); 3. has no dst attached to it (in this case since it was redirected from veth). See __fib_validate_source(): + dev_match = dev_match || (res.type == RTN_LOCAL && + dev == net->loopback_dev); ^^^^^^^^^^^^ This relaxed check only applies to lo, and I do need to redirect packets from veth ingress to lo ingress in order to trigger this. Thanks, Peilin Ye
diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index 5abe92d55b69..b8bceae00f8e 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -453,15 +453,19 @@ fib_rp_filter_test() $NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1 $NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1 + $NS_EXEC tc qd add dev dummy0 parent root handle 1: fq_codel + $NS_EXEC tc filter add dev dummy0 parent 1: protocol arp basic action mirred egress redirect dev dummy1 + $NS_EXEC tc filter add dev dummy0 parent 1: protocol ip basic action mirred egress redirect dev dummy1 + $NS_EXEC tc qd add dev dummy1 parent root handle 1: fq_codel $NS_EXEC tc filter add dev dummy1 parent 1: protocol arp basic action mirred egress redirect dev lo $NS_EXEC tc filter add dev dummy1 parent 1: protocol ip basic action mirred egress redirect dev lo set +e - run_cmd "ip netns exec ns1 ping -I dummy1 -w1 -c1 198.51.100.1" + run_cmd "ip netns exec ns1 ping -I dummy0 -w1 -c1 198.51.100.1" log_test $? 0 "rp_filter passes local packets" - run_cmd "ip netns exec ns1 ping -I dummy1 -w1 -c1 127.0.0.1" + run_cmd "ip netns exec ns1 ping -I dummy0 -w1 -c1 127.0.0.1" log_test $? 0 "rp_filter passes loopback packets" cleanup