在 AX88U + Merlin 384.19 上配置基于 RTL8156B 的 2.5GbE 网卡

主路由升级到 AX88U 已经有接近一年的时间,整体来说这台路由器非常不错:性能强悍、功能齐全。不过缺少板载的 2.5GbE 网卡属实为一大遗憾,尤其是考虑到其 CPU BCM49408 内建了对 2.5GbE 的支持1(华硕后来的 2.5GbE 产品 AX86U 就是基于这款 CPU 的)。

不过好消息是螃蟹家(Realtek)提供了一个经济的解决方案 —— RTL81562,基于 USB 3.0 的 2.5GbE 控制器。相比于贵的多的 5GbE 和 10GbE 的设备,它可以说是“相当廉价”了:30 美金左右就能买到基于 RTL8156 的 USB 网卡。

但是有一点需要特别注意,这个芯片有两个版本:RTL8156RTL8156B。我推荐购买后者这个 B 修订版的 RTL8156B,因为前者 RTL8156 在用上一段时间后会有些奇怪的稳定性问题3

此外如果买的是 USB-C 的网卡,我建议买一个“双面” USB-C 转 USB-A 的转接器(里面应该有个多路复用芯片,比如 VL1604 之类的)。不然使用非“双面”的转接器,必须搞清楚把 USB-C 头的哪一面插入到转接器里,因为只有一面能跑 USB 3.0,另一面只能跑 USB 2.0。

不能即插即用?

一切正常的话,AX88U 应该是能识别插入的 USB 网卡(在路由器管理界面的网络地图里会显示)。另外运行 ifconfig -a,也能发现网卡已经被注册为 usb0

然而一旦尝试启用网卡(ifconfig usb0 up),就会发现日志会被 cdc_ncm 这个模块刷屏:

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

造成这个问题的原因是 Linux 内核自带的驱动程序暂时还不支持 RTL8156 5,所以必须得自己编译驱动。

准备工作

编译 Linux 内核

有关如何配置梅林固件编译环境,请参阅这篇教程:Compiling under WSL2(英文)。虽然标题写的是在 WSL (Windows Subsystem for Linux) 2 里编译,但是总体步骤也适用于 WSL 1(也称 legacy WSL)和真·Linux 环境。

如果你跟我一样用的是 WSL 1,还需要额外配置 32 位运行环境(参考这个 issue),因为梅林固件提供的工具链都是 32 位的。

首先把梅林固件的源代码拖下来,因为用不到 git 的历史,只需要把 HEAD 拖下来即可:

# 只拖 HEAD
git clone --depth 1 https://github.com/RMerl/asuswrt-merlin.ng

教程里是把 brcm-arm-sdk 文件夹链接到了 src-rt-6.x-4708 里面:

# `src-rt-6.x.4708` 用于 AC56U, AC68U 和 AC87U
ln -s ~/am-toolchains/brcm-arm-sdk ~/asuswrt-merlin.ng/release/src-rt-6.x.4708/toolchains

而我们需要把它链接到 src-rt-5.02axhnd 里面,梅林固件的编译脚本6里有提到 AX88U 用的是 src-rt-5.02axhnd

# `src-rt-5.02axhnd` 用于 AX88U, AX58U 和 AX56U
ln -s ~/am-toolchains/brcm-arm-sdk ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/toolchains

接着就可以编译 AX88U 的梅林固件了:

# 目标平台 AX88U
cd release/src-rt-5.02axhnd && make rt-ax88u

由于我们只需要用到内核编译生成的头文件(.h),因此没必要把固件整个都编译出来,待内核编译流程开始之后,就可以按键盘上的 CTRL+C 终止固件编译。

编译测试工具

iperf3

iperf3 源代码从这里下载:esnet/iperf,本文使用的 iperf3 版本是 3.9。

运行下面的命令来为 AX88U 编译 iperf3

# 创建 build 文件夹,作为 iperf3 安装目录
mkdir build
# 静态链接
./configure --host=arm-linux --prefix=`pwd`/build --enable-static --disable-shared
# 编译并安装到 build 文件夹
make && make install

生成的 iperf3 二进制文件应该可以在 ./build/bin 文件夹下找到,预编译好的版本可以在这里下载:附录:预编译的二进制文件:预编译的测试工具

ethtool

