NetPlan/wpa_supplicant / NetworkManager / systemd-networkd / nmcli / wpa_cli 区别和联系
在 Linux 上连接 WiFi,通常涉及多个组件的协作。本文梳理各组件所处的层次、职责边界与常见组合方式,帮助读者快速定位问题所在。
1. 先看分层
在 Linux 上连上一个 WiFi,要经过三层:
- 链路层认证:扫描、关联、WPA 握手,拿到加密密钥。这层由 wpa_supplicant(或 iwd)负责。
- IP 层配置:DHCPv4 拿 IPv4、RA/SLAAC 拿 IPv6,设置路由和 DNS。这层由 NetworkManager / systemd-networkd / dhclient / udhcpc 负责。
- 管理与交互:保存配置、断线自动重连,提供命令行或图形界面。这层由 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 和路由。
原理
- 通过 nl80211(基于 generic netlink)向内核 cfg80211 下发扫描、认证、关联命令。老驱动走
wext。 - 关联成功后,用 packet socket 收发 EAPOL 帧完成四次握手,算出 PTK/GTK。
- 再通过 nl80211 把密钥装进驱动,链路就进入可用状态(
iw dev wlan0 link显示 Connected)。 - 对外提供两种控制接口:
- 控制 socket:
/run/wpa_supplicant/<网卡名>,Unix 数据报 socket,给 wpa_cli 用。 - D-Bus 接口:服务名
fi.w1.wpa_supplicant1,给 NetworkManager 用。
- 控制 socket:
两种运行方式
| 方式 | 命令行示例 | 配置来源 |
|---|---|---|
| 配置文件模式 | 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-<网卡名>.conf | systemd 模板服务 wpa_supplicant@wlan0.service 使用(配合 systemd-networkd 时常用) |
/etc/wpa_supplicant/wpa_supplicant-nl80211-<网卡名>.conf | wpa_supplicant-nl80211@wlan0.service 使用(Debian) |
/lib/systemd/system/wpa_supplicant.service | D-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_supplicant | wpa_cli | NetworkManager | nmcli | systemd-networkd | |
|---|---|---|---|---|---|
| 类型 | 守护进程 | 命令行客户端 | 守护进程 | 命令行客户端 | 守护进程 |
| 负责的层 | 链路层认证 | 控制 wpa_supplicant | IP 层 + 整体管理 | 控制 NetworkManager | IP 层 |
| 能完成 WiFi 认证吗 | 能 | 间接(通过 wpa_supplicant) | 能,调用 wpa_supplicant | 间接(通过 NM) | 不能,需要配合 wpa_supplicant |
| DHCP | 无 | 无 | 内置客户端;开热点时用 dnsmasq 当服务端 | 无 | 内置客户端和服务端 |
| 通信方式 | nl80211 往下;控制 socket 和 D-Bus 往上 | Unix socket | D-Bus、rtnetlink | D-Bus | rtnetlink、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 调试。
- systemd-networkd +
- 一张网卡只选一套方案,其他管理者要对这张网卡设置 unmanaged,或者直接停掉。
9. 用到的技术汇总
| 技术 | 用在哪里 |
|---|---|
| nl80211 / cfg80211(generic netlink) | wpa_supplicant、iw 与内核 WiFi 子系统通信:扫描、认证、关联、装密钥 |
| rtnetlink | NetworkManager、networkd、ip 命令设置地址、路由、链路状态,并监听链路变化 |
| D-Bus | nmcli ↔ 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 判断哪些设备由它管理 |
| dnsmasq | NetworkManager 开热点(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 客户端 | 能否换成外部客户端 |
|---|---|---|
| NetworkManager | dhcp=internal,1.20 起是默认值。DHCPv4:较新版本用 nettools 项目的 n-dhcp4,较早版本用从 systemd 拷进来的 sd-dhcp-client 代码。DHCPv6:用从 systemd 拷进来的 sd-dhcp6-client | 可以。在 NetworkManager.conf 的 [main] 段写 dhcp=dhclient 或 dhcp=dhcpcd,前提是装了对应的程序 |
| systemd-networkd | systemd 自己的 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 后再跑压测。如果换了客户端后问题消失,就说明是客户端这边的问题;如果还在,问题多半在热点端或空口。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)