zoukankan      html  css  js  c++  java
  • 实验7:基于REST API的SDN北向应用实践

    一、实验目的

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

    二、实验环境

    1. 下载虚拟机软件Oracle VisualBox或VMware;
    2. 在虚拟机中安装Ubuntu 20.04 Desktop amd64,并完整安装Mininet、OpenDaylight(Carbon版本)、Postman和Ryu;

    三、实验要求

    (一)基本要求

    1. OpenDaylight
      (1) 利用Mininet平台搭建下图所示网络拓扑,并连接OpenDaylight;
      img

      • 创建拓扑

        sudo mn --topo=single,3 --controller=remote,ip=127.0.0.1,port=6633 --switch ovsk,protocols=OpenFlow10
        

      (2) 编写Python程序,调用OpenDaylight的北向接口下发指令删除s1上的流表数据。

      #!/usr/bin/python
      import requests
      from requests.auth import HTTPBasicAuth
      
      def http_delete(url):
          url= url
          headers = {'Content-Type':'application/json'}
          resp = requests.delete(url, headers=headers, auth=HTTPBasicAuth('admin', 'admin'))
          return resp 
      
      if __name__ == "__main__":
          url = 'http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/'
          resp = http_delete(url)
          print(resp.content)
      

      (3) 编写Python程序,调用OpenDaylight的北向接口下发硬超时流表,实现拓扑内主机h1和h3网络中断20s。

      #!/usr/bin/python
      import requests
      from requests.auth import HTTPBasicAuth
      def http_put(url,jstr):
          url= url
          headers = {'Content-Type':'application/json'}
          resp = requests.put(url,jstr,headers=headers,auth=HTTPBasicAuth('admin', 'admin'))
          return resp
      
      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 f:
              jstr = f.read()
          resp = http_put(url,jstr)
          print (resp.content)
      

      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": "flow1",
                  "priority": "65535",
                  "hard-timeout": "20",
                  "cookie": "2",
                  "table_id": "0"
              }
          ]
      }
      
      

      效果如下:

      image-20211021153155284

      (4) 编写Python程序,调用OpenDaylight的北向接口获取s1上活动的流表数。

      #!/usr/bin/python
      import requests
      from requests.auth import HTTPBasicAuth
      def http_get(url):
          url= url
          headers = {'Content-Type':'application/json'}
          resp = requests.get(url,headers=headers,auth=HTTPBasicAuth('admin','admin'))
          return resp
      
      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'
          resp = http_get(url)
          print(resp.content)
      

      image-20211021143156968

    2. Ryu
      (1) 编写Python程序,调用Ryu的北向接口,实现上述OpenDaylight实验拓扑上相同的硬超时流表下发。

      #!/usr/bin/python
      import requests
      
      if __name__ == "__main__":
          url = 'http://127.0.0.1:8080/stats/flowentry/add'
          with open("addtimeout.json") as f:
              jstr = f.read()
          headers = {'Content-Type': 'application/json'}
          res = requests.post(url, jstr, headers=headers)
          print (res.content)
      

      addtimeout.json

      {
          "dpid": 1,
          "cookie": 1,
          "cookie_mask": 1,
          "table_id": 0,
          "hard_timeout": 20,
          "priority": 65535,
          "flags": 1,
          "match":{
              "in_port":1
          },
          "actions":[
      
          ]
       }
      

      image-20211021153039603

      (2) 利用Mininet平台搭建下图所示网络拓扑,要求支持OpenFlow 1.3协议,主机名、交换机名以及端口对应正确。拓扑生成后需连接Ryu,且Ryu应能够提供REST API服务。
      img

      #!/usr/bin/env python
      from mininet.topo import Topo
      
      class MyTopo(Topo):
          def __init__(self):
              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

      ryu-manager  ryu.app.simple_switch_13 ryu.app.ofctl_rest
      

      创建拓扑

      sudo mn  --custom topo.py --topo mytopo --mac --controller=remote,ip=127.0.0.1,port=6633 --switch ovsk,protocols=OpenFlow13
      

      (3) 整理一个Shell脚本,参考Ryu REST API的文档,利用curl命令,实现和实验2相同的VLAN。

      VLAN_ID Hosts
      0 h1 h3
      1 h2 h4

      shell脚本

      # 将主机1,2发送来的包打上vlan标记
      curl -X POST -d '{
          "dpid": 1,
          "priority": 1,
          "match":{
              "in_port": 1
          },
          "actions":[
              {
                  "type": "PUSH_VLAN",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                  "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
              },
              {
                  "type": "SET_FIELD",
                  "field": "vlan_vid",     # Set VLAN ID
                  "value": 4096            # Describe sum of vlan_id(e.g. 6) | OFPVID_PRESENT(0x1000=4096)
              },
              {
                  "type": "OUTPUT",
                  "port": 3
              }
          ]
       }' http://localhost:8080/stats/flowentry/add
      
       curl -X POST -d '{
          "dpid": 1,
          "priority": 1,
          "match":{
              "in_port": 2
          },
          "actions":[
              {
                  "type": "PUSH_VLAN",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                  "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
              },
              {
                  "type": "SET_FIELD",
                  "field": "vlan_vid",     # Set VLAN ID
                  "value": 4097            # Describe sum of vlan_id(e.g. 6) | OFPVID_PRESENT(0x1000=4096)
              },
              {
                  "type": "OUTPUT",
                  "port": 3
              }
          ]
       }' http://localhost:8080/stats/flowentry/add
      
      # 将主机3,4发送来的包取出vlan标记
       curl -X POST -d '{
          "dpid": 1,
          "priority": 1,
          "match":{
              "vlan_vid": 0
          },
          "actions":[
              {
                  "type": "POP_VLAN",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                  "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
              },
              {
                  "type": "OUTPUT",
                  "port": 1
              }
          ]
       }' http://localhost:8080/stats/flowentry/add
      
       curl -X POST -d '{
          "dpid": 1,
          "priority": 1,
          "match":{
              "vlan_vid": 1
          },
          "actions":[
              {
                  "type": "POP_VLAN",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                  "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
              },
              {
                  "type": "OUTPUT",
                  "port": 2
              }
          ]
       }' http://localhost:8080/stats/flowentry/add
      
      # 将主机3,4发送来的包打上vlan标记
       curl -X POST -d '{
          "dpid": 2,
          "priority": 1,
          "match":{
              "in_port": 1
          },
          "actions":[
              {
                  "type": "PUSH_VLAN",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                  "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
              },
              {
                  "type": "SET_FIELD",
                  "field": "vlan_vid",     # Set VLAN ID
                  "value": 4096            # Describe sum of vlan_id(e.g. 6) | OFPVID_PRESENT(0x1000=4096)
              },
              {
                  "type": "OUTPUT",
                  "port": 3
              }
          ]
       }' http://localhost:8080/stats/flowentry/add
      
       curl -X POST -d '{
          "dpid": 2,
          "priority": 1,
          "match":{
              "in_port": 2
          },
          "actions":[
              {
                  "type": "PUSH_VLAN",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                  "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
              },
              {
                  "type": "SET_FIELD",
                  "field": "vlan_vid",     # Set VLAN ID
                  "value": 4097            # Describe sum of vlan_id(e.g. 6) | OFPVID_PRESENT(0x1000=4096)
              },
              {
                  "type": "OUTPUT",
                  "port": 3
              }
          ]
       }' http://localhost:8080/stats/flowentry/add
      
       curl -X POST -d '{
          "dpid": 2,
          "priority": 1,
          "match":{
              "vlan_vid": 0
          },
          "actions":[
              {
                  "type": "POP_VLAN",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                  "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
              },
              {
                  "type": "OUTPUT",
                  "port": 1
              }
          ]
       }' http://localhost:8080/stats/flowentry/add
      
       curl -X POST -d '{
          "dpid": 2,
          "priority": 1,
          "match":{
              "vlan_vid": 1
          },
          "actions":[
              {
                  "type": "POP_VLAN",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                  "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
              },
              {
                  "type": "OUTPUT",
                  "port": 2
              }
          ]
       }' http://localhost:8080/stats/flowentry/add
      

      执行后效果如下:

      image-20211022094359474

      成功划分VLAN

    (二)进阶要求

    编程实现基本要求第2部分Ryu(3)中的VLAN划分。

    python代码

    #!/usr/bin/python
    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",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                    "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
                },
                {
                    "type": "SET_FIELD",
                    "field": "vlan_vid",     # Set VLAN ID
                    "value": 4096            # Describe sum of vlan_id(e.g. 6) | OFPVID_PRESENT(0x1000=4096)
                },
                {
                    "type": "OUTPUT",
                    "port": 3
                }
            ]
        }
        flow2 = {
            "dpid": 1,
            "priority": 1,
            "match":{
                "in_port": 2
            },
            "actions":[
                {
                    "type": "PUSH_VLAN",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                    "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
                },
                {
                    "type": "SET_FIELD",
                    "field": "vlan_vid",     # Set VLAN ID
                    "value": 4097            # Describe sum of vlan_id(e.g. 6) | OFPVID_PRESENT(0x1000=4096)
                },
                {
                    "type": "OUTPUT",
                    "port": 3
                }
            ]
        }
        flow3 = {
            "dpid": 1,
            "priority": 1,
            "match":{
                "vlan_vid": 0
            },
            "actions":[
                {
                    "type": "POP_VLAN",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                    "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
                },
                {
                    "type": "OUTPUT",
                    "port": 1
                }
            ]
        }
        flow4 = {
            "dpid": 1,
            "priority": 1,
            "match": {
                "vlan_vid": 1
            },
            "actions": [
                {
                    "type": "POP_VLAN",  # Push a new VLAN tag if a input frame is non-VLAN-tagged
                    "ethertype": 33024  # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
                },
                {
                    "type": "OUTPUT",
                    "port": 2
                }
            ]
        }
        flow5 = {
            "dpid": 2,
            "priority": 1,
            "match": {
                "in_port": 1
            },
            "actions": [
                {
                    "type": "PUSH_VLAN",  # Push a new VLAN tag if a input frame is non-VLAN-tagged
                    "ethertype": 33024  # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
                },
                {
                    "type": "SET_FIELD",
                    "field": "vlan_vid",  # Set VLAN ID
                    "value": 4096  # Describe sum of vlan_id(e.g. 6) | OFPVID_PRESENT(0x1000=4096)
                },
                {
                    "type": "OUTPUT",
                    "port": 3
                }
            ]
        }
        flow6 = {
            "dpid": 2,
            "priority": 1,
            "match": {
                "in_port": 2
            },
            "actions": [
                {
                    "type": "PUSH_VLAN",  # Push a new VLAN tag if a input frame is non-VLAN-tagged
                    "ethertype": 33024  # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
                },
                {
                    "type": "SET_FIELD",
                    "field": "vlan_vid",  # Set VLAN ID
                    "value": 4097  # Describe sum of vlan_id(e.g. 6) | OFPVID_PRESENT(0x1000=4096)
                },
                {
                    "type": "OUTPUT",
                    "port": 3
                }
            ]
        }
        flow7 = {
            "dpid": 2,
            "priority": 1,
            "match": {
                "vlan_vid": 0
            },
            "actions": [
                {
                    "type": "POP_VLAN",  # Push a new VLAN tag if a input frame is non-VLAN-tagged
                    "ethertype": 33024  # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
                },
                {
                    "type": "OUTPUT",
                    "port": 1
                }
            ]
        }
        flow8 = {
        "dpid": 2,
        "priority": 1,
        "match":{
            "vlan_vid": 1
        },
        "actions":[
            {
                "type": "POP_VLAN",     # Push a new VLAN tag if a input frame is non-VLAN-tagged
                "ethertype": 33024       # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
            },
            {
                "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)
    

    执行效果如下:

    image-20211022095328055

    四、个人总结

    • 实验难度:较难

      有前几次实验的积累这次实验相对来说比较顺利,但是由于对前面的知识地部分遗忘,所以在刚开始做实验时还是有一点找不到方向,但是经过知识的回顾,还是能比较明确的知道每一步的做法。

    • 实验过程遇到的困难:

      1.问题:调用OpenDaylight的北向接口下发指令删除s1上的流表数据时出现如下错误反馈

      image-20211021190436561

      解决方案:我原本以为是我请求的方式有问题导致无法找到流表信息,询问老师后发现是因为原先没有下发流表或者是之前已经将流表删除,所以无法进行删除流表操作

      2.问题:调用Ryu的北向接口实现硬超时流表下发前创建拓扑无法ping通

      解决方案:建立拓扑时应该使用OpenFlow1.3,使用OpenFlow1.0会出现无法ping通的情况

    • 个人感想:

      通过这次实验,我进一步了解了OpenDaylight和Ryu的使用,对如何阅读官方文档也有了自己的心得,除此之外还进一步学习了python的request库,把原本快要遗忘的知识重新学习巩固了起来,总体上这次实验还是有很大收获。

  • 相关阅读:
    【C++】资源管理
    【Shell脚本】逐行处理文本文件
    【算法题】rand5()产生rand7()
    【Shell脚本】字符串处理
    Apple iOS产品硬件参数. 不及格的程序员
    与iPhone的差距! 不及格的程序员
    iPhone游戏 Mr.Karoshi"过劳死"通关. 不及格的程序员
    XCode V4 发布了, 苹果的却是个变态. 不及格的程序员
    何时readonly 字段不是 readonly 的?结果出呼你想象!!! 不及格的程序员
    object file format unrecognized, invalid, or unsuitable Command 不及格的程序员
  • 原文地址:https://www.cnblogs.com/beyondzones/p/15449219.html
Copyright © 2011-2022 走看看