Mininet 学习

来自https://www.51openlab.com/college/ 的教程,以下是学习总结

Mininet 简介

Mininet 基于Linux Container这一个内核虚拟化技术开发,利用linux的network namespace机制在一台电脑上创建多台虚拟主机,此外,Mininet建立的网络拓扑的交换节点可以是Open vSwitch、Linux Bridge等软件交换机,交换节点之间的链路采用Linux的veth pair (virtual Ethernet pair)机制实现,控制器可以部署在网络可达的任意地方。因此,Mininet可以定制任意灵活的SDN网络拓扑,为实验用户提供快捷可靠的实验环境。

Mininet架构按datapath的运行权限不同,分为kernel datapath和userspace datapath两种,其中kernel datapath把分组转发的逻辑编译进入Linux内核,效率非常高; userspace datapath把分组转发逻辑实现为一个应用程序,叫做ofdatapath,效率虽不及kernel datapath,但更为灵活,更容易重新编译。

Mininet的kernel datapath架构如下图所示,控制器和交换机的网络接口都在root 命名空间中,每个主机都在自己独立的命名空间里,这也就表明每个主机在自己的命名空间中都会有自己独立的虚拟网卡eth0。控制器就是一个用户进程,它会在loopback上预留的6633端口监听来自交换机安全信道的连接。每个交换机对应几个网络接口,比如sO-eth0、sO-eth1以及一个ofprotocol进程,它负责管理和维护同一控制器之间的安全信道。

image-20210903160253663
image-20210903160253663

Mininet的userspace datapath架构如下图所示,与kernel datapath架构不同,网络的每个节点都拥有自己独立的namespace。因为分组转发逻辑是实现在用户空间,所以多出了一个进程叫ofdatapath。另外,Mininet除了支持kernel datapath和userspace datapath这两种架构以外,还支持OVS交换机。OVS充分利用内核的高效处理能力,它的性能和kernel datapath相差无几

Mininet 安装

  1. 下载github源码然后编译安装,

    1
    2
    sudo apt-get update
    git clone http://github.com/mininet/mininet.git

    其中./install.sh是安装的命令,格式如下:

    1
    ./install.sh [options]

    options如下

  • -a : 完整安装,默认在home目录下,包括 Mininet VM,以及Open vSwich的依赖关系,OpenFlow, Wireshark分离器以及POX
    • -nfv 安装mininet核心文件及其依赖,OpenFlow 和 Open vSwitch
    • -s mydir: 可以把源代码建立到一个特定的目录中
  1. 查看mininet版本

    1
    2
    cd mininet
    cat INSTALL|more
  2. 安装

    1
    2
    cd util
    ./install.sh -a
  3. 测试基本功能

    1
    mn --test pingall

    image-20210903162108693

  4. 查看安装好的mininet版本:

    1
    mn --version

