目录
一些postman介绍、基本使用,以及mininet创建拓扑之类的我就不再重复写了。
本文使用拓扑:SDN-Mininet安装使用
实验环境
- VM14.0
- Ubuntu 18.04
- JDK1.8
- OpenDaylight-Nitro版本
- Mininet
- postman
实验步骤
打开opendaylight
使用mininet创建拓扑并连接opendaylight
Postman查看流表
访问网址,http://你的ip:8181/index.html
打开Nodes标签,查看Node Id

打开YANG UI标签,opendaylight-inventory rev.2013-08-19->operational->nodes->node{id}->table{id}

点击小眼睛获得完整url

复制url,粘贴到postman。选择GET方式,验证方式为Basic Auth,Headers中的Content-Type和Accept填入application/xml(不填的话默认是application/json格式),账号密码均为admin,填入参数,table的id为0,node的id为之前Node标签看到的。

python代码查看流表
import urllib.request
from base64 import encodebytes
ip = "192.168.31.174"
node_id = "openflow:1"
table_id = "0"
username = "admin"
password = "admin"
url = "http://" + ip + ":8181/restconf/operational/opendaylight-inventory:nodes/node/" + node_id + "/flow-node-inventory:table/" + table_id
print(url)
# 添加请求的url
req = urllib.request.Request(url)
# 添加请求方法
req.get_method = lambda: "GET"
# 添加header
b64str = encodebytes(bytes('%s:%s' % (username, password), 'utf-8'))[:-1]
req.add_header("Authorization", "Basic %s" % b64str.decode('utf-8'))
returnData = urllib.request.urlopen(req)
res_json = returnData.read().decode('utf-8')
print(res_json)
xml形式的流表
<table xmlns="urn:opendaylight:flow:inventory">
<id>0</id>
<flow>
<id>L2switch-2</id>
<flow-statistics xmlns="urn:opendaylight:flow:statistics">
<packet-count>1</packet-count>
<duration>
<nanosecond>645000000</nanosecond>
<second>258</second>
</duration>
<byte-count>70</byte-count>
</flow-statistics>
<priority>2</priority>
<table_id>0</table_id>
<hard-timeout>0</hard-timeout>
<match>
<in-port>openflow:1:3</in-port>
</match>
<cookie>3098476543630901250</cookie>
<instructions>
<instruction>
<order>0</order>
<apply-actions>
<action>
<order>0</order>
<output-action>
<max-length>65535</max-length>
<output-node-connector>2</output-node-connector>
</output-action>
</action>
<action>
<order>2</order>
<output-action>
<max-length>65535</max-length>
<output-node-connector>CONTROLLER</output-node-connector>
</output-action>
</action>
<action>
<order>1</order>
<output-action>
<max-length>65535</max-length>
<output-node-connector>1</output-node-connector>
</output-action>
</action>
</apply-actions>
</instruction>
</instructions>
<idle-timeout>0</idle-timeout>
</flow>
<flow>
<id>L2switch-1</id>
<flow-statistics xmlns="urn:opendaylight:flow:statistics">
<packet-count>53</packet-count>
<duration>
<nanosecond>145000000</nanosecond>
<second>264</second>
</duration>
<byte-count>4505</byte-count>
</flow-statistics>
<priority>100</priority>
<table_id>0</table_id>
<hard-timeout>0</hard-timeout>
<match>
<ethernet-match>
<ethernet-type>
<type>35020</type>
</ethernet-type>
</ethernet-match>
</match>
<cookie>3098476543630901249</cookie>
<instructions>
<instruction>
<order>0</order>
<apply-actions>
<action>
<order>0</order>
<output-action>
<max-length>65535</max-length>
<output-node-connector>CONTROLLER</output-node-connector>
</output-action>
</action>
</apply-actions>
</instruction>
</instructions>
<idle-timeout>0</idle-timeout>
</flow>
<flow>
<id>#UF$TABLE*0-2</id>
<flow-statistics xmlns="urn:opendaylight:flow:statistics">
<packet-count>0</packet-count>
<duration>
<nanosecond>145000000</nanosecond>
<second>264</second>
</duration>
<byte-count>0</byte-count>
</flow-statistics>
<priority>0</priority>
<table_id>0</table_id>
<hard-timeout>0</hard-timeout>
<match></match>
<cookie>3098476543630901249</cookie>
<idle-timeout>0</idle-timeout>
</flow>
<flow>
<id>L2switch-0</id>
<flow-statistics xmlns="urn:opendaylight:flow:statistics">
<packet-count>1</packet-count>
<duration>
<nanosecond>652000000</nanosecond>
<second>258</second>
</duration>
<byte-count>70</byte-count>
</flow-statistics>
<priority>2</priority>
<table_id>0</table_id>
<hard-timeout>0</hard-timeout>
<match>
<in-port>openflow:1:2</in-port>
</match>
<cookie>3098476543630901248</cookie>
<instructions>
<instruction>
<order>0</order>
<apply-actions>
<action>
<order>0</order>
<output-action>
<max-length>65535</max-length>
<output-node-connector>1</output-node-connector>
</output-action>
</action>
<action>
<order>2</order>
<output-action>
<max-length>65535</max-length>
<output-node-connector>CONTROLLER</output-node-connector>
</output-action>
</action>
<action>
<order>1</order>
<output-action>
<max-length>65535</max-length>
<output-node-connector>3</output-node-connector>
</output-action>
</action>
</apply-actions>
</instruction>
</instructions>
<idle-timeout>0</idle-timeout>
</flow>
<flow>
<id>#UF$TABLE*0-3</id>
<flow-statistics xmlns="urn:opendaylight:flow:statistics">
<packet-count>3</packet-count>
<duration>
<nanosecond>647000000</nanosecond>
<second>258</second>
</duration>
<byte-count>247</byte-count>
</flow-statistics>
<priority>2</priority>
<table_id>0</table_id>
<hard-timeout>0</hard-timeout>
<match>
<in-port>openflow:1:1</in-port>
</match>
<cookie>3098476543630901249</cookie>
<instructions>
<instruction>
<order>0</order>
<apply-actions>
<action>
<order>0</order>
<output-action>
<max-length>65535</max-length>
<output-node-connector>2</output-node-connector>
</output-action>
</action>
<action>
<order>1</order>
<output-action>
<max-length>65535</max-length>
<output-node-connector>3</output-node-connector>
</output-action>
</action>
</apply-actions>
</instruction>
</instructions>
<idle-timeout>0</idle-timeout>
</flow>
<flow-table-statistics xmlns="urn:opendaylight:flow:table:statistics">
<packets-matched>57</packets-matched>
<active-flows>5</active-flows>
<packets-looked-up>105</packets-looked-up>
</flow-table-statistics>
</table>
流表分析
从这个xml中,我们可以看到流表的一些信息,包括流表的id,使用的交换机,一个流表项的入端口等,另外<flow></flow>标签中是流表的一个流表项,共5条。
字段 | 含义 |
---|---|
table_id | int,流表的id |
id | string,流表项的id |
priority | int,流表项的优先级 |
cookie | int,控制器发出的标识符 |
cookie_mask | int,掩码,用于限制必须匹配的cookie位 |
idle-timeout | int,丢弃前的空闲时间(秒) |
hard-timeout | int,丢弃前的最长时间(秒) |
match | dict,匹配域 |
ethernet-match | dict,以太网匹配 |
ethernet-type | dict,以太网类型 |
type | str,0x0800:使用ip匹配,0x8847:使用mac匹配 |
ipv4-destination | ipv4的目的ip地址 |
instructions | dict,动作集 |
instruction | list,动作,指令 |
order | int,顺序 |
Postman查看流表项

