DHCPv6 brings DS-Lite interface down when add_dynamic

Hi all,
recently I've installed OpenWRT in a Fritzbox 7412 acting as a bridge-modem, and a second Linksys wrt1900acs behind the modem. My ISP gives me native IPv6 and a DS-Lite tunnel.

I give here a bit of context:

When connecting, the interface wan6 with proto "DHCPv6" gets a reply from ISP containing the delegated prefix and the AFTR (for the DS-Lite interface). Still I need to wait for a "ra-updated" (router advertisement) packet from my ISP containing the IA_NA address, so then DS-Lite tunnel can route its traffic. This can take up to 20 mins (not sure if this is my ISP's timing, or if it is a bad configuration on my side... I've opened a topic for that in this forum). When the "ra-updated" packet comes, DHCP script calls a function "add_dynamic(...)" which, theoretically, brings up the DSLite interface.

I've noticed, when the DS-Lite interface is up, the function "add_dynamic" seems to trigger somehow a "ifdown" on ds-wan6_4 iface, followed by "ifup". In this point, the tunnel never comes up again, and the IPv4 internet is NOT accessible. It is necessary to wait another 20 mins, to get a new "ra-updated", so the add_dynamic func brings up the tunnel interface (as it was down in the previous ra-updated). After 20 mins, it will be down again, and so on, and so on.

I didn't find much info about this issue (none, indeed), but waiting 40 mins, and every 20 mins I get no IPv4... This is not a comfortable situation. And maybe it could be a bug in DHCPv6 treatment of DS-Lite interface. But, in order to circumvent this issue, I thought in giving up... but finally I've modified the DHCPv6 script and made it work. And so, I share here the result:

  • Install "ip-tiny" packet (or "ip-full"), so we can manage the tunnel interface with "ip tunnel ..."
  • In the line 185 of file "/lib/netifd/dhcpv6.script" we find:
	elif [ -n "$AFTR" -a "$IFACE_DSLITE" != 0 -a -f /lib/netifd/proto/dslite.sh ]; then

This is the relevant "elif" block to be modified by removing the actual content and adding the following:

		[ -z "$IFACE_DSLITE" -o "$IFACE_DSLITE" = 1 ] && IFACE_DSLITE=${INTERFACE}_4
		local dslite_dev=$(ubus call network.interface.$IFACE_DSLITE status | jsonfilter -e '@.l3_device')
		[ "$2" == "ra-updated" -a -n "$dslite_dev" ] && {
			[ -n "$dslite_dev" ] && {
				local status_up=$(ubus -v call network.device status "{ \"name\": \"$dslite_dev\" }" | jsonfilter -e '@.up')

				if [ -n "$status_up" -a "$status_up" == "true" ]; then
					local peer=$(ip addr show dev $dslite_dev | grep "link/tunnel6" | sed -Ene 's/^.*peer ([0-9a-f:]+).*$/\1/p')
					local local=$(ip addr show dev $dslite_dev | grep "link/tunnel6" | sed -Ene 's/^.*link\/tunnel6 ([0-9a-f:]+).*$/\1/p')
					local aftr_addr=$(resolveip -6 $AFTR)
					local ra_addr=${RA_ADDRESSES%%/*}

					if [ "$ra_addr" != "$local" -o "$aftr_addr" != "$peer" ]; then
						logger -t ${0##*/} Updating DS-Lite tunnel addresses
						ip -6 tunnel change $dslite_dev local $ra_addr remote $aftr_addr
						ip link set ds-wan6_4 mtu $RA_MTU
					fi
				else
					ubus -v call network.interface.$IFACE_DSLITE remove
					dslite_dev=""
				fi
			}
		}
		[ "$2" != "ra-updated" -o -z "$dslite_dev" ] && {
			json_init
			json_add_string name "$IFACE_DSLITE"
			json_add_string ifname "@$INTERFACE"
			json_add_string proto "dslite"
			json_add_string peeraddr "$AFTR"
			json_add_string tunlink "$INTERFACE"
			json_add_string mtu "$RA_MTU"
			[ -n "$ZONE_DSLITE" ] || ZONE_DSLITE=$ZONE
			[ -n "$ZONE_DSLITE" ] && json_add_string zone "$ZONE_DSLITE"
			[ -n "$ENCAPLIMIT_DSLITE" ] && json_add_string encaplimit "$ENCAPLIMIT_DSLITE"
			[ -n "$IFACE_DSLITE_DELEGATE" ] && json_add_boolean delegate "$IFACE_DSLITE_DELEGATE"
			json_close_object

			logger -t ${0##*/} Creating DS-Lite tunnel interface
			ubus -v call network add_dynamic "$(json_dump)"
		}
  • At the end of the script, in the "case .... esac" block, add the "$2" parameter for setup_interface function:
        ra-updated)
                [ -n "$ADDRESSES$RA_ADDRESSES$PREFIXES$USERPREFIX" ] && setup_interface "$1" "$2"

The rest of the script stays unmodified.

Quick explanation

What we do here is, in case of "ra-updated", check whether the expected DS-Lite interface exists, and if the local and remote addresses are correct.
If it does not exist -> create
If it exists, but it is NOT UP -> delete, and create again
If it exists, but addresses are wrong -> modify addresses
Do nothing is everything is correct

Of course, I don't know if there is a better way, or if any of my configs is wrong and is causing this issue... At any case, this is how I solved it. Hope it is useful for other users

Did anybody face the same? did anybody solve it in a better way? Open to suggestions :slight_smile: