软件定义网络SDN基础实验:MiniNet常用命令、创建网络拓扑、OpenFlow流表操作

此实验基于《软件定义网络实验1-5》,主要内容为:

  • MiniNet常用命令
  • 如何创建网络拓扑
  • OpenFlow流表操作

00x1 搭建SDN环境

SDN 环境配置:Mininet + Ryu

1. 测试环境是否搭建成功

启动Ryu,进入 /ryu/app,启动一个交换机案例app:

ryu-manager simple_switch_13.py

启动Mininet,mn 是创建最简单的默认拓扑,controller 默认是 Mininet 自带的控制器,这里指定为 remote 远端控制器,即 Ryu。

sudo mn --controller=remote

可以看到 Ryu 检测到网络的运行了:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gWnCFJYZ-1641200088189)(https://secure1.wostatic.cn/static/kVh7tZBkiaueFTfMt1hjTs/image.png)]

2. 启动 Mininet 可视化界面 MiniEdit

2.2.0以后版本的mininet支持可视化,在 ../mininet/mininet/examples 目录下提供 miniedit.py 脚本,切换到相应目录下,在终端中执行:

sudo python miniedit.py

或者这样也能执行:

wu@wu-ubuntu:~/mininet/mininet/examples$ ./miniedit.py

即打开了 MiniEdit 可视化界面,左边从上到下分别是主机、OpenvSwitch 交换机、传统交换机、传统路由器、链路、控制器。点击后在屏幕上点击可将设备放置到界面中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l9v88XmK-1641200088191)(https://secure1.wostatic.cn/static/tT9GJLzNmo2SNHVvxLysYE/image.png)]

00x2 Mininet 具体应用

1. Mininet 常用命令

MIninet 2.3

以上文档中更详细。

创建网络拓扑常用参数:

-c           # 释放之前创建拓扑时占用的未释放的资源
-h           # 查看帮助
--topo       # 在mininet启动时通过命令行定义拓扑
--custom     # 用于创建自定义拓扑
--switch     # 定义要使用的交换机,默认使用oVSK交换机
--controller # 定义要使用的控制器,如果没有指定则使用mininet中默认的控制器
--mac        # 自动设置设备的MAC地址从而使MAC地址更易读。

—-mac 自动设置设备的MAC地址,MAC地址与IP地址的最后一个字节相同,从而使MAC地址更易读。设置交换机的MAC、主机MAC及IP地址从小到大排列,在拓扑比较复杂的情况,容易识别机器ID。如果不设置,默认下主机随机分配MAC地址,且每次执行mn,,MAC都会改变,有些调试比较困难。

Mininet 内部交互常用命令:

mininet > help       # 获取帮助列表。
mininet > nodes      # 查看网络拓扑中结点的状态
mininet > links      # 显示链路健壮性信息
mininet > net        # 显示网络拓扑
mininet > dump       # 显示每个节点的接口设置和表示每个节点的进程的PID 
mininet > pingall    # 在网络中的所有主机之间执行ping测试
mininet > pingpair   # 只测试前两个主机的连通性
mininet > iperf      # 两个节点之间进行iperftcp带宽测试(iperf h1 n2) 
mininet > iperfudp   # 两节点之间进行iperfudp带宽测试(iperfudp bw h1 h2)
mininet > link       # 禁用或启用节点间链路(link s1 s2 up启用,link s1 s2own禁用s1和s2之间的链路)
mininet > h1 ping h2   # h1和h2节点之间执行ping测试
mininet > h1 ifconfig  # 查看host1的IP等信息。
mininet > xterm h1     # 打开host1的终端。
mininet > exit         # 退出mininet登录。

举例:ip 和 port 可不写,默认本机 ip 和 6633或6653

sudo mn --controller=remote,ip=[控制器IP],port=[监听端口]

2. 命令实操演示

打开某个 Ryu:

ryu-manager simple_switch.py

在 Mininet mininet/examples中执行一个创建好的Python脚本,或者启动Mininet时创建:

sudo mn --controller remote --topo tree,depth=2

pingall 查看连通性:

mininet> pingall
*** Ping: testing ping reachability
h1 -> h2 h3 h4
h2 -> h1 h3 h4
h3 -> h1 h2 h4
h4 -> h1 h2 h3
*** Results: 0% dropped (12/12 received)

net 查看网络拓扑:

mininet> net
h1 h1-eth0:s2-eth1    # h1和s2连接
h2 h2-eth0:s2-eth2
h3 h3-eth0:s3-eth1
h4 h4-eth0:s3-eth2
s1 lo:  s1-eth1:s2-eth3 s1-eth2:s3-eth3     # s1和s2、s3相连通
s2 lo:  s2-eth1:h1-eth0 s2-eth2:h2-eth0 s2-eth3:s1-eth1
s3 lo:  s3-eth1:h3-eth0 s3-eth2:h4-eth0 s3-eth3:s1-eth2
c0

link s2 h1 down 禁用 s2 和 h1 之间的链路。

link s2 h1 up 连接 s2 和 h1 之间的链路。

links 查看健壮性

mininet> links
s1-eth1<->s2-eth3 (OK OK)
s1-eth2<->s3-eth3 (OK OK)
s2-eth1<->h1-eth0 (OK OK)
s2-eth2<->h2-eth0 (OK OK)
s3-eth1<->h3-eth0 (OK OK)
s3-eth2<->h4-eth0 (OK OK)

dump 查看节点接口设置和节点 PID

mininet> dump
<Host h1: h1-eth0:10.0.0.1 pid=41581>
<Host h2: h2-eth0:10.0.0.2 pid=41583>
<Host h3: h3-eth0:10.0.0.3 pid=41585>
<Host h4: h4-eth0:10.0.0.4 pid=41587>
<OVSSwitch s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=41592>
<OVSSwitch s2: lo:127.0.0.1,s2-eth1:None,s2-eth2:None,s2-eth3:None pid=41595>
<OVSSwitch s3: lo:127.0.0.1,s3-eth1:None,s3-eth2:None,s3-eth3:None pid=41598>
<RemoteController c0: 127.0.0.1:6653 pid=41575>

iperf 进行网络带宽测试,例如h1和h2:

mininet> iperf h1 h2
*** Iperf: testing TCP bandwidth between h1 and h2
*** Results: ['65.3 Gbits/sec', '65.5 Gbits/sec']

help 查看帮助,显示所有可以执行的命令。

mininet> help
Documented commands (type help <topic>):
========================================
EOF    gterm  iperfudp  nodes        pingpair      py      switch  xterm
dpctl  help   link      noecho       pingpairfull  quit    time
dump   intfs  links     pingall      ports         sh      wait
exit   iperf  net       pingallfull  px            source  x

exit 退出Mininet。

3. Mininet 创建网络拓扑的常见方式

通过命令行创建
  1. 单一(single)拓扑

    整个网络拓扑中有且只有一个交换机,交换机可下挂一个或多个主机

    举例:sudo mn-topo=single,3表示创建了一台交换机交换机下挂3台主机

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ECGfzFND-1641200088192)(https://secure1.wostatic.cn/static/rzvNiMdZGZ4V27MX3Y4MYN/image.png)]

  2. 线形(linear)拓扑

    交换机连接呈线形排列,且每个交换机所连接主机数目只有一个(交换机与主机数相同)

    举例:sudo mn -- topo=linear,3

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IQfm8G5u-1641200088193)(https://secure1.wostatic.cn/static/dBbNe7W77P6KTx9GiHzD1D/image.png)]

  3. 树形(tree)拓扑

    交换机连接呈树形排列,且每个交换机下挂的主机一般有多个,类似于数据结构的二叉树。其中depth指的是交换机的深度,depth=2表示交换机有两层,fanout表示广度/扇出, fanout=3表示每台交换机均下挂3台设备。

    举例:sudo mn--topo=tree,depth=2,fanout=3

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DmrcmSHA-1641200088193)(https://secure1.wostatic.cn/static/c9185V7zbdyzUcpyupaNxh/image.png)]

  4. 自定义拓扑

    即用 Python 命令创建,后面讲脚本时候再讲。

通过可视化界面 MiniEdit 创建

打开 MiniEdit 可视化界面miniedit.py,自行点击图标搭建网络拓扑,然后进行配置。

左上角 Edit - Preference,网段可根据需要自己设置(之后主机IP需要根据网段配置),钩上 Start CLI 开启命令行修改拓扑,OpenFLow 可勾选 1.0 和 1.3。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FsBpM7tb-1641200088194)(https://secure1.wostatic.cn/static/uupPLDM75sDHqAvZK6Ryqe/image.png)]

然后修改节点配置,控制器上 右键 - Property,控制类型 Controller Type 改为远端控制器 Remote,IP为远程控制器的IP(这里就是本机IP)。交换机上设置一下16位 DPID(如0000000000000001),类型为 OpenvSwith 内核模式。主机设置网段和 IP Base 相同。回到命令行可以看到所有配置在命令行都有反馈。

运行网络拓扑之前先去开启Ryu控制器。

然后回到 MiniEdit,点左下角的 Run,即可在命令行看到启动情况。

回到 MiniEdit 停止运行,左上角 File - Export Level 2 Script 保存为 xxx.py 的Python文件到 example 目录,回到命令行在 example 目录下就能看到保存的文件了。后期修改网络拓扑也可以直接修改这个 Python 文件。

通过 Python 脚本创建

vim打开上一步保存的.py文件,可看到文件构成:

from mininet.net import Mininet
from mininet.node import Controller, RemoteController, OVSController
from mininet.node import CPULimitedHost, Host, Node
from mininet.node import OVSKernelSwitch, UserSwitch
from mininet.node import IVSSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel, info
from mininet.link import TCLink, Intf
from subprocess import call

def myNetwork():

    net = Mininet( topo=None,
                   build=False,
                   ipBase='10.0.0.0/8')

    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, dpid='0000000000000001')
    s2 = net.addSwitch('s2', cls=OVSKernelSwitch, dpid='0000000000000002')

    info( '*** Add hosts\n')
    h1 = net.addHost('h1', cls=Host, ip='10.0.0.1', defaultRoute=None)
    h2 = net.addHost('h2', cls=Host, ip='10.0.0.2', defaultRoute=None)
    h3 = net.addHost('h3', cls=Host, ip='10.0.0.3', defaultRoute=None)
    # h4 = net.addHost('h4', cls=Host, ip='10.0.0.4', defaultRoute=None)

    info( '*** Add links\n')
    net.addLink(s1, s2)
    net.addLink(s1, h1)
    net.addLink(s2, h2)
    net.addLink(s2, h3)
    # net.addLink(s2, h4)

    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])

    info( '*** Post configure switches and hosts\n')
    s1.cmd('ifconfig s1 10.0.0.0/8')
    s2.cmd('ifconfig s2 10.0.0.0/8')

    CLI(net)
    net.stop()

