How to setup ipv6 correctly so that ping -6 google.com works?

This is my current network configuration:

{ lib, ... }:
let
  defaultGw = "<redacted-ipv4-A>";
  ipv4address = "<redacted-ipv4-B>";
  defaultGw6 = "fe80::1";
  ipv6address = "<redacted-ipv6-C>::1";
in
{
  networking = {
    defaultGateway = defaultGw;
    defaultGateway6 = defaultGw6;
    dhcpcd.enable = false;
    enableIPv6 = true;
    interfaces = {
      ens18 = {
        ipv4.addresses = [
          { address=ipv4address; prefixLength=20; }
        ];
        ipv6.addresses = [
          { address=ipv6address; prefixLength=64; }
        ];
        ipv4.routes = [ { address = defaultGw; prefixLength = 32; } ];
        ipv6.routes = [ { address = defaultGw6; prefixLength = 128; } ];
      };
    };
    nameservers = [ "8.8.8.8" ];
    usePredictableInterfaceNames = lib.mkForce false;
  };
  services.udev.extraRules = ''
    ATTR{address}=="<redacted-ipv6-D>", NAME="ens18"
  '';
}

My VPS admin panel shows this info:

IPv4 addresses
IP: <redacted-ipv4-B>
Gateway: <redacted-ipv4-A>
Netmask: 255.255.255.0/24
rDNS: 80.246.56.2.in-addr.arpa.

IPv6 /64 subnets
First IP: <redacted-ipv6-C>::1
Subnet: <redacted-ipv6-C>:0:0:0:0/64
Gateway: fe80::1
Netmask: <redacted-ipv6-C>:0:0:0:0

My configuration builds ok, but fails like this on switch:

$ sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch
updating GRUB 2 menu...
activating the configuration...
setting up /etc...
reloading user units for stian...
setting up tmpfiles
warning: the following units failed: network-setup.service

× network-setup.service - Networking Setup
     Loaded: loaded (/etc/systemd/system/network-setup.service; enabled; preset: enabled)
     Active: failed (Result: exit-code) since Sat 2023-09-30 08:55:16 CEST; 4s ago
    Process: 39381 ExecStart=/nix/store/ay57nz191vzjg40xqyz9d3zz7b64pg22-unit-script-network-setup-start/bin/network-setup-start (code=exited, status=2)
   Main PID: 39381 (code=exited, status=2)
         IP: 0B in, 0B out
        CPU: 32ms

Sep 30 08:55:16 myvps systemd[1]: Starting Networking Setup...
Sep 30 08:55:16 myvps network-setup-start[39390]: Error: Egress device not specified.
Sep 30 08:55:16 myvps systemd[1]: network-setup.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Sep 30 08:55:16 myvps systemd[1]: network-setup.service: Failed with result 'exit-code'.
Sep 30 08:55:16 myvps systemd[1]: Failed to start Networking Setup.

This stands out: network-setup-start[39390]: Error: Egress device not specified.. I’ve googled this, but I have not been able to understand what it means.

ping for ipv4 works, but not for ipv6:

$ ping -4 google.com
PING google.com (142.250.186.110) 56(84) bytes of data.
64 bytes from fra24s06-in-f14.1e100.net (142.250.186.110): icmp_seq=1 ttl=56 time=1.05 ms
64 bytes from fra24s06-in-f14.1e100.net (142.250.186.110): icmp_seq=2 ttl=56 time=1.03 ms
^C
--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 1.029/1.037/1.045/0.008 ms

$ ping -6 google.com
ping: connect: Network is unreachable

route and ifconfig says this:

$ route -6
Kernel IPv6 routing table
Destination                    Next Hop                   Flag Met Ref  Use If
localhost/128                  [::]                       U    256 2      0 lo
<redacted-ipv6-C>::/64          [::]                       U    256 1      0 ens18
fe80::1/128                    [::]                       U    1024 1      0 ens18
fe80::/64                      [::]                       U    256 1      0 ens18
[::]/0                         [::]                       !n   -1  1      0 lo
localhost/128                  [::]                       Un   0   4      0 lo
myvps/128                     [::]                       Un   0   2      0 ens18
myvps/128                     [::]                       Un   0   3      0 ens18
ff00::/8                       [::]                       U    256 3      0 ens18
[::]/0                         [::]                       !n   -1  1      0 lo

$ ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:3f:3a:b2:af  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens18: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet <redacted-ipv4-B>  netmask 255.255.240.0  broadcast 0.0.0.0
        inet6 fe80::4863:6ff:fe3c:fd3  prefixlen 64  scopeid 0x20<link>
        inet6 <redacted-ipv6-C>::1  prefixlen 64  scopeid 0x0<global>
        ether <redacted-ipv6-D>  txqueuelen 1000  (Ethernet)
        RX packets 14176720  bytes 1395145826 (1.2 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 199818  bytes 41086424 (39.1 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 832  bytes 41600 (40.6 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 832  bytes 41600 (40.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Question 1: Do I need a services.udev.extraRules? What should go there? I currently have a different ipv6 address there, originally from when I used nixos-infect on a different vps.

Question 2: What am I missing, or what have I misconfigured, so that ipv6 ping doesn’t work?

To get some better error messages, I’d recommend setting networking.useNetworkd = lib.mkDefault true; than your network is configured using systemd-networkd rather than shell scripts. This hopefully also gives you better errors for the ones you are seeing in the network-setup.service. Also you can than use networkctl status <yourinterface>. It would be also helpful if you could post the output of iproute instead ip -6 r and ip a. I am more familiar parsing that in my head than oldstyle route/ipconfig output.

Thank you for responding. I found this page: systemd-networkd - NixOS Wiki, and the header “Static”. Would that be a good starting point for me? Should I then remove everything in my networking. attribute, and instead set only systemd.network.networks."10-wan"?

Here’s some more output:

$ ip route
default via <redacted-ipv4-A> dev ens18 proto static
<redacted-ipv4-E>/20 dev ens18 proto kernel scope link src <redacted-ipv4-B>
<redacted-ipv4-A> dev ens18 proto static scope link
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown

$ ip -6 r
::1 dev lo proto kernel metric 256 pref medium
<redacted-ipv6-C>::/64 dev ens18 proto kernel metric 256 pref medium
fe80::1 dev ens18 proto static metric 1024 pref medium
fe80::/64 dev ens18 proto kernel metric 256 pref medium

$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether <redacted-ipv6-D> brd ff:ff:ff:ff:ff:ff
    altname enp0s18
    altname eth0
    inet <redacted-ipv4-B>/20 scope global ens18
       valid_lft forever preferred_lft forever
    inet6 <redacted-ipv6-C>::1/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::4863:6ff:fe3c:fd3/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:3f:3a:b2:af brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever

Your static ip looks correctly configured, what your missing is the default gateway.
You don’t need ipv6.routes = [ { address = defaultGw6; prefixLength = 128; } ]; actually because the default link-local ipv6 subnet already contains fe80::1. What you are missing is the default route that is supposed to be set by networking.defaultGateway6.

Instead of a single ip for the defaultGateway, you will also need the interface, since link-local ipv6 is interface specific.

networking.defaultGateway6 = {        
  address = "fe80::1"; 
  interface = "ens18";
};

That’s why you were seeing the INVALIDARGUMENT.

1 Like

Thank you so much! That made it work

$ sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch
updating GRUB 2 menu...
activating the configuration...
setting up /etc...
reloading user units for stian...
setting up tmpfiles
restarting the following units: network-addresses-ens18.service

$ ping -6 google.com
PING google.com(fra24s06-in-x0e.1e100.net (2a00:1450:4001:829::200e)) 56 data bytes
64 bytes from fra24s06-in-x0e.1e100.net (2a00:1450:4001:829::200e): icmp_seq=1 ttl=57 time=1.15 ms
64 bytes from fra24s06-in-x0e.1e100.net (2a00:1450:4001:829::200e): icmp_seq=2 ttl=57 time=0.912 ms
^C
--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.912/1.028/1.145/0.116 ms