
搞嵌入式的朋友应该都有过这种经历电脑上VMware里跑着Ubuntu用来交叉编译内核、编译应用、跑NFS服务器手边还放着一块开发板网线直接插在主机网口上。看起来万事俱备结果一联调就翻车虚拟机ping不通开发板开发板挂不上虚拟机的NFS目录TFTP下载内核一直T T T超时折腾一下午最后发现只是VMware网络模式选错了。这篇文章就把VMware、主机、开发板三方之间的网络连接彻底讲清楚包括三种网络模式怎么选、IP该怎么规划、NFS和TFTP怎么配、网络故障怎么一步步排查还会聊一些连接打通之后的高级玩法。不管是刚接触开发板的新手还是被网络问题折磨过多次的老手应该都能从里面找到对应的解决方案。1. 先搞清楚VMware三种网络模式后面才不会白折腾说实话绝大多数开发板联调的网络问题根子都在VMware网络模式没选对。VMware Workstation给虚拟机提供三种接入网络的路径桥接、NAT、仅主机。这三者听起来都是“让虚拟机有网”实际行为差别非常大选错一个后面的IP规划、NFS挂载、TFTP下载全部跟着错而且排查起来会非常迷惑因为“看起来都正常就是不通”。1.1 桥接模式Bridged的本质是虚拟机直接“上线”桥接模式的本质是VMware在主机物理网卡上开了一条通道让虚拟机直接挂到主机所在的局域网里。你可以把它理解成原本主机的网线插在交换机上现在交换机上又接了一台独立电脑这台独立电脑就是虚拟机。所以虚拟机拥有自己独立的局域网IP它的数据包从主机的物理网卡直接进出局域网里任何设备都可以主动访问它。这个特性在开发板联调里是最有用的。因为开发板要么用网线直连主机网口要么和主机接在同一个路由器或交换机上桥接模式下虚拟机、主机、开发板天然处于同一个二层网络互相ping通几乎没有障碍。不过这里有一个关键前提主机上如果有多块网卡比如一块有线网卡加一块WiFi网卡桥接时必须手动指定“桥接到哪块网卡”。如果选成了WiFi而开发板接的是有线网口那么虚拟机和开发板虽然都在192.168.1.x之类的同一网段但物理上分属两个不同的网络入口怎么调都还是不通。这一点后面第二章会专门讲操作。1.2 NAT模式为什么适合上网却难连开发板NAT模式对应VMware的VMnet8网卡。在这个模式下虚拟机并不直接暴露在局域网里而是藏在VMware构建的一个内部网络后面。虚拟机发出的所有对外访问都通过主机进行网络地址转换后转发出去局域网里的其他设备看到的访问源是主机的IP根本看不到虚拟机。它的好处非常明显只要主机能上网虚拟机就能上网而且不需要额外占用局域网IP对网络环境几乎没有要求。默认情况下VMware新建虚拟机用的就是NAT模式所以很多新手装完Ubuntu第一件事就是先上网更新软件源一切看起来都很正常。直到有一天你把编译好的内核镜像或者应用程序拷贝出来想在开发板上跑开发板却怎么都访问不到虚拟机这时才意识到问题。原因说白了就是开发板往虚拟机的IP发包但NAT模式下这个IP只在VMnet8这个虚拟网段里有效开发板不在这片网段里数据包根本到不了虚拟机。除非你额外配置端口转发规则否则外部设备永远无法主动连接NAT模式下的虚拟机。NAT模式不是不能用但拿它作为开发板联调的主链路等于给自己加难度。1.3 仅主机模式是一个完全封闭的虚拟局域网仅主机模式对应VMnet1网卡相当于VMware在主机内部划了一个封闭的虚拟局域网只有主机和加入这个网络的虚拟机存在虚拟机发出的包不会经过主机物理网卡局域网里其他设备更是完全感知不到。这个模式平时用得不多它的核心价值是隔离。比如你要跑一些不想让办公网其他设备感知到的测试环境或者主机在一个复杂的公共网络上不想让虚拟机的流量干扰公共网段仅主机模式就很合适。但拿它来连开发板就麻烦了因为开发板的网线是插在主机物理网口上的要让开发板进入仅主机的VMnet1网络还得在主机上额外做一层网络桥接或Internet连接共享把物理网口“接”进VMnet1。配置量不小对新手不友好所以不推荐作为主力方案。1.4 开发板联调场景下的模式选择把常见场景对应的模式选择整理成一个表方便对号入座使用场景推荐模式原因开发板直连主机网口需要虚拟机和开发板通信桥接且桥接到有线物理网卡虚拟机与开发板同处一个二层网络互通最直接主机和开发板都连同一个路由器/交换机桥接虚拟机局域网可见三方互访无障碍虚拟机只需要上网不参与局域网互访NAT不占用局域网IP使用方便本地隔离测试外部设备不能访问虚拟机仅主机完全隔离安全性高虚拟机要连外部PLC或工业设备桥接工业组态软件需要在局域网内发现目标设备我的建议很直接开发板联调场景优先选桥接桥接搞不定再考虑NAT加端口转发。很多人卡住不是技术能力不行而是一开始就选错了模式后面的所有操作都在错误的网络地基上搭建自然全盘皆输。2. 网络拓扑与IP规划把三台设备的“门牌号”一次性定好模式选好了接下来就是IP规划。很多初学者容易忽略这一步直接在开发板命令里随便敲一个IP虚拟机里用默认DHCP结果互相找不到。实际上只要把三台设备的IP、子网掩码、网关规划清楚网络配置这件事就成功了一半。2.1 一套可以直接抄的IP分配方案以最常见的场景为例Windows主机一个有线网口可能是USB转网口网线直接连接开发板主机同时通过WiFi上网。这个场景下虚拟机必须桥接到有线网口才能和开发板在同一条物理链路上互通。推荐这样分配设备IP地址子网掩码网关说明主机有线网口192.168.1.20255.255.255.0不填或192.168.1.1用于连接开发板不需要上外网Ubuntu虚拟机192.168.1.50255.255.255.0192.168.1.1静态IP关键要固定下来开发板192.168.1.100255.255.255.0192.168.1.1根据开发板情况手动配置这个方案里所有设备都在192.168.1.0/24这个局域网内。网关192.168.1.1是留给路由器用的如果虚拟机不需要上网网关填不填都行但开发板联调时填上一个不会错。要注意主机有线网口的IP必须是固定静态IP因为Windows默认网卡是DHCP自动获取如果主机这个网口连了开发板且没有DHCP服务器它会自己获取一个169.254.x.x的APIPA地址导致整个网络不可用。2.2 VMware虚拟网络编辑器桥接到哪块网卡必须看清在VMware里调整桥接目标路径是“编辑”-“虚拟网络编辑器”打开后可以看到VMnet0。由于VMware默认把VMnet0设为“自动桥接”这时它可能会桥接到WiFi或者别的虚拟网卡上需要手动修改为“桥接到”指定的物理网卡。下拉列表里会出现主机上所有的网卡包括真正的有线网卡、WiFi网卡甚至其他虚拟机软件留下的虚拟网卡。你要做的就是选中连接开发板的那块有线网卡比如常见的“Realtek PCIe GbE Family Controller”或者“USB 10/100/1000 LAN”选中后确认。这一步极其关键我见过不少工程师在这里漏看配置文件全部正确开发板就是ping不通最后发现桥接的是WiFi网卡。如果是Ubuntu虚拟机网卡还需要在“虚拟机设置”-“网络适配器”里选择“桥接模式”并勾选“复制物理网络连接状态”。然后进到虚拟机系统里用ip addr查看网卡名称通常叫ens33或者ens160。2.3 Ubuntu虚拟机静态IP配置netplan写法与验证Ubuntu 18.04之后的版本默认使用netplan管理网络配置文件在/etc/netplan/目录下文件名一般是00-installer-config.yaml或01-network-manager-all.yaml。用sudo vim编辑写入固定IPnetwork: version: 2 ethernets: ens33: dhcp4: no addresses: - 192.168.1.50/24 routes: - to: default via: 192.168.1.1 nameservers: addresses: [192.168.1.1, 223.5.5.5]这里有几个注意点ens33要替换成你自己虚拟机里实际看到的网卡名用ip addr确认就行这是YAML文件缩进不能用Tab必须用空格写错一个空格netplan apply就会报错配置里的223.5.5.5是阿里公共DNS如果虚拟机不需要上外网这段不填也没问题。修改之后执行sudo netplan apply ip addr show ens33看到ens33已经变成192.168.1.50就说明配置生效了。如果在执行netplan apply时提示找不到文件或YAML语法错误检查一下文件名后缀和缩进。2.4 主机侧网卡配置与开发板侧IP设置主机有线网卡的配置比较简单打开Windows的“网络连接”找到有线网卡对应的以太网适配器右键属性双击“Internet协议版本4TCP/IPv4”选择“使用下面的IP地址”填入192.168.1.20、255.255.255.0。网关可以留空因为这块网卡只是用来连接开发板的不需要接外网。开发板这边的设置需要分两种情况。如果开发板启动后进入了完整的Linux系统可以直接用命令配置ifconfig eth0 192.168.1.100 netmask 255.255.255.0 up如果开发板停留在u-boot阶段还没有启动内核而你又想在u-boot里直接用TFTP下载内核那就要在u-boot环境变量里设置setenv ipaddr 192.168.1.100 setenv serverip 192.168.1.50 saveenv这里的serverip指向的是Ubuntu虚拟机IP因为TFTP服务在虚拟机里。全部配置完成后从开发板ping虚拟机和主机从虚拟机ping开发板三方都通了再进入下一步。如果还有谁ping不通先别往下走把问题解决了再说否则后续NFS和TFTP排错会叠加两个变量非常难受。3. 打通开发板与虚拟机的两条数据通道NFS挂载与TFTP传输网络通了之后开发板和虚拟机之间的数据交换就有了基础。嵌入式开发中最常用的两条链路是NFS和TFTP。TFTP负责在开发板还没启动完整系统时把内核镜像和设备树拉到板载内存NFS负责在系统启动后让开发板直接挂载虚拟机上的目录运行编译好的程序。这两条链路是嵌入式联调的黄金搭档。3.1 为什么开发板需要挂载虚拟机目录开发板本身的存储空间非常有限eMMC或SD卡也就几个GB而交叉编译工具链、内核源码、应用工程都放在性能强劲的Ubuntu虚拟机里。如果每次调试都手动拷贝可执行文件到开发板效率极低而且开发过程中代码会频繁修改根本拷贝不过来。NFS的解决方案是把虚拟机上的某个目录直接当作开发板的一个文件夹来使用。开发板上的程序运行到这个目录时数据其实是通过网线从虚拟机传输的。这样一来你在Ubuntu虚拟机里编译出新的版本开发板这边立即就能运行到新程序完全不需要拷贝。对于嵌入式应用调试来说这个工作方式几乎是必需品。3.2 Ubuntu侧NFS服务配置与exports权限细节在Ubuntu虚拟机里安装NFS服务端sudo apt update sudo apt install nfs-kernel-server -y创建共享目录并设置权限mkdir -p /home/你的用户名/nfs_root chmod 777 /home/你的用户名/nfs_root然后编辑/etc/exports文件在末尾加一行/home/你的用户名/nfs_root 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)这一行解释了NFS共享的所有关键参数192.168.1.0/24表示允许这个网段内的设备访问rw表示可读写sync表示数据同步写入磁盘牺牲一点性能换稳定性no_root_squash表示允许开发板上的root用户保持root权限访问这个目录嵌入式开发板上都是root用户不加这个参数经常会出现权限拒绝no_subtree_check是减少目录校验、提高兼容性的常用选项。配置完执行sudo exportfs -ra sudo systemctl restart nfs-kernel-server showmount -e 192.168.1.50如果能列出刚配置的共享目录路径NFS服务端就正常了。如果exportfs命令报错检查exports文件里有没有多空格或者路径写错。3.3 开发板挂载NFS的常见参数与报错开发板系统起来后创建挂载点并执行挂载mkdir -p /mnt/nfs mount -t nfs -o nolock,nfsvers3,hard,intr 192.168.1.50:/home/你的用户名/nfs_root /mnt/nfsnolock这个参数在嵌入式环境里几乎是必加的因为很多开发板内核没有启用NFS锁相关模块不加会提示锁失败nfsvers3强制用NFSv3协议兼容性比默认的v4更好尤其是那些旧版本内核的开发板。挂载后cd /mnt/nfs ls能看到虚拟机共享目录里的文件就算成功了。如果挂载报access denied先检查开发板的IP是不是在192.168.1.0/24网段内再检查虚拟机防火墙是否放行了NFS端口最后确认exports里的网段是否写对。如果报Operation not permitted多半是no_root_squash没加回到exports文件补上再exportfs -ra。如果挂载后操作目录卡死那就是网络断连了先回头检查网络。3.4 TFTP传输u-boot阶段下载内核和设备树开发板还没启动Linux之前无法挂NFS目录此时需要TFTP帮忙。TFTP是一个极其简单的文件传输协议没有认证、没有目录浏览就是简单粗暴地把文件从服务端拉到客户端非常适合u-boot这种带网络功能但资源有限的引导程序使用。在Ubuntu虚拟机里安装TFTP服务sudo apt install tftpd-hpa -y sudo vim /etc/default/tftpd-hpa把配置文件修改为TFTP_USERNAMEtftp TFTP_DIRECTORY/srv/tftp TFTP_ADDRESS0.0.0.0:69 TFTP_OPTIONS--secureTFTP_DIRECTORY就是tftp服务的根目录把你需要下载到开发板的内核镜像zImage和设备树文件xxx.dtb都放到这个目录下并确保权限可读sudo cp zImage /srv/tftp/ sudo cp 你的开发板设备树.dtb /srv/tftp/ sudo chmod -R 777 /srv/tftp sudo systemctl restart tftpd-hpa开发板的u-boot里已经设置了ipaddr为192.168.1.100、serverip为192.168.1.50那么执行tftp 0x80800000 zImage0x80800000是内存加载地址要按开发板实际DDR起始地址来填通常是板子厂商提供的默认值。下载过程如果出现Loading: T T T T基本就是网络问题重点排查serverip是不是指向了虚拟机、虚拟机防火墙有没有放行UDP 69端口、以及/srv/tftp目录权限。3.5 三条链路合起来的完整调试流程一个典型的嵌入式开发流程是这样的在Ubuntu虚拟机里编译好内核和设备树把文件复制到/srv/tftp开发板开机进入u-boot设置好网络环境变量后用tftp命令把内核和设备树下载到内存启动系统起来之后再执行NFS挂载把虚拟机上存放应用代码的目录挂载到开发板直接运行其中的程序。整个过程不需要插拔SD卡不需要读卡器改完代码重新编译就能立刻在开发板上验证。这也是为什么网络连接是嵌入式开发的基本功因为后面所有高效率的工作流都建立在稳定网络之上。4. 网络连不通时的完整排查链路从“激活失败”到“ping不通”网络问题千奇百怪但如果掌握了排查方法绝大多数问题都能在十分钟内定位。这一章用排查链路的方式梳理常见故障遇到问题的时候按顺序逐项检查比自己瞎试命令高效得多。4.1 Ubuntu 20.04网络连接激活失败的处理很多人在VMware里装完Ubuntu桌面版开机后右上角网络图标一直转动点击“有线网络”也没反应提示“网络连接激活失败”。这种情况在Ubuntu 20.04上尤其常见。首先要检查虚拟机设置里网卡是否勾选了“已连接”和“启动时连接”。这一步很多人忽略VMware有时候升级或加载虚拟机时会把网卡的这个选项默认取消掉导致系统认为没插网线。如果网卡已连接问题多半出在NetworkManager和netplan的配置冲突。虚拟机里可能同时存在两个网络管理工具一个通过/etc/network/interfaces管理一个通过/etc/netplan管理两边都想控制同一块网卡就会发生冲突。处理办法是如果虚拟机用的是服务器版且希望用netplan统一管理就禁用NetworkManager对有线网络的控制sudo systemctl stop NetworkManager sudo systemctl disable NetworkManager sudo netplan apply如果用的是桌面版、还需要NetworkManager管理网络连接那就在netplan配置里把renderer从networkd改为NetworkManager示例如下network: version: 2 renderer: NetworkManager ethernets: ens33: dhcp4: no addresses: - 192.168.1.50/24改完保存并执行sudo netplan apply然后在右上角网络图标里点击连接有线网络。如果还是不行就重启虚拟机。大多数“激活失败”问题在这一步就能解决。4.2 虚拟机与开发板互相ping不通的逐层排查这是最让人头疼的问题也是最常遇到的。按照以下顺序逐层排查不要跳步骤。第一层确认各设备IP。在虚拟机里执行ip addr在主机Windows命令行执行ipconfig在开发板上执行ifconfig确认三者IP都在192.168.1.0/24网段。这一步能过滤掉一大半的“配置错误”问题。第二层主机ping开发板。如果主机ping不通开发板问题出在物理链路或开发板网络没启动。检查网线是否插好、网口灯是否亮、开发板网卡是否已经up。USB转网口的线缆质量也值得怀疑劣质USB网卡在长时间传输时不稳定建议换一根网线或换一个USB口测试。第三层主机ping虚拟机。如果主机ping不通虚拟机且虚拟机是桥接模式多半是Windows防火墙阻止了ICMP回包。临时关闭Windows防火墙测试如果通了就去防火墙高级设置里放行“文件和打印机共享回显请求 - ICMPv4-In”规则。如果关闭防火墙也没用检查虚拟机的桥接目标网卡是否选对。第四层虚拟机ping开发板。如果前三层都通了但虚拟机和开发板互相不通那就要回到VMware虚拟网络编辑器确认VMnet0桥接的物理网卡是不是开发板所在的那块网卡。这是桥接模式下最容易被忽略的一个点。第五层查看ARP表。在主机执行arp -a如果开发板对应IP的MAC地址显示incomplete说明二层通信都不完整物理链路或网卡驱动有问题。总结成一句话网络排查顺序永远是物理链路、IP配置、防火墙、桥接目标不要反向排查。4.3 TFTP和NFS服务端问题速查服务端问题相对好定位大多数情况下错误提示就已经说明了原因。对于TFTP如果开发板u-boot提示Timeout查看虚拟机防火墙是否放行UDP 69端口以及/srv/tftp里文件是否存在。如果提示File not found但文件名明明存在检查是不是大小写写错了u-boot和TFTP服务都是区分大小写的。如果提示Access violation把/srv/tftp权限改成777试试。对于NFS开发板挂载时提示access denied依次检查exports里网段是否覆盖开发板IP、目录权限是否可读可写、是否缺失no_root_squash。提示protocol not supported在挂载命令里加nfsvers3强制指定一把。提示server not responding先确认开发板和虚拟机之间网络是否还在很多时候是因为虚拟机睡眠导致服务暂时无响应唤醒后重新挂载即可。4.4 几个容易忽略的小细节防火墙、VMware Tools、网卡改名防火墙是排查网络问题时的重灾区。Ubuntu虚拟机里执行sudo ufw status如果是active状态要么执行sudo ufw disable关闭要么用sudo ufw allow from 192.168.1.0/24放行指定网段。Windows防火墙和第三方安全软件同样可能拦截流量尤其是那些带网络防护的安全软件很容易在桥接模式下拦截虚拟机的数据包。VMware Tools对网络也有影响。有时候安装完VMware Tools虚拟机的网卡驱动会从e1000e切换到vmxnet3性能虽然更好但某些老内核的开发环境无法识别。如果网络在安装Tools之后变怪可以在虚拟机设置里把网卡类型改回e1000e试试。还有一个在克隆虚拟机后容易出现的问题网卡名称改变。比如原来的配置是针对ens33的克隆之后系统里的网卡变成了ens34netplan配置就不生效了。执行ip addr看清楚当前网卡真正叫什么再修改netplan里的接口名。5. 连接之后的进阶玩法外部访问、远程监控与工业场景三方网络打通之后能做的事就不只是传文件了。结合我在实际项目里用到的场景再说几个比较有代表性的进阶玩法。5.1 主机和其他机器如何访问虚拟机里的Web服务如果你在虚拟机里运行了一个Web服务或者开发板的Web管理界面反向代理主机访问虚拟机最简单的方式是直接浏览器输入虚拟机IP。在桥接模式下虚拟机和主机在同一个局域网虚拟机IP 192.168.1.50直接在主机浏览器打开就能访问。如果用的是NAT模式主机也可以访问虚拟机IP因为VMnet8这个虚拟网卡在主机上主机天然能路由到虚拟机的IP。但局域网里的其他机器想访问虚拟机就做不到了。这时可以在VMware虚拟网络编辑器里选中NAT模式对应的VMnet8点击“NAT设置”添加一条端口转发规则比如把宿主机的8080端口转发到虚拟机的80端口这样其他机器通过访问主机IP:8080就能到达虚拟机里的Web服务。5.2 隔离网络中开发板的对外访问有时候开发板放在一个独立的测试网段里外部机器想访问它的调试接口但又不希望开发板直接暴露在办公网中。这种场景可以采用端口转发思路用Ubuntu虚拟机作为中转在虚拟机上把公网侧某个端口映射到开发板IP的对应端口。简单做法是在虚拟机上用iptables做DNAT例如sudo sysctl -w net.ipv4.ip_forward1 sudo iptables -t nat -A PREROUTING -d 192.168.1.50 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80 sudo iptables -t nat -A POSTROUTING -p tcp --dport 80 -j MASQUERADE这样外部机器访问虚拟机的8080端口实际访问的是开发板的80端口。当然这种方式适合临时的工程项目测试生产级的方案应该直接配置交换机ACL或防火墙策略。5.3 在虚拟机里部署zabbix把开发板纳入监控如果你手里有多块开发板或者有一批嵌入式设备在运行想统一监控它们的在线状态和系统负载zabbix是一个不错的选择。Ubuntu虚拟机里部署zabbix-server开发板上部署zabbix-agent前提同样是网络互通。虚拟机里安装zabbix-server后将监听端口10051开发板部署agent后监听10050端口。zabbix Web界面添加主机时填开发板的IP地址选择对应模板等几十秒就能看到CPU、内存、磁盘、网络流量之类的指标。配置的关键依然是网络zabbix-server必须能通过10050端口访问到开发板agent反过来开发板也要能访问zabbix-server的10051端口。如果添加主机后显示Unreachable检查开发板和虚拟机之间的防火墙配置。5.4 工业组态场景的相通之处这个问题的底层逻辑在工业领域也完全一样。比如用VMware运行TIA博途软件去连接西门子PLC推荐的网络连接模式同样是桥接。原因与开发板联调完全一致TIA需要和PLC处于同一网段才能在项目里搜索到设备并建立在线连接。如果虚拟机用NAT模式TIA找不到网段内的PLC这时候不管怎么设置PG/PC接口都白搭。所以只要理解了“让VMware里的系统与外部设备处于同一网络是互访的前提”这个原则不管是连开发板、连PLC还是连其他嵌入式设备思路都是相同的。最后再说几句实际的在整个VMware、主机、开发板的网络连接配置中我最想叮嘱新手的就一点先把网络模式选对再谈IP配置最后才谈TFTP和NFS。顺序不要反。很多人一上来就在开发板里敲NFS挂载命令结果网络模式是NAT挂载不上然后怀疑是命令问题、服务问题折腾一晚上其实根子在最开始的选型上。另外一个小技巧是每次修改网络配置之前先给虚拟机做一个快照。netplan配置写错导致网络起不来这种事太常见了有快照在手恢复是秒级的事不然你可能要在控制台里折腾半天。最后如果碰到非常奇怪、怎么排查都解释不通的网络现象试着把VMware的虚拟网络服务重启一次在Windows的“服务”管理里找到VMware DHCP Service和VMware NAT Service重启后再试。这个问题用一句话说就是网络连接在VMware里不是玄学只要模式对、IP对、防火墙通剩下出问题的概率就非常低了。