POX 控制器
默认拓扑
如果我们不指定控制器直接运行 Mininet 提供给我们的默认拓扑:
sudo mn
你会发现节点间是 ping 得通的,因为默认的控制器进行 l2 层学习获得了流表。
要使用 POX 的远程交换机,你可以这样做:
$ cd ~/pox
$ ./pox.py forwarding.l2_learning
在另一个窗口,启动 Mininet 连接到“远程”控制器(这实际上是在本地运行,但 Mininet 的控制范围之外):
$ sudo mn --controller=remote, ip=127.0.0.1, port=6633
注意,这些其实都是默认的 IP 地址和端口值。
要进入命令行模式的话:
python pox.py openflow.of_01 py
下发流表(因为我想让两边 ping 通,所以应该配正反两条流表规则,以下只是单方向的):
POX> from pox.lib.addresses import IPAddr
POX> from pox.lib.addresses import EthAddr
POX> import pox.openflow.libopenflow_01 as of
POX> core.openflow.connections.keys()
[1]
POX> msg=of.ofp_flow_mod()
POX> msg.priority=3 # 数字越大, 优先级越高
POX> msg.match.nw_src="10.0.0.1"
POX> msg.match.in_port=2
POX> msg.actions.append(of.ofp_action_output(port=1))
POX> core.openflow.connections[1].send(msg) # 这个 1 就是 connections.keys() 返回的 1
反方向的流表只要交换一下出入端口就 OK 了。
看一看 Mininet 这边,在配流表之前,ping 不通:
mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
mininet> pingall
*** Ping: testing ping reachability
h1 -> X
h2 -> X
*** Results: 100% dropped (0/2 received)
配了单方向流表以后,依然 ping 不通:
mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=4.827s, table=0, n_packets=0, n_bytes=0, idle_age=4, priority=5,in_port=1 actions=output:2
mininet> h1 ping h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
From 10.0.0.1 icmp_seq=1 Destination Host Unreachable
From 10.0.0.1 icmp_seq=2 Destination Host Unreachable
From 10.0.0.1 icmp_seq=3 Destination Host Unreachable
^C
--- 10.0.0.2 ping statistics ---
5 packets transmitted, 0 received, +3 errors, 100% packet loss, time 4000ms
配了双向的以后:
mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=151.371s, table=0, n_packets=15, n_bytes=630, idle_age=22, priority=5,in_port=1 actions=output:2
cookie=0x0, duration=4.423s, table=0, n_packets=0, n_bytes=0, idle_age=4, priority=5,in_port=2 actions=output:1
mininet> h1 ping h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.208 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.035 ms
^C
--- 10.0.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.035/0.121/0.208/0.087 ms
mininet> pingall
*** Ping: testing ping reachability
h1 -> h2
h2 -> h1
*** Results: 0% dropped (2/2 received)
成功了!
【注】交换机的端口号一般就是从 1 按顺序的,可以在启动 Mininet 以后新打开一个窗口用下面的命令查看都有哪些端口:
$ sudo ovs-vsctl show
0072de5e-fdb2-4e99-91e7-4f5d33acfa10
Bridge "s1"
Controller "tcp:127.0.0.1:6633"
is_connected: true
Controller "ptcp:6654"
fail_mode: secure
Port "s1-eth2" # 端口 2
Interface "s1-eth2"
Port "s1"
Interface "s1"
type: internal
Port "s1-eth1" # 端口 1
Interface "s1-eth1"
ovs_version: "2.5.4"
POX 控制器里指定端口时不能用字符串,只能用数字,"s1-eth1" 和 "s1-eth2" 写成 1 和 2 就好。
(至于端口对应着哪台主机,可以从网页上看,不知道有没有什么直观的从命令行上就可以查看的方式?或者由 API 指定?)
问题解决,这个顺序是按照 AddLink 的顺序,比如 h1 和 h2 先后与 s1 连,那么 h1 就是端口 1 上的,h2 是端口 2 上的。当然也可以直接在 API 中指定,如:
# specify a different port to connect host 5 to switch 1
net.addLink( h5, s1, 1, 9 ) # h5 的 port 1 连接 s1 的 port 9 (注意如果没定义端口 1 就去定义端口 2 会报错)
另外如果不正常退出 Mininet 或 POX 的话,会对下一次运行产生影响,所以最好用 exit
退出 Mininet,用 Ctrl-D 退出 POX。不然就要 sudo mn -c
来清理 Mininet 的缓存,并手动 kill POX 的进程。
POX 的 API 可以查看这里,是相对很全的了。
自定义拓扑
利用 Mininet 的 Python API 可以很方便地开发各种拓扑以及连接远程控制器。给出一个示例:
#!/usr/bin/python
#coding=utf-8
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel
from mininet.cli import CLI
from mininet.node import RemoteController
class SingleSwitchTopo(Topo):
def __init__(self, **opts):
Topo.__init__(self, **opts)
switch1 = self.addSwitch( 's1' ) # 添加交换机到拓扑中
switch2 = self.addSwitch( 's2' )
switch3 = self.addSwitch( 's3' )
host1 = self.addHost( 'h1' ) # 添加主机到拓扑中
host2 = self.addHost( 'h2' ) # 添加主机到拓扑中
self.addLink( host1, switch1 )
self.addLink( host2, switch2 ) # 添加双向连接
self.addLink( switch2, switch1 )
self.addLink( switch2, switch3 )
self.addLink( switch3, switch1 )
def simpleTest():
topo = SingleSwitchTopo()
net = Mininet(topo) # 主要类来创建和管理网络
mycontroller = RemoteController("c0", ip = "127.0.0.1", port=6633) # 创建远程控制器 (控制器的命名最好是 "c数字", 否则可能报错)
net.controllers = [mycontroller]
net.start() # 启动拓扑网络
print "Dumping host connections"
dumpNodeConnections(net.hosts) # 输出指定的网络信息
print "Testing network connectivity"
net.pingAll() # 所有节点彼此测试互连
# CLI(net) # 进入 mininet> 提示符
net.stop() # 停止网络
if __name__ == '__main__':
setLogLevel('info') # 设置 Mininet 默认输出级别,设置 info 它将提供一些有用的信息
simpleTest()
更多 API 参见:http://mininet.org/api/annotated.html