目录

J4125 Router All In One

集路软由,NAS,透明代理(旁路由)为一体

需求分析

手上有台 J4125 的机子:

  • 4x 1Gbps RJ45(i211)
  • 8G RAM
  • 32G mSATA
  • 1T SATA HDD

单纯的做软路由有点性能过剩,单纯的做 NAS 又浪费了网口。网络上有不少装 ESXi 跑虚拟机的教程,但我追求的是资源利用最大化,J4125 这小身板和 8G 的内存顶不住啊。所以我使用 Arch Linux 做宿主系统,在纯 QEMU 上运行 iKuai 路由,不涉及内核且能在 Linux 上运行的服务则用 LXC 进行隔离。

为什么选择 Arch Linux 做宿主系统:

  1. 更新激进,可以体验最新的特性。
  2. 拥有内容丰富的 Wiki 你所遇到的疑难杂症基本都能在这里面找到。
  3. 软件包丰富。

网络结构:

1
2
3
4
5
6
7
8
9
----------------------
|       iKuai    |LXC|
---|------|----|---|---------
| PCI  | PCI  |br-lan|  Sys |
---|------|-------|------|---
| eth0 | eth1 | eth2 | eth3 |
---|------|-------|------|---
| WAN  |     LAN     |
----------------------

eth3 不使用并启动 DHCP 客户端,防止虚拟机崩溃时无法进入系统,届时直接用此接口连接其他路由器即可。

安装 Arch Linux 并配置

下载官方的 Arch Linux 镜像,按 Wiki 中的教程安装。

所需的组件:linux linux-firmware base intel-ucode sudo grub efibootmg openssh

你也可以去以下镜像下载:

修改网卡名称并为 eth3 配置 DHCP:

Arch Linux 会默认将网卡识别并命名为 enp1s0enp2s0eno1enp4s0,我们将其命名为 ethx 会更好辨认。创建并编辑以下文件:

/etc/systemd/network/10-eth0.link

1
2
3
4
5
6
[Match]
MACAddress=00:e2:69:27:da:a3

[Link]
Description=Ethernet 0
Name=eth0

/etc/systemd/network/11-eth1.link

1
2
3
4
5
6
[Match]
MACAddress=00:e2:69:27:da:a4

[Link]
Description=Ethernet 1
Name=eth1

/etc/systemd/network/12-eth2.link

1
2
3
4
5
6
[Match]
MACAddress=00:e2:69:27:da:a5

[Link]
Description=Ethernet 2
Name=eth2

/etc/systemd/network/13-eth3.link

1
2
3
4
5
6
[Match]
MACAddress=00:e2:69:27:da:a6

[Link]
Description=Ethernet 3
Name=eth3

/etc/systemd/network/23-eth3.network

1
2
3
4
5
[Match]
Name=eth3

[Network]
DHCP=yes

系统启动后应当使用以下指令启动三个服务:

1
2
3
sudo systemctl enable --now systemd-networkd
sudo systemctl enable --now systemd-resolved
sudo systemctl enable --now sshd # 启动 SSH 服务

准备虚拟机环境

创建网桥:

创建网桥 br-lan 并将 eth2 加入网桥

/etc/systemd/network/br-lan.netdev

1
2
3
4
[NetDev]
Name=br-lan
Kind=bridge
MACAddress=00:e2:69:27:da:a7

/etc/systemd/network/22-eth2.network

1
2
3
4
5
[Match]
Name=eth2

[Network]
Bridge=br-lan

br-lan 将从 ikuai 的 DHCP 服务获取 IP 地址,建议在 ikuai 中设置静态 IP 方便进入管理。

/etc/systemd/network/br-lan.network

1
2
3
4
5
[Match]
Name=br-lan

[Network]
DHCP=yes

需重启 systemd-networkd: sudo systemctl restart systemd-networkd

安装 QEMU 和 OVMF :

直接使用包管理器安装

1
sudo pacman -S qemu-headless edk2-ovmf

启用 IOMMU:

修改 /etc/default/grub

GRUB_CMDLINE_LINUX_DEFAULT= 条目内添加 intel_iommu=on iommu=pt

修改完成后使用 sudo grub-mkconfig -o /boot/grub/grub.cfg 生成新配置文件。

使用以下脚本可以查看 IOMMU 分组:

1
2
3
4
5
6
7
#!/bin/bash
shopt -s nullglob
for d in /sys/kernel/iommu_groups/*/devices/*; do
    n=${d#*/iommu_groups/*}; n=${n%%/*}
    printf 'IOMMU Group %s ' "$n"
    lspci -nns "${d##*/}"
done;

加载 virtio 内核模块:

编辑 /etc/modules-load.d/virtio-net.conf

1
2
3
virtio-net
virtio-pci
virtio

重启生效,加载这些模块后,在主机上执行 lsmod | grep virtio 不应返回空。

加载 vfio 内核模块:

