IPv6 linkdown but IPv4 linkup on same interface

I moved over to VyOS Stream 2025Q2 today, using a pre-written configure.sh script. I’m left with working IPv4 but IPv6 refuses to work on the router itself (either via WAN or LAN). However, statically assigned LAN clients can talk to each other using addresses from my global scope static IPv6 prefix. Only the VyOS router can’t ping6 anyone (WAN or LAN).

On investigation, VyOS says that IPv4 is linkup but IPv6 is linkdown on the same interface. I don’t believe that should be possible? The cable can’t be both plugged in and working, and unplugged and passing zero traffic, at the same time?!

I have a Beelink EQ12 (Intel N100, Intel I225-V B3 NICs), connected to a Yuan Ley unmanaged 2.5G switch. My ISP is symmetric 2Gbps FTTP (no PPPoE) with static IP configuration. They provide me a /29 routed over a /31, and on IPv6 I have a static /48, of which I use a statically defined /64.

VyOS is passing IPv4 WAN to LAN and back again with no issue, and I’m getting 1.8Gbps with cake enabled! It’s just IPv6 refuses to work through it. I can’t ping6 the ISP gateway over v6 (the other half of a point to point link), LAN clients can’t ping6 to the VyOS IPv6 address or the ISP’s gateway (or any site on the Internet), but they can ping6 each other. The output on the router says:

vyos@vyos:\~$ show interfaces ethernet
Codes: S - State, L - Link, u - Up, D - Down, A - Admin Down
Interface        IP Address                        S/L  Description
---------        ----------                        —  -----------
eth1             185.154.146.115/31                u/u  WAN Connection
                 185.154.147.136/32
                 185.154.147.137/32
                 185.154.147.138/32
                 185.154.147.139/32
                 185.154.147.140/32
                 185.154.147.141/32
                 185.154.147.142/32
                 185.154.147.143/32
                 2a0e:1d47::23/127
eth2             10.100.0.1/24                     u/u  LAN Network
                 2a0e:1d47:11::1/64
vyos@vyos:\~$ show ipv6 route
Codes: K - kernel route, C - connected, L - local, S - static,
       R - RIPng, O - OSPFv3, I - IS-IS, B - BGP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
       f - OpenFabric, t - Table-Direct,
       > - selected route, \* - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

S>\* ::/0 \[1/0\] via 2a0e:1d47::22, eth1, weight 1, 00:06:03
C>\* 2a0e:1d47::22/127 is directly connected, eth1 linkdown, weight 1, 00:06:13
K \* 2a0e:1d47::22/127 \[0/256\] is directly connected, eth1 linkdown, weight 1, 00:06:17
L>\* 2a0e:1d47::23/128 is directly connected, eth1 linkdown, weight 1, 00:06:13
C>\* 2a0e:1d47:11::/64 is directly connected, eth2 linkdown, weight 1, 00:06:11
K \* 2a0e:1d47:11::/64 \[0/256\] is directly connected, eth2 linkdown, weight 1, 00:06:16
L>\* 2a0e:1d47:11::1/128 is directly connected, eth2 linkdown, weight 1, 00:06:11
C \* fe80::/64 is directly connected, eth2 linkdown, weight 1, 00:06:11
C \* fe80::/64 is directly connected, eth1 linkdown, weight 1, 00:06:12
C>\* fe80::/64 is directly connected, ifb0, weight 1, 00:06:18
vyos@vyos:\~$ show ip route
Codes: K - kernel route, C - connected, L - local, S - static,
       R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
       f - OpenFabric, t - Table-Direct,
       > - selected route, \* - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

