简介:一份面向Mininet网络仿真学习的完整实验报告,适合高校网络工程或软件定义网络课程学生参考。报告基于西安财经大学《网络应用设计与系统集成》实验一内容,系统介绍了运用Miniedit可视化工具、命令行方式、交互式界面以及Python脚本构建网络拓扑的方法,并演示了主机、交换机配置与ping测试等操作。全文16页,以doc格式提供,共1个文件,包体大小为1.37MB,内容按实验目的、实验内容、技术背景、操作要点逐步展开。除了基础技能,还深入展示了基于Python脚本自定义topo linear、single、tree等拓扑,以及通过addHost、addLink限制CPU、带宽、延迟、损耗率等参数开展性能实验的思路。已有1067人学习浏览,适合需要完成Mininet实验、加深SDN拓扑理解或撰写实验报告的学生使用。1. 第一次用Mininet做网络实验:仿真器不等于模拟器手里只有一台电脑,却要交一份带拓扑截图和ping测试结果的网络实验报告——这是很多人在网络课程里遇到的第一道坎。我当时拿到这份Mininet实验报告的第一反应是:这玩意儿跟VMware里开几台虚拟机有什么区别?做完才发现,Mininet用的是进程虚拟化,不是整机虚拟化,一条sudo mn --topo single,2命令就能在几秒内拉起一个交换机加两个主机的网络,还能直接跑Wireshark、Open vSwitch和OpenFlow协议。这篇笔记把实验里三种建网方式(可视化、命令行、Python脚本)的完整操作和踩过的坑都拆开讲,适合正在做网络实验、SDN入门或者需要快速搭仿真拓扑验证想法的人。读完你不仅能照步骤复现整个实验,还能避开我在虚拟机环境和脚本导出上翻过的车。2. Mininet的三种建网方式:从miniedit可视化到命令行2.1 先理解Mininet的轻量级虚拟化做过传统网络实验的人都知道,用GNS3或EVE-NG搭拓扑要下载思科或华为的设备镜像,启动慢、占用高、还受限于厂商命令体系。Mininet的方案完全不同:它不模拟硬件,而是用Linux的命名空间(network namespace)加虚拟以太网对(veth pair),把主机、交换机、链路都当成一个个进程来跑。所以Mininet里每个host都有自己的独立网络栈,能跑真实的应用程序,但CPU和内存开销远小于开几台虚拟机。这个设计带来两个直接影响。第一,Mininet里跑的程序就是真实Linux程序,不是阉割版,实验报告里提到的Wireshark、iperf、tcpdump这些工具都能直接装进去抓包测速。第二,它天然支持OpenFlow协议,拓扑里的交换机可以指定由远端或本地的控制器来管理,这也是它成为SDN实验首选平台的原因。理解这点后再看后面三种建网方式就清楚了:无论用哪种方式创建拓扑,最终生成的都是一组进程和网络命名空间,只是入口不同。2.2 miniedit可视化创建拓扑miniedit是Mininet自带的图形化拓扑编辑器,适合第一次接触网络仿真的人,拖拽就能建拓扑,不需要背命令。启动前需要先拿到root权限,因为Mininet对网络命名空间的操作必须要root。sudo su cd ~/mininet/examples ls miniedit.py python3 miniedit.py这段操作里,sudo su切换root之前要先确认Mininet安装目录,常见位置是~/mininet/examples,如果找不到可以用find / -name miniedit.py搜一下。直接运行miniedit.py会弹出图形界面,画布左侧是主机、交换机、控制器等组件图标,拖到画布就能连线建拓扑。注意一定用python3而不是python,有些旧系统默认的python还是2.x,跑起来会直接报语法错误。拓扑建好后要逐项配置。右键点击主机选Properties,可以改主机名和MAC地址,这不只是表面功夫,后面ping测试和ifconfig看到的就是这里设置的参数。交换机和控制器也要分别配置,交换机的OpenFlow协议版本要选和控制器匹配的,不然控制器连上来会话会反复断开。配置完成后,关键一步是菜单栏的“Edit → Preferences”,这里要勾选Start CLI,这样运行拓扑时会同时打开Mininet交互命令行,方便后续做ping测试。导出脚本用“File → Export Level 2 Script”,保存为.py文件后,终端执行python3 文件名.py就能看到同样拓扑被加载起来。2.3 命令行快速建网和常用命令实际上多数实验不会每次都打开图形界面,命令行反而是最常用也最快的方式。实验报告中要求用命令行创建三类拓扑:一个交换机挂两个主机、线性四跳拓扑、单交换机挂三个主机,对应三条命令:sudo mn --topo single,2 sudo mn --topo linear,4 sudo mn --topo single,3这三条命令分别对应实验报告的S2要求。sudo mn启动Mininet后默认自带一个控制器和Open vSwitch交换机,--topo参数指定拓扑类型:single,2表示一个交换机下连接两台主机,生成的节点名是h1、h2和s1;linear,4表示四个交换机串成一条线,每个交换机挂一台主机;single,3则是单交换机挂三台主机。命令里的,号前面是拓扑类型,后面是节点数量或深度,别把顺序记反了。进入mininet>交互提示符后,实验报告列的那几条命令就是核心操作集合:net查看节点间连接关系,dump能显示每个节点的接口和进程PID,pingall让所有主机两两ping一遍,h1 ping h2只测两台主机间的连通性。这里有个很实用的细节,h1 ifconfig能直接看到主机h1的IP信息,默认情况下Mininet会用10.0.0.0/8网段给每个主机的eth0接口分配IP。想退出就输入exit,或者在mininet>提示符下按Ctrl+D,不建议直接关终端,不然残留的进程可能会影响下次启动。3. 交互式界面扩展拓扑:动态添加主机和交换机3.1 用py指令直接操作Python对象Mininet的CLI不只是执行命令,还有一个看着不起眼但极其有用的py前缀。任何输入py开头的命令都会被当作Python代码在Mininet网络对象上执行。这意味着你不需要退出CLI去改脚本,就能动态添加主机、创建链路、给接口配IP,这在调试和验证想法时比反复重启整个拓扑高效得多。比如实验报告里有一段很典型的操作:启动默认拓扑(两个主机一个交换机),然后输入py net.addHost('h3'),这个net就是当前运行的Mininet网络对象,addHost方法会创建一个名为h3的新主机。这个操作完全是在运行中的CLI里完成的,新主机即刻生效,对应的进程已经起来了。你可以接着输入py net.get('h3')拿到这个主机对象,再对它执行命令,整个思路跟写Python脚本操控网络对象一模一样。3.2 手动接线和配IP的完整步骤动态添加主机只是第一步,关键是把它接入现有交换机。实验报告给出了一个完整的接线配IP序列:py net.addHost('h3') py net.addLink(s1, net.get('h3')) py s1.attach('s1-eth3') py net.get('h3').cmd('ifconfig h3-eth0 10.3') h1 ping -c1 10.3这段代码的前两行创建了主机h3,然后把它和交换机s1之间加了一条链路。第三行的attach是很多人会卡住的地方:虽然addLink已经在逻辑上建立了连接,但Mininet里每个交换机端口需要手动attach到具体接口名,s1-eth3的意思是给交换机s1增加第三个以太网接口,只有执行这一步,数据平面才算真正连通。第四行则是在h3内部执行ifconfig,给它的h3-eth0接口配置IP为10.3(这是简写,完整写法是10.0.0.3),不然即使链路通了,也没有地址可ping。最后一行在CLI里执行h1 ping -c1 10.3,-c1表示只发一个ICMP包。如果看到64 bytes from 10.3的回显,说明这条动态添加的链路已经通了。注意这行命令前面没有py前缀,因为ping本身就是Mininet CLI的保留命令,可以直接执行。这个细节容易混淆,凡是需要传递到主机内部执行的命令都要用py net.get('xxx').cmd(),而CLI自带的命令直接写。3.3 在交互模式下查看连接状态把网络对象当成Python对象操作有个好处,你可以直接用代码遍历整个拓扑。实验报告里出现的这段就是典型的连通性检查:py from mininet.util import dumpNodeConnections py dumpNodeConnections(net.hosts) py net.pingAll()dumpNodeConnections接收一个节点列表,会逐个打印每个节点的连接关系,跑完就能看到h1连在s1的哪个接口、h3连在s1的哪个接口,非常适合验证上面加主机加链路的操作有没有成功。net.pingAll()则是在所有主机间执行全互联的ping测试,返回结果会显示丢包率。比起一条条h1 ping h2去手动验证,这种批量方式在主机数量多的时候能省不少时间。这里顺带说一个排查思路。如果pingAll显示某台主机ping不通,用dumpNodeConnections先看连接关系是否完整,再用h1 ifconfig看IP是否配置到位,最后看交换机端口是否attach成功。大部分动态添加拓扑失败的场景,问题都出在接口没有配置IP或者端口没有attach,数据链路本身反而是通的。4. Python脚本构建拓扑:从linear到tree4.1 内置拓扑的三种典型形态命令行里的--topo参数只是为了快速上手,真正要复现一个可调可控的拓扑,得用Python脚本。实验报告里要求的topo linear,4、topo single,3、topo tree,depth=2,fanout=2三类拓扑,都可以借助Mininet内置的拓扑类快速生成:from mininet.topo import LinearTopo, SingleSwitchTopo, TreeTopo from mininet.net import Mininet from mininet.cli import CLI from mininet.node import OVSSwitch, Controller net = Mininet(topo=LinearTopo(4), switch=OVSSwitch, controller=Controller) net.start() CLI(net) net.stop()这段代码里,LinearTopo(4)生成四个交换机首尾相连、每个交换机挂一台主机的链式拓扑;SingleSwitchTopo(3)生成一台交换机挂三台主机的星型结构;TreeTopo(depth=2, fanout=2)则是深度为2、扇出为2的二叉树结构,展开后是1个根交换机连2个二层交换机,每个二层交换机再挂2台主机,共4台主机。switch=OVSSwitch指定交换机类型,controller=Controller用的是Mininet自带的默认控制器。CLI(net)启动后就会进入交互界面,可以继续用上一章的py命令操作网络对象。4.2 继承Topo类写自定义拓扑真正到了要复现实验报告里“1个交换机、2个主机并赋予IP”的场景,内置拓扑就不够用了,需要自己重写Topo类。Mininet的推荐做法是继承Topo基类,在build方法里用addHost和addSwitch声明节点,用addLink声明链路:from mininet.topo import Topo class MyTopo(Topo): def build(self): s1 = self.addSwitch('s1') h1 = self.addHost('h1', ip='10.0.0.1/8') h2 = self.addHost('h2', ip='10.0.0.2/8') self.addLink(h1, s1) self.addLink(h2, s1) topos = {'mytopo': (lambda: MyTopo())}addHost里的ip参数直接给主机的eth0接口配置了地址,不用进入CLI再手动ifconfig。addSwitch创建交换机节点,addLink把两个节点连起来。最后一行的topos字典是一种约定:把拓扑类注册成一个可由--topo mytopo调用的名称,方便用sudo mn --custom 文件.py --topo mytopo的方式直接加载。build方法是在拓扑创建时自动调用的,不需要显式写__init__,这也是Mininet自定义拓扑的一个惯例写法。用这个脚本启动网络和前面的方式没有区别,只是拓扑换成了自定义结构。加载后运行net.pingAll(),两台主机之间应该能顺利互ping。IP地址要设置成同一网段,不然通了链路也无法完成ARP解析和ICMP通信,这是个看起来低级但很常见的失误。4.3 controller参数和OVS端口的配合脚本里还有一个容易忽略但影响成败的设置:Controller默认监听的是本机的6653端口(旧版本是6633)。如果之前有一个没退干净的Mininet进程占用了这个端口,新脚本启动的交换机就永远连不上控制器,表现是主机之间ping不通,但dump能看到所有接口都正常。所以在启动新脚本前,养成先执行sudo mn -c清理环境的好习惯。另一个配合细节是交换机的OpenFlow协议版本。OVSSwitch默认会协商一个版本,但如果实验环境里有额外的SDN控制器(例如某些课程要求用Ryu或Floodlight),就需要注意两端版本一致。脚本里可以通过switch=OVSSwitch的构造参数或者OVSSwitch.setOpenFlow13()来指定使用OpenFlow 1.3,避免低版本导致控制器不识别流表。这份实验报告里的拓扑都是单控制器自连,用默认设置没问题,但如果后续要接入外部控制器,这个参数就避不开了。5. Mininet避坑指南:环境、权限和常见报错5.1sudo mn提示命令找不到现象:在终端输入sudo mn后提示mn: command not found。原因:Mininet安装目录没有加入到系统的PATH环境变量,或者安装时用的是源码目录直接运行而非全局安装。解决:先确认Mininet安装位置,常见路径有~/mininet/bin和/usr/local/bin。如果是源码安装,把Mininet的bin目录加入PATH,或者每次用全路径sudo ~/mininet/bin/mn启动。我一般会直接在/usr/local/bin下建个软链接:ln -s ~/mininet/bin/mn /usr/local/bin/mn,一劳永逸。5.2 miniedit导出脚本运行报ModuleNotFoundError现象:miniedit导出的xxx.py文件用python3 xxx.py运行时,报No module named 'mininet'。原因:导出的脚本默认是当前目录直接运行,Python解释器找不到Mininet的Python库路径。源码安装的Mininet通常只对root用户可用,普通用户的PYTHONPATH里没有这个路径。解决:用root身份运行是第一步,其次可以显式指定解释器的搜索路径:PYTHONPATH=/root/mininet python3 xxx.py。如果不确定Mininet模块装在哪,用python3 -c "import mininet; print(mininet.__file__)"打印实际路径再拼到PYTHONPATH后面。5.3 pingall只丢包但接口全正常现象:pingall结果中部分主机丢包,但dump和net显示所有节点和接口都正常,ifconfig也能看到IP。原因:交换机没有成功连上控制器,处于无流表状态。Mininet的交换机默认是学习交换机,只有连上控制器才能下发流表规则,控制器没连上时数据包就会被交换机丢弃。解决:检查控制器是否启动成功,在CLI里执行py net.controllers看控制器列表;然后确认没有其他进程占用6653端口,用ss -lnt | grep 6653检查。如果端口被占,先sudo mn -c清理再重来。脚本里也可以显式指定controller=Controller并调用net.start(),确保控制器先于交换机启动。5.4 在CLI里执行h1 ping h2提示未知主机现象:在mininet>提示符下输入h1 ping h2,返回ping: h2: Name or service not known。原因:这条命令被Mininet CLI解析后传给了主机的shell去执行,而Mininet为每个主机分配的是独立的网络命名空间,主机内部并没有DNS解析h2这个名称的能力。Mininet CLI只在节点名出现在命令首部时才处理主机名映射,ping的参数部分不会自动转换。解决:在CLI里可以改用h1 ping -c1 10.0.0.2这类IP直连,或者在py前缀下用net.pingAll()做全量测试。真正用主机名通信的场景应该写在Python脚本里,用h1.cmd('ping -c1 10.0.0.2')的方式执行。这个坑是第一次接触Mininet时最容易困惑的点。5.5 脚本退出后再次启动报Address already in use现象:上一次运行net.stop()或者直接关掉了终端,再次启动新的Mininet脚本时报bind: Address already in use。原因:上次的控制器进程或者Open vSwitch的后台进程没有完全退出,端口资源没有被释放。很多时候直接关闭终端或者Ctrl+C中断,Mininet的清理钩子没有执行到。解决:在任何一次实验结束后都执行sudo mn -c清理残留进程。如果mn -c也反馈有问题,可以手动查看并杀掉残留的python和ovs进程:ps aux | grep mininet、sudo pkill -f ovs-vswitchd。从那以后我每次跑新拓扑前都强制走一遍mn -c,再也没遇到过端口占用的问题。这个习惯看着多余,实则是Mininet实验里最容易翻车的环节。6. 用参数把仿真拉回现实:带宽、延迟与丢包限制6.1 addLink与addHost参数详解实验报告最后提到了一个非常关键却没展开讲的内容:给网络加性能限制。默认的Mininet拓扑所有链路都是无限制的,主机CPU也是随便用,这跟真实网络差距很大。真实路由器之间的链路有带宽上限、有传输延迟、有丢包率,仿真里想复现这些,靠的就是addLink和addHost的参数。from mininet.topo import Topo class LimitedTopo(Topo): def build(self): s1 = self.addSwitch('s1') h1 = self.addHost('h1', cpu=0.5) h2 = self.addHost('h2', cpu=0.5) self.addLink(h1, s1, bw=10, delay='5ms', max_queue_size=1000, loss=10) self.addLink(h2, s1, bw=10, delay='5ms', max_queue_size=1000, loss=10)addHost的cpu参数是百分比,0.5表示该主机最多使用单核CPU资源的50%,这限制了主机的处理能力,模拟真实终端设备性能不足的情况。addLink里的参数更直接:bw=10单位是Mbit/s,限制链路带宽为10M;delay='5ms'表示单向传输延迟5毫秒;max_queue_size=1000是交换机端口队列可容纳的最大包数,超过就丢包;loss=10表示链路丢包率10%。组合这些参数就能构造出一个接近真实环境的有损链路,而不是实验室里那种干干净净的完美网络。6.2 用iperf验证链路参数是否生效配置了参数不等于参数生效,得实测验证。Mininet的每个主机都能跑真实程序,所以直接可以用iperf来测链路带宽。在CLI里先启动h2的iperf服务端:h2 iperf -s -u -p 5001 &这条命令里-s表示服务端模式,-u指定UDP协议(测带宽和丢包率用UDP比TCP直观),-p 5001指定监听端口,&让它在h2的shell后台运行。然后在h1侧发起测量:h1 iperf -c 10.0.0.2 -u -p 5001 -b 20M -t 10-c指定对端IP,-b 20M表示H1以20Mbit/s的速率发送UDP流量,-t 10持续10秒。因为链路配置的bw是10M,所以用20M去灌肯定会触发限速,iperf输出的实际带宽应该在10M附近,丢包率也会接近配置的值。如果测出来带宽远超设定值,基本可以断定TC(Traffic Control)规则没有挂上,检查一下交换机是否用了OVS以及系统是否支持sch_netem内核模块。这种带参数量化的仿真方式,能让你在提交实验报告时拿出实打实的数据,而不是只截图一个ping通的结果。从那以后我每次做Mininet实验都会给拓扑加一两组带宽和延迟限制,再配合iperf验证,整个流程走下来才算真正把网络行为摸透了。希望帮到你。本文还有配套的精品资源,点击获取
简介:一份面向Mininet网络仿真学习的完整实验报告,适合高校网络工程或软件定义网络课程学生参考。报告基于西安财经大学《网络应用设计与系统集成》实验一内容,系统介绍了运用Miniedit可视化工具、命令行方式、交互式界面以及Python脚本构建网络拓扑的方法,并演示了主机、交换机配置与ping测试等操作。全文16页,以doc格式提供,共1个文件,包体大小为1.37MB,内容按实验目的、实验内容、技术背景、操作要点逐步展开。除了基础技能,还深入展示了基于Python脚本自定义topo linear、single、tree等拓扑,以及通过addHost、addLink限制CPU、带宽、延迟、损耗率等参数开展性能实验的思路。已有1067人学习浏览,适合需要完成Mininet实验、加深SDN拓扑理解或撰写实验报告的学生使用。1. 第一次用Mininet做网络实验:仿真器不等于模拟器手里只有一台电脑,却要交一份带拓扑截图和ping测试结果的网络实验报告——这是很多人在网络课程里遇到的第一道坎。我当时拿到这份Mininet实验报告的第一反应是:这玩意儿跟VMware里开几台虚拟机有什么区别?做完才发现,Mininet用的是进程虚拟化,不是整机虚拟化,一条sudo mn --topo single,2命令就能在几秒内拉起一个交换机加两个主机的网络,还能直接跑Wireshark、Open vSwitch和OpenFlow协议。这篇笔记把实验里三种建网方式(可视化、命令行、Python脚本)的完整操作和踩过的坑都拆开讲,适合正在做网络实验、SDN入门或者需要快速搭仿真拓扑验证想法的人。读完你不仅能照步骤复现整个实验,还能避开我在虚拟机环境和脚本导出上翻过的车。2. Mininet的三种建网方式:从miniedit可视化到命令行2.1 先理解Mininet的轻量级虚拟化做过传统网络实验的人都知道,用GNS3或EVE-NG搭拓扑要下载思科或华为的设备镜像,启动慢、占用高、还受限于厂商命令体系。Mininet的方案完全不同:它不模拟硬件,而是用Linux的命名空间(network namespace)加虚拟以太网对(veth pair),把主机、交换机、链路都当成一个个进程来跑。所以Mininet里每个host都有自己的独立网络栈,能跑真实的应用程序,但CPU和内存开销远小于开几台虚拟机。这个设计带来两个直接影响。第一,Mininet里跑的程序就是真实Linux程序,不是阉割版,实验报告里提到的Wireshark、iperf、tcpdump这些工具都能直接装进去抓包测速。第二,它天然支持OpenFlow协议,拓扑里的交换机可以指定由远端或本地的控制器来管理,这也是它成为SDN实验首选平台的原因。理解这点后再看后面三种建网方式就清楚了:无论用哪种方式创建拓扑,最终生成的都是一组进程和网络命名空间,只是入口不同。2.2 miniedit可视化创建拓扑miniedit是Mininet自带的图形化拓扑编辑器,适合第一次接触网络仿真的人,拖拽就能建拓扑,不需要背命令。启动前需要先拿到root权限,因为Mininet对网络命名空间的操作必须要root。sudo su cd ~/mininet/examples ls miniedit.py python3 miniedit.py这段操作里,sudo su切换root之前要先确认Mininet安装目录,常见位置是~/mininet/examples,如果找不到可以用find / -name miniedit.py搜一下。直接运行miniedit.py会弹出图形界面,画布左侧是主机、交换机、控制器等组件图标,拖到画布就能连线建拓扑。注意一定用python3而不是python,有些旧系统默认的python还是2.x,跑起来会直接报语法错误。拓扑建好后要逐项配置。右键点击主机选Properties,可以改主机名和MAC地址,这不只是表面功夫,后面ping测试和ifconfig看到的就是这里设置的参数。交换机和控制器也要分别配置,交换机的OpenFlow协议版本要选和控制器匹配的,不然控制器连上来会话会反复断开。配置完成后,关键一步是菜单栏的“Edit → Preferences”,这里要勾选Start CLI,这样运行拓扑时会同时打开Mininet交互命令行,方便后续做ping测试。导出脚本用“File → Export Level 2 Script”,保存为.py文件后,终端执行python3 文件名.py就能看到同样拓扑被加载起来。2.3 命令行快速建网和常用命令实际上多数实验不会每次都打开图形界面,命令行反而是最常用也最快的方式。实验报告中要求用命令行创建三类拓扑:一个交换机挂两个主机、线性四跳拓扑、单交换机挂三个主机,对应三条命令:sudo mn --topo single,2 sudo mn --topo linear,4 sudo mn --topo single,3这三条命令分别对应实验报告的S2要求。sudo mn启动Mininet后默认自带一个控制器和Open vSwitch交换机,--topo参数指定拓扑类型:single,2表示一个交换机下连接两台主机,生成的节点名是h1、h2和s1;linear,4表示四个交换机串成一条线,每个交换机挂一台主机;single,3则是单交换机挂三台主机。命令里的,号前面是拓扑类型,后面是节点数量或深度,别把顺序记反了。进入mininet>交互提示符后,实验报告列的那几条命令就是核心操作集合:net查看节点间连接关系,dump能显示每个节点的接口和进程PID,pingall让所有主机两两ping一遍,h1 ping h2只测两台主机间的连通性。这里有个很实用的细节,h1 ifconfig能直接看到主机h1的IP信息,默认情况下Mininet会用10.0.0.0/8网段给每个主机的eth0接口分配IP。想退出就输入exit,或者在mininet>提示符下按Ctrl+D,不建议直接关终端,不然残留的进程可能会影响下次启动。3. 交互式界面扩展拓扑:动态添加主机和交换机3.1 用py指令直接操作Python对象Mininet的CLI不只是执行命令,还有一个看着不起眼但极其有用的py前缀。任何输入py开头的命令都会被当作Python代码在Mininet网络对象上执行。这意味着你不需要退出CLI去改脚本,就能动态添加主机、创建链路、给接口配IP,这在调试和验证想法时比反复重启整个拓扑高效得多。比如实验报告里有一段很典型的操作:启动默认拓扑(两个主机一个交换机),然后输入py net.addHost('h3'),这个net就是当前运行的Mininet网络对象,addHost方法会创建一个名为h3的新主机。这个操作完全是在运行中的CLI里完成的,新主机即刻生效,对应的进程已经起来了。你可以接着输入py net.get('h3')拿到这个主机对象,再对它执行命令,整个思路跟写Python脚本操控网络对象一模一样。3.2 手动接线和配IP的完整步骤动态添加主机只是第一步,关键是把它接入现有交换机。实验报告给出了一个完整的接线配IP序列:py net.addHost('h3') py net.addLink(s1, net.get('h3')) py s1.attach('s1-eth3') py net.get('h3').cmd('ifconfig h3-eth0 10.3') h1 ping -c1 10.3这段代码的前两行创建了主机h3,然后把它和交换机s1之间加了一条链路。第三行的attach是很多人会卡住的地方:虽然addLink已经在逻辑上建立了连接,但Mininet里每个交换机端口需要手动attach到具体接口名,s1-eth3的意思是给交换机s1增加第三个以太网接口,只有执行这一步,数据平面才算真正连通。第四行则是在h3内部执行ifconfig,给它的h3-eth0接口配置IP为10.3(这是简写,完整写法是10.0.0.3),不然即使链路通了,也没有地址可ping。最后一行在CLI里执行h1 ping -c1 10.3,-c1表示只发一个ICMP包。如果看到64 bytes from 10.3的回显,说明这条动态添加的链路已经通了。注意这行命令前面没有py前缀,因为ping本身就是Mininet CLI的保留命令,可以直接执行。这个细节容易混淆,凡是需要传递到主机内部执行的命令都要用py net.get('xxx').cmd(),而CLI自带的命令直接写。3.3 在交互模式下查看连接状态把网络对象当成Python对象操作有个好处,你可以直接用代码遍历整个拓扑。实验报告里出现的这段就是典型的连通性检查:py from mininet.util import dumpNodeConnections py dumpNodeConnections(net.hosts) py net.pingAll()dumpNodeConnections接收一个节点列表,会逐个打印每个节点的连接关系,跑完就能看到h1连在s1的哪个接口、h3连在s1的哪个接口,非常适合验证上面加主机加链路的操作有没有成功。net.pingAll()则是在所有主机间执行全互联的ping测试,返回结果会显示丢包率。比起一条条h1 ping h2去手动验证,这种批量方式在主机数量多的时候能省不少时间。这里顺带说一个排查思路。如果pingAll显示某台主机ping不通,用dumpNodeConnections先看连接关系是否完整,再用h1 ifconfig看IP是否配置到位,最后看交换机端口是否attach成功。大部分动态添加拓扑失败的场景,问题都出在接口没有配置IP或者端口没有attach,数据链路本身反而是通的。4. Python脚本构建拓扑:从linear到tree4.1 内置拓扑的三种典型形态命令行里的--topo参数只是为了快速上手,真正要复现一个可调可控的拓扑,得用Python脚本。实验报告里要求的topo linear,4、topo single,3、topo tree,depth=2,fanout=2三类拓扑,都可以借助Mininet内置的拓扑类快速生成:from mininet.topo import LinearTopo, SingleSwitchTopo, TreeTopo from mininet.net import Mininet from mininet.cli import CLI from mininet.node import OVSSwitch, Controller net = Mininet(topo=LinearTopo(4), switch=OVSSwitch, controller=Controller) net.start() CLI(net) net.stop()这段代码里,LinearTopo(4)生成四个交换机首尾相连、每个交换机挂一台主机的链式拓扑;SingleSwitchTopo(3)生成一台交换机挂三台主机的星型结构;TreeTopo(depth=2, fanout=2)则是深度为2、扇出为2的二叉树结构,展开后是1个根交换机连2个二层交换机,每个二层交换机再挂2台主机,共4台主机。switch=OVSSwitch指定交换机类型,controller=Controller用的是Mininet自带的默认控制器。CLI(net)启动后就会进入交互界面,可以继续用上一章的py命令操作网络对象。4.2 继承Topo类写自定义拓扑真正到了要复现实验报告里“1个交换机、2个主机并赋予IP”的场景,内置拓扑就不够用了,需要自己重写Topo类。Mininet的推荐做法是继承Topo基类,在build方法里用addHost和addSwitch声明节点,用addLink声明链路:from mininet.topo import Topo class MyTopo(Topo): def build(self): s1 = self.addSwitch('s1') h1 = self.addHost('h1', ip='10.0.0.1/8') h2 = self.addHost('h2', ip='10.0.0.2/8') self.addLink(h1, s1) self.addLink(h2, s1) topos = {'mytopo': (lambda: MyTopo())}addHost里的ip参数直接给主机的eth0接口配置了地址,不用进入CLI再手动ifconfig。addSwitch创建交换机节点,addLink把两个节点连起来。最后一行的topos字典是一种约定:把拓扑类注册成一个可由--topo mytopo调用的名称,方便用sudo mn --custom 文件.py --topo mytopo的方式直接加载。build方法是在拓扑创建时自动调用的,不需要显式写__init__,这也是Mininet自定义拓扑的一个惯例写法。用这个脚本启动网络和前面的方式没有区别,只是拓扑换成了自定义结构。加载后运行net.pingAll(),两台主机之间应该能顺利互ping。IP地址要设置成同一网段,不然通了链路也无法完成ARP解析和ICMP通信,这是个看起来低级但很常见的失误。4.3 controller参数和OVS端口的配合脚本里还有一个容易忽略但影响成败的设置:Controller默认监听的是本机的6653端口(旧版本是6633)。如果之前有一个没退干净的Mininet进程占用了这个端口,新脚本启动的交换机就永远连不上控制器,表现是主机之间ping不通,但dump能看到所有接口都正常。所以在启动新脚本前,养成先执行sudo mn -c清理环境的好习惯。另一个配合细节是交换机的OpenFlow协议版本。OVSSwitch默认会协商一个版本,但如果实验环境里有额外的SDN控制器(例如某些课程要求用Ryu或Floodlight),就需要注意两端版本一致。脚本里可以通过switch=OVSSwitch的构造参数或者OVSSwitch.setOpenFlow13()来指定使用OpenFlow 1.3,避免低版本导致控制器不识别流表。这份实验报告里的拓扑都是单控制器自连,用默认设置没问题,但如果后续要接入外部控制器,这个参数就避不开了。5. Mininet避坑指南:环境、权限和常见报错5.1sudo mn提示命令找不到现象:在终端输入sudo mn后提示mn: command not found。原因:Mininet安装目录没有加入到系统的PATH环境变量,或者安装时用的是源码目录直接运行而非全局安装。解决:先确认Mininet安装位置,常见路径有~/mininet/bin和/usr/local/bin。如果是源码安装,把Mininet的bin目录加入PATH,或者每次用全路径sudo ~/mininet/bin/mn启动。我一般会直接在/usr/local/bin下建个软链接:ln -s ~/mininet/bin/mn /usr/local/bin/mn,一劳永逸。5.2 miniedit导出脚本运行报ModuleNotFoundError现象:miniedit导出的xxx.py文件用python3 xxx.py运行时,报No module named 'mininet'。原因:导出的脚本默认是当前目录直接运行,Python解释器找不到Mininet的Python库路径。源码安装的Mininet通常只对root用户可用,普通用户的PYTHONPATH里没有这个路径。解决:用root身份运行是第一步,其次可以显式指定解释器的搜索路径:PYTHONPATH=/root/mininet python3 xxx.py。如果不确定Mininet模块装在哪,用python3 -c "import mininet; print(mininet.__file__)"打印实际路径再拼到PYTHONPATH后面。5.3 pingall只丢包但接口全正常现象:pingall结果中部分主机丢包,但dump和net显示所有节点和接口都正常,ifconfig也能看到IP。原因:交换机没有成功连上控制器,处于无流表状态。Mininet的交换机默认是学习交换机,只有连上控制器才能下发流表规则,控制器没连上时数据包就会被交换机丢弃。解决:检查控制器是否启动成功,在CLI里执行py net.controllers看控制器列表;然后确认没有其他进程占用6653端口,用ss -lnt | grep 6653检查。如果端口被占,先sudo mn -c清理再重来。脚本里也可以显式指定controller=Controller并调用net.start(),确保控制器先于交换机启动。5.4 在CLI里执行h1 ping h2提示未知主机现象:在mininet>提示符下输入h1 ping h2,返回ping: h2: Name or service not known。原因:这条命令被Mininet CLI解析后传给了主机的shell去执行,而Mininet为每个主机分配的是独立的网络命名空间,主机内部并没有DNS解析h2这个名称的能力。Mininet CLI只在节点名出现在命令首部时才处理主机名映射,ping的参数部分不会自动转换。解决:在CLI里可以改用h1 ping -c1 10.0.0.2这类IP直连,或者在py前缀下用net.pingAll()做全量测试。真正用主机名通信的场景应该写在Python脚本里,用h1.cmd('ping -c1 10.0.0.2')的方式执行。这个坑是第一次接触Mininet时最容易困惑的点。5.5 脚本退出后再次启动报Address already in use现象:上一次运行net.stop()或者直接关掉了终端,再次启动新的Mininet脚本时报bind: Address already in use。原因:上次的控制器进程或者Open vSwitch的后台进程没有完全退出,端口资源没有被释放。很多时候直接关闭终端或者Ctrl+C中断,Mininet的清理钩子没有执行到。解决:在任何一次实验结束后都执行sudo mn -c清理残留进程。如果mn -c也反馈有问题,可以手动查看并杀掉残留的python和ovs进程:ps aux | grep mininet、sudo pkill -f ovs-vswitchd。从那以后我每次跑新拓扑前都强制走一遍mn -c,再也没遇到过端口占用的问题。这个习惯看着多余,实则是Mininet实验里最容易翻车的环节。6. 用参数把仿真拉回现实:带宽、延迟与丢包限制6.1 addLink与addHost参数详解实验报告最后提到了一个非常关键却没展开讲的内容:给网络加性能限制。默认的Mininet拓扑所有链路都是无限制的,主机CPU也是随便用,这跟真实网络差距很大。真实路由器之间的链路有带宽上限、有传输延迟、有丢包率,仿真里想复现这些,靠的就是addLink和addHost的参数。from mininet.topo import Topo class LimitedTopo(Topo): def build(self): s1 = self.addSwitch('s1') h1 = self.addHost('h1', cpu=0.5) h2 = self.addHost('h2', cpu=0.5) self.addLink(h1, s1, bw=10, delay='5ms', max_queue_size=1000, loss=10) self.addLink(h2, s1, bw=10, delay='5ms', max_queue_size=1000, loss=10)addHost的cpu参数是百分比,0.5表示该主机最多使用单核CPU资源的50%,这限制了主机的处理能力,模拟真实终端设备性能不足的情况。addLink里的参数更直接:bw=10单位是Mbit/s,限制链路带宽为10M;delay='5ms'表示单向传输延迟5毫秒;max_queue_size=1000是交换机端口队列可容纳的最大包数,超过就丢包;loss=10表示链路丢包率10%。组合这些参数就能构造出一个接近真实环境的有损链路,而不是实验室里那种干干净净的完美网络。6.2 用iperf验证链路参数是否生效配置了参数不等于参数生效,得实测验证。Mininet的每个主机都能跑真实程序,所以直接可以用iperf来测链路带宽。在CLI里先启动h2的iperf服务端:h2 iperf -s -u -p 5001 &这条命令里-s表示服务端模式,-u指定UDP协议(测带宽和丢包率用UDP比TCP直观),-p 5001指定监听端口,&让它在h2的shell后台运行。然后在h1侧发起测量:h1 iperf -c 10.0.0.2 -u -p 5001 -b 20M -t 10-c指定对端IP,-b 20M表示H1以20Mbit/s的速率发送UDP流量,-t 10持续10秒。因为链路配置的bw是10M,所以用20M去灌肯定会触发限速,iperf输出的实际带宽应该在10M附近,丢包率也会接近配置的值。如果测出来带宽远超设定值,基本可以断定TC(Traffic Control)规则没有挂上,检查一下交换机是否用了OVS以及系统是否支持sch_netem内核模块。这种带参数量化的仿真方式,能让你在提交实验报告时拿出实打实的数据,而不是只截图一个ping通的结果。从那以后我每次做Mininet实验都会给拓扑加一两组带宽和延迟限制,再配合iperf验证,整个流程走下来才算真正把网络行为摸透了。希望帮到你。本文还有配套的精品资源,点击获取