本案例由开发者:华为2024年第三批次协同育人项目-南航金城学院-孙福清教师提供
一、概述
1. 案例介绍
本案例是在华为云主机中,进行软件定义网络SDN的二层交换机交换原理实践:使用 python 开源模块 mininet,编写 python 代码建立2个SDN交换机4个主机的简单网络拓扑,按照二层交换机mac地址学习和转发表原理,构建转发流表,下发到两个SDN交换机,使得4个主机之间网络互通。
通过本实践,使得学生学习理解软件定义网络SDN概念,学习和理解二层交换机mac地址学习和转发表。
华为开发者空间,是为全球开发者打造的专属开发者空间,致力于为每位开发者提供一台云主机、一套开发工具和云上存储空间,汇聚昇腾、鸿蒙、鲲鹏、GaussDB、欧拉等华为各项根技术的开发工具资源,并提供配套案例指导开发者 从开发编码到应用调测,基于华为根技术生态高效便捷的知识学习、技术体验、应用创新。
2. 适用对象
- 个人开发者
- 高校学生
3. 案例时间
本案例总时长预计90分钟。
4. 案例流程

说明:
- 配置python开发环境;
- 安装python模块mininet;
- 验证python模块mininet;
- SDN仿真(MAC地址学习和转发)。
5. 资源总览
本案例预计花费0元。
| 资源名称 | 规格 | 单价(元) | 时长(分钟) |
|---|---|---|---|
| 华为开发者空间 - 云主机 | 鲲鹏通用计算增强型 kc2 | 4vCPUs | 8G | Ubuntu | 免费 | 90 |
二、环境配置
1. 开发者空间配置
面向广大开发者群体,华为开发者空间提供一个随时访问的“开发桌面云主机”、丰富的“预配置工具集合”和灵活使用的“场景化资源池”,开发者开箱即用,快速体验华为根技术和资源。
进入华为开发者空间工作台界面,点击打开云主机 > 进入桌面连接云主机。 如果还没有领取云主机进入工作台界面后点击配置云主机,选择Ubuntu操作系统。


2. 安装文本编辑器gedit
本案例中,参考案例《【案例共创】华为云主机Linux Python开发环境配置》“三、文本编辑工具gedit”完成文本编辑工具gedit的安装和测试功能。
3. 配置ubuntu apt镜像软件源
本案例中,参考案例《【案例共创】华为云主机Linux Python开发环境配置》“四、配置ubuntu的apt软件源”完成软件源的安装和更新。
注:华为镜像源地址:
http://repo.huaweicloud.com/ubuntu-ports/
三、安装验证 python 模块 mininet
1. python 模块 mininet
SDN 是一种网络架构,它将控制平面(Control Plane)与数据平面(Data Plane)分离,使得网络控制逻辑集中在一个控制器中(如 OpenDaylight、ONOS、Ryu 等),而数据转发由交换机完成。 核心理念:通过软件编程控制网络行为,而不是手动配置每个设备。 协议:OpenFlow 是最常用的南向协议,用于控制器与交换机通信。
Mininet 是一个轻量级的软件定义网络SDN的网络仿真器,用于在linux系统(如笔记本电脑或虚拟机)上快速创建包含主机、交换机、控制器和链路的完整SDN网络拓扑。 特点: - 支持 OpenFlow 协议; - 可以运行真实的 Linux 网络栈; - 支持自定义拓扑、带宽、延迟、丢包率等参数; - 与真实网络行为高度一致。 官网地址:https://mininet.org/
2. 安装mininet
- 多种方式安装mininet 本案例采用Ubuntu包安装方式安装mininet,非常简单方便。在root用户下,先创建一个独立的文件夹SDN,在这个文件夹下安装mininet。
依次执行如下命令:
#创建文件夹
mkdir sdn
#进入文件夹
cd sdn
#安装mininet
apt install mininet

