Mininet是一个网络仿真器,它在单个Linux内核上运行一组终端主机,交换机,路由器和链接。它使用轻量级虚拟化使单个系统看起来像一个完整的网络,运行相同的内核,系统和用户代码。 Mininet主机的行为就像真机一样;你可以ssh到它并运行任意程序。你运行的程序可以通过看似真正的以太网接口发送数据包,具有给定的链接速度和延迟。数据包会通过一定数量的真实以太网交换机,路由器或中间盒进行处理。详见mininet
在终端输入sudo mn
,打开mininet进入CLI交互窗口。
在CLI环境下输入help
便可以获取可执行命令的信息,在2.3版本中有以下28个命令:
EOF gterm iperfudp nodes pingpair py switch
dpctl help link noecho pingpairfull quit time
dump intfs links pingall ports sh x
exit iperf net pingallfull px source xterm
输入:help command
便可以获取该命令的详细帮助信息。下面介绍几组常用命令:
mininet>nodes 查看全部节点信息
mininet>net 查看链路信息
mininet>dump 查看各节点详细信息
mininet>pingall 测试所有结点是否连通
mininet>pingpair 两个主机将互 ping
mininet>link s1 h2 up/down 启用/禁用s1跟h2之间的链路
mininet>links 报告所有链路状态
mininet>iperf h1 h2 两个节点之间用指定简单的 TCP 测试
mininet>iperfudp 10M h1 h2 两个节点之间用指定简单 udp 进行测试,10M指自己设置的带宽
mininet>time [command] 测量命令所执行的时间
mininet>xterm/gterm s1 打开某结点控制终端
mininet>sh [cmd args] 运行外部 shell 命令
mininet>px/py 执行 python 语句
mininet>source 从输入文件读入命令
mininet>exit/quit/EOF 退出 mininet 命令行
前面提到mininet采用轻量级的虚拟化技术,使得其模拟的每台主机和交换机都是独立的,所以可以像在真实主机的终端中执行命令一样,在模拟的主机或交换机上执行任何系统命令。在CLI环境中执行的格式为:node command
,command 格式和用法同Linux主机,如:
mininet>h1 ifconfig 查看h1节点网络信息
mininet>h1 ping -c 4 h2 实现两主机互连测试
mininet>h1 ifconfig h1-eth0 10.108.126.3 netmask 255.255.255.0 修改虚拟的主机的ip以及mask地址
还可以运行python脚本,比如在主机建立web服务器,并获取HTTP请求:
mininet> h1 python -m SimpleHTTPServer 80 & #在主机 h1 开启 Web 服务
mininet> h2 wget -O - h1 #在主机 h2 获取网页内容
这种用法和运行xterm node为节点打开单独的终端,在单独终端中运行系统命令一样。
dpctl 和 ovs-ofctl 都是命令行的OpenFlow交换机管理工具,可以用来操作和管理流表。在CLI中管理流表的用法如下:
mininet>dpctl command [arg1] [arg2] 在所有交换机上运行 dpctl 或 ovs-ofctl 命令
2.2.0以后版本的mininet支持可视化,在/home/mininet/mininet/examples目录下提供miniedit.py脚本,切换到相应目录下,在终端中执行:
sudo python miniedit.py
便会弹出Mininet的可视化界面,如下图所示。可以很方便的在界面上可进行自定义拓扑和自定义设置,还支持将创建的拓扑保存成脚本,也支持从脚本打开拓扑,十分方便。具体可以参考Mininet可视化应用。
和其他Linux命令一样,以下参数可以随意组合跟在mn后面,但要注意每个参数格式的区别,有些参数面的值是用等号连接的,但有些是用空格连接【。。。】,使用的时候需要注意。
--mac 自动设置MAC地址,MAC地址与IP地址的最后一个字节相同
--arp 为每个主机设置静态ARP表,存储同一网段的主机的mac和IP
--switch default|ivs|lxbr|ovs|ovsbr|ovsk|user[,param=value...]
其中,ovs,defaul,ovsk都为OVS(openvswitch)交换机,lxbr=LinuxBridge user=UserSwitch ivs=IVSSwitch ovsbr=OVSBridge
--controller=default|none|nox|ovsc|ref|remote|ryu[,param=value...]
其中, ovsc=OVSController none=NullController
remote=RemoteController default=DefaultController
nox=NOX ryu=Ryu ref=Controller
--controller=remote,ip=[controller IP] ,port=[controller listening port] 设置远程控制器
比如:设定启动支持openflow1.3的交换机和IP为10.108.125.9的远程交换机:
sudo mn --controller=remote,ip=10.108.125.9,port=6653 --switch ovsk,protocols=OpenFlow13
--topo single,n 单交换机,星型拓扑, n表示主机数
--topo linear,n 线性拓仆,n表示n个交换机直线连接
--topo tree,depth=a,fanout=b 树状拓仆,depth表示树深度,fanout表示每个结点有几个子结点。所有叶子结点都为主机,非叶子结点为交换机
--topo minimal|reversed|torus[,param=value] MinimalTopo,SingleSwitchReversedTopo,TorusTopo
--custom ~/mininet/custom/mytopo.py --topo=mytopo 用户自定义拓扑(mytopo.py是自己定义拓扑的python文件)
注: 一般在实际应用的时候,我们并不会通过上述两种方式创建网络拓扑,而是直接创建python脚本,在脚本中导入相关的模块,调用mininet的功能,python解释器直接执行。这样方便结合其他项目进行开发。具体可以参考mininet搭建自定义网络拓扑。需要注意的是在
topo
类和mininet
类里面都有addhost,addswitch,addlink
函数,但定义并不相同,具体参考源文件。
mn –x //作用同在cli环境中运行xterm
mn –c
注: 这里要注意的是经常在退出mininet后,再次进入会发现报如下错误:
Exception: Error creating interface pair (s5-eth1,s1-eth3): RTNETLINK answers: File exists
这是由于进程未被完全杀死造成的,所以在退出mininet环境后进行清理的时候,需要使用sudo权限:
sudo mn –c
--host=HOST cfs|proc|rt[,param=value...]
rt=CPULimitedHost{'sched': 'rt'}
proc=Host
cfs=CPULimitedHost{'sched': 'cfs'}
--link=LINK default|ovs|tc|tcu[,param=value...]
default=Link ovs=OVSLink tcu=TCULink tc=TCLink
--custom=CUSTOM read custom classes or params from .py file(s)
--test=TEST none|build|all|iperf|pingpair|iperfudp|pingall
-i IPBASE, --ipbase=IPBASE
base IP address for hosts
-v VERBOSITY, --verbosity=VERBOSITY
info|warning|critical|error|debug|output
--innamespace sw and ctrl in namespace?
--listenport=LISTENPORT
base port for passive switch listening
--nolistenport don't use passive listening port
--pre=PRE CLI script to run before tests
--post=POST CLI script to run after tests
--pin pin hosts to CPU cores (requires --host cfs or --host rt)
--nat [option=val...] adds a NAT to the topology that connects Mininet hosts to the physical network.
Warning: This may route any traffic on the machine that uses Mininet's IP subnet into the
Mininet network. If you need to change Mininet's IP subnet, see the --ipbase option.
--version prints the version and exits
--cluster=server1,server2...
run on multiple servers (experimental!)
--placement=block|random
node placement for --cluster (experimental!)
.
mininet>dpctl dump-flows
在一个depth=2,fanout=2的树形拓扑中,执行h1 ping -c1 h2,得到流表项如下:
mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
*** s2 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=4.087s, table=0, n_packets=1, n_bytes=42, idle_timeout=60, idle_age=4, priority=65535,arp,in_port=2,vlan_tci=0x0000,dl_src=06:7d:8b:e3:9f:b5,dl_dst=22:7e:4a:a6:25:c7,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=2 actions=output:1
cookie=0x0, duration=4.086s, table=0, n_packets=1, n_bytes=98, idle_timeout=60, idle_age=4, priority=65535,icmp,in_port=1,vlan_tci=0x0000,dl_src=22:7e:4a:a6:25:c7,dl_dst=06:7d:8b:e3:9f:b5,nw_src=10.0.0.1,nw_dst=10.0.0.2,nw_tos=0,icmp_type=8,icmp_code=0 actions=output:2
cookie=0x0, duration=4.085s, table=0, n_packets=1, n_bytes=98, idle_timeout=60, idle_age=4, priority=65535,icmp,in_port=2,vlan_tci=0x0000,dl_src=06:7d:8b:e3:9f:b5,dl_dst=22:7e:4a:a6:25:c7,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_tos=0,icmp_type=0,icmp_code=0 actions=output:1
*** s3 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
mininet>
mininet>dpctl add-flow in_port=2,actions=output:1
mininet>dpctl add-flow in_port=1,actions=output:2
在所有的交换机中添加流表,让从1号端口进入的报文都从2号端口转发,添加后流表项如下(在操作之前先清空交换机中的流表):
mininet> dpctl add-flow in_port=1,actions=output:2
*** s1 ------------------------------------------------------------------------
*** s2 ------------------------------------------------------------------------
*** s3 ------------------------------------------------------------------------
mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=3.454s, table=0, n_packets=0, n_bytes=0, idle_age=3, in_port=1 actions=output:2
*** s2 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=3.454s, table=0, n_packets=0, n_bytes=0, idle_age=3, in_port=1 actions=output:2
*** s3 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=3.455s, table=0, n_packets=0, n_bytes=0, idle_age=3, in_port=1 actions=output:2
流表匹配的报文数n_packets都为0,这时候通过h1 ping h2,再查看流表项:
mininet> h1 ping -c1 h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=1.79 ms
--- 10.0.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.793/1.793/1.793/0.000 ms
mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=35.967s, table=0, n_packets=2, n_bytes=140, idle_age=0, in_port=1 actions=output:2
*** s2 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=35.967s, table=0, n_packets=2, n_bytes=140, idle_age=0, in_port=1 actions=output:2
*** s3 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=35.968s, table=0, n_packets=0, n_bytes=0, idle_age=35, in_port=1 actions=output:2
这时候直接可以ping通,发现s2中的流表匹配到两个报文(一个arp请求,一个icmp请求),但通过h1 ping h3,却发现不通,因为从1端口的报文都会无条件匹配到2号端口:
mininet> h1 ping -c1 h3
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
From 10.0.0.1 icmp_seq=1 Destination Host Unreachable
--- 10.0.0.3 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
mininet>dpctl del-flows
删除后再查看,流表为空:
mininet> dpctl del-flows
*** s1 ------------------------------------------------------------------------
*** s2 ------------------------------------------------------------------------
*** s3 ------------------------------------------------------------------------
mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
*** s2 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
*** s3 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
这种流表的操作方式十分不方便,也很少有人这样使用。一般操作流表都使用ovs-ofctl,ofctl等工具在终端中操作或通过控制器环境操作。具体见下一节。
ovs-ofctl是命令行下的交换机管理工具,也可以在终端中用来管理openflow 流表。
查看交换机中的流表项:
sudo ovs-ofctl dump-flows -O openflow13 s1 # -O参数后面跟协议,s1表示交换机的id。
ovs-ofctl dump-flows br-sw
当然,也可在mininet的命令行窗口使用sh
命令来直接调用上述指令:
mininet> sh ovs-ofctl dump-flows -O openflow13 s1 # 效果同在终端中执行
执行如下命令,增加一条流表项,将主机1发给主机2的数据包丢弃:
ovs-ofctl add-flow br-sw ‘dl_type=0x0800,nw_src=10.0.0.7,nw_dst=10.0.0.11, priority=27,table=0,actions=drop’
该流表项的匹配字段包括:dl_type=0x0800(MAC帧上一层为IP协议)、nw_src=10.0.0.7(源IP地址为10.0.0.7)、nw_dst=10.0.0.11(目的IP地址为10.0.0.11);优先级priority设为27,高于其他流表,故优先执行;table id为0,即将该流表项下发到table 0中。该流表项表示:从主机10.0.0.7发往主机10.0.0.11的IP包将被抛弃。
其他流表操作
1.列出br-int网桥的接口
ovs-ofctl -O OpenFlow13 show br-int
2.列出br-int网桥的接口
ovs-ofctl dump-ports -O OpenFlow13 br-int
3.列出br-int网桥的某个接口的详细信息
ovs-ofctl dump-ports -O OpenFlow13 br-int 1
4.查看 Open vSwitch 中的端口信息
ovs-ofctl show -O OpenFlow13 br-int
5.获得网络接口的 OpenFlow 编号
ovs-vsctl get Interface tap8f178fef-10 ofport
6.查看网桥下的流表
ovs-ofctl dump-flows -O OpenFlow13 br-int
7.查看ovs下的 datapath 的信息
ovs-dpctl show
8.根据流量显示在流表中的走向
ovs-appctl ofproto/trace br-int in_port=2 | grep “Rule|action”
9.ovs设置控制器
ovs-vsctl set-controller br0 tcp:1.2.3.4:663
10.ovs添加流表
ovs-ofctl add-flow br0 in_port=1,actions=output:2
11.删除网桥中所有的流表
ovs-ofctl del-flows br0
12.删除根据匹配项删除网桥中的流表
ovs-ofctl del-flows br0 “in_port=1”
在传统网络设备中,交换机和路由器的数据转发需要依赖设备中保存的二层MAC地址转发表或者三层IP地址路由表,而OpenFlow交换机中使用的流表也是如此,不过在它的表项中整合了网络中各个层次的网络配置信息,从而在进行数据转发时可以使用更丰富的规则。
OpenFlow v1.3中流表项主要由7部分组成,分别是匹配域(用来识别该条表项对应的flow)、优先级(定义流表项的优先顺序)、计数器(用于保存与条目相关统计信息),指令(匹配表项后需要对数据分组执行的动作)、超时:最大时间计数值或流在交换机中失效之前的剩余时间、Cookie:由控制器选择的不透明数据值、Flags。
匹配字段:对数据包匹配。包括入端口和数据包头,以及由前一个表指定的可选的元数据。流表项通过匹配字段和优先级决定,在一个流表中匹配字段和优先级共同确定唯一的流表项。