Mininet是一款非常轻巧但是功能很强大的网络模拟器。网络研究者可以使用Mininet创建支持OpenFlow的SDN拓扑。随着SDN研究的发展,多控制器协作成为未来的研究方向,所以使用Mininet构建多控制器网络拓扑也成为一种需求。本篇将讲述如何使用Mininet搭建多控制器网络拓扑。
Multi-Controller
多控制器有两种理解,一种理解是面向交换机的多控制器。即一个交换机会连接多个控制器,控制器之间的关系可以是equal,也可以是master/slave模式。关于多控制器的介绍,有兴趣的读者可以参考OpenFlow1.3协议的multi-controller部分内容。另一种理解是面向控制器的多控制器。即,多个控制器分别管理各自的数据平面网络,且数据平面之间有链路互联。这种模式下,控制器之间没有关系,控制器所控制的数据平面也没有关系。关于多控制器方面的研究,笔者会在后续的博客中大篇幅介绍。
本篇将针对这两种理解,介绍如何搭建多控制器的Mininet拓扑。
面向交换机的多控制器网络拓扑
对于一个交换机而言,可以连接多个控制器,其实现方式非常简单, 在Mininet的源码中已经实现。从Mininet的node.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
|
def
start
(
self
,
controllers
)
:
"""
Start
OpenFlow
reference
user
datapath
.
Log
to
/
tmp
/
sN
-
{
ofd
,
ofp
}
.log
.
controllers
:
list
of
controller
objects
"""
# Add controllers
clist
=
','
.join
(
[
'tcp:%s:%d'
%
(
c
.IP
(
)
,
c
.port
)
for
c
in
controllers
]
)
ofdlog
=
'/tmp/'
+
self
.name
+
'-ofd.log'
ofplog
=
'/tmp/'
+
self
.name
+
'-ofp.log'
intfs
=
[
str
(
i
)
for
i
in
self
.intfList
(
)
if
not
i
.IP
(
)
]
self
.cmd
(
'ofdatapath -i '
+
','
.join
(
intfs
)
+
' punix:/tmp/'
+
self
.name
+
' -d %s '
%
self
.dpid
+
self
.dpopts
+
' 1> '
+
ofdlog
+
' 2> '
+
ofdlog
+
' &'
)
self
.cmd
(
'ofprotocol unix:/tmp/'
+
self
.name
+
' '
+
clist
+
' --fail=closed '
+
self
.opts
+
' 1> '
+
ofplog
+
' 2>'
+
ofplog
+
' &'
)
if
"no-slicing"
not
in
self
.dpopts
:
# Only TCReapply if slicing is enable
sleep
(
1
)
# Allow ofdatapath to start before re-arranging qdisc's
for
intf
in
self
.intfList
(
)
:
if
not
intf
.IP
(
)
:
self
.TCReapply
(
intf
)
|
start函数发起了交换机到控制器的网络连接。传入的参数controllers是一个可迭代的数组,clist是整合之后的控制器信息,包括控制器的IP和控制器的端口。之后调用self.cmd函数启动连接,连接到控制器。
start函数在UserSwitch和OVSSwitch等交换机类中均有对应实现。所以,只需在启动交换机时,传入对应的控制器列表即可。
关键代码举例如下:
1
2
3
4
5
6
7
8
9
10
11
|
net
=
Mininet
(
controller
=
None
,
switch
=
OVSSwitch
,
link
=
TCLink
)
s1
=
net
.addSwitch
(
's1'
)
controller_list
=
[
]
for
i
in
xrange
(
3
)
:
name
=
'controller[%s]'
%
str
(
i
)
c
=
net
.addController
(
name
,
controller
=
RemoteController
,
port
=
6661
+
i
)
controller_list
.append
(
c
)
s1
.start
(
controller_list
)
|
其余代码如头文件引入,主函数等请参考后续示例代码。
面向控制器的多控制器网络拓扑
面向控制器的多控制器网络拓扑定义了多个交换机,并使其分别连接到不同的控制器,从而完成拓扑搭建。在下列示例代码中,我们定义了7个网络分别连接到7个控制器,每一个网络中有5个全连接的交换机,不同网络之间还有链路,使得7个网络彼此联通。代码比较简单,不再赘述,读者可自行阅读。
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
#!/usr/bin/python
"""
This
example
create
7
sub
-
networks
to
connect
7
domain
controllers
.
Each
domain
network
contains
at
least
5
switches
.
For
an
easy
test
,
we
add
2
hosts
for
one
switch
.
So
,
in
our
topology
,
we
have
at
least
35
switches
and
70
hosts
.
Hope
it
will
work
perfectly
.
"""
from
mininet
.net
import
Mininet
from
mininet
.node
import
Controller
,
RemoteController
,
OVSSwitch
from
mininet
.cli
import
CLI
from
mininet
.log
import
setLogLevel
,
info
from
mininet
.link
import
Link
,
Intf
,
TCLink
from
mininet
.topo
import
Topo
import
logging
import
os
def
multiControllerNet
(
con_num
=
7
,
sw_num
=
35
,
host_num
=
70
)
:
"Create a network from semi-scratch with multiple controllers."
controller_list
=
[
]
switch_list
=
[
]
host_list
=
[
]
net
=
Mininet
(
controller
=
None
,
switch
=
OVSSwitch
,
link
=
TCLink
)
for
i
in
xrange
(
con_num
)
:
name
=
'controller[%s]'
%
str
(
i
)
c
=
net
.addController
(
name
,
controller
=
RemoteController
,
port
=
6661
+
i
)
controller_list
.append
(
c
)
print
"*** Creating %s"
%
name
print
"*** Creating switches"
switch_list
=
[
net
.addSwitch
(
's%d'
%
n
)
for
n
in
xrange
(
sw_num
)
]
print
"*** Creating hosts"
host_list
=
[
net
.addHost
(
'h%d'
%
n
)
for
n
in
xrange
(
host_num
)
]
print
"*** Creating links of host2switch."
for
i
in
xrange
(
0
,
sw_num
)
:
net
.addLink
(
switch_list
[
i
]
,
host_list
[
i
*
2
]
)
net
.addLink
(
switch_list
[
i
]
,
host_list
[
i
*
2
+
1
]
)
print
"*** Creating interior links of switch2switch."
for
i
in
xrange
(
0
,
sw_num
,
sw_num
/
con_num
)
:
for
j
in
xrange
(
sw_num
/
con_num
)
:
for
k
in
xrange
(
sw_num
/
con_num
)
:
if
j
!=
k
and
j
>
k
:
net
.addLink
(
switch_list
[
i
+
j
]
,
switch_list
[
i
+
k
]
)
print
"*** Creating intra links of switch2switch."
# 0-4 5-9 10-14 15-19 20-24 25-29 30-34
# domain1 -> others
net
.addLink
(
switch_list
[
4
]
,
switch_list
[
6
]
)
net
.addLink
(
switch_list
[
4
]
,
switch_list
[
10
]
)
net
.addLink
(
switch_list
[
1
]
,
switch_list
[
15
]
)
net
.addLink
(
switch_list
[
1
]
,
switch_list
[
20
]
)
# domain2 -> others
net
.addLink
(
switch_list
[
6
]
,
switch_list
[
10
]
)
net
.addLink
(
switch_list
[
8
]
,
switch_list
[
12
]
)
net
.addLink
(
switch_list
[
8
]
,
switch_list
[
18
]
)
net
.addLink
(
switch_list
[
7
]
,
switch_list
[
25
]
)
# domain3 -> others
net
.addLink
(
switch_list
[
10
]
,
switch_list
[
16
]
)
net
.addLink
(
switch_list
[
12
]
,
switch_list
[
16
]
)
net
.addLink
(
switch_list
[
10
]
,
switch_list
[
21
]
)
net
.addLink
(
switch_list
[
12
]
,
switch_list
[
27
]
)
# domain4 -> others
net
.addLink
(
switch_list
[
16
]
,
switch_list
[
21
]
)
net
.addLink
(
switch_list
[
18
]
,
switch_list
[
27
]
)
net
.addLink
(
switch_list
[
18
]
,
switch_list
[
31
]
)
net
.addLink
(
switch_list
[
19
]
,
switch_list
[
34
]
)
# domain5 -> others
net
.addLink
(
switch_list
[
21
]
,
switch_list
[
27
]
)
net
.addLink
(
switch_list
[
23
]
,
switch_list
[
31
]
)
# domain6 -> others
net
.addLink
(
switch_list
[
25
]
,
switch_list
[
31
]
)
net
.addLink
(
switch_list
[
27
]
,
switch_list
[
32
]
)
#domain7 has not need to add links.
print
"*** Starting network"
net
.build
(
)
for
c
in
controller_list
:
c
.start
(
)
_No
=
0
for
i
in
xrange
(
0
,
sw_num
,
sw_num
/
con_num
)
:
for
j
in
xrange
(
sw_num
/
con_num
)
:
switch_list
[
i
+
j
]
.start
(
[
controller_list
[
_No
]
]
)
_No
+=
1
#print "*** Testing network"
#net.pingAll()
print
"*** Running CLI"
CLI
(
net
)
print
"*** Stopping network"
net
.stop
(
)
if
__name__
==
'__main__'
:
setLogLevel
(
'info'
)
# for CLI output
multiControllerNet
(
con_num
=
7
,
sw_num
=
35
,
host_num
=
70
)
|
总结
Mininet功能很强大,基本可以满足日常的科研需求。最后,简单的启动脚本可以供参考。该脚本可以启动7个窗口,分别在不同的端口上启动7个ryu控制器,从而使得7个网络的交换机可以连接到对应的网络。
1
2
3
4
5
|
for
i
in
$
(
seq
1
7
)
;
do
let
port
=
i
+
6660
xterm
-
title
"app$i"
-
hold
-
e
ryu
-
manager
ryu
/
app
/
simple_switch_13
--
ofp
-
tcp
-
listen
-
port
=
$port
&
done
|
希望自己的研究能够顺利进行,最终面世。
作者简介:李呈,2014/09-至今,北京邮电大学信息与通信工程学院未来网络理论与应用实验室(FNL实验室)攻读硕士研究生。