楔子:openflow1.3的狀態轉移圖
0.SDN交換機的TCP主動連接 8s一個包,
同樣的,tcp連接成功後,馬上發送hello包
之後8s一個Hello包
如果沒收到hello的回覆包,是不會進入下一狀態的,會一直重傳hello包
1.ryu控制器是如何發現SDN交換機的?
def serve(self):
send_thr = hub.spawn(self._send_loop)
# send hello message immediately
hello = self.ofproto_parser.OFPHello(self)
self.send_msg(hello) // 這一行是最重要的~~
echo_thr = hub.spawn(self._echo_request_loop)
try:
self._recv_loop() // 處理TCP連接發送過來的報文
finally:
hub.kill(send_thr)
hub.kill(echo_thr)
hub.joinall([send_thr, echo_thr])
self.is_active = False
可以試試把self.ofproto_parser.OFPHello(self) 這一行註釋掉,
然後你會發現找不到SDN交換機了(笑)因爲沒有hello的回覆包,無法進入下一狀態,
發送了hello包之後,纔會進入recv_loop協程,這個時候調用
@set_ev_handler(ofp_event.EventOFPHello, HANDSHAKE_DISPATCHER)
def hello_handler(self, ev):
......
......
features_request = datapath.ofproto_parser.OFPFeaturesRequest(datapath)
datapath.send_msg(features_request)
2.RYU控制器如何處理SDN交換機發送過來的TCP報文?
上面的recv_loop 就是,注意看源碼
@_deactivate
def _recv_loop(self):
buf = bytearray()
count = 0
min_read_len = remaining_read_len = ofproto_common.OFP_HEADER_SIZE
while self.state != DEAD_DISPATCHER:
try:
read_len = min_read_len
if remaining_read_len > min_read_len:
read_len = remaining_read_len
ret = self.socket.recv(read_len) # 先讀報文頭
except SocketTimeout:
continue
except ssl.SSLError:
# eventlet throws SSLError (which is a subclass of IOError)
# on SSL socket read timeout; re-try the loop in this case.
continue
except (EOFError, IOError):
break
if not ret:
break
buf += ret # 讀到的字節
buf_len = len(buf)
while buf_len >= min_read_len:
(version, msg_type, msg_len, xid) = ofproto_parser.header(buf) # 解析報文頭
if msg_len < min_read_len: # msg是包括報文頭的
# Someone isn't playing nicely; log it, and try something sane.
LOG.debug("Message with invalid length %s received from switch at address %s",
msg_len, self.address)
msg_len = min_read_len
if buf_len < msg_len: # 有可能開始讀的只是報文頭,
# 但是msg_len是真實的報文長度,這個時候需要退出並繼續讀
remaining_read_len = (msg_len - buf_len)
break
msg = ofproto_parser.msg(
self, version, msg_type, msg_len, xid, buf[:msg_len]) # 消息長度纔有意義
# LOG.debug('queue msg %s cls %s', msg, msg.__class__)
if msg:
ev = ofp_event.ofp_msg_to_ev(msg)
# print "in _recv_loop. ev_cls is %s" % ev.__class__
self.ofp_brick.send_event_to_observers(ev, self.state)
def dispatchers(x):
return x.callers[ev.__class__].dispatchers
handlers = [handler for handler in
self.ofp_brick.get_handlers(ev) if
self.state in dispatchers(handler)]
for handler in handlers:
# print "in _recv_loop, handler %s executed\n" % handler
handler(ev)
buf = buf[msg_len:] # 可能會有粘包的現象
buf_len = len(buf)
remaining_read_len = min_read_len
# We need to schedule other greenlets. Otherwise, ryu
# can't accept new switches or handle the existing
# switches. The limit is arbitrary. We need the better
# approach in the future.
count += 1
if count > 2048:
count = 0
hub.sleep(0)
3.一個完整的過程
4.OFPT_PACKET_IN報文 (無動作)
5.OFPT_PACKET_OUT響應報文
具體的報文