Mininet 拓扑构建与命令使用

  1. MiniEdit:

    这个可以可视化的在界面编辑任意拓扑,然后生成python自定义拓扑脚本,Mininetnet2.20+内置,在mininet/examples里面提供mininetedit.py脚本;

  2. Mininet参数

    topo: 用于指定网络拓扑,Mininet支持minimal,singel,linear 和tree 三种

    • minimal: 创建一个交换机和两个主机相连的简单拓扑。默认无—topo参数的情况下就是这样。其内部实现就是调用了single,2对应的函数。
    • single,n:设置一个交换机和n个主机相连的拓扑。
    • linear,n:创建n个交换机,每个交换机只连接一个主机,并且所有交换机成线型排列。
    • tree,depth=n,fanout=m:创建深度为n,每层树枝为m的树型拓扑。因此形成的拓扑的交换机个数为(mn-1) /(m-1),主机个数为mn。
    • —custom:在上述已有拓扑的基础上,Mininet支持自定义的拓扑,使用一个简单的Python API即可。—custom需和—topo一起使用,如mn —custom file.py —topo mytopo。
  3. 内部交互命令:

    | 参数 | 作用 |
    | ————————————————— | —— |
    | -h | show this help message and exit |
    | —switch=SWITCH | [kernel user ovsk] |
    | —host=HOST | [process] |
    | —controller=CONTROLLER | [nox_dump none ref remote nox_pysw] |
    | —topo=TOPO | [tree reversed single linear minimal],arg1,arg2,…argN |
    | -c,—clean | clean and exit |
    | —custom=CUSTOM | read custom topo and node params from .py file |
    | —test=TEST | [cli build pingall pingpair iperf all iperfudp none] |
    | -x,—xterms | spawn xterms for each node |
    | —mac | set MACs equal to DPIDs |
    | —arp | set all-pairs ARP entries |
    | -v VEIBOSITY,—verbosity=VEIBOSITY | [info warning critical error debug output] |
    | —ip=IP | [ip address as a dotted decimal string for aremote controller] |
    | —port=PORT | [port integer for a listening remote controller] |
    | —innamespace | sw and ctrl in namespace |
    | —listenport=LISTENPORT | [base port for passive switch listening controller] |
    | —nolistenport | don’t use passive listening port |
    | —pre=PRE | [CLI script to run before tests] |
    | —post=POST | [CLI script to run after tests] |

  4. Mininet常用命令总结:

    |命令|作用|
    |——|——|
    |help|默认列出所有命令文档,后面加命令名将介绍该命令用法 dump打印节点信息|
    |gterm|给定节点上开启gnome-terminal 注:可能导致mn崩溃|
    |xterm|给定节点上开启xterm|
    |intfs|列出所有的网络接口|
    |iperf|两个节点之间进行简单的iPerf TCP测试|
    |iperfudp|两个节点之间用制定带宽UDP进行测试|
    |net|显示网络链接情况|
    |noecho|运行交互式窗口,关闭回应(echoing)|
    |pingpair|在前两个主机之间互Ping测试|
    |source|从外部文件中读入命令|
    |dpctl|在所有交换机上用dptcl执行相关命令,本地为tcp 127.0.0.1:6634|
    |link|禁用或启用两个节点之间的链路|
    |nodes|列出所有的节点信息|
    |pingall|所有主机节点之间互Ping|
    |py|执行Python表达式|
    |sh|运行外部shell命令|
    |quit/exit|退出|

实际构建拓扑

  1. 构建single拓扑:

    1
    sudo mn --topo=single,3

    image-20210903174617790

    exit退出

    single拓扑中整个网络拓扑中交换机有且仅有一个,交换机下面可以挂一个或者多个主机;本例会创建一个交换机,3个主机,3个主机挂在一个交换机下面

  2. 构建linear拓扑

    1
    sudo mn --topo=linear,3

    image-20210903174730214

    线性拓扑中交换机连接呈线性排列,每一个交换机连接的主机数目只有一个,本例创建了3个交换机,3个主机,3个主机挂在各自交换机下面并且交换机之间互相连接

  3. 构建tree拓扑

    1
    sudo mn --topo=tree,depth=2,fanout=2

    image-20210903175036157

    创建了一个数,s1为根,下面是s2,s3,然后s2,s3各自挂两个主机;depth表示交换机深度,fanout表示每一层的节点数量;

  4. 创建自定义拓扑

    1
    2
    cd /home/openlab/openlab/mininet/custom
    sudo mn --custom topo-2sw-2host.py --topo mytopo

    image-20210903175436545

    python 脚本如下:

    image-20210903175538940

内部交互命令

  1. 使用net显示连接信息
  2. 使用nodes查看节点信息
  3. 使用links查看连路鲁棒性信息
  4. 使用pingall验证所有主机间通信查看结果
  5. 使用xterm h1 h2进入设备可视化操作界面
  6. exit退出
  7. mn -c 清楚释放Mininet构建配置的交换机及主机