S>\* 0.0.0.0/0 \[1/0\] via 185.154.146.114, eth1, weight 1, 00:06:18
C>\* 10.100.0.0/24 is directly connected, eth2, weight 1, 00:06:27
L>\* 10.100.0.1/32 is directly connected, eth2, weight 1, 00:06:27
C>\* 185.154.146.114/31 is directly connected, eth1, weight 1, 00:06:29
L>\* 185.154.146.115/32 is directly connected, eth1, weight 1, 00:06:29
L \* 185.154.147.136/32 is directly connected, eth1, weight 1, 00:06:29
C>\* 185.154.147.136/32 is directly connected, eth1, weight 1, 00:06:29
L \* 185.154.147.137/32 is directly connected, eth1, weight 1, 00:06:29
C>\* 185.154.147.137/32 is directly connected, eth1, weight 1, 00:06:29
L \* 185.154.147.138/32 is directly connected, eth1, weight 1, 00:06:29
C>\* 185.154.147.138/32 is directly connected, eth1, weight 1, 00:06:29
L \* 185.154.147.139/32 is directly connected, eth1, weight 1, 00:06:29
C>\* 185.154.147.139/32 is directly connected, eth1, weight 1, 00:06:29
L \* 185.154.147.140/32 is directly connected, eth1, weight 1, 00:06:29
C>\* 185.154.147.140/32 is directly connected, eth1, weight 1, 00:06:29
L \* 185.154.147.141/32 is directly connected, eth1, weight 1, 00:06:29
C>\* 185.154.147.141/32 is directly connected, eth1, weight 1, 00:06:29
L \* 185.154.147.142/32 is directly connected, eth1, weight 1, 00:06:29
C>\* 185.154.147.142/32 is directly connected, eth1, weight 1, 00:06:29
L \* 185.154.147.143/32 is directly connected, eth1, weight 1, 00:06:29
C>\* 185.154.147.143/32 is directly connected, eth1, weight 1, 00:06:29

So clearly, only ipv6 route thinks the links are down, which would explain the lack of passing IPv6 traffic! From my limited knowledge this shouldn’t be possible? The physical interface is the same, but show ip route says linkup while show ipv6 route says linkdown. I can share the full config if needed (zone based firewall, icmpv6 allowed), but it’s long!

Do you have any ideas please folks, before I give up and go back to OPNsense? I added the latest Rolling (October 1st 2025) and booted to that to rule out a quirk in Stream 2025Q2 but the issue remains. I can’t figure this out for the life of me. If it’s a bug it’s pointless me spending another 10 hours digging at the firewall config! Thanks in advance.

Sure you’re not hitting this issue?

I’ll read through the whole of the linked thread now, but I do have a static route set for IPv6 already. My full (but redacted of domain names, local dhcp mappings etc) config is too big for the forum but you can see it on Pastebin here and its password is simply vyos2025.

Most likely culprit would be DAD failing. Run this:

show log kernel | grep 'duplicate address'

No output from that command.

Are you sure you’re using the right side of the /127?

Yeah, it’s :23 for me and :22 at the gateway at the ISP’s end. Thanks to whomever tidied up my OP, I forgot to code tag my CLI outputs, sorry.

Can you paste the config for eth1?

#...
### 2. Interface Configuration ###
set interfaces ethernet eth1 address '185.154.146.115/31'
set interfaces ethernet eth1 address '2a0e:1d47::23/127'
set interfaces ethernet eth1 description 'WAN Connection'
set interfaces ethernet eth1 address '185.154.147.136/32'
set interfaces ethernet eth1 address '185.154.147.137/32'
set interfaces ethernet eth1 address '185.154.147.138/32'
set interfaces ethernet eth1 address '185.154.147.139/32'
set interfaces ethernet eth1 address '185.154.147.140/32'
set interfaces ethernet eth1 address '185.154.147.141/32'
set interfaces ethernet eth1 address '185.154.147.142/32'
set interfaces ethernet eth1 address '185.154.147.143/32'
#
set interfaces ethernet eth2 address '10.100.0.1/24'
set interfaces ethernet eth2 address '2a0e:1d47:11::1/64'
set interfaces ethernet eth2 description 'LAN Network'
#
set interfaces input ifb0 description 'WAN Ingress for Shaper'
#
### 3. QoS (Traffic Policy) Configuration ###
set qos policy cake DOWNLOAD bandwidth '1900mbit'
set qos policy cake DOWNLOAD rtt '5'
set qos policy cake DOWNLOAD flow-isolation dual-dst-host
set qos policy cake DOWNLOAD flow-isolation nat
set qos policy cake UPLOAD bandwidth '1900mbit'
set qos policy cake UPLOAD rtt '5'
set qos policy cake UPLOAD flow-isolation dual-src-host
set qos policy cake UPLOAD flow-isolation nat
set interfaces ethernet eth1 redirect 'ifb0'
set qos interface eth1 egress 'UPLOAD'
set qos interface ifb0 egress 'DOWNLOAD'
#
### 4. Static Routing ###
set protocols static route 0.0.0.0/0 next-hop '185.154.146.114'
set protocols static route6 '::/0' next-hop '2a0e:1d47::22'
#

