Atom Login Admin

Above the clouds

Mininetの使い方について(2)

Mininet 2.0 Introduction(2)

pone()/pexec() interface

更に、MininetはPythonのpone()オブジェクトを返却する、pipe-basedインターフェースであるシェルベースのメカニズムのcmd()/sendCmd()もサポートしている。
このメカニズムは、新しくて既存のcmd()とは違う。しかし、複数のバックグラウンドプロセスやアウトプットを監視するときに便利であることが分かるであろう。
pmonitor()ファンクションは複数のPopenオブジェクトの監視を簡単にしてくれる。

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.poolや他のメカニズムも同様に使う事ができる。

重要:ファイルシステムを共有する

念頭においておく必要があるのだが、デフォルトのMininetホストは、サーバーのファイルシステムを共有する。
通常それはいいことではあるが、Mininetホストに分かれたファイルシステムを作成すると遅くなる。
(chrootした後必要であればできる)
ファイルシステムを共有することは同時にMininetホスト間でファイルをコピーする必要がなくなる。

複数のホストで同じディレクトリに同じファイルを作成した際は、競合してしまう。

もし必要であれば、将来それぞれのMininetホストにファイルシステムで共有するカスタムディレクとの作成を自動化する機能を提供するであろう

・ホスト設定メソッド
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()

それぞれのケースで、インターフェースを指定しない場合は、デフォルトインターフェースが使われる。
上記のファンクションはmininet/node.pyで定義されている。

Mininet内での名前

Mininetを効果的に使うには、ホスト、インターフェースに対する名前のスキームを理解する事が大事である。
通常、ホストはh1..hN、スイッチはs1..sNとなる。
これと同様に定義することを薦める。インターフェースであれば、明確にどのノードに所属しているか分かるように、h1-eth0としたりする。これは、h1のデフォルトインターフェースであることが分かる。また、s1-eth1であれば、s1スイッチの1番目のデータポートであることが分かる。ホストのインターフェースはホスト自身でしか見る事ができないが、スイッチのデータポートは、root名前空間から見える。結果的に、スイッチのインターフェースの試験は簡単だが、ホストのインターフェースの試験は、ホストを呼び出してから試験をする必要がある。

CLI

Mininetは構築したネットワークないのそれぞれのノードに対してして、様々な便利なコマンドや、ネットワークの呼び出しを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を開始することで、それぞれのホストへコマンドを送信することや、接続確認(pingallコマンド)、ネットワークトポロジをみたり(netコマンド)、ネットワークのデバッグを行うのに便利である。

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

他のExamplesについて

他のExamplesについてはmininet/examplesで見つける事が出来る。
便利なデモンストレーションを見つけることができるだろう。

Mininet APIドキュメントについて

次回紹介する。

パフォーマンス測定

親しんでいるツールでパフォーマンス測定を行うとよい。
1.帯域幅(bwm-ng, ethstats)
2.レイテンシ(use ping)
3.キュー(monitor.pyに含まれているtc)
4.TCP CWND statistics(monitor.pyに含まれているtcp_probe)
5.CPU使用率(global:topまたはper-container cpuacct)

OpenFlowとカスタムルーティング

Mininetの一つ強力な機能としてSoftware Defined Networkingができることである。
OpenFlowプロトコルとそれらの関連するツールを利用することによって、スイッチに入るパケットの処理をプログラミングすることができる。
OpenFlowはネットワークシステム設計から、OpenFlowでのカスタムパケットを含むフォワーディングline-rate処理のOpenFlowスイッチへの送信が簡単にでき、Mininetエミュレータのように便利である。Mininetを使った勉強用のスイッチやOpenFlowのチュートリアルは、OpenFlow Tutorialで見つけることができる。

OpenFlowコントローラ

mnコマンドでMininetを実行した場合デフォルトで、ovscコントローラが使われる。
下記と等価である。

$ sudo mn --controller ovsc

コントローラクラスを指定しないでMininet()コンストラクターを呼び出した場合は、デフォルトでStanford/OpenFlowを参照したController()クラスのインスタンスが作成される。OVS-Controllerのように、簡単な学習スイッチにスイッチをオンにするが、Mininetのinstall.shは、-fスクリプトを使用してコントローラをインストールしている場合、コントローラのパッチを適用したバージョンは、多数のスイッチをサポートする必要がある(理論上は4096以上だが、端末のリソースがそれよりも前に足りない)
mnで--contorller refを指定することで、コントローラを選択することもできる。
Controller()のサブクラスを作れば、簡単に自分で作成したコントローラを使う事ができる。任意のオプションのモジュールを渡したNOXのクラシックなコントローラはmininet.controller.NOX()で見る事ができる。

下記は、カスタムPOXコントロラーのサブクラスを作成して使っている例である。

#!/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()   

上記のスクリプトはMininetのCLIでテストする時、また、異なったトポロジを使うのと同様にmnにカスタム引数として渡す為なので、注意が必要である。

$ 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

カスタムController()サブクラスはコントローラの自動開始と停止に最も便利なメソッドである。
必要であれば、コントローラに自動開始と停止のstart() stop()メソッドを簡単に作る事ができる。
ただし、すでに別のVMに、またはあなたのラップトップ上で、LAN上のどこか、たとえば、どこか別の動作している既存のコントローラにMininetを接続することが便利な場合がある。
RemoteControllerクラスはどこかで動いているであろうネットワークのコントローラのプロキシとなる。しかし、Mininetの直接的な操作の外部で、開始や終了をおこなわなくてはならない。
MininetからRemoteControllerを使うことができる。

Mininet( topo=topo, controller=lambda name: RemoteController( name, ip='127.0.0.1' ) )

また、複数のコントローラの作成もでき、接続したい異なるコントローラへ接続するカスタム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

Multipath Routing

念頭においておく必要があるのが、MACテーブルのミスによってパケットが溢れ出すことだ。
ARPとDHCPリクエストのブロードキャストもまた同様である。
つまりネットワークに複数のパス、ループが存在するとデフォルトのovs-controllerとcontrollerまた、NOXのpyswitchまた、
POXのl2_leaningはswitch/Ethernetブリッジとしての学習が動作しなくなる。

この問題の自明正にもかかわらず、よくある質問となっている。

もしfat-treeのようなトポロジを構築した際は、POXを使った基本的なdatacenterのコントローラのRipLPOS見たくなるかもしれない。
これはmultipath routingの入門として使えるかもしれない。

また、RipLPOXを便利に呼び出すカスタムControllerのサブクラスを実装することもありである。

Mininetの更新

もしMininetの問題やバグ改修などで変更が行われた場合や、ソースコードからインストールしたい場合、Mininetのコピーを更新することができる。
下記のとおり簡単にできる。

cd ~/mininet
sudo make develop # this only needs to be done once
git fetch
git pull --rebase

Mininetの紹介は以上だ。
次回は、MininetのAPI郡について紹介する予定。
また、Ryuコントローラを実際にテストもしてみたいとも考えている。