mininet简介(一:官网翻译)

什么是Mininet?

Mininet是一个网络仿真器,或者更准确地说是一个网络仿真编排系统。它在单个Linux内核上运行一组终端主机,交换机,路由器和链接。它使用轻量级虚拟化使单个系统看起来像一个完整的网络,运行相同的内核,系统和用户代码。 Mininet主机的行为就像真机一样;你可以ssh到它(如果你启动sshd并将网络桥接到你的主机)并运行任意程序(包括安装在底层Linux系统上的任何东西。)你运行的程序可以通过看似真正的以太网发送数据包接口,具有给定的链接速度和延迟。数据包通过具有给定数量的排队的真实以太网交换机,路由器或中间盒进行处理。当两个程序(如iperf客户端和服务器)通过Mininet进行通信时,测量的性能应该与两个(较慢的)本机的性能相匹配。
简而言之,Mininet的虚拟主机,交换机,链接和控制器是真实的 - 它们只是使用软件而不是硬件创建的 - 并且大多数情况下它们的行为类似于分立的硬件元素。通常可以创建类似于硬件网络的Mininet网络,或类似于Mininet网络的硬件网络,并在任一平台上运行相同的二进制代码和应用程​​序。

为什么Mininet很酷?

它很 - 启动一个简单的网络只需几秒钟。这意味着您的run-edit-debug循环可以非常快。
您可以创建自定义拓扑:单个交换机,更大的类Internet拓扑,斯坦福主干网,数据中心或其他任何东西。
您可以运行真正的程序:在Linux上运行的任何东西都可以运行,从Web服务器到TCP窗口监视工具再到Wireshark。
您可以自定义数据包转发:Mininet的交换机可以使用OpenFlow协议进行编程。在Mininet中运行的定制软件定义网络设计可以轻松转移到硬件OpenFlow交换机,以进行线速数据包转发。
您可以在笔记本电脑,服务器,虚拟机,本机Linux机器上运行Mininet(Mininet包含在Ubuntu 12.10+!中),或者运行在云端(例如Amazon EC2。)
您可以共享和复制结果:拥有计算机的任何人都可以在打包后运行您的代码。
您可以轻松使用它:您可以通过编写简单(或必要时复杂的)Python脚本来创建和运行Mininet实验。
Mininet是一个开源项目,因此我们鼓励您在https://github.com/mininet上检查其源代码,修改它,修复错误,文件问题/功能请求以及提交补丁/拉取请求。您还可以编辑此文档以修复任何错误或添加说明或其他信息。
Mininet正在积极开发中。所以,如果它很糟糕,没有意义,或者由于某种原因不起作用,请告知我们mininet-discuss和Mininet用户和开发人员社区可以尝试解释,修复它或帮助您修复它。 :-)如果您发现错误,建议您提交补丁以修复它们,或者至少在github上提交问题,包括可重现的测试用例。

Mininet的局限是什么?

虽然我们认为Mininet很棒,但它确实有一些局限性。例如,
在单个系统上运行很方便,但它会产生资源限制:如果您的服务器具有3 GHz的CPU并且可以切换大约10 Gbps的模拟流量,则需要在虚拟主机和交换机之间平衡和共享这些资源。
Mininet为所有虚拟主机使用单个Linux内核;这意味着您无法运行依赖于BSD,Windows或其他操作系统内核的软件。 (虽然您可以将VM附加到Mininet。)
Mininet不会为您编写OpenFlow控制器;如果您需要自定义路由或切换行为,则需要查找或开发具有所需功能的控制器。
默认情况下,您的Mininet网络与您的LAN和互联网隔离 - 这通常是一件好事!但是,您可以使用NAT对象和/或--nat选项通过网络地址转换将Mininet网络连接到LAN。您还可以将实际(或虚拟)硬件接口连接到Mininet网络(有关详细信息,请参阅examples/ hwintf.py.)
默认情况下,所有Mininet主机共享主机文件系统和PID空间;这意味着如果您正在运行需要在/ etc中进行配置的守护进程,您可能必须要小心,并且您需要注意不要错误地杀死错误的进程。 (注意bind.py示例演示了如何拥有每个主机的私有目录。)
与模拟器不同,Mininet没有强大的虚拟时间概念;这意味着定时测量将基于实时,并且不能容易地模拟比实时更快的结果(例如100Gbps网络)。
暂且不谈性能:对于网络限制性实验,您必须记住的主要事项是,您可能需要使用较慢的链接,例如10或100 Mb / sec而不是10 Gb / sec,因为数据包由一组软件交换机(例如Open vSwitch)转发,这些交换机共享CPU和内存资源,并且通常具有比专用交换硬件更低的性能。对于CPU限制性实验,您还需要确保小心限制Mininet主机的CPU带宽。如果您主要关心功能正确性,则可以在没有特定带宽限制的情况下运行Mininet - 这是运行Mininet的快速简便方法,它还以负载下的计时准确性为代价提供最高性能。
除了少数例外,您可能遇到的许多限制对于Mininet来说并不是固有的;消除它们可能只是代码问题,我们鼓励您贡献您可能开发的任何增强功能!