Since it’s fairly short I included the whole section, lest you need to see it. Thanks for helping out so far! It’s got to be something daft I’ve done, or a simple bug?

Nothing crazy there. And also paste the output of this:

sudo sysctl -a | grep -E "net\.ipv6\..*\.eth1"
vyos@vyos:~$ sudo sysctl -a | grep -E "net\.ipv6\..*\.eth1"
net.ipv6.conf.eth1.accept_dad = 1
net.ipv6.conf.eth1.accept_ra = 0
net.ipv6.conf.eth1.accept_ra_defrtr = 1
net.ipv6.conf.eth1.accept_ra_from_local = 0
net.ipv6.conf.eth1.accept_ra_min_hop_limit = 1
net.ipv6.conf.eth1.accept_ra_min_lft = 0
net.ipv6.conf.eth1.accept_ra_mtu = 1
net.ipv6.conf.eth1.accept_ra_pinfo = 1
net.ipv6.conf.eth1.accept_ra_rt_info_max_plen = 0
net.ipv6.conf.eth1.accept_ra_rt_info_min_plen = 0
net.ipv6.conf.eth1.accept_ra_rtr_pref = 1
net.ipv6.conf.eth1.accept_redirects = 0
net.ipv6.conf.eth1.accept_source_route = -1
net.ipv6.conf.eth1.accept_untracked_na = 0
net.ipv6.conf.eth1.addr_gen_mode = 1
net.ipv6.conf.eth1.autoconf = 0
net.ipv6.conf.eth1.dad_transmits = 1
net.ipv6.conf.eth1.disable_ipv6 = 0
net.ipv6.conf.eth1.disable_policy = 0
net.ipv6.conf.eth1.drop_unicast_in_l2_multicast = 0
net.ipv6.conf.eth1.drop_unsolicited_na = 0
net.ipv6.conf.eth1.enhanced_dad = 1
net.ipv6.conf.eth1.force_mld_version = 0
net.ipv6.conf.eth1.force_tllao = 0
net.ipv6.conf.eth1.forwarding = 1
net.ipv6.conf.eth1.hop_limit = 64
net.ipv6.conf.eth1.ignore_routes_with_linkdown = 1
net.ipv6.conf.eth1.ioam6_enabled = 0
net.ipv6.conf.eth1.ioam6_id = 65535
net.ipv6.conf.eth1.ioam6_id_wide = 4294967295
net.ipv6.conf.eth1.keep_addr_on_down = 0
net.ipv6.conf.eth1.link_filter = 0
net.ipv6.conf.eth1.max_addresses = 16
net.ipv6.conf.eth1.max_desync_factor = 600
net.ipv6.conf.eth1.mc_forwarding = 0
net.ipv6.conf.eth1.mldv1_unsolicited_report_interval = 10000
net.ipv6.conf.eth1.mldv2_unsolicited_report_interval = 1000
net.ipv6.conf.eth1.mtu = 1500
net.ipv6.conf.eth1.ndisc_evict_nocarrier = 1
net.ipv6.conf.eth1.ndisc_notify = 0
net.ipv6.conf.eth1.ndisc_tclass = 0
net.ipv6.conf.eth1.optimistic_dad = 0
net.ipv6.conf.eth1.proxy_ndp = 0
net.ipv6.conf.eth1.ra_defrtr_metric = 1024
net.ipv6.conf.eth1.regen_max_retry = 3
net.ipv6.conf.eth1.router_probe_interval = 60
net.ipv6.conf.eth1.router_solicitation_delay = 1
net.ipv6.conf.eth1.router_solicitation_interval = 4
net.ipv6.conf.eth1.router_solicitation_max_interval = 3600
net.ipv6.conf.eth1.router_solicitations = -1
net.ipv6.conf.eth1.rpl_seg_enabled = 0
net.ipv6.conf.eth1.seg6_enabled = 0
net.ipv6.conf.eth1.seg6_require_hmac = 0
net.ipv6.conf.eth1.suppress_frag_ndisc = 1
net.ipv6.conf.eth1.temp_prefered_lft = 86400
net.ipv6.conf.eth1.temp_valid_lft = 604800
net.ipv6.conf.eth1.use_oif_addrs_only = 0
net.ipv6.conf.eth1.use_optimistic = 0
net.ipv6.conf.eth1.use_tempaddr = 0
net.ipv6.neigh.eth1.anycast_delay = 100
net.ipv6.neigh.eth1.app_solicit = 0
net.ipv6.neigh.eth1.base_reachable_time_ms = 30000
net.ipv6.neigh.eth1.delay_first_probe_time = 5
net.ipv6.neigh.eth1.gc_stale_time = 60
net.ipv6.neigh.eth1.interval_probe_time_ms = 5000
net.ipv6.neigh.eth1.locktime = 0
net.ipv6.neigh.eth1.mcast_resolicit = 0
net.ipv6.neigh.eth1.mcast_solicit = 3
net.ipv6.neigh.eth1.proxy_delay = 80
net.ipv6.neigh.eth1.proxy_qlen = 64
net.ipv6.neigh.eth1.retrans_time_ms = 1000
net.ipv6.neigh.eth1.ucast_solicit = 3
net.ipv6.neigh.eth1.unres_qlen = 101
net.ipv6.neigh.eth1.unres_qlen_bytes = 212992

