Octet

What is rp_filter, what do the values 0, 1 and 2 mean, and when does it break things?

Show the answer

Say this first

rp_filter is reverse path filtering, the anti-spoofing check from RFC 3704. For each incoming packet the kernel looks up the route back to the source. 1 strict: the best route back must point out the same interface the packet arrived on, otherwise drop. 2 loose: the source only needs to be reachable through some interface. 0 off. The effective value per interface is the higher of conf.all and conf.<iface>. Strict mode silently drops asymmetric traffic on multihomed hosts.

Go deeper

Check it

Output
$ sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.ens224.rp_filter
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.ens224.rp_filter = 1

The kernel default is 0, but distributions ship their own value (1 or 2 are both common). Check, do not assume. conf.default only applies to interfaces created after it is set.

Seeing the drops

Shell
sysctl -w net.ipv4.conf.all.log_martians=1
dmesg | grep martian
nstat -az TcpExtIPReversePathFilter
ip route get 10.0.99.21 from 10.0.50.10 iif ens224
Output
IPv4: martian source 10.0.99.21 from 10.0.50.10, on dev ens224
RTNETLINK answers: Invalid cross-device link

In the martian log the first address is the destination and the second the source. "Invalid cross-device link" from ip route get is the same check failing.

Typical breakage

  • A server with a management NIC: monitoring traffic arrives on the management interface, but the route back to the monitoring subnet points out the data interface.
  • Two uplinks with traffic coming in on the one that is not the default.
  • Routers in an ECMP or asymmetric design.

Fixes, best first

  1. Make the routing symmetric (policy routing by source address).
  2. Loose mode (2) on that interface, which still drops sources with no route at all.
  3. 0 only when you understand why, for example inside some overlay or VPN designs.

Traps

  • Setting the interface value to 0 while all is 1 and believing it is off.
  • Disabling rp_filter everywhere instead of fixing the asymmetric routing.
How did you do?