安装的位置:/usr/lib/python3/dist-packages/mininet 
由于采用了包安装方式,python包mininet位于ubuntu的python全局环境,因此直接引用mininet模块,无需创建Python的虚拟环境。
#python命令
python3
#导入mininet
import mininet
#导入之后退出
exit()

3. 验证mininet
在终端命令行下运行mininet命令mn创建一个最小的网络拓扑,并测试节点之间的可达。 创建一个最小的仿真网络:1个交换机带2个主机:
mn

测试两个主机之间是否可达:
#测试是否可达
pingall
#退出
exit

清理仿真资源
mn -c

四、网络仿真(无控制器的二层交换机)
1. 定义仿真网络
- Mininet有两种方式定义仿真网络
- 命令行方式:创建仿真网络拓扑,非常不方便,记忆众多命令,容易出错, 本案例不使用。
- python代码:创建仿真网络拓扑,可以定义更为复杂的仿真网络,本案例采用。
仿真网络思想: 没有SDN控制器ryu、pox等,只有交换机switch和主机host。 根据二层交换机的基于MAC地址学习和转发的原理,人工构造和添加流表,使得主机之间互通。
仿真网络拓扑: 
- 示例python代码
#!/usr/bin/env python
from mininet.net import Mininet
from mininet.node import RemoteController
from mininet.node import Host
from mininet.node import OVSKernelSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel, info
def myNetwork():
net = Mininet( topo=None,
build=False)
info( '*** Adding controller\n' )
c0=net.addController(name='c0',
controller=RemoteController,
ip='127.0.0.1',
protocol='tcp',
port=6633)
info( '*** Add switches\n')
s1 = net.addSwitch('s1', cls=OVSKernelSwitch)
s2 = net.addSwitch('s2', cls=OVSKernelSwitch)
info( '*** Add hosts\n')
h1 = net.addHost('h1', cls=Host, defaultRoute=None,mac='24:69:A5:A2:CA:01')
h2 = net.addHost('h2', cls=Host, defaultRoute=None,mac='24:69:A5:A2:CA:02')
h3 = net.addHost('h3', cls=Host, defaultRoute=None,mac='24:69:A5:A2:CA:03')
h4 = net.addHost('h4', cls=Host, defaultRoute=None,mac='24:69:A5:A2:CA:04')
info( '*** Add links\n')
net.addLink(h1, s1)
net.addLink(h2, s1)
net.addLink(h3, s2)
net.addLink(h4, s2)
net.addLink(s1, s2)
info( '*** Starting network\n')
net.build()
info( '*** Starting controllers\n')
for controller in net.controllers:
controller.start()
info( '*** Starting switches\n')
net.get('s1').start([c0])
net.get('s2').start([c0])
CLI(net)
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
myNetwork()
- 代码释义 (1)引入 Mininet 的核心类 代码:
from mininet.net import Mininet
from mininet.node import RemoteController, Host, OVSKernelSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel, info
释义: Mininet:整个仿真网络的“总管”。 RemoteController:让 Mininet 去连外部控制器(本例是 POX)。 Host / OVSKernelSwitch:主机与 Open vSwitch 内核交换机。 CLI:交互式命令行。 setLogLevel, info:打印彩色日志。
(2)创建一个“空壳”网络实例,稍后再往里塞节点 代码:
def myNetwork():
net = Mininet(
topo=None, # 不依赖外部 Topo 对象,后面手动加节点
build=False ) # 先不立刻 build,方便后面再改
释义: 创建空壳网络对象,后面逐步向内增加节点:控制器、交换机,主机等。
(3)添加控制器 代码:
info('*** Adding controller\n')
c0 = net.addController(
name='c0',
controller=RemoteController,
ip='127.0.0.1',
protocol='tcp',
port=6633
)
释义: 控制器名字叫 c0。 类型是 RemoteController,即外部控制器(POX、Ryu、ODL…)。 地址端口指向本地6633,正好与 POX 默认一致。
(4)添加交换机 代码:
info('*** Add switches\n')
s1 = net.addSwitch('s1', cls=OVSKernelSwitch)
s2 = net.addSwitch('s2', cls=OVSKernelSwitch)
释义: 两台 Open vSwitch 内核交换机 s1、s2。 cls=OVSKernelSwitch 表示使用内核态 datapath(性能高,需 root)。
(5)添加主机 代码:
info('*** Add hosts\n')
h1 = net.addHost('h1', cls=Host, defaultRoute=None,
mac='24:69:A5:A2:CA:01')
释义: 四个主机,手动指定 MAC 方便抓包或做流表下发实验。 defaultRoute=None 表示暂时不自动配置默认网关。
(6)添加链路 代码:
info('*** Add links\n')
net.addLink(h1, s1) # h1 连 s1
net.addLink(h2, s1) # h2 连 s1
net.addLink(h3, s2) # h3 连 s2
net.addLink(h4, s2) # h4 连 s2
net.addLink(s1, s2) # 两台交换机互连
释义: 默认链路带宽无限、延迟 0ms、无丢包;如需限制可加 bw=10,delay='5ms' 等参数。
(7)启动网络 代码:
info('*** Starting network\n')
net.build() # 真正创建 namespace、veth、OVS 等
info('*** Starting controllers\n')
for controller in net.controllers:
controller.start()
info('*** Starting switches\n')
net.get('s1').start([c0])
net.get('s2').start([c0])
释义: net.build():生成所有虚拟设备。 把 s1、s2 的控制器指向c0,这样交换机才会发 Packet-In 给 POX 等控制器。 注意顺序:先起控制器 → 再起交换机,否则交换机会报错 “no controller”。
(8)进入交互 CLI & 清理 代码和释义:
CLI(net) # 阻塞在这里,用户可敲 pingall、iperf、dpctl...
net.stop() # 用户键入 exit 后自动清理 veth、namespace、OVS
(9)代码主入口 代码:
if __name__ == '__main__':
setLogLevel('info') # 打印 INFO 级别以上日志,好看
myNetwork()
释义: 脚本直接运行时执行myNetwork(),开始仿真。
2. 启动仿真网络
- 新建空白py代码文件准备编写py代码。
gedit 2switch4hosts.py
如果gedit未授权,还需要对gedit进行root账号的X图形服务器权限授权,允许 root 用户从本地连接到 X 服务器,另开一个终端,输入如下代码:
xhost +local:root

