ryu--北向接口(流表的操作以及多控制器流表信息互通)
Posted 楊木木8023
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ryu--北向接口(流表的操作以及多控制器流表信息互通)相关的知识,希望对你有一定的参考价值。
实验目标:
(1)实现网络拓扑的各个主机之间的相互通信
(2)实现各个自治域的控制器的流表获取(各个控制器的流表信息互通)
(3)实现应用层对控制器的控制,进而实现对整个网络的控制
大致的实现效果如下:
实验原理:
利用mininet进行拓扑的模拟,构建多个控制器组成的网络。由于SDN网络留有北向接口,所以利用北向接口就可以对网络的流表等信息进行获取,在ryu中,ofctl_rest.py即是restapi的实现。本次实验,通过在docker中运行ryu控制器,同时运行ofctl_rest.py和simple_switch_13.py,然后利用python程序的get()、post()等方法对控制器的流表信息进行获取和添加,这样就实现了对流表信息的操作,同时也可以实现多个控制器流表信息的互通(公用一块公共的存储空间,如数据库),但是本次只演示基本的获取和流表的基本添加删除等操作。
实验拓扑构建:
工具:mininet进行拓扑搭建,Docker作为控制器
mininet构建实验拓扑,模拟自治域AS1和AS2,r4和r5作为自治域的边界路由器,实现域间路由。每个自治域由一台控制器控制(远端控制器最终运行在Docker上),若干台主机组成。最终通过配置路由表,实现域间的通信,实现整个网络架构各个主机之间的通信即为拓扑搭建完成。如图所示。
主机、交换机、控制器设置如下图所示。
各项设置完成无误后,运行网络拓扑。
路由表和Docker ryu配置:
(1)Docker ryu配置
关于Docker镜像ymumu/ryu:0.1:
可以参考文章(Docker命令、基于Docker的SDN实验环境部署(1)_北风-CSDN博客)
使用如下命令进行镜像ymumu/ryu的安装:
docker pull ymumu/ryu:0.1
新建两个Docker并且进行空间挂载,分别运行两个自治域的控制器,命令如下。
root@ymumu-VirtualBox:/home/ymumu# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ymumu/ryu 0.1 edb38c9e5a5c 3 weeks ago 719MB
root@ymumu-VirtualBox:/home/ymumu# docker run -it --name as1-ryu1 -v /home/ymumu/ryu/ryu/app:/home/ryu/ryu/app ymumu/ryu:0.1 /bin/bash
root@ymumu-VirtualBox:/home/ymumu# docker run -it --name as2-ryu1 -v /home/ymumu/ryu/ryu/app:/home/ryu/ryu/app ymumu/ryu:0.1 /bin/bash
以simple_switch_13为例,接下来,在各个Docker中开启ryu,命令步骤如下所示。其中,ofctl_rest.py是开启控制器的北向接口,simple_switch_13.py作为自学习交换机。
以上完成后,各个自治域内部的各个主机之间就可以通过自学习交换机进行通信,而不可以进行跨域通信,接下来就需要设置路由器和路由表。
(2)路由表配置
首先,设置两个路由器各个端口ip,命令如下。
mininet> r4 ip addr add 10.0.1.101/24 dev r4-eth0
mininet> r4 ip addr add 10.0.1.102/24 dev r4-eth1
mininet> r4 ip addr add 10.0.3.1/24 dev r4-eth2
mininet> r5 ip addr add 10.0.2.101/24 dev r5-eth0
mininet> r5 ip addr add 10.0.3.2/24 dev r5-eth1
接下来,设置路由器的路由表,命令如下。
# 添加路由表
mininet> r4 ip route add 10.0.2.0/24 via 10.0.3.2 dev r4-eth2
mininet> r5 ip route add 10.0.1.0/24 via 10.0.3.1 dev r5-eth1
# 查看路由器中的路由表
mininet> r4 ip r
10.0.1.0/24 dev r4-eth0 proto kernel scope link src 10.0.1.101
10.0.1.0/24 dev r4-eth1 proto kernel scope link src 10.0.1.102
10.0.2.0/24 via 10.0.3.2 dev r4-eth2
10.0.3.0/24 dev r4-eth2 proto kernel scope link src 10.0.3.1
mininet> r5 ip r
10.0.1.0/24 via 10.0.3.1 dev r5-eth1
10.0.2.0/24 dev r5-eth0 proto kernel scope link src 10.0.2.101
10.0.3.0/24 dev r5-eth1 proto kernel scope link src 10.0.3.2
然后,向各个主机添加路由表,为了简单起见,直接在各个主机中添加默认路由表,命令如下。
# 向as1-h1添加默认路由表
ip route add default via 10.0.1.101 dev as1-h1-eth0
# 向as1-h2添加默认路由表
ip route add default via 10.0.1.101 dev as1-h2-eth0
# 向as1-h3添加默认路由表
ip route add default via 10.0.1.102 dev as1-h3-eth0
# 向as2-h1添加默认路由表
ip route add default via 10.0.2.101 dev as2-h1-eth0
# 向as2-h2添加默认路由表
ip route add default via 10.0.2.101 dev as2-h2-eth0
以上所有路由表设置完成,网络中各个主机之间就可以相互通信了。
应用层编码
(1)原理
ryu控制器留有北向接口,即ofctl_rest.py,其通过restapi向应用层提供接口,应用层可以通过接口获取流表等信息并对流表进行操作。关于ryu的应用层接口的api使用,可以参考ryu docs:ryu.app.ofctl_rest — Ryu 4.34 documentation
通过文档可以知道,使用get()方法可以进行流表等信息的获取,使用post()方法可以实现流表等的下发操作,使用delete()方法可以实现流表等信息的删除。因此,使用pytho的get()等方法进行应用层程序的编写。
(2)获取流表
根据ryu docs中获取流表的方法为get(),url=http://ip:port/stats/flow/dpid,所以首先需要获取转发层面的控制器的dpid,获取dpid的url=http://ip:port/stats/switches,所以利用get()方法获取dpid,再根据dpid获取所有的流表,最后将流表显示出来。
# 通过get()获取交换机的dpid,并将其转化为16进制存入列表
def get_switch_id(self):
url = 'http://' + self.ip + ':' + self.port + '/stats/switches'
re_switch_id = requests.get(url=url).json()
switch_id_hex = []
for i in re_switch_id:
switch_id_hex.append(hex(i))
return switch_id_hex
# 通过get()和获取的dpid得到每一个交换机的流表项
def get_flow_table(self):
url = 'http://' + self.ip + ':' + self.port + '/stats/flow/%d'
list_switch = self.get_switch_id()
all_flow = []
for switch in list_switch:
new_url = format(url % int(switch, 16))
re_switch_flow = requests.get(url=new_url).json()
all_flow.append(re_switch_flow)
return all_flow
(3)下发流表操作(添加、删除、清空)
下发流表操作的方法使用post(),对于流表的添加,在ryu docs中使用的api的url=http://ip:port/stats/flowentry/add。然后,发送的信息包括,dpid,cookie,in_port在内的各项流表项信息。添加流表项的程序如下。
# 向控制器发送添加流表项的请求
def post_add_flow(self, dpid=None, cookie=0, priority=0, in_port=1, type='OUTPUT', port='CONTROLLER'):
url = 'http://' + self.ip + ':' + self.port + '/stats/flowentry/add'
if in_port == 'None':
# 添加的默认流表项数据信息
data = {
"dpid": dpid,
"cookie": cookie,
"cookie_mask": 0,
"table_id": 0,
"priority": priority,
"flags": 0,
"actions": [
{
"type": type,
"port": port
}
]
}
else:
in_port = int(in_port)
data = {
"dpid": dpid,
"cookie": cookie,
"cookie_mask": 0,
"table_id": 0,
"priority": priority,
"flags": 0,
"match": {
"in_port": in_port
},
"actions": [
{
"type": type,
"port": port
}
]
}
# 如果正确添加,则返回200OK
response = requests.post(url=url, json=data)
if response.status_code == 200:
print('Successfully Add!')
else:
print('Fail!')
删除流表项,即通过发送匹配信息,删除和指令匹配的流表项,在ryu docs中的url=http://ip:port/stats/flowentry/delete_strict,然后,发送的信息包括,dpid,cookie,in_port在内的各项流表项匹配信息。删除流表项的程序如下。
def post_del_flow(self, dpid=None, cookie=0, priority=0, in_port=1, type='OUTPUT', port='CONTROLLER'):
url = url = 'http://' + self.ip + ':' + self.port + '/stats/flowentry/delete_strict'
data = {
"dpid": dpid,
"cookie": cookie,
"cookie_mask": 1,
"table_id": 0,
"priority": priority,
"flags": 1,
"match": {
"in_port": in_port,
},
"actions": [
{
"type": type,
"port": port
}
]
}
response = requests.post(url=url, json=data)
if response.status_code == 200:
print('Successfully Delete!')
else:
print('Fail!')
对于清空流表项,在ryu docs中给出的例子,只需要用delete()方法向控制器请求特定url即可清空指定的交换机的流表项。程序如下。
def post_clear_flow(self, dpid=None):
url = 'http://' + self.ip + ':' + self.port + '/stats/flowentry/clear/' + str(dpid)
response = requests.delete(url=url)
if response.status_code == 200:
print('Successfully Clear!')
else:
print('Fail!')
接下来,就是主函数的编写,调用各个方法实现目标,这里不再叙述,文末有完整源码链接。
实验效果:
实验演示和操作如视频所示。
github源码地址:https://github.com/Yang-Jianlin/ryu/tree/master/ryu/app/ryu_restapi_operation
以上就是全部内容,如有疑问请私信或留言,谢谢。
以上是关于ryu--北向接口(流表的操作以及多控制器流表信息互通)的主要内容,如果未能解决你的问题,请参考以下文章