Looks fine there too, one last bit. Paste the results of this:

ip link show dev eth0
ip -6 addr show dev eth0
ip -6 route show dev eth0
ip -6 neigh show dev eth0
ip -6 route get 2a0e:1d47::22

I’m unable to create your issue in a lab right now unless I force a DAD failure, which you don’t seem to be hitting.

I’m assuming you meant eth1 (WAN):

vyos@vyos:~$ ip link show dev eth1
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc cake state UP mode DEFAULT group default qlen 1000
    link/ether e8:ff:1e:d1:e0:a9 brd ff:ff:ff:ff:ff:ff
    alias WAN Connection
    altname enp1s0
vyos@vyos:~$ ip -6 route show dev eth1
2a0e:1d47::22/127 proto kernel metric 256 pref medium
fe80::/64 proto kernel metric 256 pref medium
default nhid 17 via 2a0e:1d47::22 proto static metric 20 pref medium
vyos@vyos:~$ ip -6 neigh show dev eth1
vyos@vyos:~$ ip -6 route get 2a0e:1d47::22
2a0e:1d47::22 from :: dev eth1 proto kernel src 2a0e:1d47::23 metric 256 pref medium

2 things stand out, your route doesn’t show linkdown in that output, and you don’t have a neighbor.

Have you tried pinging 2a0e:1d47::22? Also, is it still showing linkdown? You may need to bounce the interface (disable then delete disable).

vyos@vyos:~$ ping6 -c 4 2a0e:1d47::22
PING 2a0e:1d47::22(2a0e:1d47::22) 56 data bytes