注:执行代码报授权协议,只需按照上述步骤执行即可。
再次新建空白py代码文件,将第一步中示例代码复制到文件中,点击保存。
gedit 2switch4hosts.py

- 执行代码 通过如下命令执行代码,定义、创建仿真网络,启动仿真:
python3 2switch4hosts.py

- 测试连通性 执行如下代码测试仿真网络主机之间的网络连通性。
pingall

此时仿真网络既没有配置SDN控制器,也没有下发流表,因此主机之间是不通的。
3. 构造下发流表
- 查看仿真网络端口连接关系 使用linke查看连接关系。
links

4个主机的mac地址,通过代码或者仿真命令: ('h1', cls=Host, defaultRoute=None,mac='24:69:A5:A2:CA:01') ('h2', cls=Host, defaultRoute=None,mac='24:69:A5:A2:CA:02') ('h3', cls=Host, defaultRoute=None,mac='24:69:A5:A2:CA:03') ('h4', cls=Host, defaultRoute=None,mac='24:69:A5:A2:CA:04')
根据二层交换机的MAC地址学习原理,构造MAC地址学习表:
| 主机 | MAC地址表 | 交换机 | 端口 |
|---|---|---|---|
| h1 | 24:69:A5:A2:CA:01 | s1 | 1 |
| h2 | 24:69:A5:A2:CA:02 | s1 | 2 |
| h3 | 24:69:A5:A2:CA:03 | s1 | 3 |
| h4 | 24:69:A5:A2:CA:04 | s1 | 3 |
| 主机 | MAC地址表 | 交换机 | 端口 |
|---|---|---|---|
| h1 | 24:69:A5:A2:CA:01 | s2 | 3 |
| h2 | 24:69:A5:A2:CA:02 | s2 | 3 |
| h3 | 24:69:A5:A2:CA:03 | s2 | 1 |
| h4 | 24:69:A5:A2:CA:04 | s2 | 2 |
根据二层交换机的MAC地址转发原理,从哪来到哪去,依据上面的MAC地址学习表,构造SDN的转发流表:
交换机S1:到主机h1的报文的转发规则:
sh ovs-ofctl add-flow s1 dl_dst=24:69:A5:A2:CA:01,action=output:1
交换机S1:到主机h2的报文的转发规则:
sh ovs-ofctl add-flow s1 dl_dst=24:69:A5:A2:CA:02,action=output:2
交换机S1:到主机h3的报文的转发规则:
sh ovs-ofctl add-flow s1 dl_dst=24:69:A5:A2:CA:03,action=output:3
交换机S1:到主机h4的报文的转发规则:
sh ovs-ofctl add-flow s1 dl_dst=24:69:A5:A2:CA:03,action=output:3
交换机S2:到主机h1的报文的转发规则:
sh ovs-ofctl add-flow s2 dl_dst=24:69:A5:A2:CA:01,action=output:3
交换机S2:到主机h2的报文的转发规则:
sh ovs-ofctl add-flow s2 dl_dst=24:69:A5:A2:CA:02,action=output:3
交换机S2:到主机h3的报文的转发规则:
sh ovs-ofctl add-flow s2 dl_dst=24:69:A5:A2:CA:03,action=output:1
交换机S2:到主机h4的报文的转发规则:
sh ovs-ofctl add-flow s2 dl_dst=24:69:A5:A2:CA:04,action=output:2
目的地址为广播地址(ff:ff:ff:ff:ff:ff)的转发规则,例如ipv4的ARP报文: 交换机S1和S2:广播的以太网目的地址,泛洪FLOOD。
sh ovs-ofctl add-flow s1 dl_dst=ff:ff:ff:ff:ff:ff,actions=FLOOD
sh ovs-ofctl add-flow s2 dl_dst=ff:ff:ff:ff:ff:ff,actions=FLOOD
构造的流表如下:
sh ovs-ofctl add-flow s1 dl_dst=ff:ff:ff:ff:ff:ff,actions=FLOOD
sh ovs-ofctl add-flow s2 dl_dst=ff:ff:ff:ff:ff:ff,actions=FLOOD
sh ovs-ofctl add-flow s1 dl_dst=24:69:a5:a2:ca:01,action=output:1
sh ovs-ofctl add-flow s1 dl_dst=24:69:a5:a2:ca:02,action=output:2
sh ovs-ofctl add-flow s1 dl_dst=24:69:a5:a2:ca:03,action=output:3
sh ovs-ofctl add-flow s1 dl_dst=24:69:a5:a2:ca:04,action=output:3
sh ovs-ofctl add-flow s2 dl_dst=24:69:a5:a2:ca:01,action=output:3
sh ovs-ofctl add-flow s2 dl_dst=24:69:a5:a2:ca:02,action=output:3
sh ovs-ofctl add-flow s2 dl_dst=24:69:a5:a2:ca:03,action=output:1
sh ovs-ofctl add-flow s2 dl_dst=24:69:a5:a2:ca:04,action=output:2
下发流表,将上述代码依次执行:
再次测试仿真网络的主机之间的连通性: 
五、安装验证python控制器pox
1. 开源SDN控制器pox
POX是一个基于python的开源 OpenFlow/SDN 控制器,其底层模块由C++实现,上层应用可以用python编写,提供快速开发网络控制软件原型的平台。 基于python3开源控制器POX,因其简单易用而广泛应用,适合初学者和小规模SDN网络实验,是SDN入门、学习SDN控制器的很好选择。 在SDN架构中,POX作为控制器负责集中管理网络的行为,可进行路径选择、流量管理、安全策略应用等操作。
简单案例: - mininet连接POX控制器, - POX运行l2_pairs组件, - mininet使用h1 ping h2时,mininet交换机上报给控制器事件packet_in, - 控制器的pox的l2_pairs组件可以抽取packet_in中的src_mac和in_port,进行mac地址学习, 生成mac地址转发表, - 控制器根据事件packet_in中的dst_mac,查找转发表,得到报文的转发目的端口,构造下发下发的src_mac和dst_mac的2条流表flowentry到mininet交换机, - mininet交换机就工作在传统的二层交换机模式。
代码地址: https://github.com/noxrepo/pox https://noxrepo.github.io/pox-doc/html/
2. 安装下载pox
pox目前都没有apt安装的包以及pyhton pip安装的模块,只有纯python代码,通过git可以下载到本地直接进行python运行,无需安装。 新创建一个独立文件夹:
#创建一个独立文件夹
mkdir 202507
#进入到这个目录下
cd 202507

