I haven’t found so far a simple example like this to understand the basics with reference to the sources. It’s more a prove of concept but it has taken me some effort, so I will share it with the community step by step.
Preparations
I use three virtual machines on KVM (Kernel-based Virtual Machine), all with Debian 11 (bullseye, at this time testing version) and using terminology from RFC 2460:
Node is an interface enabled for IPv6.
Router is any node that forwards IPv6 packets that are not expressly addressed to it.
Host is any node that’s not a router.
I use the IPv6 Address Prefix 2001:DB8::/32 Reserved for Documentation (RFC 3849) that is usable for valid global unicast addresses but not routed to the internet.
To have things by hand, here are some specifications:
There are some address types used (RFC 4291)
Unspecified ::/128
Loopback ::1/128
Multicast FF00::/8
Link-Local unicast FE80::/10
Global Unicast (everything else)
Global Anycast (same as Global Unicast) not used in this example
Scope of Multicast addresses (RFC 4291):
FF00:: reserved
FF01:: Interface-Local scope
FF02:: Link-Local scope
FF03:: reserved
FF04:: Admin-Local scope
FF05:: Site-Local scope
FF06:: to FF07:: (unassigned)
FF08:: Organization-Local scope
FF09:: to FF0D:: (unassigned)
FF0E:: Global scope
FF0F:: reserved
Well-known IPv6 multicast addresses (extract – complete list at IANA):
ff02::1 all nodes
ff02::2 all routers
ff02::5 all OSPF (Open Shortest Path First) routers
ff02::6 all OSPF DRs (OSPF Designated Routers)
ff02::9 all RIP (Routing Information Protocol) routers
ff02::a all EIGRP (Enhanced Interior Gateway Routing Protocol) routers
ff02::d all PIM (Protocol Independent Multicast) routers
ff02::f UPNP (Universal Plug and Play) devices
ff02::11 all homenet nodes
ff02::12 VRRP (Virtual Router Redundancy Protocol)
ff02::16 all MLDv2-capable routers
ff02::1a all RPL (Routing Protocol for Low-Power and Lossy Networks) routers (used in Internet of Things (IoT) devices)
ff02::fb multicast DNS IPv6
ff02::101 network time (NTP)
ff02::1:2 all DHCP agents
ff02::1:3 LLMNR (Link-Local Multicast Name Resolution)
ff02:0:0:0:0:1:ff00::/104 solicited node address
ff02:0:0:0:0:1-2:ff00::/104 node information query
ff05::1:3 all DHCP server (site)
ff05::101 all NTP server (site)
I will use tcpdump
to look what’s going on on the network, so install it on the router. Then enable systemd-networkd by following
Section Quick Step at Use systemd-networkd for general networking, then come back here.
I will have everything disabled so we can see what is needed and enable it step by step. On host-a
and host-b
use this network file:
host-? ~$ sudo -Es # if not already done
host-? ~# cat > /etc/systemd/network/04-wired.network <<EOF
(Match)
Name=eth0
(Network)
# on host-a uncomment
#Address=2001:db8:0:10::2/64
# on host-b uncomment
#Address=2001:db8:0:20::2/64
IPv6AcceptRA=no
LinkLocalAddressing=no
EOF
On the router use these ones:
router ~$ sudo -Es # if not already done
router ~# cat > /etc/systemd/network/04-eth0.network <<EOF
(Match)
Name=eth0
(Network)
Address=2001:db8:0:10::1/64
IPv6AcceptRA=no
LinkLocalAddressing=no
EOF
router ~# cat > /etc/systemd/network/06-eth1.network <<EOF
(Match)
Name=eth1
(Network)
Address=2001:db8:0:20::1/64
IPv6AcceptRA=no
LinkLocalAddressing=no
EOF
Simple link-local connection
First I will have a look at the direct connection between host-a
and the router
. The router is UP and I start host-a
. Tcpdump shows me on subnet 2001:db8:0:10/64:
host-a ~$ sudo tcpdump -n --number --interface=eth0 ip6 2>/dev/null
1 23:25:28.211331 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28
2 23:25:28.227326 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 2 group record(s), length 48
3 23:25:28.671386 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28
4 23:25:28.735354 IP6 :: > ff02::1:ff00:2: ICMP6, neighbor solicitation, who has 2001:db8:0:10::2, length 32
- With package 1-3
host-a
joins as listener to the multicast group ff02::16
– all MLDv2-capable routers. Router know now that it want to receive routing messages.
- With package 4 it asked if there is another node with ip address 2001:db8:0:10::2. It isn’t because there is no reply.
host-a
can use the address.
Ping to router
works:
host-a ~$ ping6 -n 2001:db8:0:10::1
PING 2001:db8:0:10::1(2001:db8:0:10::1) 56 data bytes
64 bytes from 2001:db8:0:10::1: icmp_seq=1 ttl=64 time=0.829 ms
64 bytes from 2001:db8:0:10::1: icmp_seq=2 ttl=64 time=0.863 ms
64 bytes from 2001:db8:0:10::1: icmp_seq=3 ttl=64 time=0.858 ms
--- snip ---
Link-local unicast addresses
In the next step I want to connect to the second interface eth1 on router
. For this we need a static route:
host-a ~$ sudo ip -6 route add 2001:db8:0:20::/64 via 2001:db8:0:10::1
But ping6 -nc3 2001:db8:0:20::1
does not work. I don’t get any replies. Curiously it works if I first ping the gateway 2001:db8:0:10:1:
host-a 12:32:26 ~$ ping6 -nc1 2001:db8:0:10::1
PING 2001:db8:0:10::1(2001:db8:0:10::1) 56 data bytes
64 bytes from 2001:db8:0:10::1: icmp_seq=1 ttl=64 time=1.37 ms
--- 2001:db8:0:10::1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.373/1.373/1.373/0.000 ms
host-a 12:32:39 ~$ ping6 -nc3 2001:db8:0:20::1
PING 2001:db8:0:20::1(2001:db8:0:20::1) 56 data bytes
64 bytes from 2001:db8:0:20::1: icmp_seq=1 ttl=64 time=0.629 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=2 ttl=64 time=0.744 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=3 ttl=64 time=0.743 ms
--- 2001:db8:0:20::1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2008ms
rtt min/avg/max/mdev = 0.629/0.705/0.744/0.053 ms
host-a 12:33:01 ~$ ping6 -nc3 2001:db8:0:20::1
PING 2001:db8:0:20::1(2001:db8:0:20::1) 56 data bytes
--- 2001:db8:0:20::1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2027ms
host-a 12:33:28 ~$
Have a look at the timestamp on the prompt. I only get replies some seconds after pinging the gateway. I do not really understand it but it’s good to know about this behavior when looking for troubleshooting. Anyway, it’s out of specification because for connections on the link (2001:db8:0:10:2 to 2001:db8:0:10:1) there must be used link-local addresses as specified at RFC 4291 – Link-Local IPv6 Unicast Addresses:
Link-Local addresses are designed to be used for addressing on a single link for purposes such as automatic address configuration, neighbor discovery, or when no routers are present.
Check for a link-local address on the interface. There is no one:
host-a ~$ ip -6 -br addr
lo UNKNOWN ::1/128
eth0 UP 2001:db8:0:10::2/64
I enable it with setting LinkLocalAddressing=ipv6
in all /etc/systemd/network/*.network
files on all nodes, reboot, check and ping:
host-a ~$ ip -6 -br addr
lo UNKNOWN ::1/128
eth0 UP 2001:db8:0:10::2/64 fe80::5054:ff:febc:adbe/64
router ~$ ip -6 -br addr
lo UNKNOWN ::1/128
eth0 UP 2001:db8:0:10::1/64 fe80::5054:ff:fe0f:194e/64
eth1 UP 2001:db8:0:20::1/64 fe80::5054:ff:fe0f:194e/64
host-b ~$ ip -6 -br addr
lo UNKNOWN ::1/128
eth0 UP 2001:db8:0:20::2/64 fe80::5054:ff:fe9b:34b9/64
host-a ~$ sudo ip -6 route add 2001:db8:0:20::/64 via 2001:db8:0:10::1
host-a ~$ ping6 -n 2001:db8:0:20::1
PING 2001:db8:0:20::1(2001:db8:0:20::1) 56 data bytes
64 bytes from 2001:db8:0:20::1: icmp_seq=9 ttl=64 time=2.08 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=10 ttl=64 time=0.780 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=11 ttl=64 time=0.783 ms
--- snip ---
Works.
Static Routing
If I try to connect from host-a
to host-b
then ping6 -n 2001:db8:0:20::2
fails. That is why the router
does not forward packages between its interfaces. We have to enable it. Just append IPForward=ipv6
to a *.network
file. We also need a static route on host-b
so it knows where to send the replies to host-a
. We will do it persistent now. So you will get following .network
files:
host-a
host-a ~$ cat /etc/systemd/network/04-wired.network
(Match)
Name=eth0
(Network)
Address=2001:db8:0:10::2/64
IPv6AcceptRA=no
LinkLocalAddressing=ipv6
(Route)
Destination=2001:db8:0:20::/64
Gateway=2001:db8:0:10::1
router
router ~$ cat /etc/systemd/network/04-eth0.network
(Match)
Name=eth0
(Network)
Address=2001:0DB8:0:10::1/64
IPv6AcceptRA=no
LinkLocalAddressing=ipv6
IPForward=ipv6
router ~$ cat /etc/systemd/network/06-eth1.network
(Match)
Name=eth1
(Network)
Address=2001:0DB8:0:20::1/64
IPv6AcceptRA=no
LinkLocalAddressing=ipv6
host-b
host-b ~$ cat /etc/systemd/network/04-wired.network
(Match)
Name=eth0
(Network)
Address=2001:db8:0:20::2/64
IPv6AcceptRA=no
LinkLocalAddressing=ipv6
(Route)
Destination=2001:db8:0:10::/64
Gateway=2001:db8:0:20::1
That’s it.
(Will be continued with Router Advertisement)