<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xml" href="https://wu.renjie.im/feed.xslt.xml"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.0">Jekyll</generator><link href="https://wu.renjie.im/feed.xml" rel="self" type="application/atom+xml" /><link href="https://wu.renjie.im/" rel="alternate" type="text/html" /><updated>2026-01-09T01:55:56-08:00</updated><id>https://wu.renjie.im/feed.xml</id><title type="html">I’m Renjie Wu</title><subtitle>This is Renjie Wu's personal website. This website also hosts supporting pages for papers in which he participated.</subtitle><author><name>Renjie Wu</name></author><entry xml:lang="zh-cn"><title type="html">在 Mikrotik RouterOS 6.48.2 上配置 DHCPv6-PD（前缀代理）</title><link href="https://wu.renjie.im/blog/network/ros-dhcpv6/zh-cn/" rel="alternate" type="text/html" title="在 Mikrotik RouterOS 6.48.2 上配置 DHCPv6-PD（前缀代理）" /><published>2021-06-05T01:05:17-07:00</published><updated>2021-06-05T01:05:17-07:00</updated><id>https://wu.renjie.im/blog/network/ros-dhcpv6/ros-dhcpv6</id><content type="html" xml:base="https://wu.renjie.im/blog/network/ros-dhcpv6/zh-cn/">&lt;p&gt;最近这段时间一直在折腾 10G 内网，先是买了 HPE 的 &lt;a href=&quot;https://h20195.www2.hpe.com/v2/getdocument.aspx?docname=a00073554enw&quot;&gt;MicroServer Gen10 Plus&lt;/a&gt;
来做 NAS，之后又买了威联通的交换机 &lt;a href=&quot;https://www.qnap.com/en-us/product/qsw-m2108r-2c&quot;&gt;QSW-M2108R-2C&lt;/a&gt;。路由器则选用的是 Mikrotik
的 &lt;a href=&quot;https://mikrotik.com/product/hex_s&quot;&gt;hEX S (RB760iGS)&lt;/a&gt;，而之前作为主力使用的 AX88U 变成了专职 AP。&lt;/p&gt;

&lt;p&gt;把它们堆在一起就是下面这个样子：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/ros-dhcpv6/gears.jpg&quot; alt=&quot;网络设备们&quot; /&gt;&lt;/p&gt;

&lt;p&gt;废话不多说，直接进入正题。&lt;/p&gt;

&lt;h2 id=&quot;配置-dhcpv6-pd-客户端&quot;&gt;配置 DHCPv6-PD 客户端&lt;/h2&gt;

&lt;h3 id=&quot;启用-dhcpv6-客户端&quot;&gt;启用 DHCPv6 客户端&lt;/h3&gt;
&lt;p&gt;登入 RouterOS 终端，输入以下命令启用 DHCPv6 客户端：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# 接受来自 ISP 的路由器通告 (RA)，以通过 SLAAC 获取 IPv6 WAN 地址
/ipv6 settings set accept-router-advertisements=yes
# DHCPv6 客户端配置:
# - 添加默认路由: yes
# - WAN 端口: ether1
# - IPv6 地址池名称: delegation（可以随意起名，之后的命令里对应修改）
# - IPv6 地址池前缀长度：60（这是关键，下文会解释）
# - IPv6 前缀提示: 56（和 ISP 挂钩，根据实际情况修改）
# - IPv6 请求：WAN 地址和 LAN 前缀
/ipv6 dhcp-client add add-default-route=yes interface=ether1   \
  pool-name=delegation pool-prefix-length=60 prefix-hint=::/56 \
  request=address,prefix&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;IPv6 前缀提示取决于你的 ISP，以我的 ISP 为例，Charter Spectrum 提供 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/56&lt;/code&gt; 的前缀，所以这里我使用的是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;::/56&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;要使 SLAAC（或者说无状态 DHCPv6）正常工作，你需要从 ISP 那拿到至少 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/63&lt;/code&gt; 的前缀（这种情况下可以划分两个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; 的子网）。如果 ISP 
最多只给分配 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; 的前缀，那就和前缀代理无缘了 —— 能用的方案只有 &lt;a href=&quot;https://datatracker.ietf.org/doc/html/draft-mrw-nat66-00&quot;&gt;NAT66&lt;/a&gt; 
和 &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc4389&quot;&gt;NDPv6 代理&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;这条命令中的关键是&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pool-prefix-length&lt;/code&gt; &lt;strong&gt;参数：它决定了下文中 DHCPv6 服务器下发前缀的长度（或者说二级路由器拿到的前缀的长度）。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这里我设置的是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;60&lt;/code&gt;，在 ISP 分配给我 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/56&lt;/code&gt; 前缀的前提下，hEX S 可以划分出 16 个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/60&lt;/code&gt; 的前缀给二级路由器使用，二级路由器则可以提供另外 16 个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; 的前缀给它们的设备使用。&lt;/p&gt;

&lt;p&gt;运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/ipv6 dhcp-client print&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/ipv6 pool print&lt;/code&gt; 来查看 ISP 分配的前缀：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;[admin@MikroTik] &amp;gt; /ipv6 dhcp-client print&lt;/span&gt;
Flags: &lt;strong&gt;D&lt;/strong&gt; - dynamic, &lt;strong&gt;X&lt;/strong&gt; - disabled, &lt;strong&gt;I&lt;/strong&gt; - invalid
 &lt;strong&gt;#    INTERFACE STATUS  REQUEST   PREFIX&lt;/strong&gt;
 0    ether1    &lt;strong class=&quot;mi&quot;&gt;bound&lt;/strong&gt;   address   &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n00b::/56&lt;/strong&gt;, 4d22h24m10s
                        prefix
&lt;span class=&quot;c&quot;&gt;[admin@MikroTik] &amp;gt; /ipv6 pool print&lt;/span&gt;
Flags: &lt;strong&gt;D&lt;/strong&gt; - dynamic 
 &lt;strong&gt;#   NAME       PREFIX                   PREFIX-LENGTH EXPIRES-AFTER&lt;/strong&gt;
 0 D delegation &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n00b::/56&lt;/strong&gt;            60 4d22h23m52s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;添加必要的-ipv6-防火墙规则&quot;&gt;添加必要的 IPv6 防火墙规则&lt;/h3&gt;

&lt;p&gt;如果上面命令的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STATUS&lt;/code&gt; 一栏一直显示的是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;searching&lt;/code&gt;，那么有可能是 IPv6 防火墙阻止了 UDP 端口 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;546&lt;/code&gt; 的连接入站。&lt;/p&gt;

&lt;p&gt;运行下面的命令添加允许 UDP 546 入站的规则：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# 允许 DHCPv6 客户端尝试前缀代理
/ipv6 firewall filter add action=accept chain=input \
  comment=&quot;Accept DHCPv6 client prefix delegation&quot;  \ 
  dst-port=546 protocol=udp src-address=fe80::/10&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;为-lan-端口分配-ipv6-地址&quot;&gt;为 LAN 端口分配 IPv6 地址&lt;/h3&gt;

&lt;p&gt;最后一步是从 IPv6 地址池中为默认网桥分配 IPv6 地址：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# RouterOS 默认启用了 RA，这样下级设备才能通过 SLAAC 自动配置 IPv6 地址。
# （原因是 RouterOS 的 DHCPv6 目前暂不支持有状态 IPv6 地址分配）
# 如果有单独运行的有状态 DHCPv6 服务器，则应该在后面加上 `advertise=no`。
/ipv6 address add address=::1 from-pool=delegation interface=bridge&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;如果有多个网桥或端口，则需要对每个网桥和端口单独运行上面的命令。运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/ipv6 address print&lt;/code&gt; 来查看分配到 LAN 端口的地址：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;[admin@MikroTik] &amp;gt; /ipv6 address print&lt;/span&gt;
Flags: &lt;strong&gt;X&lt;/strong&gt; - disabled, &lt;strong&gt;I&lt;/strong&gt; - invalid, &lt;strong&gt;D&lt;/strong&gt; - dynamic, &lt;strong&gt;G&lt;/strong&gt; - global, &lt;strong&gt;L&lt;/strong&gt; - link-local 
 &lt;strong&gt;#    ADDRESS                                 FROM-POOL  INTERFACE ADVERTISE&lt;/strong&gt;
 0 &lt;strong&gt; G&lt;/strong&gt; &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n00b::1/64&lt;/strong&gt;               &lt;strong class=&quot;mi&quot;&gt;delegation&lt;/strong&gt; bridge    &lt;strong class=&quot;mi&quot;&gt;yes&lt;/strong&gt;
 1 &lt;strong&gt;DL&lt;/strong&gt; fe80::a55:31ff:fe00:fake/64                        bridge    no
 2 &lt;strong&gt;DL&lt;/strong&gt; fe80::a55:31ff:fe00:fake/64                        ether1    no
 3 &lt;strong&gt;DG&lt;/strong&gt; &lt;strong class=&quot;mi&quot;&gt;2600:6c51:some:fake:addr:why:so:long/64&lt;/strong&gt;            ether1    no
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;配置-dhcpv6-pd-服务器&quot;&gt;配置 DHCPv6-PD 服务器&lt;/h2&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;注意 1：&lt;/strong&gt;要使用 DHCPv6-PD 服务器，你需要从 ISP 那拿到&lt;strong&gt;至少&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/63&lt;/code&gt; 的 IPv6 前缀。&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;注意 2：&lt;/strong&gt; 为了能让二级路由器通过 DHCPv6-PD 拿到前缀，上一节 DHCPv6 客户端中的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pool-prefix-length&lt;/code&gt; 参数必须正确设置。&lt;/p&gt;

&lt;p&gt;开始之前，先重申一下 Mikrotik 文档中的说明：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: RouterOS DHCPv6 server can only delegate IPv6 prefixes, not addresses.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p class=&quot;small&quot;&gt;Mikrotik Documentation — &lt;cite&gt;&lt;a href=&quot;https://wiki.mikrotik.com/wiki/Manual:IPv6/DHCP_Server&quot;&gt;Manual:IPv6/DHCP Server&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;换句话说，RouterOS 的 DHCPv6 服务器目前只支持 SLAAC（无状态 DHCPv6）。&lt;/p&gt;

&lt;h3 id=&quot;启用-dhcpv6-服务器&quot;&gt;启用 DHCPv6 服务器&lt;/h3&gt;

&lt;p&gt;下面的命令用于创建 DHCPv6 服务器：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# 从地址池 `delegation` 中代理 IPv6 地址
# 租约有效期为 1 天
/ipv6 dhcp-server add address-pool=delegation \
  interface=bridge lease-time=1d name=default&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;如果有多个网桥或端口，则需要对每个网桥和端口单独运行上面的命令。&lt;/p&gt;

&lt;p&gt;现在就可以运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/ipv6 dhcp-server binding print&lt;/code&gt; 来检查二级路由器有没有拿到前缀：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;[admin@MikroTik] &amp;gt; /ipv6 dhcp-server binding print&lt;/span&gt;
Flags: &lt;strong&gt;I&lt;/strong&gt; - invalid, &lt;strong&gt;X&lt;/strong&gt; - disabled, &lt;strong&gt;R&lt;/strong&gt; - radius, &lt;strong&gt;D&lt;/strong&gt; - dynamic 
 &lt;strong&gt;#    ADDRESS                   DUID            SERVER   STATUS&lt;/strong&gt;
 0  &lt;strong&gt;D&lt;/strong&gt; &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n01b::/60&lt;/strong&gt;  0xa85e45fakeid  default  &lt;strong class=&quot;mi&quot;&gt;bound&lt;/strong&gt;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果看到类似上面的输出，那就说明 DHCPv6 服务器已经正常工作了。&lt;/p&gt;

&lt;h3 id=&quot;配置-dhcpv6-选项&quot;&gt;配置 DHCPv6 选项&lt;/h3&gt;

&lt;p&gt;如果想通过 DHCPv6 下发诸如 DNS (Option 23) 和域搜索列表 (Option 24) 等选项，则需要先在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IPv6 ND&lt;/code&gt; 中启用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Other Configuration&lt;/code&gt;：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;/ipv6 nd set [ find default=yes ] other-configuration=yes&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;然后就可以设置 DHCPv6 选项了，这里我创建了 DNS 和域搜索列表两个选项：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;/ipv6 dhcp-server option
# Option 23 (DNS): fd00::1
add code=23 name=dns value=0xfd000000000000000000000000000001
# Option 24 (域搜索列表): example.local
add code=24 name=domain-search value=&quot;0x07'example'0x05'local'0x00&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;DNS (Option 23) 需要打上完整的 64 位十六进制 IPv6 地址，域搜索列表 (Option 24) 则可以使用这个工具生成：&lt;a href=&quot;https://jjjordan.github.io/dhcp119/&quot;&gt;https://jjjordan.github.io/dhcp119/&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;我这里的 DNS 设置的是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fd00::1&lt;/code&gt;，这样不需要额外的脚本就能让 hEX S 作为内网的默认 DNS （否则的话需要使用脚本来获取公网 IPv6 地址）。&lt;/p&gt;

&lt;p&gt;这个方法来源于 &lt;a href=&quot;https://forum.mikrotik.com/viewtopic.php?t=132657#p653055&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dksoft&lt;/code&gt;&lt;/a&gt;。不过对于我的应用场景而言，只需要一条命令：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# 为 `bridge` 分配 `fd00::1`，不启用 RA
/ipv6 address add address=fd00::1 advertise=no interface=bridge&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;这里没有启用 RA，因为不想也没必要让设备拿到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fd00::1/8&lt;/code&gt; 前缀的地址。&lt;/p&gt;

&lt;p&gt;最后一步就是把这些选项添加到 DHCPv6 服务器上：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# 根据你的设置对应修改服务器名称和选项名称
/ipv6 dhcp-server set default dhcp-options=dns,domain-search&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;总结&quot;&gt;总结&lt;/h2&gt;

&lt;p&gt;RouterOS 的学习曲线还是有些陡峭的，但是一旦搞明白怎么回事，属实比在 AX88U 上做相同的事来的轻松的多（感觉在讲废话，毕竟 AX88U 是针对消费市场的）。&lt;/p&gt;

&lt;p&gt;无论如何，相对于 AX88U 这种多合一的设备，确实是发现还是专事专做比较好，尤其是有那种特殊或者专业需求的时候。&lt;/p&gt;

&lt;script src=&quot;/assets/js/prism-core.min.js&quot; data-manual=&quot;yes&quot;&gt;&lt;/script&gt;

