SDN 網絡系統之 Mininet 與 API 詳解
SDN 與 Mininet 概述
SDN 全名為(Software Defined Network)即軟件定義網絡,是現互聯網中一種新型的網絡創新架構,其核心技術 OpenFlow 通過網絡設備控制面與數據面分離開來,從而實現網絡流量的靈活控制,為網絡及應用提供了良好的平台。而 Mininet 是一個輕量級軟件定義網絡和測試平台;它采用輕量級的虛擬化技術使一個單一的系統看起來像一個完整的網絡運行想過的內核系統和用戶代碼,也可簡單理解為 SDN 網絡系統中的一種基於進程虛擬化平台,它支持 OpenFlow、OpenvSwith 等各種協議,Mininet 也可以模擬一個完整的網絡主機、鏈接和交換機在同一台計算機上且有助於互動開發、測試和演示,尤其是那些使用 OpenFlow 和 SDN 技術;同時也可將此進程虛擬化的平台下代碼遷移到真實的環境中。
Mininet 實現的特性
- 支持 OpenFlow、OpenvSwitch 等軟定義網路部件
- 支持系統級的還原測試,支持復雜拓撲,自定義拓撲等
- 提供 Python API, 方便多人協作開發
- 很好的硬件移植性與高擴展性
- 支持數千台主機的網絡結構
Miniet 實現與工作流程
Mininet 的安裝方式比較簡單通過 Git 源碼和自帶的安裝腳本方式即可安裝在 Linux 系統中,這里我采用了默認安裝所有 Mininet 相關的相關套件,如:OpenFlow、POX 等工具會默認保存在當前用戶的家目錄。
1
2
3
4
5
|
# git clone git://github.com/mininet/mininet
# cd mininet/util/
# ./install.sh -a
# ls
mininet of-dissector oflops oftest openflow pox
|
創建網絡
圖 1.簡單網絡示例圖

