在RYU API流表控制(1),我们介绍了如何通过RYU提供的REST API来获取流表项目,这一节,我们将探索如何使用REST来添加、删除、修改流表。
控制器:RYU (192.168.1.196)
交换机:s1,s2
主机:h1,h2,h3,h3
联通性(直连):
h1<->s1;h2<->s1
h3<->s2;h4<->s2
s1<->s2
拓扑代码如下:
__author__ = 'jmh081701'
from mininet.topo import Topo
class MyTopo(Topo):
def __init__(self):
Topo.__init__(self)
left=[]
left.append(self.addHost("h1"))
left.append(self.addHost("h2"))
right=[]
right.append(self.addHost("h3"))
right.append(self.addHost("h4"))
switchs=[]
switchs.append(self.addSwitch("s1"))
switchs.append(self.addSwitch("s2"))
self.addLink(left[0],switchs[0])
self.addLink(left[1],switchs[0])
self.addLink(right[0],switchs[1])
self.addLink(right[1],switchs[1])
self.addLink(switchs[0],switchs[1])
topos={'mytopo':(lambda : MyTopo())}
(mininet)>pingall
*** Ping: testing ping reachability
H1 -> H2 H3 H4
H2 -> H1 H3 H4
H3 -> H1 H2 H4
H4 -> H1 H2 H3
*** Results: 0% dropped (12/12 received)
ok.
URL:http://192.168.1.196:8080/stats/flowentry/clear/1
方法:delete
URL:http://192.168.1.196:8080/stats/flowentry/clear/2
方法:delete
让h1 ping h2
mininet>h1 ifconfig
H1-eth0 Link encap:Ethernet HWaddr f2:45:ed:50:45:f9
inet addr:10.0.0.1 Bcast:10.255.255.255 Mask:255.0.0.0
···
mininet>h1 ping h2
URL: http://192.168.1.196:8080/stats/flow/1
方法:GET
{
"1": [
{
"actions": [
"OUTPUT:1"
],
"idle_timeout": 0,
"cookie": 0,
"packet_count": 7,
"hard_timeout": 0,
"byte_count": 574,
"duration_sec": 12,
"duration_nsec": 58000000,
"priority": 1,
"length": 96,
"flags": 0,
"table_id": 0,
"match": {
"dl_dst": "f2:45:ed:50:45:f9",
"in_port": 2
}
},
{
"actions": [
"OUTPUT:2"
],
"idle_timeout": 0,
"cookie": 0,
"packet_count": 6,
"hard_timeout": 0,
"byte_count": 532,
"duration_sec": 12,
"duration_nsec": 54000000,
"priority": 1,
"length": 96,
"flags": 0,
"table_id": 0,
"match": {
"dl_dst": "ba:d9:2d:31:ba:73",
"in_port": 1
}
},
{
"actions": [
"OUTPUT:CONTROLLER"
],
"idle_timeout": 0,
"cookie": 0,
"packet_count": 52,
"hard_timeout": 0,
"byte_count": 5739,
"duration_sec": 73,
"duration_nsec": 68000000,
"priority": 0,
"length": 80,
"flags": 0,
"table_id": 0,
"match": {}
}
]
}
分析:
“f2:45:ed:50:45:f9”(h1) 与S1的1号口子直连
“ba:d9:2d:31:ba:73”(h2) 与S1的2号口子直连
mininet>h3 ifconfig
H3-eth0 Link encap:Ethernet HWaddr 6e:32:5b:d2:a5:cb
inet addr:10.0.0.3 Bcast:10.255.255.255 Mask:255.0.0.0
···
mininet>h3 ping h4
让H3与H4互通
获取交换机2的流表项
URL: http://192.168.1.196:8080/stats/flow/2
方法:GET
{
"2": [
{
"actions": [
"OUTPUT:2"
],
"idle_timeout": 0,
"cookie": 0,
"packet_count": 3,
"hard_timeout": 0,
"byte_count": 182,
"duration_sec": 7,
"duration_nsec": 981000000,
"priority": 1,
"length": 96,
"flags": 0,
"table_id": 0,
"match": {
"dl_dst": "6e:32:5b:d2:a5:cb",
"in_port": 3
}
},
{
"actions": [
"OUTPUT:3"
],
"idle_timeout": 0,
"cookie": 0,
"packet_count": 2,
"hard_timeout": 0,
"byte_count": 140,
"duration_sec": 7,
"duration_nsec": 978000000,
"priority": 1,
"length": 96,
"flags": 0,
"table_id": 0,
"match": {
"dl_dst": "8a:4f:1b:f4:b0:93",
"in_port": 2
}
},
{
"actions": [
"OUTPUT:CONTROLLER"
],
"idle_timeout": 0,
"cookie": 0,
"packet_count": 55,
"hard_timeout": 0,
"byte_count": 6187,
"duration_sec": 382,
"duration_nsec": 843000000,
"priority": 0,
"length": 80,
"flags": 0,
"table_id": 0,
"match": {}
}
]
}
得到的结论:
"6e:32:5b:d2:a5:cb"(h3) 与S2的2号口子直连
"8a:4f:1b:f4:b0:93" (h4) 与S2的3号口子直连
上面的工作并非没有意义,通过流表,得到了各个主机的Mac地址,以及各个主机与交换机直连端口的关系,这对于接下来的实验很重要!尤其是匹配字段
URL:http://192.168.1.196:8080/stats/flowentry/add
方法:POST
属性:
dpid:数据通路iD,简单理解就是交换机的ID,int
table_id:流表项所在的目标流表ID,简单理解就是把这个流表项加到那张表上去,int
idle_timeout:这个流表项空闲多久就失效,int
hard_timeout:这个流表项存活多久,int
priority:流表执行的优先级,int
match:匹配字段,dict
action:匹配后流所采取的动作,list of dict
重要的属性:
dpid,priority,match,action
举例:
添加 h1到h2的截断报文,也就是让h1无法ping通h2
{
"dpid": 1,
"cookie": 1,
"cookie_mask": 1,
"table_id": 0,
"idle_timeout": 30,
"hard_timeout": 3000,
"priority": 11111,
"flags": 1,
"match":{
"eth_src":"f2:45:ed:50:45:f9",
"eth_dst":"ba:d9:2d:31:ba:73"
},
"actions":[
]
}
这里 这个action为空,就可以截断h1发往h2的报文
测试 h1与h2之间的联通性:
mininet>H1 ping H2
mininet> H1 ping H2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
From 10.0.0.1 icmp_seq=1 Destination Host Unreachable
From 10.0.0.1 icmp_seq=2 Destination Host Unreachable
ok,H1发往H2的已经阻端
只匹配match,然后修改
URL: http://192.168.1.196:8080/stats/flowentry/add
方法:Get
举例:
{
"dpid": 1,
"cookie": 1,
"cookie_mask": 1,
"table_id": 0,
"idle_timeout": 30,
"hard_timeout": 3000,
"priority": 11111,
"flags": 1,
"match":{
"eth_src":"f2:45:ed:50:45:f9",
"eth_dst":"ba:d9:2d:31:ba:73"
},
"actions":[
{
"type": "OUTPUT",
"port": 2
}
]
}
把匹配域为”eth_src”:”f2:45:ed:50:45:f9”,”eth_dst”:”ba:d9:2d:31:ba:73”流表项都修改为从2号口子出,也就是恢复H1与h2之间的联通.
匹配Match与priority两个符合字段,匹配成功了才行。
举例:
{
"dpid": 1,
"cookie": 1,
"cookie_mask": 1,
"table_id": 0,
"idle_timeout": 300,
"hard_timeout": 4001,
"priority": 11112,
"flags": 1,
"match":{
"eth_dst":"ba:d9:2d:31:ba:73"
},
"actions":[
]
}
TIP:删除时 只要填好match字段与priority就可以
URL: http://192.168.1.196:8080/stats/flowentry/delete
方法:POST
与模糊修改类似,match字段匹配即可
URL: http://192.168.1.196:8080/stats/flowentry/delete_strict
方法:POST
与严格修改类似,match与priority同时匹配才删除
上面的方法只是删除单个的流表项,如果要删除某个交换机所有的流表项则:
URL:http://192.168.1.196:8080/stats/flowentry/clear/x
删除交换机x的所有流表项,x是交换机的dpid
方法:POST
openflow 1.3,1.1,1.2都可用
其中主要的键可取:
in_port:报文的入端口,int
dl_src: 二层源地址(源MAC地址),”ff:ff:ff:ff:ff:ff”
dl_dst:目的MAC地址,”ff:ff:ff:ff:ff:ff”
dl_vlan:二层子网号,int
dl_vlan_pcp:二层子网优先级,int
dl_type:三层协议类型,如IP协议,IPv6协议,ARP协议.int
dl_type(自行转成为10进制) | 协议类型 |
---|---|
0x0800 | IPv4 |
0x86DD | IPv6 |
0x0806 | ARP |
nw_tos: ip服务类型
nw_tos | 服务类型 |
---|---|
0 | 普通 (Routine) |
1 | 优先的 |
2 | 立即的发送 (Immediate) |
3 | 闪电式的 (Flash) |
4 | 比闪电还闪电式的 (Flash Override) |
5 | CRI/TIC/ECP |
6 | 网间控制 (Internetwork Control) |
7 | 网络控制 (Network Control) |
nw_proto:ip协议上搭载的协议类型如 TCP,UDP
nw_proto | 协议类型 |
---|---|
1 | ICMP |
2 | IGMP |
6 | TCP |
17 | UDP |
88 | IGRP |
89 | OSPF |
nw_src:源IP地址(IPv4).str.点分10进制,”192.168.1.1”
nw_dst:目的ip地址(IPv4)
tp_src:网络层源端口.int
tp_dst:网络层目的端口.int
如果要匹配更高层协议的内容,那么要从二层开始一直到高层
例如:匹配所有目的端口号为80的TCP报文:
match:
{
“dl_type”:2048,
“nw_proto”:6,
“tp_dst”:80
}
首先得保证是一个TCP数据报才行,否则流表将无效。