楔子: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响应报文
具体的报文