&lt;script&gt;
(function (Prism) {
    var cmds = &quot;check-for-updates|sup-output|serial-terminal|reset-configuration|upgrade|stop|set|disable|enable|add|remove|return|delay|do|error|execute|find|for|foreach|global|if|len|local|nothing|parse|pick|put|resolve|set|time|toarray|tobool|toid|toip|toip6|tonum|tostr|totime|typeof|while|beep|export|import|led|password|ping|quit|redo|setup|undo|print|detail|file|log|info|get|cancel|download&quot;;
    Prism.languages.ros = {
        'comment': /#.*/,
        'string': {
            pattern: /([&quot;'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
            greedy: true
        },
        'ros-parameter': /\b[\w.-]+?(?=(=))\b/g,
        /* 'ros-value': /=.*?(?=(\s|$|\t|&quot;|{|;))/g, */
        'ros-command': new RegExp(&quot;\\b(&quot; + cmds + &quot;)( |$|\\t)&quot;, &quot;g&quot;),
        'ros-menu': new RegExp(&quot;^[\\\/:].*?(?=(&quot; + cmds + &quot;|$)(?=\\s|$))&quot;, &quot;gm&quot;)
    };

    var rosBlocks = document.querySelectorAll(&quot;code[data-lang='ros']&quot;);
    /* Fix for IE */
    Array.prototype.forEach.call(rosBlocks, function (element) { Prism.highlightElement(element); });
}(Prism));
&lt;/script&gt;</content><author><name>Renjie Wu</name></author><category term="Network" /><summary type="html">个人对于 [NAT66](https://datatracker.ietf.org/doc/html/draft-mrw-nat66-00) 一直持有敬而远之的态度（毕竟这实在是太不 IPv6 了）。当然，迄今为止依然还有不少 ISP 只分配 /64 的前缀，这种情况下除却 NAT66 也就只能考虑 [NDPv6 代理](https://datatracker.ietf.org/doc/html/rfc4389)。总的来说，如果能够从 ISP 那拿到比 /64 更短的前缀，前缀代理毫无疑问是（自动）划分 IPv6 子网的最佳方案。</summary></entry><entry xml:lang="en-us"><title type="html">Configure DHCPv6-PD (Prefix Delegation) Client &amp;amp; Server on Mikrotik RouterOS 6.48.2</title><link href="https://wu.renjie.im/blog/network/ros-dhcpv6/" rel="alternate" type="text/html" title="Configure DHCPv6-PD (Prefix Delegation) Client &amp;amp; Server on Mikrotik RouterOS 6.48.2" /><published>2021-05-24T23:19:58-07:00</published><updated>2021-06-04T18:06:20-07:00</updated><id>https://wu.renjie.im/blog/network/ros-dhcpv6</id><content type="html" xml:base="https://wu.renjie.im/blog/network/ros-dhcpv6/">&lt;p&gt;For the past few months, I invested some bucks on my high-speed network project. I’ve got a &lt;a href=&quot;https://h20195.www2.hpe.com/v2/getdocument.aspx?docname=a00073554enw&quot;&gt;HPE ProLiant MicroServer Gen10 Plus&lt;/a&gt; serving as the NAS, and a 10GbE switch &lt;a href=&quot;https://www.qnap.com/en-us/product/qsw-m2108r-2c&quot;&gt;QSW-M2108R-2C&lt;/a&gt; from QNAP as the network backbone. On top of them, I’m using a &lt;a href=&quot;https://mikrotik.com/product/hex_s&quot;&gt;Mikrotik hEX S (RB760iGS)&lt;/a&gt; as my main router. And you might have guessed, my AX88U now serves as an AP.&lt;/p&gt;

&lt;p&gt;In case of your curiosity, this is how my gears stack now:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/ros-dhcpv6/gears.jpg&quot; alt=&quot;Network gears&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Well enough talking, let’s go into the topic.&lt;/p&gt;

&lt;h2 id=&quot;set-up-dhcpv6-pd-client&quot;&gt;Set up DHCPv6-PD client&lt;/h2&gt;

&lt;h3 id=&quot;enable-dhcpv6-client&quot;&gt;Enable DHCPv6 client&lt;/h3&gt;
&lt;p&gt;DHCPv6 client can be enabled with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# 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&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Depending on your ISP, the prefix hint may vary. My ISP Charter Spectrum offers &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/56&lt;/code&gt; prefixes, so I’m using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;::/56&lt;/code&gt; here.&lt;/p&gt;

&lt;p&gt;Note that in order to make SLAAC (or DHCPv6 stateless) work, you’ll need a prefix at least shorter than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt;. If your 
ISP won’t offer you a prefix shorter than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt;, you can’t do subnetting (or more precisely, offering prefixes to cascading routers) 
without breaking IPv6, unless you wanna try the dirty &lt;a href=&quot;https://datatracker.ietf.org/doc/html/draft-mrw-nat66-00&quot;&gt;NAT66&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The key parameter is the&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pool-prefix-length&lt;/code&gt;&lt;strong&gt;. This value determines the prefix length, or the subnet size, that the DHCPv6 server will offer for cascading routers.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For me, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;60&lt;/code&gt; is pretty reasonable: the main router is able to offer 16 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/60&lt;/code&gt; prefixes for cascading routers, and the 
cascading routers can offer another 16 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; prefixes for their clients.&lt;/p&gt;

&lt;p&gt;Now you can check if prefix is assigned with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/ipv6 dhcp-client print&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/ipv6 pool print&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;[admin@MikroTik] &amp;gt; /ipv6 dhcp-client print&lt;/span&gt;
Flags: &lt;strong&gt;D&lt;/strong&gt; - dynamic, &lt;strong&gt;X&lt;/strong&gt; - disabled, &lt;strong&gt;I&lt;/strong&gt; - invalid
 &lt;strong&gt;#    INTERFACE STATUS  REQUEST   PREFIX&lt;/strong&gt;
 0    ether1    &lt;strong class=&quot;mi&quot;&gt;bound&lt;/strong&gt;   address   &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n00b::/56&lt;/strong&gt;, 4d22h24m10s
                        prefix
&lt;span class=&quot;c&quot;&gt;[admin@MikroTik] &amp;gt; /ipv6 pool print&lt;/span&gt;
Flags: &lt;strong&gt;D&lt;/strong&gt; - dynamic 
 &lt;strong&gt;#   NAME       PREFIX                   PREFIX-LENGTH EXPIRES-AFTER&lt;/strong&gt;
 0 D delegation &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n00b::/56&lt;/strong&gt;            60 4d22h23m52s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;add-necessary-ipv6-firewall-rule&quot;&gt;Add necessary IPv6 firewall rule&lt;/h3&gt;

&lt;p&gt;If the status keeps showing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;searching&lt;/code&gt;, check IPv6 firewall to see whether incoming packets to UDP port &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;546&lt;/code&gt; 
(DHCPv6 client) is allowed. If not, this rule can be added via:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# Accept DHCPv6 client prefix delegation
/ipv6 firewall filter add action=accept chain=input \
  comment=&quot;Accept DHCPv6 client prefix delegation&quot;  \ 
  dst-port=546 protocol=udp src-address=fe80::/10&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;assign-ipv6-address-to-interfaces&quot;&gt;Assign IPv6 address to interfaces&lt;/h3&gt;

&lt;p&gt;The last step is to assign IPv6 address on internal interface from address pool:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# 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&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you get multiple interfaces, run the above command on each interface separately. Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/ipv6 address print&lt;/code&gt; to check 
assigned addresses:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;[admin@MikroTik] &amp;gt; /ipv6 address print&lt;/span&gt;
Flags: &lt;strong&gt;X&lt;/strong&gt; - disabled, &lt;strong&gt;I&lt;/strong&gt; - invalid, &lt;strong&gt;D&lt;/strong&gt; - dynamic, &lt;strong&gt;G&lt;/strong&gt; - global, &lt;strong&gt;L&lt;/strong&gt; - link-local 
 &lt;strong&gt;#    ADDRESS                                 FROM-POOL  INTERFACE ADVERTISE&lt;/strong&gt;
 0 &lt;strong&gt; G&lt;/strong&gt; &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n00b::1/64&lt;/strong&gt;               &lt;strong class=&quot;mi&quot;&gt;delegation&lt;/strong&gt; bridge    &lt;strong class=&quot;mi&quot;&gt;yes&lt;/strong&gt;
 1 &lt;strong&gt;DL&lt;/strong&gt; fe80::a55:31ff:fe00:fake/64                        bridge    no
 2 &lt;strong&gt;DL&lt;/strong&gt; fe80::a55:31ff:fe00:fake/64                        ether1    no
 3 &lt;strong&gt;DG&lt;/strong&gt; &lt;strong class=&quot;mi&quot;&gt;2600:6c51:some:fake:addr:why:so:long/64&lt;/strong&gt;            ether1    no
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;set-up-dhcpv6-pd-server&quot;&gt;Set up DHCPv6-PD server&lt;/h2&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note 1:&lt;/strong&gt; Like I’ve mentioned before, you need a prefix &lt;strong&gt;at least shorter than&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; from your ISP to make DHCPv6-PD server works!&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note 2:&lt;/strong&gt; In order to delegate prefixes to cascading routers, you have to assign a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pool-prefix-length&lt;/code&gt; in RouterOS DHCPv6 client. 
Check the &lt;a href=&quot;#enable-dhcpv6-client&quot;&gt;previous section&lt;/a&gt; for details.&lt;/p&gt;

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

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: RouterOS DHCPv6 server can only delegate IPv6 prefixes, not addresses.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p class=&quot;small&quot;&gt;Mikrotik Documentation — &lt;cite&gt;&lt;a href=&quot;https://wiki.mikrotik.com/wiki/Manual:IPv6/DHCP_Server&quot;&gt;Manual:IPv6/DHCP Server&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;In other words, DHCPv6 server in RouterOS is only capable of SLAAC (or stateless DHCPv6). There is no support for stateful DHCPv6.&lt;/p&gt;

&lt;h3 id=&quot;enable-dhcpv6-server&quot;&gt;Enable DHCPv6 server&lt;/h3&gt;

&lt;p&gt;The following command creates a DHCPv6 server:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# 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&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Again, if you get multiple interfaces, run the above command on each interface separately.&lt;/p&gt;

&lt;p&gt;Now you can check if cascading routers are assigned prefixes with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/ipv6 dhcp-server binding print&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;[admin@MikroTik] &amp;gt; /ipv6 dhcp-server binding print&lt;/span&gt;
Flags: &lt;strong&gt;I&lt;/strong&gt; - invalid, &lt;strong&gt;X&lt;/strong&gt; - disabled, &lt;strong&gt;R&lt;/strong&gt; - radius, &lt;strong&gt;D&lt;/strong&gt; - dynamic 
 &lt;strong&gt;#    ADDRESS                   DUID            SERVER   STATUS&lt;/strong&gt;
 0  &lt;strong&gt;D&lt;/strong&gt; &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n01b::/60&lt;/strong&gt;  0xa85e45fakeid  default  &lt;strong class=&quot;mi&quot;&gt;bound&lt;/strong&gt;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Congratulations! Your DHCPv6 services on RouterOS are working now.&lt;/p&gt;

&lt;h3 id=&quot;advertise-dhcpv6-options&quot;&gt;Advertise DHCPv6 options&lt;/h3&gt;

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

&lt;p&gt;First you need to allow &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Other Configuration&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IPv6 ND&lt;/code&gt; (neighbor discovery):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;/ipv6 nd set [ find default=yes ] other-configuration=yes&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;/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=&quot;0x07'example'0x05'local'0x00&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For option 23 (DNS), you need to assign a full 64-bit address in hexadecimal.&lt;/p&gt;

&lt;p&gt;To grab the value of DHCPv6 option 24 (domain search list), use this tool: &lt;a href=&quot;https://jjjordan.github.io/dhcp119/&quot;&gt;https://jjjordan.github.io/dhcp119/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You may have noticed I’m using a ULA address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fd00::1&lt;/code&gt; for option 23. This allows me to assign my Mikrotik router as 
the default DNS without scripting.&lt;/p&gt;

&lt;p&gt;The idea comes from &lt;a href=&quot;https://forum.mikrotik.com/viewtopic.php?t=132657#p653055&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dksoft&lt;/code&gt;&lt;/a&gt;. But for my application, I only
need one command (to assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fd00::1&lt;/code&gt;):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# Assign `fd00::1` to interface `bridge` without RA
/ipv6 address add address=fd00::1 advertise=no interface=bridge&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that RA is disabled, because I don’t want clients get SLAAC addresses from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fd00::1/8&lt;/code&gt; prefix.&lt;/p&gt;

&lt;p&gt;The last step is to assign these options to DHCPv6 server:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ros&quot; data-lang=&quot;ros&quot;&gt;# Server name and dhcp-option names should match
# what you have set above
/ipv6 dhcp-server set default dhcp-options=dns,domain-search&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Trust me, it’s much more painless!&lt;/p&gt;

&lt;script src=&quot;/assets/js/prism-core.min.js&quot; data-manual=&quot;yes&quot;&gt;&lt;/script&gt;

&lt;script&gt;
(function (Prism) {
    var cmds = &quot;check-for-updates|sup-output|serial-terminal|reset-configuration|upgrade|stop|set|disable|enable|add|remove|return|delay|do|error|execute|find|for|foreach|global|if|len|local|nothing|parse|pick|put|resolve|set|time|toarray|tobool|toid|toip|toip6|tonum|tostr|totime|typeof|while|beep|export|import|led|password|ping|quit|redo|setup|undo|print|detail|file|log|info|get|cancel|download&quot;;
    Prism.languages.ros = {
        'comment': /#.*/,
        'string': {
            pattern: /([&quot;'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
            greedy: true
        },
        'ros-parameter': /\b[\w.-]+?(?=(=))\b/g,
        /* 'ros-value': /=.*?(?=(\s|$|\t|&quot;|{|;))/g, */
        'ros-command': new RegExp(&quot;\\b(&quot; + cmds + &quot;)( |$|\\t)&quot;, &quot;g&quot;),
        'ros-menu': new RegExp(&quot;^[\\\/:].*?(?=(&quot; + cmds + &quot;|$)(?=\\s|$))&quot;, &quot;gm&quot;)
    };

    var rosBlocks = document.querySelectorAll(&quot;code[data-lang='ros']&quot;);
    /* Fix for IE */
    Array.prototype.forEach.call(rosBlocks, function (element) { Prism.highlightElement(element); });
}(Prism));
&lt;/script&gt;</content><author><name>Renjie Wu</name></author><category term="Network" /><summary type="html">Who would ever need dirty hacky buggy shaky [NAT66](https://datatracker.ietf.org/doc/html/draft-mrw-nat66-00) if one can utilize prefix delegation? With a little bit effort, your Mikrotik router can serve as the centerpiece of your local IPv6 services. In this post, I'll introduce how to set up DHCPv6-PD on Mikrotik RouterOS 6.48.2.</summary></entry><entry xml:lang="en-us"><title type="html">Don’t use STL `regex` library in Microsoft Visual C++ (MSVC), at least for now</title><link href="https://wu.renjie.im/blog/programming/dont-use-stl-regex/" rel="alternate" type="text/html" title="Don’t use STL `regex` library in Microsoft Visual C++ (MSVC), at least for now" /><published>2021-02-28T23:08:12-08:00</published><updated>2021-03-01T02:31:48-08:00</updated><id>https://wu.renjie.im/blog/programming/dont-use-stl-regex</id><content type="html" xml:base="https://wu.renjie.im/blog/programming/dont-use-stl-regex/">&lt;p&gt;I’ve been working on the new research projects for several days. The first task is pretty simple: load some datasets in
&lt;a href=&quot;https://www.cs.ucr.edu/~eamonn/time_series_data_2018/&quot;&gt;UCR Time Series Archive&lt;/a&gt; into memory.&lt;/p&gt;

&lt;p&gt;In our previous papers&lt;sup id=&quot;fnref:fastdtw-is-slow&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:fastdtw-is-slow&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;,&lt;/sup&gt;&lt;sup id=&quot;fnref:ETSC-is-meaningless&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:ETSC-is-meaningless&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, since the original authors’ algorithms 
were done in Java (FastDTW&lt;sup id=&quot;fnref:fastdtw&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:fastdtw&quot; class=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;, TEASER&lt;sup id=&quot;fnref:teaser&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:teaser&quot; class=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;, etc.), I’ve mainly written Java for related experiments. I haven’t
touched C++ for a while, so this time I decided to use C++, but I never expected to pay the “price” for my choice.&lt;/p&gt;

&lt;h2 id=&quot;how-could-it-go-wrong-with-t&quot;&gt;How could it go wrong with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\t+&lt;/code&gt;?&lt;/h2&gt;

&lt;p&gt;The file format of UCR Time Series Archive is pretty straightforward: &lt;em&gt;n&lt;/em&gt; rows of time series in each dataset, and for 
each time series, there are &lt;em&gt;m&lt;/em&gt; columns separated by TAB (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\t&lt;/code&gt;), representing &lt;em&gt;m&lt;/em&gt; datapoints.&lt;/p&gt;

&lt;p&gt;C++ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;string&amp;gt;&lt;/code&gt; library didn’t come with a built-in splitting function, and I don’t really want to use 3rd-party libraries
(like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boost::split&lt;/code&gt;) in my little project. It could be very painful to use external libraries in C++, and when it comes 
to compatibility issues, oh man good luck to you.&lt;/p&gt;

&lt;p&gt;I know I could make it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string::find&lt;/code&gt;, but hey it’s year 2021, C++ 20 was finalized last September, and I believe 
there must be fancier way than tedious &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string::find&lt;/code&gt;, so I came up with an idea: searching “How to split string in modern 
C++” on Stack Overflow.&lt;/p&gt;

&lt;p&gt;And I did get a hit: &lt;a href=&quot;https://stackoverflow.com/questions/9435385/split-a-string-using-c11&quot;&gt;Split a string using C++ 11&lt;/a&gt;,
a question asked 9 years ago. The &lt;a href=&quot;https://stackoverflow.com/a/9437426&quot;&gt;most voted answer&lt;/a&gt; showed an “elegant” way 
using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::regex_token_iterator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So I wrote down this piece of code in Visual Studio 2019 (MSVC v14.28.29333, the latest version at the time of writing):&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeSeriesDataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;TimeSeriesDataset&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;readTSV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tsvPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;TimeSeriesDataset&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ifstream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tsvPath&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;R&quot;(\t+)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cregex_token_iterator&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from_chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datapoints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;back_inserter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datapoints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[](&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subMatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from_chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subMatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subMatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datapoints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that I wrote a regular expression of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\t+&lt;/code&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; sign is in fact not necessary in my case, but 
at that time I didn’t think too much about this simple expression. Consider the DFA only contains two states:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/dont-use-stl-regex/dfa.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/dont-use-stl-regex/dfa.png&quot; alt=&quot;DFA for regular expression `\t+`&quot; width=&quot;222px&quot; class=&quot;align-center&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How could it possibly go wrong?&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;bad-regex-implementation-in-msvc&quot;&gt;Bad &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;regex&amp;gt;&lt;/code&gt; implementation in MSVC&lt;/h2&gt;

&lt;h3 id=&quot;regex_token_iterator-takes-too-long&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;++regex_token_iterator&lt;/code&gt; takes too long&lt;/h3&gt;

&lt;p&gt;When I hit F5 to launch the program, I immediately noticed there is something wrong: it took way too long to load &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mallat_TEST.tsv&lt;/code&gt;.
I won’t consider this file to be big: essentially a 2345 x 1025 matrix of decimal, and my past experience in Java showed that
a second should be long enough to load this file.&lt;/p&gt;

&lt;p&gt;So I started the performance profiler to see what happened. To my surprise, it takes &lt;em&gt;6 full minutes&lt;/em&gt; (under 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Debug (Win32)&lt;/code&gt; configuration) to finish running the program on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mallat_TEST.tsv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The hot path analysis reveals which operations hold the most CPU time (click picture to enlarge):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/dont-use-stl-regex/hotpath.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/dont-use-stl-regex/hotpath.png&quot; alt=&quot;Hot path analysis result&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apparently most of the time was spent in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::transform&lt;/code&gt;, which implicitly refers to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::regex_token_iterator::operator++&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Following the call tree reveals creating, deleting, and assigning object &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::_Tgt_state_t&lt;/code&gt; in function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::_Matcher::_Do_if&lt;/code&gt; caused the problem:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/dont-use-stl-regex/tgt_state_call_tree.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/dont-use-stl-regex/tgt_state_call_tree.png&quot; alt=&quot;`std::_Tgt_state_t` in `std::Matcher::_Do_if`&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also if we sort used CPU time by functions, it reveals the same issue:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/dont-use-stl-regex/tgt_state_function.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/dont-use-stl-regex/tgt_state_function.png&quot; alt=&quot;`std::_Tgt_state_t`'s CPU time&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means there must be something wrong with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::_Tgt_state_t&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;what-indeed-happened&quot;&gt;What indeed happened?&lt;/h3&gt;

&lt;p&gt;So I looked into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;regex&amp;gt;&lt;/code&gt;’s source code for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Matcher::_Do_if&lt;/code&gt;. The first glance looks pretty normal:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// IMPLEMENTATION OF _Matcher&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_BidIt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_Elem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_RxTraits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_It&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Matcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_BidIt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Elem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_RxTraits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_It&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Do_if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Node_if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// apply if node&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_Tgt_state_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_It&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_St&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// look for the first match&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Node&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// process one branch of if&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_St&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// rewind to where the alternation starts in input&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Match_pat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// try to match this branch&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// if none of the if branches matched, fail to match&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// if we aren't looking for the longest match, that's it&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Longest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// see if there is a longer match&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_Tgt_state_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_It&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Final&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Final_len&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_STD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_St&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Cur&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Cur&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(;;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// process one branch of if&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_Node&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_St&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Match_pat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// record match if it is longer&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_STD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_St&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Cur&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Cur&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Final_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// memorize longest so far&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;_Final&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;_Final_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// set the input end to the longest match&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Final&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Tgt_state&lt;/code&gt; is a member of class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Matcher&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, if we take a closer look on how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Tgt_state&lt;/code&gt; is assigned and other temporary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Tgt_state_t&lt;/code&gt; variables 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_St&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Final&lt;/code&gt; are constructed:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;_Tgt_state_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_It&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_St&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_St&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_Tgt_state_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_It&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Final&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_Final&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_Tgt_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Final&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All these assignments are implicitly invoking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operator=&lt;/code&gt;, and the default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operator=&lt;/code&gt; performs a member-wise copy, which
could lead to &lt;strong&gt;deep copy&lt;/strong&gt; if there are STL containers without special handling mechanism.&lt;/p&gt;

&lt;p&gt;A later look at the definition of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Tgt_state_t&lt;/code&gt; proves my thought:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// CLASS TEMPLATE _Bt_state_t&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_BidIt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_Bt_state_t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// holds the state needed for backtracking&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_BidIt&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Cur&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Grp_valid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// CLASS TEMPLATE _Tgt_state_t&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_BidIt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_Tgt_state_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Bt_state_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_BidIt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// holds the current state of the match&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_Grp_t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// stores a pair of iterators&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_BidIt&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_BidIt&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_End&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Grp_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Grps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Bt_state_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_BidIt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Bt_state_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_BidIt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;amp;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Tgt_state_t&lt;/code&gt; has two member variables: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Grps&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Grp_valid&lt;/code&gt; (inherited from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Bt_state_t&lt;/code&gt;). Both of them
are STL container &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vector&lt;/code&gt;, and by default, performing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operator=&lt;/code&gt; over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vector&lt;/code&gt; incurs &lt;strong&gt;deep copy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Deep copy is already evil. To make it worse, the hot path reveals &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Do_if&lt;/code&gt; would be called recursively 
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Match_pat&lt;/code&gt; calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Do_if&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Do_if&lt;/code&gt; calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Match_pat&lt;/code&gt;). This means &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Tgt_state_t&lt;/code&gt; variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_St&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Final&lt;/code&gt; 
are created and deleted every single time when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Do_if&lt;/code&gt; is called.&lt;/p&gt;

&lt;p&gt;Remember class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_Tgt_state_t&lt;/code&gt; has two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vector&lt;/code&gt; member variables, and by default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vector&lt;/code&gt; requires memory allocation/deallocation on heap.
Normally this overhead seems neglectable, but under the circumstance of recursion, it could be a problem. The CPU time
used by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vector&lt;/code&gt; constructor/deconstructor proves:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/dont-use-stl-regex/vector_function.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/dont-use-stl-regex/vector_function.png&quot; alt=&quot;Two `vector`s' CPU time&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So how can it be fixed? Well, in the very beginning, I thought how hard could it be? But after all the deep digging into source
code, it could be &lt;em&gt;very hard&lt;/em&gt; and might require a complete refactoring.&lt;/p&gt;

&lt;h3 id=&quot;speed-under-release-configuration&quot;&gt;Speed under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Release&lt;/code&gt; configuration&lt;/h3&gt;

&lt;p&gt;I decided to give MSVC one more chance, by compiling the code under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Release&lt;/code&gt; configuration, or more precisely,
with compiling options &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/O2&lt;/code&gt; (maximum optimizations, favor speed) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Ob2&lt;/code&gt; (inline expansion level 2).&lt;/p&gt;

&lt;p&gt;I wrote a small snippet to measure how long my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readTSV&lt;/code&gt; function takes:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chrono&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;steady_clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readTSV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;R&quot;(../UCRArchive_2018/Mallat/Mallat_TEST.tsv)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chrono&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;steady_clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Mallat_TEST[0], label: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;front&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;, data[0, last]: &quot;&lt;/span&gt; 
          &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;front&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;front&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;, &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;front&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Mallat_TEST[last], label: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;, data[0, last]: &quot;&lt;/span&gt; 
          &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;front&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;, &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Elapsed: &quot;&lt;/span&gt; 
          &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chrono&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;duration_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chrono&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;milliseconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; 
          &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; ms&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The reason I added two more lines output is to avoid compiler’s optimization over potential dead code (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang&lt;/code&gt; does very
well in this kind of elimination), which may remove the invocation to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readTSV&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now I can compile this little program:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# /nologo: Suppress copyright message&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# /TP: Treat all files as C++&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# /W3: Warning level 3&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# /GR: Enable C++ RTTI&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# /EHsc: Enable C++ EH&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# /MD: Link with MSVCRT.LIB&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# /O2: Maximum optimizations (favor speed)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# /Ob2: Inline expansion level 2&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# /NDEBUG: Define NDEBUG marco&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# /std:c++17: C++ 17 stardard&lt;/span&gt;
cl /nologo /TP /W3 /GR /EHsc /MD /O2 /Ob2 /DNDEBUG /std:c++17 RegexTokenIterator_C++17.cpp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Yet it still took 31.4 seconds to load &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mallat_TEST.tsv&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# MSVC v14.28.29333 (/O2 /Ob2) with \t+&lt;/span&gt;
Mallat_TEST[0], label: 5, data[0, last]: -1.06862, -1.01192
Mallat_TEST[last], label: 8, data[0, last]: -0.949403, -0.970955
&lt;strong class=&quot;mi&quot;&gt;Elapsed: 31461 ms&lt;/strong&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;how-about-plain-t&quot;&gt;How about plain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\t&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;I also tried the simplest regex for this case: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\t&lt;/code&gt;. With the same compiler options, it still takes 4.6 seconds:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# MSVC v14.28.29333 (/O2 /Ob2) with \t&lt;/span&gt;
Mallat_TEST[0], label: 5, data[0, last]: -1.06862, -1.01192
Mallat_TEST[last], label: 8, data[0, last]: -0.949403, -0.970955
&lt;strong class=&quot;mi&quot;&gt;Elapsed: 4641 ms&lt;/strong&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which is way less desirable and 5x slower than expected.&lt;/p&gt;

&lt;h2 id=&quot;what-about-clang-and-gcc&quot;&gt;What about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt;?&lt;/h2&gt;

&lt;h3 id=&quot;clang-1101--libc-110&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang&lt;/code&gt; 11.0.1 + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc++&lt;/code&gt; 11.0&lt;/h3&gt;

&lt;p&gt;When I first tried to compile with:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;clang++ &lt;span class=&quot;nt&quot;&gt;-O3&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;c++17 &lt;span class=&quot;nt&quot;&gt;-stdlib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;libc++ RegexTokenIterator_C++17.cpp &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; clangRTI
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang&lt;/code&gt; spits out an error:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;RegexTokenIterator_C++17.cpp:34:4: error: call to deleted &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'from_chars'&lt;/span&gt;
                        std::from_chars&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;subMatch.first, subMatch.second, value&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                        ^~~~~~~~~~~~~~~
/usr/local/clang-11.0.1/bin/../include/c++/v1/algorithm:1948:21: note: &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;instantiation of &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;template specialization &lt;span class=&quot;s1&quot;&gt;'readTSV(const std::string &amp;amp;)::(anonymous class)::operator()&amp;lt;std::__1::sub_match&amp;lt;const char *&amp;gt;&amp;gt;'&lt;/span&gt; requested here
        &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;__result &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; __op&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;__first&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                    ^
RegexTokenIterator_C++17.cpp:32:8: note: &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;instantiation of &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;template specialization &lt;span class=&quot;s1&quot;&gt;'std::__1::transform&amp;lt;std::__1::regex_token_iterator&amp;lt;const char *, char, std::__1::regex_traits&amp;lt;char&amp;gt;&amp;gt;, std::__1::back_insert_iterator&amp;lt;std::__1::vector&amp;lt;double, std::__1::allocator&amp;lt;double&amp;gt;&amp;gt;&amp;gt;, (lambda at RegexTokenIterator_C++17.cpp:32:65)&amp;gt;'&lt;/span&gt; requested here
                std::transform&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;++first, last, std::back_inserter&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;datapoints&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, &lt;span class=&quot;o&quot;&gt;[](&lt;/span&gt;auto subMatch&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                     ^
/usr/local/clang-11.0.1/bin/../include/c++/v1/charconv:123:6: note: candidate &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;has been explicitly deleted
void from_chars&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;const char&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;, const char&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;, bool, int &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 10&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; delete&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
     ^
/usr/local/clang-11.0.1/bin/../include/c++/v1/charconv:606:1: note: candidate template ignored: requirement &lt;span class=&quot;s1&quot;&gt;'is_integral&amp;lt;double&amp;gt;::value'&lt;/span&gt; was not satisfied &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;with _Tp &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; double]
from_chars&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;const char&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; __first, const char&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; __last, _Tp&amp;amp; __value&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
^
/usr/local/clang-11.0.1/bin/../include/c++/v1/charconv:613:1: note: candidate &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;template not viable: requires 4 arguments, but 3 were provided
from_chars&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;const char&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; __first, const char&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; __last, _Tp&amp;amp; __value, int __base&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
^
1 error generated.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I was confused and “What?” is my first reaction. So I digged into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc++&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;charconv&amp;gt;&lt;/code&gt; and the only 3 definitions 
of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::from_chars&lt;/code&gt; I found are:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from_chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_Tp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;enable_if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_integral&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Tp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_LIBCPP_INLINE_VISIBILITY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from_chars_result&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;from_chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Tp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__from_chars_atoi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_Tp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;enable_if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_integral&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Tp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_LIBCPP_INLINE_VISIBILITY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from_chars_result&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;from_chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Tp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_LIBCPP_ASSERT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;base not in [2, 36]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__from_chars_integral&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Meh&lt;/em&gt;. This means at the time of writing, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc++&lt;/code&gt; doesn’t support floating point numbers in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::from_chars&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So I had to replace the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::from_chars&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::transform&lt;/code&gt; lambda with the old school &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strtod&lt;/code&gt;, and it worked.&lt;/p&gt;

&lt;p&gt;The result is much better than MSVC’s, but still slow:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# clang 11.0.1 (-O3) + libc++ 11.0 with \t+&lt;/span&gt;
Mallat_TEST[0], label: 5, data[0, last]: -1.06862, -1.01192
Mallat_TEST[last], label: 8, data[0, last]: -0.949403, -0.970955
&lt;strong class=&quot;mi&quot;&gt;Elapsed: 3017 ms&lt;/strong&gt;

&lt;span class=&quot;c&quot;&gt;# clang 11.0.1 (-O3) + libc++ 11.0 with \t&lt;/span&gt;
Mallat_TEST[0], label: 5, data[0, last]: -1.06862, -1.01192
Mallat_TEST[last], label: 8, data[0, last]: -0.949403, -0.970955
&lt;strong class=&quot;mi&quot;&gt;Elapsed: 1848 ms&lt;/strong&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;gcc-550--libstdc-3421&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; 5.5.0 + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libstdc++&lt;/code&gt; 3.4.21&lt;/h3&gt;

&lt;p&gt;I could have use the latest &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; 10.2, but I am just too lazy to compile it.&lt;/p&gt;

&lt;p&gt;Fortunately &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; 5.5.0 + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libstdc++&lt;/code&gt; 3.4.21 has already fully supported C++ 14 features, so at least I can continue 
my experiments by simply replacing the last C++ 17 existence of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::from_chars&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;atoi&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The complier options are:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;g++ &lt;span class=&quot;nt&quot;&gt;-O3&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;c++14 RegexTokenIterator_C++14.cpp &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; g++RTI
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’m a little bit amazed by the result:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# gcc 5.5.0 (-O3) + libstdc++ 3.4.21 with \t+&lt;/span&gt;
Mallat_TEST[0], label: 5, data[0, last]: -1.06862, -1.01192
Mallat_TEST[last], label: 8, data[0, last]: -0.949403, -0.970955
&lt;strong class=&quot;mi&quot;&gt;Elapsed: 992 ms&lt;/strong&gt;

&lt;span class=&quot;c&quot;&gt;# gcc 5.5.0 (-O3) + libstdc++ 3.4.21 with \t&lt;/span&gt;
Mallat_TEST[0], label: 5, data[0, last]: -1.06862, -1.01192
Mallat_TEST[last], label: 8, data[0, last]: -0.949403, -0.970955
&lt;strong class=&quot;mi&quot;&gt;Elapsed: 952 ms&lt;/strong&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because both MSVC and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc++&lt;/code&gt; are in their latest stable version. For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libstdc++&lt;/code&gt;, I was using an old 
version built on Oct. 2017, which I’d say it’s kind of unfair, but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libstdc++&lt;/code&gt; managed to win the game.&lt;/p&gt;

&lt;h2 id=&quot;tedious-stringfind-did-the-trick&quot;&gt;Tedious &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string::find&lt;/code&gt; did the trick&lt;/h2&gt;

&lt;p&gt;Nevertheless, I went back to the tedious way of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string::find&lt;/code&gt; (let us also forget about whatever &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::from_chars&lt;/code&gt; is):&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeSeriesDataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;TimeSeriesDataset&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;readTSV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tsvPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;TimeSeriesDataset&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ifstream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tsvPath&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tabPos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'\t'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;atoi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
      
      &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datapoints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nextTabPos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
           &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;npos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nextTabPos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'\t'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tabPos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; 
           &lt;span class=&quot;n&quot;&gt;tabPos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nextTabPos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;datapoints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strtod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tabPos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;datapoints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strtod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tabPos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datapoints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’m not surprised to see this piece of code is way more faster than its regular expression equivalent under all three libraries:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# MSVC v14.28.29333 (/O2 /Ob2)&lt;/span&gt;
Mallat_TEST[0], label: 5, data[0, last]: -1.06862, -1.01192
Mallat_TEST[last], label: 8, data[0, last]: -0.949403, -0.970955
&lt;strong class=&quot;mi&quot;&gt;Elapsed: 892 ms&lt;/strong&gt;

&lt;span class=&quot;c&quot;&gt;# clang 11.0.1 (-O3) + libc++ 11.0&lt;/span&gt;
Mallat_TEST[0], label: 5, data[0, last]: -1.06862, -1.01192
Mallat_TEST[last], label: 8, data[0, last]: -0.949403, -0.970955
&lt;strong class=&quot;mi&quot;&gt;Elapsed: 431 ms&lt;/strong&gt;

&lt;span class=&quot;c&quot;&gt;# gcc 5.5.0 (-O3) + libstdc++ 3.4.21&lt;/span&gt;
Mallat_TEST[0], label: 5, data[0, last]: -1.06862, -1.01192
Mallat_TEST[last], label: 8, data[0, last]: -0.949403, -0.970955
&lt;strong class=&quot;mi&quot;&gt;Elapsed: 294 ms&lt;/strong&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;final-speed-comparison&quot;&gt;Final speed comparison&lt;/h2&gt;

&lt;p&gt;With all the experiment data collected, we can finally compare the performance:&lt;/p&gt;

&lt;table class=&quot;table-align-center&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Compiler (Options)&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Time (ms)&lt;br /&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rti&lt;/code&gt;^ with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\t+&lt;/code&gt;)&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Time (ms)&lt;br /&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rti&lt;/code&gt;^ with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\t&lt;/code&gt;)&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Time (ms)&lt;br /&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string::find&lt;/code&gt;)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;MSVC v14.28.29333 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/O2 /Ob2&lt;/code&gt;)&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;31461&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;4641&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;892&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;clang 11.0.1 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-O3&lt;/code&gt;)&lt;br /&gt;&lt;small&gt;libc++ 11.0&lt;/small&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3017&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1848&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;431&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;gcc 5.5.0 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-O3&lt;/code&gt;)&lt;br /&gt;&lt;small&gt;libstdc++ 3.4.21&lt;/small&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;992&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;952&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;294&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p class=&quot;small&quot;&gt;^ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rti&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::regex_token_iterator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The result shows that at least for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;regex&amp;gt;&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libstdc++&lt;/code&gt;’s implementation is so far the best among all three libraries.
But it still can’t beat the plain and tedious &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string::find&lt;/code&gt;, in terms of string splitting.&lt;/p&gt;

&lt;p&gt;I tried to figure out why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;regex&amp;gt;&lt;/code&gt; has been introduced for a decade and yet still so slow and badly implemented. 
&lt;a href=&quot;https://www.reddit.com/r/cpp/comments/aetf17/stdregex_replacestdchronohigh_resolution_clocknow/&quot;&gt;A thread on Reddit&lt;/a&gt; points out something about ABI compatibility:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The fast engines add a zillion special cases for common patterns their engines recognize. But we can’t ever do that. And given that our engines were somewhat stupid initially now we can’t replace the engine with something better because that breaks ABI.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p class=&quot;small&quot;&gt;BillyONeal — &lt;cite&gt;&lt;a href=&quot;https://www.reddit.com/r/cpp/comments/aetf17/stdregex_replacestdchronohigh_resolution_clocknow/edticke/&quot;&gt;std::regex_replace/std::chrono::high_resolution_clock::now() speed&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;Well, good luck to all of us C++ users.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;It’s great to see the C++ standard getting periodical updates every 3 years since 2011: new STL components, syntax sugars, 
and a lot of other stuffs (&lt;a href=&quot;https://en.cppreference.com/w/cpp/language/range-for&quot;&gt;range-based &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; loops&lt;/a&gt;, 
&lt;a href=&quot;https://en.cppreference.com/w/cpp/language/auto&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auto&lt;/code&gt; type deduction&lt;/a&gt;, &lt;a href=&quot;https://en.cppreference.com/w/cpp/language/parameter_pack&quot;&gt;variadic template (or parameter pack)&lt;/a&gt;, and &lt;a href=&quot;https://en.cppreference.com/w/cpp/language/constraints&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concepts&lt;/code&gt;&lt;/a&gt; finally, etc.) — all of which 
I (and probably many other people) have been waiting for years.&lt;/p&gt;

&lt;p&gt;However, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;regex&amp;gt;&lt;/code&gt; library is unfortunately an exception: apparently there is something wrong with MSVC’s underlying 
implementations, and the performance is surprisingly bad. Also not to mention &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;regex&amp;gt;&lt;/code&gt; library was introduced in C++ 11
since 2011 — a decade ago.&lt;/p&gt;

&lt;p&gt;The lesson I learnt is that for simple tasks like splitting strings, it might be better just to stick with simple tools (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string::find&lt;/code&gt; in
this case, even though I have to reinvent the wheels every single time), instead of using something “fancy” like 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::regex_token_iterator&lt;/code&gt;, at least for now.&lt;/p&gt;

&lt;p&gt;Actually this is &lt;strong&gt;NOT&lt;/strong&gt; the first time that I found issues in the particular STL implementation: several years ago, I noticed 
that the order of items from &lt;a href=&quot;https://en.cppreference.com/w/cpp/algorithm/make_heap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::make_heap&lt;/code&gt;&lt;/a&gt; is slightly different 
between MSVC’s and GCC’s (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libstdc++&lt;/code&gt;). My later digging into source code revealed it was caused by the default comparison 
function: one used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&lt;/code&gt; and the other used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;=&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another issue is that specific feature mights not be fully implemented. Besides aforementioned &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc++&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::from_chars&lt;/code&gt; 
lacking support on floating point numbers, when I was trying to compile the &lt;a href=&quot;https://github.com/microsoft/cppwin32&quot;&gt;cppwin32&lt;/a&gt; 
project with Visual Studio 2017 (MSVC v14.16.27023), I found that MSVC’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::to_chars&lt;/code&gt; has no support on floating-point 
in terms of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::chars_format::hex&lt;/code&gt;&lt;sup id=&quot;fnref:charconv&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:charconv&quot; class=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;. This made me upgrade to Visual Studio 2019.&lt;/p&gt;

&lt;p&gt;All these chaos remind me the famous Russian proverb my advisor &lt;a href=&quot;https://www.cs.ucr.edu/~eamonn/&quot;&gt;Dr. Keogh&lt;/a&gt; ever cited: 
“Доверя́й, но проверя́й” or “Trust, but verify”. Even standards like STL are not exceptions.&lt;/p&gt;

&lt;p&gt;My experiences in C++ in the past decade has taught me one thing:&lt;/p&gt;

&lt;ul style=&quot;list-style: none;&quot;&gt;
  &lt;li&gt;&lt;em&gt;C++ is very hard, and to make it correct is even harder.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:fastdtw-is-slow&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;R. Wu and E.J. Keogh, “&lt;a href=&quot;/research/fastdtw-is-slow/&quot;&gt;FastDTW is approximate and Generally Slower than the Algorithm it Approximates&lt;/a&gt;,” &lt;em&gt;IEEE Transactions on Knowledge and Data Engineering (TKDE)&lt;/em&gt;, in press, 2020. &lt;a href=&quot;#fnref:fastdtw-is-slow&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:ETSC-is-meaningless&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;R. Wu, A. Der, and E.J. Keogh, “&lt;a href=&quot;/research/ETSC-is-meaningless/&quot;&gt;When is Early Classification of Time Series Meaningful?&lt;/a&gt;,” &lt;em&gt;arXiv&lt;/em&gt;, preprint, 2021. &lt;a href=&quot;#fnref:ETSC-is-meaningless&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:fastdtw&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;S. Salvador and P. Chan, “&lt;a href=&quot;https://cs.fit.edu/~pkc/papers/tdm04.pdf&quot;&gt;FastDTW: Toward Accurate Dynamic Time Warping in Linear Time and Space&lt;/a&gt;,” &lt;em&gt;Intelligent Data Analysis&lt;/em&gt;, vol. 11, no. 5, 2007, pp. 561-580. &lt;a href=&quot;#fnref:fastdtw&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:teaser&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;P. Schäfer and U. Leser, “&lt;a href=&quot;https://doi.org/10.1007/s10618-020-00690-z&quot;&gt;TEASER: Early and Accurate Time Series Classification&lt;/a&gt;,” &lt;em&gt;Data Mining and Knowledge Discovery&lt;/em&gt;, vol. 34, no. 5, pp. 1336-1362, 2020. &lt;a href=&quot;#fnref:teaser&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:charconv&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Microsoft, &lt;em&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=msvc-160#note_charconv&quot;&gt;Microsoft C++ language conformance table: charconv&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:charconv&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</content><author><name>Renjie Wu</name></author><category term="Programming" /><summary type="html">It's great to see the C++ standard getting periodical updates every 3 years since 2011: new STL components, syntax sugars, and a lot of other stuffs, which I (and probably many other people) have been waiting for years. However, `regex` library is unfortunately an exception: apparently there is something wrong with MSVC's underlying implementations, and the performance is surprisingly bad.</summary></entry><entry xml:lang="zh-cn"><title type="html">在 AX88U + Merlin 384.19 上配置基于 `RTL8156B` 的 2.5GbE 网卡</title><link href="https://wu.renjie.im/blog/network/ax88u-nbase-t/zh-cn/" rel="alternate" type="text/html" title="在 AX88U + Merlin 384.19 上配置基于 `RTL8156B` 的 2.5GbE 网卡" /><published>2021-01-09T22:32:34-08:00</published><updated>2021-01-24T13:49:14-08:00</updated><id>https://wu.renjie.im/blog/network/ax88u-nbase-t/ax88u-nbase-t</id><content type="html" xml:base="https://wu.renjie.im/blog/network/ax88u-nbase-t/zh-cn/">&lt;p&gt;主路由升级到 &lt;a href=&quot;https://www.asus.com/us/Networking/RT-AX88U/&quot;&gt;AX88U&lt;/a&gt; 已经有接近一年的时间，整体来说这台路由器非常不错：性能强悍、功能齐全。不过缺少板载的 2.5GbE 网卡属实为一大遗憾，尤其是考虑到其 CPU &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BCM49408&lt;/code&gt; 内建了对 2.5GbE 的支持&lt;sup id=&quot;fnref:bcm49408&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:bcm49408&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;（华硕后来的 2.5GbE 产品 &lt;a href=&quot;https://www.asus.com/us/Networking/RT-AX86U/&quot;&gt;AX86U&lt;/a&gt; 就是基于这款 CPU 的）。&lt;/p&gt;

&lt;p&gt;不过好消息是螃蟹家（Realtek）提供了一个经济的解决方案 —— &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt;&lt;sup id=&quot;fnref:rtl8156&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:rtl8156&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;，基于 USB 3.0 的 2.5GbE 控制器。相比于贵的多的 5GbE 和 10GbE 的设备，它可以说是“相当廉价”了：30 美金左右就能买到基于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt; 的 USB 网卡。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;但是&lt;/strong&gt;有一点需要特别注意，这个芯片有两个版本：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;。我推荐购买后者这个 &lt;strong&gt;B&lt;/strong&gt; 修订版的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;，因为前者 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt; 在用上一段时间后会有些奇怪的稳定性问题&lt;sup id=&quot;fnref:rtl8156-issue&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:rtl8156-issue&quot; class=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;

&lt;p&gt;此外如果买的是 USB-C 的网卡，我建议买一个“双面” USB-C 转 USB-A 的转接器（里面应该有个多路复用芯片，比如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VL160&lt;/code&gt;&lt;sup id=&quot;fnref:vl160&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:vl160&quot; class=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; 之类的）。不然使用非“双面”的转接器，必须搞清楚把 USB-C 头的哪一面插入到转接器里，因为只有一面能跑 USB 3.0，另一面只能跑 USB 2.0。&lt;/p&gt;

&lt;h2 id=&quot;不能即插即用&quot;&gt;不能即插即用？&lt;/h2&gt;

&lt;p&gt;一切正常的话，AX88U 应该是能识别插入的 USB 网卡（在路由器管理界面的&lt;strong&gt;网络地图&lt;/strong&gt;里会显示）。另外运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifconfig -a&lt;/code&gt;，也能发现网卡已经被注册为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usb0&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;然而一旦尝试启用网卡（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifconfig usb0 up&lt;/code&gt;），就会发现日志会被 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ncm&lt;/code&gt; 这个模块刷屏：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cdc_ncm 2-2:1.0 usb0: network connection: connected
cdc_ncm 2-2:1.0 usb0: 2500 mbit/s downlink 2500 mbit/s uplink
cdc_ncm 2-2:1.0 usb0: network connection: connected
cdc_ncm 2-2:1.0 usb0: 2500 mbit/s downlink 2500 mbit/s uplink
cdc_ncm 2-2:1.0 usb0: network connection: connected
cdc_ncm 2-2:1.0 usb0: 2500 mbit/s downlink 2500 mbit/s uplink
cdc_ncm 2-2:1.0 usb0: network connection: connected
cdc_ncm 2-2:1.0 usb0: 2500 mbit/s downlink 2500 mbit/s uplink
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;造成这个问题的原因是 Linux 内核自带的驱动程序暂时还不支持 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt; &lt;sup id=&quot;fnref:upstream-no-rtl8156&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:upstream-no-rtl8156&quot; class=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;，所以必须得自己编译驱动。&lt;/p&gt;

&lt;h2 id=&quot;准备工作&quot;&gt;准备工作&lt;/h2&gt;

&lt;h3 id=&quot;编译-linux-内核&quot;&gt;编译 Linux 内核&lt;/h3&gt;

&lt;p&gt;有关如何配置梅林固件编译环境，请参阅这篇教程：&lt;a href=&quot;https://github.com/RMerl/asuswrt-merlin.ng/wiki/Compiling-under-WSL2&quot;&gt;Compiling under WSL2&lt;/a&gt;（英文）。虽然标题写的是在 WSL (Windows Subsystem for Linux) 2 里编译，但是总体步骤也适用于 WSL 1（也称 legacy WSL）和真·Linux 环境。&lt;/p&gt;

&lt;p&gt;如果你跟我一样用的是 WSL 1，还需要额外配置 32 位运行环境（参考这个 &lt;a href=&quot;https://github.com/Microsoft/WSL/issues/2468#issuecomment-374904520&quot;&gt;issue&lt;/a&gt;），因为梅林固件提供的工具链都是 32 位的。&lt;/p&gt;

&lt;p&gt;首先把梅林固件的源代码拖下来，因为用不到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; 的历史，只需要把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; 拖下来即可：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 只拖 HEAD&lt;/span&gt;
git clone &lt;span class=&quot;nt&quot;&gt;--depth&lt;/span&gt; 1 https://github.com/RMerl/asuswrt-merlin.ng
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;教程里是把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brcm-arm-sdk&lt;/code&gt; 文件夹链接到了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src-rt-6.x-4708&lt;/code&gt; 里面：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# `src-rt-6.x.4708` 用于 AC56U, AC68U 和 AC87U&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; ~/am-toolchains/brcm-arm-sdk ~/asuswrt-merlin.ng/release/src-rt-6.x.4708/toolchains
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;而我们需要把它链接到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src-rt-5.02axhnd&lt;/code&gt; 里面，梅林固件的编译脚本&lt;sup id=&quot;fnref:merlin-build&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:merlin-build&quot; class=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;里有提到 AX88U 用的是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src-rt-5.02axhnd&lt;/code&gt;：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# `src-rt-5.02axhnd` 用于 AX88U, AX58U 和 AX56U&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; ~/am-toolchains/brcm-arm-sdk ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/toolchains
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;接着就可以编译 AX88U 的梅林固件了：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 目标平台 AX88U&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;release/src-rt-5.02axhnd &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make rt-ax88u
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;由于我们只需要用到内核编译生成的头文件（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.h&lt;/code&gt;），因此没必要把固件整个都编译出来，待内核编译流程开始之后，就可以按键盘上的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CTRL+C&lt;/code&gt; 终止固件编译。&lt;/p&gt;

&lt;h3 id=&quot;编译测试工具&quot;&gt;编译测试工具&lt;/h3&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;iperf3&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; 源代码从这里下载：&lt;a href=&quot;https://github.com/esnet/iperf&quot;&gt;esnet/iperf&lt;/a&gt;，本文使用的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; 版本是 3.9。&lt;/p&gt;

&lt;p&gt;运行下面的命令来为 AX88U 编译 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt;：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 创建 build 文件夹，作为 iperf3 安装目录&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;build
&lt;span class=&quot;c&quot;&gt;# 静态链接&lt;/span&gt;
./configure &lt;span class=&quot;nt&quot;&gt;--host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;arm-linux &lt;span class=&quot;nt&quot;&gt;--prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/build &lt;span class=&quot;nt&quot;&gt;--enable-static&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-shared&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 编译并安装到 build 文件夹&lt;/span&gt;
make &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;生成的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; 二进制文件应该可以在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./build/bin&lt;/code&gt; 文件夹下找到，预编译好的版本可以在这里下载：&lt;a href=&quot;#预编译的测试工具&quot;&gt;附录：预编译的二进制文件：预编译的测试工具&lt;/a&gt;。&lt;/p&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;ethtool&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; 源代码从这里下载：&lt;a href=&quot;https://kernel.org/pub/software/network/ethtool/&quot;&gt;kernel/software/network/ethtool&lt;/a&gt;，本文使用的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; 版本是 5.8。&lt;/p&gt;

&lt;p&gt;运行下面的代码来为 AX88U 编译 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt;：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 创建 build 文件夹，作为 ethtool 安装目录&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;build
&lt;span class=&quot;c&quot;&gt;# 禁用 netlink，一是用不到，二是去除对 libmnl 的依赖&lt;/span&gt;
./configure &lt;span class=&quot;nt&quot;&gt;--host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;arm-linux &lt;span class=&quot;nt&quot;&gt;--prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/build &lt;span class=&quot;nt&quot;&gt;--disable-netlink&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 编译并安装到 build 文件夹&lt;/span&gt;
make &amp;amp; make &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;生成的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; 二进制文件应该可以在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./build/bin&lt;/code&gt; 文件夹下找到，预编译好的版本可以在这里下载：&lt;a href=&quot;#预编译的测试工具&quot;&gt;附录 1：预编译的二进制文件：预编译的测试工具&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&quot;编译-r8152-驱动模块&quot;&gt;编译 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt; 驱动模块&lt;/h3&gt;

&lt;p&gt;你没看错，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 的驱动模块确实叫 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt;，源码从这里下载：&lt;a href=&quot;https://www.realtek.com/en/component/zoo/category/network-interface-controllers-10-100-1000m-gigabit-ethernet-usb-3-0-software&quot;&gt;Realtek USB FE / GBE / 2.5G / Gaming Ethernet Family Controller Software&lt;/a&gt;，本文使用的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt; 驱动模块版本是 v2.13.0。&lt;/p&gt;

&lt;p&gt;为了验证买来的网卡是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 芯片的，可以在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtl8152_get_drvinfo&lt;/code&gt; 函数里加上下面一句代码，这样就可以通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; 来获取芯片的版本：&lt;/p&gt;

&lt;div class=&quot;language-patch highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gd&quot;&gt;--- source-2.13.0/r8152-original.c     2020-04-20 01:36:49.000000000 -0700
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+++ source-2.13.0/r8152-modified.c     2020-10-06 23:47:07.123659400 -0700
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@@ -16369,6 +16369,7 @@&lt;/span&gt;
        strlcpy(info-&amp;gt;driver, MODULENAME, sizeof(info-&amp;gt;driver));
        strlcpy(info-&amp;gt;version, DRIVER_VERSION, sizeof(info-&amp;gt;version));
        usb_make_path(tp-&amp;gt;udev, info-&amp;gt;bus_info, sizeof(info-&amp;gt;bus_info));
&lt;span class=&quot;gi&quot;&gt;+       snprintf(info-&amp;gt;fw_version, sizeof(info-&amp;gt;fw_version), &quot;0x%04x&quot;, tp-&amp;gt;version);
&lt;/span&gt; } 

 #if LINUX_VERSION_CODE &amp;lt; KERNEL_VERSION(4,20,0)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;运行下面的命令来编译驱动：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 架构: arm64&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 交叉编译器: aarch64-linux&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 内核源代码目录: ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1&lt;/span&gt;
