实验7:基于REST API的SDN北向应用实践
一、实验目的
- 能够编写程序调用OpenDaylight REST API实现特定网络功能;
- 能够编写程序调用Ryu REST API实现特定网络功能。
二、实验环境
- 下载虚拟机软件Oracle VisualBox或VMware;
- 在虚拟机中安装Ubuntu 20.04 Desktop amd64,并完整安装Mininet、OpenDaylight(Carbon版本)、Postman和Ryu;
三、实验要求
(一)基本要求
编写Python程序,调用OpenDaylight的北向接口实现以下功能
(1) 利用Mininet平台搭建下图所示网络拓扑,并连接OpenDaylight;


(2) 下发指令删除s1上的流表数据。

|
1
2
3
4
5
6
7
8
|
# delete.pyimport requestsfrom requests.auth import HTTPBasicAuthif __name__ == "__main__": url = 'http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/' headers = {'Content-Type': 'application/json'} res = requests.delete(url, headers=headers, auth=HTTPBasicAuth('admin', 'admin')) print (res.content) |
(3) 下发硬超时流表,实现拓扑内主机h1和h3网络中断20s。

|
1
2
3
4
5
6
7
8
9
10
|
# timeout.pyimport requestsfrom requests.auth import HTTPBasicAuthif __name__ == "__main__": url = 'http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/flow/1' with open("./timeout.json") as file: str = file.read() headers = {'Content-Type': 'application/json'} res = requests.put(url, str, headers=headers, auth=HTTPBasicAuth('admin', 'admin')) print (res.content) |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
# timeout.json{ "flow": [ { "id": "1", "match": { "in-port": "1", "ethernet-match": { "ethernet-type": { "type": "0x0800" } }, "ipv4-destination": "10.0.0.3/32" }, "instructions": { "instruction": [ { "order": "0", "apply-actions": { "action": [ { "order": "0", "drop-action": {} } ] } } ] }, "flow-name": "flow", "priority": "65535", "hard-timeout": "20", "cookie": "2", "table_id": "0" } ] } |
(4) 获取s1上活动的流表数。

