backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / app / ofctl / service.py
1 # Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2014 YAMAMOTO Takashi <yamamoto at valinux co jp>
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # ofctl service
18
19 import numbers
20
21 from ryu.base import app_manager
22
23 from ryu.controller import ofp_event
24 from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER,\
25     DEAD_DISPATCHER
26 from ryu.controller.handler import set_ev_cls
27
28 from . import event
29 from . import exception
30
31
32 class _SwitchInfo(object):
33     def __init__(self, datapath):
34         self.datapath = datapath
35         self.xids = {}
36         self.barriers = {}
37         self.results = {}
38
39
40 class OfctlService(app_manager.RyuApp):
41     def __init__(self, *args, **kwargs):
42         super(OfctlService, self).__init__(*args, **kwargs)
43         self.name = 'ofctl_service'
44         self._switches = {}
45         self._observing_events = {}
46
47     def _observe_msg(self, msg_cls):
48         assert msg_cls is not None
49         ev_cls = ofp_event.ofp_msg_to_ev_cls(msg_cls)
50         self._observing_events.setdefault(ev_cls, 0)
51         if self._observing_events[ev_cls] == 0:
52             self.logger.debug('ofctl: start observing %s', ev_cls)
53             self.register_handler(ev_cls, self._handle_reply)
54             self.observe_event(ev_cls)
55         self._observing_events[ev_cls] += 1
56
57     def _unobserve_msg(self, msg_cls):
58         assert msg_cls is not None
59         ev_cls = ofp_event.ofp_msg_to_ev_cls(msg_cls)
60         assert self._observing_events[ev_cls] > 0
61         self._observing_events[ev_cls] -= 1
62         if self._observing_events[ev_cls] == 0:
63             self.unregister_handler(ev_cls, self._handle_reply)
64             self.unobserve_event(ev_cls)
65             self.logger.debug('ofctl: stop observing %s', ev_cls)
66
67     def _cancel(self, info, barrier_xid, exception):
68         xid = info.barriers.pop(barrier_xid)
69         req = info.xids.pop(xid)
70         msg = req.msg
71         datapath = msg.datapath
72         parser = datapath.ofproto_parser
73         is_barrier = isinstance(msg, parser.OFPBarrierRequest)
74
75         info.results.pop(xid)
76
77         if not is_barrier and req.reply_cls is not None:
78             self._unobserve_msg(req.reply_cls)
79
80         self.logger.error('failed to send message <%s>', req.msg)
81         self.reply_to_request(req, event.Reply(exception=exception))
82
83     @staticmethod
84     def _is_error(msg):
85         return (ofp_event.ofp_msg_to_ev_cls(type(msg)) ==
86                 ofp_event.EventOFPErrorMsg)
87
88     @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
89     def _switch_features_handler(self, ev):
90         datapath = ev.msg.datapath
91         id = datapath.id
92         assert isinstance(id, numbers.Integral)
93         old_info = self._switches.get(id, None)
94         new_info = _SwitchInfo(datapath=datapath)
95         self.logger.debug('add dpid %s datapath %s new_info %s old_info %s',
96                           id, datapath, new_info, old_info)
97         self._switches[id] = new_info
98         if old_info:
99             old_info.datapath.close()
100             for xid in list(old_info.barriers):
101                 self._cancel(
102                     old_info, xid, exception.InvalidDatapath(result=id))
103
104     @set_ev_cls(ofp_event.EventOFPStateChange, DEAD_DISPATCHER)
105     def _handle_dead(self, ev):
106         datapath = ev.datapath
107         id = datapath.id
108         self.logger.debug('del dpid %s datapath %s', id, datapath)
109         if id is None:
110             return
111         try:
112             info = self._switches[id]
113         except KeyError:
114             return
115         if info.datapath is datapath:
116             self.logger.debug('forget info %s', info)
117             self._switches.pop(id)
118             for xid in list(info.barriers):
119                 self._cancel(info, xid, exception.InvalidDatapath(result=id))
120
121     @set_ev_cls(event.GetDatapathRequest, MAIN_DISPATCHER)
122     def _handle_get_datapath(self, req):
123         result = None
124         if req.dpid is None:
125             result = [v.datapath for v in self._switches.values()]
126         else:
127             if req.dpid in self._switches:
128                 result = self._switches[req.dpid].datapath
129         self.reply_to_request(req, event.Reply(result=result))
130
131     @set_ev_cls(event.SendMsgRequest, MAIN_DISPATCHER)
132     def _handle_send_msg(self, req):
133         msg = req.msg
134         datapath = msg.datapath
135         parser = datapath.ofproto_parser
136         is_barrier = isinstance(msg, parser.OFPBarrierRequest)
137
138         try:
139             si = self._switches[datapath.id]
140         except KeyError:
141             self.logger.error('unknown dpid %s' % (datapath.id,))
142             rep = event.Reply(exception=exception.
143                               InvalidDatapath(result=datapath.id))
144             self.reply_to_request(req, rep)
145             return
146
147         def _store_xid(xid, barrier_xid):
148             assert xid not in si.results
149             assert xid not in si.xids
150             assert barrier_xid not in si.barriers
151             si.results[xid] = []
152             si.xids[xid] = req
153             si.barriers[barrier_xid] = xid
154
155         if is_barrier:
156             barrier = msg
157             datapath.set_xid(barrier)
158             _store_xid(barrier.xid, barrier.xid)
159         else:
160             if req.reply_cls is not None:
161                 self._observe_msg(req.reply_cls)
162             datapath.set_xid(msg)
163             barrier = datapath.ofproto_parser.OFPBarrierRequest(datapath)
164             datapath.set_xid(barrier)
165             _store_xid(msg.xid, barrier.xid)
166             if not datapath.send_msg(msg):
167                 return self._cancel(
168                     si, barrier.xid,
169                     exception.InvalidDatapath(result=datapath.id))
170
171         if not datapath.send_msg(barrier):
172             return self._cancel(
173                 si, barrier.xid,
174                 exception.InvalidDatapath(result=datapath.id))
175
176     @set_ev_cls(ofp_event.EventOFPBarrierReply, MAIN_DISPATCHER)
177     def _handle_barrier(self, ev):
178         msg = ev.msg
179         datapath = msg.datapath
180         parser = datapath.ofproto_parser
181         try:
182             si = self._switches[datapath.id]
183         except KeyError:
184             self.logger.error('unknown dpid %s', datapath.id)
185             return
186         try:
187             xid = si.barriers.pop(msg.xid)
188         except KeyError:
189             self.logger.error('unknown barrier xid %s', msg.xid)
190             return
191         result = si.results.pop(xid)
192         req = si.xids.pop(xid)
193         is_barrier = isinstance(req.msg, parser.OFPBarrierRequest)
194         if req.reply_cls is not None and not is_barrier:
195             self._unobserve_msg(req.reply_cls)
196         if is_barrier and req.reply_cls == parser.OFPBarrierReply:
197             rep = event.Reply(result=ev.msg)
198         elif any(self._is_error(r) for r in result):
199             rep = event.Reply(exception=exception.OFError(result=result))
200         elif req.reply_multi:
201             rep = event.Reply(result=result)
202         elif len(result) == 0:
203             rep = event.Reply()
204         elif len(result) == 1:
205             rep = event.Reply(result=result[0])
206         else:
207             rep = event.Reply(exception=exception.
208                               UnexpectedMultiReply(result=result))
209         self.reply_to_request(req, rep)
210
211     @set_ev_cls(ofp_event.EventOFPErrorMsg, MAIN_DISPATCHER)
212     def _handle_reply(self, ev):
213         msg = ev.msg
214         datapath = msg.datapath
215         try:
216             si = self._switches[datapath.id]
217         except KeyError:
218             self.logger.error('unknown dpid %s', datapath.id)
219             return
220         try:
221             req = si.xids[msg.xid]
222         except KeyError:
223             self.logger.error('unknown error xid %s', msg.xid)
224             return
225         if ((not isinstance(ev, ofp_event.EventOFPErrorMsg)) and
226                 (req.reply_cls is None or not isinstance(ev.msg, req.reply_cls))):
227             self.logger.error('unexpected reply %s for xid %s', ev, msg.xid)
228             return
229         try:
230             si.results[msg.xid].append(ev.msg)
231         except KeyError:
232             self.logger.error('unknown error xid %s', msg.xid)