make &lt;span class=&quot;nv&quot;&gt;ARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;arm64 &lt;span class=&quot;nv&quot;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;aarch64-linux- &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1 &lt;span class=&quot;nv&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; modules
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果你倾向用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; 的话，可以在这里找到：&lt;a href=&quot;#makefile&quot;&gt;附录 2：脚本：Makefile&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;一切顺利的情况下，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152.ko&lt;/code&gt; 这个文件会生成在当前目录下，预编译好的版本可以在这里下载：&lt;a href=&quot;#预编译的驱动模块&quot;&gt;附录：预编译的二进制文件：预编译的驱动模块&lt;/a&gt;。&lt;/p&gt;

&lt;h2 id=&quot;配置驱动&quot;&gt;配置驱动&lt;/h2&gt;

&lt;p&gt;首先在路由器 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs&lt;/code&gt; 文件夹内创建 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drivers&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools&lt;/code&gt; 两个文件夹，然后把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152.ko&lt;/code&gt; 上传到路由器 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/drivers&lt;/code&gt; 文件夹内，把编译好的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; 上传到路由器 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/tools&lt;/code&gt; 文件夹内。&lt;/p&gt;

&lt;h3 id=&quot;加载驱动&quot;&gt;加载驱动&lt;/h3&gt;

&lt;p&gt;前文“&lt;a href=&quot;#不能即插即用&quot;&gt;不能即插即用？&lt;/a&gt;”一节已经提到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ncm&lt;/code&gt; 会接管 USB 网卡，所以首先需要把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ncm&lt;/code&gt; 卸载掉。&lt;/p&gt;

&lt;p&gt;运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lsmod | grep cdc_ncm&lt;/code&gt; 可以看到依赖 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ncm&lt;/code&gt; 的模块：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# admin@ax88u:/# lsmod | grep cdc_ncm&lt;/span&gt;
&lt;strong class=&quot;mi&quot;&gt;cdc_ncm&lt;/strong&gt;                16787  1 &lt;strong class=&quot;mi&quot;&gt;cdc_mbim&lt;/strong&gt;
usbnet                 21074  7 cdc_mbim,qmi_wwan,cdc_ncm,rndis_host,cdc_ether,ax88179_178a,asix
usbcore               166572 23 uas,usb_storage,cdc_mbim,qmi_wwan,cdc_wdm,cdc_ncm,rndis_host,cdc_ether,ax88179_178a,asix,cdc_acm,usbnet,usblp,ohci_pci,ohci_platform,ohci_hcd,ehci_pci,ehci_platform,ehci_hcd,xhci_pci,xhci_plat_hcd,xhci_hcd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;所以得把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_mbim&lt;/code&gt; 也一同卸载掉：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 先卸载 cdc_mbim，因为它依赖于 cdc_ncm&lt;/span&gt;
rmmod cdc_mbim
&lt;span class=&quot;c&quot;&gt;# 卸载 cdc_ncm&lt;/span&gt;
rmmod cdc_ncm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;现在就可以加载 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152.ko&lt;/code&gt; 了，同时记得把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ncm&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_mbim&lt;/code&gt; 也加载回来：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 加载 r8152 驱动模块&lt;/span&gt;
insmod /jffs/drivers/r8152.ko
&lt;span class=&quot;c&quot;&gt;# 加载 cdc_ncm&lt;/span&gt;
insmod cdc_ncm
&lt;span class=&quot;c&quot;&gt;# 加载 cdc_mbim&lt;/span&gt;
insmod cdc_mbim
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果一切正常的话，系统日志（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tail /tmp/syslog.log&lt;/code&gt;）会显示驱动加载成功：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# admin@ax88u:/# tail /tmp/syslog.log&lt;/span&gt;
Oct  7 21:27:42 kernel: usbcore: deregistering interface driver cdc_mbim
Oct  7 21:27:42 kernel: usbcore: registered new interface driver r8152
Oct  7 21:27:42 kernel: usb 2-2: reset SuperSpeed USB device number 2 using xhci-hcd
Oct  7 21:27:42 kernel: netif_napi_add() called with weight 256 on device eth%d
Oct  7 21:27:42 kernel: r8152 2-2:1.0 eth8: v2.13.0 (2020/04/20)
Oct  7 21:27:42 kernel: r8152 2-2:1.0 eth8: This product is covered by one or more of the following patents:
Oct  7 21:27:42 kernel: 		US6,570,884, US6,115,776, and US6,327,625.
Oct  7 21:27:42 hotplug: &lt;strong class=&quot;mi&quot;&gt;add net eth8&lt;/strong&gt;.
Oct  7 21:27:42 kernel: usbcore: registered new interface driver cdc_ncm
Oct  7 21:27:42 kernel: usbcore: registered new interface driver cdc_mbim
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;从上面的日志里可以看到 USB 网卡被注册为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth8&lt;/code&gt;，运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifconfig eth8&lt;/code&gt; 可以验证这一点：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;eth8      Link encap:Ethernet  HWaddr 00:E0:4C:00:FA:KE
          inet6 addr: fe80::2e0:4cff:fe00:fake/64 Scope:Link
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在路由器管理界面的 &lt;em&gt;网络地图&lt;/em&gt; 里也可以看到 USB 网卡：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/ax88u-nbase-t/web_ui.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/ax88u-nbase-t/web_ui.png&quot; alt=&quot;网络地图中的 USB 网卡&quot; class=&quot;align-center&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;接下来就可以更新 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvram&lt;/code&gt; 变量，启用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth8&lt;/code&gt; 并把它加入网桥 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 里：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 更新 nvram 变量&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;br0_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get br0_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lan_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get lan_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;wired_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get wired_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 把 eth8 加入网桥 br0，然后启用 eth8&lt;/span&gt;
brctl addif br0 eth8
ifconfig eth8 allmulti up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;最后插入网线，运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/tools/ethtool eth8&lt;/code&gt; 来验证协商的速度为全双工 2500Mb/s：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# admin@ax88u:/# /jffs/tools/ethtool eth8&lt;/span&gt;
Settings for eth8:
        Supported ports: [ MII ]
        Supported link modes:   10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
                                2500baseX/Full
        Supported pause frame use: No
        Supports auto-negotiation: Yes
        Supported FEC modes: Not reported
        Advertised link modes:  10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
                                2500baseX/Full
        Advertised pause frame use: Symmetric Receive-only
        Advertised auto-negotiation: Yes
        Advertised FEC modes: Not reported
        Link partner advertised link modes:  10baseT/Half 10baseT/Full
                                             100baseT/Half 100baseT/Full
                                             1000baseT/Full
        Link partner advertised pause frame use: No
        Link partner advertised auto-negotiation: Yes
        Link partner advertised FEC modes: Not reported
        &lt;strong class=&quot;mi&quot;&gt;Speed: 2500Mb/s&lt;/strong&gt;
        &lt;strong class=&quot;mi&quot;&gt;Duplex: Full&lt;/strong&gt;
        Port: MII
        PHYAD: 32
        Transceiver: internal
        Auto-negotiation: on
        Supports Wake-on: pumbg
        Wake-on: g
        Current message level: 0x00007fff (32767)
                               drv probe link timer ifdown ifup rx_err tx_err tx_queued intr tx_done rx_status pktdata hw wol
        &lt;strong class=&quot;mi&quot;&gt;Link detected: yes&lt;/strong&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;提示：&lt;/strong&gt;完整的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 配置脚本可以在这里找到：&lt;a href=&quot;#rtl8156b-配置脚本&quot;&gt;附录：脚本：RTL8156B 配置脚本&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&quot;验证-rtl-芯片版本&quot;&gt;验证 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL&lt;/code&gt; 芯片版本&lt;/h3&gt;

&lt;p&gt;运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/tools/ethtool --driver eth8&lt;/code&gt;：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# admin@ax88u:/# /jffs/tools/ethtool --driver eth8&lt;/span&gt;
driver: r8152
version: v2.13.0 (2020/04/20)
&lt;strong class=&quot;mi&quot;&gt;firmware-version: 0x000e&lt;/strong&gt;
expansion-rom-version:
bus-info: usb-xhci-hcd.0-2
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: no
supports-priv-flags: no
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;如果 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firmware-version&lt;/code&gt; 为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x000b&lt;/code&gt; 或 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x000c&lt;/code&gt;，则芯片为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt;。&lt;/li&gt;
  &lt;li&gt;如果 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firmware-version&lt;/code&gt; 为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x000d&lt;/code&gt; 或 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x000e&lt;/code&gt;，则芯片为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这里给出的输出结果中的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firmware-version&lt;/code&gt; 为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x000e&lt;/code&gt;，因此证明我的网卡芯片为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;。&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;注意：&lt;/strong&gt;为了显示 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firmware-version&lt;/code&gt;, 必须在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtl8152_get_drvinfo&lt;/code&gt; 函数中添加一句代码，详情请参阅&lt;a href=&quot;#编译-r8152-驱动模块&quot;&gt;准备工作：编译 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt; 驱动模块&lt;/a&gt;。&lt;/p&gt;

&lt;h2 id=&quot;性能优化&quot;&gt;性能优化&lt;/h2&gt;

&lt;p&gt;完整的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 配置脚本可以在这里找到：&lt;a href=&quot;#rtl8156b-配置脚本&quot;&gt;附录：脚本：RTL8156B 配置脚本&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&quot;接收rx&quot;&gt;接收（RX）&lt;/h3&gt;

&lt;p&gt;默认情况下，AX88U 上只有 4 号 CPU 核心为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xhci-hcd:usb1&lt;/code&gt; 响应硬件中断（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat /proc/irq/28/smp_affinity_list&lt;/code&gt;）。而且由于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 只有一个接收队列，也没法通过改变 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smp_affinity_list&lt;/code&gt; 的方式，把硬件中断请求分散到其他核心去处理。&lt;/p&gt;

&lt;p&gt;因此必须启用 RPS (Receive Packet Steering) 来分配软件中断（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;softirq&lt;/code&gt;）到各个核心，以达到优化接收性能的目的。有关 RPS 的更多信息，可以参考 Red Hat 的一篇文档：&lt;a href=&quot;https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/performance_tuning_guide/network-rps&quot;&gt;Performance Tuning Guide: 8.7 Receive Packet Steering&lt;/a&gt;（英文）。&lt;/p&gt;

&lt;p&gt;运行下面的命令在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth8&lt;/code&gt; 上启用 RPS：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 在 eth8 上启用 RPS (Receive Packet Steering)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 因为 AX88U 有四个核心，所以这里设置为 f&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;f &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /sys/class/net/eth8/queues/rx-0/rps_cpus
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;我之后进行的测试表明仅启用 RPS 已经足以在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; 跑到理论峰值速度，但是这里还是给出一些别的优化方法：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;增加 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net.core.netdev_max_backlog&lt;/code&gt;。默认值为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1000&lt;/code&gt;，可以增加到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2500&lt;/code&gt;：
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 1000 是 1GbE 的默认值，因此对 2.5GbE 来说 2500 看起来很合理&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;2500 &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /proc/sys/net/core/netdev_max_backlog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;增加 RX 中断合并窗口（从而减少产生的中断数量）。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rx-usecs&lt;/code&gt; 的默认值为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;15&lt;/code&gt;，运行以下命令以修改：
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# &amp;lt;N&amp;gt; 是数据包达到后产生 RX 中断的延迟时间，单位为毫秒。&lt;/span&gt;
/jffs/tool/ethtool &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; eth8 rx-usecs &amp;lt;N&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;增加 RX 缓冲区大小。默认值为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;100&lt;/code&gt;，可以增加到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4096&lt;/code&gt;（最大值）：
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 4096 是 RX 缓冲区大小的最大值&lt;/span&gt;
/jffs/tool/ethtool &lt;span class=&quot;nt&quot;&gt;-G&lt;/span&gt; eth8 rx 4096
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这三篇文章（英文）介绍了更多优化接收性能的方法：&lt;a href=&quot;https://cromwell-intl.com/open-source/performance-tuning/ethernet.html&quot;&gt;Performance Tuning on Linux — Ethernet&lt;/a&gt;、&lt;a href=&quot;https://blog.cloudflare.com/how-to-achieve-low-latency/&quot;&gt;How to achieve low latency with 10Gbps Ethernet&lt;/a&gt;、&lt;a href=&quot;https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/performance_tuning_guide/main-network&quot;&gt;Performance Tuning Guide: Chapter 8. Networking&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&quot;发送tx&quot;&gt;发送（TX）&lt;/h3&gt;

&lt;p&gt;不像 RPS，启用 XPS (Transmit Packet Steering) 对于提升 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 的发送性能没有帮助，这是因为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 只有一个发送队列，并且：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;For a network device with a &lt;strong&gt;single transmission queue&lt;/strong&gt;, XPS configuration has no effect, since there is no choice in this case.&lt;/p&gt;

  &lt;p&gt;对于&lt;strong&gt;只有一个发送队列&lt;/strong&gt;的网络设备，启用 XPS 不会起到任何效果，因为能用的发送队列就只有一个。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p class=&quot;small&quot;&gt;Linux 内核文档 — &lt;cite&gt;&lt;a href=&quot;https://www.kernel.org/doc/Documentation/networking/scaling.txt&quot;&gt;Scaling in the Linux Networking Stack&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;有关发送性能优化的方法并不多，其中一个是把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;txqueuelen&lt;/code&gt; 增加到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2500&lt;/code&gt;：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 1000 是 1GbE 的默认值，因此对 2.5GbE 来说 2500 看起来很合理&lt;/span&gt;
ifconfig eth8 txqueuelen 2500
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;不知道为什么 Realtek 在内核版本低于 5.2.3 时（梅林 384.19 的内核版本号为 4.1.51），默认不启用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 的 USB scatter/gather：&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#if LINUX_VERSION_CODE &amp;gt;= KERNEL_VERSION(5,2,3)
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usb_device_no_sg_constraint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;udev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sg_use&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* LINUX_VERSION_CODE &amp;gt;= KERNEL_VERSION(5,2,3) */&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然而不启用这个功能会严重影响发送性能，因此另外一个优化方法是启用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 的 USB scatter/gather：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 在 eth8 上启用 USB scatter/gather&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /sys/class/net/eth8/rtl_adv/sg_en
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;注意：&lt;/strong&gt; 该选项仅适用于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt; 驱动模块支持的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL&lt;/code&gt; 芯片。&lt;/p&gt;

&lt;h2 id=&quot;性能测试&quot;&gt;性能测试&lt;/h2&gt;

&lt;h3 id=&quot;iperf3-1&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;该项测试中 AX88U 是服务端，我的 Windows 台式机是客户端。&lt;/p&gt;

&lt;p&gt;台式机到 AX88U，最快 2.35Gbits/sec:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PS E:\Tools\iperf-3.9-win64&amp;gt; .\iperf3.exe -c 192.168.50.1
Connecting to host 192.168.50.1, port 5201
[  5] local 192.168.50.X port 13610 connected to 192.168.50.1 port 5201
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   280 MBytes  2.35 Gbits/sec
[  5]   1.00-2.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   2.00-3.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   3.00-4.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   4.00-5.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   5.00-6.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   6.00-7.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   7.00-8.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   8.00-9.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   9.00-10.00  sec   279 MBytes  2.34 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.00  sec  2.73 GBytes  2.34 Gbits/sec              sender
[  5]   0.00-10.04  sec  2.73 GBytes  2.33 Gbits/sec              receiver

iperf Done.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;AX88U 到台式机，最快 2.38Gbits/sec:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PS E:\Tools\iperf-3.9-win64&amp;gt; .\iperf3.exe -c 192.168.50.1 -R
Connecting to host 192.168.50.1, port 5201
Reverse mode, remote host 192.168.50.1 is sending
[  5] local 192.168.50.X port 13619 connected to 192.168.50.1 port 5201
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   284 MBytes  2.38 Gbits/sec
[  5]   1.00-2.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   2.00-3.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   3.00-4.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   4.00-5.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   5.00-6.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   6.00-7.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   7.00-8.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   8.00-9.00   sec   282 MBytes  2.36 Gbits/sec
[  5]   9.00-10.00  sec   283 MBytes  2.37 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.03  sec  2.77 GBytes  2.37 Gbits/sec    0         sender
[  5]   0.00-10.00  sec  2.76 GBytes  2.37 Gbits/sec              receiver

iperf Done.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;smb-文件传输&quot;&gt;SMB 文件传输&lt;/h3&gt;

&lt;p&gt;该项测试中我的 Windows 台式机作为服务端，我的 Surface Pro（通过千兆有线 USB 网卡连接到路由器）和 Macbook Pro（通过 802.11ac 无线连接到路由器，协商链路速度为 1300 Mbps）作为客户端，测试内容为两个客户端同时从服务端拷贝 20GB 的文件。&lt;/p&gt;

&lt;p&gt;测试结果表明 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BCM49408&lt;/code&gt; 的性能不足以双向跑满 2.5 Gbps，但是也还算可以了：最大传输速度约 195.7MB/s，平均传输速度约 177.3MB/s。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/ax88u-nbase-t/smb_speed.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/ax88u-nbase-t/smb_speed.png&quot; alt=&quot;SMB 文件传输速度测试&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;提示：&lt;/strong&gt;在 Windows 上运行这个命令可以快速创建一个 20GB 的文件：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fsutil file createNew 20GB.txt 21474836480&lt;/code&gt;。最后一个参数为要创建的文件的大小，单位为字节。&lt;/p&gt;

&lt;h2 id=&quot;实现-5gbe&quot;&gt;实现 5GbE&lt;/h2&gt;

&lt;p&gt;截至本文发布时，市面上基于 USB 的 5GbE 解决方案只有 Aquantia 家（已经被 Marvell&lt;sup id=&quot;fnref:marvell-acquire&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:marvell-acquire&quot; class=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt; 收购了）的 &lt;a href=&quot;https://www.marvell.com/content/dam/marvell/en/public-collateral/ethernet-adaptersandcontrollers/marvell-ethernet-controllers-aqtion-aqc111u-112u-product-brief.pdf&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt;&lt;/a&gt;。就像一开始说的，5GbE 网卡并不便宜，我找到的最便宜的也得要 60 美金。&lt;/p&gt;

&lt;p&gt;而且因为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; 是 USB 3.1 &lt;strong&gt;Gen 1&lt;/strong&gt; 的方案，哪怕是启用 9K 巨型帧，减去 USB 开销&lt;sup id=&quot;fnref:usb-overhead&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:usb-overhead&quot; class=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;和以太网开销&lt;sup id=&quot;fnref:ethernet-overhead&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:ethernet-overhead&quot; class=&quot;footnote&quot;&gt;9&lt;/a&gt;&lt;/sup&gt;，理论上能达到的最大传输速度约 3.96 Gbps。&lt;/p&gt;

&lt;p&gt;同时 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BCM49408&lt;/code&gt; 的性能也不足以支撑这个速度，启用了“&lt;a href=&quot;#性能优化&quot;&gt;性能优化&lt;/a&gt;”一章中描述的所有性能优化方法后，在我的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; 测试中也只能实现最大 3.35 Gbits/sec（AX88U 到台式机）和 1.75 Gbits/sec（台式机到 AX88U）。&lt;/p&gt;

&lt;p&gt;除此之外 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; 还有以下的问题：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;驱动不稳定。在短暂运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; 之后，我的 AX88U 直接 kernel panic 然后重启了。&lt;/li&gt;
  &lt;li&gt;发热很猛，容易掉线。传输过程中网卡会变得非常热，然后不久就失去网络连接了。不太清楚是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; 的问题，还是我买的网卡（&lt;a href=&quot;https://www.sabrent.com/product/NT-SS5G/usb-type-a-or-type-c-to-5-gigabit-ethernet-adapter-10-100-1000-2500-5000-mbps-nt-ss5g/&quot;&gt;Sabrent NT-SS5G&lt;/a&gt;）的散热设计的问题。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;编译-aqc111-驱动模块&quot;&gt;编译 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111&lt;/code&gt; 驱动模块&lt;/h3&gt;

&lt;p&gt;如果还是想试一下 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt;，可以从这里下载驱动：&lt;a href=&quot;https://www.marvell.com/support/downloads.html&quot;&gt;Marvell Drivers&lt;/a&gt;。在下载页面的 PLATFORM 下拉框里选择 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Linux Kernel 3.10 and Higher&lt;/code&gt;，搜索结果中的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Marvell AQtion USB 3.1 Linux Driver&lt;/code&gt; 即为所需驱动，本文使用的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111&lt;/code&gt; 驱动模块版本是 v1.3.3.0。&lt;/p&gt;

&lt;p&gt;运行下面的命令来编译驱动：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 架构: arm64&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 交叉编译器: aarch64-linux&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 内核源代码目录: ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1&lt;/span&gt;
make &lt;span class=&quot;nv&quot;&gt;ARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;arm64 &lt;span class=&quot;nv&quot;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;aarch64-linux- &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1 &lt;span class=&quot;nv&quot;&gt;SUBDIRS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; modules
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果你倾向用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; 的话，可以在这里找到：&lt;a href=&quot;#makefile&quot;&gt;附录 2：脚本：Makefile&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;一切顺利的情况下，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111.ko&lt;/code&gt; 这个文件会生成在当前目录下，预编译好的版本可以在这里下载：&lt;a href=&quot;#预编译的驱动模块&quot;&gt;附录：预编译的二进制文件：预编译的驱动模块&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&quot;配置驱动--性能优化&quot;&gt;配置驱动 &amp;amp; 性能优化&lt;/h3&gt;

&lt;p&gt;把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111.ko&lt;/code&gt; 上传到路由器 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/drivers/&lt;/code&gt; 文件夹内，如果该文件夹不存在，则首先在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs&lt;/code&gt; 文件夹下创建 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drivers&lt;/code&gt; 文件夹。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; 的配置流程和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 的有些许不同，这里需要卸载的是模块是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ether&lt;/code&gt;：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 卸载 rndis_host，因为它依赖于 cdc_ether&lt;/span&gt;
rmmod rndis_host
&lt;span class=&quot;c&quot;&gt;# 卸载 cdc_ether&lt;/span&gt;
rmmod cdc_ether
&lt;span class=&quot;c&quot;&gt;# 加载 aqc111.ko&lt;/span&gt;
insmod /jffs/drivers/aqc111.ko
&lt;span class=&quot;c&quot;&gt;# 加载 cdc_ether&lt;/span&gt;
insmod cdc_ether
&lt;span class=&quot;c&quot;&gt;# 加在 rndis_host&lt;/span&gt;
insmod rndis_host
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;针对 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; 的性能优化则和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 的差不多，只是没法调整 RX 中断合并窗口和 RX 缓冲区大小，因为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111&lt;/code&gt; 驱动模块不支持修改这两个属性。&lt;/p&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;提示：&lt;/strong&gt;完整的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; 配置脚本可以在这里找到：&lt;a href=&quot;#aqc111u-配置脚本&quot;&gt;附录：脚本：AQC111U 配置脚本&lt;/a&gt;。&lt;/p&gt;

&lt;h2 id=&quot;总结&quot;&gt;总结&lt;/h2&gt;

&lt;p&gt;其实在去年早些时候，我就已经开始在 AX88U 上折腾 2.5GbE 网卡。只是在那个时候，市面上能买到的网卡都是基于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt; 的，上文也提到过这个最初版本的芯片是有缺陷的。最终几个月之后，Realtek 修复了这些缺陷，并发布了修订版的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;，这才使得我完成了在 AX88U 上配置 2.5GbE 网卡的任务。&lt;/p&gt;

&lt;p&gt;另外还有一个好消息：QNAP 最近发布了一款小型（相比其他至少要 1U 的产品）的被动散热 5 口 2.5GbE 交换机 &lt;a href=&quot;https://www.qnap.com/en-us/product/qsw-1105-5t&quot;&gt;QNAP QSW-1105-5T&lt;/a&gt;&lt;sup id=&quot;fnref:qsw-1105-5t&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:qsw-1105-5t&quot; class=&quot;footnote&quot;&gt;10&lt;/a&gt;&lt;/sup&gt;，售价为 100 美金，算是物美价廉吧，适合家庭使用。&lt;/p&gt;

&lt;h2 id=&quot;附录预编译的二进制文件&quot;&gt;附录：预编译的二进制文件&lt;/h2&gt;

&lt;h3 id=&quot;预编译的驱动模块&quot;&gt;预编译的驱动模块&lt;/h3&gt;

&lt;p&gt;以下驱动模块仅适用于 AX88U（上传到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/drivers/&lt;/code&gt;）:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt; 驱动模块 v2.13.0：&lt;a href=&quot;/assets/bin/posts/ax88u-nbase-t/drivers/r8152.ko&quot;&gt;r8152.ko&lt;/a&gt;。SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e3a9f7a868baae6756bde4665a45852fcd578bdd&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111&lt;/code&gt; 驱动模块 v1.3.3.0：&lt;a href=&quot;/assets/bin/posts/ax88u-nbase-t/drivers/aqc111.ko&quot;&gt;aqc111.ko&lt;/a&gt;。SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;9dc4768154e065d19a274dcc33235a6b58fd9fb9&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;预编译的测试工具&quot;&gt;预编译的测试工具&lt;/h3&gt;

&lt;p&gt;以下测试工具仅适用于 AX88U（上传到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/tools/&lt;/code&gt;）：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; 5.8：&lt;a href=&quot;/assets/bin/posts/ax88u-nbase-t/tools/ethtool&quot;&gt;ethtool&lt;/a&gt;。SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6936931589476b2001667c50a8f91d713be705fb&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; 3.9：&lt;a href=&quot;/assets/bin/posts/ax88u-nbase-t/tools/iperf3&quot;&gt;iperf3&lt;/a&gt;。SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ec19717ecb56a5b5bbfeda3316cd7e712cb6bde0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;附录脚本&quot;&gt;附录：脚本&lt;/h2&gt;

&lt;h3 id=&quot;makefile&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;以下 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; 仅适用于 AX88U：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt;：&lt;a href=&quot;/assets/code/posts/ax88u-nbase-t/r8152/Makefile&quot;&gt;r8152/Makefile&lt;/a&gt;。SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dc22346bdae40f5ea5bb2a0c193dc922fa3e4b60&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111&lt;/code&gt;：&lt;a href=&quot;/assets/code/posts/ax88u-nbase-t/aqc111/Makefile&quot;&gt;acq111/Makefile&lt;/a&gt;。SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;37dfc73f2e4b6676e5dd712ad38b389f0140fb76&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;rtl8156b-配置脚本&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; 配置脚本&lt;/h3&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;jffsscriptsinit-start&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/init-start&lt;/code&gt;&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/001-init-start
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rtl8156&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;init-start: loading RTL8156 driver...&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# It's safe to `insmod` here, since `usbcore` has already been &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# installed before `init-start` was called. &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# init.c: sysinit() -&amp;gt; init_wl() -&amp;gt; &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#         init-broadcom.c: eval(&quot;insmod&quot;, &quot;usbcore&quot;);&lt;/span&gt;
insmod /jffs/drivers/r8152.ko

&lt;span class=&quot;c&quot;&gt;# Note `insmod r8152.ko` must be executed before `cdc_ncm` module &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# is loaded into kernel. Otherwise `cdc_ncm` will take control &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# of the USB 2.5GbE adapter.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# If `r8152.ko` can't be loaded before `cdc_ncm`, then you should &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# `rmmod cdc_ncm`,` insmod r8152.ko` and `insmod cdc_ncm`&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# (remember to rm/insmod modules depending on `cdc_ncm` first)&lt;/span&gt;

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rtl8156&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;init-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/001-init-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;jffsscriptsservices-start&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/services-start&lt;/code&gt;&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/001-services-start
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rtl8156&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: setting up eth8...&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Update nvram variables&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;br0_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get br0_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lan_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get lan_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;wired_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get wired_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Add eth8 into br0&lt;/span&gt;
brctl addif br0 eth8

