根據 Ryu 所提供的官方文件第一個實作的應用程式,他們把它稱為
dumb layer 2 switch 我很好奇為什麼稱呼他為 dumb layer 2 switch

或許是因為 dumb(愚笨的)的關係?在他的 source code 中表現出來的行為,我覺得它更像是一台 layer 1 的 Hub。

稍微複習一下 Hub 與 Switch 的差別,其實很容易區分它們二者的差異性。

  • Hub(集線器):
    網路層級中屬於 L1 同一個集線器底下所有的 host 連接的 port 都是可以互通的,也就是說 host A 傳給 host B 是以 Broadcasting 的方式送出去,而在集線器底下所有的 host 都能看見這個封包,其他的 host 雖然會收到,但是因為接收者不是他,就直接丟棄了(但也可以不丟棄,因此有網路安全上的疑慮)。

  • Switch(交換器) :
    交換器與集線器最大的差別就在於,交換器能依照每一個 port 記錄每一個 host 的 MAC Address 因此不再需要每次都以 Broadcasting 的方式送資料,而是針對性的對某一個 port 發送資料,每一個 port 都是獨立的。
    但是它在第一次接上數個 host 時並不知道哪一個 port 對應到哪一個 host 它會經過學習(MAC learning),而建立一張表。

接著來看看第一個程式 DumbL2Switch.py

DumbL2Switch.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls

class L2Switch(app_manager.RyuApp):
def __init__(self, *args, **kwargs):
super(L2Switch, self).__init__(*args, **kwargs)

@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
ofp_parser = dp.ofproto_parser

actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)]
out = ofp_parser.OFPPacketOut(
datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port,
actions=actions)
dp.send_msg(out)

稍微 不負責任地 解讀一下這個應用程式

在定義 packet_in_handler() 函式之前加上 @ 修飾子的語法(decorator)依我對 decorator 的理解。它是用來對 packet_in_handler() 函式做包裝(修飾),可以在 packet_in_handler() 函式的進入點及離開點增加一些行為,換句話說 @set_ev_cls 幫你做了某些事,是在進入 packet_in_handler() 之後或離開之前幫你做完某些事情。

至於實際上做了什麼事情,這邊我不太了解需要去追一下這段程式碼,不過可以確定的是需要傳兩個參數進去 ofp_event.EventOFPPacketInMAIN_DISPATCHER

packet_in_handler() 如同函式的名稱一樣,當封包來的時候要處理些什麼事情,裏面做的事情很單純 msg.datapath 拿到 datapath,dp.ofprotodp.ofproto_parser 得到 OpenFlow protocol

重點在 ofp_parser.OFPActionOutput() 做出 ofp.OFPP_FLOOD 意思是向所有的 Physical ports 發送訊息,其物理意義是廣播(Broadcasting)

最後由 ofp_parser.OFPPacketOut() 把所有資訊做個包裝,再用 dp.send_msg 送出去。