实验7:基于REST API的SDN北向应用实践
一、实验目的
1.能够编写程序调用OpenDaylight REST API实现特定网络功能;
2.能够编写程序调用Ryu REST API实现特定网络功能。
二、实验环境
1.下载虚拟机软件Oracle VisualBox或VMware;
2.在虚拟机中安装Ubuntu 20.04 Desktop amd64,并完整安装Mininet、OpenDaylight(Carbon版本)、Postman和Ryu;
三、实验要求
(一)基本要求
1.编写Python程序,调用OpenDaylight的北向接口实现以下功能
(1) 利用Mininet平台搭建下图所示网络拓扑,并连接OpenDaylight;
(2) 下发指令删除s1上的流表数据。
(3) 下发硬超时流表,实现拓扑内主机h1和h3网络中断20s。
(4) 获取s1上活动的流表数。
2.编写Python程序,调用Ryu的北向接口实现以下功能
(1) 实现上述OpenDaylight实验拓扑上相同的硬超时流表下发。
(2) 参考Ryu REST API的文档,基于VLAN实验的网络拓扑,编程实现相同的VLAN配置。
提示:拓扑生成后需连接Ryu,且Ryu应能够提供REST API服务
VLAN_ID Hosts
0 h1 h3
1 h2 h4
(二)进阶要求
OpenDaylight或Ryu任选其一,编程实现查看前序VLAN实验拓扑中所有节点(含交换机、主机)的名称,以及显示每台交换机的所有流表项。
(三)实验报告
1.(1) 利用Mininet平台搭建下图所示网络拓扑,并连接OpenDaylight:
1.(2) 下发指令删除s1上的流表数据:
delete.py代码:
1 2 3 4 5 6 7 8 |
# delete.py
import requests
from requests.auth import HTTPBasicAuth
if __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)
|
1.(3) 下发硬超时流表,实现拓扑内主机h1和h3网络中断20s:
timeout.py代码:
1 2 3 4 5 6 7 8 9 10 |
# timeout.py
import requests
from requests.auth import HTTPBasicAuth
if __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)
|
timeout.json代码:
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"
}
]
}
|
1.(4) 获取s1上活动的流表数:
getflow.py代码:
1 2 3 4 5 6 7 8 |
# getflow.py
import requests
from requests.auth import HTTPBasicAuth
if __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)
|
2.(1) 实现上述OpenDaylight实验拓扑上相同的硬超时流表下发:
ryu_timeout.py代码:
1 2 3 4 5 6 7 8 9 |
# ryu_timeout.py
import requests
if __name__ = = "__main__" :
url = 'http://127.0.0.1:8080/stats/flowentry/add'
with open ( "./ryu_timeout.json" ) as file :
str = file .read()
headers = { 'Content-Type' : 'application/json' }
res = requests.post(url, str , headers = headers)
print (res.content)
|
ryu_timeout.json代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 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.(2) 参考Ryu REST API的文档,基于VLAN实验的网络拓扑,编程实现相同的VLAN配置:
ryu_topo.py代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# ryu_topo.py
from mininet.topo import Topo
class MyTopo(Topo):
def __init__( self ):
# initilaize topology
Topo.__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_vlan.py代码:
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# ryu_vlan.py
import json
import requests
if __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)
|