Static IPv6 wan6 interface but odhcp6c daemon requests address

Router: NETGEAR WNDR3800
Firmware Version: LEDE 17.01.4

Background

My ISP has recently started supporting IPv6. They offer a /64 address via DHCPv6 and a statically allocated /56 address. There are unresolved routing problems with some of the DHCPv6 /64 addresses, but addresses from the static /56 space work well.

I have configured the router to use static-pd with the /56 address and assign one /64 to each of the lan and wan interfaces. Configuration files below. This works (with a work around).

Problem

The odhcp6c daemon it is running on the wan interface and grabbing a /64 address, which isn't routed properly. This address has priority and all outbound IPv6 traffic goes a couple of hops then gets lost.

I can see with ifstatus wan6 that the wan6 interface has two IPv6 addresses <ipv6_good> and <ipv6_bad>. traceroute -6 -s <ipv6_good> ipv6.google.com works but traceroute -6 -s <ipv6_bad> ipv6.google.com fails at the ISP boundary.

Work around

My current work around is to add the config route6 block to /etc/config/network. This insures the good IPv6 address is used outbound.

Troubleshooting

I have been poking around at this for a few months, but have exhausted my meagre knowledge of openwrt and IPv6.

  • ifstatus wan6 shows that the wan6 interface is getting ipv6 addresses both statically and via DHCPv6
  • traceroute shows my ISP has routing error. This has been confirmed by another customer.
  • ps shows the process odhcp6c -s /lib/netifd/dhcpv6.script -P0 -t120 pppoe-wan is running
  • I found that odhcp6c is run from /lib/netifd/proto/dhcpv6.sh and edited this file to add the -v flag for verbose output to the system log file
  • I added some logger commands to the script to see the options passed in
  • I tried killing odhcp6c from the command line but it returns from the dead
  • I hard coded the command line to odhcp6c -s /lib/netifd/dhcpv6.script -v -Nnone pppoe-wan which stops DHCPv6 from requesting an address

Phew!!!

When I look at what is happening when /lib/netifd/proto/dhcpv6.sh is called I see

  • config=wan_6
  • iface=pppoe-wan
  • reqaddress=
  • reqprefix=

This gives the odhcp6c command line above.

Questions

I'd like to know

  • Should odhcp6c be running when option proto 'static' is specified?
  • Can I stop odhcp6c from running?
  • Where is it called from?
  • If I can't stop it, can I pass the option -Nnone to it to make it mostly harmless?

Configuration file

/etc/config/network

[...]

config interface 'lan'
        option ifname 'eth0.1'
        option force_link '1'
        option type 'bridge'
        option proto 'static'
        option ipaddr '192.168.1.1'
        option netmask '255.255.255.0'
        option ip6assign '64'
        option ip6hint '1'

config interface 'wan'
        option ifname 'eth1'
        option proto 'pppoe'
        option keepalive '5 5'
        option username '********'
        option password '********'

config interface 'wan6'
        option ifname '@wan'
        option proto 'static'
        option ip6prefix '2400:4dc0:0:X::/56'
        option ip6assign '64'
        option ip6hint '0'
        option dns '2001:df5:3c00:100::67 2001:df5:3c00:100::68'
        option reqaddress 'none'
        option reqprefix 'no'

config route6
        option interface 'wan6'
        option target '::/0'
        option source '2400:4dc0:0:X::/56'

[...]

Just in case anyone is interested, here are my hacks to /lib/netifd/proto/dhcpv6.sh

A bit crude, so open to suggestions.

--- /rom/lib/netifd/proto/dhcpv6.sh     2017-10-17 17:46:20.000000000 +0000
+++ /lib/netifd/proto/dhcpv6.sh 2018-03-26 09:39:52.000000000 +0000
@@ -37,9 +37,17 @@
        local config="$1"
        local iface="$2"

