简介这是一份面向网络工程、软件定义网络SDN初学者的 Mininet 实验报告完整记录了从可视化建拓扑到 Python 脚本构建拓扑的全过程。报告覆盖 Miniedit 可视化工具创建、命令行创建、交互式界面创建主机与交换机、节点间 ping 测试等基础技能并介绍了 Mininet 的核心特性、常用命令及 Linear、Single、Tree 等典型拓扑的 Python 实现方法。资源为单份 doc 文档共 1 个文件压缩包大小约 1.37MB适合作为课程实验报告或实验操作参考模板。目前已有 1066 人学习内容结构清晰、步骤翔实可直接对照练习对理解 Mininet 仿真环境和 SDN 入门实验很有帮助。1. 一份 Mininet 实验报告背后真正要你交付的能力一份写着「Mininet 实验报告」的 doc 文件放到真实环境里对应的是这样一件事在 Linux 上搭出一台虚拟网络实验台用内核真实的网络栈把一台物理机切成若干主机和交换机再在上面验证 OpenFlow 流表如何建立、转发决策如何下发。很多人第一次跑完实验报告里只贴一张拓扑图加几行 pingall 输出但真正值钱的部分是验证过程本身——第一次 ping 前和 ping 后的流表差异、idle_timeout 老化、链路带宽有没有按参数生效、丢包到底发生在哪一跳。这些才是别人照着做就能复现、能定位问题的内容。Mininet 不是传统意义上的网络模拟器它基于 Linux network namespace 和 Open vSwitch 构建数据包走的是一条真实内核转发路径。这篇笔记从环境选型讲到拓扑生成、连通性验证、流表观测再用独立章节记录我实际踩过的坑最后给出一个参数化实验脚本的写法。适合正在准备网络课程实验的人也适合刚接触 SDN、想快速把控制器和交换机串起来的开发者。2. 先搞清 Mininet 在实验里的角色再谈安装和参数2.1 用 namespace 理解 Mininet一台物理机怎么被切成那么多台「机器」做网络实验可以走好几条路传统模拟器只教配置命令重型虚拟化方案会拉起完整的设备镜像而 Mininet 的定位完全不同。它靠 Linux 内核的 network namespace 实现隔离每个 namespace 拥有独立的网络栈——自己的路由表、ARP 表、iptables 规则和 socket 接口。进程在 namespace 里看到的是一台完整主机内核却把这些进程关在各自独立的网络空间里互不干扰。所以当你执行 h1 ping h2 时实际发生的是这么一条路径h1 的 namespace 发出 ICMP 请求经过虚拟以太网对的一端进入 Open vSwitch交换机查流表后把包转发到 h2 的 namespace。链路延迟、丢包比例、TCP 拥塞窗口都来自内核的现成机制而不是某个数学模型估算出来的结果。这也是 Mininet 与 Packet Tracer 这类纯模拟工具的本质区别它的二层转发和 IP 协议栈是真实的实验结论在多数场景下可以映射到真实网络设备。在这个模型里Mininet 里的「主机」不是一个精简的进程它就是一个完整的网络命名空间你可以进去跑 tcpdump、iperf、ip addr 甚至临时改路由表。理解这一点之后很多奇怪现象就有了解释为什么某条命令要加 sudo为什么修改了 h1 的路由不会影响 h2为什么控制器通过 OpenFlow 下发的规则能直接影响内核转发行为。2.2 装一个最小干净的实验环境安装、验证、VM 配置最常见的做法是在 Linux VM 里跑 Mininet。在 Debian/Ubuntu 系上一行命令就能装好sudo apt-get update sudo apt-get install -y mininet装完先做一次冒烟测试确认内核模块和依赖都没问题sudo mn --test pingall看到输出里两个主机之间丢包率为 0%说明默认拓扑的二层连通性已经通了。如果这条命令卡住或报错先不要继续往下做实验直接检查内核模块是否加载、Open vSwitch 是否正常工作问题越早暴露越好解决。我一般会把下面这段检查命令固定成习惯每次新建实验环境后先跑一遍uname -r sudo mn --version sudo ovs-vsctl showuname -r 确认内核版本mn --version 确认 Mininet 本身可用ovs-vsctl show 确认 Open vSwitch 的网桥和端口状态正常。版本号只要是你当前安装的实际输出就行不需要追求最新稳定可用排在第一位。虚拟机的硬件配置不用太高但也不宜太抠我常用的一套配置如下| 资源 | 建议值 | 说明 | | 内存 | 至少 2GB推荐 4GB | 内核网络栈与 OVS 都在内存里运行 | | CPU | 2 核以上 | 拓扑较大或流表较多时用得上 | | 磁盘 | 20GB 以上 | 安装依赖、留存抓包文件均够用 | | 网络模式 | 桥接或仅主机 | 只要能与控制器进程通信即可 |有人会尝试用容器代替 VM 跑 Mininet我一般不建议。容器环境需要额外赋予特权并挂载内核模块目录系统内核一升级就会出现各种奇怪问题VM 碰到问题容易回滚、容易排查。如果你需要图形界面注意 VM 内存 4GB 以下跑桌面环境会非常卡这点在后面的避坑章节会专门展开。还有一个细节容易在实验前栽跟头Mininet 默认连接控制器的端口是 6653但历史上 6633 也曾是默认端口不同控制器版本监听的可能不一样。我习惯显式指定端口不依赖任何默认值sudo mn --toposingle,3 --controllerremote,ip127.0.0.1,port6653ip 写 127.0.0.1 表示控制器跑在本机port 和控制器进程实际监听的端口保持一致。这个参数后面所有实验都会用到先记住它。3. 从命令行到 Python 脚本生成能复现的拓扑3.1 三行命令把实验跑起来--topo 里那些参数的准确含义先讲最省事的入门路径用命令行参数直接拉起一个拓扑sudo mn --toposingle,3 --controllerremote,ip127.0.0.1,port6653single,3 表示 1 个交换机下挂 3 个主机生成 h1、h2、h3 三台终端和一台名为 s1 的交换机。整体结构就是一个星型拓扑三台主机都接到同一台交换机上。如果想看链状拓扑可以换成 linear,4四台交换机首尾相连每台交换机挂一台主机。进入交互界面后先输入 net 和 dump 看一眼拓扑结构mininet net mininet dumpnet 打印所有节点和链路接口的对应关系dump 输出每个节点的基本信息和 IP 地址。确认拓扑符合预期之后再测连通性mininet pingallpingall 会依次对每对主机执行 ping最终汇总丢包率。在报告里记录这一步时不要只贴最终结果把命令和输出一起放进去读者才能知道你测的是哪个拓扑下的哪个连通关系。需要提醒的是命令行拓扑只适合做快速验证。一旦实验涉及特定带宽、时延、丢包率或更复杂的网络结构命令行参数会变得很长且难以维护。我一般会在交互验证通过之后立即转入 Python 脚本方式构建拓扑。3.2 用 Python 脚本自定义拓扑带带宽、时延与丢包的三主机实验做课程实验或正式测试时我不会用命令行拼拓扑而是把一个完整的拓扑脚本写出来。这样每个参数都有据可查改动一处就能重新跑一轮实验。下面是一个带带宽和时延的三主机拓扑示例from mininet.net import Mininet from mininet.node import OVSSwitch, RemoteController from mininet.link import TCLink from mininet.cli import CLI from mininet.topo import Topo class ExpTopo(Topo): def build(self): h1 self.addHost(h1, ip10.0.0.1/24) h2 self.addHost(h2, ip10.0.0.2/24) h3 self.addHost(h3, ip10.0.0.3/24) s1 self.addSwitch(s1) # 三台主机都接同一交换机链路带宽 10Mbit、时延 5ms self.addLink(h1, s1, bw10, delay5ms) self.addLink(h2, s1, bw10, delay5ms) self.addLink(h3, s1, bw10, delay5ms) # 需要模拟丢包时加 loss5表示 5% 丢包率 topo ExpTopo() net Mininet( topotopo, controllerRemoteController(c0, ip127.0.0.1, port6653), switchOVSSwitch, linkTCLink, ) net.start() CLI(net) net.stop()把脚本保存为 mytopo.py用sudo python3 mytopo.py运行。脚本里最关键的参数是linkTCLink它表示链路类型走 Traffic Control 约束bw 参数才真正生效。bw 单位是 Mbitdelay 是字符串格式比如5msloss 表示丢包百分比。如果不传 TCLinkaddLink 里写的带宽和延迟会被直接忽略——这是很多人调了半天带宽却没有任何变化的第一个原因。控制器这里用了 RemoteController意味着实验里真正下发流表的是外部控制器进程而不是 Mininet 自带的简单控制器。这样做的好处是你能在控制器侧看到完整的 packet_in 和 flow_mod 日志对流表建立过程有更直观的认识。3.3 让拓扑「看得见」dump、xterm 与外部工具配合拓扑跑起来之后光靠 net 命令的输出还不足以定位问题。我一般会做两件事先通过 dump 确认 IP 分配是否符合预期再开独立终端做抓包观察。sudo mn --toposingle,3 --controllerremote,ip127.0.0.1,port6653 --xterm加 --xterm 参数后Mininet 会为每个节点弹出独立的 xterm 窗口。你可以在 h1 的窗口里执行 tcpdump 抓包在 s1 的窗口里执行 ovs-ofctl 查看流表窗口互不干扰非常方便定位问题。如果你的实验机没有图形桌面可以用 ssh 登录后在终端里开多个 tmux 窗口效果类似只是视觉上不如 xterm 直观。另一种轻量做法是在 Python 脚本里直接输出拓扑连接关系print(net.dumpNodeConnections())这段代码会打印每个节点连接了哪些接口适合在实验启动阶段快速确认链路建链状态。三种方式各有分工命令行拓扑适合快速冒烟测试Python 脚本适合记录实验参数xterm 和抓包适合排错实际做实验时可以组合使用。4. 验证连通性只是开始流表观测和抓包定位4.1 pingall 还不是「验证过了」ARP、ICMP 与首次 ping 的抖动在交互界面里执行 pingall看起来是一句命令背后实际发生了很多事。大多数实验报告只关心丢包率是否为 0%但真正的验证应该关注协议交互过程。第一次执行 ping 时主机之间要先进行 ARP 解析源主机发送 ARP 请求询问目的主机的 MAC 地址拿到响应后才能封装 ICMP 报文。ARP 表建立之后第二次 ping 就直接走 IP 层不再有地址解析过程时延会明显下降。这个现象不是实验环境出了问题而是网络协议栈的正常行为。如果你想在报告里记录稳定的时延数据正确做法是先 ping 一次做「暖机」让 ARP 表建立起来再取后面几组 ping 的统计结果。记录时把命令输出原文贴进去比单独写一句「网络通畅」有说服力得多。4.2 用 ovs-ofctl 读流表在数据包进来之前交换机其实「不会转发」Mininet 默认创建的交换机是 Open vSwitch本质上是一台软件交换机它只会根据流表转发数据。执行 ping 之前先看一眼流表sudo ovs-vsctl show sudo ovs-ofctl dump-flows s1第一次执行时流表通常只有 table-miss 项或者完全为空。这是因为交换机还没收到任何数据包控制器也还没有下发任何规则。当 h1 发出第一个 ARP 请求时交换机会因为查不到匹配流表项把包封装成 packet_in 消息上送给控制器控制器根据自身逻辑计算出转发路径再下发 flow_mod 规则。此时再 dump 一次流表就能看到新出现的转发条目。流表里常见的几个字段如下| 字段 | 含义 | 在实验中的表现 | | cookie | 流表项的标识 | 控制器分配的流水号 | | priority | 匹配优先级 | 默认值通常够用 | | table-miss | 未命中时的行为 | 丢包或上送控制器 | | idle_timeout | 空闲老化时间 | 超过时限自动删除 | | actions | 匹配后执行的动作 | 转发到指定端口或上送控制器 |读流表是 SDN 实验报告里最有力的证据它直接证明转发行为由控制器下发而不是 Mininet 在主机之间提前搭好了静态通路。如果 pingall 全通但流表空无一物说明转发行为可能走了 Mininet 的默认路径控制器并没有真正参与转发整个实验的 SDN 属性就要打折扣了。4.3 用 tcpdump 抓包定位转发链路到底是谁把包丢了连通性问题有时候表现为 pingall 全通但 iperf 测吞吐就是上不去。这种场景单看流表很难定位我一般直接在主机上用 tcpdump 抓包# 在 h1 窗口执行 sudo tcpdump -i h1-eth0 -e -vv icmp # 在 h2 窗口执行 sudo tcpdump -i h2-eth0 -e -vv icmp-e 参数显示 MAC 头部抓包输出能同时看到 ARP 和 ICMP 报文。如果 h1 侧发出了 ARP 请求、h2 侧也收到了但 ICMP 报文始终不出现问题多半在流表或交换机端口配置上。如果 h2 侧连 ARP 都收不到说明链路层已经断了要往接口状态、链路两端配置方向排查。抓包和流表两者对照能解决实验中八成以上的连通性问题。流表告诉你交换机「打算怎么做」抓包告诉你数据包「实际走到了哪里」两者对齐之后问题定位通常只需要几分钟。5. 六个高频踩坑记录现象、原因与解决方案5.1 虚拟机图形界面卡到没法敲命令现象是鼠标飘忽、窗口重绘极慢命令敲到一半界面直接卡死Mininet 交互窗口里的命令经常被吞掉。原因是虚拟机图形加速能力不足加上内存分配偏小2GB 以下跑桌面版 Linux 本来就很吃力。解决的第一个办法是放弃桌面环境用 ssh 登录到虚拟机的终端操作把图形界面留在宿主机一侧第二个办法是给虚拟机分配 4GB 以上内存并安装轻量桌面环境。我自己的习惯是实验机一律不开桌面ssh 加 tmux 足够覆盖全部操作场景。5.2 控制器一直连不上报 connection refused现象是 mn 启动后长时间卡在 controller 连接阶段或者 ovs-ofctl dump-flows 时提示连接失败。原因通常是控制器进程没启动、监听端口不是 6653、或者防火墙拦截了本地回环接口上的连接。解决方法是先确认控制器进程的监听端口再用--controllerremote,ip127.0.0.1,port6653显式指定。实验机如果本身部署了防火墙策略记得放行本地回环或直接把回环接口设为信任。不要想当然地把控制器 IP 配置成其他地址除非你已经确认 VM 与控制器之间的路由是通的。5.3 主机之间能 ping 通外网却全丢现象是 h1 ping h2 正常但 h1 ping 8.8.8.8 全部 unreachable看路由表也没有默认路由。原因不是 Mininet 坏了而是默认拓扑没有提供外部网络路径主机处于隔离的 namespace 里既没有 NAT 也没有出网路由。解决方法是实验需要访问外网时启动命令加--nat参数或者自己加一个能上网的 NAT 节点。如果只是在做 SDN 转发实验完全可以忽略外网把注意力放在控制器下发的流表行为上。5.4 带宽参数明明写了iperf 测出来却完全没限速现象是 addLink 里写了 bw10结果 iperf 测出来还有几百 Mbit 甚至更高。原因是链路对象没有指定为 TCLinkbw 参数被 Mininet 静默忽略。解决方法是构造 Mininet 对象时指定linkTCLink或者在命令行加--linktc。验证流量整形是否生效可以在节点侧执行tc qdisc show看到 htb 或 netem 条目才说明参数真的起作用了。只看脚本参数不看实际队列规则是这个坑最常见的误判方式。5.5 流表 dump 为空或 ovs-ofctl 命令提示连接失败现象是 dump-flows 输出为空或者干脆报 connection failed。原因可能是网桥名不对、datapath 不可访问、或者 OpenFlow 协议版本不匹配。解决方法是先执行ovs-vsctl show拿到准确的网桥名确认网桥存在后再对网桥执行 ovs-ofctl。如果协议版本不匹配可以在自定义拓扑中给交换机指定协议from mininet.node import OVSSwitch net Mininet( topotopo, controllerRemoteController(c0, ip127.0.0.1, port6653), switchOVSSwitch, linkTCLink, switchOptsdict(protocolsOpenFlow13), )OpenFlow13 是目前主流控制器普遍支持的版本指定之后能减少不少控制器与交换机之间的兼容问题。不要忽略协议版本差异它是 OpenFlow 实验里最容易忽略但影响最大的一个参数。5.6 apt 安装完 Mininet 后 mn 命令找不到现象是 apt-get install 提示安装成功但执行 mn 时提示命令不存在。原因通常是命令路径不在 PATH 环境变量里或者安装过程中依赖缺失导致可执行文件没有正确放置。解决方法是先用find / -name mn -type f 2/dev/null定位可执行文件的实际位置再检查 PATH 是否包含对应目录。如果确认文件存在但无法运行重新安装依赖并做一次干净的apt-get install --reinstall mininet。不要反复安装不同来源的 Mininet环境会越弄越乱。6. 让实验报告可复现把拓扑参数化并回采集证据6.1 用 argparse 把实验参数变成命令行输入前面几章的实验流程已经能把拓扑搭起来并验证连通性但到这一步实验还停留在「手动跑一轮、记录一轮」的状态。真正可复现的实验应该做到每次运行前传入参数就能得到对应的拓扑和结果。我把这个思路落地成了参数化脚本import argparse from mininet.topo import Topo parser argparse.ArgumentParser(descriptiongenerate mininet topo) parser.add_argument(--hosts, typeint, default3) parser.add_argument(--bw, typeint, default10) parser.add_argument(--delay, default5ms) parser.add_argument(--loss, typeint, default0) args parser.parse_args() class ExpTopo(Topo): def build(self): s1 self.addSwitch(s1) for i in range(1, args.hosts 1): h self.addHost(fh{i}, ipf10.0.0.{i}/24) self.addLink(h, s1, bwargs.bw, delayargs.delay, lossargs.loss)保存为 exp_topo.py 后配合前面章节的 Mininet() 构造和 CLI() 一起使用。启动实验时直接改参数不需要重新编辑脚本sudo python3 exp_topo.py --hosts 4 --bw 20 --delay 5ms这种方式跑出来的实验参数、拓扑、测量结果一一对应报告里可以写清楚「本次实验用 4 台主机、带宽 20Mbit、时延 5ms」复现成本降到最低。实验跑完后我习惯从三个位置收集证据pingall 的完整输出、流表的前后对比、以及 tc qdisc 的队列规则。命令输出直接贴进报告流表对比能说明控制器参与转发的过程tc 规则证明链路参数真实生效。这三样东西放在一起实验结论才站得住脚。我第一次写 Mininet 实验报告时只贴了拓扑截图和 pingall 结果后来才意识到报告真正有价值的地方在于把「命令输入、协议交互、流表变化、链路实测」串成一条完整的证据链。养成这个习惯之后即使过了一个月再回看自己的实验记录也能照着复现出现问题时还能根据记录定位到具体环节。希望帮到你。本文还有配套的精品资源点击获取