1. 为什么一块免驱网卡在Ubuntu上反而更折腾TP-LINK TL-XDN7000H 这个型号在电商页面上写的是免驱版很多人的第一反应是插上就能用。我当初也是这么想的结果插到 Ubuntu 20.04 的机器上lsusb能看到设备ip link里却什么都没有dmesg里刷了一堆usb 1-2: new high-speed USB device之后就没了下文。所谓免驱准确说是在 Windows 下免驱——厂商把驱动打包进了 Windows 的安装程序或者直接内置在系统驱动库里Linux 这边压根没管。这块卡本质上是 RTL8811CU / RTL8821CU 芯片方案的贴牌产品市面上大量 USB 双频网卡都是这个方案。Linux 内核主线对 8811CU 的支持一直不完整Ubuntu 20.04 自带的 5.4 内核里没有可用的驱动模块所以你必须自己编译第三方驱动。而重启失效这个坑几乎每个手动编译过这个驱动的人都踩过——编译完insmod能用一重启就回到解放前。这篇内容适合三类人一是刚装完 Ubuntu 20.04、手头只有这块 USB 网卡的新手二是编译过驱动但被重启失效折磨过的中级用户三是想搞清楚 Linux 驱动加载机制、不想每次都靠玄学重装解决问题的折腾党。我会把芯片识别、驱动选型、编译安装、开机自动加载、以及重启失效的根因和彻底修复方案完整走一遍所有命令都可以直接复制执行。先说结论重启失效的核心原因通常不是驱动编译错了而是模块没有被正确安装到内核模块目录或者模块被内核自带的冲突模块抢先占用。搞清这两点问题就解决了一大半。2. 动手之前先把芯片和系统底细摸清楚2.1 用 lsusb 确认芯片真实身份不要相信包装盒上写的型号直接看 USB 描述符。插上网卡执行lsusb你会看到类似这样一行Bus 001 Device 004: ID 2357:010c TP-Link TL-XDN7000H关键在2357:010c这个 VID:PID 组合。2357是 TP-LINK 的厂商 ID010c是产品 ID。这个 ID 对应的就是 RTL8811CU 方案。如果你看到的是0bda:1a2b或者0bda:c811那说明芯片是 Realtek 原厂 ID驱动选择会略有不同但大方向一致。提示有些批次的卡在插入瞬间会先以CD-ROM 模式出现模拟一个驱动安装盘过几秒才切换成网卡模式。如果你lsusb只看到一个存储设备等 5 秒再执行一次。2.2 确认内核版本和头文件是否齐全编译任何内核模块linux-headers必须和当前运行内核版本严格对应。先查uname -r比如输出5.4.0-150-generic。然后确认头文件dpkg -l | grep linux-headers-$(uname -r)如果没有输出说明头文件没装先补上sudo apt update sudo apt install -y linux-headers-$(uname -r) build-essential git dkms这里我特意把dkms一起装了。DKMSDynamic Kernel Module Support是解决内核升级后驱动失效的关键工具后面会详细讲它怎么用。很多人只装build-essential就开干结果内核一升级驱动又没了白折腾。2.3 检查是否已有冲突模块在捣乱Ubuntu 20.04 内核里自带了一些 Realtek 的通用模块比如rtl8xxxu、rtw88系列。这些模块有时会抢先绑定你的网卡导致你编译的驱动加载不上。先看看有没有lsmod | grep -E rtl|rtw|8811|8821如果看到rtl8xxxu之类的模块先记下来后面要把它加入黑名单。这一步是很多人忽略的也是编译成功但网卡不工作的常见原因。3. 驱动源码怎么选三个主流方案的真实对比3.1 方案一aircrack-ng 维护的 rtl8812au 分支这是最老牌的方案GitHub 上aircrack-ng/rtl8812au仓库同时支持 8811CU、8812AU、8821AU 等多个芯片。优点是社区活跃、issue 多、遇到问题容易搜到答案缺点是仓库主要面向 8812AU对 8811CU 的支持是顺带的某些内核版本下编译会报错。克隆和编译git clone https://github.com/aircrack-ng/rtl8812au.git cd rtl8812au make sudo make install3.2 方案二brektrou 的 rtl8821cu 专用仓库brektrou/rtl8821cu是专门针对 8821CU/8811CU 的驱动代码更聚焦。我在 Ubuntu 20.04 5.4 内核上实测这个仓库编译最顺报错最少。推荐新手优先用这个git clone https://github.com/brektrou/rtl8821cu.git cd rtl8821cu make sudo make install3.3 方案三morrownr 的 8821cu 仓库最推荐morrownr/8821cu-20210916是目前维护最勤、对新内核兼容最好的仓库。作者 morrownr 专门做 Realtek USB 网卡驱动文档写得非常清楚还内置了 DKMS 支持。如果你不想后面被内核升级搞死直接用这个git clone https://github.com/morrownr/8821cu-20210916.git cd 8821cu-20210916 sudo ./install-driver.sh这个脚本会自动处理 DKMS 注册、模块安装、冲突模块黑名单基本是一键到位。下面我以这个方案为主线把每一步拆开讲清楚因为一键脚本虽然方便但出问题时你得知道它到底干了什么。方案仓库优点缺点推荐场景方案一aircrack-ng/rtl8812au社区大、资料多非专用、易报错有编译经验的老手方案二brektrou/rtl8821cu专用、编译顺维护频率一般新手快速上手方案三morrownr/8821cu维护勤、带DKMS需要读脚本长期稳定使用3.4 为什么我最终选了 morrownr 方案说个真实经历。我最早用方案一编译过了insmod也加载了但网卡只能看到 2.4G 频段5G 死活出不来。换方案二之后 5G 正常了但每次内核小版本升级比如从 5.4.0-148 升到 5.4.0-150驱动就失效得重新编译。后来换到方案三脚本里自动注册了 DKMS内核升级后 DKMS 会自动重新编译模块彻底解放。DKMS 的原理说白了就是它把你的驱动源码注册到系统里每次内核更新时自动触发重新编译。你可以在/var/lib/dkms/下看到注册记录。这是解决重启失效和升级失效的治本方案强烈建议所有人都用带 DKMS 的仓库。4. 编译安装的完整链路与每一步的真实意图4.1 安装依赖为什么这几个包一个都不能少sudo apt update sudo apt install -y build-essential dkms git bc linux-headers-$(uname -r)逐个解释build-essential提供gcc、make等编译工具链没有它make直接报 command not found。dkms动态内核模块支持解决内核升级后驱动失效。git拉取源码。bc这个包很多人不知道为什么要装。内核模块编译过程中会调用bc做数学计算缺了它会报/bin/sh: 1: bc: not found编译中断。linux-headers-$(uname -r)内核头文件提供编译所需的Module.symvers、include/等。注意linux-headers的版本必须和uname -r完全一致。如果你刚升级过内核但还没重启uname -r显示的是旧内核而apt装的是新内核头文件编译会失败。这种情况先重启一次再操作。4.2 拉源码与编译make 背后发生了什么git clone https://github.com/morrownr/8821cu-20210916.git cd 8821cu-20210916 make clean makemake这一步会调用内核的 kbuild 系统把驱动源码编译成8821cu.ko这个内核模块文件。编译过程中你会看到大量CC [M]开头的输出[M]表示编译的是模块module而非内置进内核。如果编译报错最常见的是两类内核版本不兼容报implicit declaration of function之类的错误。解决办法是换仓库或者手动打补丁。morrownr 的仓库一般不会遇到。头文件路径不对报No such file or directory: /lib/modules/xxx/build。说明linux-headers没装对回到 4.1 重装。4.3 安装模块make install 到底装到哪了sudo make install这一步做了三件事把8821cu.ko复制到/lib/modules/$(uname -r)/kernel/drivers/net/wireless/目录下。执行depmod -a更新模块依赖关系数据库。如果配置了 DKMS还会把源码复制到/usr/src/并注册到 DKMS。你可以验证一下ls /lib/modules/$(uname -r)/kernel/drivers/net/wireless/ | grep 8821看到8821cu.ko就说明装好了。4.4 加载模块并验证sudo modprobe 8821cu然后检查lsmod | grep 8821cu ip linkip link里应该出现一个wlx开头的网卡接口。如果没出现看dmesg最后几行dmesg | tail -30常见错误和处理dmesg 报错原因解决module verification failed内核签名校验关闭 secure boot 或签名模块unknown symbol模块依赖缺失执行sudo depmod -a后重新 modprobedevice not claimed冲突模块占用黑名单冲突模块无任何输出模块没加载检查lsmod手动insmod看报错5. 重启失效的根因拆解与彻底修复5.1 为什么重启后驱动就没了这是全文最关键的部分。重启失效通常有三个层次的原因很多人只解决了第一层就以为搞定了结果下次重启又失效。第一层模块没有配置开机自动加载。modprobe是临时加载重启后内核不会自动加载你的模块。需要在/etc/modules里加上模块名或者依赖/etc/modprobe.d/配置。第二层冲突模块抢先绑定。即使你配置了自动加载内核自带的rtl8xxxu可能比你的8821cu先加载抢先占用了 USB 设备。这时候你的模块加载了也没用因为设备已经被别人拿走了。第三层内核升级导致模块失效。模块是针对特定内核版本编译的内核一升级旧模块的 vermagic 对不上加载会报version magic mismatch。这就是 DKMS 要解决的问题。5.2 配置开机自动加载的正确姿势先创建模块配置文件echo 8821cu | sudo tee /etc/modules-load.d/8821cu.conf这个目录/etc/modules-load.d/是 systemd 时代的标准做法比直接改/etc/modules更规范。系统启动时 systemd-modules-load 服务会读取这个目录下所有.conf文件逐行加载模块。然后配置模块参数可选但建议sudo tee /etc/modprobe.d/8821cu.conf EOF options 8821cu rtw_switch_usb_mode0 EOFrtw_switch_usb_mode0是防止驱动在 USB 模式切换时出问题某些批次必须加这个参数才能稳定工作。5.3 黑名单冲突模块这一步不能省创建黑名单文件sudo tee /etc/modprobe.d/blacklist-rtl8xxxu.conf EOF blacklist rtl8xxxu blacklist rtw88_8821cu blacklist rtw88_core EOF然后更新 initramfs让黑名单在启动早期就生效sudo update-initramfs -u提示blacklist只是不自动加载如果某个模块被其他模块依赖还是可能被拉起来。更彻底的做法是用install xxx /bin/true覆盖但一般情况 blacklist 够用。5.4 用 DKMS 一劳永逸解决内核升级问题如果你用的是 morrownr 的仓库install-driver.sh脚本已经自动注册了 DKMS。手动验证一下dkms status应该看到类似8821cu, 5.12.0, 5.4.0-150-generic, x86_64: installed如果没注册手动加sudo dkms add ./8821cu-20210916 sudo dkms build 8821cu/5.12.0 sudo dkms install 8821cu/5.12.0DKMS 注册后每次内核升级dkms autoinstall会自动为新内核重新编译模块。你可以在/etc/kernel/postinst.d/dkms看到这个钩子。5.5 完整验证模拟一次重启不要真的重启用这个命令卸载再加载模拟启动流程sudo modprobe -r 8821cu sudo modprobe 8821cu ip link如果ip link里网卡正常出现说明配置没问题。再检查一遍黑名单是否生效lsmod | grep -E rtl8xxxu|rtw88应该没有任何输出。如果还有说明黑名单没生效检查update-initramfs是否执行成功。6. 那些文档里不会写的踩坑记录6.1 Secure Boot 导致的模块签名问题Ubuntu 20.04 默认开启 Secure Boot 时未签名的内核模块会被拒绝加载dmesg里会看到Loading of unsigned module is tainted或者直接module verification failed。两个解决办法一是进 BIOS 关闭 Secure Boot最简单。二是给模块签名需要自己生成密钥并注册到 MOKMachine Owner Key流程比较繁琐sudo apt install -y mokutil openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj /CNCustom/ sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 MOK.priv MOK.der /lib/modules/$(uname -r)/kernel/drivers/net/wireless/8821cu.ko sudo mokutil --import MOK.der然后重启在 MOK 管理界面确认导入。我一般建议直接关 Secure Boot省事。6.2 USB 口供电不足导致的不稳定这块卡在 USB 2.0 口上偶尔会掉线dmesg里刷usb disconnect。原因是 8811CU 芯片峰值功耗较高老机器的 USB 口供电不足。解决办法是插到 USB 3.0 口蓝色口或者用带独立供电的 USB Hub。这个坑很隐蔽因为网卡能识别、能连上就是隔几分钟断一次很容易误以为是驱动问题。6.3 5G 频段搜不到的几个原因编译成功、网卡工作但nmcli dev wifi list里只有 2.4G 的 SSID。排查顺序确认路由器 5G 频段已开启且信道在驱动支持范围内一般 36-165。检查驱动是否加载了正确的固件。8811CU 需要rtl8821cufw.bin固件文件放在/lib/firmware/rtlwifi/或/lib/firmware/下。morrownr 仓库里带了固件make install会自动复制。用iw list查看支持的频段iw list | grep -A 10 Frequencies如果 5G 频段列表为空说明驱动没正确初始化射频前端重新编译并确认固件路径。6.4 内核升级后 dkms 没自动重编译偶尔会遇到 DKMS 没触发的情况手动补救sudo dkms autoinstall如果报错先dkms status看状态再sudo dkms remove 8821cu/5.12.0 --all然后重新add/build/install。我遇到过几次是因为/usr/src/下的源码目录被清理工具删了DKMS 找不到源码。所以建议把源码仓库保留在一个固定位置别随手删。6.5 NetworkManager 不接管新网卡网卡接口出现了但 NetworkManager 不管它nmcli dev status里显示unmanaged。这是因为接口被标记为不受管。检查cat /etc/NetworkManager/NetworkManager.conf如果[keyfile]段有unmanaged-devices包含你的网卡 MAC删掉即可。或者临时用sudo nmcli dev set wlxXXXXXXXXXXXX managed yes7. 一套可复用的排查思路把上面的经验抽象一下遇到任何 USB 网卡在 Linux 下不工作都可以按这个顺序排查lsusb确认设备被识别记下 VID:PID。dmesg | tail看内核有没有报错有没有绑定到错误模块。lsmod看当前加载了哪些相关模块有没有冲突。确认linux-headers和uname -r一致。编译安装驱动modprobe加载ip link验证。配置/etc/modules-load.d/自动加载/etc/modprobe.d/黑名单冲突模块。注册 DKMS解决内核升级问题。update-initramfs -u让配置在启动早期生效。这套流程不只适用于 TL-XDN7000H市面上大部分 RTL8811CU/8821CU 方案的 USB 网卡都通用。区别只在仓库选择和固件文件名。我个人在实际操作中的体会是Linux 下折腾 USB 网卡80% 的时间花在确认芯片真实型号和处理模块冲突上真正编译的时间反而很短。所以别急着 clone 仓库就 make先把第 2 章的底细摸清楚能省掉后面一大堆返工。另外DKMS 这个东西用过就回不去了强烈建议所有手动编译内核模块的场景都配上。