• 实验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库,把原本快要遗忘的知识重新学习巩固了起来,总体上这次实验还是有很大收获。

  • 相关阅读:
    Alpha冲刺(3/10)
    Alpha冲刺(2/10)
    Alpha冲刺(1/10)
    软工实践第七次作业——需求分析报告
    2018软工实践第八次作业-团队项目UML设计
    2018软工实践第六次作业-团队选题报告
    2018软工实践第五次作业-结对作业(2)
    软工实践第四次作业-团队展示
    2018软工实践第三次作业-结对作业
    Alpha冲刺(4/10)
  • 原文地址:https://www.cnblogs.com/beyondzones/p/15449219.html
Copyright © 2020-2023  润新知