可视化构建

  1. 使用MiniEdit

    在mininet/examples下执行miniedit.py

    1
    sudo ./miniedit.py
  2. 如下图,可以选择的助教有:主机,OpenFlow交换机,传统交换机,传统路由器,链路,控制器:

    image-20210903180059575

  3. Miniedit属性配置

    在左侧设备列表中选中需要的设备,在右侧空白区域单击,设备即添加成功。设备及链路上可进行鼠标右击长按,选择Properties即可对其进行配置。在控制器上进行鼠标右击长按,选择Properties即可对控制器进行配置:

    image-20210903180311795

    然后修改了交换机,选择Porperties,配置了16位的DPID:

    image-20210903180550232

    然后修改了主机的IP地址:

    image-20210903180606359

    修改的同时miniedit.py会在窗口中显示修改的设备属性

    image-20210903180633749
    image-20210903180633749

  4. 全局配置

    Miniedit左上角Edit可以剪切删除设备,对整个网络进行全局配置

    image-20210903180728737

  5. 点击左下角run即可运行设置好的网络拓扑

    image-20210903180824459

    然后此时对交换机主机右击常看可以查看交换机的bridge信息以及打开host终端

  6. Minideit保存脚本

    File—Export Level 2 Scirpt可以保存为python脚本,默认在mininet/examples下面,用 chomod给权限之后直接运行可以直接重现

    比如

    1
    2
    chmod -R 777 temp.py
    sudo ./temp.py

Mininet 调用API扩展自定义拓扑

  1. Mininet作为一个基于Python的网络仿真工具,可以分为两大部分:Python库和运行文件。前者对网络中元素进行抽象和实现,例如定义主机类来表示网络中的一台主机;后者则基于这些库完成模拟过程。
    topo 类中包含构建网络的函数如:
    • addHost(“host name”): 添加主机
    • addSwitch(“sw name”): 添加交换机
    • addLink(node,node): 添加链路
    • attach(port):添加端口
  1. 首先使用自定义拓扑:

    1
    sudo mn --custom topo-2sw-2host.py --topo mytopo
  2. 添加主机h3

    1
    py net.addHost(‘h3’)
  3. 添加s3与主机h3之间的链路

    1
    py net.addLink(s3,net.get(‘h3’))
  4. 在Mininet交互环境中添加端口

    1
    py s3.attach(‘s3-eth3’)
  5. 在Mininet交互环境中对主机进行配置IP地址

    1
    py net.get(‘h3’).cmd(‘ifconfig h3-eth0 10.3’)
  6. 查看节点信息

    1
    2
    dump
    nodes

    image-20210903221343833

  7. 验证连通性

    1
    2
    h1 ping h3
    pingall

