在 Linux 上连接 WiFi,通常涉及多个组件的协作。本文梳理各组件所处的层次、职责边界与常见组合方式,帮助读者快速定位问题所在。

1. 先看分层

在 Linux 上连上一个 WiFi,要经过三层:

  1. 链路层认证:扫描、关联、WPA 握手,拿到加密密钥。这层由 wpa_supplicant(或 iwd)负责。
  2. IP 层配置:DHCPv4 拿 IPv4、RA/SLAAC 拿 IPv6,设置路由和 DNS。这层由 NetworkManager / systemd-networkd / dhclient / udhcpc 负责。
  3. 管理与交互:保存配置、断线自动重连,提供命令行或图形界面。这层由 NetworkManager / networkd 守护进程负责,用户通过 nmcli / networkctl / wpa_cli 和它们交互。
用户工具    nmcli / nmtui / GNOME    networkctl        wpa_cli        iw / ip
              │ D-Bus (libnm)      │ D-Bus/varlink   │ Unix socket   │ netlink
              ▼                    ▼                 ▼               │
管理守护    NetworkManager       systemd-networkd                    │
              ├ 内置 DHCP 客户端    ├ 内置 DHCPv4/v6 客户端            │
              ├ 内置 IPv6 RA 处理   │ 及 DHCP 服务端                   │
              └ D-Bus ──────────┐  └ 不管 WiFi 认证                   │
                                ▼                    ▼               │
链路认证              wpa_supplicant(一个进程可以管理多张网卡)        │
                                │ nl80211 (generic netlink)         │
────────────────────────────────┼───────────────────────────────────┼────
内核                  cfg80211 / mac80211 ── WiFi 驱动 (brcmfmac 等)  rtnetlink
                      地址、路由、邻居表 ◄────── NM / networkd 通过 rtnetlink 设置

一句话总结:

  • wpa_supplicant 只负责“连上 AP”,不管 IP。
  • NetworkManager 和 systemd-networkd 负责“拿到 IP、管理整台机器的网络”。两者都靠 wpa_supplicant 完成 WiFi 认证。
  • nmcli 是 NetworkManager 的客户端,wpa_cli 是 wpa_supplicant 的客户端。它们本身不联网,只是给守护进程发命令。

2. wpa_supplicant

作用

WiFi 客户端(STA)的认证程序(802.11 supplicant)。它负责:

  • 扫描和选择 AP(BSS)
  • 认证和关联
  • WPA/WPA2 四次握手、WPA3-SAE、802.1X/EAP 企业认证
  • 把密钥装进驱动
  • 漫游(bgscan)、WPS、WiFi P2P,以及简单的 AP 模式(NetworkManager 开热点时用的就是这个)

它不做 DHCP,也不配 IP 和路由。

原理

  1. 通过 nl80211(基于 generic netlink)向内核 cfg80211 下发扫描、认证、关联命令。老驱动走 wext。
  2. 关联成功后,用 packet socket 收发 EAPOL 帧完成四次握手,算出 PTK/GTK。
  3. 再通过 nl80211 把密钥装进驱动,链路就进入可用状态(iw dev wlan0 link 显示 Connected)。
  4. 对外提供两种控制接口:
    • 控制 socket:/run/wpa_supplicant/<网卡名>,Unix 数据报 socket,给 wpa_cli 用。
    • D-Bus 接口:服务名 fi.w1.wpa_supplicant1,给 NetworkManager 用。

两种运行方式

方式命令行示例配置来源
配置文件模式wpa_supplicant -B -i wlan0 -D nl80211 -c /etc/wpa_supplicant/wpa_supplicant.conf读 conf 文件
D-Bus 模式wpa_supplicant -u -s -O "DIR=/run/wpa_supplicant GROUP=netdev"没有 conf 文件,网卡和网络都由 NetworkManager 等通过 D-Bus 下发

D-Bus 模式下 -O 的作用:给通过 D-Bus 添加的网卡也开启控制 socket,这样 wpa_cli 还能连上去查看状态。