与Mininet合作

以下部分描述了您可能会觉得有用的Mininet(及其Python API)的几个功能。

创建拓扑

Mininet支持参数​​化拓扑。使用几行Python代码,您可以创建一个灵活的拓扑,可以根据您传入的参数进行配置,并重复用于多个实验。
例如,这是一个简单的网络拓扑(基于mininet / topo.py:SingleSwitchTopo),它由连接到单个交换机(s1)的指定数量的主机(h1hN)组成:
请注意,这是Mininet 2.2中引入的推荐(简化)拓扑语法:

#!/usr/bin/python                                                                            
                                                                                             
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel

class SingleSwitchTopo(Topo):
    "Single switch connected to n hosts."
    def build(self, n=2):
        switch = self.addSwitch('s1')
        # Python's range(N) generates 0..N-1
        for h in range(n):
            host = self.addHost('h%s' % (h + 1))
            self.addLink(host, switch)

def simpleTest():
    "Create and test a simple network"
    topo = SingleSwitchTopo(n=4)
    net = Mininet(topo)
    net.start()
    print "Dumping host connections"
    dumpNodeConnections(net.hosts)
    print "Testing network connectivity"
    net.pingAll()
    net.stop()

if __name__ == '__main__':
    # Tell mininet to print useful information
    setLogLevel('info')
    simpleTest()

上述代码中的重要类,方法,函数和变量包括:
Topo:Mininet拓扑的基类
build():在拓扑类中重写的方法。 构造函数参数(n)将由Topo .__ init __()自动传递给它。
addSwitch():将交换机添加到拓扑并返回交换机名称
addHost():将主机添加到拓扑并返回主机名
addLink():向拓扑添加双向链接(并返回链接密钥,但这并不重要)。 Mininet中的链接是双向的,除非另有说明。
Mininet:创建和管理网络的主要类
start():启动你的网络
pingAll():尝试让所有节点互相ping通来测试连接性
stop():停止你的网络
net.hosts:网络中的所有主机
dumpNodeConnections():转储与一组节点的连接。
setLogLevel('info'|'debug'|'output'):设置Mininet的默认输出级别; 建议使用’info’,因为它提供了有用的信息。
可以在mininet /examples中找到附加示例代码。

早期Mininet版本的注意事项不同版本的Mininet中的拓扑API略有变化。

在1.0中,addSwitchaddHost等方法称为add_switchadd_host。 另外,在1.0和2.0中,覆盖的首选方法是__init__而不是build

class SingleSwitchTopo(Topo):

"Single switch connected to n hosts."

def __init__(self, n=2, **opts):

    # Initialize topology and default options

    Topo.__init__(self, **opts)

    switch = self.addSwitch('s1')

    # Python's range(N) generates 0..N-1

    for h in range(n):

        host = self.addHost('h%s' % (h + 1))

        self.addLink(host, switch)

脚本输出

运行此脚本应该会产生如下内容:

$ sudo python simpletest.py

*** Creating network

*** Adding controller

*** Adding hosts:

h1 h2 h3 h4 

*** Adding switches:

s1 

*** Adding links:

(h1, s1) (h2, s1) (h3, s1) (h4, s1) 

*** Configuring hosts

h1 h2 h3 h4 

*** Starting controller

c0 

*** Starting 1 switches

s1 ...

Dumping host connections

h1 h1-eth0:s1-eth1

h2 h2-eth0:s1-eth2

h3 h3-eth0:s1-eth3

h4 h4-eth0:s1-eth4

Testing network connectivity

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

*** Stopping 1 controllers

c0 

*** Stopping 4 links

....

*** Stopping 1 switches

s1 

*** Stopping 4 hosts

h1 h2 h3 h4 

*** Done

设置性能参数

除了基本的行为网络,Mininet还通过CPULimitedHostTCLink类提供性能限制和隔离功能。

有多种方法可以使用这些类,但一种简单的方法是将它们指定为默认主机,并将类/构造函数链接到Mininet(),然后在拓扑中指定适当的参数。 (您还可以在拓扑本身中指定自定义类,或者创建自定义节点和链接构造函数和/或子类。)