Mininet 流表应用实战1——手动添加流表

  1. 自定义拓扑脚本文件exper1.py,脚本代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #!/usr/bin/python
    from mininet.topo import Topo
    from mininet.net import Mininet
    from mininet.node import RemoteController
    from mininet.link import TCLink
    from mininet.util import dumpNodeConnections
    class MyTopo( Topo ):
    "Simple topology example."
    def __init__( self ):
    "Create custom topo."
    # Initialize topology
    Topo.__init__( self )
    # Add hosts and switches
    Host1 = self.addHost(h1)
    Host2 = self.addHost(h2)
    Host3 = self.addHost(h3)
    Switch1 = self.addSwitch(s1)
    Switch2 = self.addSwitch(s2)
    # Add links
    self.addLink( Host1, Switch1 )
    self.addLink( Host2, Switch1 )
    self.addLink( Host3, Switch2 )
    self.addLink( Switch1, Switch2 )
    topos = {mytopo: ( lambda: MyTopo() ) }
  2. 运行脚本并且远程指定一个不存在的控制器,使交换机不受控制器控制;

    1
    sudo mn --custom exper1.py --topo mytopo --controller=remote,ip=127.0.0.1,port=6653

    image-20210906210457031

  3. 使用如下命令打开可视化终端:

    1
    xterm h1 h2 h3

    image-20210906210631094

  4. 使用如下命令dpctl dump-flows查看交换机当前的flow table信息。

    image-20210906211022175

    可以看到交换机s1 s2中没有流表

  5. h2中使用tcp dump -n -i h2-eth0抓取网卡h2-eth0上的数据包

    h3中使用tcp dump -n -i h3-eth0抓取网卡h2-eth0上的数据包

  6. 在主机h1中执行如下命令分别ping主机h2和h3

    1
    2
    # ping -c 3 10.0.0.2
    # ping -c 3 10.0.0.3
  7. 在主机h2和h3上查看tcpdump抓包结果。

    image-20210907023743542

    发现主机h1ping h2和h3都失败了,主机h2和h3么有收到任何ICMP ecjp reqiest packet。原理解析:ping操作时,由于拓扑里没有SDN控制器,也没有用dptcl给OpenFlow交换机添加任何flow entry,所以交换机不会做转发决定,并直接丢弃h1到h2及h1到h3的ping包。

  8. 添加流表

    执行如下命令添加交换机端口流表使主机h1和h2通信。

    1
    2
    mininet> dpctl add-flow in_port=1,actions=output:2
    mininet> dpctl add-flow in_port=2,actions=output:1

    然后使用dpctl dump-flows查看流表,发现添加成功:

    image-20210907025832428

  9. 再次 ping,发现h2可以ping通,h3不可以:

    image-20210907025905095

    原理解析:用dpctl对交换机添加flow,让交换机从s1-eth1这个端口接收到的所有traffic都从s1-eth2这个端口发出去。用dpctl给交换机添加双向流表,因为ping包除了echo request还有echo reply。所以还需要用dpctl对交换机添加flow,让交换机从s1-eth2这个端口接收到的所有traffic都从s1-eth1这个端口发出去。添加这两条flow后,h1能够ping通h2,但是并没有为h1和h3之间添加对应的端口流表,所以h1与h3不通。

  10. 添加协议流表使h1/h2通信:

    执行如下命令删除之前通过端口添加的流表并且查看,确保交换机流表为空:

    1
    2
    dpctl del-flows
    dpctl dump-flows
  11. 执行如下命令添加两条traffic类型为IPV4协议相关的flow entry并且查看下发的流表:

    1
    2
    3
    dpctl add-flow dl_type=0x0800,nw_dst=10.0.0.2,actions=output:2
    dpctl add-flow dl_type=0x0800,nw_dst=10.0.0.1,actions=output:1
    dpctl dump-flows
  12. 执行命令ping h2 和h3:

       ![image-20210907030326211](/picture/image-20210907030326211.png)
    

​ 可以看到无法ping通

  1. 在主机h2,h3上面查看:

    image-20210907030627886

    原理解析:用dpctl对交换机添加flow,让交换机把所有EtherType为0x0800(IPv4)并且destiation IP为10.0.0.2的traffic从s1-eth2这个端口发出去。用dpctl对交换机添加flow,让交换机把所有EtherType为0x0800(IPv4)并且destiation IP为10.0.0.1的traffic从s1-eth1这个端口发出去。但处在同一网段下的主机,它们之间的交流是L2 forwarding,需要靠ARP来解析MAC地址,之前只匹配了0x0800(IPv4)协议,并没有匹配到0x0806(ARP),这样当交换机收到h1的ARP包后,因为没有控制器,flow table里面也没有相应的flow告诉它如何转发这个ARP包,交换机只能将它丢弃,从而导致h1 ping h2失败,所以需要添加ARP协议的流表来使通信。

  2. 执行命令dpctl add-flow dl_type=0x0806,actions=NORMAL添加ARP(0x0806)协议相关的流表,让交换机以NORMAL形式(广播)将所有ARP包从各个端口广播出去:

  3. 执行dpctl dump-flows查看:

    image-20210907030845798

    然后ping h2和h3 发现可以ping通h2:

    image-20210907030928420

    image-20210907030936961

