QEMU SLIRP 用户态网络:默认 10.0.2.0 网段与 virtio-net 接线实测
装好 QEMU、敲下第一条 qemu-system-riscv64 命令时,很多读者并没有写任何网络参数,但进了客户机却发现能上网、能解析域名。这块「凭空出现」的网络就是本篇的主角:QEMU SLIRP,命令行里对应的后端类型是 -netdev user,也常被直接叫作 user 网络。它是 QEMU 免配置体验的重要一环,也是后续端口转发、多机组网等进阶话题的地基。虚拟机、宿主机、镜像这些基本概念还没建立的读者,建议先读 认识 QEMU:从零看懂虚拟机、镜像与快照;命令行参数的整体读法可以配合 QEMU 命令行参数逐段注解 一起看。
本文要回答的问题
- 启动命令里一个网络参数都不写,QEMU 内部到底有没有网络?
info network里的hub和type=user各是什么? - QEMU SLIRP 凭什么不需要 root 权限、也不创建网桥就能让客户机出网,它和 tap/网桥方案差在哪?
- 为什么默认轮
info network里只有后端没有网卡,加了-device virtio-net-device之后才出现 MAC 地址? - 客户机里的
10.0.2.15、网关10.0.2.2、DNS10.0.2.3这套地址是谁分配的,为什么每台虚拟机都一样? - SLIRP 网络能做什么、不能做什么,外部主机想主动连进客户机该怎么办?
先把全篇结论压成一张概念卡:QEMU SLIRP 可以拆成后端、前端、地址约定与能力边界四个面来看,后面的每一节都是在给这张卡片补证据。
这张卡片最容易被忽略的是第二组:SLIRP 后端默认就在,但 RISC-V 的 virt 机器并不会自动配一块网卡前端,后端和前端是两个独立部件,需要显式接线。这一点会在第三节用实测坐实。
一、不写任何网络参数时,QEMU 里已经有什么
第一轮实验故意什么网络参数都不加,用最短命令启动一台 RISC-V virt 机器,再通过 QMP(QEMU Machine Protocol,QEMU 的机器控制接口)向监控通道发 info network,把内部的网络接线状态原样取回来。监控通道的用法见 QEMU Monitor 入门:HMP 与 QMP 两种监控姿势。
返回内容只有三行有效信息,逐行拆。hub 0 是 QEMU 内部的一个软件集线器(hub),可以理解成一块看不见的虚拟交换机,所有网络部件都挂在它的端口上。hub0port1: #net130 ... type=user,net=10.0.2.0,restrict=off 说明 1 号端口上已经挂了一个 user 类型的后端,网段是 10.0.2.0,restrict=off 表示不限制它与主机侧通信。而 hub0port0 后面空空如也——0 号端口没有接任何网卡。
这就是「默认网络」的完整真相:QEMU 进程一启动,SLIRP 后端就被自动创建并接在集线器上,不需要任何参数、不需要管理员权限;但在 RISC-V virt 机器上,集线器的另一侧没有网卡前端,客户机内部看不到任何网络接口。后端准备好了,插口上却没线。顺带一提,#net130 这样的编号是本次进程内的内部对象序号,每次启动都会变,不用记忆。
二、SLIRP 是什么:住进 QEMU 进程里的「租房路由器」
要理解 SLIRP 的行为,先想一个生活场景。出租屋的路由器对内是 192.168.1.x 的小网段,屋里的手机、电脑各自拿一个内网地址;对外只有一根入户宽带,整个屋子共用运营商分配的公网 IP。你主动刷网页、发消息都没问题,因为路由器会做 NAT(Network Address Translation,网络地址转换),把内网源地址改写成公网地址再发出去,回来的数据包再按记录改回去;但外网的人无法主动敲开你屋里某台手机的门,因为内网地址对外不可见。
QEMU SLIRP 就是把这样一台路由器完整地搬进了 QEMU 进程内部。它起源于早期拨号上网时代的 SLIRP 程序,本质是一个用户态的 TCP/IP 协议栈:它不是操作系统内核里的网络模块,而是 QEMU 进程里的一段普通代码,通过进程自己的 socket 向真实网络收发数据。客户机发出的以太网帧被网卡前端送进 SLIRP,SLIRP 按协议栈逻辑解析出 TCP/UDP 报文,做 NAT 改写后,用 QEMU 进程在主机上的普通套接字发到外网;回程流量再逆向翻译回客户机的内网连接。
读图抓住颜色的语义:蓝色是客户机侧的流量入口,紫色是 SLIRP 这个核心转换环节,橙色是主机侧的实际执行,绿色是流量最终到达的外部世界。整条路径里没有任何内核虚拟网卡、网桥或管理员授权动作——主机只知道「有个普通进程发起了网络连接」,这正是它无需 root 的原因。
对照之下,tap/网桥方案走的是内核路线:tap 是内核提供的虚拟网卡设备,创建它通常需要 root 权限(或预先配置好的 capability 授权),再把 tap 接进 Linux bridge,让客户机像一台真正接入二层网络的机器那样收发裸以太网帧。tap 性能更高、协议支持更完整、客户机可被外部直接寻址,但配置重、权限要求高。入门阶段先用好 SLIRP,tap 与网桥留给后续的高阶组网篇展开。
三、显式接线:-netdev user 配 virtio-net-device
第二轮实验把缺的前端补上。命令行里出现两个新部件:-netdev user,id=net0 显式创建一个 user 后端并起名为 net0,-device virtio-net-device,netdev=net0 给机器添加一块 virtio-net 网卡,并通过同名 id 把它接到这个后端上。这种「后端 netdev 与前端 device 分离、用 id 绑定」的写法是现代 QEMU 的标准接线方式。
这次 info network 的输出变成两级结构。第一行 virtio-net-device.0: index=0,type=nic,model=virtio-net-device,macaddr=52:54:00:12:34:56 是网卡前端:类型 nic,型号 virtio-net,MAC 地址 52:54:00:12:34:56——这是 QEMU 在未指定 MAC 时给出的默认值,以 52:54:00 开头是 QEMU 的 OUI 惯例。第二行 net0: index=0,type=user,net=10.0.2.0,restrict=off 就是上一轮自动出现的那个 SLIRP 后端,这次它有了显式名字 net0,网段依旧是默认的 10.0.2.0。缩进的树形符号表示两者已经挂在同一个集线器端口对上,客户机内部从此能看到一块可用的网卡。
两轮实验的差异可以收进一张对照表里,判据都来自日志原文。
| 对比项 | 无网络参数(默认轮) | 显式 -netdev user + virtio-net |
|---|---|---|
| user 后端 | 有,自动挂在 hub0port1 | 有,显式命名为 net0 |
| 后端类型与网段 | type=user,net=10.0.2.0 | type=user,net=10.0.2.0 |
| 网卡前端(nic) | 无,hub0port0 空置 | virtio-net-device.0 |
| MAC 地址 | 不存在 | 52:54:00:12:34:56 |
| 客户机内可见网卡 | 否 | 是 |
| 是否需要 root | 否 | 否 |
注意一个常见误解:显式写 -netdev user 并没有「开启」SLIRP,它本来就开着;这条命令的真正作用是给后端一个可引用的 id,让 -device 能把网卡接上去。

