上兩篇詣在說明控制器和交換機的交互,但是感覺還是沒有理的特別清楚
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的模塊,由模塊進行處理。至此交換機和控制器的數據就進入了各個模塊中進行處理。下一節應該學習學習模塊了.