• 沒有找到結果。

第二章 802.1ag 協定概要

2.4 Linktrace Protocol

2.4.1 Linktrace Message, Linktrace Reply

LTM 亦是 multi-cast 的封包,裡面的 destination_address 參數也是由 802.1ag 標準依據 MD Level 所規範,LTM 封包會一直被交換機所傳送直到封包到達適當 MD Level 上的 MP 為止。這一個 MP 會中止 LTM 的傳輸,並且將 LTM 封包轉 送到這個交換機的 Linktrace Responder 上面。

再者,Linktrace Responder 也會決定 MEP 或者 MIP 接收到 LTM 之後是否回 應 LTR 封包,至於判斷的依據,在 802.1ag 標準裡面有詳述[1]。

圖 2-4 Linktrace Protocol

我們用圖 2-4 來說明簡單的 Linktrace Protocol 運作方式。由 MEP A 製造 LTM 封包,讓 MIP B 以及 MIP C 都沿著路徑 B-C 傳送 LTR 回原點 MEP A,並朝著 MEP D 傳送 LTM 封包。故此協定可以達成路徑發現以及錯誤隔絕功能。

第三章 第三章 第三章 第三章 物件規劃

物件規劃 物件規劃

物件規劃、 、 、狀態圖 、 狀態圖 狀態圖以及事件處理 狀態圖 以及事件處理 以及事件處理 以及事件處理

3.1 物件規劃 物件規劃 物件規劃 物件規劃

在我們的程式中,規劃了如下列的物件。

Tester:為一個獨立的進程(Process),裡面包含著接收指令的線程(Thread)。

cliRcv: 用 來 接 收 並 處 理 管 理 人 員 指 令 的 線 程 , 為 CLI(Command Line Interface)的一部份。

MEP:由 CLI 下指令後所創造的一個線程,擁有收送封包(sniff 程式)的能力,

也是 802.1ag 協定中最重要的架構,裡面包含了 802.1ag 中定義的狀態機,

如 MEP Continuity Check Receiver、MEP Continuity Check Initiator…等等。

cliSend:為一個獨立的進程,此進程用意在於給予管理人員下達命令的介 面。並藉由訊息佇列(Message Queue)和 cliRcv 溝通。

3.2 狀態圖 狀態圖 狀態圖 狀態圖

再這一小節,我們陳述如何將 802.1ag 標準上面的狀態圖轉換成最終我們所 使用的程式碼。

3.2.1 MEP Continuity Check Receiver 在 在 在 在 802.1ag 標準內 標準內 標準內 標準內的表示 的表示 的表示 的表示

圖 3-1 802.1ag 標準內的 MEP Continuity Check Receiver

圖 3-1 為 802.1ag 標準上面 MEP Continuity Check Receiver 的狀態圖,我們 可以清楚看到裡面有四個狀態:HR_RESET、HR_IDLE、HR_RECORD_EQUAL 以及 HR_RECORD_LOW。

MEP Continuity Check Receiver 在被 MEP 創造出來時會先進入 HR_RESET 這個狀態,並且將兩個參數,CCMreceivedLow 以及 CCMreceivedEqual 設置成 false。接著狀態無條件的轉移(UCT)到 HR_IDLE,此時由於 CCMreceivedLow 以 及 CCMreceivedEqual 都是 false,所以狀態機便在此停住,完成了初始的動作。

等待有封包來時,Equal Opcode Demultiplexer 或者 Low Opcode Demultiplexer 的 觸發。Equal(Low) Opcode Demultiplexer 的功能是將接收到的 CFM 封包分門別 類,Equal 或者 Low 的差異在於接收到封包的 MD Level 與接收封包 MEP 的 MD Level 是相等或是較低。

假設 Equal(Low) Opcode Demultiplexer 判斷收到的 CFM 封包為 CCM,會先 更改 CCMreceivedEqual(CCMreceivedLow),之後再去觸發 MEP Continuity Check Receiver 的狀態圖,使得 MEP Continuity Check Receiver 的狀態會再從 HR_IDLE 進入 HR_RECORD_EQUAL(HR_RECORD_LOW),做完了該狀態的事情後,又 無條件的將狀態轉移到 HR_IDLE,等待下一次的觸發。

3.2.2 MEP Continuity Check Receiver 在 在 在 在 UML 工具上的表示 工具上的表示 工具上的表示 工具上的表示

圖 3-2 UML 工具內 MEP Continuity Check Receiver 的表示

圖 3-2 為使用 UML 工具的表示方法,同樣的我們也做四個狀態,名稱與 802.1ag 標準內的相對應。對於標準內的 UCT 部份,我們在工具內可以自己產生 給自己一個 evUCT 這樣的事件(使用 UML 工具中提供的 GEN()函式),使狀態可 以從_HR_RESET 轉移到_HR_IDLE。

