RYU多控制器通信
随着SDN控制平面不断扩展,单一的控制器很难满足需求,这时候部署多个控制器是势在必行的,一旦部署了多控制器,如何使它们协同工作就成了亟待解决的问题。Ryu是基于Python的控制器,不像java类型的控制器一样带有集群功能,不过好在比java方便,本篇文章就介绍一下如何利用C/S架构进行多控制器之间的通信。
设计原理
因为控制器一旦运行,就要占用一个TCP端口,如果跟其他控制器直接通信,需要再占用其他端口,如果控制器数量很多,那么控制器全互联的代价很大,配置也很不方便。为了解决这个问题,我们设置一个第三方服务器,其他的控制器都与服务器建立连接,把信息发送给服务器,这样既能够让控制器专注于控制网络,也使得网络层次更加分明。每个控制器相当于一个客户端,自己持有自己那部分网络的信息,同时为了获得其他网络的信息而不断与服务器进行交互。
为了创建一个高效方便的服务器,我们使用gevent的StreamServer模块。
gevent 是一个基于协同程序的Python网络库,它以greenlet为核心,提供了非常高的并发性能,简单的说就是可以让多线程更加高效,StreamServer是一个通用的TCP服务器,当客户端连接到它的时候可以运行用户提供的处理函数。
StreamServer的定义是这样的:
class StreamServer(listener, handle=None, backlog=None, spawn='default', **ssl_args)
在Ryu中lib/hub.py中可以找到这个类的定义。
服务器设计
作为服务器,我们需要监听客户端的请求,同时还需要与客户端通信,还要存储客户端传来的数据,那么它的结构是下面这样
每一个控制器连接到服务器时,服务器都会分出一个线程来建立连接,然后再启动用于服务器和控制器通信的线程,当控制器传过来数据时,负责连接控制器的线程会把数据存到服务器中。传输的消息采用json格式,方便读取。
with contextlib.closing(Client(socket)) as client:
client.server = self
client_id = len(self.clients)+1
client.set_id(client_id)
self.clients[client_id] = client
client.start()
客户端设计
作为客户端的控制器只需要在启动后连接到服务器(要先保证服务器已经启动),然后创建线程接受和发送消息即可。要发送的消息储存再发送队列,由发送线程周期性发送。
def _send_loop(self):
try:
while self.status:
message = self.send_queue.get()
message += '\n'
self.socket.sendall(message)
finally:
self.send_queue = None
实验验证
下面做一个简单的检测全局拓扑的实验
拓扑是这样的:
c1 c2
/ \ / \
s1 s2 s3 s4
| | | |
h1 h2 h3 h4
每个控制器的输出表明,每个控制器只能检测到连接到自己的交换机之间的链路
而服务器的输出则展示了全局拓扑
总结
多控制器的应用越来越广泛,C/S架构是一种简单的多控制器之间通信模式,通过服务器收集所有控制器的信息,可以实现网络模块化,分布式部署以及交换机迁移等功能,对于管理者来说也十分方便,源码已上传Github,希望本文能够对读者有所帮助。