json格式的流表项
{
"flow-node-inventory:flow": [
{
"id": "L2switch-2",
"opendaylight-flow-statistics:flow-statistics": {
"packet-count": 2,
"duration": {
"nanosecond": 81000000,
"second": 768
},
"byte-count": 140
},
"priority": 2,
"table_id": 0,
"hard-timeout": 0,
"match": {
"in-port": "openflow:1:3"
},
"cookie": 3098476543630901250,
"instructions": {
"instruction": [
{
"order": 0,
"apply-actions": {
"action": [
{
"order": 0,
"output-action": {
"max-length": 65535,
"output-node-connector": "2"
}
},
{
"order": 2,
"output-action": {
"max-length": 65535,
"output-node-connector": "CONTROLLER"
}
},
{
"order": 1,
"output-action": {
"max-length": 65535,
"output-node-connector": "1"
}
}
]
}
}
]
},
"idle-timeout": 0
}
]
}
Python代码查看流表项
import urllib.request
from base64 import encodebytes
ip = "192.168.31.174"
node_id = "openflow:1"
table_id = "0"
flow_id = "L2switch-2"
username = "admin"
password = "admin"
url = "http://" + ip + ":8181/restconf/operational/opendaylight-inventory:nodes/node/" + node_id + "/flow-node-inventory:table/" + table_id +"/flow/"+flow_id
print(url)
# 添加请求的url和method
req = urllib.request.Request(url, method="GET")
# 添加header
b64str = encodebytes(bytes('%s:%s' % (username, password), 'utf-8'))[:-1]
req.add_header("Authorization", "Basic %s" % b64str.decode('utf-8'))
returnData = urllib.request.urlopen(req)
res_json = returnData.read().decode('utf-8')
print(res_json)
Postman添加流表项