而裡面的 evCCMreceivedEqual 或者 evCCMreceivedLow 皆是由 Equal(Low) Opcode Demultiplexer 對 MEP Continuity Check Receiver 來發送進而達到觸發的 效果,可以達到與 802.1ag 標準內相同行為的狀態圖。

3.2.3 MEP Continuity Check Receiver 更改後的程式碼 更改後的程式碼 更改後的程式碼 更改後的程式碼

最後我們將 UML 工具所產生出來的狀態圖做最後的轉換,取消了 UML 工 具之中 Event 功能,大幅減少了程式碼所佔用的記憶體。並且將整個狀態圖用一 個函式來概括,我們將其命名為 handle()。程式碼如下:

void MEPCCR::handle() {

//getItsMEP()->getMEP_config_ptr()->CCMreceivedLow=false;

//getItsMEP()->getMEP_config_ptr()->CCMreceivedEqual=false;

myState = _HR_IDLE;

else if( getItsMEP()->getMEP_config_ptr()->CCMreceivedEqual ) { myState = _HR_RECORD_EQUAL;

break;

case _HR_RECORD_LOW:

MEPprocessLowCCM();

getItsMEP()->getMEP_config_ptr()->CCMreceivedLow = false;

myState = _HR_IDLE;

getItsMEP()->getMEP_config_ptr()->CCMreceivedEqual = false;

myState = _HR_IDLE; 圖,我們還加上了 while 迴圈以及一個 stateCount 參數,用來控制這個 handle() 函數何時停止,何時應該繼續運作,何時應該無條件的轉移狀態。

3.2.4 MEP Continuity Check Initiator 在在 802.1ag 內的表示法 在 內的表示法 內的表示法 內的表示法

圖 3-3 802.1ag 標準內的 MEP Continuity Check Initiator

圖 3-3 為 802.1ag 標準內的另一個狀態機,我們用此狀態機來說明如何處理 有時間事件的狀況。

這個狀態機裡面只有兩個狀態,分別為 CCI_IDLE 以及 CCI_WAITING。首 先進入到 CCI_IDLE,經由判斷 CCIenabled 為真或假的值,來決定是否進入 CCI_WAITING 這個狀態。CCIenabled 也是一個讓 MEP Continuity Check Initiator 可否傳送 CCM 封包的重要參數。凡進入 CCI_WAITING 狀態,第一件事就是傳 送出一個 CCM 封包,由 xmitCCM()來達成,再來將 MACstatusChanged 設成 false,接著便是停留一段時間,這段停留的時間由 CCMtime()來做決定,不同的 CCMinterval 的設定對於 CCMtime()所造成的輸出都不相同。最後再判斷是否停 留在 CCI_WAITING 狀態(繼續的週期性發送 CCM 封包),亦或回到 CCI_IDLE 狀態(MEP Continuity Check Initiator 不工作)。值得注意的是,CCIenabled 是一個 可以由網路管理人員經過 CLI(Command Lind Interface)更改的參數。

3.2.5 MEP Continuity Check Initiator 在在 UML 工具上的表示 在 工具上的表示 工具上的表示 工具上的表示

圖 3-4 UML 工具內 MEP Continuity Check Initiator 的表示

我們先將 802.1ag 標準裡的 MEP Continuity Check Initiator 做成如圖 3-4,一 開始先進入_CCI_IDLE 之後,自動觸發(自己給予自己)事件 evCondition,先行判 斷 CCIenabled 為 真 或 假 , 才 決 定 是 否 進 入 _CCI_WAITING 。 一 旦 進 入 _CCI_WAITING 狀態,行為便和 3.2.4 小節陳述的相同。唯一要注意的地方是,

我們利用 UML 工具之中的 tm()函式來達到時間事件的處理,tm()這個函式就是 倒數計時,等到時間消耗掉之後,便去判斷後面的條件式,來決定是否停留在 _CCI_WAITING 或是回到_CCI_IDLE,只要 CCIenabled 持續的為 true(沒有被網 路管理人員設定為 false),那麼狀態機就會持續的保留在_CCI_WAITING 狀態,

並且每隔一段時間(由 tm()這個函數倒數時間),執行 xmitCCM()這個函式。

3.2.6 MEP Continuity Check Initiator 更改後的程式碼 更改後的程式碼 更改後的程式碼 更改後的程式碼

這一部份我們結合了 mepScheduler 來幫助我們達到時間事件的處理,主要 的函式便是 generateEvent(),我們要藉由這個函式,將狀態機與 mepScheduler 連 接起來,mepScheduler 需要在裡面置有事件後,執行 run()函式才有意義,至於 generateEvent()詳細的觀念與作法我們在 3.3.2.1 節 Real-Time Scheduler 概念中會 詳細闡述。

我們將 MEP Continuity Check Initiator 的程式碼完成如下:

void MEPCCI::handle(Event* ev_mepcci) { generateEvent();

stateCount = 1;

while ( stateCount ) { switch ( myState ) { case _CCI_IDLE:

if ( getItsMEP()->getMEP_config_ptr()->CCIenabled ) { myState = _CCI_WAITING;

stateCount = 1;

} else {

myState = _CCI_IDLE;

stateCount = 0;

} break;

case _CCI_WAITING:

xmitCCM();

itsMEP->getMEP_config_ptr()->MACstatusChanged = true;

if((getItsMEP()->getMEP_config_ptr()->CCMinterval==5)||(getItsMEP()->getMEP_config_ptr() ->CCMinterval==6) || (getItsMEP()->getMEP_config_ptr()->CCMinterval==7)) {

getItsMEP()->getMEP_config_ptr()->MACstatusChanged = true;

} else {

; }

if(itsMEP->getMEP_config_ptr()->CCIenabled&&( itsMEP->getMEP_config_ptr()->MA CstatusChanged||((getItsMEP()->getMEP_config_ptr()->CCIwhile)==0) ) ) {

myState = _CCI_WAITING;

stateCount = 0;

}

else if ( !(itsMEP->getMEP_config_ptr()->CCIenabled) ) { myState = _CCI_IDLE;

stateCount = 0;

這邊要注意,由於我們用 mepScheduler 取代了原本 UML 工具上的作法,所 以 MEP Continuity Check Initiator 的狀態機也需要做些許的改變,來符合與 802.1ag 標準定義的行為。

我們首先在 MEP 的 handle()函式裡面先執行 MEP Continuity Check Initiator 的 generateEvent()函式,如下程式碼所示:

void MEP::handle() {

addStateMachinesRelation();

initialMEP_config(getMEP_config_ptr());

setItsMepScheduler(p_mepScheduler);

itsMepScheduler->getPRealSche()->reset(); // mepScheduler first reset();

itsMEPCCI->generateEvent();

itsMepScheduler->getPRealSche()->run();

}

這樣可以使第一個事件加到 mepScheduler 裡面。但是僅這樣子就執行 mepScheduler 的 run()函式時,只會讓 MEP Continuity Check Initiator 的 handle() 被執行一次,而沒有辦法讓 MEP Continuity Check Initiator 持續被執行,原因在 於呼叫一次 generateEvent()只會讓 mepScheduler 裡面多一個事件。

有鑑於此,我們要讓 MEP Continuity Check Initiator 持續被執行,就必須要 在 MEP Continuity Check Initiator 的 handle()函式內加入 generateEvent(),使其每 執行一次 handle()時一開始又再執行 generateEvent(),將事件加入到 mepScheduler 裡面,讓 mepScheduler 裡面持續有事件。如此我們將 MEP Continuity Check Initiaor 這台狀態機加到 mepScheduler 裡面就可以持續被執行。

3.3 事件處理 事件處理 事件處理 事件處理

針對事件的處理,我們將其分為兩種類型,並且分別在實做上有不同的方法:

訊號事件(Signal Event):

自身觸發事件:802.1ag 標準內的 UCT(Unconditional Transition)即為此代表。

一般訊號事件:需要經由其他狀態機來觸發的事件。

時間事件(Time Event):

每隔一段時間就去執行一次的事件:802.1ag 裡面的 MEP Continuity Check Initiator 每隔一個時間週期就會傳送 CCM 封包,此種事件謂之時間事件。

3.3.1 訊號事件 訊號事件 訊號事件 訊號事件

圖 3-5 訊號事件狀態圖說明

圖 3-5 為訊號事件的範例,裡面所示的 evUCT、evCCMreceivedEqual 以及 evCCMreceivedLow 都是屬於訊號事件。在 UML 工具中,對於 evUCT 這種無條 件的狀態轉移,我們可以使用自身觸發事件,也就是進入狀態_HR_RESET 之後,

自己產生一個事件 evUCT 使狀態轉換到_HR_IDLE,要使用這樣的方法(自身觸 發)原因在於每個狀態都不應該平白無故的轉移,必須要有觸發(trigger)才會有狀

態轉移。而在我們最後所使用的程式碼中,是使用 while loop 與 stateCount 參數 來達成,或者不需要一個明顯的狀態來處理這樣的情況。

再者,對於 evCCMreceivedEqual 或者 evCCMreceivedLow 這兩個事件,並 不 是 由 自己 所 造成 , 在 802.1ag 標準之中,造成狀態由_HR_IDLE 轉換到 _HR_RECORD_EQUAL 或 者 _HR_RECORD_LOW 。 是 由 Equal Opcode Demultiplexer 或者 Low Opcode Demultiplexer 來觸發,所以理所當然的要由 Equal / Low Opcode Demultiplexer 產生事件給 MEP Continuity Check Receiver,觸發狀 態轉移。值得一提的是,在 UML 工具中有提供 GEN()這樣的函式可供使用來產

//getItsMEP()->getMEP_config_ptr()->CCMreceivedLow=false;

//getItsMEP()->getMEP_config_ptr()->CCMreceivedEqual=false;

myState = _HR_IDLE;

由_HR_RESET 狀態到_HR_IDLE 狀態就是 evUCT 的效果,只要搭配 while loop 以及控制的 stateCount 就可以輕易的做到這件事情,讓狀態無條件的轉移。

另外對於 evCCMreceivedEqual 或者 evCCMreceivedLow 這兩種由其他狀態 機觸發的事件,我們使用的方法也相當容易了解,在 3.2.3 我們有提到 MEP Continuity Check Receiver 的程式碼,裡面可以清楚看到,系統初始化時,

CCMreceivedEqual 以 及 CCMreceivedLow 皆 為 false , 所 以 狀 態 機 會 停 在 _HR_IDLE 的狀態並且設定 stateCount 為 0,被閒置在此狀態。當一個 CFM 封包 被 Equal Opcode Demultiplexer 給 判 斷 為 CCM 形 式 同 時 , Equal Opcode Demultiplexer 會再度呼叫 MEP Continuity Check Receiver 的狀態機,也就是再一 次的呼叫 MEP Continuity Check Receiver 的 handle()函式,此動作便是我們處理 evCCMreceivedEqual 或者 evCCMreceivedLow 的方法,簡單來說就是讓前一個狀 態機(Equal Opcode Demultiplexer)呼叫現在這個狀態機(MEP Continuity Check Receiver)的函式(handle()),就可以達成此種類型的訊號事件。

3.3.2 時間事件 時間事件 時間事件 時間事件

對 於 時 間 事 件 的 處 理 , 是 一 個 非 常 重 要 的 部 份 , 我 們 使 用 Real-Time Scheduler 來 針 對 時 間 事 件 做 一 系 列 的 處 理 動 作 。 在 我 們 的 程 式 碼 裡 面 的 Real-Time Scheduler 稱為 mepScheduler。

不使用 C 語言提供的 sleep()函式原因主要在於 multi-thread 狀況下使用 sleep() 可能會被搶走 CPU 的使用權而使狀態機的運行中斷而使行為與 802.1ag 標準內 規定的不符。而擁有越多時間事件,一般狀況都是在一個進程(Process)內增加線 程(Thread),這樣會相當耗費資源,使用 Scheduler 可以避免這樣的狀況產生。

3.3.2.1 Real-Time Scheduler 的概念 的概念 的概念 的概念

圖 3-6 Real-Time Scheduler 架構圖

圖 3-6 我們用來說明 mepScheduler 在運作前需要建立起來的物件關係圖。整 個 mepScheduler 之中最基本的 class 就是 Handler 以及 Event。

mepScheduler 這個 class 裡面主要的函式為 dispatch()、run()、reset()以及 schedule()。

reset():將 mepScheduler 初始化的函數,主要是將 clock 初始化。

schedule():狀態機將 Event 的指標、Event 當中 handler_的指標位置(其實就 是指到狀態機 handle()的位置)以及每個事件的延遲時間(Delay Time)給予 mepScheduler 的函數。

run():最後讓整個 mepScheduler 開始運作的函式。

dispatch():mepScheduler 去執行當下事件所用的函式,也就是不斷的去抓 handler_的位置來執行。

Handler 是對於所有事件最基本的 class,裡面擁有 handle()這個函數,型別 為 virtual,代表的就是要執行的時間事件,也就是擁有時間事件狀態機的 handle() 函式,使用 virtual 型別是為了給狀態機的 handle()函式繼承使用。

Event 這個 class 裡面擁有型別為 Handler 的 handler_指標,用意在於指到現

在要執行的時間事件(其實就是擁有時間事件狀態機 handle()函式)的位置。

當一個事件的排程時間到達,這個事件就需要被傳到 handler_指標上面去,

然後利用 Handler 之中的 handle()函式,也就是指到狀態機的 handle()函式將事件 消耗掉。

關於繼承的使用原因,在於本身 mepScheduler 的 Handler 已經寫好了對於 mepScheduler 以及 Event 之間的關係,如果不使用繼承,那只要有時間事件的狀

關於繼承的使用原因,在於本身 mepScheduler 的 Handler 已經寫好了對於 mepScheduler 以及 Event 之間的關係,如果不使用繼承,那只要有時間事件的狀

相關文件