if __name__ == '__main__':
    setLogLevel( 'info' )
    myNetwork()

接下来增加一台主机h4,将h4和s2进行连接,即对应位置增加两行代码(上面注释掉了):

h4 = net.addHost('h4', cls=Host, ip='10.0.0.4', defaultRoute=None)

net.addLink(s2, h4)

00x3 OpenFlow 协议和流表基本操作

1. OpenFlow协议工作原理

h1想和h2通信,先给s1,s1流表中没有inport=2的流表项,就发送packin消息给控制器,控制器收到后下发packout消息给s1,s1根据收到的流表转发数据包给s2,s2流表中也没有匹配项,也需要发packin给控制器,控制器下发packout,s2进行转发给h2.

h2收到消息后想给h1发送数据包,先给s2,s2也没有inport=2的流表项,联系控制器packin-packout,s2再转发给s1,s1已经有了inport=2的流表项,直接转发给h1。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-de61kIsh-1641200088194)(https://secure1.wostatic.cn/static/4kaB3iWH1WGqY1MyrMfKdj/image.png)]

2. OpenFlow 流表常用配置命令

# 查看流表
dpctl dump-flows

# 添加流表(1号端口进,2号端口出的转发流表)
dpctl add-flow in_port=1,actions=output:2

# 添加丢弃数据包流表(2号端口进,丢弃数据包)
dpctl add-flow in_port=2,actions=drop

# 删除所有交换机的所有流表
dpctl del-flows

# 删除所有交换机的特定流表项(输出2号端口进的流表项)
dpctl del-flows in_port=2 

# 删除某个交换机的流表(删除s1中从2号端口进的流表项)
sh ovs-ofctl del-flows s1 in_port=2

3. 命令实操

打开ryu控制器和mininet,以simple_switch.py和之前自建的1222.py为例。

available nodes are:
c0 h1 h2 h3 h4 s1 s2
mininet> links            # 后面的-eth?就是端口号
s1-eth1<->s2-eth1 (OK OK)
s1-eth2<->h1-eth0 (OK OK)
s2-eth2<->h2-eth0 (OK OK)
s2-eth3<->h3-eth0 (OK OK)
s2-eth4<->h4-eth0 (OK OK)

拓扑图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M2PiGk2d-1641200088195)(https://secure1.wostatic.cn/static/muyk9gEzTp5v3FPUQbbryT/image.png)]

输入dpctl dump-flows查看流表项:

mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
*** s2 ------------------------------------------------------------------------

可见s1和s2中都还没有流表项。

执行一下pingall后再查看流表项,就能看到s1和s2都生成了很多流表项,以s1部分流表项为例:

*** s1 ------------------------------------------------------------------------
 cookie=0x0, duration=50.671s, table=0, n_packets=3, n_bytes=238, in_port="s1-eth1",dl_src=c6:bf:4f:c2:93:4d,dl_dst=be:d8:db:39:8d:0e actions=output:"s1-eth2"
 cookie=0x0, duration=50.669s, table=0, n_packets=2, n_bytes=140, in_port="s1-eth2",dl_src=be:d8:db:39:8d:0e,dl_dst=c6:bf:4f:c2:93:4d actions=output:"s1-eth1"

第一条流表中,in_port="s1-eth1"表示从s1的1号端口进,actions=output:"s1-eth2"表示从s1的2号端口出的转发动作,dl_srcdl_dst分别为原MAC地址和目的MAC地址。

执行dpctl del-flows即可删除所有流表。


执行手动添加流表dpctl add-flow in_port=1,actions=output:2

dpctl dump-flows查询流表可以看到s1和s2都生成了1号端口进2号端口出的流表:

mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
 cookie=0x0, duration=5.018s, table=0, n_packets=0, n_bytes=0, in_port="s1-eth1" actions=output:"s1-eth2"
*** s2 ------------------------------------------------------------------------
 cookie=0x0, duration=5.018s, table=0, n_packets=0, n_bytes=0, in_port="s2-eth1" actions=output:"s2-eth2"

再添加一条从2号端口进1号端口出的流表:dpctl add-flow in_port=2,actions=output:1

执行h1 ping h2,即可ping通,ctrl+c退出ping。

再执行h1 ping h3,无法ping通,原因是没有s2的3号端口转发的流表。s2根据流表只能1号端口进转发给2号端口出,3号端口连接的h3无法收到数据包。


删除交换机s1中从2号端口进的所有流表sh ovs-ofctl del-flows s1 in_port=2,再查看流表可以看到被删除。

删除所有交换机中输入端口为1的流表项dpctl del-flows in_port=1

删除所有交换机中输入端口为2的流表项dpctl del-flows in_port=2

再查看流表可见s1和s2中都没有流表项。


添加丢弃从2号端口进的数据包的流表项:dpctl add-flow in_port=2,actions=drop

再执行pingall,发现只有h3和h4之间是互通的。原因是2号端口进的数据包都匹配到流表项需要丢弃,h3从3号端口进的和h4从4号端口进的没有流表项匹配,就向控制器申请下发流表。

mininet> pingall
*** Ping: testing ping reachability
h1 -> X X X
h2 -> X X X
h3 -> X X h4
h4 -> X X h3
*** Results: 83% dropped (2/12 received)

dpctl dump-flows查询流表可以看到s2中新增了关于3号4号端口的流表项。

如果这里把2号3号端口进的都丢弃,那么虽然4号进的会下发流表发出数据包,但是2号3号端口不会回应,所以pingall都不能通。


删除所有流表后pingall,即让控制器下发所有端口的流表项。然后再手动添加丢弃2号和3号端口的流表项,再执行pingall,会发现所有通信仍是正常的。

原因是此时手动添加的流表项和控制器下发的流表项共存,而控制器下发的流表项优先级更高,所以会执行控制器下发的流表项。

  • 20
    点赞
  • 266
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值