--- 2a0e:1d47::22 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3111ms
vyos@vyos:~$ show ipv6 neighbors
Address    Interface    Link layer address    State
---------  -----------  --------------------  -------

Still linkdown on the show ipv6 route output:

vyos@vyos:~$ show ipv6 route
Codes: K - kernel route, C - connected, L - local, S - static,
       R - RIPng, O - OSPFv3, I - IS-IS, B - BGP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
       f - OpenFabric, t - Table-Direct,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

S>* ::/0 [1/0] via 2a0e:1d47::22, eth1, weight 1, 01:43:29
C>* 2a0e:1d47::22/127 is directly connected, eth1 linkdown, weight 1, 01:43:39
K * 2a0e:1d47::22/127 [0/256] is directly connected, eth1 linkdown, weight 1, 01:43:43
L>* 2a0e:1d47::23/128 is directly connected, eth1 linkdown, weight 1, 01:43:39
C>* 2a0e:1d47:11::/64 is directly connected, eth2 linkdown, weight 1, 01:43:37
K * 2a0e:1d47:11::/64 [0/256] is directly connected, eth2 linkdown, weight 1, 01:43:42
L>* 2a0e:1d47:11::1/128 is directly connected, eth2 linkdown, weight 1, 01:43:37
C * fe80::/64 is directly connected, eth2 linkdown, weight 1, 01:43:37
C * fe80::/64 is directly connected, eth1 linkdown, weight 1, 01:43:38
C>* fe80::/64 is directly connected, ifb0, weight 1, 01:43:44

I’m bouncing the interface again now, but I have already tried that before (and rebooting, and switching from Stream 2025 Q2 to rolling, and wiping the config and starting again!).

After bouncing eth1 -

vyos@vyos:~$ show ipv6 route
Codes: K - kernel route, C - connected, L - local, S - static,
       R - RIPng, O - OSPFv3, I - IS-IS, B - BGP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
       f - OpenFabric, t - Table-Direct,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

S>* ::/0 [1/0] via 2a0e:1d47::22, eth1, weight 1, 00:00:27
C>* 2a0e:1d47::22/127 is directly connected, eth1, weight 1, 00:00:27
L>* 2a0e:1d47::23/128 is directly connected, eth1, weight 1, 00:00:27
C>* 2a0e:1d47:11::/64 is directly connected, eth2 linkdown, weight 1, 01:48:58
K * 2a0e:1d47:11::/64 [0/256] is directly connected, eth2 linkdown, weight 1, 01:49:03
L>* 2a0e:1d47:11::1/128 is directly connected, eth2 linkdown, weight 1, 01:48:58
C * fe80::/64 is directly connected, eth1, weight 1, 00:00:25
C * fe80::/64 is directly connected, eth2 linkdown, weight 1, 01:48:58
C>* fe80::/64 is directly connected, ifb0, weight 1, 01:49:05

The ISP’s gateway now has a separate entry that isn’t linkdown, but I still can’t ping the ISP gateway or ping the VyOS box from a LAN client (set with a static IP from my /64).

vyos@vyos:~$ show ipv6 neighbors
Address    Interface    Link layer address    State
---------  -----------  --------------------  -------

Your eth2 is down, so that is likely why you can’t ping your client. You may need to bounce that as well.

One thing I just tested was putting in the interface and qos config at the same time, and I hit the same results you did. After bouncing the interfaces, they were fine. So you may be hitting a bug with a race condition here.

That’s kind of my point - it says linkdown but the interface is up. I can ping through it on IPv4 (to and from LAN clients) and I’m participating in this thread through that same eth2 LAN interface. The show ipv6 route command just thinks it’s down.

Physical state and logical state are different. The physical state is up, the logical state for ipv4 is up, but the logical state for ipv6 is down.

So it’s not that it think’s it’s down, the logical state IS down.

Ah, sorry, I’ve misconstrued it then. I’ll bounce eth2 again now.