RYU实战,REST API流表控制(2)

前言

在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())}

启动mn及控制器

初始联通性测试

(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

获得S1的流表:

让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号口子直连

获取S2 的流表

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都可用

match 的各个字段,以dict的方式给出

其中主要的键可取:
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数据报才行,否则流表将无效。

你可能感兴趣的:(SDN,rest,sdn,交换机,api,ryu)