Floodlight 使用的是Netty架构,在Controller.java 入口函数中显示创建ServerBootstrap,设置套接字选项,ChannelPipeline,此时监听套接字就准备优点理来自SW的各种消息;这里最核心的就是 OpenflowPipelineFactory ,会增加各个业务相关的Handler,代码例如以下:
public
ChannelPipeline getPipeline()
throws
Exception {
OFChannelState state =
new
OFChannelState();
ChannelPipeline pipeline = Channels. pipeline();
pipeline.addLast(
"ofmessagedecoder"
,
new
OFMessageDecoder());
pipeline.addLast(
"ofmessageencoder"
,
new
OFMessageEncoder());
pipeline.addLast(
"idle"
,
idleHandler
);
pipeline.addLast(
"timeout"
,
readTimeoutHandler
);
pipeline.addLast(
"handshaketimeout"
,
new
HandshakeTimeoutHandler(state,
timer
, 15));
if
(
pipelineExecutor
!=
null
)
pipeline.addLast(
"pipelineExecutor"
,
new
ExecutionHandler(
pipelineExecutor
));
//OFChannelHandler 是核心
pipeline.addLast(
"handler"
,
controller
.getChannelHandler(state));
return
pipeline;
}
接下来的main loop就是处理交换机或者Controller角色变化等消息,这是我们关注的地方,代码例如以下:
// main loop
// 不断处理堵塞队列中SW的更新信息
while
(
true
) {
try
{
IUpdate update =
updates.take();
update.dispatch();
}
catch
(InterruptedException e) {
return
;
}
catch
(StorageException e) {
log
.error(
"Storage exception in controller "
+
"updates loop; terminating process"
, e);
return
;
}
catch
(Exception e) {
log
.error(
"Exception in controller updates loop"
, e);
}
}
那么Controller中的BlockingQueue中的更新信息是在何时增加的呢?这里仅仅跟踪交换机增加的情况,非常easy想到当监听套接字收到一个来自OF SW请求的时候。所以我们看 OFChannelHandler ,能够视为是业务相关的第一个UpstreamHandler,在通道连接的时候会回送一个HELLO消息,这里的重点看处理消息的过程,进入函数 messageReceived 接下来的处理流程(例如以下),在收到 GET_CONFIG_REPLY 消息之后说明这个SW准备好了(会把握手状态改为 HandshakeState.READY),而后会把这个SW增加到activeSwitches 和 updates中:
更新堵塞队列的代码是:
updateActiveSwitchInfo(sw);
SwitchUpdate update =
new
SwitchUpdate(sw,
true
);
try
{
// 把update加到BlockingQueue里,假设BlockQueue没有空间,则调用此方法的线程被阻断
// 直到BlockingQueue里面有空间再继续.
this
.
updates
.put(update);
}
catch
(InterruptedException e) {
log
.error(
"Failure adding update to queue"
, e);
}
通过上面的分析,相当于有了一个生产消费者模型,生产者就是交换机的增加或者移除消息,消费者就是Controller的处理过程,取出消息进行计算,为拓扑更新服务。详细过程仍然是一个监听者模式,把SW的更新信息分发到各个订阅者中进行处理(看SwitchUpdate类),代码例如以下:
public
void
dispatch() {
if
(
log
.isDebugEnabled()) {
log
.debug(
"Dispatching switch update {} {}"
,
sw
,
added
);
}
// 遍历这些listeners,处理增加或移除事件
if
(
switchListeners
!=
null
) {
for
(IOFSwitchListener listener :
switchListeners
) {
if
(
added
)
listener.addedSwitch(
sw
);
else
listener.removedSwitch(
sw
);
}
}
}
那么订阅 SwitchUpdate 消息的类是谁呢?LinkDiscoveryManager!交换机的增加或者移除活动肯定会带来链路信息的改变,当增加一个新SW的时候,就会通过发送 LLDP frame 来发现拓扑结构(參见 Floodlight Controller 路由原理 )。代码例如以下
public
void
addedSwitch(IOFSwitch sw) {
//这里的设计须要优化
// It's probably overkill to send LLDP from all switches, but we don't
// know which switches might be connected to the new switch.
// Need to optimize when supporting a large number of switches.
sendLLDPTask
.reschedule(2000, TimeUnit.
MILLISECONDS
);
// Update event history
evHistTopoSwitch(sw, EvAction.
SWITCH_CONNECTED
,
"None"
);
}