Interface following a link

High level tools like NetworkManager usually remove address and route on "linkdown" links (ie: with the NO-CARRIER flag displayed on the interface). So if the interface is managed by such tool, one can expect for its route to appear and disappear when plugged and unplugged.

I understand using NetworkManager might be too intrusive with a dynamic routing protocol used at the same time and so might not be the best idea.

But actually the kernel routing stack already provides such feature, without having to modify any address or route: ignore_routes_with_linkdown.

As a few other entries, this one which appeared in kernel 4.2 (so available in Debian 10's kernel 4.19) and was shown then in kernelnewbies.org when it appeared, has been documented only since kernel 5.11:

ignore_routes_with_linkdown - BOOLEAN
Ignore routes whose link is down when performing a FIB lookup.

So if the interface is called mgmt0 and the route it provides should be used only when a carrier is detected on it, one should simply do:

sysctl -w net.ipv4.conf.mgmt0.ignore_routes_with_linkdown=1

or put this in /etc/sysctl.conf.

Now when this interface still kept administratively up is disconnected, the route entry displayed back by ip route would show the flags dead linkdown instead of the single flag linkdown to tell userland that indeed this route is currently ignored during a FIB lookup.

Note: for an interface to detect a link, it has to be powered up. So it must stay administratively up. If it was brought down when the carrier is lost, it couldn't be brought back up automatically later on carrier detect, since there would be no such detection anymore.


Complete example:

ip link add name vethtest1 up type veth peer name vethtest1peer
ip link add name vethtest2 up type veth peer name vethtest2peer
ip link set dev vethtest2peer up
ip address add 192.0.2.2/25 dev vethtest1
ip address add 192.0.2.3/24 dev vethtest2

Setting the addresses installs the automatic kernel LAN routes. vethtest1 whose peer interface wasn't brought up will have a NO-CARRIER status and its routes will get a linkdown flag.

# ip route show to root 192.0.2.0/24
192.0.2.0/25 dev vethtest1 proto kernel scope link src 192.0.2.2 linkdown 
192.0.2.0/24 dev vethtest2 proto kernel scope link src 192.0.2.3 

A route to 192.0.2.100 will use vethtest1 since it got a narrower route (despite having the linkdown flag).

# ip route get 192.0.2.100
192.0.2.100 dev vethtest1 src 192.0.2.2 uid 0 
    cache 

Then with the new setting:

sysctl -w net.ipv4.conf.vethtest1.ignore_routes_with_linkdown=1

comes the new behavior:

# ip route show to root 192.0.2.0/24
192.0.2.0/25 dev vethtest1 proto kernel scope link src 192.0.2.2 dead linkdown 
192.0.2.0/24 dev vethtest2 proto kernel scope link src 192.0.2.3 
# ip -4 netconf show dev vethtest1
inet vethtest1 forwarding on rp_filter off mc_forwarding off proxy_neigh off ignore_routes_with_linkdown on 
# ip route get 192.0.2.100
192.0.2.100 dev vethtest2 src 192.0.2.3 uid 0 
    cache 

Now if the interface gets carrier (simulated here by bringing up its peer interface):

ip link set dev vethtest1peer up

route is restored through it:

# ip route show to root 192.0.2.0/24
192.0.2.0/25 dev vethtest1 proto kernel scope link src 192.0.2.2 
192.0.2.0/24 dev vethtest2 proto kernel scope link src 192.0.2.3 
# ip route get 192.0.2.100
192.0.2.100 dev vethtest1 src 192.0.2.2 uid 0 
    cache