+       # debug to log file
+       logger "DHCPV6-DEBUG proto_dhcpv6_setup config=$1"
+       logger "DHCPV6-DEBUG proto_dhcpv6_setup iface=$2"
+
        local reqaddress reqprefix clientid reqopts noslaaconly forceprefix extendprefix norelease ip6prefix iface_dslite iface_map iface_464xlat ifaceid userclass vendorclass delegate zone_dslite zone_map zone_464xlat zone soltimeout fakeroutes sourcefilter keep_ra_dnslifetime
        json_get_vars reqaddress reqprefix clientid reqopts noslaaconly forceprefix extendprefix norelease ip6prefix iface_dslite iface_map iface_464xlat ifaceid userclass vendorclass delegate zone_dslite zone_map zone_464xlat zone soltimeout fakeroutes sourcefilter keep_ra_dnslifetime

+        # debug to log file
+        logger "DHCPV6-DEBUG proto_dhcpv6_setup reqaddress=$reqaddress"
+        logger "DHCPV6-DEBUG proto_dhcpv6_setup reqprefix=$reqprefix"
+

        # Configure
        local opts=""
@@ -84,6 +92,11 @@
        [ "$sourcefilter" = "0" ] && proto_export "NOSOURCEFILTER=1"
        [ "$extendprefix" = "1" ] && proto_export "EXTENDPREFIX=1"

+       logger "DHCPV6-DEBUG proto_dhcpv6_setup OVERRIDE opts"
+       logger "DHCPV6-DEBUG proto_dhcpv6_setup  was opts=$opts"
+       opts="-v -Nnone"
+       logger "DHCPV6-DEBUG proto_dhcpv6_setup  now opts=$opts"
+
        proto_export "INTERFACE=$config"
        proto_run_command "$config" odhcp6c \
                -s /lib/netifd/dhcpv6.script \