#!/usr/bin/python



from mininet.topo import Topo

from mininet.net import Mininet

from mininet.node import CPULimitedHost

from mininet.link import TCLink

from mininet.util import dumpNodeConnections

from mininet.log import setLogLevel



class SingleSwitchTopo( Topo ):
    "Single switch connected to n hosts."
    def build( self, n=2 ):
    	switch = self.addSwitch( 's1' )
    	for h in range(n):
           # Each host gets 50%/n of system CPU
           host = self.addHost( 'h%s' % (h + 1), cpu=.5/n )
           # 10 Mbps, 5ms delay, 2% loss, 1000 packet queue
           self.addLink( host, switch, bw=10, delay='5ms', loss=2,max_queue_size=1000, use_htb=True )



def perfTest():

    "Create network and run simple performance test"

    topo = SingleSwitchTopo( n=4 )

    net = Mininet( topo=topo, host=CPULimitedHost, link=TCLink )

    net.start()

    print "Dumping host connections"

    dumpNodeConnections( net.hosts )

    print "Testing network connectivity"

    net.pingAll()

    print "Testing bandwidth between h1 and h4"

    h1, h4 = net.get( 'h1', 'h4' )

    net.iperf( (h1, h4) )

    net.stop()



if __name__ == '__main__':

    setLogLevel( 'info' )

    perfTest()

重要的方法和参数:

self.addHost(name,cpu = f):

这允许您指定将分配给虚拟主机的整个系统CPU资源的一小部分。

self.addLink(node1,node2,bw = 10,delay ='5ms',max_queue_size = 1000,loss = 10,use_htb = True)

添加带宽,延迟和丢失特性的双向链路,最大队列大小为1000 使用Hierarchical Token Bucket速率限制器和netem延迟/丢失仿真器的数据包。 参数bw表示为以Mbit为单位的数字; delay表示为具有单位的字符串(例如’5ms’,‘100us’,‘1s’); loss以百分比表示(介于0和100之间); 和max_queue_size以包表示。

您可能会发现创建Python字典很有用,可以很容易地将相同的参数传递给多个方法调用,例如:

linkopts = dict(bw=10, delay='5ms', loss=10, max_queue_size=1000, use_htb=True)

# (or you can use brace syntax: linkopts = {'bw':10, 'delay':'5ms', ... } )

self.addLink(node1, node2, **linkopts)

这种技术(** dict)对于将选项传递给Matplotlib和其他库非常有用。

net.get():按名称检索节点(主机或交换机)对象。 如果要将命令发送到主机(例如,使用host.cmd())并获取其输出,这一点很重要。

注意:在Mininet的当前主分支中,您可以简单地使用大括号(例如net ['h1'])按名称检索给定节点。

在主机中运行程序

在实验中您需要做的最重要的事情之一是在主机中运行程序,这样您可以运行比Mininet本身提供的简单pingAll()iperf()测试更多的测试。

每个Mininet主机本质上都是一个连接到一个或多个网络接口的bash shell进程,因此与它交互的最简单方法是使用cmd()方法将输入发送到shell。

要在主机中运行命令并获取输出,请使用cmd()方法。

h1 = net.get('h1')    

result = h1.cmd('ifconfig')

print result

在许多情况下,您希望在后台运行命令一段时间,停止命令并将其输出保存到文件中:

from time import sleep

...

print "Starting test..."

h1.cmd('while true; do date; sleep 1; done > /tmp/date.out &')

sleep(10)

print "Stopping test"

h1.cmd('kill %while')

print "Reading output"

f = open('/tmp/date.out')

lineno = 1

for line in f.readlines():

    print "%d: %s" % ( lineno, line.strip() )

    lineno += 1

f.close()

请注意,我们使用shell的输出重定向功能将输出发送到/tmp/date.out,后台执行shell的&特性以在后台运行命令,并且作业控制kill%while关闭正在运行的程序在后台。不幸的是,如果你让作业在后台运行,如果Mininet退出(无论是故意还是由于错误),它们都不能保证停止,所以你需要确保你干净地停止所有的工作。您可能希望定期使用ps命令以确保没有僵尸作业无意中前进并减慢EC2实例的速度。

(注意:Python字符串可以使用单引号或双引号分隔。上面的示例在print语句中使用双引号,在函数参数中使用单引号,但您可以执行任何您喜欢的操作.Python的print语句是为了方便而存在,可能有助于BASIC程序员在家里感觉更多。)

拥有一个shell进程可以让您轻松执行其他任务。例如,您可以使用查找后台命令的PID

