systemd-networkd and direct routes

I have problem adding direct routes through systemd-networkd. What I'm trying to achieve is similar to:

ip a a 192.168.0.2/32 dev enp0s3
ip r a 192.168.0.1/32 dev enp0s3
ip r a default via 192.168.0.1

This is weird setup, I know, but I can't use usual ip a a 192.168.0.2/24 to reach gateway. For some reason whole /24 subnet is reachable through the gateway in this subnet. So this default route is not only for catch-all routes, but to reach subnet as well. So, I've created /etc/systemd/network/enp0s3.network:

[Match]
Name=enp0s3

[Address]
Address=192.168.0.2/32

[Route]
Destination=192.168.0.1/32

[Route]
Gateway=192.168.0.1

The problem with this setup is that second Route block is never executed. I did some debugging and here is the difference between what ip and systemd-networkd does for the first Route block.

# ip
192.168.0.1 dev enp0s3 scope link
# networkd
192.168.0.1 dev enp0s3 proto static

So systemd-networkd doesn't add scope link to the route. That's why an attempt to add default route via 192.168.0.1 fails with Network is unreachable error. This is fixable by

ip r c 192.168.0.1/32 dev enp0s3 # automatically adds `scope link`
ip r a default via 192.168.0.1   # added successfully

So my question is: should such behaviour be considered a systemd-networkd bug or am I using it wrong? I couldn't find any documentation regarding direct routes in networkd. For now I've disabled systemd-networkd and created service to run ip commands directly. But I'd like to use standard approach as this is CoreOS I'm trying to configure.


Solution 1:

So the solution here is a bit tricky: you need to add gateway as a pointopoint parameter with /32 mask. This works:

[Match]
Name=enp0s3

[Address]
Address=192.168.0.2
Peer=192.168.0.1/32

[Network]
Gateway=192.168.0.1

Solution 2:

What you want is to specify how the Gateway can be reached via the local scope. That is it in fact reachable on the same segment. You example is merely missing the line Scope=link.

[Match]
Name=enp0s3

[Address]
Address=192.168.0.2/32

[Route]
Destination=192.168.0.1/32
Scope=link

[Route]
Gateway=192.168.0.1

Solution 3:

None of the solutions proposed worked with systemd 237, because GatewayOnlink=true was missing.

I have been able to use a link-local IPv4 gateway with a /32 interface address with this configuration:

[Match]
Name=eth0

[Network]
Address=192.0.2.42/32

[Route]
Destination=169.254.1.1
Scope=link

[Route]
Gateway=169.254.1.1
GatewayOnlink=true