在此目录下下载源码:
git clone https://github.com/noxrepo/pox
#查看
ls
#进入pox
cd pox
#查看
ls

下载的代码是pox的gar分支,要求python3:POX versions are named. Starting with POX "gar", POX officially requires Python 3。 下载后的快速启动方式:python3 pox.py samples.pretty_log forwarding.l2_learning。
3. 启动控制器pox
- 快速启动pox 使用如下命令进行启动:
python3 pox.py log.level --DEBUG forwarding.l2_learning
说明: - pox.py,是其启动入口。 - log.level --DEBUG,是将调试信息打开,可以更好的观察过程。 - forwarding.l2_learning,是一种控制器实现的模式,二层交换机学习。 
从提示信息可以看出,pox最后更新时间比较早,最高只支持python3.9版本。而华为云主机的预装python版本为 python3.12。但实际pox在python 3.12下运行也正常。
- 启动mininet 在另一个终端启动mininet。
python3 2switch4hosts.py

从上图可以看到,POX终端的输出提示mininet成功连接上了pox控制器。 “ERROR:packet:(dns) parsing questions: ord() expected string of length 1, but int found"提示dns报文解释错误,不用理会,不影响本案例。 如果要消除,需要在华为云主机上安装python的多版本,使用python3.9来运行pox,则消除错误。
- Mininet的SDN交换机连接上pox的SDN控制器,可以开始仿真 依次执行如下命令,查看仿真结果:
dpctl dump-flows
第一次仿真不通,进行pingall操作:
pingall
再次仿真:
dpctl dump-flows

