ryu—Rest API

1. 代码解析

ryu/app/simple_switch_rest_13.py:

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}


class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13):
    _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})

    @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_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


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]

    @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 = kwargs[dpid]

        if dpid not in simple_switch.mac_to_port:
            return Response(status=404)

        mac_table = simple_switch.mac_to_port.get(dpid, {})
        body = json.dumps(mac_table)
        return Response(content_type=application/json, text=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 = 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)

        try:
            mac_table = simple_switch.set_mac_to_port(dpid, new_entry)
            body = json.dumps(mac_table)
            return Response(content_type=application/json, text=body)
        except Exception as e:
            return Response(status=500)
  • 类变量_CONTEXTS用于指定Ryu的WSGI-compatible Web server 类;
  • wsgi.register(...)用于注册SimpleSwitchController,并使得SimpleSwitchController可以在其构造器通过键simple_switch_api_app访问SimpleSwitchRest13实例;
  • set_mac_to_port()方法用于注册MAC地址和端口信息;如,self.mac_to_port中已存在映射信息00:00:00:00:00:01, 1,此时使用entry00:00:00:00:00:02, 2的参数调用set_mac_to_port()方法,则有如下流项会被注册:
    • Matching condition: in_port = 1, dst_mac = 00:00:00:00:00:02 Action: output=2
    • Matching condition: in_port = 2, dst_mac = 00:00:00:00:00:01 Action: output=1

 

2. 运行

# --topo sigle,3: 单个交换机,3个主机
# --mac: 自动设置主机的MAC地址
# --switch ovsk: 使用 ovs
# --controller remote: 使用外部OpenFlow控制器
# -x: 启动xterm
$ sudo mn --topo single,3 --mac --switch ovsk --controller remote -x

此时会启动5个xterm:h1~h3, switch, controller.

设置OpenFlow版本:switch: s1

# ovs-vsctl set Bridge s1 protocols=OpenFlow13

启动控制器:controller: c0

# ryu-manager --verbose ryu/app/simple_switch_rest_13.py

ping:

mininet> h1 ping -c1 h2

执行Rest API:

$ curl -X GET http://127.0.0.1:8080/simpleswitch/mactable/0000000000000001

$ curl -X PUT -d {"mac" : "00:00:00:00:00:01", "port" : 1} http://127.0.0.1:8080/simpleswitch/mactable/0000000000000001
$ curl -X PUT -d {"mac" : "00:00:00:00:00:02", "port" : 2} http://127.0.0.1:8080/simpleswitch/mactable/0000000000000001

 

参考资料

https://osrg.github.io/ryu-book/en/Ryubook.pdf

ryu—Rest API

上一篇:win10卸载软件的问题


下一篇:搜狗翻译 API nodejs