|
1
2
3
4
5
6
7
8
|
# get.pyimport requestsfrom requests.auth import HTTPBasicAuthif __name__ == "__main__": url = 'http://127.0.0.1:8181/restconf/operational/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/opendaylight-flow-table-statistics:flow-table-statistics' headers = {'Content-Type': 'application/json'} res = requests.get(url,headers=headers, auth=HTTPBasicAuth('admin', 'admin')) print (res.content) |
编写Python程序,调用Ryu的北向接口实现以下功能
(1) 实现上述OpenDaylight实验拓扑上相同的硬超时流表下发。
(1) 实现上述OpenDaylight实验拓扑上相同的硬超时流表下发。
-
关闭ODL控制器,关闭上次的拓扑并清除拓扑后
-
使用命令
ryu-manager ryu.app.simple_switch_13 ryu.app.ofctl_rest打开Ryu控制器 -
![]()
-
使用命令
sudo mn --topo=single,3 --mac --controller=remote,ip=127.0.0.1,port=6633 --switch ovsk,protocols=OpenFlow13创建拓扑![]()
-
h1 ping h3,同时运行ryu硬超时运行ryu_timeout,h1 ping h3中断20秒
-
![]()
![]()
-
123456789
# ryu_timeout.pyimportrequestsif__name__=="__main__":url='http://127.0.0.1:8080/stats/flowentry/add'withopen("./ryu_timeout.json") asfile:str=file.read()headers={'Content-Type':'application/json'}res=requests.post(url,str, headers=headers)print(res.content)12345678910111213141516# ryu_timeout.json{"dpid":1,"cookie":1,"cookie_mask":1,"table_id":0,"hard_timeout":20,"priority":65535,"flags":1,"match":{"in_port":1},"actions":[]}(2) 参考Ryu REST API的文档,基于VLAN实验的网络拓扑,编程实现相同的VLAN配置。
提示:拓扑生成后需连接Ryu,且Ryu应能够提供REST API服务 -
1234567891011121314151617181920212223
#ryu_topo.pyfrommininet.topoimportTopoclassMyTopo(Topo):def__init__(self):# initilaize topologyTopo.__init__(self)self.addSwitch("s1")self.addSwitch("s2")self.addHost("h1")self.addHost("h2")self.addHost("h3")self.addHost("h4")self.addLink("s1","h1")self.addLink("s1","h2")self.addLink("s2","h3")self.addLink("s2","h4")self.addLink("s1","s2")topos={'mytopo': (lambda: MyTopo())}-
关闭控制器,关闭上一次实验的拓扑并清除拓扑
-
使用命令
ryu-manager ryu.app.simple_switch_13 ryu.app.ofctl_rest打开Ryu控制器 -
使用命令
sudo mn --custom topo.py --topo mytopo --mac --controller=remote,ip=127.0.0.1,port=6633 --switch ovsk,protocols=OpenFlow13创建拓扑 -
![]()
-
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
# ryu_vlan.pyimportjsonimportrequestsif__name__=="__main__":url='http://127.0.0.1:8080/stats/flowentry/add'headers={'Content-Type':'application/json'}flow1={"dpid":1,"priority":1,"match":{"in_port":1},"actions":[{"type":"PUSH_VLAN","ethertype":33024},{"type":"SET_FIELD","field":"vlan_vid","value":4096},{"type":"OUTPUT","port":3}]}flow2={"dpid":1,"priority":1,"match":{"in_port":2},"actions":[{"type":"PUSH_VLAN","ethertype":33024},{"type":"SET_FIELD","field":"vlan_vid","value":4097},{"type":"OUTPUT","port":3}]}flow3={"dpid":1,"priority":1,"match":{"vlan_vid":0},"actions":[{"type":"POP_VLAN","ethertype":33024},{"type":"OUTPUT","port":1}]}flow4={"dpid":1,"priority":1,"match": {"vlan_vid":1},"actions": [{"type":"POP_VLAN","ethertype":33024},{"type":"OUTPUT","port":2}]}flow5={"dpid":2,"priority":1,"match": {"in_port":1},"actions": [{"type":"PUSH_VLAN","ethertype":33024},{"type":"SET_FIELD","field":"vlan_vid","value":4096},{"type":"OUTPUT","port":3}]}flow6={"dpid":2,"priority":1,"match": {"in_port":2},"actions": [{"type":"PUSH_VLAN","ethertype":33024},{"type":"SET_FIELD","field":"vlan_vid","value":4097},{"type":"OUTPUT","port":3}]}flow7={"dpid":2,"priority":1,"match": {"vlan_vid":0},"actions": [{"type":"POP_VLAN","ethertype":33024},{"type":"OUTPUT","port":1}]}flow8={"dpid":2,"priority":1,"match": {"vlan_vid":1},"actions": [{"type":"POP_VLAN","ethertype":33024},{"type":"OUTPUT","port":2}]}res1=requests.post(url, json.dumps(flow1), headers=headers)res2=requests.post(url, json.dumps(flow2), headers=headers)res3=requests.post(url, json.dumps(flow3), headers=headers)res4=requests.post(url, json.dumps(flow4), headers=headers)res5=requests.post(url, json.dumps(flow5), headers=headers)res6=requests.post(url, json.dumps(flow6), headers=headers)res7=requests.post(url, json.dumps(flow7), headers=headers)res8=requests.post(url, json.dumps(flow8), headers=headers)![]()
-
![]()
(二)进阶要求
OpenDaylight或Ryu任选其一,编程实现查看前序VLAN实验拓扑中所有节点(含交换机、主机)的名称,以及显示每台交换机的所有流表项。
-
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
#getnodes.pyimportrequestsimporttimeimportreclassGetNodes:def__init__(self, ip):self.ip=ipdefget_switch_id(self):url='http://'+self.ip+'/stats/switches're_switch_id=requests.get(url=url).json()switch_id_hex=[]foriinre_switch_id:switch_id_hex.append(hex(i))returnswitch_id_hexdefgetflow(self):url='http://'+self.ip+'/stats/flow/%d'switch_list=self.get_switch_id()ret_flow=[]forswitchinswitch_list:new_url=format(url%int(switch,16))re_switch_flow=requests.get(url=new_url).json()ret_flow.append(re_switch_flow)returnret_flowdefshow(self):flow_list=self.getflow()forflowinflow_list:fordpidinflow.keys():dp_id=dpidswitchnum='{1}'.format(hex(int(dp_id)),int(dp_id))print('s'+switchnum,end=" ")switchnum=int(switchnum)forlist_tableinflow.values():fortableinlist_table:string1=str(table)ifre.search("'dl_vlan': '(.*?)'", string1)isnotNone:num=re.search("'dl_vlan': '(.*?)'", string1).group(1);ifnum=='0'andswitchnum==1:print('h1',end=" ")ifnum=='1'andswitchnum==1:print('h2',end=" ")ifnum=='0'andswitchnum==2:print('h3',end=" ")ifnum=='1'andswitchnum==2:print('h4',end=" ")print("")flow_list=self.getflow()forflowinflow_list:fordpidinflow.keys():dp_id=dpidprint('switch_name:s{1}'.format(hex(int(dp_id)),int(dp_id)))forlist_tableinflow.values():fortableinlist_table:print(table)s1=GetNodes("127.0.0.1:8080")s1.show()四、个人总结
- 通过本次实验,学习了使用OpenDaylight REST API和Ryu REST API实现调用网络功能,除此之外还进一步学习了python的request库。本次实验感觉比较难,综合了前几次的实验。在实验中要记得先把流表清空。还有curl的下载,按照百度的方法利用wget来下载,下了好几次都不行,最后用命令行里的提示,利用命令sudo apt install curl才下载成功。删除流表时,需要授权使用sudo curl -X DELETE http://localhost:8080/stats/flowentry/clear/1。
-
-







浙公网安备 33010602011771号