&lt;span class=&quot;c&quot;&gt;# Set TX queue length to 2500 on eth8 and bring it up&lt;/span&gt;
ifconfig eth8 txqueuelen 2500 allmulti up

&lt;span class=&quot;c&quot;&gt;# Enable USB scatter/gather on eth8&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /sys/class/net/eth8/rtl_adv/sg_en

&lt;span class=&quot;c&quot;&gt;# Enable RPS (Receive Packet Steering) on eth8.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Since AX88U has four cores, we set it to 'f'&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;f &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /sys/class/net/eth8/queues/rx-0/rps_cpus

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rtl8156&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/001-services-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;aqc111u-配置脚本&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; 配置脚本&lt;/h3&gt;

&lt;p&gt;尽管能在 AX88U 上使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt;，但是发挥不出来 5Gbps 的性能，详情请参阅章节 &lt;a href=&quot;#实现-5gbe&quot;&gt;实现 5GbE&lt;/a&gt;。&lt;/p&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;jffsscriptsservices-start-1&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/services-start&lt;/code&gt;&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/001-services-start
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;aqc111&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: loading AQC111 driver...&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# No need to `rmmod cdc_ether` here, as `cdc_ncm` will be loaded &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# after `services-start` is called&lt;/span&gt;
insmod /jffs/drivers/aqc111.ko

&lt;span class=&quot;c&quot;&gt;# Note `insmod aqc111.ko` must be executed before `cdc_ether` &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# module is loaded into kernel. Otherwise `cdc_ether` will take &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# control of the USB 5GbE adapter.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# If `aqc111.ko` can't be loaded before `cdc_ether`, then you should &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# `rmmod cdc_ether`, `insmod aqc111.ko` and `insmod cdc_ether` &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# (remember to rm/insmod modules depending on cdc_ether first)&lt;/span&gt;
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;aqc111&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: AQC111 driver loaded&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Now we can setup the new interface&lt;/span&gt;
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;aqc111&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: setting up eth8...&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Update nvram variables&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;br0_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get br0_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lan_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get lan_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;wired_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get wired_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Add eth8 into br0 and bring eth8 up&lt;/span&gt;
brctl addif br0 eth8
ifconfig eth8 allmulti up

&lt;span class=&quot;c&quot;&gt;# Enable RPS (Receive Packet Steering) on eth8.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Since AX88U has four cores, we set it to 'f'.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;f &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /sys/class/net/eth8/queues/rx-0/rps_cpus

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;aqc111&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/001-services-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;参考文献&quot;&gt;参考文献&lt;/h2&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:bcm49408&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Broadcom, &lt;em&gt;&lt;a href=&quot;https://www.broadcom.com/products/wireless/wireless-lan-infrastructure/bcm49408&quot;&gt;BCM49408: 64 bit Quad-Core ARM v8 compliant Processor for Enterprise Access Point Applications&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:bcm49408&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:rtl8156&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Realtek, &lt;em&gt;&lt;a href=&quot;https://www.realtek.com/en/press-room/news-releases/item/realtek-launches-world-s-first-single-chip-2-5g-ethernet-controller-for-multiple-applications-including-gaming-solution&quot;&gt;Realtek Launches World’s First Single-Chip 2.5G Ethernet Controller for Multiple Applications, including Gaming Solution&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:rtl8156&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:rtl8156-issue&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;domih, &lt;em&gt;&lt;a href=&quot;https://forum.odroid.com/viewtopic.php?t=38713&quot;&gt;[HOWTO] 2.5Gbe or 5Gbe with H2 and/or N2 and/or C4?&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:rtl8156-issue&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:vl160&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;VIA Labs, Inc., &lt;em&gt;&lt;a href=&quot;https://www.via-labs.com/product_show.php?id=72&quot;&gt;VL160 - USB-C™ 2:4 Data Switch with CC Function for USB 3.1&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:vl160&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:upstream-no-rtl8156&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Kai-Heng Feng, &lt;em&gt;&lt;a href=&quot;https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1832472/comments/39&quot;&gt;Comment 39 for bug 1832472: cdc_ncm floods syslog unneccessarily&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:upstream-no-rtl8156&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:merlin-build&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;RMerl and Adamm, &lt;em&gt;&lt;a href=&quot;https://github.com/RMerl/asuswrt-merlin.ng/blob/master/tools/build-all#L203&quot;&gt;asuswrt-merlin.ng/build-all at master · RMerl/asuswrt-merlin.ng&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:merlin-build&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:marvell-acquire&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Marvell, &lt;em&gt;&lt;a href=&quot;https://www.marvell.com/company/newsroom/marvell-to-acquire-aquantia-accelerating-ethernet-technology-leadership.html&quot;&gt;Marvell to Acquire Aquantia - Accelerating Ethernet Technology Leadership&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:marvell-acquire&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:usb-overhead&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Andrew Ku, &lt;em&gt;&lt;a href=&quot;https://www.tomshardware.com/reviews/usb-3-uas-turbo,3215-2.html&quot;&gt;So, What Makes USB 3.0 Slower Than We Expect? - Faster USB 3.0 Performance: Examining UASP And Turbo Mode&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:usb-overhead&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:ethernet-overhead&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Rickard Nobel, &lt;em&gt;&lt;a href=&quot;http://rickardnobel.se/actual-throughput-on-gigabit-ethernet/&quot;&gt;Actual throughput on Gigabit Ethernet&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:ethernet-overhead&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:qsw-1105-5t&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Ryan Smith, &lt;em&gt;&lt;a href=&quot;https://www.anandtech.com/show/15916/at-last-a-25gbps-consumer-network-switch-qnap-releases-qsw11055t-5port-switch&quot;&gt;At Last, a 2.5Gbps Consumer Network Switch: QNAP Releases QSW-1105-5T 5-Port Switch&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:qsw-1105-5t&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</content><author><name>Renjie Wu</name></author><category term="Network" /><summary type="html">AX88U 缺少板载的 2.5GbE 网卡实为一大遗憾，尤其是考虑到它的 CPU `BCM49408` 提供了原生支持。幸好螃蟹家（Realtek）提供了一个经济的 USB 3.0 解决方案 —— `RTL8156B`，本文将介绍如何在 AX88U + Merlin 384.19 上配置基于 `RTL8156B` 的 2.5GbE 网卡。</summary></entry><entry xml:lang="en-us"><title type="html">Towards 2.5GbE (NBASE-T) on ASUS RT-AX88U with `RTL8156B` and Asuswrt-Merlin 384.19</title><link href="https://wu.renjie.im/blog/network/ax88u-nbase-t/" rel="alternate" type="text/html" title="Towards 2.5GbE (NBASE-T) on ASUS RT-AX88U with `RTL8156B` and Asuswrt-Merlin 384.19" /><published>2020-10-11T17:24:54-07:00</published><updated>2021-01-24T13:49:14-08:00</updated><id>https://wu.renjie.im/blog/network/ax88u-nbase-t</id><content type="html" xml:base="https://wu.renjie.im/blog/network/ax88u-nbase-t/">&lt;p&gt;It has been several months since I updated my main router to &lt;a href=&quot;https://www.asus.com/us/Networking/RT-AX88U/&quot;&gt;AX88U&lt;/a&gt;.
It is undoubtedly an excellent router and I’m quite satisfied with its features.&lt;/p&gt;

&lt;p&gt;However, the lack of integrated 2.5GbE port unfortunately shadows its power and ability, not to mention that its 
processor &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BCM49408&lt;/code&gt; does natively support 2.5GbE&lt;sup id=&quot;fnref:bcm49408&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:bcm49408&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. To make it worse, recently released 
&lt;a href=&quot;https://www.asus.com/us/Networking/RT-AX86U/&quot;&gt;AX86U&lt;/a&gt; comes with a similar processor &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BCM4908&lt;/code&gt; and, yeah, has a 
built-in 2.5GbE port.&lt;/p&gt;

&lt;p&gt;The good news is that there is an external solution from Realtek: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt;&lt;sup id=&quot;fnref:rtl8156&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:rtl8156&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, a USB 3.0 based 2.5GbE controller. 
Comparing to much expensive 5 or 10GbE equipments, it is fairly “cheap”: you can easily find a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RLT8156&lt;/code&gt; based USB dongle 
for about $30.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But&lt;/strong&gt; do note that there are two versions of this chip: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;. You should look for the &lt;strong&gt;B&lt;/strong&gt; revision 
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;), as the original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt; has a weird stability issue in long time tests&lt;sup id=&quot;fnref:rtl8156-issue&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:rtl8156-issue&quot; class=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;In addition, if you bought a USB Type-C dongle, you may also need an “active” or “double side” USB Type-C to USB-A adapter
(which usually include a multiplexer chip, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VL160&lt;/code&gt;&lt;sup id=&quot;fnref:vl160&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:vl160&quot; class=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;). Otherwise, you have to figure out which side of the USB
Type-C port to insert, since one side will work at the speed of USB 3.0 and the other side will do USB 2.0 only.&lt;/p&gt;

&lt;h2 id=&quot;no-plug-and-play&quot;&gt;No Plug-and-Play?&lt;/h2&gt;

&lt;p&gt;If you directly insert the USB dongle into AX88U, there is no problem to get it recognized (on &lt;strong&gt;Network Map&lt;/strong&gt; page in router’s 
web management console). Also in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifconfig -a&lt;/code&gt;, you can find that the dongle has been registered as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usb0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, if you try to bring it up with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifconfig usb0 up&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dmesg&lt;/code&gt; will be spammed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ncm&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cdc_ncm 2-2:1.0 usb0: network connection: connected
cdc_ncm 2-2:1.0 usb0: 2500 mbit/s downlink 2500 mbit/s uplink
cdc_ncm 2-2:1.0 usb0: network connection: connected
cdc_ncm 2-2:1.0 usb0: 2500 mbit/s downlink 2500 mbit/s uplink
cdc_ncm 2-2:1.0 usb0: network connection: connected
cdc_ncm 2-2:1.0 usb0: 2500 mbit/s downlink 2500 mbit/s uplink
cdc_ncm 2-2:1.0 usb0: network connection: connected
cdc_ncm 2-2:1.0 usb0: 2500 mbit/s downlink 2500 mbit/s uplink
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The reason is that the built-in driver in Linux kernel has no support for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt; yet&lt;sup id=&quot;fnref:upstream-no-rtl8156&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:upstream-no-rtl8156&quot; class=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;. 
So we have to build the driver on our own.&lt;/p&gt;

&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;

&lt;h3 id=&quot;compile-linux-kernel&quot;&gt;Compile Linux Kernel&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/RMerl/asuswrt-merlin.ng/wiki/Compiling-under-WSL2&quot;&gt;Follow this guide&lt;/a&gt; for setting up the compiling 
environment for Asuswrt-Merlin. Though it is titled for WSL (Windows Subsystem for Linux) 2, you can still follow these
steps under WSL 1 (legacy WSL) or pure Linux.&lt;/p&gt;

&lt;p&gt;If you’re using legacy WSL like me, you have to &lt;a href=&quot;https://github.com/Microsoft/WSL/issues/2468#issuecomment-374904520&quot;&gt;follow this comment&lt;/a&gt; 
to run 32-bit applications in legacy WSL, because the provided toolchains are 32-bit.&lt;/p&gt;

&lt;p&gt;As we don’t really need the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; history, we can just clone the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Clone the HEAD only&lt;/span&gt;
git clone &lt;span class=&quot;nt&quot;&gt;--depth&lt;/span&gt; 1 https://github.com/RMerl/asuswrt-merlin.ng
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Also note that instead of linking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brcm-arm-sdk&lt;/code&gt; folder under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src-rt-6.x.4708&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# `src-rt-6.x.4708` is for AC56U, AC68U and AC87U&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; ~/am-toolchains/brcm-arm-sdk ~/asuswrt-merlin.ng/release/src-rt-6.x.4708/toolchains
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… in the guide, we link it under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src-rt-5.02axhnd&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# `src-rt-5.02axhnd` is for AX88U, AX58U and AX56U&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; ~/am-toolchains/brcm-arm-sdk ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/toolchains
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… since we’re targeting AX88U, according to Merlin’s build script&lt;sup id=&quot;fnref:merlin-build&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:merlin-build&quot; class=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Once you got the environment done, run this to build the firmware for AX88U:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Targeting AX88U&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;release/src-rt-5.02axhnd &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make rt-ax88u
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is not necessary to complete the whole firmware compiling, as we only need the generated header files (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.h&lt;/code&gt;)
from the part of compiling Linux kernel.&lt;/p&gt;

&lt;p&gt;Therefore once the kernel building starts for a while, you may interrupt the build process by pressing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CTRL+C&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;compile-tools&quot;&gt;Compile Tools&lt;/h3&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;iperf3&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;Source code for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; can be &lt;a href=&quot;https://github.com/esnet/iperf&quot;&gt;found at here&lt;/a&gt;. 
At the time of writing, the latest version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; is 3.9.&lt;/p&gt;

&lt;p&gt;Run the following lines to compile &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; for AX88U:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create `build` folder as installation prefix&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;build
&lt;span class=&quot;c&quot;&gt;# We need the static-linked binary&lt;/span&gt;
./configure &lt;span class=&quot;nt&quot;&gt;--host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;arm-linux &lt;span class=&quot;nt&quot;&gt;--prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/build &lt;span class=&quot;nt&quot;&gt;--enable-static&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-shared&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Build the binary and install it into `build` folder&lt;/span&gt;
make &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; binary should be generated in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./build/bin/iperf3&lt;/code&gt;. Or you can get the pre-compiled one in section 
&lt;a href=&quot;#pre-compiled-tools&quot;&gt;Appendix: Pre-compiled Binaries: Pre-compiled Tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; running on Windows, please check &lt;a href=&quot;https://www.neowin.net/forum/topic/1234695-iperf-39-windows-build/&quot;&gt;this post&lt;/a&gt;.&lt;/p&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;ethtool&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;Source code for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; can be &lt;a href=&quot;https://kernel.org/pub/software/network/ethtool/&quot;&gt;found at here&lt;/a&gt;. 
At the time of writing, the latest version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; is 5.8.&lt;/p&gt;

&lt;p&gt;Run the following lines to compile &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; for AX88U:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create `build` folder as installation prefix&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;build
&lt;span class=&quot;c&quot;&gt;# Disable netlink, as we don't need it at all in our case.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# This also helps eliminate the dependency on `libmnl`&lt;/span&gt;
./configure &lt;span class=&quot;nt&quot;&gt;--host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;arm-linux &lt;span class=&quot;nt&quot;&gt;--prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/build &lt;span class=&quot;nt&quot;&gt;--disable-netlink&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Build the binary and install it into `build` folder&lt;/span&gt;
make &amp;amp; make &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; binary should be generated in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./build/bin/ethtool&lt;/code&gt;. Or you can get the pre-compiled one in section 
&lt;a href=&quot;#pre-compiled-tools&quot;&gt;Appendix: Pre-compiled Binaries: Pre-compiled Tools&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;compile-r8152-driver&quot;&gt;Compile &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt; Driver&lt;/h3&gt;

&lt;p&gt;It might be confusing at the beginning, but yes, the driver for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; is called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt;. The source code can be 
&lt;a href=&quot;https://www.realtek.com/en/component/zoo/category/network-interface-controllers-10-100-1000m-gigabit-ethernet-usb-3-0-software&quot;&gt;downloaded from here&lt;/a&gt;.
At the time of writing, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt; driver version is v2.13.0.&lt;/p&gt;

&lt;p&gt;I added a line to function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtl8152_get_drvinfo&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152.c&lt;/code&gt;, so we can verify the chip version is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-patch highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gd&quot;&gt;--- source-2.13.0/r8152-original.c     2020-04-20 01:36:49.000000000 -0700
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+++ source-2.13.0/r8152-modified.c     2020-10-06 23:47:07.123659400 -0700
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@@ -16369,6 +16369,7 @@&lt;/span&gt;
        strlcpy(info-&amp;gt;driver, MODULENAME, sizeof(info-&amp;gt;driver));
        strlcpy(info-&amp;gt;version, DRIVER_VERSION, sizeof(info-&amp;gt;version));
        usb_make_path(tp-&amp;gt;udev, info-&amp;gt;bus_info, sizeof(info-&amp;gt;bus_info));
&lt;span class=&quot;gi&quot;&gt;+       snprintf(info-&amp;gt;fw_version, sizeof(info-&amp;gt;fw_version), &quot;0x%04x&quot;, tp-&amp;gt;version);
&lt;/span&gt; } 

 #if LINUX_VERSION_CODE &amp;lt; KERNEL_VERSION(4,20,0)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since we’re targeting AX88U, we need to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aarch64-linux&lt;/code&gt; cross-compiler and set the architecture to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arm64&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Architecture: arm64&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Cross-compiler: aarch64-linux&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Kernel source code directory: ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1&lt;/span&gt;
make &lt;span class=&quot;nv&quot;&gt;ARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;arm64 &lt;span class=&quot;nv&quot;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;aarch64-linux- &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1 &lt;span class=&quot;nv&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; modules
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you prefer using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; instead, it can be found in section &lt;a href=&quot;#makefile&quot;&gt;Appendix: Scripts: Makefile&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If everything goes well, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152.ko&lt;/code&gt; should be generated in the working directory. You can also get the
pre-compiled one in section &lt;a href=&quot;#pre-compiled-drivers&quot;&gt;Appendix: Pre-compiled Binaries: Pre-compiled Drivers&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;Upload &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152.ko&lt;/code&gt; into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/drivers/&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/tools/&lt;/code&gt;. Remember to create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drivers&lt;/code&gt;
and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools&lt;/code&gt; folders in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs&lt;/code&gt; first.&lt;/p&gt;

&lt;h3 id=&quot;load-driver&quot;&gt;Load Driver&lt;/h3&gt;

&lt;p&gt;As we discussed in section &lt;a href=&quot;#no-plug-and-play&quot;&gt;No Plug-and-Play?&lt;/a&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ncm&lt;/code&gt; will try to take control of the USB dongle,
so we need to unload it first.&lt;/p&gt;

&lt;p&gt;We need to check which modules depends on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ncm&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lsmod | grep cdc_ncm&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# admin@ax88u:/# lsmod | grep cdc_ncm&lt;/span&gt;
&lt;strong class=&quot;mi&quot;&gt;cdc_ncm&lt;/strong&gt;                16787  1 &lt;strong class=&quot;mi&quot;&gt;cdc_mbim&lt;/strong&gt;
usbnet                 21074  7 cdc_mbim,qmi_wwan,cdc_ncm,rndis_host,cdc_ether,ax88179_178a,asix
usbcore               166572 23 uas,usb_storage,cdc_mbim,qmi_wwan,cdc_wdm,cdc_ncm,rndis_host,cdc_ether,ax88179_178a,asix,cdc_acm,usbnet,usblp,ohci_pci,ohci_platform,ohci_hcd,ehci_pci,ehci_platform,ehci_hcd,xhci_pci,xhci_plat_hcd,xhci_hcd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So we have to unload &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_mbim&lt;/code&gt; first and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ncm&lt;/code&gt; later:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Unload `cdc_mbim`, as it depends on `cdc_ncm`&lt;/span&gt;
rmmod cdc_mbim
&lt;span class=&quot;c&quot;&gt;# Unload `cdc_ncm`&lt;/span&gt;
rmmod cdc_ncm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can load &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152.ko&lt;/code&gt; and also load &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ncm&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_mbim&lt;/code&gt; back:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Load `r8152` driver&lt;/span&gt;
insmod /jffs/drivers/r8152.ko
&lt;span class=&quot;c&quot;&gt;# Load `cdc_ncm`&lt;/span&gt;
insmod cdc_ncm
&lt;span class=&quot;c&quot;&gt;# Load `cdc_mbim`&lt;/span&gt;
insmod cdc_mbim
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If everything goes well, system log (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tail /tmp/syslog.log&lt;/code&gt;) should reflect this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# admin@ax88u:/# tail /tmp/syslog.log&lt;/span&gt;
Oct  7 21:27:42 kernel: usbcore: deregistering interface driver cdc_mbim
Oct  7 21:27:42 kernel: usbcore: registered new interface driver r8152
Oct  7 21:27:42 kernel: usb 2-2: reset SuperSpeed USB device number 2 using xhci-hcd
Oct  7 21:27:42 kernel: netif_napi_add() called with weight 256 on device eth%d
Oct  7 21:27:42 kernel: r8152 2-2:1.0 eth8: v2.13.0 (2020/04/20)
Oct  7 21:27:42 kernel: r8152 2-2:1.0 eth8: This product is covered by one or more of the following patents:
Oct  7 21:27:42 kernel: 		US6,570,884, US6,115,776, and US6,327,625.
Oct  7 21:27:42 hotplug: &lt;strong class=&quot;mi&quot;&gt;add net eth8&lt;/strong&gt;.
Oct  7 21:27:42 kernel: usbcore: registered new interface driver cdc_ncm
Oct  7 21:27:42 kernel: usbcore: registered new interface driver cdc_mbim
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, the adapter is registered as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth8&lt;/code&gt;, thus if we run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifconfig eth8&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;eth8      Link encap:Ethernet  HWaddr 00:E0:4C:00:FA:KE
          inet6 addr: fe80::2e0:4cff:fe00:fake/64 Scope:Link
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Also if you check the &lt;em&gt;Network Map&lt;/em&gt; page in Web management UI, the adapter should show up there:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/ax88u-nbase-t/web_ui.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/ax88u-nbase-t/web_ui.png&quot; alt=&quot;Adapter shown in Network Map page&quot; class=&quot;align-center&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we can update &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvram&lt;/code&gt; variables, add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth8&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; and bring &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth8&lt;/code&gt; up:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Update nvram variables&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;br0_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get br0_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lan_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get lan_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;wired_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get wired_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Add eth8 into br0 and bring it up&lt;/span&gt;
brctl addif br0 eth8
ifconfig eth8 allmulti up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally we can connect the ethernet cable to the USB dongle.&lt;/p&gt;

&lt;p&gt;Run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/tools/ethtool eth8&lt;/code&gt; to verify the driver is correctly loaded and the negotiated link speed 
is 2500Mb/s full-duplex:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# admin@ax88u:/# /jffs/tools/ethtool eth8&lt;/span&gt;
Settings for eth8:
        Supported ports: [ MII ]
        Supported link modes:   10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
                                2500baseX/Full
        Supported pause frame use: No
        Supports auto-negotiation: Yes
        Supported FEC modes: Not reported
        Advertised link modes:  10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
                                2500baseX/Full
        Advertised pause frame use: Symmetric Receive-only
        Advertised auto-negotiation: Yes
        Advertised FEC modes: Not reported
        Link partner advertised link modes:  10baseT/Half 10baseT/Full
                                             100baseT/Half 100baseT/Full
                                             1000baseT/Full
        Link partner advertised pause frame use: No
        Link partner advertised auto-negotiation: Yes
        Link partner advertised FEC modes: Not reported
        &lt;strong class=&quot;mi&quot;&gt;Speed: 2500Mb/s&lt;/strong&gt;
        &lt;strong class=&quot;mi&quot;&gt;Duplex: Full&lt;/strong&gt;
        Port: MII
        PHYAD: 32
        Transceiver: internal
        Auto-negotiation: on
        Supports Wake-on: pumbg
        Wake-on: g
        Current message level: 0x00007fff (32767)
                               drv probe link timer ifdown ifup rx_err tx_err tx_queued intr tx_done rx_status pktdata hw wol
        &lt;strong class=&quot;mi&quot;&gt;Link detected: yes&lt;/strong&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Complete scripts for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; can be found in &lt;a href=&quot;#scripts-for-rtl8156b&quot;&gt;Appendix: Scripts: Scripts for RTL8156B&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;verify-rtl-version&quot;&gt;Verify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL&lt;/code&gt; Version&lt;/h3&gt;

&lt;p&gt;To tell if the dongle is really &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;, you can run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/tools/ethtool --driver eth8&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# admin@ax88u:/# /jffs/tools/ethtool --driver eth8&lt;/span&gt;
driver: r8152
version: v2.13.0 (2020/04/20)
&lt;strong class=&quot;mi&quot;&gt;firmware-version: 0x000e&lt;/strong&gt;
expansion-rom-version:
bus-info: usb-xhci-hcd.0-2
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: no
supports-priv-flags: no
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firmware-version&lt;/code&gt; is either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x000b&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x000c&lt;/code&gt;, the internal chip is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firmware-version&lt;/code&gt; is either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x000d&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x000e&lt;/code&gt;, the internal chip is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, mine &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firmware-version&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x000e&lt;/code&gt; thus it is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;.&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note:&lt;/strong&gt; In order to show the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firmware-version&lt;/code&gt;, the added line to function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtl8152_get_drvinfo&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152.c&lt;/code&gt; is necessary.
Check deatils about it in section &lt;a href=&quot;#compile-r8152-driver&quot;&gt;Preparation: Compile &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt; driver&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;performance-tuning&quot;&gt;Performance Tuning&lt;/h2&gt;

&lt;p&gt;Complete scripts for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; can be found in &lt;a href=&quot;#scripts-for-rtl8156b&quot;&gt;Appendix: Scripts: Scripts for RTL8156B&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;receive-rx&quot;&gt;Receive (RX)&lt;/h3&gt;

&lt;p&gt;By default, hardware interrupts for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xhci-hcd:usb1&lt;/code&gt; on AX88U is only handled by CPU core 4 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat /proc/irq/28/smp_affinity_list&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;However, as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; controller only has 1 RX queue, we can’t spread those hardware interrupts to other cores
via changing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smp_affinity_list&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thus we have to enable RPS (Receive Packet Steering). RPS helps to distribute software interrupts (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;softirq&lt;/code&gt;) to multiple cores.
You can &lt;a href=&quot;https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/performance_tuning_guide/network-rps&quot;&gt;check here&lt;/a&gt; 
for more details about RPS.&lt;/p&gt;

&lt;p&gt;To enable RPS on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth8&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Enable RPS (Receive Packet Steering) on eth8&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Since AX88U has four cores, so we set it to 'f'&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;f &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /sys/class/net/eth8/queues/rx-0/rps_cpus
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At least in my test, enabling RPS alone allows the adapter to reach its maxmium performance in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But if you are looking for more RX tweaks, here are some examples:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Increase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net.core.netdev_max_backlog&lt;/code&gt;. The default value is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1000&lt;/code&gt; and you may increase it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2500&lt;/code&gt; via:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 1000 is the default for 1GbE, thus 2500 seems reasonable for 2.5GbE&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;2500 &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /proc/sys/net/core/netdev_max_backlog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Increase RX interrupt coalescing (to decrase # interrupts). The defuault &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rx-usecs&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;15&lt;/code&gt; and you may change it via:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# &amp;lt;N&amp;gt; is the microseconds to delay an RX interrupt after packet arrival&lt;/span&gt;
/jffs/tool/ethtool &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; eth8 rx-usecs &amp;lt;N&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Increase RX ring buffer size. The default value is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;100&lt;/code&gt; and you may change it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4096&lt;/code&gt; (which is the maxmium):
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 4096 is the maxmium supported value for RX ring buffer&lt;/span&gt;
/jffs/tool/ethtool &lt;span class=&quot;nt&quot;&gt;-G&lt;/span&gt; eth8 rx 4096
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More information can be found &lt;a href=&quot;https://cromwell-intl.com/open-source/performance-tuning/ethernet.html&quot;&gt;here&lt;/a&gt;, 
&lt;a href=&quot;https://blog.cloudflare.com/how-to-achieve-low-latency/&quot;&gt;here&lt;/a&gt; and 
&lt;a href=&quot;https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/performance_tuning_guide/main-network&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;transmit-tx&quot;&gt;Transmit (TX)&lt;/h3&gt;

&lt;p&gt;Unlike RPS, XPS (Transmit Packet Steering) will not help increase performance in our case, because&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;For a network device with a &lt;strong&gt;single transmission queue&lt;/strong&gt;, XPS configuration has no effect, since there is no choice in this case.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p class=&quot;small&quot;&gt;Linux Kernel Documentation — &lt;cite&gt;&lt;a href=&quot;https://www.kernel.org/doc/Documentation/networking/scaling.txt&quot;&gt;Scaling in the Linux Networking Stack&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;… and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; has only 1 TX queue.&lt;/p&gt;

&lt;p&gt;But we can increase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;txqueuelen&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2500&lt;/code&gt; on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth8&lt;/code&gt; anyway:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 1000 is the default for 1GbE, thus 2500 seems reasonable for 2.5GbE&lt;/span&gt;
ifconfig eth8 txqueuelen 2500
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Somehow Realtek didn’t enable USB scatter/gather for kernel version below 5.2.3 (AX88U’s kernel version is 4.1.51), 
according to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152.c&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#if LINUX_VERSION_CODE &amp;gt;= KERNEL_VERSION(5,2,3)
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usb_device_no_sg_constraint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;udev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sg_use&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* LINUX_VERSION_CODE &amp;gt;= KERNEL_VERSION(5,2,3) */&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… and without USB scatter/gather enabled, the TX performance is really hurt.&lt;/p&gt;

&lt;p&gt;Of course you can modify the driver, but I found a way to enable it externally:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Enable USB scatter/gather on eth8&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /sys/class/net/eth8/rtl_adv/sg_en
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note:&lt;/strong&gt; This option only works for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt; driver supported &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL&lt;/code&gt; chips.&lt;/p&gt;

&lt;h2 id=&quot;performance-evaluation&quot;&gt;Performance Evaluation&lt;/h2&gt;

&lt;h3 id=&quot;iperf3-1&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;AX88U is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; server and my Windows PC is the client.&lt;/p&gt;

&lt;p&gt;PC to AX88U, achieving ~2.35Gbits/sec:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PS E:\Tools\iperf-3.9-win64&amp;gt; .\iperf3.exe -c 192.168.50.1
Connecting to host 192.168.50.1, port 5201
[  5] local 192.168.50.X port 13610 connected to 192.168.50.1 port 5201
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   280 MBytes  2.35 Gbits/sec
[  5]   1.00-2.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   2.00-3.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   3.00-4.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   4.00-5.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   5.00-6.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   6.00-7.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   7.00-8.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   8.00-9.00   sec   279 MBytes  2.34 Gbits/sec
[  5]   9.00-10.00  sec   279 MBytes  2.34 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.00  sec  2.73 GBytes  2.34 Gbits/sec              sender
[  5]   0.00-10.04  sec  2.73 GBytes  2.33 Gbits/sec              receiver

iperf Done.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;AX88U to PC, achieving ~2.38Gbits/sec:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PS E:\Tools\iperf-3.9-win64&amp;gt; .\iperf3.exe -c 192.168.50.1 -R
Connecting to host 192.168.50.1, port 5201
Reverse mode, remote host 192.168.50.1 is sending
[  5] local 192.168.50.X port 13619 connected to 192.168.50.1 port 5201
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   284 MBytes  2.38 Gbits/sec
[  5]   1.00-2.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   2.00-3.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   3.00-4.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   4.00-5.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   5.00-6.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   6.00-7.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   7.00-8.00   sec   283 MBytes  2.37 Gbits/sec
[  5]   8.00-9.00   sec   282 MBytes  2.36 Gbits/sec
[  5]   9.00-10.00  sec   283 MBytes  2.37 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.03  sec  2.77 GBytes  2.37 Gbits/sec    0         sender
[  5]   0.00-10.00  sec  2.76 GBytes  2.37 Gbits/sec              receiver

iperf Done.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;smb-file-transfer&quot;&gt;SMB File Transfer&lt;/h3&gt;

&lt;p&gt;Here we test a real-world application: SMB file transfer.&lt;/p&gt;

&lt;p&gt;My Windows PC acts the SMB server, while my Surface Pro (connected via wire with USB 1GbE adapter) and my Macbook Pro 
(connected via 802.11ac WiFi, negotiated link speed: 1300Mbps) are trying to copy a 20GB file simultaneously.&lt;/p&gt;

&lt;p&gt;Consider the overhead of SMB protocol and the relatively less powerful &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BCM49408&lt;/code&gt; comparing to x86 CPUs, I’d say the 
result below is fairly good by the speed reaching ~195.7MB/s and averaging at around 177.3MB/s.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/ax88u-nbase-t/smb_speed.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/ax88u-nbase-t/smb_speed.png&quot; alt=&quot;SMB file transfer speed test result&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;Tip:&lt;/strong&gt; To quickly create a dummy file of 20GB on Windows: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fsutil file createNew 20GB.txt 21474836480&lt;/code&gt;. 
The last parameter is the specified file size in bytes.&lt;/p&gt;

&lt;h2 id=&quot;what-about-5gbe&quot;&gt;What about 5GbE?&lt;/h2&gt;

&lt;p&gt;At the time of writing, the only USB solution for 5GbE is Aquantia’s (acquired by Marvell&lt;sup id=&quot;fnref:marvell-acquire&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:marvell-acquire&quot; class=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;) 
&lt;a href=&quot;https://www.marvell.com/content/dam/marvell/en/public-collateral/ethernet-adaptersandcontrollers/marvell-ethernet-controllers-aqtion-aqc111u-112u-product-brief.pdf&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt;&lt;/a&gt;.
Like I said before, 5GbE is not cheap: the cheapest 5GbE adapter I found costs $60.&lt;/p&gt;

&lt;p&gt;Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; is a USB 3.1 &lt;strong&gt;Gen 1&lt;/strong&gt; based solution, even with 9K jumbo frame enabled, theoretically the 
maxmium speed you can reach is about 3.96 Gbits/sec considering the overhead from both USB&lt;sup id=&quot;fnref:usb-overhead&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:usb-overhead&quot; class=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt; and 
Ethernet&lt;sup id=&quot;fnref:ethernet-overhead&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:ethernet-overhead&quot; class=&quot;footnote&quot;&gt;9&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Not to mention that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BCM49408&lt;/code&gt; seems not able to handle this speed: after applied all the tweaks described in
section &lt;a href=&quot;#performance-tuning&quot;&gt;Performance Tuning&lt;/a&gt;, I can only get ~3.35 Gbits/sec from AX88U to PC, and ~1.75 Gbits/secs
from PC to AX88U in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; test.&lt;/p&gt;

&lt;p&gt;There are also some other issues:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; driver seems unstable. Somehow my AX88U got kernel panic and suddenly rebooted after running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; for a short while.&lt;/li&gt;
  &lt;li&gt;Connection lost after a while. It becomes very hot during transmission and will eventually lose ethernet connection. 
Not sure if the latter is caused by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; or the thermal design of the particular adapter I have.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;compile-aqc111-driver&quot;&gt;Compile &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111&lt;/code&gt; Driver&lt;/h3&gt;

&lt;p&gt;If you still want to give it a try, you can &lt;a href=&quot;https://www.marvell.com/support/downloads.html&quot;&gt;download the driver code here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Choose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Linux Kernel 3.10 and Higher&lt;/code&gt; in the PLATFORM droplist and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Marvell AQtion USB 3.1 Linux Driver&lt;/code&gt; is the one to look for.&lt;/p&gt;

&lt;p&gt;At the time of writing, the least driver version is v1.3.3.0.&lt;/p&gt;

&lt;p&gt;Since we’re targeting AX88U, we need to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aarch64-linux&lt;/code&gt; cross-compiler and set the architecture to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arm64&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Architecture: arm64&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Cross-compiler: aarch64-linux&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Kernel source code directory: ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1&lt;/span&gt;
make &lt;span class=&quot;nv&quot;&gt;ARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;arm64 &lt;span class=&quot;nv&quot;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;aarch64-linux- &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1 &lt;span class=&quot;nv&quot;&gt;SUBDIRS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; modules
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you prefer using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; instead, it can be found in section &lt;a href=&quot;#makefile&quot;&gt;Appendix: Scripts: Makefile&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If everything goes well, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111.ko&lt;/code&gt; should be generated in the working directory. You can also get the
pre-compiled one in section &lt;a href=&quot;#pre-compiled-drivers&quot;&gt;Appendix: Pre-compiled Binaries: Pre-compiled Drivers&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;installation--performance-tuning&quot;&gt;Installation &amp;amp; Performance Tuning&lt;/h3&gt;

&lt;p&gt;First upload &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111.ko&lt;/code&gt; into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/drivers/&lt;/code&gt;. Remember to create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drivers&lt;/code&gt; folder under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs&lt;/code&gt; if not exist.&lt;/p&gt;

&lt;p&gt;The installation is a little bit different from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;. Instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ncm&lt;/code&gt;, we need to unload &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdc_ether&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Unload `rndis_host`, as it depends on `cdc_ether`&lt;/span&gt;
rmmod rndis_host
&lt;span class=&quot;c&quot;&gt;# Unload `cdc_ether`&lt;/span&gt;
rmmod cdc_ether
&lt;span class=&quot;c&quot;&gt;# Load `aqc111.ko`&lt;/span&gt;
insmod /jffs/drivers/aqc111.ko
&lt;span class=&quot;c&quot;&gt;# Load `cdc_ether` back&lt;/span&gt;
insmod cdc_ether
&lt;span class=&quot;c&quot;&gt;# Load `rndis_host` back&lt;/span&gt;
insmod rndis_host
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Tuning performance for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; is similar to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;. However you can’t adjust interrupt coalescing or ring buffer size,
since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111&lt;/code&gt; driver doesn’t support them. You can refer to section &lt;a href=&quot;#performance-tuning&quot;&gt;Performance Tuning&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Complete scripts for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; can be found in &lt;a href=&quot;#scripts-for-aqc111u&quot;&gt;Appendix: Scripts: Scripts for AQC111U&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Actually early this year, I’ve already started to try to bring 2.5GbE to AX88U. At that time, however, there was only
the original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156&lt;/code&gt; chip and I couldn’t make it reach the maximum performance in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; test.&lt;/p&gt;

&lt;p&gt;Finally several months later, Realtek fixed the problem and released the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt; revision. I’m so happy to see that
I finally got the next generation of network and made my router future-proof.&lt;/p&gt;

&lt;p&gt;Another good news is that QNAP recently announced an affordable ($100) 5-port 2.5GbE switch 
&lt;a href=&quot;https://www.qnap.com/en-us/product/qsw-1105-5t&quot;&gt;QNAP QSW-1105-5T&lt;/a&gt;&lt;sup id=&quot;fnref:qsw-1105-5t&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:qsw-1105-5t&quot; class=&quot;footnote&quot;&gt;10&lt;/a&gt;&lt;/sup&gt;, which is passive-cooled and small 
in size - pretty suitable for home networking.&lt;/p&gt;

&lt;p&gt;I hope you enjoy this post and upgrade your network to the next generation :)&lt;/p&gt;

