简介:一份Mininet网络仿真实验报告,适合网络工程、计算机等专业学生完成《网络应用设计与系统集成》课程实验时参考,帮助快速掌握Mininet可视化工具及Python脚本构建网络拓扑的方法。报告完整呈现了实验目的、实验内容、技术背景与操作要点,具体涵盖Miniedit图形化创建拓扑、命令行创建最小/线性/单交换机拓扑、交互式界面添加主机与交换机、节点间ping测试,以及编写Python脚本构建linear、single、tree等拓扑并对主机CPU、链路带宽、延迟、丢包率等性能参数进行限制。资源为1个doc文档,压缩包共1.37MB,内容页数较多、步骤截图清晰,便于对照练习与撰写实验报告。已有1066人学习下载,适合需要系统梳理Mininet操作流程、完成课程实验或准备SDN相关实践考核的学生使用。
1. 写Mininet实验报告的第一步:先想清楚这份报告要证明什么
周日晚十一点,一整套看上去很完整的Mininet实验报告被老师打回重写:拓扑截图有、pingall全通、iperf测出30Mbps带宽、Wireshark里还抓到了几条OpenFlow报文。但老师只反问了一句:这个带宽是TCP还是UDP测的?丢包率在哪个环节设置的?——这份报告只有结果,没有过程。
Mininet实验报告不是把终端输出粘贴成册,而是让读报告的人能按你的步骤,在同样的环境里复现出同样的数据。它要证明的是三件事:环境真的搭起来了、控制面和数据面真的按预期工作、测量结果确实反映了你设置的那组参数。这个逻辑一旦立住,后面的命令、截图、表格都会有归属感,而不是拼凑。
所以这篇笔记按我的习惯来拆:先跑通Mininet的最小环境并留下报告级证据,再抓OpenFlow协商、测iperf、记链路参数,然后专门讲那些看起来成功其实是假象的坑,最后把手工操作脚本化,让实验报告经得起复现。
2. 用Mininet把实验环境拉起来:最小命令、CLI验证与报告级证据
2.1 动手前先确认Mininet真的可用:三种安装形态下的检查顺序
很多实验报告翻车,第一刀就砍在环境上。有人用的是虚拟机镜像里的Mininet,有人是在物理机上apt装的原生包,还有人跑在WSL里——这三种形态的可用性完全不一样。我的建议是:先不要写任何报告内容,把一组检查命令按顺序跑一遍,确认你最依赖的几个能力在。
which mn && mn --version sudo mn --test pingall sudo ovs-vsctl show sudo mn -c逻辑说明:which mn确认命令行工具在PATH里,mn --version看版本号,报告里这两行输出可以放在“实验环境”一节;sudo mn --test pingall会用默认的minimal拓扑(1台交换机连2台主机)自动创建网络、执行pingall然后退出,如果这条路通,说明最基础的命名空间与虚拟网卡链路没问题;sudo ovs-vsctl show是确认Open vSwitch控制进程真的活着,后面的OpenFlow实验全靠它;最后sudo mn -c是清理上一次可能残留的网桥和命名空间。
参数说明:默认拓扑是--topo=minimal,只含h1、s1、h2三个节点,适合做冒烟测试。如果这一步pingall就不通,先别折腾后面的控制器,百分之九十五是环境问题——比如宿主机上装了Docker,docker0网桥与Mininet的网段冲突,或者VMware/NAT网络模式下虚拟网卡MTU被改小了。把这些排查过程写进报告的“异常记录”里,反而是加分项。
我一般还会顺手确认一下Wireshark和tshark是否可用,因为后面要抓OpenFlow报文。缺了就sudo apt install tshark先装好。不要在实验做到一半才想起来抓包工具没有,那是给自己挖坑。
2.2 写进报告的最小拓扑命令:拓扑、控制器与链路参数怎么选
报告里“实验步骤”部分最忌讳只写半行命令。下面这条命令是SDN相关实验最常见的起手式,它同时把拓扑、控制器、链路参数都定义好了,适合直接作为报告的“实验组网”依据。
sudo mn --topo=single,3 \ --controller=remote,ip=127.0.0.1,port=6653 \ --link=tc,bw=2,delay=10ms,loss=1 \ --switch=ovs逻辑说明:--topo=single,3表示1台交换机连接3台主机,是最小的“单交换机组网”,画拓扑图时最直观;--controller=remote,ip=127.0.0.1,port=6653表示交换机去连接一个外部控制器,而不是用Mininet自带的none控制器,这样你后续才能观察到真实的OpenFlow协商与流表下发;--link=tc,bw=2,delay=10ms,loss=1是用Linux tc机制给每条虚拟链路限带宽2Mbps、加10ms延迟、加1%丢包率;--switch=ovs明确使用Open vSwitch。
参数说明:这三个参数是报告里最容易被问到的。bw单位是Mbps,delay单位是ms,loss是百分比。为什么用tc而不是默认的无限制链路?因为tc会给每对veth网卡挂上htb队列规则,真正模拟带宽天花板,实测iperf结果才会出现稳定的瓶颈值。如果你不写--link=tc,Mininet默认是空链路,iperf跑出来的带宽就是本机回环能跑多少跑多少,那个数字基本没有实验意义。
拓扑起来后,Mininet会进入交互式CLI,提示符长得像mininet>。报告里至少要留下这几条命令的输出:
mininet> pingall mininet> iperf h1 h2 mininet> sh ovs-ofctl dump-flows s1 mininet> exit逻辑说明:pingall验证所有主机之间的连通性,报告里必然要放,正常的输出是*** Results: 0% dropped (6/6 received);iperf h1 h2是Mininet封装的带宽测试,直接输出两个方向的平均吞吐;sh ovs-ofctl dump-flows s1是进入OVS内部查看流表,控制器是否下发规则、规则超时时间是多少,一眼就能看出来;exit退出CLI并拆除网络。
2.3 报告级证据的截法:用script命令留存完整运行日志
很多同学交报告是从终端窗口截图,图里只有命令和结果,前面的警告信息被滚动条吞掉了。老师想看的是完整的实验过程,而不是一张精心裁切的结果图。我用一个很土但可靠的办法:用script命令把整段操作录成文本日志,报告中引用日志片段,原始文件作为附件。
script -q mininet_run.log sudo mn --topo=single,3 --controller=remote,ip=127.0.0.1,port=6653 mininet> pingall mininet> exit exit逻辑说明:script -q启动后,终端所有输出会同时写入mininet_run.log,直到你再次输入exit结束录制。这个日志文件是“过程证据”,比截图更有说服力。报告里你可以用等宽字体引用其中几行,并注明“完整日志见附件mininet_run.log”。
这里有个小习惯:录日志前先执行export LC_ALL=C,保证终端输出是英文而不是本地化语言。否则录下来的日志里混着中文提示,报告排版容易乱,复现时也容易让人误读状态。
3. 报告里最值钱的四张证据:控制器协商、iperf数值、链路参数与表格化结论
3.1 用tshark抓OpenFlow协商:证明你的实验不是“OVS自学习”在冒充控制面
一个合格的Mininet实验报告,不能只证明“网络通了”,还要证明“是这个控制器让网络通的”。这里的关键证据是OpenFlow握手与PacketIn消息。我通常不用Wireshark图形界面,而是在控制器的同一台机器上用tshark抓包,切出文本记录放进报告。
sudo tshark -i any -f "tcp port 6653 or tcp port 6633" \ -T fields -e frame.number -e ip.src -e tcp.srcport -e openflow_v4.type逻辑说明:-i any抓取所有网卡,因为控制器流量可能走loopback;-f是抓包过滤,只保留与OpenFlow相关的TCP端口;-T fields让tshark输出指定字段,其中openflow_v4.type是OpenFlow 1.3消息类型字段。启动tshark后,再启动一个连到该控制器的Mininet拓扑,你会看到类似4 127.0.0.1 6653 5的输出,表示收到一条OFPT_FEATURES_REPLY。
参数说明:OpenFlow协议里常见的type值:0是HELLO、4是FEATURES_REQUEST、5是FEATURES_REPLY、10是PACKET_IN、14是FLOW_MOD。报告里只要出现了0和5,就说明交换机与控制器完成了握手;出现了10,说明第一个数据包触发了PacketIn上报;后续再出现14,说明控制器下发了流表。这三类消息凑齐,控制面逻辑就完整了。
有一个非常容易踩的坑:如果启动Mininet时用的是默认控制器(不带--controller=remote),Mininet会自己拉一个控制器进程,报告里写“连接了外部控制器”就是虚假描述。抓包时看连接对端IP是不是127.0.0.1的6653端口,这个细节能帮你的报告自证清白。
3.2 iperf数值不能只报平均值:TCP重传、窗口与UDP模式的差异
老师问“30Mbps是TCP还是UDP”,问的就是测量方法的边界。Mininet CLI里直接敲iperf h1 h2,底层其实是让h1起服务端、h2起客户端,默认用TCP。这个数字受TCP拥塞窗口、接收窗口和网卡卸载机制影响,和链路bw参数不一定对得上。我一般在报告里做两组测量:TCP吞吐和UDP极限吞吐。
mininet> xterm h1 h2 # 在h1的窗口里执行 iperf -s -t 20 -i 2 # 在h2的窗口里执行 iperf -c 10.0.0.1 -t 20 -i 2 -w 64k # UDP模式,h1端 iperf -s -u -t 20 # h2端 iperf -c 10.0.0.1 -u -t 20 -b 5m逻辑说明:iperf -s是服务端,-t 20表示持续20秒,-i 2表示每2秒打印一次中间结果;客户端用-c指定服务端IP,-w 64k指定TCP窗口为64KB;UDP模式在两端都加-u,-b 5m指定发送目标带宽。报告里给出TCP模式的平均带宽、UDP模式的丢包率,比只给一个数字严谨得多。
参数说明:遇到TCP模式测量结果远低于bw设定值时,优先怀疑窗口过小,试着增大-w;如果UDP模式测得带宽能接近链路bw但丢包率很高,说明链路参数设置生效了,这是一个“预期内的现象”,写进报告反而是亮点。
3.3 动态修改链路参数:验证“带宽限制”真实生效的第二个手段
静态启动参数容易让人怀疑“你是不是只在命令行里写了,实际没生效”。报告里加一组动态修改链路的实验,能把这个疑虑打掉。Mininet支持运行时把某条链路断开、更改流量控制参数,再去测一次连通性,形成“前测—变更—后测”的闭环。
mininet> link h1 s1 down mininet> ping h1 h2 mininet> link h1 s1 up mininet> py net.h1.cmd('tc qdisc show dev h1-eth0')逻辑说明:link h1 s1 down会把h1与交换机之间的虚拟链路设为down,此时h1到h2的ping必然不通,输出connect: Network is unreachable;link h1 s1 up恢复链路后,再ping就恢复通。这段过程截图放进报告,能直接证明拓扑中的链路由Mininet管理,而不是宿主机上的物理以太网“碰巧通了”。
参数说明:最后一行py net.h1.cmd('tc qdisc show dev h1-eth0')是进入Python运行时,在h1的网络命名空间里执行tc命令,查看h1-eth0上挂的队列规则。输出中含有netem delay 10ms和rate 2Mbit,这就是你在启动命令里设的参数已经落地到虚拟网卡的直接证据。
3.4 用一张表格把测量结果装进去:报告结论的规范结构
报告末尾的实验结果部分,我习惯用一张表把环境参数、测量方法和结果对齐,避免大段文字里藏着关键数字。下面这种结构可以直接套用:
| 实验项 | 链路参数 | 测量方法 | 测得结果 | 备注 |
|---|---|---|---|---|
| 基本连通性 | 无限制 | pingall | 0% dropped (6/6) | 默认minimal拓扑 |
| TCP吞吐 | bw=2, delay=10ms | iperf -t 20 | 1.87 Mbps | 接近限速 |
| UDP吞吐 | bw=2, delay=10ms | iperf -u -b 5m | 2.01 Mbps, 12% loss | 达到瓶颈 |
| 动态断链 | 同上 | link down/up | 断链不通,恢复后通 | 验证链路管理 |
这张表的好处是:老师第一眼就能看到“链路限速2Mbps,实测TCP约1.87Mbps”,理解你做了什么、得到了什么。表里一定要写“接近限速”而不是“正好2Mbps”,因为tc的htb限速本身有少量误差,写得太精确反而显得是编的。
4. Mininet实验常见假象与排查:数据面通了但控制面没跑、带宽测不准
4.1 现象一:pingall全通过,但控制器日志里没有任何OpenFlow消息
这个现象我见了太多次:报告写的是“控制器下发流表使网络互通”,实际实验时把--controller=remote写错成--controller=none,或者外部控制器没启动,但网络照样ping全通。原因是Open vSwitch在没有任何控制器连接时,会进入一个fallback模式,自己像普通二层交换机一样做MAC地址学习与转发。也就是说,数据面“通”了,但控制面根本没参与。
排查方法分三步:先确认Mininet启动时是否带了--controller=remote;再检查OVS到底连没连上控制器,执行ovs-vsctl show看controller列表是否为空;最后看tshark有没有抓到握手包。报告里写明这三步的排查过程,比掩饰问题更能体现实验素养。
4.2 现象二:iperf测出来的带宽是链路限速的好几倍
有同学在bw=2的链路上测出30Mbps,第一反应是参数写错了,其实不然。Mininet的虚拟链路走的是Linux内核协议栈,当TCP发送数据时,网卡的TSO/GSO/GRO卸载机制会提前把数据聚合、绕过一部分队列限制,导致测出的吞吐高于htb设定的速率。另外,iperf的TCP模式如果在同一主机上的两个命名空间之间跑,回环路径的缓冲也可能让结果失真。
解决方法是在测试前关闭收发端的卸载功能,在Mininet CLI里执行:
mininet> py net.h1.cmd('ethtool -K h1-eth0 tso off gso off gro off') mininet> py net.h2.cmd('ethtool -K h2-eth0 tso off gso off gro off') mininet> iperf h1 h2逻辑说明:ethtool -K关闭网卡的TCP分段卸载、通用分段卸载和通用接收卸载,让每个数据包按真实大小进入队列,htb限速才能准确生效。做这一步后重新跑iperf,结果通常会回到接近bw设定值。这个操作可以写进实验步骤里作为“测量前置条件”,它会显著提高报告的可信度。
4.3 现象三:Mininet里ping得通,换个终端在宿主机上ping不通实验IP
这是命名空间的认知偏差。Mininet创建的主机都在独立网络命名空间里,10.0.0.x这个地址只存在于命名空间内部。在宿主机上直接ping 10.0.0.1,宿主机自己的路由表和ARP表里根本没有这个地址,自然会失败。这不是实验有问题,是“从外面ping里面”本身就不该通。
解决方法是:所有针对实验主机的操作都要进入Mininet环境执行,要么用CLI里的h1 ping h2、xterm h1,要么用py net.h1.cmd('ifconfig h1-eth0')在命名空间里执行命令。报告里如果放了宿主机route -n的输出,再加一句“所有测量均在Mininet命名空间内进行”,能避免读报告的人产生同样的误解。
4.4 现象四:上次实验的痕迹没清干净,重启时报“端口被占用”或“网桥已存在”
Mininet异常退出后,OVS网桥、veth网卡对和命名空间不会自动拆除。下次再启动时,系统里残留的ovsbr0或s1就会与新拓扑冲突,报错五花八门。我每次实验前都会无脑执行一条清场命令:
sudo mn -c sudo pkill -f ovscontroller逻辑说明:mn -c是Mininet自带的清理命令,会删除所有残留网桥和命名空间;pkill -f ovscontroller是为了杀掉Mininet可能自动拉起的默认控制器进程,避免它占着6633端口影响你后续连接自定义控制器。
4.5 现象五:抓包只看到OpenFlow握手,之后看不到任何PacketIn与数据流
正常情况下,握手之后只要主机间发包,Wireshark里就应该出现PacketIn消息。如果只看到握手包,没有后续内容,多半是抓包监听位置选错了。Mininet主机的数据流量走的是各自的veth网卡,不经过物理网卡,也不是所有流量都经过loopback;tshark -i any能抓到所有接口流量,但如果你开Wireshark时只选了物理网卡,自然看不到。
另外注意过滤表达式:OpenFlow消息的TCP端口是6653(新规范)或6633(旧版),有些发行版里OVS默认监听6633,控制器对端端口不一致时握手也起不来。抓包命令里把两个端口都放进去,能少踩一半的坑。
5. 把手工实验变成可复现的脚本:自定义Python拓扑与自动化产出
5.1 为什么要把--topo=single,3升级成Python拓扑脚本
命令行里的--topo只适合最简拓扑。一旦你想要“每台主机的带宽不同、延迟不同、有些链路还带丢包”,命令行参数会变得又长又乱,而且报告里说不清。常规做法是写一个自定义Python拓扑文件,继承Mininet的Topo类,在build方法里定义节点和链路,脚本即拓扑,也即报告里的“组网图”文字版。
#!/usr/bin/env python3 from mininet.topo import Topo from mininet.net import Mininet from mininet.node import OVSSwitch, RemoteController from mininet.cli import CLI class LabTopo(Topo): def build(self, n=5, bw=2, delay="10ms", loss=1): s1 = self.addSwitch("s1") for i in range(1, n + 1): host = self.addHost("h%d" % i, ip="10.0.0.%d/24" % i) self.addLink( host, s1, bw=bw, delay=delay, loss=loss, use_htb=True ) if __name__ == "__main__": topo = LabTopo(n=5, bw=5, delay="5ms", loss=0) net = Mininet( topo=topo, switch=OVSSwitch, controller=RemoteController("c0", ip="127.0.0.1", port=6653) ) net.start() CLI(net) net.stop()代码逻辑说明:LabTopo继承Topo后,通过addSwitch创建交换机,通过addHost创建主机并指定IP,最后用addLink把主机与交换机连起来,同时把带宽、延迟、丢包参数挂在链路上。主程序部分把topo传入Mininet,指定交换机类型为OVSSwitch,控制器为RemoteController,连接本地6653端口。这份文件存成lab_topo.py,启动命令只需sudo python3 lab_topo.py。
参数说明:addHost里的ip="10.0.0.%d/24" % i会自动给每台主机生成同一网段递增IP,省去手动配置;use_htb=True明确告诉Mininet使用htb队列实现带宽限制,如果你不写,某些版本默认用的是netem,行为会有细微差别。
5.2 让脚本自动跑测量并保存结果:从交互式实验到自动化实验
有了自定义拓扑,还可以进一步把“测试”也写进脚本,让实验变成一条命令跑完、自动输出日志。对于报告里的“多次重复测量取中位数”,这是最省力的实现方式。
import subprocess def run_iperf(net): h1, h2 = net.get("h1"), net.get("h2") result = net.iperf((h1, h2), seconds=20) print("TCP throughput:", result) with open("iperf_result.txt", "w") as f: f.write(str(result) + "\n") def main(): topo = LabTopo(n=3, bw=10, delay="2ms") net = Mininet(topo=topo, switch=OVSSwitch, controller=RemoteController("c0", ip="127.0.0.1", port=6653)) net.start() net.pingAll() run_iperf(net) net.stop() if __name__ == "__main__": main()逻辑说明:net.iperf((h1, h2), seconds=20)是Mininet封装好的iperf调用,传入两台主机对象和测试时长,返回字符串形式的吞吐结果;pingAll()在开头执行,先保障拓扑连通,再测带宽。整段代码跑完后,屏幕上能看到完整测试过程,磁盘上多出iperf_result.txt,这份文件的路径可以写进报告的“数据附件”清单。
参数说明:seconds=20对应iperf的-t 20参数。如果链路参数改成bw=100,测试时长建议也适当缩短,带宽大时数据量增长很快,Mininet的临时文件目录可能被撑爆。
5.3 把脚本输出落进报告:三次测量与结论写法
自动化脚本跑出来的原始输出不能直接粘贴成报告结论,需要做一个简单的加工。我一般会连跑三次,把三次的吞吐值记录到一张小表里,取中位数写进结论,同时保留最大值与最小值之间的波动幅度。这个做法看起来是多花了三倍时间,但老师一眼就能看出你不是“只挑了一次好看的结果”。
| 测量次数 | 链路限速 | 实测吞吐 | 重传次数 |
|---|---|---|---|
| 第1次 | 10 Mbps | 9.62 Mbps | 3 |
| 第2次 | 10 Mbps | 9.74 Mbps | 1 |
| 第3次 | 10 Mbps | 9.51 Mbps | 5 |
| 中位数 | 10 Mbps | 9.62 Mbps | 3 |
报告中结论的写法,我习惯用一句话模板:“链路限速10Mbps下,三次TCP吞吐测试的样本中位数为9.62Mbps,波动范围9.51~9.74Mbps,与tc限速值偏差小于5%,说明链路参数设置有效。”这种写法把参数、方法和结果绑在一起,不需要多余的修饰。
6. 实验报告可信度自检:三次测量、留存日志、写明边界
6.1 一个能反复使用的自检命令:测三遍并分别留存日志
如果你用的是自带--test参数的Mininet,自检阶段可以写一个简单的bash循环,把三次测量结果分别存成独立文件,后续对比它们的差异。
for i in 1 2 3; do sudo mn --topo=single,2 \ --link=tc,bw=10,delay=2ms \ --controller=remote,ip=127.0.0.1,port=6653 \ --test=iperf > /tmp/mininet_$i.log 2>&1 sleep 1 done逻辑说明:循环三次执行Mininet并自动跑iperf测试,每次结果写入不同的日志文件。跑完后可以grep -E "throughput|Mbits" /tmp/mininet_*.log快速对比三次吞吐。这里的--test=iperf等价于启动拓扑后自动执行iperf并退出,不需要人工介入,适合做批量重复实验。
6.2 报告里写清测量边界的一句惯用收尾
我这边踩过最尴尬的一次,是在报告里写了“实测带宽20Mbps,符合预期”,结果老师追问“这个20Mbps是VM里的虚拟链路,还是物理机的真实链路?”当时我压根没在结论里区分实验环境与真实环境。之后我养成了一个习惯:每个实验报告的结论段都会加一句边界说明,比如“本次所有测量均在Mininet虚拟网络命名空间内完成,链路为veth虚拟网卡与tc队列模拟,不代表真实物理网络性能”。
写清楚这个边界,不是为了给自己开脱,而是让实验结论站得住:你验证的是Mininet环境下的组网与控制面逻辑,不是物理网络的性能指标。读报告的人不会再拿真实网卡的标准来质疑你的虚拟链路。
这些自检动作看起来很琐碎,但真的能救急。我认识不少同学,报告被打回后才发现自己贴的iperf结果是同事跑出来的,或者用的拓扑参数与实际不一致。数据留痕、三次测量、边界标注,这三步做好了,你交出去的Mininet实验报告才算真正“闭环”。希望帮到你。
本文还有配套的精品资源,点击获取