1 # Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
18 from ryu.app import simple_switch_13
19 from ryu.controller import ofp_event
20 from ryu.controller.handler import CONFIG_DISPATCHER
21 from ryu.controller.handler import set_ev_cls
22 from ryu.app.wsgi import ControllerBase
23 from ryu.app.wsgi import Response
24 from ryu.app.wsgi import route
25 from ryu.app.wsgi import WSGIApplication
26 from ryu.lib import dpid as dpid_lib
28 simple_switch_instance_name = 'simple_switch_api_app'
29 url = '/simpleswitch/mactable/{dpid}'
32 class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13):
34 _CONTEXTS = {'wsgi': WSGIApplication}
36 def __init__(self, *args, **kwargs):
37 super(SimpleSwitchRest13, self).__init__(*args, **kwargs)
40 wsgi.register(SimpleSwitchController,
41 {simple_switch_instance_name: self})
43 @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
44 def switch_features_handler(self, ev):
45 super(SimpleSwitchRest13, self).switch_features_handler(ev)
46 datapath = ev.msg.datapath
47 self.switches[datapath.id] = datapath
48 self.mac_to_port.setdefault(datapath.id, {})
50 def set_mac_to_port(self, dpid, entry):
51 mac_table = self.mac_to_port.setdefault(dpid, {})
52 datapath = self.switches.get(dpid)
54 entry_port = entry['port']
55 entry_mac = entry['mac']
57 if datapath is not None:
58 parser = datapath.ofproto_parser
59 if entry_port not in mac_table.values():
61 for mac, port in mac_table.items():
63 # from known device to new device
64 actions = [parser.OFPActionOutput(entry_port)]
65 match = parser.OFPMatch(in_port=port, eth_dst=entry_mac)
66 self.add_flow(datapath, 1, match, actions)
68 # from new device to known device
69 actions = [parser.OFPActionOutput(port)]
70 match = parser.OFPMatch(in_port=entry_port, eth_dst=mac)
71 self.add_flow(datapath, 1, match, actions)
73 mac_table.update({entry_mac: entry_port})
77 class SimpleSwitchController(ControllerBase):
79 def __init__(self, req, link, data, **config):
80 super(SimpleSwitchController, self).__init__(req, link, data, **config)
81 self.simple_switch_app = data[simple_switch_instance_name]
83 @route('simpleswitch', url, methods=['GET'],
84 requirements={'dpid': dpid_lib.DPID_PATTERN})
85 def list_mac_table(self, req, **kwargs):
87 simple_switch = self.simple_switch_app
88 dpid = dpid_lib.str_to_dpid(kwargs['dpid'])
90 if dpid not in simple_switch.mac_to_port:
91 return Response(status=404)
93 mac_table = simple_switch.mac_to_port.get(dpid, {})
94 body = json.dumps(mac_table)
95 return Response(content_type='application/json', body=body)
97 @route('simpleswitch', url, methods=['PUT'],
98 requirements={'dpid': dpid_lib.DPID_PATTERN})
99 def put_mac_table(self, req, **kwargs):
101 simple_switch = self.simple_switch_app
102 dpid = dpid_lib.str_to_dpid(kwargs['dpid'])
104 new_entry = req.json if req.body else {}
106 raise Response(status=400)
108 if dpid not in simple_switch.mac_to_port:
109 return Response(status=404)
112 mac_table = simple_switch.set_mac_to_port(dpid, new_entry)
113 body = json.dumps(mac_table)
114 return Response(content_type='application/json', body=body)
115 except Exception as e:
116 return Response(status=500)