&lt;h2 id=&quot;appendix-pre-compiled-binaries&quot;&gt;Appendix: Pre-compiled Binaries&lt;/h2&gt;

&lt;h3 id=&quot;pre-compiled-drivers&quot;&gt;Pre-compiled Drivers&lt;/h3&gt;

&lt;p&gt;Pre-compiled drivers for AX88U (store them into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/drivers/&lt;/code&gt;):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt; driver v2.13.0: &lt;a href=&quot;/assets/bin/posts/ax88u-nbase-t/drivers/r8152.ko&quot;&gt;r8152.ko&lt;/a&gt;. SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e3a9f7a868baae6756bde4665a45852fcd578bdd&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111&lt;/code&gt; driver v1.3.3.0: &lt;a href=&quot;/assets/bin/posts/ax88u-nbase-t/drivers/aqc111.ko&quot;&gt;aqc111.ko&lt;/a&gt;. SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;9dc4768154e065d19a274dcc33235a6b58fd9fb9&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;pre-compiled-tools&quot;&gt;Pre-compiled Tools&lt;/h3&gt;

&lt;p&gt;Pre-compiled tools for AX88U (store them into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/tools&lt;/code&gt;):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; 5.8: &lt;a href=&quot;/assets/bin/posts/ax88u-nbase-t/tools/ethtool&quot;&gt;ethtool&lt;/a&gt;. SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6936931589476b2001667c50a8f91d713be705fb&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iperf3&lt;/code&gt; 3.9: &lt;a href=&quot;/assets/bin/posts/ax88u-nbase-t/tools/iperf3&quot;&gt;iperf3&lt;/a&gt;. SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ec19717ecb56a5b5bbfeda3316cd7e712cb6bde0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;appendix-scripts&quot;&gt;Appendix: Scripts&lt;/h2&gt;

&lt;h3 id=&quot;makefile&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Here are the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;s for drivers targeting AX88U.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r8152&lt;/code&gt;: &lt;a href=&quot;/assets/code/posts/ax88u-nbase-t/r8152/Makefile&quot;&gt;r8152/Makefile&lt;/a&gt;. SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dc22346bdae40f5ea5bb2a0c193dc922fa3e4b60&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aqc111&lt;/code&gt;: &lt;a href=&quot;/assets/code/posts/ax88u-nbase-t/aqc111/Makefile&quot;&gt;acq111/Makefile&lt;/a&gt;. SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;37dfc73f2e4b6676e5dd712ad38b389f0140fb76&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;scripts-for-rtl8156b&quot;&gt;Scripts for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTL8156B&lt;/code&gt;&lt;/h3&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;jffsscriptsinit-start&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/init-start&lt;/code&gt;&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/001-init-start
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rtl8156&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;init-start: loading RTL8156 driver...&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# It's safe to `insmod` here, since `usbcore` has already been &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# installed before `init-start` was called. &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# init.c: sysinit() -&amp;gt; init_wl() -&amp;gt; &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#         init-broadcom.c: eval(&quot;insmod&quot;, &quot;usbcore&quot;);&lt;/span&gt;
insmod /jffs/drivers/r8152.ko

&lt;span class=&quot;c&quot;&gt;# Note `insmod r8152.ko` must be executed before `cdc_ncm` module &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# is loaded into kernel. Otherwise `cdc_ncm` will take control &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# of the USB 2.5GbE adapter.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# If `r8152.ko` can't be loaded before `cdc_ncm`, then you should &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# `rmmod cdc_ncm`,` insmod r8152.ko` and `insmod cdc_ncm`&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# (remember to rm/insmod modules depending on `cdc_ncm` first)&lt;/span&gt;

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rtl8156&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;init-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/001-init-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;jffsscriptsservices-start&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/services-start&lt;/code&gt;&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/001-services-start
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rtl8156&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: setting up eth8...&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Update nvram variables&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;br0_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get br0_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lan_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get lan_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;wired_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get wired_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Add eth8 into br0&lt;/span&gt;
brctl addif br0 eth8

&lt;span class=&quot;c&quot;&gt;# Set TX queue length to 2500 on eth8 and bring it up&lt;/span&gt;
ifconfig eth8 txqueuelen 2500 allmulti up

&lt;span class=&quot;c&quot;&gt;# Enable USB scatter/gather on eth8&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /sys/class/net/eth8/rtl_adv/sg_en

&lt;span class=&quot;c&quot;&gt;# Enable RPS (Receive Packet Steering) on eth8.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Since AX88U has four cores, we set it to 'f'&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;f &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /sys/class/net/eth8/queues/rx-0/rps_cpus

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rtl8156&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/001-services-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;scripts-for-aqc111u&quot;&gt;Scripts for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Though &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AQC111U&lt;/code&gt; works on AX88U, its maximum performance is unachievable.&lt;/p&gt;

&lt;p&gt;Read section &lt;a href=&quot;#what-about-5gbe&quot;&gt;What about 5GbE?&lt;/a&gt; for more details.&lt;/p&gt;

&lt;h4 class=&quot;no_toc&quot; id=&quot;jffsscriptsservices-start-1&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/services-start&lt;/code&gt;&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/001-services-start
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;aqc111&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: loading AQC111 driver...&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# No need to `rmmod cdc_ether` here, as `cdc_ncm` will be loaded &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# after `services-start` is called&lt;/span&gt;
insmod /jffs/drivers/aqc111.ko

&lt;span class=&quot;c&quot;&gt;# Note `insmod aqc111.ko` must be executed before `cdc_ether` &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# module is loaded into kernel. Otherwise `cdc_ether` will take &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# control of the USB 5GbE adapter.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# If `aqc111.ko` can't be loaded before `cdc_ether`, then you should &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# `rmmod cdc_ether`, `insmod aqc111.ko` and `insmod cdc_ether` &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# (remember to rm/insmod modules depending on cdc_ether first)&lt;/span&gt;
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;aqc111&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: AQC111 driver loaded&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Now we can setup the new interface&lt;/span&gt;
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;aqc111&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: setting up eth8...&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Update nvram variables&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;br0_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get br0_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lan_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get lan_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;
nvram &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;wired_ifnames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get wired_ifnames&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eth8&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Add eth8 into br0 and bring eth8 up&lt;/span&gt;
brctl addif br0 eth8
ifconfig eth8 allmulti up

&lt;span class=&quot;c&quot;&gt;# Enable RPS (Receive Packet Steering) on eth8.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Since AX88U has four cores, we set it to 'f'.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;f &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /sys/class/net/eth8/queues/rx-0/rps_cpus

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;aqc111&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/001-services-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:bcm49408&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Broadcom, &lt;em&gt;&lt;a href=&quot;https://www.broadcom.com/products/wireless/wireless-lan-infrastructure/bcm49408&quot;&gt;BCM49408: 64 bit Quad-Core ARM v8 compliant Processor for Enterprise Access Point Applications&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:bcm49408&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:rtl8156&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Realtek, &lt;em&gt;&lt;a href=&quot;https://www.realtek.com/en/press-room/news-releases/item/realtek-launches-world-s-first-single-chip-2-5g-ethernet-controller-for-multiple-applications-including-gaming-solution&quot;&gt;Realtek Launches World’s First Single-Chip 2.5G Ethernet Controller for Multiple Applications, including Gaming Solution&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:rtl8156&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:rtl8156-issue&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;domih, &lt;em&gt;&lt;a href=&quot;https://forum.odroid.com/viewtopic.php?t=38713&quot;&gt;[HOWTO] 2.5Gbe or 5Gbe with H2 and/or N2 and/or C4?&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:rtl8156-issue&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:vl160&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;VIA Labs, Inc., &lt;em&gt;&lt;a href=&quot;https://www.via-labs.com/product_show.php?id=72&quot;&gt;VL160 - USB-C™ 2:4 Data Switch with CC Function for USB 3.1&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:vl160&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:upstream-no-rtl8156&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Kai-Heng Feng, &lt;em&gt;&lt;a href=&quot;https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1832472/comments/39&quot;&gt;Comment 39 for bug 1832472: cdc_ncm floods syslog unneccessarily&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:upstream-no-rtl8156&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:merlin-build&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;RMerl and Adamm, &lt;em&gt;&lt;a href=&quot;https://github.com/RMerl/asuswrt-merlin.ng/blob/master/tools/build-all#L203&quot;&gt;asuswrt-merlin.ng/build-all at master · RMerl/asuswrt-merlin.ng&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:merlin-build&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:marvell-acquire&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Marvell, &lt;em&gt;&lt;a href=&quot;https://www.marvell.com/company/newsroom/marvell-to-acquire-aquantia-accelerating-ethernet-technology-leadership.html&quot;&gt;Marvell to Acquire Aquantia - Accelerating Ethernet Technology Leadership&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:marvell-acquire&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:usb-overhead&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Andrew Ku, &lt;em&gt;&lt;a href=&quot;https://www.tomshardware.com/reviews/usb-3-uas-turbo,3215-2.html&quot;&gt;So, What Makes USB 3.0 Slower Than We Expect? - Faster USB 3.0 Performance: Examining UASP And Turbo Mode&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:usb-overhead&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:ethernet-overhead&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Rickard Nobel, &lt;em&gt;&lt;a href=&quot;http://rickardnobel.se/actual-throughput-on-gigabit-ethernet/&quot;&gt;Actual throughput on Gigabit Ethernet&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:ethernet-overhead&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:qsw-1105-5t&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Ryan Smith, &lt;em&gt;&lt;a href=&quot;https://www.anandtech.com/show/15916/at-last-a-25gbps-consumer-network-switch-qnap-releases-qsw11055t-5port-switch&quot;&gt;At Last, a 2.5Gbps Consumer Network Switch: QNAP Releases QSW-1105-5T 5-Port Switch&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:qsw-1105-5t&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</content><author><name>Renjie Wu</name></author><category term="Network" /><summary type="html">The lack of integrated 2.5GbE port makes ASUS RT-AX88U less powerful in my mind, especially when taking its processor `BCM49408`, which natively supports 2.5GbE, into account. The game however has changed, after I managed to finally reveal the full potential of AX88U with Realtek's USB-based 2.5GbE solution: `RTL8156B`.</summary></entry><entry xml:lang="en-us"><title type="html">Parse MATLAB classification tree and Generate corresponding JSON</title><link href="https://wu.renjie.im/blog/programming/parse-matlab-ctree/" rel="alternate" type="text/html" title="Parse MATLAB classification tree and Generate corresponding JSON" /><published>2020-09-16T23:17:39-07:00</published><updated>2022-06-30T08:06:22-07:00</updated><id>https://wu.renjie.im/blog/programming/parse-matlab-ctree</id><content type="html" xml:base="https://wu.renjie.im/blog/programming/parse-matlab-ctree/">&lt;p&gt;MATLAB Classification Learner is a powerful tool for building and testing classification model. 
However, the generated classification tree is not very user-friendly to use outside of MATLAB.&lt;/p&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Don’t care about details? Here is the final tool: &lt;a href=&quot;/tools/matlab-ctree-parser/&quot;&gt;MATLAB Classification Tree Parser&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; After I finished everything (the tool and this post), I somehow found that recently a MathWorks staff 
&lt;a href=&quot;https://www.mathworks.com/matlabcentral/fileexchange/68869-export-machine-learning-models-to-pmml&quot;&gt;released a helper in File Exchange&lt;/a&gt; 
to export MATLAB models to PMML. What can I say? ¯\_(ツ)_/¯.&lt;/p&gt;

&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;

&lt;p&gt;An example output&lt;sup id=&quot;fnref:matlab-view-ctree&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:matlab-view-ctree&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; (i.e. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;view(ctree)&lt;/code&gt;) of MATLAB classification tree looks like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Decision tree for classification
1  if x3&amp;lt;2.45 then node 2 elseif x3&amp;gt;=2.45 then node 3 else setosa
2  class = setosa
3  if x4&amp;lt;1.75 then node 4 elseif x4&amp;gt;=1.75 then node 5 else versicolor
4  if x3&amp;lt;4.95 then node 6 elseif x3&amp;gt;=4.95 then node 7 else versicolor
5  class = virginica
6  if x4&amp;lt;1.65 then node 8 elseif x4&amp;gt;=1.65 then node 9 else versicolor
7  class = virginica
8  class = versicolor
9  class = virginica
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is quite difficult to use in other environments. Say if I want to make a classifier in C++, I need to convert
the above tree output into C++ code by hand, which is a very tedious work and prone to error especially when the tree is dense.&lt;/p&gt;

&lt;p&gt;Though MATLAB allows you to visually inspect tree in GUI via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;view(ctree, 'mode', 'graph')&lt;/code&gt;, it is still annoying to convert it manually.&lt;/p&gt;

&lt;p&gt;Also in one of my projects, I’ve implemented a decision tree classifier in C++ and it allows me to dynamically 
load decision trees from JSON files. Since these trees have to be updated periodically, I have to manually write
the JSON frequently for more than a year. It would definitely be nice if I can make a tool to automatically 
generate those JSON files.&lt;/p&gt;

&lt;p&gt;In the beginning, I looked into MATLAB toolbox’s source code but found nothing useful about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;view&lt;/code&gt; method in either
class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClassificationTree&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompactClassificationTree&lt;/code&gt;. Thus I need to “decipher” the output by myself.&lt;/p&gt;

&lt;p&gt;Though it is possible to parse the tree output with regular expressions, I’d prefer to solve it in a similar way of
building compilers. Because we’re dealing with a tree, and a parser in compiler also build a &lt;em&gt;tree&lt;/em&gt; (AST, or Abstract Syntax Tree).&lt;/p&gt;

&lt;h2 id=&quot;define-the-grammar&quot;&gt;Define the Grammar&lt;/h2&gt;

&lt;p&gt;I wrote the grammar in &lt;a href=&quot;https://www.antlr.org/&quot;&gt;ANTLR 4&lt;/a&gt;. ANTLR can also generates lexer and parser
for my later building the tool.&lt;/p&gt;

&lt;p&gt;Here is the context-free grammar for MATLAB classification tree:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-g4&quot; data-lang=&quot;g4&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;// MatlabCTree.g4
grammar MatlabCTree;

start           : 'Decision tree for classification'? stmtList;

stmtList        : stmt | stmtList stmt;
stmt            : INTEGER (ifStmt | classExpr);

ifStmt          : ifClause elseifClause? elseClause?;
ifClause        : 'if' condExpr 'then' nodeExpr;
elseifClause    : 'elseif' condExpr 'then' nodeExpr;
elseClause      : 'else' nodeExpr;

labelExpr       : INTEGER | IDENTIFIER;
classExpr       : 'class' '=' labelExpr;
nodeExpr        : 'node' INTEGER | labelExpr;

constExpr       : INTEGER | RATIONAL;
condExpr        : IDENTIFIER '&amp;lt;'  constExpr
                | IDENTIFIER '&amp;gt;'  constExpr
                | IDENTIFIER '&amp;lt;=' constExpr
                | IDENTIFIER '&amp;gt;=' constExpr
                | IDENTIFIER '==' constExpr
                | IDENTIFIER '~=' constExpr;

INTEGER         : '0' | [1-9] [0-9]*;
IDENTIFIER      : [a-zA-Z] [a-zA-Z0-9_]*;

// Adapted from https://git.io/JU4M9
RATIONAL        : NUMBER (E SIGN? NUMBER)?;
fragment NUMBER : INTEGER? '.' [0-9]+;
fragment E      : 'E' | 'e';
fragment SIGN   : '+' | '-';

WHITESPACE      : [ \t\r\n]+ -&amp;gt; skip;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Some key points in the above grammar:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Line 4:&lt;/strong&gt; The prefix &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Decision tree for classification&lt;/code&gt; is optional.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Line 7:&lt;/strong&gt; The following lines are either a branch or a leaf starting with a node number.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Line 9:&lt;/strong&gt; At least from MATLAB’s example&lt;sup id=&quot;fnref:matlab-view-ctree:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:matlab-view-ctree&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; and my own experience, the output of tree branch has
a fixed pattern of&lt;br /&gt;
    &lt;div class=&quot;language-matlab highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;elseif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;some_label&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;However I’m not sure if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;elseif&lt;/code&gt; clause and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;else&lt;/code&gt; clause would be present in all scenarios. So I decided to leave
them as optional.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Line 14:&lt;/strong&gt; Depending on how Learner is configured, the label could be either a string (MATLAB’s example) or an integer
(my case).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Line 19-24:&lt;/strong&gt; Only 6 operators are supported: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;=&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;=&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;==&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~=&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Line 26:&lt;/strong&gt; Preceding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;s are not allowed in integers.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Line 27:&lt;/strong&gt; This follows the variable naming convention in MATLAB.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we have the grammar, we can test MATLAB’s example classification with ANTLR’s built-in GUI tester (click the figure to enlarge):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/parse-matlab-ctree/antlr4_parse_tree.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/parse-matlab-ctree/antlr4_parse_tree.png&quot; alt=&quot;ANTLR parsing tree for MATLAB's example classification tree&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above parsing tree looks like just what I want! It’s time to build the tool.&lt;/p&gt;

&lt;h2 id=&quot;build-the-tool&quot;&gt;Build the Tool&lt;/h2&gt;

&lt;p&gt;Initially I was thinking to build a tool in Java or C#, but later I realized why not make a web-based tool as ANTLR 
supports outputting lexers and parsers in JavaScript. A online tool also makes everyone’s life easier: no need to worry 
in setting up environments and doing (potentially annoying) compiling job.&lt;/p&gt;

&lt;p&gt;Also this tool will purely run in the browser, that is 100% of the code running on user’s device, there is no
need to set up a server nor any interaction with remote server at all.&lt;/p&gt;

&lt;p&gt;If you’re not familiar with using ANTLR on JavaScript target, here is &lt;a href=&quot;https://github.com/antlr/antlr4/blob/master/doc/javascript-target.md&quot;&gt;the official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I used the below command to generate lexer and parser. Note that I’ll use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;visitor&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listener&lt;/code&gt; in the final product.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;java &lt;span class=&quot;nt&quot;&gt;-jar&lt;/span&gt; antlr-4.8-complete.jar &lt;span class=&quot;nt&quot;&gt;-Dlanguage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;JavaScript &lt;span class=&quot;nt&quot;&gt;-visitor&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-no-listener&lt;/span&gt; MatlabCTree.g4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note:&lt;/strong&gt; I’ll only cover the main points in the following sections. If you want to dive into details, source code is 
available in section &lt;a href=&quot;#source-code&quot;&gt;Source code&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;traverse-ast-abstract-syntax-tree&quot;&gt;Traverse AST (Abstract Syntax Tree)&lt;/h3&gt;

&lt;p&gt;This part is pretty straightforward, just traverse the generated AST and store all classification tree nodes into an array.&lt;/p&gt;

&lt;p&gt;Since it’s possible that node numbers are not in a increasing order, for example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Decision tree for classification
1  if x&amp;lt;0 then node 2 elseif x&amp;gt;=0 then node 3 else foo
3  class = foo
2  class = bar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the above order is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2&lt;/code&gt; while we expect &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In order to detect this, we need to setup a counter, increase the counter every time we visit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stmt&lt;/code&gt; and 
check if the node number matches the counter:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;visitStmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// stmt: INTEGER (ifStmt | classExpr);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;nodeNumber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Check if the counter matches node number in stmt&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nodeNumber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;nodeNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;symbol&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`mismatched node number &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nodeNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; `&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;`expecting &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nodeNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visitChildren&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jsonNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Actually it doesn't matter whether result is returned&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because the generated tree from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fitctree&lt;/code&gt; is a binary tree&lt;sup id=&quot;fnref:fitctree&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:fitctree&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, we just need to check if the conditions in 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;elseif&lt;/code&gt; clauses are complement. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;else&lt;/code&gt; clause can be safely ignored.&lt;/p&gt;

&lt;p&gt;Here are the examples that conditions are not complement:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Feature name doesn't match (x and y)
1  if x&amp;lt;0.5 then node 2 elseif y&amp;gt;=0.5 then node 3 else foo

# Comparison value doesn't match (0.5 and -0.5)
1  if x&amp;lt;0.5 then node 2 elseif x&amp;gt;=-0.5 then node 3 else foo

# Operators are not complement (&amp;lt; and &amp;gt;, which supposed to be &amp;lt; and &amp;gt;=)
1  if x&amp;lt;0.5 then node 2 elseif x&amp;gt;0.5 then node 3 else foo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To handle this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;visitIfStmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// ifStmt: ifClause elseifClause? elseClause?;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visitChildren&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;featureName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;identifer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;compareValue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;trueBranch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;falseBranch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// 2 or more clauses?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// elseifClause&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elseifFN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;identifer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elseifOP&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elseifCV&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;// Does conditions match?&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;elseifFN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;featureName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;elseifOP&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;complementOperators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;elseifCV&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;compareValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elseIfExpr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elseIfExpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`mismatched elseif clause '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;elseIfExpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;' `&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;`expecting '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;featureName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; 
            &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;complementOperators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; 
            &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;compareValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;'`&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;falseBranch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// elseClause&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;falseBranch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// We ignored the elseClause here if there are 3 clauses present.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// This should be safe since the generated classification tree from&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// MATLAB's fitctree function is supposed to be a binary tree.&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;featureName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;compareValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;trueBranch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;falseBranch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;generate-json&quot;&gt;Generate JSON&lt;/h3&gt;

&lt;p&gt;The output JSON follows the below format:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
    &quot;featureName&quot;: &quot;{feature name}&quot;,
    &quot;operator&quot;: &quot;{operator for comparison}&quot;,
    &quot;compareValue&quot;: {the value to be compared (in double)},
    &quot;trueBranch&quot;: {true branch, if `fn op val` holds},
    &quot;falseBranch&quot;: {false branch, otherwise}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trueBranch&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;falseBranch&lt;/code&gt; are either a string representing the predicted label, or an above object indicating a child tree node.&lt;/p&gt;

&lt;p&gt;My classifier actually accepts a &lt;em&gt;compact&lt;/em&gt; version of it. The key names are simplified into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fn&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;op&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;val&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tb&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fb&lt;/code&gt; for saving spaces.&lt;/p&gt;