由於 Mininet 支持自定義網絡,這里先引用一個簡單網絡示例如圖 1,在 Mininet 網絡系統中直接輸入 mn 命令,可以在此系統中創建單層的拓撲網絡,從中默認創建了兩台 host 和一個交換機,並且激活了控制器和交換機。同時也可以通過命令 net 查看到鏈路情況,先簡單列出了示例,如在 Mininet 系統中啟用 Web 服務器與客戶端。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# mn
*** Creating network
*** Adding controller
*** Adding hosts:
h1 h2
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1)
*** Configuring hosts
h1 h2
*** Starting controller
*** Starting 1 switches
s1
*** Starting CLI:
mininet>
|
啟用與關閉 Web 服務
在 Mininet 環境中可方便建立一個 Web 服務器,從下面示例中可以看到從 host1 建立了一個 Web 服務器,並從另外一台 Host 主機想 Web 服務器獲取 HTTP 請求。
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
|
mininet> h1 python -m SimpleHTTPServer 80 & #在主機 h1 開啟 Web 服務
mininet> h2 wget -O - h1 #主機 h2 上下載 h1 web 站點內容
--2013-11-04 00:05:40-- http://10.0.0.1/
Connecting to 10.0.0.1:80... connected.
HTTP request sent, awaiting response... 200 OK
…………
Length: 760 [text/html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><
html
>
<
title
>Directory listing for /</
title
>
<
li
><
a
href
=
".bash_history"
>.bash_history</
a
>
<
li
><
a
href
=
".wireshark/"
>.wireshark/</
a
>
<
li
><
a
href
=
"install-mininet-vm.sh"
>install-mininet-vm.sh</
a
>
<
li
><
a
href
=
"mininet/"
>mininet/</
a
>
<
li
><
a
href
=
"of-dissector/"
>of-dissector/</
a
>
<
li
><
a
href
=
"oflops/"
>oflops/</
a
>
<
li
><
a
href
=
"oftest/"
>oftest/</
a
>
<
li
><
a
href
=
"openflow/"
>openflow/</
a
>
<
li
><
a
href
=
"pox/"
>pox/</
a
>
</
ul
>
<
hr
>
</
body
>
</
html
>
0K 100% 1.65M=0s
2013-11-04 00:05:40 (1.65 MB/s) - written to stdout [760/760]
mininet> h1 kill %python # 殺掉 web 進程
10.0.0.2 - - [04/Nov/2013 00:05:40] "GET / HTTP/1.1" 200 -
bash: line 23: kill: python: ambiguous job spec
Ping 測試
|
在 Mininet 系統上,實現兩主機互連測試。
1
2
3
4
5
6
7
8
9
10
|
mininet> h1 ping -c4 h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=1.55 ms
64 bytes from 10.0.0.2: icmp_req=2 ttl=64 time=0.094 ms
64 bytes from 10.0.0.2: icmp_req=3 ttl=64 time=0.075 ms
64 bytes from 10.0.0.2: icmp_req=4 ttl=64 time=0.071 ms
--- 10.0.0.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3006ms
rtt min/avg/max/mdev = 0.071/0.448/1.553/0.638 ms
|
查看節點與鏈接
1
2
3
4
5
6
7
8
|
mininet> nodes
available nodes are:
c0 h1 h2 s1
mininet> net
h1 h1-eth0:s1-eth1
h2 h2-eth0:s1-eth2
s1 lo: s1-eth1:h1-eth0 s1-eth2:h2-eth0
c0
|
自定義拓撲
Mininet 支持自定義拓撲結構,在 mininet/custom 目錄下給出了一個實例,如在 topo-2sw-2host.py 文件中定義了一個 mytopo,則可以通過--topo 選項來指定使用這一拓撲:
圖 2. 自定拓撲示例

由於 Mininet 也支持參數化拓撲,通過 Python 代碼也可以創建一個靈活的拓撲結構,也可根據自定義傳遞進去的參數進行配置,並且可重用到多個環境中,下面簡短列出其代碼的大致結構及含義。
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
|
#!/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):
def __init__(self, n=2, **opts):
Topo.__init__(self, **opts)
switch = self.addSwitch('s1') #添加一個交換機在拓撲中
for h in range(n):
host = self.addHost('h%s' % (h + 1)) #添加主機到拓撲中
self.addLink(host, switch) #添加雙向連接拓撲
def simpleTest():
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__':
setLogLevel('info') # 設置 Mininet 默認輸出級別,設置 info 它將提供一些有用的信息
simpleTest()
|
驗證參數化拓撲結構
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
|
# python test-single.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
*** 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)
|
名字空間 namespace
通常情況下,主機界面有用獨立的名字空間 namespace,而控制節點跟交換節點都在根名字空間(root namespace)中。如果想要讓所有節點擁有各自的名字空間,需要添加 --innamespace 參數,即執行:mn --innamespace
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
# mn --innamespace --switch user
*** Creating network
*** Adding controller
*** Adding hosts:
h1 h2
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1)
c0 <-> s1
*** Testing control network
s1 -> c0
c0 -> s1
*** Results: 0% dropped (2/2 received)
*** Configuring hosts
h1 h2
*** Starting controller
*** Starting 1 switches
s1
*** Starting CLI:
|
Mininet 常用操作
表 1.Mininet 常用指令
dpctl 命令實踐
dpctl 程序是一個命令行工具用來檢測和管理 OpenFlow 數據通路,它能夠顯示當前的狀態數據通路,包括功能配置和表中的條目,以及合適使用 OpenFlow 的內核模塊,可以用來添加,刪除,修改和監視 datapaths。
查看交換機端口信息基本情況(TCP 端口 6634 是默認交換機監聽端口)。
1
2
3
4
5
6
7
8
9
10
|
# dpctl show tcp:9.123.137.25:6634
features_reply (xid=0x94af8117): ver:0x1, dpid:1
n_tables:255, n_buffers:256
features: capabilities:0xc7, actions:0xfff
1(s1-eth1): addr:2e:d1:ca:aa:af:67, config: 0, state:0
current: 10GB-FD COPPER
2(s1-eth2): addr:66:93:32:1e:9b:9e, config: 0, state:0
current: 10GB-FD COPPER
LOCAL(s1): addr:5e:bc:ab:cc:dc:43, config: 0x1, state:0x1
get_config_reply (xid=0x92fc9e48): miss_send_len=0
|
查看流表信息:
1
2
|
# dpctl dump-flows tcp:9.123.137.25:6634
stats_reply (xid=0xe2c7ea1e): flags=none type=1(flow)
|
此時,流表為空,執行 h1 ping h2 無法得到響應。因此我們需要通過 dpctl 手動添加流表項,實現轉發。
手動添加流表項:
1
2
3
4
5
6
7
8
|
# dpctl add-flow tcp:9.123.137.25:6634 in_port=1,actions=output:2
# dpctl add-flow tcp:9.123.137.25:6634 in_port=2,actions=output:1
# dpctl dump-flows tcp:9.123.137.25:6634
stats_reply (xid=0x131ed782): flags=none type=1(flow)
cookie=0, duration_sec=13s, duration_nsec=401000000s, table_id=0, priority=32768, \
n_packets=0, n_bytes=0,idle_timeout=60,hard_timeout=0,in_port=1,actions=output:2
cookie=0, duration_sec=5s, duration_nsec=908000000s, table_id=0, priority=32768, \
n_packets=0, n_bytes=0,idle_timeout=60,hard_timeout=0,in_port=2,actions=output:1
|
此時查看流表可以看到新的轉發信息,同時可以在 h1 和 h2 之間可以相互連通。
dpctl 其他常用操作
創建 datapath 編號為 0
1
|
#dpctl adddp n1:0
|
增加兩個網絡設備到新的 datapath
1
2
|
#dpctl adddp n1:0 eth0
#dpctl adddp n1:0 eth1
|
檢測數據通路接收的流量
1
|
#dpctl monitor n1:0
|
在數據通路中刪除網絡設備
1
|
#dpctl delif nl:0 eth0
|
Mininet Python API
OpenFlow 與自定義路由機制
Mininet 的最強大和最有用的功能之一是它使用的軟件定義網絡(Software Defined Network).使用的 OpenFlow 協議和相關工具,您可以設定程序開關去做幾乎任何您想要與之輸入的數據包,OpenFlow 使得 Mininet 更加高效,因為網絡的系統設計,包括自定義的數據包轉發與 OpenFlow 可以輕松轉移到硬件 OpenFlow 交換機線路速率操作等。
OpenFlow 控制器
在您執行 mn 命令未指定一個控制器的話,它會默認采用 ovsc 控制,ovs-controller,如下命令:
1
2
3
4
|
# mn --controller ovsc
*** Creating network
*** Adding controller
當然您也根據上面的 mininet 參數化拓撲方式進行自定義控制器的創建與設計,代碼格式如表 1 參數化拓撲
|
外部 OpenFlow 控制器
通常自定義 controller 子類是最方便的方法來自動啟動和關閉您的控制器,很容易創建 start 和 stop 類在參數拓撲中,便於 Mininet 控制器將自動啟動和停止。從而,您可能會發現它有用 Mininet 連接到一個現有的控制器已經運行在其他地方,例如在某個地方上運行您的 LAN 或 VM 上。通常可以在代碼中定義一個 RemoteController 類作為一個代理控制器,運行在控制網絡的任何地方,但必須通過 Mininet 收到直接控制它們的啟動和關閉操作。需要在您的參數拓撲中增加一小段代碼:
1
|
Miniet( topo=topo,controller=lambda name: RemoteController( name,ip=‘192.168.1.101’) )
|
當然也可以指定外部已存在的控制器通過以下命令
1
|
#mn --controller remote,192.168.1.102
|
代碼分析
MininetRunner 類分析
Mininet 安裝后會在當前目錄下會生成 10 個子目錄分別為:bin、build、custom、debian、dist、doc、example、mininet、mininet.egg-info、util
和幾個文件。
圖 3.Mininet 相關文件示例