记录上半段是不带任何网络参数的默认轮,info network 里只能看到 type=user,net=10.0.2.0 的 SLIRP 后端挂在集线器上,前端端口空置;下半段加上 -netdev user,id=net0 与 -device virtio-net-device 后,输出多出一行 type=nic 的 virtio-net 前端,MAC 落为 QEMU 默认的 52:54:00:12:34:56,而后端的网段依旧是同一个 10.0.2.0。两轮末尾的关机事件都是 host-qmp-quit,说明差异只来自接线参数,与生命周期管理无关。
四、默认网段地址约定:10.0.2.x 各自代表谁
SLIRP 内置了一个迷你 DHCP 服务器,客户机开机自动配置网络时,拿到的地址几乎是「背」下来的固定值。这套约定写在 QEMU 官方文档里,与平台无关,本篇环境的 net=10.0.2.0 实测也与之吻合。
| 地址 | 在 SLIRP 网络里的角色 | 客户机里的典型体现 |
|---|---|---|
| 10.0.2.15 | 分配给客户机网卡的地址 | 网卡主 IP,默认从 DHCP 获取 |
| 10.0.2.2 | 网关,同时兼任 DHCP 服务器 | 默认路由与 DHCP 应答方 |
| 10.0.2.3 | DNS 服务器 | /etc/resolv.conf 里的 nameserver |
| 10.0.2.4 | SMB 文件共享服务器 | 仅在启动时配置 smb= 目录后可达 |
为什么每台虚拟机的地址都一模一样也不会冲突?因为这个网段只活在各自 QEMU 进程的 SLIRP 实例内部,主机网络和别的进程都看不到 10.0.2.x。两台虚拟机各说各的 10.0.2.15,就像两栋楼里都有「302 室」,出了楼门(经过 NAT)用的是各自房东的地址,互不干扰。也正因为如此,客户机不能靠 10.0.2.15 互相找到对方,SLIRP 网络天然是隔离的单机组网。
10.0.2.2 这个网关地址还有个实用功能:从客户机视角访问它,等于访问宿主机。在客户机里把服务地址填成 10.0.2.2 加端口,就能连到主机上监听的开发服务,做嵌入式开发时用来回传日志、下载固件很方便。
五、能力边界:能出不能进,以及补救办法
把 SLIRP 的行为边界一次讲清,省得日后踩坑再回头查。
第一,出站连接自由,入站连接默认全拒。客户机主动发起的 TCP、UDP 连接经 NAT 正常出网,DNS 由 10.0.2.3 代理解析;但任何外部主机(包括宿主机)都无法主动连到客户机的 10.0.2.15,因为这个地址在 SLIRP 之外不可路由。需要从主机访问客户机服务时,用 hostfwd 端口转发把主机端口映射进客户机,例如把主机的 2222 转到客户机的 22,具体写法与实测见姊妹篇 QEMU 端口转发 hostfwd:让主机连进 SLIRP 客户机。
第二,协议支持以常用传输层为限。日常的 HTTP、SSH、DNS、TCP/UDP 都没问题;但 SLIRP 对 ICMP 的支持有限,在部分平台上客户机里 ping 外网可能不通,这并不代表网络坏了,先用 TCP 类工具验证连通性。组播、广播、需要二层裸帧的协议也不支持,这类需求应改用 tap/网桥。
第三,性能有固定损耗。每个数据包都要经过「客户机 virtio 队列 → 用户态协议栈解析与 NAT → 主机套接字」两次拷贝和上下文切换,吞吐与延迟都不如 tap 直通。学习、单机开发、CI 场景下这点开销可以忽略;高吞吐压测或多机集群实验再换方案。
第四,restrict=off 给出了隔离开关。默认值 off 表示 SLIRP 可以与主机通信,所以客户机能借主机出网、能访问 10.0.2.2 上的主机服务;若把它置为 on,SLIRP 被限制在纯客户机本地模式,出站路径切断,只保留 SLIRP 内部的 DHCP/DNS 等内建服务。
这一篇在知识体系里的位置
本篇属于 SoC 与 QEMU 入门路线的网络基础环节,向上承接虚拟机基本概念与命令行读法:认识 QEMU:从零看懂虚拟机、镜像与快照 解释宿主机、客户机与镜像的关系,QEMU 命令行参数逐段注解 讲清 -device、-netdev 这类参数的通用语法,QEMU Monitor 入门:HMP 与 QMP 两种监控姿势 是本篇 info network 观测手段的出处。向下的直接后续是 QEMU 端口转发 hostfwd:让主机连进 SLIRP 客户机,专门补上 SLIRP「不能进」的短板;再往后的高阶组网篇会展开 tap、网桥与多机互联,与本篇的用户态方案形成完整对照。
代码获取:本篇两轮
info network对照实验的可复现脚本见公开仓库 derekzhuo/geek-doc.cn 的experiments/qemu-slirp-user-network/目录。克隆后执行./run.sh即可重新生成含 QMP 原始返回的完整日志。
实验环境
机器/系统:MacBook Pro(Intel x86_64)/ macOS 26
工具版本:QEMU 11.1.2(
qemu-system-riscv64 --version输出 11.1.2)、nc(经 Unix 套接字向 QMP 通道发送监控命令)日期:2026-11-07
完整命令序列(由
./run.sh编排,QMP 交互经 nc 完成):bash./run.sh # 脚本内部依次执行两轮启动: qemu-system-riscv64 -machine virt -bios default -no-reboot qemu-system-riscv64 -machine virt -bios default -no-reboot \ -netdev user,id=net0 \ -device virtio-net-device,netdev=net0 # 每轮通过 QMP 发送 query-status 与 info network,原始返回见 run1.log
总结
QEMU SLIRP 是住进 QEMU 进程的用户态 TCP/IP 栈与 NAT 路由器:无需 root、不建网桥,客户机的流量经地址转换后借主机套接字出网,外部看到的始终是主机 IP。实测表明,不带任何网络参数启动时 SLIRP 后端已自动挂在集线器上(type=user,net=10.0.2.0),但 RISC-V virt 机器没有网卡前端,hub0port0 空置;补上 -netdev user,id=net0 -device virtio-net-device,netdev=net0 后才出现 MAC 为 52:54:00:12:34:56 的 virtio-net 网卡。客户机固定使用 10.0.2.15、网关 10.0.2.2、DNS 10.0.2.3 这套地址约定,网段仅在进程内部可见;它能出站不能入站,入站需求交给 hostfwd 端口转发,高性能与二层协议需求则留给 tap/网桥方案。