ryu---北向接口(利用socket对外通信)
Posted 楊木木8023
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ryu---北向接口(利用socket对外通信)相关的知识,希望对你有一定的参考价值。
一、原理
最近有人问ryu控制器如何实现与应用层(如web、app等)的通信,实际上,实现通信就需要利用SDN的北向接口,关于SDN的北向接口,各种文章的解释不一,难以理解。实质上,北向接口实现的功能就是和两个软件实体之间的通信无任何区别,也就是说,北向接口不需要任何新的协议,只要会写简单的socket编程就能轻易实现应用层与控制层之间的通信。下面我介绍一下如何使用python的socket编程实现控制器和应用层之间的通信。
关于python socket编程参考:https://blog.csdn.net/weixin_40042248/article/details/114779625?spm=1001.2014.3001.5501
二、网路拓扑及实施原理
这个实验,仅仅演示控制器与应用层如何通信,所以为了便于理解,本次实验以hub为例,也就是利用ryu实现hub,然后获取每次通信的dpid和port传输给应用层。拓扑结构如下。
三、实验代码编写
本次实验,数据转发层面和控制层面都是在Ubuntu虚拟机下面的mininet进行拓扑仿真的,在ryu运行编写好的程序,在宿主机中运行编写好的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 = '10.50.177.208'
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()
(2)ryu程序编写
本次实验以简单的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 = '10.50.177.208'
dst_port = 12345
# 防止server端连接不上影响hub的使用
try:
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.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.doflow(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中构建完成拓扑后,运行拓扑。
(2) 在宿主机中,运行server端,本次实验直接在win下的pycharm编写server端运行。
(3) 启动ryu程序,如图所示。
ryu启动之后,就可以在server端控制台看见输出连接成功。
(4) 接下来,在mininet命令行输入h1 ping h2,此时可以发现server端输出了dpid和port信息,同时ryu也打印出了信息。
实验完成,可以发现实验实现了控制层和应用层的简单通信,原理非常简单。
GitHub源码地址:
https://github.com/Yang-Jianlin/ryu/blob/master/ryu/app/north_socket_yjl.py
https://github.com/Yang-Jianlin/ryu/blob/master/ryu/app/server.py
以上是关于ryu---北向接口(利用socket对外通信)的主要内容,如果未能解决你的问题,请参考以下文章