编辑 /etc/modules-load.d/vfio-net.conf

1
2
3
4
5
vfio_iommu_type1
vfio-pci-core
vfio-pci
vfio
vfio_virqfd

网络相关设置

启用 IP 转发:

启用内核转发,顺便设置一下其他参数最大连接数。

编辑 /etc/sysctl.d/60-net.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
net.ipv4.ip_forward = 1
net.ipv6.conf.default.forwarding = 1
net.ipv6.conf.all.forwarding = 1
# 最大连接数
net.netfilter.nf_conntrack_max = 65535
# TCP fastopen
net.ipv4.tcp_fastopen = 3
# BBR
net.core.default_qdisc = cake
net.ipv4.tcp_congestion_control = bbr

sudo sysctl -p /etc/sysctl.d/60-net.conf 立即生效。

不确定配置文件中的注释对系统运行是否有影响,请在复制时自行清除。

创建虚拟机

创建磁盘:

1
qemu-img create -f raw ikuai.img 4G

首次安装: 通过 spice://hostname:5930 进入安装

1
2
3
4
5
6
7
8
9
qemu-system-x86_64 \
-enable-kvm \
-bios /usr/share/ovmf/x64/OVMF_CODE.fd \
-smp 4 -m 3456 \
-cdrom iKuai8_x64_3.5.11_Build202112031159.iso \
-hda ikuai.img \
-vga qxl -device virtio-serial-pci -spice port=5930,disable-ticketing \
-device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0 \
-chardev spicevmc,id=spicechannel0,name=vdagent

分离设备并进行首次运行设置:

从主机分离并 bind 到 vfio

1
2
3
echo "0000:01:00.0" > /sys/bus/pci/devices/0000\:01\:00.0/driver/unbind
echo "0000:02:00.0" > /sys/bus/pci/devices/0000\:02\:00.0/driver/unbind
echo "8086 1539" > /sys/bus/pci/drivers/vfio-pci/new_id

修改 ACL :

1
2
3
sudo mkdir -p /etc/qemu
sudo touch /etc/qemu/bridge.conf
sudo chown 0640 /etc/qemu/bridge.conf

修改 /etc/qemu/bridge.conf

1
allow br-lan

启动虚拟机:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
qemu-system-x86_64 \
-enable-kvm \
-bios /usr/share/ovmf/x64/OVMF_CODE.fd \
-smp 4 -m 2048 \
-device vfio-pci,host=01:00.0 \
-device vfio-pci,host=02:00.0 \
-net nic,model=virtio -net bridge,br=br-lan \
-hda ikuai.img \
-vga qxl -device virtio-serial-pci -spice port=5930,disable-ticketing \
-device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0 \
-chardev spicevmc,id=spicechannel0,name=vdagent

其中 -net nic,model=virtio -net bridge,br=br-lan 可以换成以下写法。

1
2
-netdev bridge,id=hn0,br=br-lan \
-device virtio-net-pci,netdev=hn0,id=nic0 \

设置开机自启:

需要软件包:gnu-netcat

/opt/ikuai/env

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
args="-enable-kvm \
-bios /usr/share/ovmf/x64/OVMF_CODE.fd \
-smp 4 -m 2048 \
-device vfio-pci,host=01:00.0 \
-device vfio-pci,host=02:00.0 \
-net nic,model=virtio -net bridge,br=br-lan \
-hda /opt/ikuai/ikuai.img -vga none \
-serial telnet:localhost:7000,server,nowait,nodelay \
-monitor telnet:localhost:7100,server,nowait,nodelay -vnc :0"

haltcmd="echo 'system_powerdown' | nc localhost 7100"

/opt/ikuai/vfiobind

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#!/bin/bash
if [ ! -e "/dev/vfio/14" ];
then
    if [ -e "/sys/bus/pci/devices/0000:01:00.0/driver/unbind" ];
    then
        echo "Unbind from system..."
        echo "0000:01:00.0" > /sys/bus/pci/devices/0000\:01\:00.0/driver/unbind
        echo "0000:02:00.0" > /sys/bus/pci/devices/0000\:02\:00.0/driver/unbind
        echo "8086 1539" > /sys/bus/pci/drivers/vfio-pci/new_id
    else
        echo "Bind to vfio..."
        echo "0000:01:00.0" > /sys/bus/pci/drivers/vfio-pci/bind
        echo "0000:02:00.0" > /sys/bus/pci/drivers/vfio-pci/bind
    fi
else
    echo "Nothings to do."
fi

/etc/systemd/system/ikuai.service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Unit]
Description=iKuai virtual machine

[Service]
Group=root
User=root
Environment="haltcmd=kill -INT $MAINPID"
EnvironmentFile=/opt/ikuai/env
ExecStartPre=/opt/ikuai/vfiobind
ExecStart=/usr/bin/qemu-system-x86_64 -name ikuai $args
ExecStop=/usr/bin/bash -c ${haltcmd}
ExecStop=/usr/bin/bash -c 'while nc localhost 7100; do sleep 1; done'

