ryu学习---利用socket
一 实验目的
本实验仅学习控制器与应用层如何通信,利用ryu实现hub,然后获取每次通信的dpid和port传输给应用层。拓扑结构如下:
记得都要关闭防火墙。
二 实验代码
本次实验,数据转发层面和控制层面都是在一台Ubuntu系统下面的mininet进行拓扑仿真的,在ryu运行编写好的程序,在另一台windows下运行编写好的server端程序。
(1)server程序
server端主要用于接收控制器的连接,并接收由控制器发送过来的信息,这里主要是dpid和port信息,也就是当主机h1、h2进行通信时,控制器收集通信时经过的端口和交换机id。
import socket
import re
def main():
server1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP
host = ''
port = 12345
server1.bind((host, port))
server1.listen(5)
while True:
conn, addr = server1.accept()
print("----------------------------")
print("Success connect from ", addr)
try:
count = 0
while True:
data = conn.recv(1024)
data = re.split(r'[, :]', data.decode('utf-8')) # 对收到的信息进行解析,包括dpid和port
count += 1
print("from {0}:dpid={1}, in_port={2}".format(addr, data[0], data[1]))
conn.close()
except Exception as error: # 当控制器和应用层断开连接后,输出统计信息
print('共接收{}条信息。'.format(count - 1))
print(error)
exit()
if __name__ == '__main__':
main()
(1)client程序
该实验以简单的hub为基础,在hub中写入client端程序实现控制器和应用层的通信。
from ryu.base import app_manager
from ryu.controller.handler import set_ev_cls
from ryu.controller.handler import MAIN_DISPATCHER, CONFIG_DISPATCHER
from ryu.controller import ofp_event
from ryu.ofproto import ofproto_v1_3
import socket
class L2Switch(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.dp_id = '0'
self.in_port = '0'
# 开启client,并连接server
self.client1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
dst_host = '192.168.0.100'
dst_port = 12345
# 防止server端连接不上影响hub的使用
try:
self.client1.connect((dst_host, dst_port))
except Exception as error:
print('Connect error:', error)
def add_flow(self, datapath, command, priority, match, actions):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
inst = [ofp_parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions)]
req = ofp_parser.OFPFlowMod(datapath=datapath, command=command,
priority=priority, match=match, instructions=inst)
datapath.send_msg(req)
# 控制器和交换机握手时,向交换机下发默认流表项
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
# add table-miss
command = ofp.OFPFC_ADD
match = ofp_parser.OFPMatch()
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_CONTROLLER, ofp.OFPCML_NO_BUFFER)]
self.add_flow(datapath, command, 0, match, actions)
@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
self.dp_id = dp.id
# 计算出in_port
start = str(msg).index('oxm_fields') + 11
end = str(msg).index('),reason')
inport_str = str(msg)[start:end]
instr = eval(inport_str)
self.in_port = instr['in_port']
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)]
data = None
if msg.buffer_id == ofp.OFP_NO_BUFFER:
data = msg.data
print('id:{0} in_port:{1}'.format(self.dp_id, self.in_port))
# 每次有信息经过交换机时,控制器就将获取的dpid和port发送给server
info = str(self.dp_id) + ',' + str(self.in_port)
self.client1.send(info.encode())
out = ofp_parser.OFPPacketOut(
datapath=dp, buffer_id=msg.buffer_id, in_port=self.in_port,
actions=actions, data=data)
dp.send_msg(out)
三 运行实验
(1)在mininet中创建拓扑
$ sudo mn --controller=remote --topo=single,2 --mac
(2)运行server端程序
(3)启动ryu程序
sudo ryu-manager hub_client.py --observe-links
ryu启动后,可以在server端控制台看见输出连接成功。
(4)h1 ping h2,观察输出信息
server端:
client端:
server与client断开通信:
打印共接收到多少条信息。