Mininet流表应用实战——控制器下发流表协议分析

  1. 实验原理:在SDN环境下,当交换机收到一个数据包并且交换机中没有与改数据包匹配的流表项的时候,交换机将此数据包发给控制器,由控制器决策数据包如何处理,控制器下发决策后,交换机根据控制器下发的信息来进行数据包的处理,即转发或者丢弃这个数据包。
  2. 这个实验做了一下,基本就是控制器,主机两个,主机上进行抓包然后分析协议

Mininet 多数据中心网络拓扑流量带宽实验

  1. 使用mininet中的iperf工具在网络中生成UDP流量,iperf客户端传送数据流到iperf的服务端,由服务端接收并记录相关信息。网络性能评估中一个巨大的挑战就是如何生成真实的网络流量,可以通过程序来创造人工的网络流量,通过建立测试环境来模拟真实的状况。此应用主要以数据中心网络为目标场景,在mininet仿真环境中尽可能地还原数据中心内部的真实流量情况。
  2. Mininet数据中心应用价值:

    • 树状拓扑结构容错能力强
    • 降低数据中心成本消耗
    • 提供重新排列的全带宽无阻碍路径
    • 提高带宽利用率
    • 分析数据中心网络流量性能
    • 为真实数据中心和仿真测试床提供有用信息
  3. 在mininet中进行自定义命令iperfmulti功能拓展主要分为4步:
    1.修改mininet/net.py
    2.修改mininet/cli.py
    3.修改bin/mn
    4.重新安装Mininet核心文件:~/mininet/util/install.sh -n

  4. 实验拓扑:

    image-20210907215209183

  5. 实验设备:

    image-20210907221043663

编写网络带宽测试程序

  1. 在mininet/net.py中的”def iperf”下面添加定义iperf_single()函数实现两个主机间的iperf udp 测试,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
        
    def iperf_single( self,hosts=None, udpBw='10M', period=60, port=5001):
    """Run iperf between two hosts using UDP.
    hosts: list of hosts; if None, uses opposite hosts
    returns: results two-element array of server and client speeds"""
    if not hosts:
    return
    else:
    assert len( hosts ) == 2
    client, server = hosts
    filename = client.name[1:] + '.out'
    output( '*** Iperf: testing bandwidth between ' )
    output( "%s and %s\n" % ( client.name, server.name ) )
    iperfArgs = 'iperf -u '
    bwArgs = '-b ' + udpBw + ' '
    print "***start server***"
    server.cmd( iperfArgs + '-s -i 1' + ' > /home/sdnlab/log/' + filename + '&')
    print "***start client***"
    client.cmd(
    iperfArgs + '-t '+ str(period) + ' -c ' + server.IP() + ' ' + bwArgs
    +' > /home/sdnlab/log/' + 'client' + filename +'&')

    image-20210907220635571

  2. 在Mininet类中添加自定义命令iperfmulti()函数,这个函数的作用使实现为每一台主机随机选择另一台主机作为iperf的服务器段,通过调用iperf_single,自身以客户端的身份按照指令参数发送UDP流,服务器生成的报告以重定向的方式输出到文件中。使用iperfmulti命令,主机随机地向另一台主机发起一个恒定带宽的UDP数据流。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    def iperfMulti(self, bw, period=60):
    base_port = 5001
    server_list = []
    client_list = [h for h in self.hosts]
    host_list = []
    host_list = [h for h in self.hosts]

    cli_outs = []
    ser_outs = []

    _len = len(host_list)
    for i in xrange(0, _len):
    client = host_list[i]
    server = client
    while( server == client ):
    server = random.choice(host_list)
    server_list.append(server)
    self.iperf_single(hosts = [client, server], udpBw=bw, period= period, port=base_port)
    sleep(.05)
    base_port += 1

    sleep(period)
    print "test has done"

    image-20210907220651767

  3. 打开/mininet/cli.py文件,加入如下代码,注册iperfmulti命令:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def do_iperfmulti( self, line ):
    """Multi iperf UDP test between nodes"""
    args = line.split()
    if len(args) == 1:
    udpBw = args[ 0 ]
    self.mn.iperfMulti(udpBw)
    elif len(args) == 2:
    udpBw = args[ 0 ]
    period = args[ 1 ]
    err = False
    self.mn.iperfMulti(udpBw, float(period))
    else:
    error('invalid number of args: iperfmulti udpBw period\n' +'udpBw examples: 1M 120\n')

    image-20210907220705100

  4. 使用sudo vim mininet/bin/mn,加入iperfmulti可执行命令:

    image-20210907220743581

  5. 执行如下命令重新编译Mininet:

    1
    2
    cd openlab/mininet/util
    ./install.sh -n
  6. 使用sudo mn 创建一个topo查看是否存在iperfmulti命令,作为验证:

    image-20210907220846860