&lt;p&gt;Since we have already gathered all the nodes in the classification tree via AST visitor, we just need to perform a simple DFS (Depth-First Search):&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;dfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visitedNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;na&quot;&gt;featureName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;featureName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;compareValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;compareValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;trueBranch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visitBranch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trueBranch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;falseBranch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visitBranch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;falseBranch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Even though it is guaranteed to be a tree, it doesn’t prevent us to add support for forest:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Perform DFS on all nodes so we can also handle forests&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jsonNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Only take care not yet visited ifStmt nodes&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visitedNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;jsonOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We also need to handle a boundary condition where the tree consists of a label node only, for example:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Decision tree for classification
1  class = setosa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To handle this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jsonNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Boundary condition, the tree only has a label.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visitedNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;jsonOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;One more thing need to take care is branch target’s node number in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;elseif&lt;/code&gt;, since it might exceed the number of nodes. For example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Decision tree for classification
1  if x3&amp;lt;2.45 then node 2 elseif x3&amp;gt;=2.45 then node 3 else setosa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Apparently, node &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3&lt;/code&gt; are missing in the input. So we need to detect this and report error:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jsonNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`invalid node index &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; `&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;`expecting no greater than &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jsonNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;wrapper-class&quot;&gt;Wrapper class&lt;/h3&gt;

&lt;p&gt;Now we can make a wrapper class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MatlabCTreeConverter&lt;/code&gt; to call lexer and parser, 
and invoke AST visitor and JSON generator.&lt;/p&gt;

&lt;p&gt;Here is the way to handle syntax errors, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;syntaxErrors&lt;/code&gt; is for later error reporting:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;syntaxErrors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Adapted from https://stackoverflow.com/a/60841205&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeErrorListeners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addErrorListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;syntaxError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;recognizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;offendingSymbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;syntaxErrors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since our starting rule happened to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start&lt;/code&gt;, we can build AST by:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ast&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;webpack-everything&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack&lt;/code&gt; everything&lt;/h3&gt;

&lt;p&gt;Setting up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack&lt;/code&gt; is quite annoying and very painful. Fortunately, I found a working configuration file for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack&lt;/code&gt;&lt;sup id=&quot;fnref:webpack-basic-config&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:webpack-basic-config&quot; class=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. 
Hat tip to &lt;a href=&quot;https://github.com/nicolasdao&quot;&gt;@nicolasdao&lt;/a&gt;!&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note:&lt;/strong&gt; Since anyway the core code will be publicly accessible, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uglifyjs-webpack-plugin&lt;/code&gt; is not used.&lt;/p&gt;

&lt;p&gt;Once you got everything in &lt;a href=&quot;https://gist.github.com/nicolasdao/2e6cdb8a92b5584d90019a0224b1fddc&quot;&gt;that gist&lt;/a&gt; done, 
remember to add the following entry to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack.config.js&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;module.exports&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;net&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is &lt;strong&gt;VERY&lt;/strong&gt; important (noted in &lt;a href=&quot;https://github.com/antlr/antlr4/blob/master/doc/javascript-target.md#how-do-i-get-the-runtime-in-my-browser&quot;&gt;ANTLR’s official documentation&lt;/a&gt;),
otherwise ANTLR will try to import &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fs&lt;/code&gt; module which is not available in browsers.&lt;/p&gt;

&lt;h3 id=&quot;user-interface&quot;&gt;User Interface&lt;/h3&gt;

&lt;p&gt;Big &lt;em&gt;bruh&lt;/em&gt; moment. Needless to say how tedious is UI design and implementation. Anyway here is how it looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/parse-matlab-ctree/tool.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/parse-matlab-ctree/tool.png&quot; alt=&quot;Overview of MATLAB Classification Tree Parser&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If any error is detected in the input, it will report which line goes wrong:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/parse-matlab-ctree/tool-with-error.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/parse-matlab-ctree/tool-with-error.png&quot; alt=&quot;Error tooltip&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case you’re curious, I’m using &lt;a href=&quot;https://codemirror.net/&quot;&gt;CodeMirror&lt;/a&gt; for the input and output editors, 
and &lt;a href=&quot;http://viz-js.com/&quot;&gt;Viz.js&lt;/a&gt; for drawing the classification tree.&lt;/p&gt;

&lt;p&gt;Finally the link to the tool: &lt;a href=&quot;/tools/matlab-ctree-parser/&quot;&gt;MATLAB Classification Tree Parser&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;source-code&quot;&gt;Source Code&lt;/h2&gt;

&lt;p&gt;Grammar definition has been covered &lt;a href=&quot;#define-the-grammar&quot;&gt;here&lt;/a&gt;. Simply copy the code there and save it as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MatlabCTree.g4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Full JavaScript project for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack&lt;/code&gt;: &lt;a href=&quot;/assets/code/posts/parse-matlab-ctree/matlab-ctree-parser.zip&quot;&gt;matlab-ctree-parser.zip&lt;/a&gt;. SHA1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;212f9647d35ad83f67a01a4bc825d72ac2ad21df&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;script src=&quot;/assets/js/prism-g4.min.js&quot; data-manual=&quot;true&quot;&gt;&lt;/script&gt;

&lt;script&gt;Prism.highlightElement(document.querySelector(&quot;code[data-lang='g4'] td[class='code'] pre&quot;));&lt;/script&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:matlab-view-ctree&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;MathWorks Help Center, &lt;em&gt;&lt;a href=&quot;https://www.mathworks.com/help/stats/view-decision-tree.html&quot;&gt;View Decision Tree - MATLAB &amp;amp; Simulink&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:matlab-view-ctree&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt; &lt;a href=&quot;#fnref:matlab-view-ctree:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:fitctree&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;MathWorks Help Center, &lt;em&gt;&lt;a href=&quot;https://www.mathworks.com/help/stats/fitctree.html&quot;&gt;Fit binary decision tree for multiclass classification - MATLAB fitctree&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:fitctree&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:webpack-basic-config&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Nicolas Dao, &lt;em&gt;&lt;a href=&quot;https://gist.github.com/nicolasdao/2e6cdb8a92b5584d90019a0224b1fddc&quot;&gt;Basic damn Webpack config for simple transpilation ES6 to ES5&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:webpack-basic-config&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</content><author><name>Renjie Wu</name></author><category term="Programming" /><summary type="html">MATLAB Classification Learner is a powerful tool for building and testing classification model. However, the generated classification tree is not very user-friendly to use outside of MATLAB. This post introduces a context-free grammar for parsing MATLAB classification tree and a tool to generate the corresponding JSON file.</summary></entry><entry xml:lang="zh-cn"><title type="html">在 AX88U + Merlin 384.16 上实现 LAN 端口隔离（静态 VLAN）</title><link href="https://wu.renjie.im/blog/network/ax88u-vlan/zh-cn/" rel="alternate" type="text/html" title="在 AX88U + Merlin 384.16 上实现 LAN 端口隔离（静态 VLAN）" /><published>2020-04-30T22:08:50-07:00</published><updated>2021-06-23T15:39:53-07:00</updated><id>https://wu.renjie.im/blog/network/ax88u-vlan/ax88u-vlan</id><content type="html" xml:base="https://wu.renjie.im/blog/network/ax88u-vlan/zh-cn/">&lt;p&gt;最近把手头用了四年多的 &lt;a href=&quot;https://www.asus.com/us/Networking/RTAC68P/&quot;&gt;AC68P&lt;/a&gt; 升级成了支持 802.11ax (WiFi 6) 的 &lt;a href=&quot;https://www.asus.com/us/Networking/RT-AX88U/&quot;&gt;AX88U&lt;/a&gt;。不用多说，到手第一天就刷了 Merlin 梅林固件。&lt;/p&gt;

&lt;p&gt;不过无论是原厂固件还是梅林固件，它们都没有提供原生的 GUI 划分 VLAN 的功能（相比之下，在 OpenWrt 上配置 VLAN 就很方便）。但是由于博通搞的闭源驱动&lt;sup id=&quot;fnref:ax88u-openwrt&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:ax88u-openwrt&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;，OpenWrt 在有生之年大概都不会支持 AX88U。所以要在 AX88U 上配置 VLAN，只能通过命令行的方式。&lt;/p&gt;

&lt;h2 id=&quot;需求&quot;&gt;需求&lt;/h2&gt;

&lt;p&gt;AX88U 上一共有 8 个 LAN 口，我想把 LAN 2 隔离出来，用做访客网络。换句话说，LAN 1, 3 - 8 划入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 1&lt;/code&gt;, LAN 2 单独划入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 2&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;理论上，真正的隔离应该是禁止两个 VLAN 互相访问。但是考虑到万一需要在我的电脑（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 1&lt;/code&gt;）上重新配置二级路由器（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 2&lt;/code&gt;），还是得允许 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 1&lt;/code&gt; 到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 2&lt;/code&gt; 的单向通信。&lt;/p&gt;

&lt;p&gt;此外，上述提到的隔离对客户端应当是完全透明的：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 2&lt;/code&gt; 里的客户端不需要额外的配置，只需要插上网线即可上网。&lt;/p&gt;

&lt;h2 id=&quot;有关-ax88u&quot;&gt;有关 AX88U&lt;/h2&gt;

&lt;h3 id=&quot;没有-robocfg&quot;&gt;没有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;robocfg&lt;/code&gt;？&lt;/h3&gt;

&lt;p&gt;很不幸的是，AX88U（博通 HND 平台）移除了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;robocfg&lt;/code&gt; 命令。搜索了一番之后，发现似乎 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vlanctl&lt;/code&gt;&lt;sup id=&quot;fnref:vlanctl&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:vlanctl&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; 可以用来配置 VLAN。但是玩了一阵子，目测 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vlanctl&lt;/code&gt; 只能搞 Tagged VLAN，没法实现静态 VLAN。&lt;/p&gt;

&lt;p&gt;不过以防有人有这方面的需求，推荐阅读这篇文章：&lt;a href=&quot;https://www.cnblogs.com/u128393/p/11629969.html&quot;&gt;上海电信 TL-EP110 + RT-AC86U 实现观看 4K IPTV 无卡顿 (2019-10)&lt;/a&gt;。这篇文章介绍了如何在 AC86U（也是 HND 平台的路由器）上配置 Tagged VLAN。&lt;/p&gt;

&lt;h3 id=&quot;以太网接口到物理端口的映射&quot;&gt;以太网接口到物理端口的映射&lt;/h3&gt;

&lt;p&gt;在网上我没搜到相关的信息，不过经过若干次网线插拔之后，总结出来这张表：&lt;/p&gt;

&lt;table class=&quot;table-align-center&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;以太网接口&lt;/th&gt;
      &lt;th&gt;物理端口&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;eth0&lt;/td&gt;
      &lt;td&gt;WAN&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth1&lt;/td&gt;
      &lt;td&gt;LAN 4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth2&lt;/td&gt;
      &lt;td&gt;LAN 3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth3&lt;/td&gt;
      &lt;td&gt;LAN 2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth4&lt;/td&gt;
      &lt;td&gt;LAN 1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth5&lt;/td&gt;
      &lt;td&gt;LAN 5 - 8 的网桥&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth6&lt;/td&gt;
      &lt;td&gt;2.4 GHz 无线&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth7&lt;/td&gt;
      &lt;td&gt;5 GHz 无线&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;这里注意 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth5&lt;/code&gt; 应该是通过 BCM53134 组的硬件网桥（LAN 5 - 8）。使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;etchtl&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethswctl&lt;/code&gt; 或许能解散这个网桥，不过我没试验。所以，下文提到的解决方案只能用于隔离 LAN 1 - 4。&lt;/p&gt;

&lt;p&gt;此外，AX88U 默认把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth1&lt;/code&gt; ~ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth7&lt;/code&gt; 组成了网桥 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;。&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;注意：&lt;/strong&gt;我的 &lt;strong&gt;WAN 联机类型&lt;/strong&gt; 是 &lt;strong&gt;动态 IP&lt;/strong&gt;。如果你用的是 PPPoE 的话，可能需要看情况把下文提到的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth0&lt;/code&gt; 换成 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ppp0&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&quot;一条命令ebtables的解决方案&quot;&gt;一条命令（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ebtables&lt;/code&gt;）的解决方案&lt;/h2&gt;

&lt;p&gt;如果不需要给两个 VLAN 划分独立子网的话，只需要一条 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ebtables&lt;/code&gt; 命令就可以了：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 在 AX88U 上，eth3 是物理端口 LAN 2 &lt;/span&gt;
ebtables &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; eth3 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这里的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt; 是物理端口 LAN 2。这条命令使用了二层防火墙 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ebtables&lt;/code&gt;，用于阻隔 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 之间的通信。由于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt; 还在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 里，所以不需要额外配置 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables&lt;/code&gt; 或者 DHCP。&lt;/p&gt;

&lt;h2 id=&quot;基于网桥的解决方案&quot;&gt;基于网桥的解决方案&lt;/h2&gt;

&lt;p&gt;如果需要给两个 VLAN 划分独立的子网的话，就需要创建新的网桥了。下文以 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 1&lt;/code&gt; 使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.50.0/24&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 2&lt;/code&gt; 使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.150.0/24&lt;/code&gt; 为例。&lt;/p&gt;

&lt;h3 id=&quot;新建网桥-br1&quot;&gt;新建网桥 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;首先，从 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 里移除 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt;，创建 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 并把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt; 加入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 从 br0 中删除需要隔离的端口&lt;/span&gt;
brctl delif br0 eth3

&lt;span class=&quot;c&quot;&gt;# 把需要隔离的端口加入 br1&lt;/span&gt;
brctl addbr br1
brctl stp br1 on &lt;span class=&quot;c&quot;&gt;# 启用 STP 协议防止环路，避免网络风暴&lt;/span&gt;
brctl addif br1 eth3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这里新建网桥 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 而不是直接使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt; 是为了方便管理：如果以后想把其他端口也隔离进 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 2&lt;/code&gt;，只需要把对应的端口移出 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 并加入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 即可。由于下文提到的所有规则都是针对 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 的，所以新加入的端口不需要额外的设置。&lt;/p&gt;

&lt;p&gt;执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brctl show&lt;/code&gt; 验证 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 已正确创建：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# brctl show&lt;/span&gt;
bridge name     bridge id               STP enabled     interfaces
br0             8000.a85e45fakeid       yes             eth1
                                                        eth2
                                                        eth4
                                                        eth5
                                                        eth6
                                                        eth7
&lt;strong class=&quot;mi&quot;&gt;br1&lt;/strong&gt;             8000.a85e45fakeid       &lt;strong class=&quot;mi&quot;&gt;yes&lt;/strong&gt;             &lt;strong class=&quot;mi&quot;&gt;eth3&lt;/strong&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后，给 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 设置 IPv4 地址 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.150.1/24&lt;/code&gt;，并启用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 设置 br1 的 IPv4 地址并启用 br1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 这里使用的 IPv4 子网是 192.168.150.0/24&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 系统会自动设置 IPv6 链路本地地址&lt;/span&gt;
ifconfig br1 192.168.150.1 netmask 255.255.255.0
ifconfig br1 allmulti up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;由于 AX88U 默认给 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 分配了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.50.1/24&lt;/code&gt;，所以不需要设置 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;最后，执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifconfig br&lt;/code&gt; 验证 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 的 IPv4 地址：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# ifconfig br1&lt;/span&gt;
br1       Link encap:Ethernet  HWaddr A8:5E:45:00:FA:KE
          &lt;strong class=&quot;mi&quot;&gt;inet addr:192.168.150.1&lt;/strong&gt;  Bcast:192.168.150.255  &lt;strong class=&quot;mi&quot;&gt;Mask:255.255.255.0&lt;/strong&gt;
          inet6 addr: fe80::aa5e:45ff:fe00:fake/64 Scope:Link
          &lt;strong class=&quot;mi&quot;&gt;UP&lt;/strong&gt; BROADCAST RUNNING &lt;strong class=&quot;mi&quot;&gt;ALLMULTI&lt;/strong&gt; MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;系统会使用 &lt;a href=&quot;https://en.wikipedia.org/wiki/IPv6_address#Modified_EUI-64&quot;&gt;EUI-64&lt;/a&gt; 算法自动为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 生成 IPv6 链路本地地址。&lt;/p&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;提示：&lt;/strong&gt;完整的脚本可以在 &lt;a href=&quot;#services-start&quot;&gt;脚本与配置文件：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/services-start&lt;/code&gt;&lt;/a&gt; 中找到。&lt;/p&gt;

&lt;h3 id=&quot;添加-iptables-规则&quot;&gt;添加 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables&lt;/code&gt; 规则&lt;/h3&gt;

&lt;p&gt;首先，允许来自 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 的传入连接：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 允许来自 br1 的传入连接&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; NEW &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;但是禁止 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 访问路由器 Web UI 和 SSH：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 禁止 br1 访问路由器 Web UI 和 SSH&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 80 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 22 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后，不转发来自 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 的数据包：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 不转发来自 br1 的数据包&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;但是允许 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 内部的转发：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 但是允许 br1 内部的转发&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;也允许 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 的数据包转发至 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth0&lt;/code&gt; (WAN)：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 允许 br1 的数据包转发至 eth0 (WAN)&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; eth0 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;也允许 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 的单向通信：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 允许 br0 到 br1 的单向通信&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; RELATED,ESTABLISHED &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;最后，配置 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 所属子网 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.150.0/24&lt;/code&gt; 的 NAT：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;iptables &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; nat &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; POSTROUTING &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 192.168.150.0/24 &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; 192.168.150.0/24 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; MASQUERADE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;分别执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables -S INPUT&lt;/code&gt;，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables -S FORWARD&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables -t nat -S POSTROUTING&lt;/code&gt; 验证相应的规则已添加:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# iptables -S INPUT&lt;/span&gt;
-P INPUT ACCEPT
&lt;strong class=&quot;mi&quot;&gt;-A INPUT -i br1 -p tcp -m tcp --dport 22 -j DROP&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A INPUT -i br1 -p tcp -m tcp --dport 80 -j DROP&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A INPUT -i br1 -m state --state NEW -j ACCEPT&lt;/strong&gt;
&lt;span class=&quot;c&quot;&gt;# ... 省略多余输出 ...&lt;/span&gt;
-A INPUT -j DROP

&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# iptables -S FORWARD&lt;/span&gt;
-P FORWARD DROP
&lt;strong class=&quot;mi&quot;&gt;-A FORWARD -i br1 -o br0 -m state --state RELATED,ESTABLISHED -j ACCEPT&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A FORWARD -i br0 -o br1 -j ACCEPT&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A FORWARD -i br1 -o eth0 -j ACCEPT&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A FORWARD -i br1 -o br1 -j ACCEPT&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A FORWARD -i br1 -j DROP&lt;/strong&gt;
&lt;span class=&quot;c&quot;&gt;# ... 省略多余输出 ...&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# iptables -t nat -S POSTROUTING&lt;/span&gt;
-P POSTROUTING ACCEPT
&lt;span class=&quot;c&quot;&gt;# ... 省略多余输出 ...&lt;/span&gt;
-A POSTROUTING -s 192.168.50.0/24 -d 192.168.50.0/24 -o br0 -j MASQUERADE
&lt;strong class=&quot;mi&quot;&gt;-A POSTROUTING -s 192.168.150.0/24 -d 192.168.150.0/24 -o br1 -j MASQUERADE&lt;/strong&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;notice--info&quot;&gt;
&lt;p&gt;&lt;strong&gt;提示：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;完整防火墙配置脚本：&lt;a href=&quot;#firewall-start&quot;&gt;脚本与配置文件：/jffs/scripts/firewall-start&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;完整 NAT 配置脚本：&lt;a href=&quot;#nat-start&quot;&gt;脚本与配置文件：/jffs/scripts/nat-start&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;h3 id=&quot;配置-dhcpv4-dnsmasq&quot;&gt;配置 DHCPv4 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt;)&lt;/h3&gt;

&lt;p&gt;在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/configs/&lt;/code&gt; 中创建配置文件 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq.conf.add&lt;/code&gt;：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /jffs/configs/dnsmasq.conf.add
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;比照 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;，为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 设置 DHCPv4 的地址池和选项：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt; &amp;gt;&amp;gt; /jffs/configs/dnsmasq.conf.add
interface=br1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 地址池: 192.168.150.2 - 192.168.150.254, 子网掩码: 255.255.255.0
# DHCPv4 租约时间: 86400 秒 (1 天)&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;dhcp-range=br1,192.168.150.2,192.168.150.254,255.255.255.0,86400s&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 路由器 (option 3): 192.168.150.1&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;dhcp-option=br1,3,192.168.150.1&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;重启 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; 以应用设置：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;service restart_dnsmasq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tail /tmp/syslog.log -n 50&lt;/code&gt; 验证 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq.conf.add&lt;/code&gt; 已被正确加载：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# tail /tmp/syslog.log -n 50&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# ... 省略多余输出 ...&lt;/span&gt;
Apr 14 20:49:22 rc_service: service 15995:notify_rc restart_dnsmasq
Apr 14 20:49:22 dnsmasq[1149]: exiting on receipt of SIGTERM
&lt;strong class=&quot;mi&quot;&gt;Apr 14 20:49:22 custom_config: Appending content of /jffs/configs/dnsmasq.conf.add.&lt;/strong&gt;
Apr 14 20:49:22 dnsmasq[15998]: started, version 2.81rc4-33-g7558f2b cachesize 1500
Apr 14 20:49:22 dnsmasq[15998]: asynchronous logging enabled, queue limit is 5 messages
&lt;strong class=&quot;mi&quot;&gt;Apr 14 20:49:22 dnsmasq-dhcp[15998]: DHCP, IP range 192.168.150.2 -- 192.168.150.254, lease time 1d&lt;/strong&gt;
Apr 14 20:49:22 dnsmasq-dhcp[15998]: DHCP, IP range 192.168.50.2 -- 192.168.50.254, lease time 1d
&lt;span class=&quot;c&quot;&gt;# ... 省略多余输出 ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;配置-ipv6&quot;&gt;配置 IPv6&lt;/h2&gt;

&lt;p&gt;本文使用的是无状态 DHCPv6 (DHCPv6 stateless)，主机的 IPv6 地址是通过 SLAAC&lt;sup id=&quot;fnref:slaac&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:slaac&quot; class=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; 自动生成的。&lt;/p&gt;

&lt;p&gt;由于 SLAAC 使用了 EUI-64 算法，这要求 IPv6 前缀长度必须小于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt;。所以要使用下文提到的解决方案，ISP 分配的 IPv6 LAN 前缀长度&lt;strong&gt;必须&lt;/strong&gt;小于等于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/63&lt;/code&gt;。&lt;/p&gt;

&lt;h3 id=&quot;通过前缀提示-prefix-hint-获取更短的前缀&quot;&gt;通过前缀提示 (Prefix Hint) 获取更短的前缀&lt;/h3&gt;

&lt;p&gt;某些 ISP 允许通过发送&lt;a href=&quot;https://tools.ietf.org/html/rfc3633#page-5&quot;&gt;前缀长度提示&lt;/a&gt;获取小于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; 的前缀。例如，我这里的 ISP Charter Spectrum 就允许通过前缀提示获取 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/56&lt;/code&gt; 的前缀。&lt;/p&gt;

&lt;p&gt;我的 AX88U 上 IPv6 的设置是：&lt;/p&gt;

&lt;table class=&quot;table-align-center&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;名称&lt;/th&gt;
      &lt;th&gt;值&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;基本设置&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;联机类型&lt;/td&gt;
      &lt;td&gt;Native&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;DHCP-PD&lt;/td&gt;
      &lt;td&gt;启用&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;IPv6 内部网络设置&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;自动配置设置&lt;/td&gt;
      &lt;td&gt;Stateless&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;IPv6 DNS 设置&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;自动接上 DNS 服务器&lt;/td&gt;
      &lt;td&gt;关闭&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;IPv6 DNS 服务器 1&lt;/td&gt;
      &lt;td&gt;2606:4700:4700::1111&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;IPv6 DNS 服务器 2&lt;/td&gt;
      &lt;td&gt;2606:4700:4700::1001&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;IPv6 DNS 服务器 3&lt;/td&gt;
      &lt;td&gt;&lt;em&gt;留空&lt;/em&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;自动配置设置&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;是否启动路由广播&lt;/td&gt;
      &lt;td&gt;启用&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;AX88U 上的 DHCPv6 客户端 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;odhcp6c&lt;/code&gt; 默认不会发送前缀提示。要强制 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;odhcp6c&lt;/code&gt; 发送前缀提示&lt;sup id=&quot;fnref:prefix-hint&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:prefix-hint&quot; class=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;，首先执行：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ps | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'s/^.*\odhcp6c \(.*\)$/\1/;t;d'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;获取系统运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;odhcp6c&lt;/code&gt; 的命令：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;-df -R -s /tmp/dhcp6c -N try &lt;strong class=&quot;mi&quot;&gt;-c &amp;lt;duid&amp;gt; -FP 0:&amp;lt;iaid&amp;gt;&lt;/strong&gt; eth0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;duid&amp;gt;&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;iaid&amp;gt;&lt;/code&gt; 与路由器的 MAC 地址有关。取决于 IPv6 设置，可能还有类似 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-r23&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-r24&lt;/code&gt; 的参数，在下面的命令里也要加上这些参数。&lt;/p&gt;

&lt;p&gt;对应替换 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;duid&amp;gt;&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;iaid&amp;gt;&lt;/code&gt;，执行下面的两条命令：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 结束现有的 odhcp6c&lt;/span&gt;
killall odhcp6c
&lt;span class=&quot;c&quot;&gt;# 重新运行 odhcp6c，前缀提示长度为 56&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 对应替换 -c 和 -FP 的参数 &amp;lt;duid&amp;gt; 和 &amp;lt;iaid&amp;gt;&lt;/span&gt;
odhcp6c -df &lt;strong class=&quot;mi&quot;&gt;-P56&lt;/strong&gt; -R -s /tmp/dhcp6c -N try &lt;strong class=&quot;mi&quot;&gt;-c &amp;lt;duid&amp;gt; -FP 0:&amp;lt;iaid&amp;gt;&lt;/strong&gt; eth0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这里 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-P56&lt;/code&gt; 中的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;56&lt;/code&gt; 即是要发送的前缀提示长度。&lt;/p&gt;

&lt;p&gt;执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifconfig br0&lt;/code&gt; 验证 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 已被分配到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/56&lt;/code&gt; 的 IPv6 全局地址：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# ifconfig br0&lt;/span&gt;
br0       Link encap:Ethernet  HWaddr A8:5E:45:00:FA:KE
          inet addr:192.168.50.1  Bcast:192.168.50.255  Mask:255.255.255.0
          inet6 addr: 2600:6c51:fake:n00b::1&lt;strong class=&quot;mi&quot;&gt;/56&lt;/strong&gt; Scope:&lt;strong class=&quot;mi&quot;&gt;Global&lt;/strong&gt;
          inet6 addr: fe80::aa5e:45ff:fe00:fake/64 Scope:Link
          UP BROADCAST RUNNING ALLMULTI MULTICAST  MTU:1500  Metric:1
          RX packets:4241 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3714 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:829133 (809.7 KiB)  TX bytes:1787334 (1.7 MiB)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果没看到类似的输出，那下文的解决方案并不适合你，但你可以在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 上设置有状态 DHCPv6 (DHCPv6 stateful)。&lt;/p&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;提示：&lt;/strong&gt;完整的脚本可以在 &lt;a href=&quot;#wan-event&quot;&gt;脚本与配置文件：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/wan-event&lt;/code&gt;&lt;/a&gt; 中找到。&lt;/p&gt;

&lt;h3 id=&quot;添加-ip6tables-规则&quot;&gt;添加 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip6tables&lt;/code&gt; 规则&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip6tables&lt;/code&gt; 的规则类似上文 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables&lt;/code&gt; 的规则，但是不需要设置 NAT。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INPUT&lt;/code&gt; 链：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 允许来自 br1 的传入连接&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT &lt;span class=&quot;c&quot;&gt;# br0 的默认规则&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; NEW &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# 禁止 br1 访问路由器 Web UI 和 SSH&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 80 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 22 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FORWARD&lt;/code&gt; 链：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 不转发来自 br1 的数据包&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP

&lt;span class=&quot;c&quot;&gt;# 但是允许 br1 内部的转发&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# 也允许 `br1` 的数据包转发至 `eth0` (WAN)&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; eth0 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# 也允许 `br0` 到 `br1` 的单向通信&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; RELATED,ESTABLISHED &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;提示：&lt;/strong&gt;完整的脚本可以在 &lt;a href=&quot;#firewall-start&quot;&gt;脚本与配置文件：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/firewall-start&lt;/code&gt;&lt;/a&gt; 中找到。&lt;/p&gt;

&lt;h3 id=&quot;配置-dhcpv6&quot;&gt;配置 DHCPv6&lt;/h3&gt;

&lt;p&gt;默认情况下，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 会使用整个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/56&lt;/code&gt; 的子网。如果要为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 划分子网，则需要改变 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 的前缀长度。&lt;/p&gt;

&lt;p&gt;首先，执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip -6 addr show br0 scope global&lt;/code&gt; 获取 ISP 分配的 IPv6 LAN 前缀：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# ip -6 addr show br0 scope global&lt;/span&gt;
22: br0: &amp;lt;BROADCAST,MULTICAST,ALLMULTI,UP,LOWER_UP&amp;gt; mtu 1500
    inet6 &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n00b::1/56&lt;/strong&gt; scope global
       valid_lft forever preferred_lft forever
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;你拿到的前缀&lt;strong&gt;肯定&lt;/strong&gt;跟这里的是不一样的，所以执行下面的命令时别忘了对应替换。&lt;/p&gt;

&lt;p&gt;然后，为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 重新设置 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; 的前缀长度：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 删除 /56 前缀，把 2600:6c51:fake:n00b::1 换成你的&lt;/span&gt;
ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr del 2600:6c51:fake:n00b::1/56 dev br0
&lt;span class=&quot;c&quot;&gt;# 设置 /64 前缀，把 2600:6c51:fake:n00b::1 换成你的&lt;/span&gt;
ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add 2600:6c51:fake:n00b::1/64 dev br0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;当然这里可以为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 设置更短的前缀长度，但是我觉得 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; 已经够用了。&lt;/p&gt;

&lt;p&gt;再次执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip -6 addr show br0 scope global&lt;/code&gt;，检查 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 的新前缀：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# ip -6 addr show br0 scope global&lt;/span&gt;
22: br0: &amp;lt;BROADCAST,MULTICAST,ALLMULTI,UP,LOWER_UP&amp;gt; mtu 1500
    inet6 &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n00b::1/64&lt;/strong&gt; scope global
       valid_lft forever preferred_lft forever
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;由于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; 并不支持 DHCPv6 前缀代理（DHCPv6 Prefix Delegation, DHCPv6-PD）&lt;sup id=&quot;fnref:dnsmasq-author&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:dnsmasq-author&quot; class=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; &lt;sup id=&quot;fnref:dhcp6-protocol&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:dhcp6-protocol&quot; class=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt; 所需的 option 25 和 26 &lt;sup id=&quot;fnref:rfc-3633&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:rfc-3633&quot; class=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;，下面分两种情况讨论。&lt;/p&gt;

&lt;h4 id=&quot;不使用-dhcpv6-pd&quot;&gt;不使用 DHCPv6-PD&lt;/h4&gt;

&lt;p&gt;如果不接二级路由器的话，倒是可以用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; 当 DHCPv6 服务器。&lt;/p&gt;

&lt;p&gt;首先，为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 设置 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 的邻接 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; 前缀：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 为 br1 设置 br0 的邻接 /64 前缀&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 比如 br0 的前缀为 aaaa:bbbb:cccc:dddd::1/64,&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 则 br1 的前缀为 aaaa:bbbb:cccc:ddde::1/64.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 把 2600:6c51:fake:n00c::1 换成你的&lt;/span&gt;
ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add 2600:6c51:fake:n00c::1/64 dev br1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后，为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 设置 DHCPv6 地址池和选项：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt; &amp;gt;&amp;gt; /jffs/configs/dnsmasq.conf.add&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 路由广播间隔：10 秒, 路由器生命周期：600 秒&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;ra-param=br1,10,600&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 地址池：通过 br1 的前缀构造
# DHCPv6 前缀长度：64, 模式：无状态 DHCPv6
# DHCPv6 租约时间：600 秒 (10 分钟)&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;dhcp-range=br1,::,constructor:br1,ra-stateless,64,600&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 DNS (option 23)：从路由器继承&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;dhcp-option=br1,option6:23,[::]&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;重启 dnsmasq 以应用设置：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;service restart_dnsmasq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;执行 tail /tmp/syslog.log -n 50 验证 dnsmasq.conf.add 已被正确加载：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# tail /tmp/syslog.log -n 50&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# ... 省略多余输出 ...&lt;/span&gt;
Apr 14 20:49:22 rc_service: service 15995:notify_rc restart_dnsmasq
Apr 14 20:49:22 dnsmasq[1149]: exiting on receipt of SIGTERM
&lt;strong class=&quot;mi&quot;&gt;Apr 14 20:49:22 custom_config: Appending content of /jffs/configs/dnsmasq.conf.add.&lt;/strong&gt;
Apr 14 20:49:22 dnsmasq[15998]: started, version 2.81rc4-33-g7558f2b cachesize 1500
Apr 14 20:49:22 dnsmasq[15998]: asynchronous logging enabled, queue limit is 5 messages
Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCP, IP range 192.168.150.2 -- 192.168.150.254, lease time 1d
Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCP, IP range 192.168.50.2 -- 192.168.50.254, lease time 1d
Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCPv6 stateless on br0
Apr 15 18:09:01 dnsmasq-dhcp[18800]: router advertisement on br0
&lt;strong class=&quot;mi&quot;&gt;Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCPv6 stateless on 2600:6c51:fake:n00b::, constructed for br0&lt;/strong&gt;
Apr 15 18:09:01 dnsmasq-dhcp[18800]: router advertisement on 2600:6c51:fake:n00b::, constructed for br0
Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCPv6 stateless on br1
Apr 15 18:09:01 dnsmasq-dhcp[18800]: router advertisement on br1
&lt;strong class=&quot;mi&quot;&gt;Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCPv6 stateless on 2600:6c51:fake:n00b::, constructed for br1&lt;/strong&gt;
Apr 15 18:09:01 dnsmasq-dhcp[18800]: router advertisement on 2600:6c51:fake:n00c::, constructed for br1
Apr 15 18:09:01 dnsmasq-dhcp[18800]: IPv6 router advertisement enabled
&lt;span class=&quot;c&quot;&gt;# ... 省略多余输出 ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;使用-dhcpv6-pd&quot;&gt;使用 DHCPv6-PD&lt;/h4&gt;

&lt;p&gt;如果需要在二级路由器上启用 DHCPv6-PD，则应该使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6relayd&lt;/code&gt; 作为 DHCPv6-PD 服务器。&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;注意：&lt;/strong&gt;如果使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6relayd&lt;/code&gt;，不要在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/configs/dnsmasq.conf.add&lt;/code&gt; 中添加 DHCPv6 相关的设置。&lt;/p&gt;

&lt;p&gt;在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6relayd&lt;/code&gt;&lt;sup id=&quot;fnref:6relayd&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:6relayd&quot; class=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt; 的服务器模式下，它会通过 DHCPv6-PD 把第二个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; 前缀分配给二级路由器。所以，只需要为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; 分配一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/63&lt;/code&gt; 的前缀。&lt;/p&gt;

&lt;p&gt;这里使用的是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; 的邻接 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/63&lt;/code&gt; 前缀：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 为 br1 设置 br0 的邻接 /63 前缀&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 把 2600:6c51:fake:n00c::1 换成你的&lt;/span&gt;
ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add 2600:6c51:fake:n00c::1/63 dev br1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后，执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6relayd -v -d -S . br1&lt;/code&gt; 启动 DHCPv6-PD 服务器：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 监听于 br1 上的 DHCPv6-PD 服务器&lt;/span&gt;
6relayd &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; br1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果收到 DHCPv6 请求的话，系统日志 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat /tmp/syslog.log | grep 6relayd&lt;/code&gt;) 应该显示：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# admin@ax88u:/# cat /tmp/syslog.log | grep 6relayd&lt;/span&gt;
Apr 15 18:20:00 6relayd[1765]: Got DHCPv6 request
Apr 15 18:20:01 6relayd[1765]: Got DHCPv6 request
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;最后，在二级路由器上检查 IPv6 设置（&lt;em&gt;系统记录&lt;/em&gt; -&amp;gt; &lt;em&gt;IPv6&lt;/em&gt;）：&lt;/p&gt;

&lt;table class=&quot;table-align-center&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;IPv6 Connection Type&lt;/th&gt;
      &lt;th&gt;Native with DHCP-PD&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;WAN IPv6 Address&lt;/td&gt;
      &lt;td&gt;2600:6c51:fake:n00c::fake&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;WAN IPv6 Gateway&lt;/td&gt;
      &lt;td&gt;fe80::aa5e:45ff:fe00:fake&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;LAN IPv6 Address&lt;/td&gt;
      &lt;td&gt;2600:6c51:fake:n00d::1/64&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;LAN IPv6 Link-Local Address&lt;/td&gt;
      &lt;td&gt;fe80::a62:66ff:fe01:fake/64&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;DHCP-PD&lt;/td&gt;
      &lt;td&gt;Enabled&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;LAN IPv6 Prefix&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;2600:6c51:fake:n00d::/64&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;DNS Address&lt;/td&gt;
      &lt;td&gt;2600:6c51:fake:n00c::1&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;如果一切正常，&lt;em&gt;LAN IPv6 Prefix&lt;/em&gt; 应该显示 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2600:6c51:fake:n00d::/64&lt;/code&gt;。&lt;/p&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;提示：&lt;/strong&gt; 自动配置 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6relayd&lt;/code&gt; 的脚本可以在 &lt;a href=&quot;#dhcpc-event&quot;&gt;脚本与配置文件：/jffs/scripts/dhcpc-event&lt;/a&gt; 中找到。&lt;/p&gt;

&lt;h2 id=&quot;脚本与配置文件&quot;&gt;脚本与配置文件&lt;/h2&gt;

&lt;p&gt;把下文中的脚本与配置文件上传到路由器对应的目录里，即可在路由器每次重启时自动配置 VLAN。&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;注意 1：&lt;/strong&gt;路由器 &lt;em&gt;系统管理&lt;/em&gt; -&amp;gt; &lt;em&gt;系统设置&lt;/em&gt; 中的 &lt;strong&gt;Enable JFFS custom scripts and configs&lt;/strong&gt; 需要设为 &lt;strong&gt;是&lt;/strong&gt;。&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;注意 2：&lt;/strong&gt;上传完毕之后，运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chmod +x /jffs/scripts/*&lt;/code&gt; 为这些脚本赋予可执行权限。&lt;/p&gt;

&lt;h3 id=&quot;services-start&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/services-start&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/000-services-start

&lt;span class=&quot;c&quot;&gt;# Physical port to interface map:&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth0   WAN&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth1   LAN 4&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth2   LAN 3&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth3   LAN 2&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth4   LAN 1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth5   Bridge of LAN 5, LAN 6, LAN 7, LAN 8&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth6   2.4 GHz Radio&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth7   5 GHz Radio&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Delete those interfaces that we want to isolate from br0&lt;/span&gt;
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: deleting LAN 2 (eth3) from br0&quot;&lt;/span&gt;
brctl delif br0 eth3

&lt;span class=&quot;c&quot;&gt;# Create a new bridge br1 for isolated interfaces&lt;/span&gt;
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: creating br1 with LAN 2 (eth3)&quot;&lt;/span&gt;
brctl addbr br1
brctl stp br1 on &lt;span class=&quot;c&quot;&gt;# STP to prevent bridge loops&lt;/span&gt;
brctl addif br1 eth3

&lt;span class=&quot;c&quot;&gt;# Set up the IPv4 address for br1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Here we set the subnet to be 192.168.150.0/24&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# IPv6 link local address will be assigned automatically&lt;/span&gt;
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: setting up IPv4 address for br1&quot;&lt;/span&gt;
ifconfig br1 192.168.150.1 netmask 255.255.255.0
ifconfig br1 allmulti up

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/000-services-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;firewall-start&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/firewall-start&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/000-firewall-start
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;firewall-start: applying INPUT rules for br1&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Allow new incoming connections from br1&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; NEW &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT &lt;span class=&quot;c&quot;&gt;# Same rule as br0 by default&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; NEW &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# Only forbid br1 access the web UI and SSH of the main router&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 80 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 22 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 80 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 22 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;firewall-start: applying FORWARD rules for br1&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Forbid packets from br1 to be forwarded to other interfaces&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP

&lt;span class=&quot;c&quot;&gt;# But allow packet forwarding inside br1&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# Allow packet forwarding between br1 and eth0 (WAN)&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; eth0 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; eth0 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# Allow one-way traffic from br0 to br1&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; RELATED,ESTABLISHED &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; RELATED,ESTABLISHED &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;firewall-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/000-firewall-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;nat-start&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/nat-start&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/000-nat-start
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;nat-start: applying POSTROUTING rules for br1&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# NAT inside 192.168.150.0/24 on br1&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; nat &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; POSTROUTING &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 192.168.150.0/24 &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; 192.168.150.0/24 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; MASQUERADE

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;nat-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/000-nat-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;wan-event&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/wan-event&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;该脚本&lt;strong&gt;仅&lt;/strong&gt;用于 IPv6。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;PD_PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;56 &lt;span class=&quot;c&quot;&gt;# Change to which works for your ISP&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;RETRY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10

&lt;span class=&quot;c&quot;&gt;# Only run for connected event (the old wan-start)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$2&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;connected&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;0
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/000-wan-event-connected

&lt;span class=&quot;c&quot;&gt;# ipv6_service = dhcp6 means Connection Type: Native, &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# also we require DHCP PD to be enabled&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_service&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcp6&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_dhcp_pd&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# Try to find odhcp6c&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-lt&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$RETRY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Get odhcp6c's pid. If there are multiple instances (unlikely), &lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# we use the smallest one.&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;PID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;pidof odhcp6c | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'\n'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 1&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;CMDLINE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/proc/&lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt;/cmdline

    &lt;span class=&quot;c&quot;&gt;# Found odhcp6c?&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$CMDLINE&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
      &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;COMMAND&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'\0'&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt; &amp;lt; /proc/&lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt;/cmdline&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
      logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;found odhcp6c, PID: &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, command: &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$COMMAND&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

      &lt;span class=&quot;c&quot;&gt;# The first 11 chars should be &quot;odhcp6c -df&quot;&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$COMMAND&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c1-11&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;odhcp6c -df&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# There is a space between &quot;odhcp6c -df&quot; and remaining arguments.&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# So we start from the 13rd char.&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;ARGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$COMMAND&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c13-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;# Check if arguments start with -P$PD_PREFIX&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;ARG1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ARGS&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c1-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;expr &lt;/span&gt;length &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; + 2&lt;span class=&quot;si&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ARG1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-P&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;# Prefix length (-P$PD_PREFIX)&lt;/span&gt;
          &lt;span class=&quot;nv&quot;&gt;COMMAND&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;odhcp6c -df -P&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ARGS&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
          logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;re-run odhcp6c with prefix hint &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$COMMAND&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

          killall odhcp6c
          &lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$COMMAND&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else
          &lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;odhcp6c already started with prefix hint &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;fi
      else
        &lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;odhcp6c command prefix mismatch!&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;found '&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;', expects 'odhcp6c -df'&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

      &lt;span class=&quot;c&quot;&gt;# We break from here once found the `odhcp6c` process&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;break
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else
      &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
      logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;odhcp6c not found (&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$RETRY&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&quot;&lt;/span&gt;

      &lt;span class=&quot;c&quot;&gt;# Hope we're lucky next time&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;1
    &lt;span class=&quot;k&quot;&gt;fi
  done
else
  &lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]: DHCPv6 PD not enabled&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi

&lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/000-wan-event-connected
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;dhcpc-event&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/dhcpc-event&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;该脚本&lt;strong&gt;仅&lt;/strong&gt;用于 IPv6。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

link_local_ipv6&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# Get IPv6 link local address from br0 (with the prefix length part)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr show br0 scope &lt;span class=&quot;nb&quot;&gt;link&lt;/span&gt; |&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'s/^.*inet6 \([^ ]*\).*$/\1/;t;d'&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

setup_br1&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# ipv6_service = dhcp6 means Connection Type: Native, &lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# also we require DHCP PD to be enabled&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_service&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcp6&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_dhcp_pd&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    
    &lt;span class=&quot;c&quot;&gt;# Wait for udhcpc (udhcpc.c: bound6 -&amp;gt; add_ip6_lanaddr). &lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# We need to the updated ipv6 prefix from nvram.&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;2

    &lt;span class=&quot;c&quot;&gt;# Allocated IPv6 prefix from ISP&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_prefix&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
      &lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event: empty IPv6 prefix&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else
      &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PD_PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_prefix_length&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ge&lt;/span&gt; 63 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# We need at least 3 /64 subnets, /63 only gives 2 /64 subnet&lt;/span&gt;
        logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event: IPv6 prefix&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;(/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;) is too long, at least /62 requried&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else
        if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-le&lt;/span&gt; 48 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;# Shorter than /49? &lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;# br1 will on a:b:c:2::/63 (br0 is on a:b:c:0::/64)&lt;/span&gt;
          &lt;span class=&quot;nv&quot;&gt;BR1_PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;':'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f1-3&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:2::&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;# /49 to /62? &lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;# br1 will on a:b:c:dddf::/63 (br0 is on a:b:c:dddd::/64)&lt;/span&gt;
          &lt;span class=&quot;nv&quot;&gt;BR0_NET_ID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;':'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f4&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;nv&quot;&gt;BR1_NET_ID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;%x&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;x&lt;span class=&quot;nv&quot;&gt;$BR0_NET_ID&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;x2&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;nv&quot;&gt;BR1_PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;':'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f1-3&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BR1_NET_ID&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;# Clean up br0&lt;/span&gt;
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; route flush dev br0
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr flush dev br0 scope global

        &lt;span class=&quot;c&quot;&gt;# Assign br0 with the first /64 subnet (instead the /56 one)&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# ipv6_rtr_addr is the default router's IPv6 address &lt;/span&gt;
        logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event: set prefix&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_rtr_addr&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/64 to br0&quot;&lt;/span&gt;
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_rtr_addr&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/64&quot;&lt;/span&gt; dev br0

        &lt;span class=&quot;c&quot;&gt;# Clean up br1 (note we also remove link local address)&lt;/span&gt;
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; route flush dev br1
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr flush dev br1

        &lt;span class=&quot;c&quot;&gt;# Re-add link local address&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# So route to fe80::/64 will be added back&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# Note this is VERY important for 6relayd&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# Otherwise 6relayd will throw network unreachable error&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# Because route to fe80::/64 doesn't exist&lt;/span&gt;
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;link_local_ipv6&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt; dev br1

        &lt;span class=&quot;c&quot;&gt;# Assign br1 with a /63 subnet, so the cascading router &lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# will be on the first /64 subnet and it will also get&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# the second /64 prefix via DHCPv6-PD by 6relayd&lt;/span&gt;
        logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event: set prefix&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BR1_PREFIX&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1/63 to br1&quot;&lt;/span&gt;
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BR1_PREFIX&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1/63&quot;&lt;/span&gt; dev br1

        &lt;span class=&quot;c&quot;&gt;# Re-run 6relayd&lt;/span&gt;
        logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event: re-run 6relayd on br1&quot;&lt;/span&gt;
        killall 6relayd

        &lt;span class=&quot;c&quot;&gt;# Automatic DHCPv6 server to delegate prefix on br1 in daemon&lt;/span&gt;
        6relayd &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; br1
      &lt;span class=&quot;k&quot;&gt;fi
    fi
  fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

teardown_br1&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# ipv6_service = dhcp6 means Connection Type: Native,&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# also we require DHCP PD to be enabled&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_service&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcp6&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_dhcp_pd&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
     
    &lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;flush IPv6 route and IPv6 address on br1&quot;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;# br0 will be handled by udhcpc, &lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# we only need to care about br1&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Note we also remove link local address&lt;/span&gt;
    ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; route flush dev br1
    ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr flush dev br1

    &lt;span class=&quot;c&quot;&gt;# Re-add link local address&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# So route to fe80::/64 will be added back&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Note this is VERY important for 6relayd&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Otherwise 6relayd will throw network unreachable error&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Because route to fe80::/64 doesn't exist&lt;/span&gt;
    ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;link_local_ipv6&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt; dev br1
  &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/000-dhcpc-event

&lt;span class=&quot;c&quot;&gt;# Adapted from odhcp6c-example-script.sh&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  flock 9
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in
    &lt;/span&gt;bound&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      teardown_br1
      setup_br1
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    informed|updated|rebound|ra-updated&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      setup_br1
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    stopped|unbound&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      teardown_br1
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    started&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      teardown_br1
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 9&amp;gt;/tmp/odhcp6c.lock.br1
&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /tmp/odhcp6c.lock.br1

&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/000-dhcpc-event
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;dnsmasq-conf-add&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/configs/dnsmasq.conf.add&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;不需要 DHCPv6：&lt;/p&gt;

&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;py&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 range: 192.168.150.2 - 192.168.150.254, netmask: 255.255.255.0
# DHCPv4 lease time: 86400s (1 day)
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,192.168.150.2,192.168.150.254,255.255.255.0,86400s&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 router (option 3): 192.168.150.1
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-option&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,3,192.168.150.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;需要 DHCPv6，并且需要为二级路由器启用 DHCPv6-PD：&lt;/p&gt;

&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;py&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 range: 192.168.150.2 - 192.168.150.254, netmask: 255.255.255.0
# DHCPv4 lease time: 86400s (1 day)
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,192.168.150.2,192.168.150.254,255.255.255.0,86400s&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 router (option 3): 192.168.150.1
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-option&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,3,192.168.150.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;（你没看错，和不用 DHCPv6 是一样的）&lt;/p&gt;

&lt;p&gt;需要 DHCPv6，但是不需要 DHCPv6-PD：&lt;/p&gt;

&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;py&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 range: 192.168.150.2 - 192.168.150.254, netmask: 255.255.255.0
# DHCPv4 lease time: 86400s (1 day)
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,192.168.150.2,192.168.150.254,255.255.255.0,86400s&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 router (option 3): 192.168.150.1
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-option&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,3,192.168.150.1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 RA interval: 10s, router lifetime: 600s
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;ra-param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,10,600&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 range: whole subnet, constructing from br1's prefix
# DHCPv6 prefix length: 64, mode: Stateless DHCPv6
# DHCPv6 lease time: 600s (10 minutes)
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,::,constructor:br1,ra-stateless,64,600&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 DNS (option 23): inherit from the router
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-option&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,option6:23,[::]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;参考文献&quot;&gt;参考文献&lt;/h2&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:ax88u-openwrt&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;slh, &lt;em&gt;&lt;a href=&quot;https://forum.openwrt.org/t/asus-rt-ax88u-router/52275/2&quot;&gt;Reply: ASUS RT-AX88U Router&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:ax88u-openwrt&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:vlanctl&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;u128393, &lt;em&gt;&lt;a href=&quot;https://www.cnblogs.com/u128393/p/11629970.html&quot;&gt;RT-AC86U VLAN 配置 - vlanctl 篇&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:vlanctl&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:slaac&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Wikipedia, &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/IPv6_address#Stateless_address_autoconfiguration&quot;&gt;Stateless address autoconfiguration&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:slaac&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:prefix-hint&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;buddyp, &lt;em&gt;&lt;a href=&quot;https://www.snbforums.com/threads/ipv6-with-prefix-delegation.22834/#post-168667&quot;&gt;Reply: IPv6 with Prefix Delegation&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:prefix-hint&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:dnsmasq-author&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Simon Kelley, &lt;em&gt;&lt;a href=&quot;http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2014q1/008218.html&quot;&gt;[Dnsmasq-discuss] IPV6 Prefix Delegation (IA_PD)&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:dnsmasq-author&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:dhcp6-protocol&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Simon Kelley, &lt;em&gt;&lt;a href=&quot;https://github.com/RMerl/asuswrt-merlin.ng/blob/master/release/src/router/dnsmasq/src/dhcp6-protocol.h&quot;&gt;dnsmasq: dhcp6-protocol.h&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:dhcp6-protocol&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:rfc-3633&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;O. Troan, R. Droms, &lt;em&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc3633&quot;&gt;RFC 3633 - IPv6 Prefix Options for Dynamic Host Configuration Protocol (DHCP) version 6&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:rfc-3633&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:6relayd&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Steven Barth, &lt;em&gt;&lt;a href=&quot;https://github.com/RMerl/asuswrt-merlin.ng/tree/master/release/src/router/6relayd&quot;&gt;6relayd - Embedded DHCPv6/RA Server &amp;amp; Relay&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:6relayd&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</content><author><name>Renjie Wu</name></author><category term="Network" /><summary type="html">尽管博通 HND 平台移除了 `robocfg` 命令，梅林固件也没有提供划分 VLAN 的 GUI 支持，但通过把以太网端口分离至独立网桥 + 防火墙规则 (`ebtables` 或 `iptables`) 的方式，仍然可以在 AX88U + Merlin 384.16 上实现 LAN 端口隔离（静态 VLAN）。</summary></entry><entry xml:lang="en-us"><title type="html">LAN port isolation (port-based VLAN) on ASUS RT-AX88U with Asuswrt-Merlin 384.16</title><link href="https://wu.renjie.im/blog/network/ax88u-vlan/" rel="alternate" type="text/html" title="LAN port isolation (port-based VLAN) on ASUS RT-AX88U with Asuswrt-Merlin 384.16" /><published>2020-04-15T18:32:03-07:00</published><updated>2022-02-16T17:08:22-08:00</updated><id>https://wu.renjie.im/blog/network/ax88u-vlan</id><content type="html" xml:base="https://wu.renjie.im/blog/network/ax88u-vlan/">&lt;p&gt;Recently I upgraded my 4-years-old &lt;a href=&quot;https://www.asus.com/us/Networking/RTAC68P/&quot;&gt;AC68P&lt;/a&gt; to the 
802.11ax (or WiFi 6, but I prefer the former) supported &lt;a href=&quot;https://www.asus.com/us/Networking/RT-AX88U/&quot;&gt;AX88U&lt;/a&gt;. 
Like my old AC68P, I flashed Asuswrt-Merlin on AX88U since day one.&lt;/p&gt;

&lt;p&gt;However, one issue with Asuswrt (either the stock firmware or Merlin) is no built-in GUI support on VLANs. 
I really miss the good old days with OpenWrt, as you can configure VLANs in GUI. But OpenWrt won’t support AX88U in a
foreseeable future (due to Broadcom’s closed source driver&lt;sup id=&quot;fnref:ax88u-openwrt&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:ax88u-openwrt&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;), CLI seems to be the only solution.&lt;/p&gt;

&lt;h2 id=&quot;requirement&quot;&gt;Requirement&lt;/h2&gt;

&lt;p&gt;Pretty straightforward. There are 8 LAN ports on AX88U and I want to isolate LAN 2 from the remaining 7 ports. 
LAN 1 and LAN 3 through 8 will be in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 1&lt;/code&gt;, while LAN 2 will be isolated into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 2&lt;/code&gt; (guest network).&lt;/p&gt;

&lt;p&gt;The traffic between two VLANs should be forbidden. But ideally, I want to allow one way traffic from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 1&lt;/code&gt; 
to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 2&lt;/code&gt;. So I can still access the cascading router (in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 2&lt;/code&gt;) from my computer (in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 1&lt;/code&gt;), in case I need to 
reconfigure the secondary router.&lt;/p&gt;

&lt;p&gt;In addition, I prefer everything to be configured automatically. So for clients in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 2&lt;/code&gt;, the only thing is to 
plug in the ethernet cable and get connected to the Internet.&lt;/p&gt;

&lt;h2 id=&quot;about-ax88u&quot;&gt;About AX88U&lt;/h2&gt;

&lt;h3 id=&quot;no-robocfg&quot;&gt;No &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;robocfg&lt;/code&gt;?&lt;/h3&gt;

&lt;p&gt;The first problem is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;robocfg&lt;/code&gt; is no more provided on AX88U (Broadcom’s HND platform). An alternative to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;robocfg&lt;/code&gt; 
on HND platform seems to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vlanctl&lt;/code&gt;&lt;sup id=&quot;fnref:vlanctl&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:vlanctl&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. However, after several hours of searching, trying and error, 
I believe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vlanctl&lt;/code&gt; can only create tagged VLAN, which unfortunately can’t satisfy my need.&lt;/p&gt;

&lt;p&gt;But in case someone else has special demand on tagged VLAN, I recommend to read (in Chinese): 
&lt;a href=&quot;https://www.cnblogs.com/u128393/p/11629969.html&quot;&gt;上海电信 TL-EP110 + RT-AC86U 实现观看 4K IPTV 无卡顿 (2019-10)&lt;/a&gt;. 
This post describes how to set tagged VLANs up properly on AC86U (also a HND platform router).&lt;/p&gt;

&lt;h3 id=&quot;interface-to-physical-port-mapping&quot;&gt;Interface to Physical Port Mapping&lt;/h3&gt;

&lt;p&gt;Somehow I didn’t find it in the Internet. After playing with an ethernet cable on different ports, I figured out:&lt;/p&gt;

&lt;table class=&quot;table-align-center&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Interface&lt;/th&gt;
      &lt;th&gt;Physical Port&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;eth0&lt;/td&gt;
      &lt;td&gt;WAN&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth1&lt;/td&gt;
      &lt;td&gt;LAN 4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth2&lt;/td&gt;
      &lt;td&gt;LAN 3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth3&lt;/td&gt;
      &lt;td&gt;LAN 2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth4&lt;/td&gt;
      &lt;td&gt;LAN 1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth5&lt;/td&gt;
      &lt;td&gt;Bridge of LAN 5 - 8&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth6&lt;/td&gt;
      &lt;td&gt;2.4 GHz Radio&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;eth7&lt;/td&gt;
      &lt;td&gt;5 GHz Radio&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Note that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth5&lt;/code&gt; seems to be a hardware bridge (BCM53134) of LAN 5 - 8. You may be able to ungroup it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethctl&lt;/code&gt; 
or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethswctl&lt;/code&gt;, but I didn’t spend much time on them. My solution can only isolate LAN ports 1 - 4.&lt;/p&gt;

&lt;p&gt;By default, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth1&lt;/code&gt; ~ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth7&lt;/code&gt; are grouped in bridge &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;.&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note:&lt;/strong&gt; My &lt;strong&gt;WAN Connection Type&lt;/strong&gt; is &lt;strong&gt;Automatic IP&lt;/strong&gt;. If you are using other types like PPPoE, you may need to replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth0&lt;/code&gt; 
to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ppp0&lt;/code&gt; in the below accordingly.&lt;/p&gt;

&lt;h2 id=&quot;one-liner-with-ebtables&quot;&gt;One-liner with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ebtables&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;If you don’t care about separating ports into different subnets, there actually exists an one-line solution:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# eth3 maps to LAN port 2 on AX88U &lt;/span&gt;
ebtables &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; eth3 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt; maps to LAN 2. The layer 2 firewall &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ebtables&lt;/code&gt; will essentially block access between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt; 
and remaining interfaces in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt; is still in the same subnet as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;, there is no need to worry about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables&lt;/code&gt; or DHCP.
Everything will just be fine.&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note 1:&lt;/strong&gt; If it doesn’t work, try &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ebtables -A FORWARD -i eth3 --logical-out br0 -j DROP&lt;/code&gt;. Thanks to &lt;a href=&quot;https://disqus.com/by/marianmaciag/&quot;&gt;@MarianMaciag&lt;/a&gt;!&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note 2:&lt;/strong&gt; If it still doesn’t work, try &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables&lt;/code&gt; instead: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables -A FORWARD -i eth3 -o br0 -j DROP&lt;/code&gt;. The downside with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables&lt;/code&gt; is that only layer 3+ access is restricted.&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note 3:&lt;/strong&gt; Also remember this only blocks access in &lt;strong&gt;one&lt;/strong&gt; direction: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;. You need &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-i br0 -o eth3&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--logical-in br0 -o eth3&lt;/code&gt;) to block &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt;.&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note 4:&lt;/strong&gt; If it again doesn’t work, go separate bridge approach below.&lt;/p&gt;

&lt;h2 id=&quot;better-approach-with-separate-bridge&quot;&gt;Better Approach with Separate Bridge&lt;/h2&gt;

&lt;p&gt;However, my goal is to associate two VLANs with two subnets. Say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 1&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.50.0/24&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VLAN 2&lt;/code&gt;
with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.150.0/24&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;create-bridge-br1&quot;&gt;Create Bridge &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;First, remove &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; and create a new bridge &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth3&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Delete those interfaces that we want to isolate from br0&lt;/span&gt;
brctl delif br0 eth3

&lt;span class=&quot;c&quot;&gt;# Create a new bridge br1 for our isolated interfaces&lt;/span&gt;
brctl addbr br1
brctl stp br1 on &lt;span class=&quot;c&quot;&gt;# STP to prevent bridge loops&lt;/span&gt;
brctl addif br1 eth3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we use bridge &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; for easier management. If you want to add isolate other LAN ports, you can simply
add the corresponding interface to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;. All rules on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; will automatically apply to that port.&lt;/p&gt;

&lt;p&gt;Now run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brctl show&lt;/code&gt; to verify the settings for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# brctl show&lt;/span&gt;
bridge name     bridge id               STP enabled     interfaces
br0             8000.a85e45fakeid       yes             eth1
                                                        eth2
                                                        eth4
                                                        eth5
                                                        eth6
                                                        eth7
&lt;strong class=&quot;mi&quot;&gt;br1&lt;/strong&gt;             8000.a85e45fakeid       &lt;strong class=&quot;mi&quot;&gt;yes&lt;/strong&gt;             &lt;strong class=&quot;mi&quot;&gt;eth3&lt;/strong&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By default, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; is assigned with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.50.1/24&lt;/code&gt; on AX88U, so we don’t have to worry about it&lt;/p&gt;

&lt;p&gt;Then, assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.150.1/24&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; and bring it up:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Set up the IPv4 address for br1 and bring it up&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Here we set the subnet to be 192.168.150.0/24&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# IPv6 link local address will be assigned automatically&lt;/span&gt;
ifconfig br1 192.168.150.1 netmask 255.255.255.0
ifconfig br1 allmulti up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifconfig br1&lt;/code&gt; to see if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; is up:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# ifconfig br1&lt;/span&gt;
br1       Link encap:Ethernet  HWaddr A8:5E:45:00:FA:KE
          &lt;strong class=&quot;mi&quot;&gt;inet addr:192.168.150.1&lt;/strong&gt;  Bcast:192.168.150.255  &lt;strong class=&quot;mi&quot;&gt;Mask:255.255.255.0&lt;/strong&gt;
          inet6 addr: fe80::aa5e:45ff:fe00:fake/64 Scope:Link
          &lt;strong class=&quot;mi&quot;&gt;UP&lt;/strong&gt; BROADCAST RUNNING &lt;strong class=&quot;mi&quot;&gt;ALLMULTI&lt;/strong&gt; MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The IPv6 link local address is automatically generated by &lt;a href=&quot;https://en.wikipedia.org/wiki/IPv6_address#Modified_EUI-64&quot;&gt;EUI-64&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Complete script can be found in &lt;a href=&quot;#services-start&quot;&gt;Scripts &amp;amp; Configs: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/services-start&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;add-iptables-rules&quot;&gt;Add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables&lt;/code&gt; Rules&lt;/h3&gt;

&lt;p&gt;First, allow new incoming connections from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; to the router:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Allow new incoming connections from br1&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; NEW &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But forbid accessing web UI and SSH from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Only forbid br1 access the web UI and SSH of the main router&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 80 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 22 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, drop all forwarding packets from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Forbid packets from br1 to be forwarded to other interfaces&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But allow packet forwarding inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# But allow packet forwarding inside br1&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… also allow packet forwarding between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth0&lt;/code&gt; (WAN):&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Allow packet forwarding between br1 and eth0 (WAN)&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; eth0 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… also allow one-way traffic from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Allow one-way traffic from br0 to br1&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; RELATED,ESTABLISHED &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, set up NAT inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.150.0/24&lt;/code&gt; on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;iptables &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; nat &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; POSTROUTING &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 192.168.150.0/24 &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; 192.168.150.0/24 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; MASQUERADE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables -S INPUT&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables -S FORWARD&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables -t nat -S POSTROUTING&lt;/code&gt; to verify that rules 
have been added:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# iptables -S INPUT&lt;/span&gt;
-P INPUT ACCEPT
&lt;strong class=&quot;mi&quot;&gt;-A INPUT -i br1 -p tcp -m tcp --dport 22 -j DROP&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A INPUT -i br1 -p tcp -m tcp --dport 80 -j DROP&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A INPUT -i br1 -m state --state NEW -j ACCEPT&lt;/strong&gt;
&lt;span class=&quot;c&quot;&gt;# ... output omitted ...&lt;/span&gt;
-A INPUT -j DROP

&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# iptables -S FORWARD&lt;/span&gt;
-P FORWARD DROP
&lt;strong class=&quot;mi&quot;&gt;-A FORWARD -i br1 -o br0 -m state --state RELATED,ESTABLISHED -j ACCEPT&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A FORWARD -i br0 -o br1 -j ACCEPT&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A FORWARD -i br1 -o eth0 -j ACCEPT&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A FORWARD -i br1 -o br1 -j ACCEPT&lt;/strong&gt;
&lt;strong class=&quot;mi&quot;&gt;-A FORWARD -i br1 -j DROP&lt;/strong&gt;
&lt;span class=&quot;c&quot;&gt;# ... output omitted ...&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# iptables -t nat -S POSTROUTING&lt;/span&gt;
-P POSTROUTING ACCEPT
&lt;span class=&quot;c&quot;&gt;# ... output omitted ...&lt;/span&gt;
-A POSTROUTING -s 192.168.50.0/24 -d 192.168.50.0/24 -o br0 -j MASQUERADE
&lt;strong class=&quot;mi&quot;&gt;-A POSTROUTING -s 192.168.150.0/24 -d 192.168.150.0/24 -o br1 -j MASQUERADE&lt;/strong&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;notice--info&quot;&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Complete scripts can be found below.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Script for firewall: &lt;a href=&quot;#firewall-start&quot;&gt;Scripts &amp;amp; Configs: /jffs/scripts/firewall-start&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Script for NAT: &lt;a href=&quot;#nat-start&quot;&gt;Scripts &amp;amp; Configs: /jffs/scripts/nat-start&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;h3 id=&quot;configure-dnsmasq-for-dhcpv4&quot;&gt;Configure &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; for DHCPv4&lt;/h3&gt;

&lt;p&gt;Create an additional configuration file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq.conf.add&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/configs/&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /jffs/configs/dnsmasq.conf.add
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Similar to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;, set up DHCPv4 ranges and options on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt; &amp;gt;&amp;gt; /jffs/configs/dnsmasq.conf.add
interface=br1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 range: 192.168.150.2 - 192.168.150.254, netmask: 255.255.255.0
# DHCPv4 lease time: 86400s (1 day)&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;dhcp-range=br1,192.168.150.2,192.168.150.254,255.255.255.0,86400s&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 router (option 3): 192.168.150.1&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;dhcp-option=br1,3,192.168.150.1&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Restart &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; to apply the config:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;service restart_dnsmasq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tail /tmp/syslog.log -n 50&lt;/code&gt; to see if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq.conf.add&lt;/code&gt; is loaded:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# tail /tmp/syslog.log -n 50&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# ... output omitted ...&lt;/span&gt;
Apr 14 20:49:22 rc_service: service 15995:notify_rc restart_dnsmasq
Apr 14 20:49:22 dnsmasq[1149]: exiting on receipt of SIGTERM
&lt;strong class=&quot;mi&quot;&gt;Apr 14 20:49:22 custom_config: Appending content of /jffs/configs/dnsmasq.conf.add.&lt;/strong&gt;
Apr 14 20:49:22 dnsmasq[15998]: started, version 2.81rc4-33-g7558f2b cachesize 1500
Apr 14 20:49:22 dnsmasq[15998]: asynchronous logging enabled, queue limit is 5 messages
&lt;strong class=&quot;mi&quot;&gt;Apr 14 20:49:22 dnsmasq-dhcp[15998]: DHCP, IP range 192.168.150.2 -- 192.168.150.254, lease time 1d&lt;/strong&gt;
Apr 14 20:49:22 dnsmasq-dhcp[15998]: DHCP, IP range 192.168.50.2 -- 192.168.50.254, lease time 1d
&lt;span class=&quot;c&quot;&gt;# ... output omitted ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;what-about-ipv6&quot;&gt;What about IPv6?&lt;/h2&gt;

&lt;p&gt;Even in the scenario of stateless DHCPv6, hosts’ IPv6 addresses are still generated via SLAAC&lt;sup id=&quot;fnref:slaac&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:slaac&quot; class=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; according to &lt;a href=&quot;https://tools.ietf.org/html/rfc3736&quot;&gt;RFC 3736&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A node that uses stateless DHCP must have obtained its IPv6 addresses through some other mechanism, typically 
&lt;strong&gt;stateless address autoconfiguration&lt;/strong&gt; (or SLAAC).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since SLAAC uses EUI-64 algorithm, the subnet prefix is required to be shorter than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt;. That means to do subnetting 
with stateless DHCPv6, the IPv6 LAN prefix allocated from your ISP &lt;strong&gt;must&lt;/strong&gt; be at least of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/63&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;prefix-hint-for-shorter-subnet-prefix&quot;&gt;Prefix Hint for Shorter Subnet Prefix&lt;/h3&gt;

&lt;p&gt;Some ISPs allow you send &lt;a href=&quot;https://tools.ietf.org/html/rfc3633#page-5&quot;&gt;prefix length hint&lt;/a&gt; to get a prefix shorter 
than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; (fortunately Charter Spectrum does assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/56&lt;/code&gt;). If you’re not sure about this, you can try the
following steps.&lt;/p&gt;

&lt;p&gt;By the way, my AX88U’s IPv6 configuration is:&lt;/p&gt;

&lt;table class=&quot;table-align-center&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Name&lt;/th&gt;
      &lt;th&gt;Value&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Basic Config&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Connection type&lt;/td&gt;
      &lt;td&gt;Native&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;DHCP-PD&lt;/td&gt;
      &lt;td&gt;Enable&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;IPv6 LAN Setting&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Auto Configuration Setting&lt;/td&gt;
      &lt;td&gt;Stateless&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;IPv6 DNS Setting&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Connect to DNS Server automatically&lt;/td&gt;
      &lt;td&gt;Disable&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;IPv6 DNS Server 1&lt;/td&gt;
      &lt;td&gt;2606:4700:4700::1111&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;IPv6 DNS Server 2&lt;/td&gt;
      &lt;td&gt;2606:4700:4700::1001&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;IPv6 DNS Server 3&lt;/td&gt;
      &lt;td&gt;&lt;em&gt;&amp;lt;leave blank&amp;gt;&lt;/em&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Auto Configuration Setting&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Enable Router Advertisement&lt;/td&gt;
      &lt;td&gt;Enable&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;By default, the DHCPv6 client &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;odhcp6c&lt;/code&gt; on AX88U wouldn’t send prefix hint.&lt;br /&gt;
To force it do so&lt;sup id=&quot;fnref:prefix-hint&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:prefix-hint&quot; class=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;, first run&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ps | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'s/^.*\odhcp6c \(.*\)$/\1/;t;d'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;to get the arguments of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;odhcp6c&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;-df -R -s /tmp/dhcp6c -N try &lt;strong class=&quot;mi&quot;&gt;-c &amp;lt;duid&amp;gt; -FP 0:&amp;lt;iaid&amp;gt;&lt;/strong&gt; eth0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;duid&amp;gt;&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;iaid&amp;gt;&lt;/code&gt; are linked to your router’s MAC address. Depends on your IPv6 configuration, there may be 
additional arguments like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-r23&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-r24&lt;/code&gt;, don’t forget to append them too.&lt;/p&gt;

&lt;p&gt;So in the next two commands, replace them with the output you got:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Kill existing odhcp6c.&lt;/span&gt;
killall odhcp6c
&lt;span class=&quot;c&quot;&gt;# Re-run odhcp6c with prefix hint 56.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Replace `-c` and `-FP` arguments with the `ps` output you got.&lt;/span&gt;
odhcp6c -df &lt;strong class=&quot;mi&quot;&gt;-P56&lt;/strong&gt; -R -s /tmp/dhcp6c -N try &lt;strong class=&quot;mi&quot;&gt;-c &amp;lt;duid&amp;gt; -FP 0:&amp;lt;iaid&amp;gt;&lt;/strong&gt; eth0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-P56&lt;/code&gt; determines which prefix hint length to send.&lt;/p&gt;

&lt;p&gt;Now you can run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifconfig br0&lt;/code&gt; to verify if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/56&lt;/code&gt; subnet is assigned:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# ifconfig br0&lt;/span&gt;
br0       Link encap:Ethernet  HWaddr A8:5E:45:00:FA:KE
          inet addr:192.168.50.1  Bcast:192.168.50.255  Mask:255.255.255.0
          inet6 addr: 2600:6c51:fake:n00b::1&lt;strong class=&quot;mi&quot;&gt;/56&lt;/strong&gt; Scope:&lt;strong class=&quot;mi&quot;&gt;Global&lt;/strong&gt;
          inet6 addr: fe80::aa5e:45ff:fe00:fake/64 Scope:Link
          UP BROADCAST RUNNING ALLMULTI MULTICAST  MTU:1500  Metric:1
          RX packets:4241 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3714 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:829133 (809.7 KiB)  TX bytes:1787334 (1.7 MiB)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If something similar is printed to your screen, Congratulations! You can proceed to the next section. 
Otherwise, you may have to stop here and try to set up stateful DHCPv6 server on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;, which I didn’t try.&lt;/p&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Complete script for re-running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;odhcp6c&lt;/code&gt; automatically after reboot can be found in &lt;a href=&quot;#wan-event&quot;&gt;Scripts &amp;amp; Configs: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/wan-event&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;add-ip6tables-rules&quot;&gt;Add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip6tables&lt;/code&gt; Rules&lt;/h3&gt;

&lt;p&gt;Similiar to IPv4 solution, some necessary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip6tables&lt;/code&gt; rules have to be added. But no need to deal with NAT (It’s IPv6!).&lt;/p&gt;

&lt;p&gt;For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INPUT&lt;/code&gt; chain:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Allow new incoming connections from br1&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT &lt;span class=&quot;c&quot;&gt;# Same rule as br0 by default&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; NEW &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# Only forbid br1 access the web UI and SSH of the main router&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 80 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 22 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FORWARD&lt;/code&gt; chain:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Forbid packets from br1 to be forwarded to other interfaces&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP

&lt;span class=&quot;c&quot;&gt;# But allow packet forwarding inside br1&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# Allow packet forwarding between br1 and eth0 (WAN)&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; eth0 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# Allow one-way traffic from br0 to br1&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; RELATED,ESTABLISHED &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Complete script can be found in &lt;a href=&quot;#firewall-start&quot;&gt;Scripts &amp;amp; Configs: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/firewall-start&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;configure-dhcpv6&quot;&gt;Configure DHCPv6&lt;/h3&gt;

&lt;p&gt;By default, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; will take the whole &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/56&lt;/code&gt; subnet. We need to change it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; for subnetting on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, check what prefix &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; has gotten from ISP with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip -6 addr show br0 scope global&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# ip -6 addr show br0 scope global&lt;/span&gt;
22: br0: &amp;lt;BROADCAST,MULTICAST,ALLMULTI,UP,LOWER_UP&amp;gt; mtu 1500
    inet6 &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n00b::1/56&lt;/strong&gt; scope global
       valid_lft forever preferred_lft forever
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You IPv6 address is &lt;strong&gt;different&lt;/strong&gt; so remember to replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2600:6c51:fake:n00b::1&lt;/code&gt; with yours in following commands.&lt;/p&gt;

&lt;p&gt;Then, reassign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; subnet:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Remove /56 subnet. Replace 2600:6c51:fake:n00b::1 with yours.&lt;/span&gt;
ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr del 2600:6c51:fake:n00b::1/56 dev br0
&lt;span class=&quot;c&quot;&gt;# Assign /64 subnet. Replace 2600:6c51:fake:n00b::1 with yours.&lt;/span&gt;
ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add 2600:6c51:fake:n00b::1/64 dev br0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course you can make a shorter subnet prefix for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;, but I feel comfortable enough with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip -6 addr show br0 scope global&lt;/code&gt; again to check &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;’s new perfix:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# ip -6 addr show br0 scope global&lt;/span&gt;
22: br0: &amp;lt;BROADCAST,MULTICAST,ALLMULTI,UP,LOWER_UP&amp;gt; mtu 1500
    inet6 &lt;strong class=&quot;mi&quot;&gt;2600:6c51:fake:n00b::1/64&lt;/strong&gt; scope global
       valid_lft forever preferred_lft forever
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The subnet for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; is a little bit tricky, because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; doesn’t support DHCPv6 Prefix Delegation (PD), 
quoting from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt;’s author&lt;sup id=&quot;fnref:dnsmasq-author&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:dnsmasq-author&quot; class=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You’re right, though &lt;strong&gt;this&lt;/strong&gt; (dnsmasq does not support replying to IA_PD (prefix delegation) requests) 
may change in the future.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The code of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; shipped in Merlin&lt;sup id=&quot;fnref:dhcp6-protocol&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:dhcp6-protocol&quot; class=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt; also proves no support of DHCPv6 prefix delegation 
(option 25 and 26&lt;sup id=&quot;fnref:rfc-3633&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:rfc-3633&quot; class=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;).&lt;/p&gt;

&lt;h4 id=&quot;without-prefix-delegation&quot;&gt;Without Prefix Delegation&lt;/h4&gt;

&lt;p&gt;If you have no cascading routers or don’t care about PD, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; can be used as DHCPv6 server.&lt;/p&gt;

&lt;p&gt;First, assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; with the sibling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; subnet of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Assign the sibling /64 subnet of br0 to br1.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# For example, if br0 is on aaaa:bbbb:cccc:dddd::1/64,&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# then br1 should on aaaa:bbbb:cccc:ddde::1/64.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Replace 2600:6c51:fake:n00c::1 with yours.&lt;/span&gt;
ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add 2600:6c51:fake:n00c::1/64 dev br1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, set up DHCPv6 ranges and options on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt; &amp;gt;&amp;gt; /jffs/configs/dnsmasq.conf.add&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 RA interval: 10s, router lifetime: 600s&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;ra-param=br1,10,600&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 range: whole subnet, constructing from br1's prefix
# DHCPv6 prefix length: 64, mode: Stateless DHCPv6
# DHCPv6 lease time: 600s (10 minutes)&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;dhcp-range=br1,::,constructor:br1,ra-stateless,64,600&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 DNS (option 23): inherit from the router&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;dhcp-option=br1,option6:23,[::]&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Restart &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; to apply the config:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;service restart_dnsmasq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tail /tmp/syslog.log -n 50&lt;/code&gt; to see if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq.conf.add&lt;/code&gt; is loaded:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;&lt;span class=&quot;c&quot;&gt;admin@ax88u:/# tail /tmp/syslog.log -n 50&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# ... output omitted ...&lt;/span&gt;
Apr 14 20:49:22 rc_service: service 15995:notify_rc restart_dnsmasq
Apr 14 20:49:22 dnsmasq[1149]: exiting on receipt of SIGTERM
&lt;strong class=&quot;mi&quot;&gt;Apr 14 20:49:22 custom_config: Appending content of /jffs/configs/dnsmasq.conf.add.&lt;/strong&gt;
Apr 14 20:49:22 dnsmasq[15998]: started, version 2.81rc4-33-g7558f2b cachesize 1500
Apr 14 20:49:22 dnsmasq[15998]: asynchronous logging enabled, queue limit is 5 messages
Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCP, IP range 192.168.150.2 -- 192.168.150.254, lease time 1d
Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCP, IP range 192.168.50.2 -- 192.168.50.254, lease time 1d
Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCPv6 stateless on br0
Apr 15 18:09:01 dnsmasq-dhcp[18800]: router advertisement on br0
&lt;strong class=&quot;mi&quot;&gt;Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCPv6 stateless on 2600:6c51:fake:n00b::, constructed for br0&lt;/strong&gt;
Apr 15 18:09:01 dnsmasq-dhcp[18800]: router advertisement on 2600:6c51:fake:n00b::, constructed for br0
Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCPv6 stateless on br1
Apr 15 18:09:01 dnsmasq-dhcp[18800]: router advertisement on br1
&lt;strong class=&quot;mi&quot;&gt;Apr 15 18:09:01 dnsmasq-dhcp[18800]: DHCPv6 stateless on 2600:6c51:fake:n00b::, constructed for br1&lt;/strong&gt;
Apr 15 18:09:01 dnsmasq-dhcp[18800]: router advertisement on 2600:6c51:fake:n00c::, constructed for br1
Apr 15 18:09:01 dnsmasq-dhcp[18800]: IPv6 router advertisement enabled
&lt;span class=&quot;c&quot;&gt;# ... output omitted ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;with-prefix-delegation&quot;&gt;With Prefix Delegation&lt;/h4&gt;

&lt;p&gt;Otherwise, if you want cascading router to get IPv6 prefix automatically through PD, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6relayd&lt;/code&gt; is required as a minimalistic
DHCPv6 PD server.&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note:&lt;/strong&gt; Don’t add DHCPv6 range and options to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/configs/dnsmasq.conf.add&lt;/code&gt; if you wish to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6relayd&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the sever mode of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6realyd&lt;/code&gt;&lt;sup id=&quot;fnref:6relayd&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:6relayd&quot; class=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If there are non-local addresses assigned to the slave interface when a
router solicitation is received, said prefixes are announced automatically
for stateless autoconfiguration and also offered via stateful DHCPv6.
&lt;strong&gt;If all prefixes are bigger than /64 all but the first /64 of these prefixes
is offered via DHCPv6-PD to downstream routers.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;… that is what we want. We’ll assign a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/63&lt;/code&gt; subnet for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6relayd&lt;/code&gt; will delegate a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/64&lt;/code&gt; subnet for the 
cascading router.&lt;/p&gt;

&lt;p&gt;First, assign a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;63&lt;/code&gt; subnet for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt; (here we use the sibling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/63&lt;/code&gt; subnet of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Assign the sibling /63 subnet of br0 to br1.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Use a IPv6 subnet tool for the `/63` subnet range on `br0`.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Replace 2600:6c51:fake:n00c::1 with yours.&lt;/span&gt;
ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add 2600:6c51:fake:n00c::1/63 dev br1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6relayd -v -d -S . br1&lt;/code&gt; for DHCPv6 PD server:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Automatic DHCPv6 server to delegate prefix on br1 in daemon&lt;/span&gt;
6relayd &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; br1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If there are incoming DHCPv6 requests, system log (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat /tmp/syslog.log | grep 6relayd&lt;/code&gt;) should show:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# admin@ax88u:/# cat /tmp/syslog.log | grep 6relayd&lt;/span&gt;
Apr 15 18:20:00 6relayd[1765]: Got DHCPv6 request
Apr 15 18:20:01 6relayd[1765]: Got DHCPv6 request
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… which means &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6relayd&lt;/code&gt; is working properly.&lt;/p&gt;

&lt;p&gt;Now check the &lt;em&gt;System Log&lt;/em&gt; -&amp;gt; &lt;em&gt;IPv6&lt;/em&gt; page in the cascading router (here my old AC68P is the cascading one):&lt;/p&gt;

&lt;table class=&quot;table-align-center&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;IPv6 Connection Type&lt;/th&gt;
      &lt;th&gt;Native with DHCP-PD&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;WAN IPv6 Address&lt;/td&gt;
      &lt;td&gt;2600:6c51:fake:n00c::fake&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;WAN IPv6 Gateway&lt;/td&gt;
      &lt;td&gt;fe80::aa5e:45ff:fe00:fake&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;LAN IPv6 Address&lt;/td&gt;
      &lt;td&gt;2600:6c51:fake:n00d::1/64&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;LAN IPv6 Link-Local Address&lt;/td&gt;
      &lt;td&gt;fe80::a62:66ff:fe01:fake/64&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;DHCP-PD&lt;/td&gt;
      &lt;td&gt;Enabled&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;LAN IPv6 Prefix&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;2600:6c51:fake:n00d::/64&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;DNS Address&lt;/td&gt;
      &lt;td&gt;2600:6c51:fake:n00c::1&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;If everything is good, &lt;em&gt;LAN IPv6 Prefix&lt;/em&gt; should show &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2600:6c51:fake:n00d::/64&lt;/code&gt;.&lt;/p&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Automatic script for setting up DHCPv6 PD can be found in &lt;a href=&quot;#dhcpc-event&quot;&gt;Scripts &amp;amp; Configs: /jffs/scripts/dhcpc-event&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;scripts--configs&quot;&gt;Scripts &amp;amp; Configs&lt;/h2&gt;

&lt;p&gt;In order to apply all settings after reboot, save the following scripts and configs into corresponding folders.&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note 1:&lt;/strong&gt; Don’t forget to set &lt;strong&gt;Enable JFFS custom scripts and configs&lt;/strong&gt; to &lt;strong&gt;Yes&lt;/strong&gt; in &lt;em&gt;Administration&lt;/em&gt; -&amp;gt; &lt;em&gt;System&lt;/em&gt;.&lt;/p&gt;

&lt;p class=&quot;notice--warning&quot;&gt;&lt;strong&gt;Note 2:&lt;/strong&gt; &lt;strong&gt;After&lt;/strong&gt; uploading the following scripts, don’t forget to mark them as executable with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chmod +x /jffs/scripts/*&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;services-start&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/services-start&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/000-services-start

&lt;span class=&quot;c&quot;&gt;# Physical port to interface map:&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth0   WAN&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth1   LAN 4&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth2   LAN 3&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth3   LAN 2&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth4   LAN 1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth5   Bridge of LAN 5, LAN 6, LAN 7, LAN 8&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth6   2.4 GHz Radio&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# eth7   5 GHz Radio&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Delete those interfaces that we want to isolate from br0&lt;/span&gt;
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: deleting LAN 2 (eth3) from br0&quot;&lt;/span&gt;
brctl delif br0 eth3

&lt;span class=&quot;c&quot;&gt;# Create a new bridge br1 for isolated interfaces&lt;/span&gt;
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: creating br1 with LAN 2 (eth3)&quot;&lt;/span&gt;
brctl addbr br1
brctl stp br1 on &lt;span class=&quot;c&quot;&gt;# STP to prevent bridge loops&lt;/span&gt;
brctl addif br1 eth3

&lt;span class=&quot;c&quot;&gt;# Set up the IPv4 address for br1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Here we set the subnet to be 192.168.150.0/24&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# IPv6 link local address will be assigned automatically&lt;/span&gt;
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: setting up IPv4 address for br1&quot;&lt;/span&gt;
ifconfig br1 192.168.150.1 netmask 255.255.255.0
ifconfig br1 allmulti up

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;services-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/000-services-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;firewall-start&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/firewall-start&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/000-firewall-start
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;firewall-start: applying INPUT rules for br1&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Allow new incoming connections from br1&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; NEW &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT &lt;span class=&quot;c&quot;&gt;# Same rule as br0 by default&lt;/span&gt;
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; NEW &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# Only forbid br1 access the web UI and SSH of the main router&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 80 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 22 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 80 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 22 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;firewall-start: applying FORWARD rules for br1&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Forbid packets from br1 to be forwarded to other interfaces&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DROP

&lt;span class=&quot;c&quot;&gt;# But allow packet forwarding inside br1&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# Allow packet forwarding between br1 and eth0 (WAN)&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; eth0 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; eth0 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;# Allow one-way traffic from br0 to br1&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; RELATED,ESTABLISHED &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; FORWARD &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br0 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; RELATED,ESTABLISHED &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;firewall-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/000-firewall-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;nat-start&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/nat-start&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/000-nat-start
logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;nat-start: applying POSTROUTING rules for br1&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# NAT inside 192.168.150.0/24 on br1&lt;/span&gt;
iptables &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; nat &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; POSTROUTING &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 192.168.150.0/24 &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; 192.168.150.0/24 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; br1 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; MASQUERADE

logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;nat-start: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/000-nat-start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;wan-event&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/wan-event&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;This script is &lt;strong&gt;only&lt;/strong&gt; for IPv6.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;PD_PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;56 &lt;span class=&quot;c&quot;&gt;# Change to which works for your ISP&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;RETRY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10

&lt;span class=&quot;c&quot;&gt;# Only run for connected event (the old wan-start)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$2&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;connected&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;0
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/000-wan-event-connected

&lt;span class=&quot;c&quot;&gt;# ipv6_service = dhcp6 means Connection Type: Native, &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# also we require DHCP PD to be enabled&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_service&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcp6&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_dhcp_pd&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# Try to find odhcp6c&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-lt&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$RETRY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Get odhcp6c's pid. If there are multiple instances (unlikely), &lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# we use the smallest one.&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;PID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;pidof odhcp6c | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'\n'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 1&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;CMDLINE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/proc/&lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt;/cmdline

    &lt;span class=&quot;c&quot;&gt;# Found odhcp6c?&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$CMDLINE&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
      &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;COMMAND&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'\0'&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt; &amp;lt; /proc/&lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt;/cmdline&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
      logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;found odhcp6c, PID: &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, command: &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$COMMAND&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

      &lt;span class=&quot;c&quot;&gt;# The first 11 chars should be &quot;odhcp6c -df&quot;&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$COMMAND&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c1-11&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;odhcp6c -df&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# There is a space between &quot;odhcp6c -df&quot; and remaining arguments.&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# So we start from the 13rd char.&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;ARGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$COMMAND&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c13-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;# Check if arguments start with -P$PD_PREFIX&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;ARG1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ARGS&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c1-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;expr &lt;/span&gt;length &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; + 2&lt;span class=&quot;si&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ARG1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-P&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;# Prefix length (-P$PD_PREFIX)&lt;/span&gt;
          &lt;span class=&quot;nv&quot;&gt;COMMAND&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;odhcp6c -df -P&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ARGS&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
          logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;re-run odhcp6c with prefix hint &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$COMMAND&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

          killall odhcp6c
          &lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$COMMAND&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else
          &lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;odhcp6c already started with prefix hint &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;fi
      else
        &lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;odhcp6c command prefix mismatch!&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;found '&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;', expects 'odhcp6c -df'&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

      &lt;span class=&quot;c&quot;&gt;# We break from here once found the `odhcp6c` process&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;break
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else
      &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
      logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;odhcp6c not found (&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$RETRY&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&quot;&lt;/span&gt;

      &lt;span class=&quot;c&quot;&gt;# Hope we're lucky next time&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;1
    &lt;span class=&quot;k&quot;&gt;fi
  done
else
  &lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]: DHCPv6 PD not enabled&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi

&lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wan-event[connected]: all done&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/000-wan-event-connected
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;dhcpc-event&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/scripts/dhcpc-event&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;This script is &lt;strong&gt;only&lt;/strong&gt; for IPv6.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

link_local_ipv6&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# Get IPv6 link local address from br0 (with the prefix length part)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr show br0 scope &lt;span class=&quot;nb&quot;&gt;link&lt;/span&gt; |&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'s/^.*inet6 \([^ ]*\).*$/\1/;t;d'&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

setup_br1&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# ipv6_service = dhcp6 means Connection Type: Native, &lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# also we require DHCP PD to be enabled&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_service&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcp6&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_dhcp_pd&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    
    &lt;span class=&quot;c&quot;&gt;# Wait for udhcpc (udhcpc.c: bound6 -&amp;gt; add_ip6_lanaddr). &lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# We need to the updated ipv6 prefix from nvram.&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;2

    &lt;span class=&quot;c&quot;&gt;# Allocated IPv6 prefix from ISP&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_prefix&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
      &lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event: empty IPv6 prefix&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else
      &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PD_PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_prefix_length&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ge&lt;/span&gt; 63 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# We need at least 3 /64 subnets, /63 only gives 2 /64 subnet&lt;/span&gt;
        logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event: IPv6 prefix&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;(/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;) is too long, at least /62 requried&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else
        if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PD_PREFIX&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-le&lt;/span&gt; 48 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;# Shorter than /49? &lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;# br1 will on a:b:c:2::/63 (br0 is on a:b:c:0::/64)&lt;/span&gt;
          &lt;span class=&quot;nv&quot;&gt;BR1_PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;':'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f1-3&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:2::&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;# /49 to /62? &lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;# br1 will on a:b:c:dddf::/63 (br0 is on a:b:c:dddd::/64)&lt;/span&gt;
          &lt;span class=&quot;nv&quot;&gt;BR0_NET_ID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;':'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f4&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;nv&quot;&gt;BR1_NET_ID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;%x&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;x&lt;span class=&quot;nv&quot;&gt;$BR0_NET_ID&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;x2&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;nv&quot;&gt;BR1_PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PREFIX&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;':'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f1-3&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BR1_NET_ID&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;# Clean up br0&lt;/span&gt;
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; route flush dev br0
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr flush dev br0 scope global

        &lt;span class=&quot;c&quot;&gt;# Assign br0 with the first /64 subnet (instead the /56 one)&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# ipv6_rtr_addr is the default router's IPv6 address &lt;/span&gt;
        logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event: set prefix&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_rtr_addr&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/64 to br0&quot;&lt;/span&gt;
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_rtr_addr&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/64&quot;&lt;/span&gt; dev br0

        &lt;span class=&quot;c&quot;&gt;# Clean up br1 (note we also remove link local address)&lt;/span&gt;
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; route flush dev br1
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr flush dev br1

        &lt;span class=&quot;c&quot;&gt;# Re-add link local address&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# So route to fe80::/64 will be added back&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# Note this is VERY important for 6relayd&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# Otherwise 6relayd will throw network unreachable error&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# Because route to fe80::/64 doesn't exist&lt;/span&gt;
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;link_local_ipv6&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt; dev br1

        &lt;span class=&quot;c&quot;&gt;# Assign br1 with a /63 subnet, so the cascading router &lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# will be on the first /64 subnet and it will also get&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;# the second /64 prefix via DHCPv6-PD by 6relayd&lt;/span&gt;
        logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event: set prefix&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BR1_PREFIX&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1/63 to br1&quot;&lt;/span&gt;
        ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BR1_PREFIX&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1/63&quot;&lt;/span&gt; dev br1

        &lt;span class=&quot;c&quot;&gt;# Re-run 6relayd&lt;/span&gt;
        logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event: re-run 6relayd on br1&quot;&lt;/span&gt;
        killall 6relayd

        &lt;span class=&quot;c&quot;&gt;# Automatic DHCPv6 server to delegate prefix on br1 in daemon&lt;/span&gt;
        6relayd &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; br1
      &lt;span class=&quot;k&quot;&gt;fi
    fi
  fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

teardown_br1&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# ipv6_service = dhcp6 means Connection Type: Native,&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# also we require DHCP PD to be enabled&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_service&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcp6&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;nvram get ipv6_dhcp_pd&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
     
    &lt;/span&gt;logger &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;isolate_port&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dhcpc-event:&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;flush IPv6 route and IPv6 address on br1&quot;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;# br0 will be handled by udhcpc, &lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# we only need to care about br1&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Note we also remove link local address&lt;/span&gt;
    ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; route flush dev br1
    ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr flush dev br1

    &lt;span class=&quot;c&quot;&gt;# Re-add link local address&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# So route to fe80::/64 will be added back&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Note this is VERY important for 6relayd&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Otherwise 6relayd will throw network unreachable error&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Because route to fe80::/64 doesn't exist&lt;/span&gt;
    ip &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; addr add &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;link_local_ipv6&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt; dev br1
  &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the script is indeed invoked&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /tmp/000-dhcpc-event

&lt;span class=&quot;c&quot;&gt;# Adapted from odhcp6c-example-script.sh&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  flock 9
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in
    &lt;/span&gt;bound&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      teardown_br1
      setup_br1
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    informed|updated|rebound|ra-updated&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      setup_br1
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    stopped|unbound&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      teardown_br1
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    started&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      teardown_br1
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 9&amp;gt;/tmp/odhcp6c.lock.br1
&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /tmp/odhcp6c.lock.br1

&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/000-dhcpc-event
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;dnsmasq-conf-add&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/jffs/configs/dnsmasq.conf.add&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;If you need DHCPv6-PD (with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6relayd&lt;/code&gt;) for cascading router, or if you don’t care about IPv6:&lt;/p&gt;

&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;py&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 range: 192.168.150.2 - 192.168.150.254, netmask: 255.255.255.0
# DHCPv4 lease time: 86400s (1 day)
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,192.168.150.2,192.168.150.254,255.255.255.0,86400s&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 router (option 3): 192.168.150.1
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-option&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,3,192.168.150.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Otherwise, DHCPv6 is done by dnsmasq on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br1&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;py&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 range: 192.168.150.2 - 192.168.150.254, netmask: 255.255.255.0
# DHCPv4 lease time: 86400s (1 day)
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,192.168.150.2,192.168.150.254,255.255.255.0,86400s&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv4 router (option 3): 192.168.150.1
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-option&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,3,192.168.150.1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 RA interval: 10s, router lifetime: 600s
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;ra-param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,10,600&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 range: whole subnet, constructing from br1's prefix
# DHCPv6 prefix length: 64, mode: Stateless DHCPv6
# DHCPv6 lease time: 600s (10 minutes)
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,::,constructor:br1,ra-stateless,64,600&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DHCPv6 DNS (option 23): inherit from the router
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dhcp-option&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;br1,option6:23,[::]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:ax88u-openwrt&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;slh, &lt;em&gt;&lt;a href=&quot;https://forum.openwrt.org/t/asus-rt-ax88u-router/52275/2&quot;&gt;Reply: ASUS RT-AX88U Router&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:ax88u-openwrt&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:vlanctl&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;u128393, &lt;em&gt;&lt;a href=&quot;https://www.cnblogs.com/u128393/p/11629970.html&quot;&gt;RT-AC86U VLAN 配置 - vlanctl 篇&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:vlanctl&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:slaac&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Wikipedia, &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/IPv6_address#Stateless_address_autoconfiguration&quot;&gt;Stateless address autoconfiguration&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:slaac&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:prefix-hint&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;buddyp, &lt;em&gt;&lt;a href=&quot;https://www.snbforums.com/threads/ipv6-with-prefix-delegation.22834/#post-168667&quot;&gt;Reply: IPv6 with Prefix Delegation&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:prefix-hint&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:dnsmasq-author&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Simon Kelley, &lt;em&gt;&lt;a href=&quot;http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2014q1/008218.html&quot;&gt;[Dnsmasq-discuss] IPV6 Prefix Delegation (IA_PD)&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:dnsmasq-author&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:dhcp6-protocol&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Simon Kelley, &lt;em&gt;&lt;a href=&quot;https://github.com/RMerl/asuswrt-merlin.ng/blob/master/release/src/router/dnsmasq/src/dhcp6-protocol.h&quot;&gt;dnsmasq: dhcp6-protocol.h&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:dhcp6-protocol&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:rfc-3633&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;O. Troan, R. Droms, &lt;em&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc3633&quot;&gt;RFC 3633 - IPv6 Prefix Options for Dynamic Host Configuration Protocol (DHCP) version 6&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:rfc-3633&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:6relayd&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Steven Barth, &lt;em&gt;&lt;a href=&quot;https://github.com/RMerl/asuswrt-merlin.ng/tree/master/release/src/router/6relayd&quot;&gt;6relayd - Embedded DHCPv6/RA Server &amp;amp; Relay&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref:6relayd&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</content><author><name>Renjie Wu</name></author><category term="Network" /><summary type="html">Although there is no more `robocfg` command on HND platform and Asuswrt-Merlin lacks GUI support on creating VLAN, port-based VLANs (or static VLAN) can still be achieved by separating ethernet interfaces into isolated bridges and applying firewall (`ebtables` or `iptables`) rules.</summary></entry><entry xml:lang="en-us"><title type="html">Hello, World!</title><link href="https://wu.renjie.im/blog/others/hello-world/" rel="alternate" type="text/html" title="Hello, World!" /><published>2020-03-12T19:59:48-07:00</published><updated>2021-01-16T18:34:16-08:00</updated><id>https://wu.renjie.im/blog/others/hello-world</id><content type="html" xml:base="https://wu.renjie.im/blog/others/hello-world/">&lt;p&gt;I’m glad you found this place from somewhere on the Internet!&lt;/p&gt;

&lt;p&gt;Hope the following Java code snippet may give you the idea of this post ;)&lt;/p&gt;

&lt;!--more--&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;IntStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1214606444&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1865162839&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1869769828&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;555753482&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;mapToObj&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IntStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;iterate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                                    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;boxed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
                                    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                                    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ByteBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;allocate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
                                            &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;byteValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()),&lt;/span&gt;
                                            &lt;span class=&quot;nl&quot;&gt;ByteBuffer:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StandardCharsets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;UTF_8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Collectors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;joining&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;notice--info&quot;&gt;&lt;strong&gt;Tip:&lt;/strong&gt; You need JDK 9 or higher to compile the code above, or if you were lazy like me :P, &lt;a href=&quot;https://ideone.com/h7L6Xa&quot;&gt;click here&lt;/a&gt; to see the output.&lt;/p&gt;</content><author><name>Renjie Wu</name></author><category term="Others" /><summary type="html">I’m glad you found this place from somewhere on the Internet! Hope the following Java code snippet may give you the idea of this post ;)</summary></entry></feed>