ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Mininet SDN实验指南:三种建网方式与链路性能限制全解析

Mininet SDN实验指南:三种建网方式与链路性能限制全解析 简介这是一份面向高校网络工程、软件定义网络课程实验的 Mininet 实验报告适合正在学习网络仿真与 SDN 拓扑构建的本科生或自学者使用。报告以西安财经大学《网络应用设计与系统集成》实验一为蓝本系统梳理了 Mininet 的核心概念、主要特性与常用命令并通过三个层次展开实践先使用可视化工具 Miniedit 创建拓扑再通过命令行和交互式界面添加主机、交换机并执行 ping 测试最后编写 Python 脚本构建 linear、single、tree 等交换拓扑同时给出了主机 IP 配置和网络性能限制的示例。资源为 1 个 doc 文档压缩包 1.37MB共 16 页完整记录实验目的、知识背景、操作步骤、关键配置与结果验证可帮助读者对照完成仿真实验并理解 Mininet 的核心机制。已有 1066 人浏览学习适合作为课程实验报告参考或 SDN 入门实践的配套材料。1. Mininet 实验报告拆解一份能照着跑完的 SDN 拓扑实战做网络实验最烦的不是配协议而是拓扑根本建不起来。Mininet 看着轻量真正上手时大部分人卡在同一个地方miniedit 里画好的拓扑导不出能跑的脚本或者脚本能跑但 ping 不通。这份实验报告的价值在于把「可视化建拓扑、命令行建拓扑、Python 脚本建拓扑、链路性能限制、节点通信验证」这条链路完整走了一遍每一步都给了能直接抄的参数和命令而且最后还落到了 OpenFlow 与 SDN 场景上——它不只是一份交差的作业更是一份能复现的实验室操作手册。我正在做网络应用设计类课程实验或者要在本机快速搭一套可复现的 SDN 测试环境拿它当前期参照都很合适。后面所有步骤我都按原报告的实验顺序拆开讲踩过的坑也一并标出来省得你再走一遍弯路。2. 三种建网方式怎么选miniedit 可视化、命令行与交互式 APIMininet 的设计哲学是「同一张拓扑三种入口」图形界面、命令行参数、Python API。三种方式不是重复造轮子而是分别对应三种使用场景。可视化工具适合演示和教学能让人一眼看懂拓扑长什么样命令行适合快速验证一条命令就能拉起一个指定结构的网络交互式 CLI 则适合在运行中的拓扑上做增量修改比如临时加一台主机、挂一条链路不用重启整个网络。实际做实验时我一般先用可视化把拓扑结构画出来确认逻辑再转成命令行或脚本批量复现。这样既能保证理解到位又能把实验过程留给后面复用。2.1 miniedit 可视化适合理解拓扑但不适合批量实验miniedit 是 Mininet 自带的 Tkinter 图形前端底层仍然是调用 Mininet 的 Python API只是把 addHost、addSwitch、addLink 这些操作变成了鼠标拖拽。它的价值在于把抽象的网络结构可视化尤其适合刚接触 SDN 的人搞清楚「控制器、交换机、主机、链路」四者之间的关系。按原报告的流程在 Linux 环境里启动 miniedit 大概分这么几步进入 root 模式或确保当前用户有 sudo 权限。定位 miniedit.py 文件。常见位置是/usr/lib/python2.7/site-packages/mininet/examples/或 Mininet 源码目录下的examples/直接用find / -name miniedit.py 2/dev/null找最稳妥。启动sudo python miniedit.py。注意这里用 python 还是 python3取决于你的 Mininet 装在哪个解释器下。在画布上添加 Host、Switch、Controller用连线工具把它们连起来。右键节点配置参数控制器填 127.0.0.1交换机选 OpenFlow 协议版本主机配置同一网段的 IP。在 Edit → Preferences 里勾选 Start CLI这样启动网络后会自动进入 Mininet 命令行。通过 File → Export Level 2 Script 保存为 Python 脚本再用sudo python xxx.py运行重现拓扑。提示miniedit 导出的 Level 2 Script 只包含拓扑结构和基本 IP 配置不包含你在 CLI 里后续做的动态操作。想保留那些操作必须写进脚本里。控制器配置这一步最容易忽略。如果拓扑里放的是「None」型控制器Mininet 不会启动控制器进程交换机就处于没有控制器的待机状态数据包会被丢弃。如果只是在本机做连通性测试选默认 Controller 并填 127.0.0.1 即可如果要用外部控制器选 None 后再手动启动。2.2 命令行创建把拓扑结构变成参数命令行的核心是--topo参数语法为类型,参数1,参数2。原报告里给了三种典型结构我按可复现的顺序重排如下# 最简拓扑1 个交换机下挂 2 台主机 sudo mn --topo single,2 # 线性拓扑4 个交换机串联每个交换机下挂 1 台主机 sudo mn --topo linear,4 # 星形拓扑3 台主机全部接到同一个交换机 sudo mn --topo single,3 # 树形拓扑深度 2、扇出 2共 3 台交换机、4 台主机 sudo mn --topo tree,depth2,fanout2single,2是整个 Mininet 里最简单的结构s1 连接 h1 和 h2适合验证基本连通性。linear,4是链式结构s1-s2-s3-s4 依次串起来每个交换机挂一台主机数据从 h1 到 h4 要经过多跳便于观察多跳转发行为。tree,depth2,fanout2是二叉树结构根交换机下挂两台子交换机每台子交换机再挂两台主机层级关系更接近真实网络。这三种拓扑分别对应了「汇聚」「链式」「分层」三种常见组网形态做课程实验时建议三种都跑一遍。进入 CLI 后用net看拓扑连线、dump看节点 IP 和进程 PID、pingall做全网连通性测试。这些命令是后面所有验证的基础。2.3 交互式接口在运行中的网络上动态改拓扑命令行创建完拓扑后如果还想加节点不用退出重建直接在 CLI 里用py前缀执行 Python API。原报告演示的就是这个操作sudo mn mininet py net.addHost(h3) mininet py net.addLink(s1, net.get(h3)) mininet py s1.attach(s1-eth3) mininet py net.get(h3).cmd(ifconfig h3-eth0 10.0.0.3/24) mininet h1 ping -c1 10.0.0.3py net.addHost(h3)只是在对象层面上新建了一台主机此时它还没接入网络addLink(s1, net.get(h3))创建了 h3 到 s1 的虚拟链路但 Open vSwitch 的端口还没有真正启用s1.attach(s1-eth3)才是把交换机端口挂载上这一步漏掉的话链路是断的。最后用cmd()在 h3 内部执行 ifconfig 分配 IP然后从 h1 ping 新主机验证连通。再强调一个容易抄错的点原报告里写的是from mininet.until import dumpNodeConnections实际模块名是mininet.utiluntil是笔误。用py dumpNodeConnections(net.hosts)或py net.pingAll()也能达到同样效果。这种细节不亲自敲一遍代码很难发现后面避坑章节我还会专门讲。3. 用 Python 脚本构建拓扑从 single/linear/tree 到自定义网络命令行能覆盖的拓扑类型有限一旦要定义环形、冗余链路、跨网段隔离这类结构就必须用 Python 脚本。Mininet 官方推荐的方式是定义 Topo 子类在build()方法里声明节点和链路然后交给 Mininet 类去启动。这种方式是声明式的拓扑结构一目了然而且天然支持参数化——同一个类可以生成不同规模的网络。3.1 Topo 类与 Mininet 对象脚本建网的底层逻辑写脚本前先搞清楚两个概念。Topo类是拓扑蓝图只描述「有哪些节点、节点间怎么连」不实际创建进程和网卡Mininet类才是执行者拿到 Topo 后调用start()才真正拉起主机、交换机、控制器。第三方的实验脚本经常把两者混在一起用在build()里就去启动网络这样会导致拓扑定义和运行逻辑纠缠后面想改参数非常痛苦。我的习惯是build()里只做节点和链路声明运行时逻辑全放在main()里。这里再补充一个底层原理。Mininet 里的每台 host 是一个 network namespace交换机是 Open vSwitch 的用户态进程host 与 switch 之间通过 veth pair 虚拟网线连接。addHost(ip10.0.0.1/24)等价于创建命名空间并配置网卡地址addLink(h1, s1)等价于拉了一根 veth 线并把两端分别塞进 host 和 switch。理解这个模型后脚本里那些看似抽象的对象就都有了实体对应。3.2 四种拓扑的完整脚本linear、single、tree 与单交换机双主机先看最常见的 linear 拓扑。我们定义 4 台交换机串联、每台各挂 1 台主机#!/usr/bin/env python from mininet.topo import Topo from mininet.net import Mininet from mininet.cli import CLI class Linear4(Topo): def build(self): prev None for i in range(1, 5): s self.addSwitch(s%d % i) h self.addHost(h%d % i, ip10.0.0.%d/24 % i) self.addLink(h, s) if prev: self.addLink(prev, s) prev s if __name__ __main__: topo Linear4() net Mininet(topotopo) net.start() CLI(net) net.stop()prev变量记住前一个交换机循环到第 2 台交换机时把prev和当前交换机连接就形成了链式结构。IP 用10.0.0.x/24保证所有主机在同一广播域后面 ping 时不需要额外配路由。CLI(net)会进入交互式命令行让你像命令行方式一样执行 pingall、dumpnet.stop()在退出时统一清理进程避免残留 OVS 配置。single 拓扑更简单一台交换机承接所有主机class Single3(Topo): def build(self): s1 self.addSwitch(s1) for i in range(1, 4): h self.addHost(h%d % i, ip192.168.1.%d/24 % i) self.addLink(h, s1)tree 拓扑则适合用递归实现深度和扇出都可以参数化。Mininet 其实自带TreeTopo(depth2, fanout2)直接用内置类更省事但理解递归写法有助于处理更复杂的分层网络from mininet.topo import TreeTopo if __name__ __main__: topo TreeTopo(depth2, fanout2) net Mininet(topotopo) net.start() CLI(net) net.stop()如果只是想快速搭一台交换机挂两台主机并手动分配 IP不写 Topo 子类也完全可以。Mininet 支持命令式实例化from mininet.net import Mininet from mininet.node import Controller from mininet.cli import CLI net Mininet() c0 net.addController(c0, controllerController, ip127.0.0.1) s1 net.addSwitch(s1) h1 net.addHost(h1, ip10.0.1.1/24) h2 net.addHost(h2, ip10.0.1.2/24) net.addLink(h1, s1) net.addLink(h2, s1) net.start() CLI(net) net.stop()显式声明控制器对象是一种好习惯虽然 Mininet 在缺省情况下会自动拉起一个 Controller但显式写清楚控制器 IP 和类型后排查问题时能少一半疑虑。ip10.0.1.1/24在 addHost 阶段就完成了网卡 IP 配置比在 CLI 里再敲 ifconfig 干净得多。3.3 脚本方式和命令行方式的差异什么时候该写脚本脚本和命令行的边界并不绝对但有几个实用的判断标准。命令行sudo mn --topo single,3能覆盖的实验写脚本反而增加心智负担但一旦涉及性能参数、多控制器、自定义路由策略、批量跑自动化测试命令行就不够用了。脚本的优势在于可复现和可参数化同一份代码改一个数字就能生成 8 台主机或者 16 台交换机这是命令行做不到的。miniedit 导出的 Level 2 Script 本质上也是 Topo 子类只是把拖拽操作变成了代码。所以「可视化设计 → 导出脚本 → 修改参数 → 批量复现」是最高效的工作流。原报告这一步的流程非常完整照着做一遍三种建网方式的关系自然就清楚了。4. 给链路加约束TCLink 性能参数与验证方法拓扑建通只是第一步真实网络里的带宽、延迟、丢包都是需要模拟的指标。Mininet 里做这件事的关键是 TCLink——它会在链路两端的虚拟网卡上挂 Linux 流量控制规则用 netem 模拟延迟和丢包用 tbf 或 hfsc 限制带宽。如果不指定 TCLinkMininet 默认使用的是普通 veth 链路带宽跑满宿主机网卡延迟几乎为零跟真实网络完全是两码事。4.1 TCLink 的作用bw、delay、loss 背后的流量控制原理TCLink 的常用参数有四个bw是带宽单位 Mbpsdelay是单向延迟单位毫秒需要写成字符串形式如10msloss是丢包率单位是百分比取值范围 0 到 100max_queue_size是最大队列长度单位是包数。需要注意的是delay是单向延迟ping 的 RTT 大约是它的两倍加处理时延loss是单向丢包率双向测试时实际丢包率会叠加。原理层面bw10会在网卡上挂一个 tbf 队列规则超过 10 Mbps 的流量被丢弃或排队delay10ms则用 netem 给每个包加上 10ms 的发送延迟。这两个规则是独立的所以一个链路可以同时限制带宽和增加延迟。写脚本时用linkTCLink全局参数一次性启用from mininet.link import TCLink from mininet.net import Mininet from mininet.cli import CLI net Mininet(linkTCLink) h1 net.addHost(h1) h2 net.addHost(h2) s1 net.addSwitch(s1) net.addLink(h1, s1, bw10, delay10ms, loss1, max_queue_size100) net.addLink(h2, s1, bw10, delay10ms, loss1, max_queue_size100) net.start() CLI(net) net.stop()这里最容易犯的错是只在addLink里写了 bw却忘了在Mininet(linkTCLink)指定链路类型。addLink 的带宽参数在默认链路类型下会被静默忽略不报任何错但限速就是不起作用。我拆这类实验报告时发现至少一半「带宽限制不生效」的问题都出在这。4.2 写一个带性能限制的脚本并用 iperf 验证链路约束配置好之后验证才是重头戏。用 ping 测延迟用 iperf 测吞吐用 ping 的统计信息看丢包。进入 CLI 后这样操作mininet h1 ping -c 5 h2 mininet h1 iperf -s -p 5555 mininet h2 iperf -c h1 -t 10 -p 5555ping 的输出里rtt 平均值应该稳定在 20ms 上下对应单向 10ms 延迟的往返。iperf 的结果会显示实际吞吐量如果bw10设置正确吞吐曲线应该被压在 10 Mbps 附近如果看到几百 Mbps 甚至上 Gbps基本可以断定 TCLink 没生效。注意iperf 短连接测出来的带宽往往偏高因为 tbf 允许一定程度的突发。测速时间至少拉到 10 秒或者用 UDP 模式指定带宽后观察 loss结果才可信。还有个细节有些最小化安装的 Linux 并没有预装 iperf需要先apt-get install iperf。Mininet 自带的 iperf 有些版本较旧如果两端都要用 iperf3务必保持一致否则握手会失败。4.3 别忘了主机的 cpu 参数CPULimitedHost 与 cgroups原报告里提到addHost()可以对主机 CPU 进行设置实现方式如下from mininet.node import CPULimitedHost from mininet.net import Mininet from mininet.cli import CLI net Mininet(hostCPULimitedHost, linkTCLink) h1 net.addHost(h1, cpu0.5) h2 net.addHost(h2, cpu0.5) s1 net.addSwitch(s1) net.addLink(h1, s1) net.addLink(h2, s1) net.start() CLI(net) net.stop()注意cpu参数是 0 到 1 之间的小数cpu0.5表示该主机最多使用单核 CPU 的 50%不是 50%。原报告里写的是「以百分数的形式」这容易误导实际代码里写cpu50会导致 cgroup 配额计算异常。原理是 CPULimitedHost 通过 cgroup 的 cpu 子系统限制主机内所有进程的 CPU 占用率需要 root 权限才能生效。验证方法是在 CLI 里跑一个死循环进程然后开另一个终端用 top 看 CPU 占用理论上会稳定在 50% 附近。5. 避坑指南五个必踩问题与排查顺序这份实验报告本身步骤完整但照着重跑一遍有几个地方几乎是必踩。我按出现频率排序写在这里每条都给出了现象、原因和解决方式实操时可以按顺序排查。5.1 坑一miniedit 启动报错文件到底在哪现象运行sudo python miniedit.py直接提示ModuleNotFoundError或者找不到这个文件。原因Mininet 安装路径不统一新版 Mininet 把 miniedit 放在了examples目录但 PYTHONPATH 里没有包含它另外不同的发行版安装目录差异很大盲目用绝对路径自然失败。解决先执行find / -name miniedit.py 2/dev/null定位文件如果报模块缺失进入文件所在目录运行sudo python miniedit.py仍然报错就手动export PYTHONPATH$PYTHONPATH:/usr/lib/python2.7/site-packages/mininet/examples。这个坑本身不复杂但卡住的概率极高我建议第一步就用 find 定位别凭记忆硬猜路径。5.2 坑二导出脚本跑不起来python2/python3 与路径问题现象miniedit 里保存的脚本运行时报ImportError: No module named mininet或者语法错误。原因有两个层面一是 Mininet 装的是 python2 版本而系统默认 python 是 3.x代码用 python2 语法写但被 python3 解释执行二是导出脚本里的 import 路径依赖安装目录换了一台机器后解释器找不到包。解决统一用sudo python执行而不是python3如果是在自己笔记本上复现装完 Mininet 后先把mn --version跑通再运行脚本脚本开头加上#!/usr/bin/env python并确认 PATH 里优先的 python 指向正确解释器。5.3 坑三pingall 不通问题多半在控制器与 IP 网段现象启动拓扑后执行pingall结果出现大量 dropped packets或者全网全丢。原因80% 的情况是控制器没配上。miniedit 里如果把控制器类型选成 None交换机处于无控制器状态不会转发任何数据包另一种情况是主机 IP 不在同一网段导致 ARP 解析失败。解决先执行dump看每个节点的 IP 和 PID确认 controller 进程存在再执行net看链路是否完整如果控制器正常检查各主机 IP 掩码是否一致。还想深挖的话在 OVS 侧执行ovs-vsctl show看 controller 是否连接成功再ovs-ofctl dump-flows看流表是否下发了规则。这一步能把「拓扑建好但业务不通」的问题缩小到可定位的范围。5.4 坑四带宽限制不生效TCLink 没挂上现象addLink里明明写了bw10iperf 测出来的带宽却是几百兆甚至上千兆。原因Mininet 默认链路类型不是 TCLinkbw、delay、loss在默认 IntfLink 下全部被忽略而且不报错。这是这份实验脚本里最隐蔽的一个坑因为拓扑能正常通信只是限速失效容易被当成「网络质量不好」而错过真正原因。解决实例化改为Mininet(linkTCLink)或者更直接一点在 CLI 里执行py h1.cmd(tc qdisc show dev h1-eth0)如果没有任何 qdisc 输出说明流量控制规则没挂上。还可以搭配py net.pingAll()和 iperf 做对照确认规则生效后再看吞吐数据。5.5 坑五xterm 与 Wireshark 打不开图形环境缺失现象在 CLI 里输入xterm h1后终端闪退或无响应wireshark 启动提示无法连接显示器。原因Mininet 的 xterm 和 Wireshark 依赖图形环境和 X11。如果是在远程服务器上通过 SSH 跑实验只有一个纯命令行会话DISPLAY 环境变量是空的图形程序根本起不来。解决本机图形桌面直接跑没问题远程环境先apt-get install xterm再用ssh -X登录如果不想折腾图形转发就放弃 Wireshark改用命令行抓包工具tshark或tcpdump在 CLI 里执行h1 tcpdump -i h1-eth0 -c 20一样能看到流量。这个坑不涉及 Mininet 本身但会直接影响实验截图做报告时尤其尴尬。6. 把实验浓缩成一条命令参数化拓扑与验收技巧前面拆了那么多步其实 Mininet 本身提供了一个「一行命令拉起完整实验」的入口。信息密度最高的写法是任意拓扑结构加上流量控制参数、协议版本、自动 MAC 分配全部塞进sudo mn命令。sudo mn --topotree,depth2,fanout2 \ --linktc,bw10,delay5ms,loss1,max_queue_size100 \ --switchovsk,protocolsOpenFlow13 \ --mac这条命令把第 3 章的拓扑定义和第 4 章的性能限制合并成了一句话。--linktc等价于脚本里的TCLink后面的bw10,delay5ms,loss1全部作用于每一条链路--switchovsk,protocolsOpenFlow13显式指定使用 Open vSwitch 并启用 OpenFlow 1.3--mac让每个 host 自动分配固定的 MAC 地址避免 ARP 表中的地址解析问题。进入 CLI 后按下面这张表验收验证项命令预期结果拓扑结构net节点与链路和设计一致全网连通pingall0 dropped链路延迟h1 ping -c 5 h2rtt 均值约等于 2 倍 delay链路带宽h1 iperf -s -p 5555 再h2 iperf -c h1 -t 10 -p 5555吞吐接近 bw 设定值节点状态dump每个 host 都有 IP、MAC、PID这一套流程很适合用来给课程实验报告留档进入 CLI 后先net截一张拓扑图pingall截一张连通性结果iperf截一张带宽数据三张图基本就能说明实验完成了。也是因为有了这条命令我后来做任何网络仿真实验都习惯先跑一遍这条完整链路确认拓扑和限速都正常再往里面加控制器逻辑。以前总是先写几百行脚本再调试半天翻车了好几次那以后我强制自己先验证后扩展确认基础环境没问题再叠加功能。这份实验报告帮你把该踩的坑都标好了直接拿它当模板往下做就行希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进