@@ -92,6 +105,7 @@

 proto_dhcpv6_renew() {
        local interface="$1"
+       logger "DHCPV6-DEBUG proto_dhcpv6_renew interface=$1"
        # SIGUSR1 forces odhcp6c to renew its lease
        local sigusr1="$(kill -l SIGUSR1)"
        [ -n "$sigusr1" ] && proto_kill_command "$interface" $sigusr1
@@ -99,6 +113,7 @@

 proto_dhcpv6_teardown() {
        local interface="$1"
+        logger "DHCPV6-DEBUG proto_dhcpv6_teardown interface=$1"
        proto_kill_command "$interface"
 }

and some filtered output after ifup wan

logread | grep -i dhcp | grep -v dnsmasq

Mon Mar 26 06:17:24 2018 daemon.info odhcpd[861]: Raising SIGUSR1 due to default route change
Mon Mar 26 06:17:24 2018 daemon.info odhcpd[861]: Raising SIGUSR1 due to address change on br-lan
Mon Mar 26 06:17:24 2018 daemon.info odhcpd[861]: Raising SIGUSR1 due to address change on pppoe-wan
Mon Mar 26 06:17:24 2018 user.notice root: DHCPV6-DEBUG proto_dhcpv6_teardown interface=wan_6
Mon Mar 26 06:17:24 2018 daemon.info odhcpd[861]: Raising SIGUSR1 due to address change on pppoe-wan
Mon Mar 26 06:17:25 2018 daemon.info odhcpd[861]: Using a RA lifetime of 1800 seconds on br-lan
Mon Mar 26 06:17:40 2018 daemon.info odhcpd[861]: Raising SIGUSR1 due to default route change
Mon Mar 26 06:17:40 2018 user.notice root: DHCPV6-DEBUG proto_dhcpv6_setup config=wan_6
Mon Mar 26 06:17:40 2018 user.notice root: DHCPV6-DEBUG proto_dhcpv6_setup iface=pppoe-wan
Mon Mar 26 06:17:40 2018 user.notice root: DHCPV6-DEBUG proto_dhcpv6_setup reqaddress=
Mon Mar 26 06:17:40 2018 user.notice root: DHCPV6-DEBUG proto_dhcpv6_setup reqprefix=
Mon Mar 26 06:17:40 2018 user.notice root: DHCPV6-DEBUG proto_dhcpv6_setup OVERRIDE opts
Mon Mar 26 06:17:40 2018 user.notice root: DHCPV6-DEBUG proto_dhcpv6_setup  was opts=-P0 -t120
Mon Mar 26 06:17:40 2018 user.notice root: DHCPV6-DEBUG proto_dhcpv6_setup  now opts=-v -Nnone
Mon Mar 26 06:17:40 2018 daemon.notice odhcp6c[29284]: (re)starting transaction on pppoe-wan
Mon Mar 26 06:17:40 2018 daemon.notice odhcp6c[29284]: Starting INFOREQ transaction (timeout 4294967295s, max rc 0)
Mon Mar 26 06:17:40 2018 daemon.notice odhcp6c[29284]: Got a valid reply after 9ms
Mon Mar 26 06:17:40 2018 daemon.notice odhcp6c[29284]: entering stateless-mode on pppoe-wan
Mon Mar 26 06:17:40 2018 daemon.notice odhcp6c[29284]: Starting  transaction (timeout 86400s, max rc 0)
Mon Mar 26 06:17:41 2018 daemon.info odhcpd[861]: Using a RA lifetime of 1800 seconds on br-lan
Mon Mar 26 06:25:18 2018 daemon.notice odhcpd[861]: Got DHCPv6 request

That command "ip addrlabel" can be used to affect how the linux kernel chooses IPv6 source addresses. When selecting a source address the kernel will choose an address with the same label as the destination address. If you want the kernel to avoid addresses from a certain IPv6 prefix then you can configure that prefix with its own label. Which means those addresses will only be used when communicating with another address within the same prefix.

You probably need ip-full for the addrlabel command, and /etc/rc.local is a suitable location to add the call.

Thanks. I searched a little for this but failed.

Insert the prefix you want to avoid in the command below and try it in the shell.

/usr/sbin/ip addrlabel add prefix 2400:4dc0:XXXX:XXXX::/64 label 20

Got it. This is an alternate work around. Useful to know.

Doesn't address the root cause, which may be a configuration error.

This was answered in a related thread How is odhcp6c daemon started. Summarizing:

The wan interface wan uses the pppoe protocol. The DHCPv6 client is launched by the autoipv6 feature of the pppoe proto. To inhibit this automatic IPv6 handling, set option ipv6 0 on the wan PPPoE interface.

This worked.

... but after a reboot other "bad things" happened with IPv6. I have reverted to my previous working configuration and – at least for now – will just work around my ISPs brokenness. It is working so I really should just leave it alone.

Thanks for the useful information. I had fun digging around in openwrt internals and learned a little more about IPv6.

NOW I think I understand. The results below surprised me – probably because I didn't understand the documentation. These results apply to a pppoe protocol wan interface.

The value of network.wan.ipv6 can be auto (default), 0 or 1:

  • 0: IPv6 is not available on wan interface
  • 1: IPv6 requested on wan interface and a Link Local address is allocated – presumably if available. odhcp6c not started automatically
  • auto (default): IPv6 requested on wan interface and Link Local address is requested. pseudo-interface wan_6 is created and odhcp6c started automatically

For me network.wan.ipv6 = 0 or 1 works best. I can use the network.wan6 section to configure IPv6 as static, dhcpv6 or whatever. When odhcp6c isn't doing things behind my back the network behaviour is much more predictable.

I think my previous confusion was due to:

  • ignorance
  • assuming that the default value for ipv6 was either '0' or '1'.
  • intermittent IPv6 routing issues with my ISP

I have added a section PPP-based protocols and option ipv6 to the wiki page https://openwrt.org/docs/guide-user/network/ipv6/start