ryu控制器在SDN三层架构中是处于中间层,(如图1)
图1 SDN三层架构
如何实现与应用层的通信,如图1所示,实现RYU控制器与应用层(如开发应用web界面时数据可视化平台)数据通信就需要利用SDN的北向接口。北向接口实现的功能就时某个应用软件实体与控制器中的数据的通信。本文,我们将用socket编程就能轻易实现应用层与RYU控制器之间的数据通信以及简单展示
实现拓扑逻辑原理
三、实现代码
服务端(在ubuntu上)
server端主要用于接收控制器的连接,并接收由控制器发送过来的信息,这里主要是dpid和port信息,也就是当主机h1、h2进行通信时,控制器收集通信时经过的端口和交换机id
具体代码:
import socket
import redef main():server1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCPhost = '10.0.0.2' #ubuntu地址,开启服务功能,用来给ryu主动连接提交数据port = 12345 #开放端口,自主定义一般大于1024server1.bind((host, port))server1.listen(5)while True:conn, addr = server1.accept()print("----------------------------")print("Success connect from ", addr)try:count = 0while True:data = conn.recv(1024)data = re.split(r'[, :]', data.decode('utf-8')) # 对收到的信息进行解析,包括dpid和portcount += 1print("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()
mininet拓扑代码
ryu
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 socketclass 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'self.client1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)dst_host = '10.0.0.2'dst_port = 12345try:self.client1.connect((dst_host, dst_port))except Exception as error:print('Connect error:', error)def doflow(self, datapath, command, priority, match, actions):ofp = datapath.ofprotoofp_parser = datapath.ofproto_parserinst = [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.msgdatapath = msg.datapathofp = datapath.ofprotoofp_parser = datapath.ofproto_parser# add table-misscommand = ofp.OFPFC_ADDmatch = ofp_parser.OFPMatch()actions = [ofp_parser.OFPActionOutput(ofp.OFPP_CONTROLLER, ofp.OFPCML_NO_BUFFER)]self.doflow(datapath, command, 0, match, actions)@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)def packet_in_handler(self, ev):msg = ev.msgdp = msg.datapathofp = dp.ofprotoofp_parser = dp.ofproto_parserself.dp_id = dp.idstart = str(msg).index('oxm_fields') + 11end = 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 = Noneif msg.buffer_id == ofp.OFP_NO_BUFFER:data = msg.dataprint('id:{0} in_port:{1}'.format(self.dp_id, self.in_port))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)
四、实验测试
注意启动步骤:(如图中编号)
扩展,如何把服务器上收集的数据存入一个文件
将数据存储为Excel文件(.xlsx),您可以使用第三方库如openpyxl来实现。以下是将数据存储到Excel文件的修改版本:
import openpyxl
import socket
import redef main():server1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCPhost = '10.0.0.2' # ubuntu地址,开启服务功能,用来给ryu主动连接提交数据port = 12345 # 开放端口,自主定义一般大于1024server1.bind((host, port))server1.listen(5)# 创建Excel文件并写入表头workbook = openpyxl.Workbook()sheet = workbook.activesheet.append(['Address', 'DPID', 'In_Port']) # 表头while True:conn, addr = server1.accept()print("----------------------------")print("Success connect from ", addr)try:count = 0while True:data = conn.recv(1024)data = re.split(r'[, :]', data.decode('utf-8')) # 对收到的信息进行解析,包括dpid和portcount += 1print("from {0}: dpid={1}, in_port={2}".format(addr, data[0], data[1]))# 将数据写入Excel文件sheet.append([addr, data[0], data[1]])except Exception as error: # 当控制器和应用层断开连接后,输出统计信息print('共接收{}条信息。'.format(count - 1))print(error)workbook.save('data.xlsx') # 保存Excel文件exit()if __name__ == '__main__':main()
在上述代码中,我们使用了openpyxl库来创建并写入Excel文件。在循环中,每次接收到数据时,将数据写入Excel文件的工作表中。最后,使用workbook.save方法保存Excel文件
方法2
可以使用Python的CSV模块来实现。以下是将数据存储到CSV文件的修改版本:
import csv
import socket
import redef main():server1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCPhost = '10.0.0.2' # ubuntu地址,开启服务功能,用来给ryu主动连接提交数据port = 12345 # 开放端口,自主定义一般大于1024server1.bind((host, port))server1.listen(5)# 创建CSV文件并写入表头with open('data.csv', 'w', newline='') as csvfile:writer = csv.writer(csvfile)writer.writerow(['Address', 'DPID', 'In_Port']) # 表头while True:conn, addr = server1.accept()print("----------------------------")print("Success connect from ", addr)try:count = 0while True:data = conn.recv(1024)data = re.split(r'[, :]', data.decode('utf-8')) # 对收到的信息进行解析,包括dpid和portcount += 1print("from {0}: dpid={1}, in_port={2}".format(addr, data[0], data[1]))# 将数据写入CSV文件writer.writerow([addr, data[0], data[1]])except Exception as error: # 当控制器和应用层断开连接后,输出统计信息print('共接收{}条信息。'.format(count - 1))print(error)exit()
if __name__ == '__main__':main()
在上述代码中,我们使用了csv模块来创建并写入CSV文件。在循环中,每次接收到数据时,将数据写入CSV文件中。
在服务端所在文件的通目录下(默认情况)可以检测到有有新生成的文件data .csv用记事本打开可以看到相关的数据