Scenario: IPVS is used to route traffic to various ports on some VIP to different sets of backend servers. Those backend servers are configured with local routes for that VIP in order to accept incoming packets as local INPUT.
$ ip route add local 194.197.235.245 dev lo
Problem: The backend servers cannot themselves connect to the other services on the same IPVS VIP, because the VIP is locally routed.
$ ip ro get 194.197.235.245
local 194.197.235.245 dev lo table local src 194.197.235.245
cache <local>
Leave the local VIP route in the local
route table, but bypass it for output route lookups for the VIP:
# move the local table lookup later in the rules
$ ip rule add pref 100 lookup local
$ ip rule del pref 0 lookup local
# add normal local routes for the VIP
$ ip -4 route add local 194.197.235.245 dev eth-test
$ ip -6 route add local 2001:2060:41:f0::f5 dev eth-test
# bypass the local route lookup for output route lookups
$ ip -4 rule add to 194.197.235.245 iif lo pref 10 table main
$ ip -6 rule add to 2001:2060:41:f0::f5 iif lo pref 10 table main
Unidirection local routes no longer work in newer Linux versions:
$ ip rule add to 194.197.235.245 iif eth-test table 100
$ ip route add local 194.197.235.245 dev eth-test table 100
The outgoing/incoming packets are routed correctly, but the return packets are dropped:
$ ip route get 194.197.235.245
194.197.235.245 via 10.100.0.1 dev eth-test src 10.100.100.38
cache
$ sudo ip route get 194.197.235.245 from 192.0.2.1 iif eth-test
local 194.197.235.245 from 192.0.2.1 dev lo table 100
cache <local> iif eth-test
$ sudo ip route get 192.0.2.1 from 194.197.235.245 # OUTPUT path when iif is unspecified
RTNETLINK answers: Invalid argument
This is because ip_route_output
now does a lookup on the src IP, and expects it to have a local route in the local routing table:
- https://elixir.bootlin.com/linux/v4.9.184/source/net/ipv4/route.c#L2669
- https://elixir.bootlin.com/linux/v4.9.184/source/net/ipv4/route.c#L2256
This shows up in netstat -s | grep 'dropped because of missing route'
, and the ktrace stopping on ip_route_output_flow
=> __ip_dev_find
=> fib_table_lookup
.