配置文件

路径说明
/etc/wpa_supplicant/wpa_supplicant.conf常用的默认路径,需要在 -c 里显式指定
/etc/wpa_supplicant/wpa_supplicant-<网卡名>.confsystemd 模板服务 wpa_supplicant@wlan0.service 使用(配合 systemd-networkd 时常用)
/etc/wpa_supplicant/wpa_supplicant-nl80211-<网卡名>.confwpa_supplicant-nl80211@wlan0.service 使用(Debian)
/lib/systemd/system/wpa_supplicant.serviceD-Bus 模式的服务单元(NetworkManager 依赖它)

配置示例:

ctrl_interface=DIR=/run/wpa_supplicant GROUP=netdev
update_config=1          # 允许 wpa_cli save_config 写回本文件
country=CN
network={
ssid="MyHotspot"
psk="12345678"
key_mgmt=WPA-PSK     # WPA3 用 SAE,开放网络用 NONE
priority=10
}

3. wpa_cli

作用

wpa_supplicant 的命令行客户端,通过控制 socket(/run/wpa_supplicant/wlan0)发文本命令。

原理和要点

  • 连到 ctrl_interface 目录下以网卡名命名的 Unix socket,发送 SCAN、STATUS 等文本命令,接收回复和事件(CTRL-EVENT-CONNECTED 等)。
  • 用 wpa_cli 改的配置默认只在内存里。只有 conf 文件里写了 update_config=1,并执行 save_config,才会写回文件。
  • wpa_cli -a <脚本> -B 可以在连上或断开时执行脚本。老式 ifupdown 就是靠这个机制,在连上之后再启动 DHCP 客户端。
  • wpa_cli 自己没有配置文件。

常用命令

wpa_cli -i wlan0 status                # 当前状态:wpa_state / ssid / bssid / ip_address
wpa_cli -i wlan0 scan; wpa_cli -i wlan0 scan_results
wpa_cli -i wlan0 list_networks
wpa_cli -i wlan0 add_network           # 返回 id
wpa_cli -i wlan0 set_network 0 ssid '"MyHotspot"'
wpa_cli -i wlan0 set_network 0 psk '"12345678"'
wpa_cli -i wlan0 select_network 0
wpa_cli -i wlan0 disconnect / reconnect / reassociate
wpa_cli -i wlan0 signal_poll           # RSSI、速率
wpa_cli -i wlan0 save_config

4. NetworkManager

作用

桌面和通用发行版上的全功能网络管理守护进程。它管理有线、WiFi、移动网络、VPN、bond/bridge/VLAN、热点等,负责:

  • 保存连接配置
  • 自动连接、断线重连
  • 获取 IP、设置路由和 DNS
  • 按优先级在多个网络间切换

原理

环节实现
WiFi 认证通过 D-Bus 调用 wpa_supplicant(所以 wpa_supplicant 要以 -u 模式运行),把 SSID、PSK 等下发给它
DHCPv4 / DHCPv6默认用内置 DHCP 客户端(internal,1.20 起默认),也可以配成 dhclient / dhcpcd。DHCP 包通过 packet socket 收发,因为这时还没有 IP
IPv6 RA / SLAAC在用户态自己处理 RA:把内核的 accept_ra 置 0,由 NetworkManager 自己解析 RA 并配置地址
设置地址和路由通过 rtnetlink 写入内核
DNS写 /etc/resolv.conf,或交给 systemd-resolved / dnsmasq
热点ipv4.method shared 时,NetworkManager 让 wpa_supplicant 进入 AP 模式,同时启动 dnsmasq 做 DHCP/DNS,并配置 NAT
权限普通用户的 nmcli 操作要经过 polkit 授权
事件钩子/etc/NetworkManager/dispatcher.d/ 下的脚本,在连接上下线时执行