从上可以看出,初始mininet交换机上没有流表,但开始执行主机互通测试后,得到流表,并且主机之间也互通。 POX终端输出调试信息:向交换机下发安装转发规则的流表 “DEBUG:forwarding.l2_learning:installing flow for 24:69:a5:a2:ca:02.2 -> 24:69:a5:a2:ca:01.1 DEBUG:forwarding.l2_learning:installing flow for 24:69:a5:a2:ca:01.1 -> 24:69:a5:a2:ca:02.2……”。
控制器pox自带的forwarding.l2_learning的模式,下发的流表: “cookie=0x0, duration=5.399s, table=0, n_packets=1, n_bytes=42, idle_timeout=10, hard_timeout=30, priority=65535,arp,in_port="s1-eth2",vlan_tci=0x0000,dl_src=24:69:a5:a2:ca:02,dl_dst=24:69:a5:a2:ca:01,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=2 actions=output:"s1-eth1"……” 这个流表,不是前面所说的传统L2交换机的只基于MAC地址学习和转发的转发模式,而是使用了:源mac,目的mac,源ip,目的ip等的匹配规则。
六、反馈改进建议
如您在案例实操过程中遇到问题或有改进建议,可以到论坛帖评论区反馈即可,我们会及时响应处理,谢谢!
6万+

被折叠的 条评论
为什么被折叠?