pid = int( h1.cmd('echo $!') )

然后你可以等待一个特定的进程来使用wait来完成执行,例如:

 h1.cmd('wait', pid)

请注意,这仅适用于UNIX命令,而不适用于内置于bash shell本身的命令(例如whilecd)(并且没有单独的pid!)另请注意,这些命令中的每一个都在前台执行( 没有)而不是后台(),因为我们想得到输出。

[编辑:UNIX的(和bash的)缩写和特殊字符($)可以追溯到每秒快速300比特“网络”和Teletype™终端的日子,这些终端在你打字时打印在纸上。 Linux坚持使用兼容性,因为人类仍然输入缓慢。 如果你想使用它们,bash有时会提供更详细的等价物。

除了使用shell的等待机制之外,Mininet本身还允许您使用sendCmd()启动前台命令,然后等待稍后使用waitOutput()完成:

for h in hosts:

    h.sendCmd('sleep 20')

…

results = {}

for h in hosts:

    results[h.name] = h.waitOutput()

如果要将输出发送到文件,您可能希望在测试运行时以交互方式监视该文件的内容。 examples / multipoll.py示例提供了一个函数monitorFiles(),它实现了一种监视多个输出文件的可能机制。 这简化了测试的实现,该测试以交互方式监视来自多个主机的输出:

def monitorTest( N=3, seconds=3 ):

    "Run pings and monitor multiple hosts"

    topo = SingleSwitchTopo( N )

    net = Mininet( topo )

    net.start()

    hosts = net.hosts

    print "Starting test..."

    server = hosts[ 0 ]

    outfiles, errfiles = {}, {}

    for h in hosts:

        # Create and/or erase output files

        outfiles[ h ] = '/tmp/%s.out' % h.name

        errfiles[ h ] = '/tmp/%s.err' % h.name

        h.cmd( 'echo >', outfiles[ h ] )

        h.cmd( 'echo >', errfiles[ h ] )

        # Start pings

        h.cmdPrint('ping', server.IP(),

               '>', outfiles[ h ],

               '2>', errfiles[ h ],

               '&' )

    print "Monitoring output for", seconds, "seconds"

    for h, line in monitorFiles( outfiles, seconds, timeoutms=500 ):

        if h:

            print '%s: %s' % ( h.name, line )

    for h in hosts:

        h.cmd('kill %ping')

    net.stop()

您可能希望运行multipoll.py并查看其输出。

另一个例子,examples / multiping.py演示了使用Node.monitor()方法监视来自主机的标准输出的不同(可能更简单但不太灵活)的方法,因此您可能也希望查看它。

新:popen()/ pexec()接口

除了基于shell的cmd()/ sendCmd()机制之外,Mininet现在还支持基于管道的接口,该接口返回标准的Python Popen()对象(有关详细信息,请参阅Python的子进程模块。)此机制更新,而不是 经过充分测试的cmd()机制,但您可能会发现在后台运行多个进程并监视其输出很方便。 提供了一个pmonitor()函数,可以更轻松地监视多个Popen()对象。

警告:在Mininet 2.0.0中,pmonitor()可能会在收到EOF后返回一些空行。 现在应该在主分支中修复此问题。

examples / popenpoll.py中的代码使用popen()接口和pmonitor()辅助函数实现类似于上面描述的功能:

def pmonitorTest( N=3, seconds=10 ):

    "Run pings and monitor multiple hosts using pmonitor"

    topo = SingleSwitchTopo( N )

    net = Mininet( topo )

    net.start()

    hosts = net.hosts

    print "Starting test..."

    server = hosts[ 0 ]

    popens = {}

    for h in hosts:

        popens[ h ] = h.popen('ping', server.IP() )

        print "Monitoring output for", seconds, "seconds"

        endTime = time() + seconds

        for h, line in pmonitor( popens, timeoutms=500 ):

            if h:

                print '%s: %s' % ( h.name, line ),

                 if time() >= endTime:

                    for p in popens.values():

                        p.send_signal( SIGINT )

        net.stop()

请注意,这种实现略有不同,因为它将时间管理从助手函数中拉出来,但这使得pmonitor()能够在中断后捕获ping的输出。

当然,您不必使用pmonitor() - 您可以使用Popen.communicate()(只要您没有太多文件描述符)或select.poll()或任何其他有效的机制。

如果您在popen()界面中发现错误,请告诉我们。

重要:共享文件系统!

要记住的一件事是,Mininet主机默认共享底层服务器的根文件系统。通常这是一件非常好的事情,因为为每个Mininet主机创建一个单独的文件系统是一个巨大的痛苦(并且很慢)(如果你愿意,你可以这样做,然后chroot到它!)

共享根文件系统也意味着您几乎不需要在Mininet主机之间复制数据,因为它已经存在。

然而,其中一个副作用是主机共享Mininet服务器的/ etc目录。这意味着如果您需要程序的特定配置(例如httpd),则可能需要为每个Mininet主机创建不同的配置文件,并将它们指定为您正在运行的程序的启动选项。

另一个副作用是,如果您尝试在多个主机上的同一目录中创建相同的文件,则可能会发生文件冲突。

如果需要每个主机的私有目录,可以将它们指定为Host的选项,例如:

  h = Host( 'h1', privateDirs=[ '/some/directory' ] )

有关更多信息,请参阅examples / bind.py

主机配置方法

Mininet主机为网络配置提供了许多便利方法:

IP():返回主机或特定接口的IP地址。

MAC():返回主机或特定接口的MAC地址。

setARP():将静态ARP条目添加到主机的ARP缓存中。

setIP():设置主机或特定接口的IP地址。

setMAC():设置主机或特定接口的MAC地址

例如:

print "Host", h1.name, "has IP address", h1.IP(), "and MAC address", h1.MAC()

在每种情况下,如果您不提供特定接口(例如h1-eth0或接口对象),则该方法将使用主机的默认接口。上述函数在mininet / node.py中定义。

在Mininet中命名

为了有效地使用Mininet,了解其主机,交换机和接口的命名方案非常重要。通常,主机称为h1..hN,交换机称为s1..sN。我们建议您遵循此约定或类似约定。为清楚起见,属于节点的接口以节点名称开头命名,例如h1-eth0是主机h1的默认接口,s1-eth1是交换机s1的第一个数据端口。主机接口只能在主机内部看到,但是交换机数据端口在“根”命名空间中可见(您可以通过在Mininet运行时在另一个窗口中键入ip link show来查看它们。)因此,很容易检查切换接口,但检查主机接口有点棘手,因为您必须告诉主机这样做(通常使用host.cmd()。)

CLI

Mininet包括一个可在网络上调用的命令行界面(CLI),并提供各种有用的命令,以及显示xterm窗口和在网络中的各个节点上运行命令的功能。 您可以通过将网络对象传递到CLI()构造函数来调用网络上的CLI:

from mininet.topo import SingleSwitchTopo

from mininet.net import Mininet

from mininet.cli import CLI



net = Mininet(SingleSwitchTopo(2))

net.start()

CLI(net)

net.stop()

启动CLI对于调试网络非常有用,因为它允许您查看网络拓扑(使用net命令),测试连接(使用pingall命令),以及向各个主机发送命令。

*** Starting CLI:

mininet> net

c0

s1 lo:  s1-eth1:h1-eth0 s1-eth2:h2-eth0

h1 h1-eth0:s1-eth1

h2 h2-eth0:s1-eth2

mininet> pingall

*** Ping: testing ping reachability

h1 -> h2

h2 -> h1

*** Results: 0% dropped (0/2 lost)

mininet> h1 ip link show

746: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

749: h1-eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000

    link/ether d6:13:2d:6f:98:95 brd ff:ff:ff:ff:ff:ff

使用--custom文件自定义mn

除了用Python编写完整的Mininet脚本之外,您还可以使用--custom选项扩展mn命令行工具。 这允许您使用mn来调用您自己的自定义拓扑,交换机,主机,控制器或链接类。 您还可以定义和调用自己的系统测试,并添加新的Mininet CLI命令。

要添加可以使用mn命令调用的新功能,您需要根据选项类型在--custom文件中定义一个dict。 dict的键是传递给相应选项的短名称,值是相应的子类,构造函数或函数:
在这里插入图片描述

例如:

class MyTopo( Topo ):
   def build( self, ...):
def myTest( net ):
...
topos = { 'mytopo': MyTopo }
tests = { 'mytest': myTest }

这将MyTopo类(或构造函数)添加到topos字典,允许它与--topo选项一起使用,以及新测试mytest。 请注意,使用顶级Mininet对象调用测试函数,您可以将字符串或数字参数传递给MyTopo

sudo mn --custom mytopo.py --topo mytopo,3

您也可以指定多个自定义文件:

sudo mn --custom mytopo.py,mytest.py --topo mytopo,3 --test mytest

这将使用mytopo作为默认拓扑并调用mytest测试。

这可以是一个非常方便的单行命令来启动Mininet,运行端到端系统测试(或多个测试),并关闭Mininet。 如果发生异常,将调用标准Mininet清理代码,因为在这种情况下通常会执行mn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值