1:准备工作
首先运行ryu控制器
ryu-manager --verbose simple_switch_13.py ofctl_rest.py rest_topology.py
运行mininet拓扑
sudo mn --controller remote --topo tree,depth=2
2:REST API的使用
API使用方法:
# REST API
#
# Retrieve the switch stats
#
# get the list of all switches
# GET /stats/switches
#
# get the desc stats of the switch
# GET /stats/desc/
#
# get flows stats of the switch
# GET /stats/flow/
#
# get flows stats of the switch filtered by the fields
# POST /stats/flow/
#
# get aggregate flows stats of the switch
# GET /stats/aggregateflow/
#
# get aggregate flows stats of the switch filtered by the fields
# POST /stats/aggregateflow/
#
# get ports stats of the switch
# GET /stats/port/
(1)查看拓扑结构
url:http://localhost:8080/v1.0/topology/links
不过只能显示交换机之间的链路信息,无法显示主机的链路信息。
(2) 查看拓扑中的交换机
url:http://localhost:8080/stats/switches
(3)查看交换机1的流表信息
url:http://localhost:8080/stats/flow/1
(4) 查看交换机1的状态描述
url:http://localhost:8080/stats/desc/1
(5)查看交换机1的流量统计信息
url:http://localhost:8080/stats/aggregateflow/1
(6)查看交换机1的端口统计信息
url:http://localhost:8080/stats/port/1
3:调用代码
import urllib2
import json
def get_all_switches():
url = "http://127.0.0.1:8080/v1.0/topology/switches"
req = urllib2.Request(url)
res_data = urllib2.urlopen(req)
res = res_data.read()
res = json.loads(res)
return res
def get_all_links():
url = "http://127.0.0.1:8080/v1.0/topology/links"
req = urllib2.Request(url)
res_data = urllib2.urlopen(req)
res = res_data.read()
res = json.loads(res)
return res
def get_switch(dpid):
url = "http://127.0.0.1:8080/v1.0/topology/switches/" + dpid
req = urllib2.Request(url)
res_data = urllib2.urlopen(req)
res = res_data.read()
res = json.loads(res)
return res
def get_flow_entries(dpid):
url = "http://127.0.0.1:8080/stats/flow/" + dpid
req = urllib2.Request(url)
res_data = urllib2.urlopen(req)
res = res_data.read()
res = json.loads(res)
return res
def add_flow_entry(dpid,match,priority,actions):
url = "http://127.0.0.1:8080/stats/flowentry/add"
post_data = "{'dpid':%s,'match':%s,'priority':%s,'actions':%s}" % (dpid,str(match),priority,str(actions))
req = urllib2.Request(url,post_data)
res = urllib2.urlopen(req)
return res.getcode()
def delete_flow_entry(dpid, match=None, priority=None, actions=None):
url = "http://127.0.0.1:8080/stats/flowentry/delete"
post_data = "{'dpid':%s" % dpid
if match is not None:
post_data += ",'match':%s" % str(match)
if priority is not None:
post_data += ",'priority':%s" % priority
if actions is not None:
post_data += ",'actions':%s" % str(actions)
post_data += "}"
req = urllib2.Request(url,post_data)
res = urllib2.urlopen(req)
return res.getcode()
函数说明:
#get_all_switches()
参数:无
返回结果:一个包含所有交换机信息的列表
结果示例:
[{"ports": [{"hw_addr": "12:ad:47:17:6d:1d", "name": "s1-eth1", "port_no": "00000001", "dpid": "0000000000000001"}, {"hw_addr": "62:bf:89:79:68:67", "name": "s1-eth2", "port_no": "00000002", "dpid": "0000000000000001"}], "dpid": "0000000000000001"}, {"ports": [{"hw_addr": "da:d7:cb:f8:a4:7f", "name": "s2-eth1", "port_no": "00000001", "dpid": "0000000000000002"}, {"hw_addr": "ce:31:74:a1:c1:2d", "name": "s2-eth2", "port_no": "00000002", "dpid": "0000000000000002"}], "dpid": "0000000000000002"}, {"ports": [{"hw_addr": "ea:c5:e8:ee:72:f7", "name": "s3-eth1", "port_no": "00000001", "dpid": "0000000000000003"}, {"hw_addr": "da:57:80:b2:74:67", "name": "s3-eth2", "port_no": "00000002", "dpid": "0000000000000003"}], "dpid": "0000000000000003"}]
#get_all_links()
参数:无
返回结果:一个包含所有链路信息的列表
结果示例:
[{"src": {"hw_addr": "12:ad:47:17:6d:1d", "name": "s1-eth1", "port_no": "00000001", "dpid": "0000000000000001"}, "dst": {"hw_addr": "da:d7:cb:f8:a4:7f", "name": "s2-eth1", "port_no": "00000001", "dpid": "0000000000000002"}}, {"src": {"hw_addr": "ea:c5:e8:ee:72:f7", "name": "s3-eth1", "port_no": "00000001", "dpid": "0000000000000003"}, "dst": {"hw_addr": "ce:31:74:a1:c1:2d", "name": "s2-eth2", "port_no": "00000002", "dpid": "0000000000000002"}}, {"src": {"hw_addr": "da:d7:cb:f8:a4:7f", "name": "s2-eth1", "port_no": "00000001", "dpid": "0000000000000002"}, "dst": {"hw_addr": "12:ad:47:17:6d:1d", "name": "s1-eth1", "port_no": "00000001", "dpid": "0000000000000001"}}, {"src": {"hw_addr": "ce:31:74:a1:c1:2d", "name": "s2-eth2", "port_no": "00000002", "dpid": "0000000000000002"}, "dst": {"hw_addr": "ea:c5:e8:ee:72:f7", "name": "s3-eth1", "port_no": "00000001", "dpid": "0000000000000003"}}]
#get_switch(dpid)
参数:dpid为字符串,比如"0000000000000001"
返回结果:一个包含dpid对应的交换机的信息的列表
结果示例:
[{"ports": [{"hw_addr": "12:ad:47:17:6d:1d", "name": "s1-eth1", "port_no": "00000001", "dpid": "0000000000000001"}, {"hw_addr": "62:bf:89:79:68:67", "name": "s1-eth2", "port_no": "00000002", "dpid": "0000000000000001"}], "dpid": "0000000000000001"}]
#get_flow_entries(dpid)
参数:dpid为字符串,比如"0000000000000001"
返回结果:一个包含流表项的字典
结果示例:
{"1": [{"actions": ["OUTPUT:65533"], "idle_timeout": 0, "cookie": 0, "packet_count": 2252, "hard_timeout": 0, "byte_count": 114852, "duration_nsec": 370000000, "priority": 65535, "duration_sec": 2026, "table_id": 0, "match": {"dl_type": 35020, "nw_dst": "0.0.0.0", "dl_vlan_pcp": 0, "dl_src": "00:00:00:00:00:00", "nw_tos": 0, "tp_src": 0, "dl_vlan": 0, "nw_src": "0.0.0.0", "nw_proto": 0, "tp_dst": 0, "dl_dst": "01:80:c2:00:00:0e", "in_port": 0}}, {"actions": ["OUTPUT:2"], "idle_timeout": 0, "cookie": 0, "packet_count": 0, "hard_timeout": 0, "byte_count": 0, "duration_nsec": 864000000, "priority": 1111, "duration_sec": 104, "table_id": 0, "match": {"dl_type": 0, "nw_dst": "0.0.0.0", "dl_vlan_pcp": 0, "dl_src": "00:00:00:00:00:00", "nw_tos": 0, "tp_src": 0, "dl_vlan": 0, "nw_src": "0.0.0.0", "nw_proto": 0, "tp_dst": 0, "dl_dst": "00:00:00:00:00:00", "in_port": 1}}]}
其中开头的“1”表示dpid号
#add_flow_entry(dpid,match,priority,actions)
参数:
dpid为字符串,比如"0000000000000001"
match为字典,比如match = {"in_port":00000001},其他键的名称见《ryu Documentation》P161的Flow Match Structure
priority为字符串,比如"1111"
actions为列表,比如actions = [{"type":"OUTPUT","port":00000002}],其他元素名称见《ryu Documentation》P282的actions
返回结果:整数,HTTP状态码,200表示添加流表项成功
结果示例:200,403,404
#delete_flow_entry(dpid,match,priority,actions)
参数:
dpid为字符串,比如"0000000000000001"
match为字典,比如match = {"in_port":00000001},其他键的名称见《ryu Documentation》P161的Flow Match Structure
priority为字符串,比如"1111"
actions为列表,比如actions = [{"type":"OUTPUT","port":00000002}],其他元素名称见《ryu Documentation》P282的actions
返回结果:整数,HTTP状态码,200表示删除流表项成功
结果示例:200,403,404
4.使用浏览器插件操作REST API
推荐使用chrome的插件POSTMAN和Firefox的RESTClient(HttpRequester已停用)来操作RESTAPI,取代终端的curl命令。 在插件中输入相应内容就可以下发请求信息。如:
请求dpid为1的交换机上的流表信息:
http://localhost:8080/stats/flow/1
选择动作为GET,点击send,可以获得交换机1上的流表信息。
查看经过美化的JSON流表信息:
- 对流表进行修改
使用POST动作类型,下发一个flow_mod消息,对现有流表进行操作。输入URI如下:
POST http://127.0.0.1:8080/stats/flowentry/add
或者
POST http://localhost:8080/stats/flowentry/modify
然后在mininet里 pingall 查看h1和h2是否能ping通。