在--custom
文件中添加新的CLI命令
在--custom
文件中很容易添加新的CLI命令:
def mycmd( self, line ):
"mycmd is an example command to extend the Mininet CLI"
net = self.mn
output( 'mycmd invoked for', net, 'with line', line, '\n' )
CLI.do_mycmd = mycmd
这会把mycmd
命令添加到Mininet CLI中:
sudo mn --custom mycmd.py -v output
mininet> help mycmd
mycmd is an example command to extend the Mininet CLI
mininet> mycmd foo
mycmd invoked for <mininet.net.Mininet object at 0x7fd7235fb9d0> with line foo
请注意,添加到CLI的命令功能名称应具有do_
前缀
其他例子
可以在mininet /examples
中找到Mininet脚本的其他示例。
这些示例旨在具有教育意义,因为它们展示了可以使用Mininet API的不同方式。 我们鼓励您尝试阅读Python代码并自行运行示例。 如果他们由于某种原因不起作用,看看你能否找出原因!
您可能会发现其中一些(例如consoles.py
)是您可以构建的有趣的演示。
特别是,您可能会发现(miniedit.py
)是使用Mininet进行简单实验的特别有用的GUI。
注意:这些示例旨在作为阅读和理解的教学材料,而不是作为您可能遇到的任何问题的完整,开箱即用的解决方案。 您可以使用一些代码进行修改,但能够检查和理解代码非常重要。
了解Mininet API
在本简介的过程中,您已经了解了许多包含Mininet API的Python类,包括Topo
,Mininet
,Host
,Switch
,Link
及其子类等类。将这些类划分为级别(或层)很方便,因为通常使用较低级别的API构建高级API。
Mininet的API建立在三个主要级别:
低级API:低级API由基本节点和链接类(例如主机host
,交换机switch
和链路link
及其子类)组成,这些类实际上可以单独实例化并用于创建网络,但它有点笨拙。
中级API:中级API添加Mininet
对象,该对象充当节点和链接的容器。它提供了许多方法(例如addHost()
,addSwitch()
和addLink()
),用于添加节点和网络链接,以及网络配置,启动和关闭(特别是start()
和stop(
)。 )
高级API:高级API添加拓扑模板抽象,Topo
类,它提供了创建可重用,参数化拓扑模板的功能。这些模板可以传递给mn
命令(通过--custom
选项)并从命令行使用。
了解每个API级别很有价值。通常,当您想直接控制节点和交换机时,可以使用低级API。当您想要启动或停止网络时,通常使用中级API(尤其是Mininet
类)。
当您开始考虑创建完整的网络时,事情变得有趣。可以使用任何API级别创建完整的网络(如示例所示),但通常您需要选择中级API(例如Mininet.add *()
)或高级API(Topo.add*()
)来创建您的网络。
以下是使用每个API级别创建网络的示例:
低级API:结点和链路
h1 = Host( 'h1' )
h2 = Host( 'h2' )
s1 = OVSSwitch( 's1', inNamespace=False )
c0 = Controller( 'c0', inNamespace=False )
Link( h1, s1 )
Link( h2, s1 )
h1.setIP( '10.1/8' )
h2.setIP( '10.2/8' )
c0.start()
s1.start( [ c0 ] )
print h1.cmd( 'ping -c1', h2.IP() )
s1.stop()
c0.stop()
中级API:网络对象
net = Mininet()
h1 = net.addHost( 'h1' )
h2 = net.addHost( 'h2' )
s1 = net.addSwitch( 's1' )
c0 = net.addController( 'c0' )
net.addLink( h1, s1 )
net.addLink( h2, s1 )
net.start()
print h1.cmd( 'ping -c1', h2.IP() )
CLI( net )
net.stop()
高级API:拓扑和模板
class SingleSwitchTopo( Topo ):
"Single Switch Topology"
def build( self, count=1 ):
hosts = [ self.addHost( 'h%d' % i )
for i in range( 1, count + 1 ) ]
s1 = self.addSwitch( 's1' )
for h in hosts:
self.addLink( h, s1 )
net = Mininet( topo=SingleSwitchTopo( 3 ) )
net.start()
CLI( net )
net.stop()
如您所见,对于此示例,中级API实际上是最简单和最简洁的,因为它不需要创建拓扑类。 低级和中级API灵活且功能强大,但与高级Topo
API及其拓扑模板相比,可能不太方便重用。
另请注意,在2.2.0之前的Mininet版本中,高级Topo
不支持节点之间的多个链接,但是较低级别的API会支持多个链接。 目前Topo
也不关心哪些开关由哪些控制器控制(您可以使用自定义Switch
子类来执行此操作,如上所述。)使用中级和低级API,您可以手动启动开关 如果需要,将适当的控制器列表传递给每个交换机。
Mininet API文档
Mininet包含每个模块和API调用的Python文档字符串。 这些可以从Python的常规help()
机制访问。 例如,
python
>>> from mininet.node import Host
>>> help(Host.IP)
Help on method IP in module mininet.node:
IP(self, intf=None) unbound mininet.node.Host method
Return IP address of a node or specific interface.
Mininet网站http://api.mininet.org上也提供了相同的文档。
您可能希望使用doxypy
自己生成HTML(和PDF)文档:
sudo apt-get install doxypy
cd ~/mininet
make doc
cd doc
python -m SimpleHTTPServer
此时,您可以将Web浏览器指向运行Mininet的主机的端口8000,并浏览每个Mininet类的文档。
性能测量
建议使用这些参数,但您可以自由使用您熟悉的任何工具。
带宽(bwm-ng
,ethstats
)
延迟(使用ping
)
队列(使用monitor.py
中的tc
)
TCP CWND
统计信息(tcp_probe
,也许我们应该将它添加到monitor.py
中)
CPU使用率(全局:top
或每容器cpuacct
)
OpenFlow与自定义路由
Mininet最强大和最有用的功能之一是它使用软件定义网络。 使用OpenFlow协议和相关工具,您可以将开关编程为使用输入它们的数据包执行几乎任何操作。 OpenFlow使像Mininet这样的仿真器更加有用,因为网络系统设计(包括使用OpenFlow的自定义数据包转发)可以轻松地传输到硬件OpenFlow交换机以进行线速操作。 可以在以下位置找到使用Mininet和OpenFlow创建简单学习交换机的教程:
https://github.com/mininet/openflow-tutorial/wiki添加链接描述
OpenFlow控制器
如果在未指定控制器的情况下运行mn
命令,它将选择默认控制器,如Controller
或OVSController
,具体取决于可用的内容。
这等价于:
$ sudo mn --controller default
该控制器实现了一个简单的以太网学习交换机,最多可支持16个独立的交换机。
如果在脚本中调用Mininet()
构造函数而未指定控制器类,则默认情况下它将使用Controller()
类创建Stanford / OpenFlow引用控制器控制器的实例。 像ovs-controller
一样,它将你的开关变成简单的学习交换机,但是如果你使用Mininet的install.sh -f
脚本安装了控制器,那么修补后的控制器版本应该支持大量的交换机(理论上最多4096个,但是你 可能会更早地将计算资源最大化。)您还可以通过指定--controller ref
为mn
选择参考控制器。
如果要使用自己的控制器,可以轻松创建Controller()
的自定义子类并将其传递给Mininet。 在mininet.controller.NOX()
中可以看到一个示例,它使用作为选项传入的一组模块调用NOX classic。
以下是创建和使用自定义POX Controller
子类的简单示例:
#!/usr/bin/python
from mininet.net import Mininet
from mininet.node import Controller
from mininet.topo import SingleSwitchTopo
from mininet.log import setLogLevel
import os
class POXBridge( Controller ):
"Custom Controller class to invoke POX forwarding.l2_learning"
def start( self ):
"Start POX learning switch"
self.pox = '%s/pox/pox.py' % os.environ[ 'HOME' ]
self.cmd( self.pox, 'forwarding.l2_learning &' )
def stop( self ):
"Stop POX"
self.cmd( 'kill %' + self.pox )
controllers = { 'poxbridge': POXBridge }
if __name__ == '__main__':
setLogLevel( 'info' )
net = Mininet( topo=SingleSwitchTopo( 2 ), controller=POXBridge )
net.start()
net.pingAll()
net.stop()
请注意,编写上述脚本时,它也可以用作mn的自定义参数,以便与不同的拓扑和测试以及Mininet CLI一起使用:
$ sudo mn --custom poxbridge.py --controller poxbridge --topo tree,2,2 --test pingall -v output
*** Ping: testing ping reachability
h1 -> h2 h3 h4
h2 -> h1 h3 h4
h3 -> h1 h2 h4
h4 -> h1 h2 h3
*** Results: 0% dropped (0/12 lost)
如果你看一下mininet / node.py
中NOX
类的实现,你会发现它实际上可以接受选项,允许启动不同的模块,具体取决于传递给它的参数,来自构造函数或mn
命令行。
外部OpenFlow控制器
自定义Controller()
子类是自动启动和关闭控制器的最方便的方法。 创建start()
和stop()
方法很容易,因此Mininet会根据需要自动启动和停止控制器。
(有关更多信息,请查看此博客文章。)
但是,您可能会发现将Mininet连接到已在其他位置运行的现有控制器很有用,例如LAN上的某个位置,另一个VM或笔记本电脑上。
RemoteController
类充当控制器的代理,该控制器可以在控制网络上的任何地方运行,但必须手动启动和关闭,或者通过Mininet直接控制之外的其他机制启动和关闭。
你可以使用Mininet
的RemoteController
:
from functools import partial
net = Mininet( topo=topo, controller=partial( RemoteController, ip='127.0.0.1', port=6633 ) )
或者,你可能会更喜欢:
net = Mininet( topo=topo, controller=lambda name: RemoteController( name, ip='127.0.0.1' ) )
甚至,这也可以:
net = Mininet( topo=topo, controller=None)
net.addController( 'c0', controller=RemoteController, ip='127.0.0.1', port=6633 )
请注意,在这种情况下,控制器controller
(如主机host
和交换机switch
)是构造函数,而不是对象(但请参阅下面的其他信息!)您可以使用partial
或lambda
在线创建自定义构造函数,或者您可以传入自己的函数 (必须采用name
参数并返回控制器对象)或类(例如RemoteController
的子类。)
您还可以创建多个控制器并创建自定义Switch()
子类,根据需要连接到不同的控制器:
c0 = Controller( 'c0' ) # local controller
c1 = RemoteController( 'c1', ip='127.0.0.2' ) # external controller
cmap = { 's1': c0, 's2': c1, 's3': c1 }
class MultiSwitch( OVSSwitch ):
"Custom Switch() subclass that connects to different controllers"
def start( self, controllers ):
return OVSSwitch.start( self, [ cmap[ self.name ] ] )
您还可以从mn命令行指定外部控制器:
$ sudo mn --controller remote,ip=192.168.51.101
通过传入控制器对象来滥用API
在Mininet 2.2.0及更高版本中,您可以选择传入一个Controller
对象而不是一个构造器(甚至是一个对象列表。)这是因为尽管API明确指定构造函数是需要。
这允许您执行以下操作:
net = Mininet( topo, controller=RemoteController( 'c0', ip='127.0.0.1' ) )
要想获得您想要的行为,扔需要允许构造器。
多路径路由
重要的是要记住以太网桥(也称为学习交换机)将泛滥其MAC表中丢失的数据包。他们还会充斥ARP和DHCP请求等广播。这意味着如果您的网络中有环路或多个路径,它将无法与默认的ovs-controller
和controller
控制器,NOX的pyswitch
或POX的l2_learning
一起使用,它们都充当学习交换机/以太网桥。
尽管这个问题显而易见,但它已成为一个常见问题。
更新的(也是更复杂的)OpenFlow控制器确实支持多路径路由 - 请参阅控制器的文档以确定是否需要任何特殊配置。
如果您正在构建类似胖树的拓扑,您可能希望看一下使用POX实现的基本数据中心控制器RipLPOX
。您可以将它用作自定义多路径路由的起点。
为了方便起见,您可能还希望实现一个自定义Controller()
子类来调用RipLPOX。
或者,如果你真的大胆/疯狂,你甚至可以尝试将Mininet和POX或RipLPOX导入一个Python脚本!但你可能不想这样做。)
更新mininet
如果我们需要对Mininet进行更改或添加以修复错误或其他问题,并且您已从源代码安装Mininet,您可能希望更新Mininet的副本。 这可以使用以下两种方法之一轻松完成:
使用符号链接更新到Mininet源代码树(可以轻松更新Mininet的python代码):
cd ~/mininet
git checkout master # assuming you want to update to the current master branch
sudo make develop # this only needs to be done initially and when mnexec.c changes
git fetch
git pull --rebase
更新将Mininet源复制到/ usr / lib / python …(允许您删除或移动Mininet源树):
cd ~/mininet
git checkout master # assuming you want to update to the current master branch
git fetch
git pull --rebase
sudo make install
使用Mininet的有用背景
Random list, no particular order
面向对象编程 (创建类,从类创建对象等)
导入Python模块 http://docs.python.org/tutorial/modules.html
从Python调用系统实用程序(system utilities) http://docs.python.org/library/subprocess.html
http://docs.python.org/library/os.html
https://github.com/amoffat/pbs
以您自己的格式解析输出文件 http://docs.python.org/library/re.html
将命令行参数传递给脚本 http://docs.python.org/dev/library/argparse.html
matplotlib 绘图
http://matplotlib.sourceforge.net