For the past few months, I invested some bucks on my high-speed network project. I’ve got a HPE ProLiant MicroServer Gen10 Plus serving as the NAS, and a 10GbE switch QSW-M2108R-2C from QNAP as the network backbone. On top of them, I’m using a Mikrotik hEX S (RB760iGS) as my main router. And you might have guessed, my AX88U now serves as an AP.

In case of your curiosity, this is how my gears stack now:

Network gears

Well enough talking, let’s go into the topic.

Set up DHCPv6-PD client

Enable DHCPv6 client

DHCPv6 client can be enabled with:

# Accept RA from ISP, so the router can get WAN address using SLAAC
/ipv6 settings set accept-router-advertisements=yes
# Configure DHCPv6 client:
# - Add default route: yes
# - WAN interface: ether1
# - IPv6 address pool: delegation (You can change to whatever you want)
# - Prefix length for DHCPv6 server's offering cascading routers: 60
# - Prefix-hint: 56 (This value may vary, depending on your ISP)
# - Request both WAN address and LAN prefix from ISP
/ipv6 dhcp-client add add-default-route=yes interface=ether1   \
  pool-name=delegation pool-prefix-length=60 prefix-hint=::/56 \
  request=address,prefix

Depending on your ISP, the prefix hint may vary. My ISP Charter Spectrum offers /56 prefixes, so I’m using ::/56 here.

Note that in order to make SLAAC (or DHCPv6 stateless) work, you’ll need a prefix at least shorter than /64. If your ISP won’t offer you a prefix shorter than /64, you can’t do subnetting (or more precisely, offering prefixes to cascading routers) without breaking IPv6, unless you wanna try the dirty NAT66.

The key parameter is the pool-prefix-length. This value determines the prefix length, or the subnet size, that the DHCPv6 server will offer for cascading routers.

For me, 60 is pretty reasonable: the main router is able to offer 16 /60 prefixes for cascading routers, and the cascading routers can offer another 16 /64 prefixes for their clients.

Now you can check if prefix is assigned with /ipv6 dhcp-client print and /ipv6 pool print:

[admin@MikroTik] > /ipv6 dhcp-client print
Flags: D - dynamic, X - disabled, I - invalid
 #    INTERFACE STATUS  REQUEST   PREFIX
 0    ether1    bound   address   2600:6c51:fake:n00b::/56, 4d22h24m10s
                        prefix
[admin@MikroTik] > /ipv6 pool print
Flags: D - dynamic 
 #   NAME       PREFIX                   PREFIX-LENGTH EXPIRES-AFTER
 0 D delegation 2600:6c51:fake:n00b::/56            60 4d22h23m52s

Add necessary IPv6 firewall rule

If the status keeps showing searching, check IPv6 firewall to see whether incoming packets to UDP port 546 (DHCPv6 client) is allowed. If not, this rule can be added via:

# Accept DHCPv6 client prefix delegation
/ipv6 firewall filter add action=accept chain=input \
  comment="Accept DHCPv6 client prefix delegation"  \ 
  dst-port=546 protocol=udp src-address=fe80::/10

Assign IPv6 address to interfaces

The last step is to assign IPv6 address on internal interface from address pool:

# RA is enabled by default. Clients connected to this interface 
# can get their IPv6 addresses via SLAAC. If you don't want clients
# configure themselves automatically or if you are running a separate 
# stateful DHCPv6 server, disable advertise with `advertise=no`
/ipv6 address add address=::1 from-pool=delegation interface=bridge

If you get multiple interfaces, run the above command on each interface separately. Use /ipv6 address print to check assigned addresses:

[admin@MikroTik] > /ipv6 address print
Flags: X - disabled, I - invalid, D - dynamic, G - global, L - link-local 
 #    ADDRESS                                 FROM-POOL  INTERFACE ADVERTISE
 0  G 2600:6c51:fake:n00b::1/64               delegation bridge    yes
 1 DL fe80::a55:31ff:fe00:fake/64                        bridge    no
 2 DL fe80::a55:31ff:fe00:fake/64                        ether1    no
 3 DG 2600:6c51:some:fake:addr:why:so:long/64            ether1    no

Set up DHCPv6-PD server

Note 1: Like I’ve mentioned before, you need a prefix at least shorter than /64 from your ISP to make DHCPv6-PD server works!

Note 2: In order to delegate prefixes to cascading routers, you have to assign a pool-prefix-length in RouterOS DHCPv6 client. Check the previous section for details.

Before started, I want to re-state the note (at least at the time of writing) from Mikrotik’s documentation:

Note: RouterOS DHCPv6 server can only delegate IPv6 prefixes, not addresses.

Mikrotik Documentation — Manual:IPv6/DHCP Server

In other words, DHCPv6 server in RouterOS is only capable of SLAAC (or stateless DHCPv6). There is no support for stateful DHCPv6.

Enable DHCPv6 server

The following command creates a DHCPv6 server:

# Delegate IPv6 addresses from pool `delegation`
# Lease is valid for 1 day
/ipv6 dhcp-server add address-pool=delegation \
  interface=bridge lease-time=1d name=default

Again, if you get multiple interfaces, run the above command on each interface separately.

Now you can check if cascading routers are assigned prefixes with /ipv6 dhcp-server binding print:

[admin@MikroTik] > /ipv6 dhcp-server binding print
Flags: I - invalid, X - disabled, R - radius, D - dynamic 
 #    ADDRESS                   DUID            SERVER   STATUS
 0  D 2600:6c51:fake:n01b::/60  0xa85e45fakeid  default  bound  

Congratulations! Your DHCPv6 services on RouterOS are working now.

… though there could be one more question: what if I want to configure DHCPv6 options (DNS, search domains, etc.)?

First you need to allow Other Configuration in IPv6 ND (neighbor discovery):

/ipv6 nd set [ find default=yes ] other-configuration=yes

Then we can set up DHCPv6 options. Here I’m creating option 23 (DNS) and 24 (domain search list):

/ipv6 dhcp-server option
# Option 23 (DNS): fd00::1
add code=23 name=dns value=0xfd000000000000000000000000000001
# Option 24 (domain search list): example.local
add code=24 name=domain-search value="0x07'example'0x05'local'0x00"

For option 23 (DNS), you need to assign a full 64-bit address in hexadecimal.

To grab the value of DHCPv6 option 24 (domain search list), use this tool: https://jjjordan.github.io/dhcp119/.

You may have noticed I’m using a ULA address fd00::1 for option 23. This allows me to assign my Mikrotik router as the default DNS without scripting.

The idea comes from dksoft. But for my application, I only need one command (to assign fd00::1):

# Assign `fd00::1` to interface `bridge` without RA
/ipv6 address add address=fd00::1 advertise=no interface=bridge

Note that RA is disabled, because I don’t want clients get SLAAC addresses from fd00::1/8 prefix.

The last step is to assign these options to DHCPv6 server:

# Server name and dhcp-option names should match
# what you have set above
/ipv6 dhcp-server set default dhcp-options=dns,domain-search

Conclusion

I’d say once you figure out how RouterOS works, it is much less painful than doing the same things on AX88U, though it might be unfair to AX88U since it is designed for consumer market.

So what have I learned? Well, if you have special requirements to fullfil, instead of going for all-in-one products (for example AX88U in this case: you get a router, a switch, and an AP), buy products that focuses on specific applications.

Trust me, it’s much more painless!