zoukankan      html  css  js  c++  java
  • RYU 灭龙战 fourth day (2)

    RYU 灭龙战 fourth day (2)

    前言

    之前试过在ODL调用他们的rest api,一直想自己写一个基于ODL的rest api,结果还是无果而终。这个小目标却在RYU身上实现了。今日说法,为你带来,基于RYU的北向rest api开发

    目的

    • mac地址表获取 API

      取得基于RYU 灭龙战 third day实验的mac地址表内容。即 对应的mac地址和连接端口 以JSON的形式回传

    • mac地址表注册 API

      向mac地址表加入新的mac地址和端口号,同时加到交换机的流表中

    实验方案

    附录源码

    # Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #    http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    # implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    import json
    
    from ryu.app import simple_switch_13
    from ryu.controller import ofp_event
    from ryu.controller.handler import CONFIG_DISPATCHER
    from ryu.controller.handler import set_ev_cls
    from ryu.app.wsgi import ControllerBase
    from ryu.app.wsgi import Response
    from ryu.app.wsgi import route
    from ryu.app.wsgi import WSGIApplication
    from ryu.lib import dpid as dpid_lib
    
    simple_switch_instance_name = 'simple_switch_api_app'
    url = '/simpleswitch/mactable/{dpid}'
    
    #SimpleSwitchRest13用来扩展实验一的功能,让它可以更新mac地址表,其中switch_features_handler方法由于需要更新mac地址表,所以这个地方继承原方法,进行重写
    class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13):
    
        #指定RYU使用的为WSGI网页服务器
        _CONTEXTS = {'wsgi': WSGIApplication}
    
        def __init__(self, *args, **kwargs):
            super(SimpleSwitchRest13, self).__init__(*args, **kwargs)
            #已连接交换机集合
            self.switches = {}
            wsgi = kwargs['wsgi']
            wsgi.register(SimpleSwitchController,
                          {simple_switch_instance_name: self})
    
        #接收消息为OPFSwitchFeatures,交换机状态为接收SwitchFeatures消息
        @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
        def switch_features_handler(self, ev):
            #继承原方法
            super(SimpleSwitchRest13, self).switch_features_handler(ev)
            datapath = ev.msg.datapath
            self.switches[datapath.id] = datapath
            self.mac_to_port.setdefault(datapath.id, {})
    
        def set_mac_to_port(self, dpid, entry):
            mac_table = self.mac_to_port.setdefault(dpid, {})
            datapath = self.switches.get(dpid)
    
            #entry用来存储已经注册的mac地址和端口
            entry_port = entry['port']
            entry_mac = entry['mac']
    
            if datapath is not None:
                parser = datapath.ofproto_parser
                if entry_port not in mac_table.values():
    
                    for mac, port in mac_table.items():
    
                        # from known device to new device
                        actions = [parser.OFPActionOutput(entry_port)]
                        match = parser.OFPMatch(in_port=port, eth_dst=entry_mac)
                        self.add_flow(datapath, 1, match, actions)
    
                        # from new device to known device
                        actions = [parser.OFPActionOutput(port)]
                        match = parser.OFPMatch(in_port=entry_port, eth_dst=mac)
                        self.add_flow(datapath, 1, match, actions)
    
                    mac_table.update({entry_mac: entry_port})
            return mac_table
    
    #SimpleSwitchController用来实现收到HTTP请求时所需要回应的方法
    class SimpleSwitchController(ControllerBase):
    
        def __init__(self, req, link, data, **config):
            super(SimpleSwitchController, self).__init__(req, link, data, **config)
            self.simple_switch_app = data[simple_switch_instance_name]
    
        #参数说明,第一个参数任意名称,第二个参数url,指定url,使得对应的url为http://<IP>:8080/simpleswitch/mactable/<datapath ID>,第三个参数为GET方法,
        # 第四个参数为指定的URL形式,即simpleswitch/mactable/<datapath ID>的<datapapath ID>要和目标文件的值相对应
        @route('simpleswitch', url, methods=['GET'],
               requirements={'dpid': dpid_lib.DPID_PATTERN})
        def list_mac_table(self, req, **kwargs):
    
            simple_switch = self.simple_switch_app
            dpid = dpid_lib.str_to_dpid(kwargs['dpid'])
            #如果dpid不在表中的话,就会返回404
            if dpid not in simple_switch.mac_to_port:
                return Response(status=404)
            #把对应的dpid对应的mac地址表用json的形式返回
            mac_table = simple_switch.mac_to_port.get(dpid, {})
            body = json.dumps(mac_table)
            return Response(content_type='application/json', body=body)
    
        #同上
        @route('simpleswitch', url, methods=['PUT'],
               requirements={'dpid': dpid_lib.DPID_PATTERN})
        def put_mac_table(self, req, **kwargs):
    
            simple_switch = self.simple_switch_app
            dpid = dpid_lib.str_to_dpid(kwargs['dpid'])
            try:
                new_entry = req.json if req.body else {}
            except ValueError:
                raise Response(status=400)
    
            if dpid not in simple_switch.mac_to_port:
                return Response(status=404)
    
            #调用set_mac_to_port方法,注册相应的mac,port,并下发流表
            try:
                mac_table = simple_switch.set_mac_to_port(dpid, new_entry)
                body = json.dumps(mac_table)
                return Response(content_type='application/json', body=body)
            except Exception as e:
                return Response(status=500)
    
    

    实验过程

    • mininet端
    sudo mn --topo single,3 --mac --switch ovsk,protocols=OpenFlow13 --controller remote
    

    • 另外一个终端,目录为ryu/app
    ryu-manager --verbose ./simple_switch_rest_13.py
    

    • mininet端,让h1 ping h2 ,看RYU端的变化
    h1 ping -c1 h2
    

    • 使用curl调用rest api进行获取mac地址表

    • 使用curl调用rest api进行mac地址表的注册

    • 在OVS上查看流表

    可以看得到刚刚PUT的请求,也转化为流表的形式下发了

    总结

    学习到这里,基本了解一些RYU的一些大概框架和结构,知道如何相应事件去做相应的处理。接下来我将

    • 学一下RYU对LLDP报文的机制
    • 对该机制进行这3天来的实验汇总,功能包括对LLDP报文做相应处理,并在这基础上增加rest api的调用
  • 相关阅读:
    实现Runnable接口和继承Thread类的区别
    图的DFS和BFS
    图建模
    数据结构-图的基本知识和表示
    除自身以外的乘积数组(力扣第238题)
    MapReduce源码分析--Shuffle阶段
    转到博客园
    vue中使用剪切板插件 clipboard.js
    vue中使用vue-qrcode生成二维码
    h5中嵌入视频自动播放的问题
  • 原文地址:https://www.cnblogs.com/wpqwpq/p/6495193.html
Copyright © 2011-2022 走看看