[Install]
WantedBy=multi-user.target

sudo systemctl enable --now ikuai

共享磁盘设置

所需软件包:hdparm

磁盘测速:

sudo hdparm -Tt /dev/sda

设置磁盘休眠: 磁盘 sda 将在 10min 后休眠

sudo hdparm -B 127 -S 120 /dev/sda

持久化设置:

/etc/udev/rules.d/69-hdparm.rules

1
ACTION=="add", SUBSYSTEM=="block", KERNEL=="sda", RUN+="/usr/bin/hdparm -B 127 -S 120 /dev/sda"

挂载磁盘:

创建挂载文件夹:sudo mkdir -p /mnt/share

手动挂载:sudo mount /dev/sda1 /mnt/share

自动挂载:修改 /etc/fstab

1
UUID=74e9771c-be8d-43aa-8355-f8f1b6141c3b   /mnt/share  btrfs   rw,relatime,space_cache,subvolid=5,subvol=/ 0   0

SMB 共享

Arch Linux 自带 ksmbd 模块。但是我们仍需要手动编译 ksmbd-tools,所需软件包:base-devel

1
2
3
4
5
6
curl https://download.fastgit.org/cifsd-team/ksmbd-tools/releases/download/3.4.3/ksmbd-tools-3.4.3.tar.gz -o ksmbd-tools-3.4.3.tar.gz
tar -xzf ksmbd-tools-3.4.3.tar.gz
cd ksmbd-tools-3.4.3
./configure
make
sudo make install

配置:

1
2
3
4
sudo mkdir -p /etc/ksmbd
sudo touch /etc/ksmbd/smb.conf
sudo ksmbd.adduser -a $USER
sudo ksmbd.addshare -a share -o "writable = yes, path = /mnt/share"

启动测试:

加载模块:sudo modprobe ksmbd
启动:sudo ksmbd.mountd
关闭:sudo ksmbd.control -s
卸载模块:sudo rmmod ksmbd

开机自启:

/etc/systemd/system/ksmbd.service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
[Unit]
Description=ksmbd userspace daemon
Wants=network-online.target
After=network.target network-online.target

[Service]
Type=oneshot
User=root
Group=root
RemainAfterExit=yes
ExecStartPre=-/usr/local/sbin/modprobe ksmbd
ExecStart=/usr/local/sbin/ksmbd.mountd -s
ExecReload=/bin/sh -c '/usr/local/sbin/ksmbd.control -s && /usr/local/sbin/ksmbd.mountd -s'
ExecStop=/usr/local/sbin/ksmbd.control -s

[Install]
WantedBy=multi-user.target

sudo systemctl enable --now ksmbd

NFS 共享

所需软件包:nfs-utils

添加分享路径:

/etc/exports

1
/mnt/share  *(rw,sync)

若修改了配置文件需要执行 sudo exportfs -arv 使其生效。

启动:

sudo systemctl enable --now nfs-server

调优:

修改 /etc/nfs.conf 将线程数设置为 8 及以上:

1
2
[nfsd]
threads=16

重启服务:sudo systemctl restart nfs-server

torrent 下载服务

所需软件包:transmission-cli

覆写启动用户:

创建文件夹 sudo mkdir -p /etc/systemd/system/transmission.service.d/,修改 /etc/systemd/system/transmission.service.d/$USER.conf

$USER 改为自己的用户名

1
2
3
[Service]
Group=$USER
User=$USER

sudo systemctl enable --now transmission

403: Forbidden 错误:

停止服务,编辑 ~/.config/transmission-daemon/settings.json,向 rpc-whitelist 中添加白名单 IP 或将 rpc-whitelist-enabled 设置为 false 关闭白名单模式。随后重新启动服务即可。

原版界面过于简陋:

停止服务,使用 https://github.com/ronggang/transmission-web-control 项目中的 src/ 替换 /usr/share/transmission/web/ 随后重新启动服务即可。(注意文件权限)

设置 UDP 缓冲区:

编辑 /etc/sysctl.d/61-transmission.conf

1
2
net.core.rmem_max = 4194304
net.core.wmem_max = 1048576

sudo sysctl -p /etc/sysctl.d/61-transmission.conf 立即生效。

LXC 旁路由

所需软件包:lxc

1
2
sudo lxc-create -n clash -t download -- -d archlinux -a amd64 \
-r current --server mirrors.bfsu.edu.cn/lxc-images --no-validate

/var/lib/lxc/clash/config

1
2
3
4
5
6
lxc.mount.auto = proc:mixed sys:mixed cgroup:mixed

lxc.net.0.type = veth
lxc.net.0.link = br-lan
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:e2:69:27:da:a8

sudo systemctl enable --now lxc@clash