实验7:基于REST API的SDN北向应用实践

一、实验目的

  1. 能够编写程序调用OpenDaylight REST API实现特定网络功能;
  2. 能够编写程序调用Ryu REST API实现特定网络功能。

二、实验环境

  1. Oracle VisualBox;
  2. Ubuntu 22.04 Desktop amd64;

三、实验要求

(一)基本要求

1.编写Python程序,调用OpenDaylight的北向接口实现以下功能

创建拓扑

  • delete.py
# 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)


删除S1流表

  • timeout.py
# 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
# 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"

      }

    ]

  }


h1 ping h3并执行硬超时代码网络中断20s

  • getflow.py
# 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)


获取S1流表数

2.编写Python程序,调用Ryu的北向接口实现以下功能

  • ryu_timeout.py
# 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
# 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":[



    ]

 }


启动RYU控制器并建立拓扑

执行硬超时代码

参考Ryu REST API的文档,基于VLAN实验的网络拓扑,编程实现相同的VLAN配置。

  • ryu_topo.py
# 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
# 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)


建立拓扑

删除流表后运行代码

(二)进阶要求

OpenDaylight或Ryu任选其一,编程实现查看前序VLAN实验拓扑中所有节点(含交换机、主机)的名称,以及显示每台交换机的所有流表项。

  • getall.py
# getall.py

import requests

import time

import re





class GetNodes:

    def __init__(self, ip):

        self.ip = ip

        

    def get_switch_id(self):

        url = 'http://' + self.ip + '/stats/switches'

        re_switch_id = requests.get(url=url).json()

        switch_id_hex = []

        for i in re_switch_id:

            switch_id_hex.append(hex(i))



        return switch_id_hex



    def getflow(self):

        url = 'http://' + self.ip + '/stats/flow/%d'

        switch_list = self.get_switch_id()

        ret_flow = []

        for switch in switch_list:

            new_url = format(url % int(switch, 16))

            re_switch_flow = requests.get(url=new_url).json()

            ret_flow.append(re_switch_flow)

        return ret_flow



    def show(self):

        flow_list = self.getflow()

        for flow in flow_list:

            for dpid in flow.keys():

                dp_id = dpid

                switchnum= '{1}'.format(hex(int(dp_id)), int(dp_id))        

                print('s'+switchnum,end = " ")

                switchnum = int(switchnum)

            for list_table in flow.values():

                for table in list_table:          

                    string1 = str(table)

                    if re.search("'dl_vlan': '(.*?)'", string1) is not None:

                       num = re.search("'dl_vlan': '(.*?)'", string1).group(1);

                       if num == '0' and switchnum == 1:

                          print('h1',end = " ")

                       if num == '1' and switchnum == 1:

                          print('h2',end = " ")

                       if num == '0' and switchnum == 2:

                          print('h3',end = " ")

                       if num == '1' and switchnum == 2:

                          print('h4',end = " ")

        print("")

        flow_list = self.getflow()

        for flow in flow_list:

            for dpid in flow.keys():

                dp_id = dpid

                print('switch_name:s{1}'.format(hex(int(dp_id)), int(dp_id)))

            for list_table in flow.values():

                for table in list_table:

                    print(table)

s1 = GetNodes("127.0.0.1:8080")

s1.show()


运行代码

查看流表

四、总结

  • 本次实验比较难,主要实在代码方面。这次的代码量比较大,需要多多参考学习;
  • 在执行第一个超时文件前,h1 ping h3刚开始一直不可达,多试几次就可以了,不用关掉;
  • 用curl删除流表时报错,缺少插件,根据提示安装插件即可;
  • 做进阶要求前不可以将前面的拓扑清空,否则会出现报错;
  • 我学会了用OpenDaylight和Ryu的rest API来实现特定的要求。
posted @ 2022-10-25 21:11  MobiusX  阅读(17)  评论(0编辑  收藏  举报