IPv6 default route is not installed when using SLAAC?

Hello everyone,

recently i have ran into a issue, where the IPv6 default route is either not being installed when enabling IPv6 on a running FreeBSD host, or it disappears after restarting network + routing.
This has been very annoying to deal with, especially on my IPv6-only FreeBSD hosts, as all routed network communication breaks down.

Problem Description

When stateless address auto configuration (SLAAC) is enabled on a network interface on a FreeBSD 13.2-RELEASE-p4 host, IPv6 addresses are installed, but the IPv6 default route isn't.
Interestingly, on the armv6 version of FreeBSD 13.1-RELEASE (Raspberry Pi 1 Model B) the IPv6 default route is installed when SLAAC is enabled on a network interface without problem.
Both send a router solicitation and receive a router advertisement with the needed information which I have confirmed with tcpdump on all three hosts (PC, VM, Raspberry Pi 1).

Currently the only solution is to reboot FreeBSD or to install the IPv6 default route by hand. This is only a minor Problem, but as it is working on armv6, is should also be working on amd64.
I have read recommendations to use rtsol -a / rtsold, but neither worked, except on the Raspberry Pi 1, where it usually did install the IPv6 default route.

Steps to reproduce

1. Add the following line to /etc/rc.conf and replace igb0 with the name of your Ethernet adapter:
ifconfig_igb0_ipv6="inet6 accept_rtadv"

2. Execute the following command to restart your network interface, again, replace igb0 if necessary:
# service netif restart igb0 && service routing restart

Expected behavior

  1. For each IPv6 prefix advertised by the router, one IPv6 should be created on the network interface igb0.
  2. The link-local IPv6 address of the router sending the router advertisements (RA) should be installed as the IPv6 default route.
  3. Additional information like IPv6 DNS servers and a DNS search domain should be installed in /etc/resolve.conf.

Workarounds

  1. Reboot the FreeBSD Host / VM / Jail, after the reboot the IPv6 default route will be installed.
  2. Manually add the IPv6 default route with the command # route add -a default fe80::1&igb0 - replace fe80::1 with the link-local address of your router.

Log files

Note: For privacy reasons, I have changed the first three hexs of my IPv6 addresses to "2001:db8:1000::/32".

Output of tcpdump -i vtnet0 -v icmp6 on a FreeBSD 13.2-RELEASE-p4 VM on Proxmox VE, after the # service netif restart && service routing restart was ran:
  • The output of the FreeBSD Host with the igb0 NIC and the FreeBSD Raspberry Pi 1 with the ue0 NIC is virtually identical, so I've excluded them.

1. FreeBSD performing DAD (duplicate address detection) to make sure it's link-local IPv6 address is unique:
Code:
22:09:00.617764 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) :: > ff02::1:ffe9:d1d1: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has fe80::600e:59ff:fee9:d1d1
          unknown option (14), length 8 (1):
          0x0000:  d3fb 8a56 af37

2. FreeBSD sends a router solicitation message to the all routers multicast group:
Code:
22:09:01.770510 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 16) fe80::600e:59ff:fee9:d1d1 > ff02::2: [icmp6 sum ok] ICMP6, router solicitation, length 16
          source link-address option (1), length 8 (1): 62:0e:59:e9:d1:d1

3. The router (OPNsense 23.7.6 in this case) answers with a router advertisement, containing it's own link-local IPv6 address with it's lifetime, a global and local IPv6 prefix, two local DNS servers and a dns domain:
Code:
22:09:01.771735 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 160) fe80::219:99ff:feec:b44a > fe80::600e:59ff:fee9:d1d1: [icmp6 sum ok] ICMP6, router advertisement, length 160
        hop limit 64, Flags [none], pref medium, router lifetime 1800s, reachable time 0ms, retrans timer 0ms
          prefix info option (3), length 32 (4): 2001:db8:1000:4820::/64, Flags [onlink, auto], valid time 86400s, pref. time 14400s
          prefix info option (3), length 32 (4): fd00:20::/64, Flags [onlink, auto], valid time 86400s, pref. time 14400s
          rdnss option (25), length 40 (5):  lifetime 600s, addr: fd00:60::13 addr: fd00:60::14
          dnssl option (31), length 24 (3):  lifetime 600s, domain(s): subdomain.domain.tld.
          mtu option (5), length 8 (1):  1484
          source link-address option (1), length 8 (1): 00:19:99:ec:b4:4a

4. FreeBSD performs DAD for it's IPv6 global unicast address:
Code:
22:09:01.777709 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) :: > ff02::1:ffe9:d1d1: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has fd00:20::600e:59ff:fee9:d1d1
          unknown option (14), length 8 (1):
          0x0000:  e569 f0f0 9b45