构建多数据中心拓扑

  1. 在/mininet/custom中创建fattree.py,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    #!/usr/bin/python
    """Custom topology example
    Adding the 'topos' dict with a key/value pair to generate our newly defined
    topology enables one to pass in '--topo=mytopo' from the command line.
    """
    from mininet.topo import Topo
    from mininet.net import Mininet
    from mininet.node import RemoteController,CPULimitedHost
    from mininet.link import TCLink
    from mininet.util import dumpNodeConnections

    class MyTopo( Topo ):
    "Simple topology example."

    def __init__( self ):
    "Create custom topo."

    # Initialize topology
    Topo.__init__( self )
    L1 = 2
    L2 = L1 * 2
    L3 = L2
    c = []
    a = []
    e = []

    # add core ovs
    for i in range( L1 ):
    sw = self.addSwitch( 'c{}'.format( i + 1 ) )
    c.append( sw )

    # add aggregation ovs
    for i in range( L2 ):
    sw = self.addSwitch( 'a{}'.format( L1 + i + 1 ) )
    a.append( sw )

    # add edge ovs
    for i in range( L3 ):
    sw = self.addSwitch( 'e{}'.format( L1 + L2 + i + 1 ) )
    e.append( sw )

    # add links between core and aggregation ovs
    for i in range( L1 ):
    sw1 = c[i]
    for sw2 in a[i/2::L1/2]:
    # self.addLink(sw2, sw1, bw=10, delay='5ms', loss=10, max_queue_size=1000, use_htb=True)
    self.addLink( sw2, sw1 )

    # add links between aggregation and edge ovs
    for i in range( 0, L2, 2 ):
    for sw1 in a[i:i+2]:
    for sw2 in e[i:i+2]:
    self.addLink( sw2, sw1 )

    #add hosts and its links with edge ovs
    count = 1
    for sw1 in e:
    for i in range(2):
    host = self.addHost( 'h{}'.format( count ) )
    self.addLink( sw1, host )
    count += 1
    topos = { 'mytopo': ( lambda: MyTopo() ) }

    Mininet创建网络拓扑的代码中,可以通过改变代码中定义的L1变量来设置核心交换机的数量,并通过添加额外的交换机和链路来构成更复杂的数据中心网络拓扑。随着边缘交换机的增加,主机个数也随之增长,利用Mininet的易用性和扩展性,可以创建基于多种数据中心场景下的网络拓扑,达到更好更全面的实验效果。

  2. 在控制器主机上面用ifconfig看主机的ip:

    image-20210907221233085

  3. 在host,也就是mininet所在的主机上面使用如下命令生成测试拓扑结构:

    1
    sudo mn --custom fattree.py --topo mytopo --controller=remote,ip=30.0.1.69,port=6653

    这里ip以上面查出来的为准;

    pingall验证连通性

  4. 控制器上通过OPENDAYLIGHT,在浏览器:http://30.0.1.69:8181/index.html中可以看到ODL控制器。查看拓扑如下:

    image-20210907221616586

  5. 在mininet主机上面可以iperf h1 h2测主机间带宽

  6. 使用iperfmulti 0.025M可以看到8太主机随机向另外的主机发数据包,然后数据记录在/home/sdnlab/log里面。

    image-20210907221750866

这个实验可以用来借鉴测试速度之类的实验