使用PUT方式,账号密码依然还是admin,注意url是使用的config,不是operational,选择json格式,点击send。


再次查看流表后发现添加了一条流表项,h1、h2使用的是交换机s1的端口s1-eth1与s1-eth2,所以,h1与h2可以ping通。
Python添加流表项
import urllib.request
from base64 import encodebytes
from django.contrib.sites import requests
ip = "192.168.31.174"
# node_id = "openflow:1"
print("please input name of switch:")
node_id = input()
table_id = "0"
# flow_id = "L2switch-2"
print("please input id of flow:")
flow_id = input()
username = "admin"
password = "admin"
url = "http://" + ip + ":8181/restconf/config/opendaylight-inventory:nodes/node/" + node_id + "/flow-node-inventory:table/" + table_id + "/flow/" + flow_id
print(url)
flow = {
"flow-node-inventory:flow": [
{
"id": "L2switch-2",
"priority": 2,
"table_id": 0,
"hard-timeout": 0,
"match": {
"in-port": "openflow:1:3"
},
"cookie": 3098476543630901250,
"instructions": {
"instruction": [
{
"order": 0,
"apply-actions": {
"action": [
{
"order": 0,
"output-action": {
"max-length": 65535,
"output-node-connector": "2"
}
}
]
}
}
]
},
"idle-timeout": 0
}
]
}
flow["flow-node-inventory:flow"][0]["id"] = flow_id
print("please input priority of this flow:")
flow["flow-node-inventory:flow"][0]["priority"] = int(input())
print("please input hard-timeout of this flow:")
flow["flow-node-inventory:flow"][0]["hard-timeout"] = int(input())
print("please input idle-timeout of this flow:")
flow["flow-node-inventory:flow"][0]["idle-timeout"] = int(input())
print("please input in-port of this flow:")
flow["flow-node-inventory:flow"][0]["match"]["in-port"] = node_id + ":" + input()
print("please input output-port of this flow:")
flow["flow-node-inventory:flow"][0]["instructions"]["instruction"][0]["apply-actions"]["action"][0]["output-action"][
"output-node-connector"] = input()
print("flow_id:" + str(flow["flow-node-inventory:flow"][0]["id"]))
print("priority:" + str(flow["flow-node-inventory:flow"][0]["priority"]))
print("hard-timeout:" + str(flow["flow-node-inventory:flow"][0]["hard-timeout"]))
print("idle-timeout:" + str(flow["flow-node-inventory:flow"][0]["idle-timeout"]))
print("in-port:" + flow["flow-node-inventory:flow"][0]["match"]["in-port"])
print("output-port:" +
flow["flow-node-inventory:flow"][0]["instructions"]["instruction"][0]["apply-actions"]["action"][0][
"output-action"]["output-node-connector"])
print(flow)
# 添加请求的url、data、method
req = urllib.request.Request(url=url, data=bytes(str(flow), 'utf-8'), method="PUT")
# 添加header
b64str = encodebytes(bytes('%s:%s' % (username, password), 'utf-8'))[:-1]
req.add_header("Authorization", "Basic %s" % b64str.decode('utf-8'))
req.add_header("Accept", "application/json")
req.add_header("Content-Type", "application/json")
returnData = urllib.request.urlopen(req)
res_json = returnData.read().decode('utf-8')
print(res_json)


我是通过端口添加的流表项,除此之外,你还可以使用ip或mac添加,使用ethernet-type、ipv4-destination等字段。
Postman、Python修改流表项
这个只需要使你请求的数据中流表项的id在流表中存在,就会覆盖掉原来的。
更多SDN相关内容,请查看:SDN-自学笔记
有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。