由此可以解释“能拿到 IPv6、拿不到 IPv4”:IPv6 走的是 RA,DHCPv4 走的是独立的 DHCP 客户端,两条路径互不依赖,所以可以出现一个成功、一个失败的情况。

配置文件

路径说明
/etc/NetworkManager/NetworkManager.conf主配置:插件、dhcp=、dns=、[device] 中的 wifi.scan-rand-mac-address、[keyfile] 中的 unmanaged-devices 等
/etc/NetworkManager/conf.d/*.conf追加配置,会覆盖主配置中的同名项
/etc/NetworkManager/system-connections/*.nmconnection每个连接一个文件(keyfile 格式,权限 600,里面有明文密码)
/run/NetworkManager/system-connections/临时连接,例如 netplan 生成的,重启后消失
/var/lib/NetworkManager/运行状态:DHCP 租约 internal-<uuid>-<网卡名>.lease、NetworkManager.state、seen-bssids
/etc/sysconfig/network-scripts/ifcfg-*RHEL 旧格式(ifcfg-rh 插件)
/etc/network/interfaces如果网卡写在这里,并且 [ifupdown] managed=false,NetworkManager 就不管它

查看最终生效的配置:NetworkManager --print-config

连接文件示例:

[connection]
id=MyHotspot
type=wifi
interface-name=wlan0
autoconnect=true
[wifi]
ssid=MyHotspot
mode=infrastructure
powersave=2              # 2 关闭省电,3 开启省电
cloned-mac-address=permanent
[wifi-security]
key-mgmt=wpa-psk
psk=12345678
[ipv4]
method=auto
[ipv6]
method=auto

5. nmcli

作用

NetworkManager 的命令行客户端。nmtui(文本界面)、nm-applet 和 GNOME 设置也都是 NetworkManager 的客户端。

原理

  • 通过 libnm 走 D-Bus(org.freedesktop.NetworkManager)调用 NetworkManager。
  • nmcli 自己没有配置文件。 它所做的修改由 NetworkManager 写进 system-connections/,所以是持久的。

常用命令

nmcli general status
nmcli dev status                        # 每张网卡的状态:connected / disconnected / unmanaged
nmcli dev wifi list                     # 扫描结果
nmcli dev wifi connect MyHotspot password 12345678 ifname wlan0
nmcli con show                          # 已保存的连接
nmcli con show MyHotspot                # 连接的全部属性,包括 DHCP4.OPTION 里的租约信息
nmcli con modify MyHotspot wifi.powersave 2
nmcli con up / down MyHotspot
nmcli dev wifi hotspot ifname wlan0 ssid Test password 12345678   # 开热点
nmcli general logging level DEBUG domains WIFI,DHCP4,IP6          # 临时打开调试日志
journalctl -u NetworkManager -f

6. systemd-networkd

作用

systemd 自带的轻量网络配置守护进程,常用于服务器、容器和嵌入式设备。它通过声明式配置文件,配置网卡的 IP、路由、DHCP,以及创建 bridge/bond/VLAN 等。

原理

环节实现
WiFi 认证不处理。需要另外运行 wpa_supplicant@wlan0.service(读 conf 文件)或 iwd。networkd 只看链路状态,链路 up(carrier)之后才开始配 IP
DHCP / RA内置 sd-dhcp DHCPv4/v6 客户端、RA 处理(IPv6AcceptRA=),还内置 DHCP 服务端(DHCPServer=yes),可以给热点或网口分配地址
设置地址和路由通过 rtnetlink
DNS交给 systemd-resolved
网卡命名由 udev 读取 .link 文件处理

配置文件

优先级 /etc > /run > /usr/lib,同名文件高优先级的生效;按文件名字典序匹配,第一个匹配的生效。

路径说明
/etc/systemd/network/*.network匹配网卡后配置 IP、DHCP、路由
/etc/systemd/network/*.netdev创建虚拟网卡(bridge、bond、vlan 等)
/etc/systemd/network/*.link网卡命名、MAC、MTU(由 udev 处理)
/etc/systemd/networkd.conf全局设置
/run/systemd/netif/leases/<ifindex>DHCP 租约

WiFi 场景示例:

# /etc/systemd/network/25-wlan.network
[Match]
Name=wlan0
[Network]
DHCP=yes
IPv6AcceptRA=yes
systemctl enable --now wpa_supplicant@wlan0    # 读 /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
systemctl enable --now systemd-networkd systemd-resolved
networkctl list / networkctl status wlan0

7. 对比

wpa_supplicantwpa_cliNetworkManagernmclisystemd-networkd
类型守护进程命令行客户端守护进程命令行客户端守护进程
负责的层链路层认证控制 wpa_supplicantIP 层 + 整体管理控制 NetworkManagerIP 层
能完成 WiFi 认证吗能间接(通过 wpa_supplicant)能,调用 wpa_supplicant间接(通过 NM)不能,需要配合 wpa_supplicant
DHCP无无内置客户端;开热点时用 dnsmasq 当服务端无内置客户端和服务端
通信方式nl80211 往下;控制 socket 和 D-Bus 往上Unix socketD-Bus、rtnetlinkD-Busrtnetlink、D-Bus
配置文件wpa_supplicant*.conf(D-Bus 模式下没有)无NetworkManager.conf、system-connections/无/etc/systemd/network/*.network 等
适用场景所有 WiFi 场景嵌入式调试桌面、笔记本、需要频繁切换网络的设备同左服务器、嵌入式、固定网络

另外几个相关组件:

  • netplan(Ubuntu):只负责从 /etc/netplan/*.yaml 生成配置。renderer: NetworkManager 时生成到 NetworkManager,renderer: networkd 时生成到 networkd。
  • ifupdown:/etc/network/interfaces,配合 wpa-conf 和 dhclient 使用。
  • iwd:Intel 出的 wpa_supplicant 替代品。NetworkManager 和 networkd 都能配合它使用。
  • dhclient / udhcpc / dhcpcd:独立的 DHCP 客户端,嵌入式上常和 wpa_supplicant 搭配使用。

8. 可以同时开启多个吗?

原则:同一张网卡,每一层只能有一个“主人”。 不同网卡可以分别交给不同的管理者。

组合能否同时开说明
NetworkManager + wpa_supplicant(D-Bus 模式)✅ 必须一起开这是标准组合,wpa_supplicant 就是给 NetworkManager 干活的
NetworkManager + wpa_cli⚠️ 只建议只读使用status、signal_poll 等查询没问题。用 select_network、disconnect 等命令会和 NetworkManager 冲突:NetworkManager 会认为连接失败,重新连接或换一个 AP
NetworkManager + nmcli✅客户端和服务端的关系
systemd-networkd + wpa_supplicant@wlan0✅ 必须一起开标准组合
NetworkManager + systemd-networkd,管理不同网卡✅在 NetworkManager 里设置 [keyfile] unmanaged-devices=interface-name:eth0,或者 networkd 的 .network 文件只匹配它负责的网卡
NetworkManager + systemd-networkd,管理同一张网卡❌两边都会跑 DHCP、写地址和路由,结果是地址重复、路由被反复覆盖、断网
两个 wpa_supplicant 管理同一张网卡❌例如 D-Bus 实例被 NetworkManager 用着,又手动起了一个 -i wlan0 -c xxx.conf 的实例。两者会抢着扫描和关联,导致频繁掉线
NetworkManager 管理的网卡上再手动运行 dhclient / udhcpc❌两个 DHCP 客户端会互相打架,也会造成“偶尔拿不到 IPv4”这类现象
ifupdown 和 NetworkManager 管理同一张网卡❌默认 [ifupdown] managed=false,NetworkManager 会自动避让 interfaces 文件里写了的网卡
开启了 systemd-networkd 但没有配置任何网卡✅ 但有副作用systemd-networkd-wait-online 会让开机多等 2 分钟。不用就 disable 掉

检查本机谁在管理网卡

systemctl is-active NetworkManager systemd-networkd wpa_supplicant 'wpa_supplicant@*'
ps -ef | grep -E '[w]pa_supplicant|[d]hclient|[u]dhcpc|[d]hcpcd|[d]nsmasq'   # 看有没有重复进程
nmcli dev status          # 显示 unmanaged 的网卡不归 NetworkManager 管
networkctl list           # 显示 configured 的网卡归 networkd 管,unmanaged 则不归它管
ls /run/wpa_supplicant/   # 每个 socket 文件对应一张由 wpa_supplicant 管理的网卡
cat /etc/netplan/*.yaml 2>/dev/null   # Ubuntu 上看 renderer

选型建议

  • 桌面、笔记本、需要经常切换 WiFi 的设备:NetworkManager + wpa_supplicant(D-Bus 模式),用 nmcli 操作;wpa_cli 只用来查看状态。
  • 嵌入式、固定网络:
    • systemd-networkd + wpa_supplicant@wlan0;
    • 或者更简单的 wpa_supplicant(conf 文件模式)+ udhcpc,用 wpa_cli 调试。
  • 一张网卡只选一套方案,其他管理者要对这张网卡设置 unmanaged,或者直接停掉。

9. 用到的技术汇总

技术用在哪里
nl80211 / cfg80211(generic netlink)wpa_supplicant、iw 与内核 WiFi 子系统通信:扫描、认证、关联、装密钥
rtnetlinkNetworkManager、networkd、ip 命令设置地址、路由、链路状态,并监听链路变化
D-Busnmcli ↔ NetworkManager ↔ wpa_supplicant;networkctl ↔ networkd
Unix 域 socket(控制接口)wpa_cli ↔ wpa_supplicant
EAPOL / 802.1X、WPA2 四次握手、SAE(WPA3)wpa_supplicant 的链路认证和密钥协商
DHCPv4(UDP 67/68,packet socket 广播)、DHCPv6获取 IPv4 地址和网关/DNS;获取 IPv6 地址或前缀
IPv6 RA / SLAAC(ICMPv6)获取 IPv6 地址。和 DHCPv4 完全独立,所以会出现“有 IPv6、没 IPv4”
polkit普通用户操作 NetworkManager 时的权限控制
udev网卡命名(.link 文件),NetworkManager 判断哪些设备由它管理
dnsmasqNetworkManager 开热点(shared 模式)时提供 DHCP/DNS 服务
nmcli -f NAME,TYPE,FILENAME con show   # 每个连接对应哪个文件

netplan 是 Ubuntu 上的配置生成器,不是守护进程。它本身不联网,只做一件事:把 /etc/netplan/*.yaml 翻译成 NetworkManager 或 systemd-networkd 的配置文件,再由它们去联网。

/etc/netplan/*.yaml
      │  开机时由 systemd generator 自动执行 netplan generate;手动改完后执行 netplan apply
      ▼
renderer: NetworkManager                    renderer: networkd
      │                                            │
/run/NetworkManager/system-connections/     /run/systemd/network/*.network
  netplan-*.nmconnection                    /run/netplan/wpa-wlan0.conf(WiFi 时生成)
      │                                            │
NetworkManager → wpa_supplicant(D-Bus)      systemd-networkd + netplan-wpa-wlan0.service

要点:

  • renderer 字段决定交给谁:NetworkManager 或 networkd,默认是 networkd。
  • 生成的文件都在 /run 下,每次开机重新生成。直接改它们,重启后就没了。要永久修改,必须改 yaml。
  • WiFi 写在 wifis: 下面,示例:
network:
  version: 2
  renderer: NetworkManager
  wifis:
    wlan0:
      dhcp4: true
      access-points:
        "MyHotspot":
          password: "12345678"

常用命令:

  • netplan get:查看合并后的配置。
  • netplan try:试用新配置,不确认的话 120 秒后自动回滚,远程改网络时很有用。
  • netplan apply:生效。
  • netplan generate:只生成配置,不生效。

几种常见情况:

系统netplan 配置SSID 实际保存在哪
Ubuntu 桌面版(22.04 及以前)01-network-manager-all.yaml 里只有 renderer: NetworkManager 一行NetworkManager 自己的 /etc/NetworkManager/system-connections/
Ubuntu 23.10 及以后NetworkManager 和 netplan 打通用 nmcli 或图形界面新建的连接会写成 /etc/netplan/90-NM-<uuid>.yaml,再生成到 /run/NetworkManager/system-connections/
Ubuntu Server一般用 renderer: networkd,或者不写SSID 和密码在 yaml 里
Debian、RHEL、嵌入式 BSP通常没有 netplan不涉及

和前面说的组件放在一起:netplan 排在 NetworkManager 和 networkd 之上,只负责写配置。同一张网卡只能交给一个 renderer,所以 netplan 本身不会造成双管理者冲突。但如果同一个连接在 yaml 和 /etc/NetworkManager/system-connections/ 里各有一份,就会出现两个同名连接。

看你的机器有没有用 netplan:执行 ls /etc/netplan/,没有这个目录就是没用。

wpa_supplicant 和 netplan 都没有 DHCP 客户端;NetworkManager、systemd-networkd 和 iwd 各自内置了一套。

组件内置 DHCP 客户端能否换成外部客户端
NetworkManagerdhcp=internal,1.20 起是默认值。DHCPv4:较新版本用 nettools 项目的 n-dhcp4,较早版本用从 systemd 拷进来的 sd-dhcp-client 代码。DHCPv6:用从 systemd 拷进来的 sd-dhcp6-client可以。在 NetworkManager.conf 的 [main] 段写 dhcp=dhclient 或 dhcp=dhcpcd,前提是装了对应的程序
systemd-networkdsystemd 自己的 libsystemd-network 库:sd-dhcp-client(v4)、sd-dhcp6-client(v6)。同一个库里还有 sd-dhcp-server(DHCP 服务端)和 sd-radv(发 RA)不能
wpa_supplicant没有—
netplan没有,由 renderer 指定的 NetworkManager 或 networkd 负责—
iwd有,用 ell 库的 l_dhcp。需要在 /etc/iwd/main.conf 里设置 EnableNetworkConfiguration=true 才启用默认不启用,交给 NetworkManager 或 networkd
ifupdown没有。按顺序找系统里装了的外部客户端:dhclient(isc-dhcp-client)→ pump → udhcpc → dhcpcd—
嵌入式(busybox)一般是 udhcpc,它通过 /usr/share/udhcpc/default.script 配置地址—

NetworkManager 的 DHCPv4 用的是 n-dhcp4 还是 sd-dhcp,取决于版本。我记得大约 1.36 起改成了 n-dhcp4,但这个版本号没有核实,以你机器上的版本为准。

查本机实际用的是哪个:
NetworkManager --version
NetworkManager --print-config | grep -i dhcp # 没写 dhcp= 就是 internal
journalctl -u NetworkManager -b | grep -i "dhcp.*client" # 启动日志里会打印用的是哪个 DHCP 客户端
ps -ef | grep -E '[d]hclient|[d]hcpcd|[u]dhcpc' # 用内置客户端时,看不到单独的 DHCP 进程

排查 IPv4 问题:
- 内置客户端没有单独进程和日志文件,DHCP 过程只出现在 NetworkManager 的日志里。打开详细日志:
nmcli general logging level TRACE domains DHCP4,IP4
journalctl -u NetworkManager -f
能看到 Discover、Offer、Request、ACK 每一步有没有发出和收到。
- 对比验证:可以临时改成 dhcp=dhclient,重启 NetworkManager 后再跑压测。如果换了客户端后问题消失,就说明是客户端这边的问题;如果还在,问题多半在热点端或空口。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