IPv6 on Comcast Using OpenWRT

I bought a new wireless router (TP-Link N750 TL-WDR4300) that had fantastic hardware specs. It was to replace what I had been using, an Airport extreme, that was having problems dealing with the number of DHCP leases on my network. I also didn’t like the lack of flexibility in firewalling, DHCP options, and on and on. Basically the Airport worked great, but sticks to Apple’s design philosophy: user’s don’t really know what they want, so we’ll tell them. One thing I really liked about the Airport, however, was that it worked great with IPv6. The new TP-Link router didn’t support IPv6, crashed a lot, would randomly stop routing bridged traffic between the wired and wireless interfaces, and did a pretty good job of pissing me off. It’s OS was based on an older version of either OpenWRT or dd-wrt; and this was the source of my problems. Since it wasn’t really working I decided to go ahead and drop OpenWRT’s latest snapshot on the router, I figured what do I have to lose.  (I am super happy with the results, what a great community project!) I’m not going to cover how to install it, that’s well-enough documented at the OpenWRT site.  I am going to give a couple of pointers to getting IPv6 working on Comcast’s network.  It’s actually pretty easy once you install the right packages.  There are  different ways to get IPv6 working in OpenWRT, and this is the combination I got to work, I tried a lot of things.  Other setups might work better or not at all, I don’t know–I stopped once it worked. opkgs you will want: Wide DHCP Client, and the route advertisement daemon. (You don’t need wide-dhcp-server.)
opkg install wide-dhcpv6-client radvd
First a couple of gotchas that tripped me up.
  • Comcast only delegates a /64 prefix (standard ISP practice is a /60,) which means a few things that at first tricked me …
    • You can’t subnet a /64, so at layer 3 you will talk to the upstream router using link local addresses.
    • The br-lan interface will get the delegated address.
    • The default config for wide dhcp6c assumes a /60 delegation, if you don’t change this you won’t get your lease.
  • By default the native IPv6 stack is configured to listen for route advertisements and send route solicitations.  This conflicts with what dhcp6c is doing. I’m not sure, but it might be possible to use the native IPv6 settings in /etc/config/network but I’m not sure if it works as expected with the /64 delegation; I was seeing the wan interface get the address assignment and not the internal layer-3 interface we would use as the default gateway.
    • If you are seeing strange behavior on your network this might be the cause … when I didn’t know better and had both native and dhcp6c enabled I would restart the network, or reboot the router and IPv6 would be working great.  A few hours later it would stop working.  I would also see that my clients had been assigned new network prefixes.  But they had not disabled the old ones (marked as deprecated but still listening.)  And I could’t route IPv6 anymore.
Here are some of my settings that got my OpenWRT routing IPv6 on Comcast (sorry, just config files I didn’t even install the web gui.) /etc/config/network: (Notable change is “accept_ra” and “send_rs” are both set to 0.)
config interface 'loopback'
 option ifname 'lo'
 option proto 'static'
 option ipaddr ''
 option netmask ''
config interface 'lan'
 option ifname 'eth0.1'
 option type 'bridge'
 option proto 'static'
 option ipaddr ''
 option netmask ''
 option accept_ra 0
 option send_rs 0
config interface 'wan'
 option ifname 'eth0.2'
 option proto 'dhcp'
 option accept_ra 0
 option send_rs 0
config switch
 option name 'eth0'
 option reset '1'
 option enable_vlan '1'
config switch_vlan
 option device 'eth0'
 option vlan '1'
 option ports '0t 2 3 4 5'
config switch_vlan
 option device 'eth0'
 option vlan '2'
 option ports '0t 1'
config interface
 option interface 'lan'
 option AdvSendAdvert 1
 option AdvManagedFlag 0
 option AdvOtherConfigFlag 0
 list client ''
 option ignore 0
config prefix
 option interface 'lan'
 # If not specified, a non-link-local prefix of the interface is used
 list prefix ''
 option AdvOnLink 1
 option AdvAutonomous 1
 option AdvRouterAddr 0
 option ignore 0
config route
 option interface 'lan'
 list prefix ''
 option ignore 0
config rdnss
 option interface 'lan'
 # If not specified, the link-local address of the interface is used
 list addr ''
 option ignore 0
config dnssl
 option interface 'lan'
 list suffix ''
 option ignore 1
And finally /etc/config/dhcp6c: (Notable change is “sla_len” set to 0 for the lan interface, this specifies that we’re getting a /64, and assigning the delegation to the inside interface.)
config 'dhcp6c' 'basic'
 option 'enabled' '1' # 1 = enabled; 0 = disabled
 option 'interface' 'wan' # This is the interface the DHCPv6 client will run on
 #option 'dns' 'dnsmasq' # Which DNS server you run (only dnsmasq currently supported)
 option 'debug' '0' # 1 = enable debugging; 0 = disable debugging
 # Send options (1 = send; 0 = do not send)
 option 'pd' '1' # Prefix Delegation
 #option 'na' '1' # Non-Temporary Address
 option 'na' '0' # Non-Temporary Address
 option 'rapid_commit' '1' # Rapid Commit
 # Request options (1 = request; 0 = do not request)
 option 'domain_name_servers' '1'
 option 'domain_name' '0'
 option 'ntp_servers' '0'
 option 'sip_server_address' '0'
 option 'sip_server_domain_name' '0'
 option 'nis_server_address' '0'
 option 'nis_domain_name' '0'
 option 'nisp_server_address' '0'
 option 'nisp_domain_name' '0'
 option 'bcmcs_server_address' '0'
 option 'bcmcs_server_domain_name' '0'
 # Override the used DUID, by default it is derived from the interface MAC
 # The given value must be uppercase and globally unique!
 #option 'duid' '00:03:00:06:D8:5D:4C:A5:03:F2'
 # Script to run when a reply is received
 option 'script' '/usr/bin/dhcp6c-state'
 # Define one or more interfaces on which prefixes should be assigned
#config 'interface' 'loopback'
# option 'enabled' '1' # 1 = enabled; 0 = disabled
# option 'sla_id' '0' # Site level aggregator identifier specified in decimal (subnet)
# option 'sla_len' '4' # Site level aggregator length (64 - size of prefix being delegated)
 # e.g. /60 from ISP -> 64 - 60 = 4
config 'interface' 'lan'
 option 'enabled' '1'
 option 'sla_id' '0'
 option 'sla_len' '0'