ethtool 源代码从这里下载:kernel/software/network/ethtool,本文使用的 ethtool 版本是 5.8。

运行下面的代码来为 AX88U 编译 ethtool

# 创建 build 文件夹,作为 ethtool 安装目录
mkdir build
# 禁用 netlink,一是用不到,二是去除对 libmnl 的依赖
./configure --host=arm-linux --prefix=`pwd`/build --disable-netlink
# 编译并安装到 build 文件夹
make & make install

生成的 ethtool 二进制文件应该可以在 ./build/bin 文件夹下找到,预编译好的版本可以在这里下载:附录 1:预编译的二进制文件:预编译的测试工具

编译 r8152 驱动模块

你没看错,RTL8156B 的驱动模块确实叫 r8152,源码从这里下载:Realtek USB FE / GBE / 2.5G / Gaming Ethernet Family Controller Software,本文使用的 r8152 驱动模块版本是 v2.13.0。

为了验证买来的网卡是 RTL8156B 芯片的,可以在 rtl8152_get_drvinfo 函数里加上下面一句代码,这样就可以通过 ethtool 来获取芯片的版本:

--- source-2.13.0/r8152-original.c     2020-04-20 01:36:49.000000000 -0700
+++ source-2.13.0/r8152-modified.c     2020-10-06 23:47:07.123659400 -0700
@@ -16369,6 +16369,7 @@
        strlcpy(info->driver, MODULENAME, sizeof(info->driver));
        strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
        usb_make_path(tp->udev, info->bus_info, sizeof(info->bus_info));
+       snprintf(info->fw_version, sizeof(info->fw_version), "0x%04x", tp->version);
 } 

 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)

运行下面的命令来编译驱动:

# 架构: arm64
# 交叉编译器: aarch64-linux
# 内核源代码目录: ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1
make ARCH=arm64 CROSS_COMPILE=aarch64-linux- -C ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1 M=`pwd` modules

如果你倾向用 Makefile 的话,可以在这里找到:附录 2:脚本:Makefile

一切顺利的情况下,r8152.ko 这个文件会生成在当前目录下,预编译好的版本可以在这里下载:附录:预编译的二进制文件:预编译的驱动模块

配置驱动

首先在路由器 /jffs 文件夹内创建 driverstools 两个文件夹,然后把 r8152.ko 上传到路由器 /jffs/drivers 文件夹内,把编译好的 iperf3ethtool 上传到路由器 /jffs/tools 文件夹内。

加载驱动

前文“不能即插即用?”一节已经提到 cdc_ncm 会接管 USB 网卡,所以首先需要把 cdc_ncm 卸载掉。

运行 lsmod | grep cdc_ncm 可以看到依赖 cdc_ncm 的模块:

# admin@ax88u:/# lsmod | grep cdc_ncm
cdc_ncm                16787  1 cdc_mbim
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

所以得把 cdc_mbim 也一同卸载掉:

# 先卸载 cdc_mbim,因为它依赖于 cdc_ncm
rmmod cdc_mbim
# 卸载 cdc_ncm
rmmod cdc_ncm

现在就可以加载 r8152.ko 了,同时记得把 cdc_ncmcdc_mbim 也加载回来:

# 加载 r8152 驱动模块
insmod /jffs/drivers/r8152.ko
# 加载 cdc_ncm
insmod cdc_ncm
# 加载 cdc_mbim
insmod cdc_mbim

如果一切正常的话,系统日志(tail /tmp/syslog.log)会显示驱动加载成功:

# admin@ax88u:/# tail /tmp/syslog.log
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: add net eth8.
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

从上面的日志里可以看到 USB 网卡被注册为 eth8,运行 ifconfig eth8 可以验证这一点:

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)

在路由器管理界面的 网络地图 里也可以看到 USB 网卡:

网络地图中的 USB 网卡

接下来就可以更新 nvram 变量,启用 eth8 并把它加入网桥 br0 里:

# 更新 nvram 变量
nvram set br0_ifnames="$(nvram get br0_ifnames) eth8"
nvram set lan_ifnames="$(nvram get lan_ifnames) eth8"
nvram set wired_ifnames="$(nvram get wired_ifnames) eth8"

# 把 eth8 加入网桥 br0,然后启用 eth8
brctl addif br0 eth8
ifconfig eth8 allmulti up