mn
執行文件
1mn 是一個 Python 代碼文件是程序執行的解釋器,定義 MininetRunner 類,為整個測試創建基礎平台。主要執行 3 大步驟有
parseArgs()
:
解析參數
- Setup(): 調用 mininet.net.init()
- 3. Begin(): 執行執行給定參數,包括創建拓撲、地址分配等;調用 mininet.net.Mininet()創建網絡平台 mn;調用 mininet.cli.CLI()創建 CLI 對象;調用 mn.start()啟動網絡;執行指定的測試命令,默認為 cli,即調用 CLI(mn)進入交互環境;執行結束后調用 mn.stop()退出
- mnexec 文件 完成一些 python 代碼執行起來比較慢或者難以實現的功能,包括關閉文件描述、使用 setsid 從控制 tty 剝離、在網絡空間運行、打印 pid 等。
Mininet 子目錄及節點代碼詳解
mininet 相關實現的主代碼目錄,包括若干.py 源文件。
- __init__.py: python 代碼導入控制文件。
- clean.py: 提供兩個函數 sh(cmd) 調用 shell 來執行 cmd;cleanup() 清理殘余進程或臨時文件。
- cli.py: 定義 CLI 類,在 mn 運行后提供簡單的命令行接口,解析用戶鍵入的各項命令。
- log.py: 實現日志記錄等功能, 定義三個類 MininetLogger 、Singleton 和 StreamHandlerNoNewLine。
- moduledeps.py: 模塊依賴相關處理。定義 5 個函數:lsmod() 、rmmod(mod) 、modprobe(mod) 、 moduleDeps(subtract=None, add=None)、pathCheck(*args,**kwargs)。
- net.py: mn 網絡平台的主類。完成包括節點管理、基本測試等功能。
- node.py: 實現網絡節點功能的幾個類。包括主機、交換機、控制器等,各個類的集成關系如下圖。
圖 4. 網絡節點示例

