1 # Copyright (C) 2012 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2012 Isaku Yamahata <yamahata at private email ne jp>
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
8 # http://www.apache.org/licenses/LICENSE-2.0
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
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
20 import ryu.exception as ryu_exc
21 from ryu.base import app_manager
22 from ryu.controller import event
25 class RemoteDPIDAlreadyExist(ryu_exc.RyuException):
26 message = ('port (%(dpid)s, %(port)s) has already '
27 'remote dpid %(remote_dpid)s')
30 class TunnelKeyAlreadyExist(ryu_exc.RyuException):
31 message = 'tunnel key %(tunnel_key)s already exists'
34 class TunnelKeyNotFound(ryu_exc.RyuException):
35 message = 'no tunnel key for network %(network_id)s'
38 class EventTunnelKeyBase(event.EventBase):
39 def __init__(self, network_id, tunnel_key):
40 super(EventTunnelKeyBase, self).__init__()
41 self.network_id = network_id
42 self.tunnel_key = tunnel_key
45 class EventTunnelKeyAdd(EventTunnelKeyBase):
47 An event class for tunnel key registration.
49 This event is generated when a tunnel key is registered or updated
51 An instance has at least the following attributes.
53 =========== ===============================================================
55 =========== ===============================================================
58 =========== ===============================================================
61 def __init__(self, network_id, tunnel_key):
62 super(EventTunnelKeyAdd, self).__init__(network_id, tunnel_key)
65 class EventTunnelKeyDel(EventTunnelKeyBase):
67 An event class for tunnel key registration.
69 This event is generated when a tunnel key is removed by the REST API.
70 An instance has at least the following attributes.
72 =========== ===============================================================
74 =========== ===============================================================
77 =========== ===============================================================
80 def __init__(self, network_id, tunnel_key):
81 super(EventTunnelKeyDel, self).__init__(network_id, tunnel_key)
84 class EventTunnelPort(event.EventBase):
86 An event class for tunnel port registration.
88 This event is generated when a tunnel port is added or removed
90 An instance has at least the following attributes.
92 =========== ===============================================================
94 =========== ===============================================================
95 dpid OpenFlow Datapath ID
96 port_no OpenFlow port number
97 remote_dpid OpenFlow port number of the tunnel peer
98 add_del True for adding a tunnel. False for removal.
99 =========== ===============================================================
102 def __init__(self, dpid, port_no, remote_dpid, add_del):
103 super(EventTunnelPort, self).__init__()
105 self.port_no = port_no
106 self.remote_dpid = remote_dpid
107 self.add_del = add_del
110 class TunnelKeys(dict):
111 """network id(uuid) <-> tunnel key(32bit unsigned int)"""
113 def __init__(self, f):
114 super(TunnelKeys, self).__init__()
117 def get_key(self, network_id):
119 return self[network_id]
121 raise TunnelKeyNotFound(network_id=network_id)
123 def _set_key(self, network_id, tunnel_key):
124 self[network_id] = tunnel_key
125 self.send_event(EventTunnelKeyAdd(network_id, tunnel_key))
127 def register_key(self, network_id, tunnel_key):
128 if network_id in self:
129 raise ryu_exc.NetworkAlreadyExist(network_id=network_id)
130 if tunnel_key in self.values():
131 raise TunnelKeyAlreadyExist(tunnel_key=tunnel_key)
132 self._set_key(network_id, tunnel_key)
134 def update_key(self, network_id, tunnel_key):
135 if network_id not in self and tunnel_key in self.values():
136 raise TunnelKeyAlreadyExist(key=tunnel_key)
138 key = self.get(network_id)
140 self._set_key(network_id, tunnel_key)
142 if key != tunnel_key:
143 raise ryu_exc.NetworkAlreadyExist(network_id=network_id)
145 def delete_key(self, network_id):
147 tunnel_key = self[network_id]
148 self.send_event(EventTunnelKeyDel(network_id, tunnel_key))
151 raise ryu_exc.NetworkNotFound(network_id=network_id)
155 """dpid -> port_no -> remote_dpid"""
157 def __init__(self, f):
158 super(DPIDs, self).__init__()
159 self.dpids = collections.defaultdict(dict)
162 def list_ports(self, dpid):
163 return self.dpids[dpid]
165 def _add_remote_dpid(self, dpid, port_no, remote_dpid):
166 self.dpids[dpid][port_no] = remote_dpid
167 self.send_event(EventTunnelPort(dpid, port_no, remote_dpid, True))
169 def add_remote_dpid(self, dpid, port_no, remote_dpid):
170 if port_no in self.dpids[dpid]:
171 raise ryu_exc.PortAlreadyExist(dpid=dpid, port=port_no,
173 self._add_remote_dpid(dpid, port_no, remote_dpid)
175 def update_remote_dpid(self, dpid, port_no, remote_dpid):
176 remote_dpid_ = self.dpids[dpid].get(port_no)
177 if remote_dpid_ is None:
178 self._add_remote_dpid(dpid, port_no, remote_dpid)
179 elif remote_dpid_ != remote_dpid:
180 raise ryu_exc.RemoteDPIDAlreadyExist(dpid=dpid, port=port_no,
181 remote_dpid=remote_dpid)
183 def get_remote_dpid(self, dpid, port_no):
185 return self.dpids[dpid][port_no]
187 raise ryu_exc.PortNotFound(dpid=dpid, port=port_no)
189 def delete_port(self, dpid, port_no):
191 remote_dpid = self.dpids[dpid][port_no]
192 self.send_event(EventTunnelPort(dpid, port_no, remote_dpid, False))
193 del self.dpids[dpid][port_no]
195 raise ryu_exc.PortNotFound(dpid=dpid, port=port_no)
197 def get_port(self, dpid, remote_dpid):
199 dp = self.dpids[dpid]
201 raise ryu_exc.PortNotFound(dpid=dpid, port=None, network_id=None)
203 res = [port_no for (port_no, remote_dpid_) in dp.items()
204 if remote_dpid_ == remote_dpid]
207 raise ryu_exc.PortNotFound(dpid=dpid, port=None, network_id=None)
211 class Tunnels(app_manager.RyuApp):
213 super(Tunnels, self).__init__()
214 self.name = 'tunnels'
215 self.tunnel_keys = TunnelKeys(self.send_event_to_observers)
216 self.dpids = DPIDs(self.send_event_to_observers)
218 def get_key(self, network_id):
219 return self.tunnel_keys.get_key(network_id)
221 def register_key(self, network_id, tunnel_key):
222 self.tunnel_keys.register_key(network_id, tunnel_key)
224 def update_key(self, network_id, tunnel_key):
225 self.tunnel_keys.update_key(network_id, tunnel_key)
227 def delete_key(self, network_id):
228 self.tunnel_keys.delete_key(network_id)
230 def list_ports(self, dpid):
231 return self.dpids.list_ports(dpid).keys()
233 def register_port(self, dpid, port_no, remote_dpid):
234 self.dpids.add_remote_dpid(dpid, port_no, remote_dpid)
236 def update_port(self, dpid, port_no, remote_dpid):
237 self.dpids.update_remote_dpid(dpid, port_no, remote_dpid)
239 def get_remote_dpid(self, dpid, port_no):
240 return self.dpids.get_remote_dpid(dpid, port_no)
242 def delete_port(self, dpid, port_no):
243 self.dpids.delete_port(dpid, port_no)
246 # methods for gre tunnel
248 def get_port(self, dpid, remote_dpid):
249 return self.dpids.get_port(dpid, remote_dpid)