最后插入网线,运行 /jffs/tools/ethtool eth8 来验证协商的速度为全双工 2500Mb/s:

# admin@ax88u:/# /jffs/tools/ethtool eth8
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
        Speed: 2500Mb/s
        Duplex: Full
        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
        Link detected: yes

提示:完整的 RTL8156B 配置脚本可以在这里找到:附录:脚本:RTL8156B 配置脚本

验证 RTL 芯片版本

运行 /jffs/tools/ethtool --driver eth8

# admin@ax88u:/# /jffs/tools/ethtool --driver eth8
driver: r8152
version: v2.13.0 (2020/04/20)
firmware-version: 0x000e
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
  • 如果 firmware-version0x000b0x000c,则芯片为 RTL8156
  • 如果 firmware-version0x000d0x000e,则芯片为 RTL8156B

这里给出的输出结果中的 firmware-version0x000e,因此证明我的网卡芯片为 RTL8156B

注意:为了显示 firmware-version, 必须在 rtl8152_get_drvinfo 函数中添加一句代码,详情请参阅准备工作:编译 r8152 驱动模块

性能优化

完整的 RTL8156B 配置脚本可以在这里找到:附录:脚本:RTL8156B 配置脚本

接收(RX)

默认情况下,AX88U 上只有 4 号 CPU 核心为 xhci-hcd:usb1 响应硬件中断(cat /proc/irq/28/smp_affinity_list)。而且由于 RTL8156B 只有一个接收队列,也没法通过改变 smp_affinity_list 的方式,把硬件中断请求分散到其他核心去处理。

因此必须启用 RPS (Receive Packet Steering) 来分配软件中断(softirq)到各个核心,以达到优化接收性能的目的。有关 RPS 的更多信息,可以参考 Red Hat 的一篇文档:Performance Tuning Guide: 8.7 Receive Packet Steering(英文)。

运行下面的命令在 eth8 上启用 RPS:

# 在 eth8 上启用 RPS (Receive Packet Steering)
# 因为 AX88U 有四个核心,所以这里设置为 f
echo f > /sys/class/net/eth8/queues/rx-0/rps_cpus

我之后进行的测试表明仅启用 RPS 已经足以在 iperf3 跑到理论峰值速度,但是这里还是给出一些别的优化方法:

  • 增加 net.core.netdev_max_backlog。默认值为 1000,可以增加到 2500
    # 1000 是 1GbE 的默认值,因此对 2.5GbE 来说 2500 看起来很合理
    echo 2500 > /proc/sys/net/core/netdev_max_backlog
    
  • 增加 RX 中断合并窗口(从而减少产生的中断数量)。rx-usecs 的默认值为 15,运行以下命令以修改:
    # <N> 是数据包达到后产生 RX 中断的延迟时间,单位为毫秒。
    /jffs/tool/ethtool -C eth8 rx-usecs <N>
    
  • 增加 RX 缓冲区大小。默认值为 100,可以增加到 4096(最大值):
    # 4096 是 RX 缓冲区大小的最大值
    /jffs/tool/ethtool -G eth8 rx 4096
    

这三篇文章(英文)介绍了更多优化接收性能的方法:Performance Tuning on Linux — EthernetHow to achieve low latency with 10Gbps EthernetPerformance Tuning Guide: Chapter 8. Networking

发送(TX)

不像 RPS,启用 XPS (Transmit Packet Steering) 对于提升 RTL8156B 的发送性能没有帮助,这是因为 RTL8156B 只有一个发送队列,并且:

For a network device with a single transmission queue, XPS configuration has no effect, since there is no choice in this case.

对于只有一个发送队列的网络设备,启用 XPS 不会起到任何效果,因为能用的发送队列就只有一个。

Linux 内核文档 — Scaling in the Linux Networking Stack

有关发送性能优化的方法并不多,其中一个是把 txqueuelen 增加到 2500

# 1000 是 1GbE 的默认值,因此对 2.5GbE 来说 2500 看起来很合理
ifconfig eth8 txqueuelen 2500

不知道为什么 Realtek 在内核版本低于 5.2.3 时(梅林 384.19 的内核版本号为 4.1.51),默认不启用 RTL8156B 的 USB scatter/gather:

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,3)
    if (usb_device_no_sg_constraint(udev))
        tp->sg_use = true;
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,3) */

然而不启用这个功能会严重影响发送性能,因此另外一个优化方法是启用 RTL8156B 的 USB scatter/gather:

# 在 eth8 上启用 USB scatter/gather
echo enable > /sys/class/net/eth8/rtl_adv/sg_en

注意: 该选项仅适用于 r8152 驱动模块支持的 RTL 芯片。

性能测试

iperf3

该项测试中 AX88U 是服务端,我的 Windows 台式机是客户端。

台式机到 AX88U,最快 2.35Gbits/sec:

PS E:\Tools\iperf-3.9-win64> .\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.

AX88U 到台式机,最快 2.38Gbits/sec:

PS E:\Tools\iperf-3.9-win64> .\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.

SMB 文件传输

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

测试结果表明 BCM49408 的性能不足以双向跑满 2.5 Gbps,但是也还算可以了:最大传输速度约 195.7MB/s,平均传输速度约 177.3MB/s。

SMB 文件传输速度测试

提示:在 Windows 上运行这个命令可以快速创建一个 20GB 的文件:fsutil file createNew 20GB.txt 21474836480。最后一个参数为要创建的文件的大小,单位为字节。

实现 5GbE

截至本文发布时,市面上基于 USB 的 5GbE 解决方案只有 Aquantia 家(已经被 Marvell7 收购了)的 AQC111U。就像一开始说的,5GbE 网卡并不便宜,我找到的最便宜的也得要 60 美金。

而且因为 AQC111U 是 USB 3.1 Gen 1 的方案,哪怕是启用 9K 巨型帧,减去 USB 开销8和以太网开销9,理论上能达到的最大传输速度约 3.96 Gbps。

同时 BCM49408 的性能也不足以支撑这个速度,启用了“性能优化”一章中描述的所有性能优化方法后,在我的 iperf3 测试中也只能实现最大 3.35 Gbits/sec(AX88U 到台式机)和 1.75 Gbits/sec(台式机到 AX88U)。

除此之外 AQC111U 还有以下的问题:

  • 驱动不稳定。在短暂运行 iperf3 之后,我的 AX88U 直接 kernel panic 然后重启了。
  • 发热很猛,容易掉线。传输过程中网卡会变得非常热,然后不久就失去网络连接了。不太清楚是 AQC111U 的问题,还是我买的网卡(Sabrent NT-SS5G)的散热设计的问题。

编译 aqc111 驱动模块

如果还是想试一下 AQC111U,可以从这里下载驱动:Marvell Drivers。在下载页面的 PLATFORM 下拉框里选择 Linux Kernel 3.10 and Higher,搜索结果中的 Marvell AQtion USB 3.1 Linux Driver 即为所需驱动,本文使用的 aqc111 驱动模块版本是 v1.3.3.0。

运行下面的命令来编译驱动:

# 架构: arm64
# 交叉编译器: aarch64-linux
# 内核源代码目录: ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1
make ARCH=arm64 CROSS_COMPILE=aarch64-linux- -C ~/asuswrt-merlin.ng/release/src-rt-5.02axhnd/kernel/linux-4.1 SUBDIRS=`pwd` modules

如果你倾向用 Makefile 的话,可以在这里找到:附录 2:脚本:Makefile

一切顺利的情况下,aqc111.ko 这个文件会生成在当前目录下,预编译好的版本可以在这里下载:附录:预编译的二进制文件:预编译的驱动模块

配置驱动 & 性能优化

aqc111.ko 上传到路由器 /jffs/drivers/ 文件夹内,如果该文件夹不存在,则首先在 /jffs 文件夹下创建 drivers 文件夹。

AQC111U 的配置流程和 RTL8156B 的有些许不同,这里需要卸载的是模块是 cdc_ether

# 卸载 rndis_host,因为它依赖于 cdc_ether
rmmod rndis_host
# 卸载 cdc_ether
rmmod cdc_ether
# 加载 aqc111.ko
insmod /jffs/drivers/aqc111.ko
# 加载 cdc_ether
insmod cdc_ether
# 加在 rndis_host
insmod rndis_host

针对 AQC111U 的性能优化则和 RTL8156B 的差不多,只是没法调整 RX 中断合并窗口和 RX 缓冲区大小,因为 aqc111 驱动模块不支持修改这两个属性。

提示:完整的 AQC111U 配置脚本可以在这里找到:附录:脚本:AQC111U 配置脚本

