14
14
# License for the specific language governing permissions and limitations
15
15
# under the License.
17
from sqlalchemy import exc as sa_exc
18
from sqlalchemy import func
19
from sqlalchemy.orm import exc as orm_exc
21
from quantum.common import exceptions as q_exc
17
22
import quantum.db.api as db
18
from quantum.db.models_v2 import Network
19
from quantum.plugins.ryu.db import models_v2
23
from quantum.db import models_v2
24
from quantum.openstack.common import log as logging
25
from quantum.plugins.ryu.db import models_v2 as ryu_models_v2
28
LOG = logging.getLogger(__name__)
22
31
def set_ofp_servers(hosts):
23
32
session = db.get_session()
24
session.query(models_v2.OFPServer).delete()
33
session.query(ryu_models_v2.OFPServer).delete()
25
34
for (host_address, host_type) in hosts:
26
host = models_v2.OFPServer(host_address, host_type)
35
host = ryu_models_v2.OFPServer(address=host_address,
31
41
def network_all_tenant_list():
32
42
session = db.get_session()
33
return session.query(Network).all()
43
return session.query(models_v2.Network).all()
46
class TunnelKey(object):
49
# TODO(yamahata): STT: 64bits
51
_KEY_MAX_HARD = 0xffffffff
53
def __init__(self, key_min=_KEY_MIN_HARD, key_max=_KEY_MAX_HARD):
54
self.key_min = key_min
55
self.key_max = key_max
57
if (key_min < self._KEY_MIN_HARD or key_max > self._KEY_MAX_HARD or
59
raise ValueError(_('Invalid tunnel key options '
60
'tunnel_key_min: %(key_min)d '
61
'tunnel_key_max: %(key_max)d. '
62
'Using default value') % {'key_min': key_min,
65
def _last_key(self, session):
67
return session.query(ryu_models_v2.TunnelKeyLast).one()
68
except orm_exc.MultipleResultsFound:
69
max_key = session.query(
70
func.max(ryu_models_v2.TunnelKeyLast.last_key))
71
if max_key > self.key_max:
72
max_key = self.key_min
74
session.query(ryu_models_v2.TunnelKeyLast).delete()
75
last_key = ryu_models_v2.TunnelKeyLast(last_key=max_key)
76
except orm_exc.NoResultFound:
77
last_key = ryu_models_v2.TunnelKeyLast(last_key=self.key_min)
81
return session.query(ryu_models_v2.TunnelKeyLast).one()
83
def _find_key(self, session, last_key):
85
Try to find unused tunnel key in TunnelKey table starting
87
When all keys are used, raise sqlalchemy.orm.exc.NoResultFound
89
# key 0 is used for special meanings. So don't allocate 0.
91
# sqlite doesn't support
92
# '(select order by limit) union all (select order by limit) '
95
# new_key = session.query("new_key").from_statement(
96
# # If last_key + 1 isn't used, it's the result
98
# 'FROM (SELECT :last_key + 1 AS new_key) q1 '
100
# '(SELECT 1 FROM tunnelkeys WHERE tunnel_key = :last_key + 1) '
104
# # if last_key + 1 used,
105
# # find the least unused key from last_key + 1
106
# '(SELECT t.tunnel_key + 1 AS new_key '
107
# 'FROM tunnelkeys t '
108
# 'WHERE NOT EXISTS '
109
# '(SELECT 1 FROM tunnelkeys ti '
110
# ' WHERE ti.tunnel_key = t.tunnel_key + 1) '
111
# 'AND t.tunnel_key >= :last_key '
112
# 'ORDER BY new_key LIMIT 1) '
114
# 'ORDER BY new_key LIMIT 1'
115
# ).params(last_key=last_key).one()
117
new_key = session.query("new_key").from_statement(
118
# If last_key + 1 isn't used, it's the result
120
'FROM (SELECT :last_key + 1 AS new_key) q1 '
122
'(SELECT 1 FROM tunnelkeys WHERE tunnel_key = :last_key + 1) '
123
).params(last_key=last_key).one()
124
except orm_exc.NoResultFound:
125
new_key = session.query("new_key").from_statement(
126
# if last_key + 1 used,
127
# find the least unused key from last_key + 1
128
'(SELECT t.tunnel_key + 1 AS new_key '
131
'(SELECT 1 FROM tunnelkeys ti '
132
' WHERE ti.tunnel_key = t.tunnel_key + 1) '
133
'AND t.tunnel_key >= :last_key '
134
'ORDER BY new_key LIMIT 1) '
135
).params(last_key=last_key).one()
137
new_key = new_key[0] # the result is tuple.
138
LOG.debug(_("last_key %(last_key)s new_key %(new_key)s") %
139
{"last_key": last_key, "new_key": new_key})
140
if new_key > self.key_max:
141
LOG.debug(_("no key found"))
142
raise orm_exc.NoResultFound()
145
def _allocate(self, session, network_id):
146
last_key = self._last_key(session)
148
new_key = self._find_key(session, last_key.last_key)
149
except orm_exc.NoResultFound:
150
new_key = self._find_key(session, self.key_min)
152
tunnel_key = ryu_models_v2.TunnelKey(network_id=network_id,
154
last_key.last_key = new_key
155
session.add(tunnel_key)
158
_TRANSACTION_RETRY_MAX = 16
160
def allocate(self, session, network_id):
163
session.begin(subtransactions=True)
165
new_key = self._allocate(session, network_id)
168
except sa_exc.SQLAlchemyError:
172
if count > self._TRANSACTION_RETRY_MAX:
173
# if this happens too often, increase _TRANSACTION_RETRY_MAX
174
LOG.warn(_("Transaction retry reaches to %d. "
175
"abandan to allocate tunnel key."), count)
176
raise q_exc.ResourceExhausted()
180
def delete(self, session, network_id):
181
session.query(ryu_models_v2.TunnelKey).filter_by(
182
network_id=network_id).delete()
186
session = db.get_session()
187
return session.query(ryu_models_v2.TunnelKey).all()
190
def port_binding_create(port_id, net_id, dpid, port_no):
191
session = db.get_session()
192
session.query(models_v2.Port).filter(
193
models_v2.Port.network_id == net_id).filter(
194
models_v2.Port.id == port_id).one() # confirm port exists
195
with session.begin():
196
port_binding = ryu_models_v2.PortBinding(net_id, port_id,
198
session.add(port_binding)
203
def port_binding_get(port_id, net_id):
204
session = db.get_session()
205
session.query(models_v2.Port).filter(
206
models_v2.Port.network_id == net_id).filter(
207
models_v2.Port.id == port_id).one() # confirm port exists
208
return session.query(ryu_models_v2.PortBinding).filter_by(
209
network_id=net_id).filter_by(port_id=port_id).one()
212
def port_binding_destroy(session, port_id, net_id):
214
session.query(models_v2.Port).filter(
215
models_v2.Port.network_id == net_id).filter(
216
models_v2.Port.id == port_id).one() # confirm port exists
217
port_binding = session.query(ryu_models_v2.PortBinding).filter_by(
218
network_id=net_id).filter_by(port_id=port_id).one()
219
session.delete(port_binding)
222
except orm_exc.NoResultFound:
223
raise q_exc.PortNotFound(port_id=port_id, net_id=net_id)
226
def port_binding_all_list(session):
227
return session.query(ryu_models_v2.PortBinding).all()
230
def set_port_status(session, port_id, status):
232
port = session.query(models_v2.Port).filter_by(id=port_id).one()
233
port['status'] = status
236
except orm_exc.NoResultFound:
237
raise q_exc.PortNotFound(port_id=port_id, net_id=None)