各個類功能為:
- Host:等同於 Node。
- KernelSwitch:內核空間的交換機,僅能在 root 名字空間中執行。
- OVSLegacyKernelSwith:內核兼容模式交換機,僅能 root 名字空間中執行。
- UserSwitch:用戶空間的交換機。
- OVSKernelSwitch:Open vSwitch 的內核空間交換機,僅能在 root 名字空間中執行。
- NOX:NOX 控制器。
- RemoteController:mininet 外的控制,通過指定 IP 地址等進行連接。
- term.py: 實現在每個節點上運行 terminal 的功能。
- topolib.py: 實現可能需要的拓撲結構。包括一個 TreeTopo 類和 TreeNet 函數。前者提供給定深度和 fanout 的樹狀結構,后者返回一個樹狀結構的 Mininet 網絡。
- topo.py: 創建網絡拓撲的主文件。包括一些常見拓撲,例如線型、星型等。
- util.py: mininet 的一些輔助功能,包括調用 shell 執行命令,網絡地址格式的解析等。
總結
通過本文的闡述及實踐,我們了解 Mininet 以及 OpenFlow 的基本概念。通過 Mininet 網絡系統去仿真網絡拓撲和自定義參數網絡拓撲的實現,並且采用 dpctl 命令實現 OpenFlow 協議修改了流表項及其他常用的操作,最后對 Mininet 網絡系統幾個重要的執行文件進行了代碼分析。
相關主題
- 參考 Mininet 項目主頁,查看 Mininet 的最新信息及相關使用技巧
- 參考 Mininet API 手冊頁,查看或獲取相關 Mininet python API 信息
- OpenFlow 是 OpenFlow 協議的主頁,里面提供了 OpenFlow 協議的白皮書以及 OpenFlow 交換機的實現規范。
- developerWorks 雲計算站點 提供了有關雲計算的更新資源,包括
- 雲計算 簡介。
- 更新的 技術文章和教程,以及網絡廣播,讓您的開發變得輕松,專家研討會和錄制會議 幫助您成為高效的雲開發人員。
- 連接轉為雲計算設計的 IBM 產品下載和信息。
- 關於 社區最新話題 的活動聚合。