5. FreeBSD performs DAD for it's IPv6 unique local address:
Code:
22:09:01.777721 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) :: > ff02::1:ffe9:d1d1: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has 2001:db8:1000:4820:600e:59ff:fee9:d1d1
          unknown option (14), length 8 (1):
          0x0000:  abd3 e6e8 7868

Output of # netstat -rn -6on a PC running FreeBSD 13.2-RELEASE-p4 after restarting the network:
  • As one can see, the entry default is missing from the routing table after IPv6 is configured via SLAAC (on amd64).

Code:
Routing tables

Internet6:
Destination                       Gateway                       Flags     Netif Expire
::/96                             ::1                           URS         lo0
::1                               link#2                        UHS         lo0
::ffff:0.0.0.0/96                 ::1                           URS         lo0
2001:db8:1000:4820::/4            link#1                        U          igb0
2001:db8:1000:4820:a236:9fff:fe77:f0cb link#1                    UHS         lo0
fd00:20::/64                      link#1                        U          igb0
fd00:20::a236:9fff:fe77:f0cb      link#1                        UHS         lo0
fe80::/10                         ::1                           URS         lo0
fe80::%igb0/64                    link#1                        U          igb0
fe80::a236:9fff:fe77:f0cb%igb0    link#1                        UHS         lo0
fe80::%lo0/64                     link#2                        U           lo0
fe80::1%lo0                       link#2                        UHS         lo0
ff02::/16                         ::1                           URS         lo0

Output of on a Raspberry Pi 1 running FreeBSD 13.1-RELEASE after restarting the network:
  • This time, the default entry is present in the IPv6 routing table (on armv6):

Code:
Routing tables

Internet6:
Destination                       Gateway                       Flags     Netif Expire
::/96                             ::1                           UGRS        lo0
default                           fe80::219:99ff:feec:b44a%ue0  UG          ue0 <--- IPv6 default route present
::1                               link#1                        UHS         lo0
::ffff:0.0.0.0/96                 ::1                           UGRS        lo0
2001:db8:1000:4820::/64            link#2                        U           ue0
2001:db8:1000:4820:745f:a4ff:fe39:edd link#2                     UHS         lo0
fd00:20::/64                      link#2                        U           ue0
fd00:20::745f:a4ff:fe39:edd       link#2                        UHS         lo0
fe80::/10                         ::1                           UGRS        lo0
fe80::%lo0/64                     link#1                        U           lo0
fe80::1%lo0                       link#1                        UHS         lo0
fe80::%ue0/64                     link#2                        U           ue0
fe80::745f:a4ff:fe39:edd%ue0      link#2                        UHS         lo0
ff02::/16                         ::1                           UGRS        lo0

Possibly related Links

Environment

FreeBSD Host

  • FreeBSD 13.2-RELEASE
  • AMD Athlon 3000G
  • Intel i210-T1 NIC

FreeBSD VM
  • FreeBSD 13.2-RELEASE-p4
  • Intel Core i3-10100
  • VirtIO vtnet NIC

FreeBSD Raspberry
  • FreeBSD 13.1-RELEASE
  • Raspberry Pi 1 Model B
  • Embedded 100 Mbps NIC



At this point, I don't know if this is a bug in and amd64 build or if I'm doing something wrong, so any advice is welcome. :)
 
I am pretty sure that the default route is advertised, as it works on my Android smartphone, Linux laptop, Windows PC, and even the FreeBSD Raspberry Pi 1.
And if I am not mistaken, there is a default route in the router advertisement sent by my OPNsense firewall (This is what I meant with the "link-local IPv6 address" of OPNsense in the tcpdump output).
 
I have several systems with SLAAC in my home network. It all works as expected. So I don't think it's a bug.
 
I myself have 4 FreeBSD VMs, 18 Jails and three FreeBSD Hosts in my home network using IPv6 via SLAAC without a problem.

What I am trying to explain is that IPv6 breaks when I change something about the network, like adding ifconfig_[ifname]_ipv6="inet6 accept_rtadv" on a IPv4-only Host or add an IP alias to an IPv6-only Host like ifconfig_vtnet0_alias0="inet6 fd00:20::11/64") in /etc/rc.conf and run # service netif restart && service routing restart.

Since this works just fine on my Raspberry Pi 1 running FreeBSD 13.1-RELEASE, I don't understand what is stopping the installation of the IPv6 default route on physical Hosts, VMs and Jails. :(
And because the IPv4 default route is installed too when enabling DHCP on the same interfaces that are using SLAAC, I would expect the same for IPv6...
 
Back
Top