上两篇诣在说明控制器和交换机的交互,但是感觉还是没有理的特别清楚
http://blog.csdn.net/crystonesc/article/details/70143117
http://blog.csdn.net/crystonesc/article/details/70170482
今天打算结合openflow协议和代码来说明,openflow版本较多,我选了具有代表性的1.0和1.3版本进行学习,主要还是要搞清楚floodlight中控制器和交换机的交互过程.
前面的两篇文章讲到,控制器与交换机建立连接后,是通过netty的pipeline交由
net.floodlightcontroller.core.internal.OFChannelHandler
这个handler来处理,这个handler主要完成hello,Feature,echo的状态交互,完成这些简单的握手后,OFChannelHandler将连接传递给更高级的处理层面,它是:
net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler
那么这个handler完成更多复杂的交互.值得说明这两个handler都在其内部设置了类似于状态机的内部类来完成状态的切换,所以通过查看这两个状态类,能够很快的跟踪到交互的过程。以下是OFChannelHandler的状态机类:
OFSwitchHandshakeHandler 状态机类如下:
当然通过抓包也能够很快的看出交互的过程,以下分别为of1.0和of1.3的抓包截图:
具体这些交互过程在做什么这里不做具体的介绍,有兴趣可以参考
OpenFlow Switch Specification(1.0/1.3)
我们继续往下看代码,在交换机和控制器交互的过程中,控制器会声明自己的角色(master/slave/equal),这里多嘴一句,只有master的控制器才能对交换机进行写的操作,而slave状态的控制器只能够进行读操作。那么我们看看作为master的控制器要做哪些工作:
public class MasterState extends OFSwitchHandshakeState {
MasterState() {
super(true);
}
@Override
void enterState() {
if (OFSwitchManager.clearTablesOnEachTransitionToMaster) {
log.info("Clearing flow tables of {} on upcoming transition to MASTER.", sw.getId().toString());
//清除已有的流表
clearAllTables();
} else if (OFSwitchManager.clearTablesOnInitialConnectAsMaster && initialRole == null) { /* don't do it if we were slave first */
initialRole = OFControllerRole.ROLE_MASTER;
log.info("Clearing flow tables of {} on upcoming initial role as MASTER.", sw.getId().toString());
clearAllTables();
}
sendBarrier(); /* Need to make sure the tables are clear before adding default flows */
addDefaultFlows();
/*
* We also need a barrier between adding flows and notifying modules of the
* transition to master. Some modules might modify the flow tables and expect
* the clear/default flow operations above to have completed.
*/
sendBarrier();
setSwitchStatus(SwitchStatus.MASTER);
}
}
可以看到,在master状态的交换机,首先要清除交换机的流表信息,然后添加默认的流表信息,最后将交换机的中自己的角色设置为master。(交换机是不能够自己修改其中维护的controller的角色的)
同时处于master的控制器还承担这分发交换机上传消息的职责,例如pack_i数据包:
@Override
void processOFPacketIn(OFPacketIn m) {
dispatchMessage(m);
}
/**
* Dispatches the message to the controller packet pipeline
*/
private void dispatchMessage(OFMessage m) {
this.switchManager.handleMessage(this.sw, m, null);
}
@Override
public void handleMessage(IOFSwitchBackend sw, OFMessage m, FloodlightContext bContext) {
floodlightProvider.handleMessage(sw, m, bContext);
}
最终pack_in数据包的处理是在floodlightProvider中来处理,也就是controller类中.
//controller将消息分发到IOFMessageListeners
@Override
public void handleMessage(IOFSwitch sw, OFMessage m,
FloodlightContext bContext) {
Ethernet eth = null;
log.trace("Dispatching OFMessage to listeners.");
//如果contrller角色不是master,则不进行分发
if (this.notifiedRole == HARole.STANDBY) {
counters.dispatchMessageWhileStandby.increment();
// We are SLAVE. Do not dispatch messages to listeners.
return;
}
counters.dispatchMessage.increment();
switch (m.getType()) {
case PACKET_IN:
counters.packetIn.increment();
OFPacketIn pi = (OFPacketIn)m;
//获取packet-in消息的数据
if (pi.getData().length <= 0) {
log.error("Ignoring PacketIn (Xid = " + pi.getXid() + ") because the data field is empty.");
return;
}
//反序列化pack-in消息中的data
if (alwaysDecodeEth) {
eth = new Ethernet();
eth.deserialize(pi.getData(), 0, pi.getData().length);
}
// fall through to default case...
default:
List<IOFMessageListener> listeners = null;
if (messageListeners.containsKey(m.getType())) {
listeners = messageListeners.get(m.getType()).getOrderedListeners();
}
FloodlightContext bc = null;
if (listeners != null) {
// Check if floodlight context is passed from the calling
// function, if so use that floodlight context, otherwise
// allocate one
if (bContext == null) {
bc = flcontext_alloc();
} else {
bc = bContext;
}
if (eth != null) {
IFloodlightProviderService.bcStore.put(bc,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
eth);
}
// Get the starting time (overall and per-component) of
// the processing chain for this packet if performance
// monitoring is turned on
pktinProcTimeService.bootstrap(listeners);
pktinProcTimeService.recordStartTimePktIn();
Command cmd;
for (IOFMessageListener listener : listeners) {
pktinProcTimeService.recordStartTimeComp(listener);
cmd = listener.receive(sw, m, bc);
pktinProcTimeService.recordEndTimeComp(listener);
if (Command.STOP.equals(cmd)) {
break;
}
}
pktinProcTimeService.recordEndTimePktIn(sw, m, bc);
}
// paag
// And just before we exit the controller loop we see if anyone
// is interested in knowing that we are exiting the loop
for (IControllerCompletionListener listener : completionListeners)
listener.onMessageConsumed(sw, m, bc);
if ((bContext == null) && (bc != null)) flcontext_free(bc);
}
}
可以看出pack_in消息会通过controller传递给其它实现了IOFMessageListeners的模块,由模块进行处理。至此交换机和控制器的数据就进入了各个模块中进行处理。下一节应该学习学习模块了.