总结

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

另外还有一个好消息:QNAP 最近发布了一款小型(相比其他至少要 1U 的产品)的被动散热 5 口 2.5GbE 交换机 QNAP QSW-1105-5T10,售价为 100 美金,算是物美价廉吧,适合家庭使用。

附录:预编译的二进制文件

预编译的驱动模块

以下驱动模块仅适用于 AX88U(上传到 /jffs/drivers/):

  • r8152 驱动模块 v2.13.0:r8152.ko。SHA1: e3a9f7a868baae6756bde4665a45852fcd578bdd
  • aqc111 驱动模块 v1.3.3.0:aqc111.ko。SHA1: 9dc4768154e065d19a274dcc33235a6b58fd9fb9

预编译的测试工具

以下测试工具仅适用于 AX88U(上传到 /jffs/tools/):

  • ethtool 5.8:ethtool。SHA1: 6936931589476b2001667c50a8f91d713be705fb
  • iperf3 3.9:iperf3。SHA1: ec19717ecb56a5b5bbfeda3316cd7e712cb6bde0

附录:脚本

Makefile

以下 Makefile 仅适用于 AX88U:

  • r8152r8152/Makefile。SHA1: dc22346bdae40f5ea5bb2a0c193dc922fa3e4b60
  • aqc111acq111/Makefile。SHA1: 37dfc73f2e4b6676e5dd712ad38b389f0140fb76

RTL8156B 配置脚本

/jffs/scripts/init-start

#!/bin/sh

# Make sure the script is indeed invoked
touch /tmp/001-init-start
logger -t "rtl8156" "init-start: loading RTL8156 driver..."

# It's safe to `insmod` here, since `usbcore` has already been 
# installed before `init-start` was called. 
# init.c: sysinit() -> init_wl() -> 
#         init-broadcom.c: eval("insmod", "usbcore");
insmod /jffs/drivers/r8152.ko

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

logger -t "rtl8156" "init-start: all done"
date >> /tmp/001-init-start

/jffs/scripts/services-start

#!/bin/sh

# Make sure the script is indeed invoked
touch /tmp/001-services-start
logger -t "rtl8156" "services-start: setting up eth8..."

# Update nvram variables
nvram set br0_ifnames="$(nvram get br0_ifnames) eth8"
nvram set lan_ifnames="$(nvram get lan_ifnames) eth8"
nvram set wired_ifnames="$(nvram get wired_ifnames) eth8"

# Add eth8 into br0
brctl addif br0 eth8

# Set TX queue length to 2500 on eth8 and bring it up
ifconfig eth8 txqueuelen 2500 allmulti up

# Enable USB scatter/gather on eth8
echo enable > /sys/class/net/eth8/rtl_adv/sg_en

# Enable RPS (Receive Packet Steering) on eth8.
# Since AX88U has four cores, we set it to 'f'
echo f > /sys/class/net/eth8/queues/rx-0/rps_cpus

logger -t "rtl8156" "services-start: all done"
date >> /tmp/001-services-start

AQC111U 配置脚本

尽管能在 AX88U 上使用 AQC111U,但是发挥不出来 5Gbps 的性能,详情请参阅章节 实现 5GbE

/jffs/scripts/services-start

#!/bin/sh

# Make sure the script is indeed invoked
touch /tmp/001-services-start
logger -t "aqc111" "services-start: loading AQC111 driver..."

# No need to `rmmod cdc_ether` here, as `cdc_ncm` will be loaded 
# after `services-start` is called
insmod /jffs/drivers/aqc111.ko

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

# Now we can setup the new interface
logger -t "aqc111" "services-start: setting up eth8..."

# Update nvram variables
nvram set br0_ifnames="$(nvram get br0_ifnames) eth8"
nvram set lan_ifnames="$(nvram get lan_ifnames) eth8"
nvram set wired_ifnames="$(nvram get wired_ifnames) eth8"

# Add eth8 into br0 and bring eth8 up
brctl addif br0 eth8
ifconfig eth8 allmulti up

# Enable RPS (Receive Packet Steering) on eth8.
# Since AX88U has four cores, we set it to 'f'.
echo f > /sys/class/net/eth8/queues/rx-0/rps_cpus

logger -t "aqc111" "services-start: all done"
date >> /tmp/001-services-start

参考文献