16
16
# under the License.
17
17
# @author: Isaku Yamahata
21
19
from ryu.app import client
20
from ryu.app.client import ignore_http_not_found
22
21
from ryu.app import rest_nw_id
22
from sqlalchemy.exc import IntegrityError
23
from sqlalchemy.orm import exc as orm_exc
25
from quantum.common import constants as q_const
24
26
from quantum.common import exceptions as q_exc
25
27
from quantum.common import topics
26
28
from quantum.db import api as db
27
29
from quantum.db import db_base_plugin_v2
30
from quantum.db.dhcp_rpc_base import DhcpRpcCallbackMixin
28
31
from quantum.db import l3_db
29
32
from quantum.db import models_v2
30
from quantum.db.dhcp_rpc_base import DhcpRpcCallbackMixin
31
33
from quantum.openstack.common import cfg
34
from quantum.openstack.common import log as logging
32
35
from quantum.openstack.common import rpc
33
36
from quantum.openstack.common.rpc import dispatcher
34
from quantum.plugins.ryu import ofp_service_type
35
37
from quantum.plugins.ryu.common import config
36
38
from quantum.plugins.ryu.db import api_v2 as db_api_v2
39
from quantum.plugins.ryu import ofp_service_type
38
42
LOG = logging.getLogger(__name__)
50
54
options.update({"reconnect_interval": reconnect_interval})
51
55
db.configure_db(options)
57
self.tunnel_key = db_api_v2.TunnelKey(
58
cfg.CONF.OVS.tunnel_key_min, cfg.CONF.OVS.tunnel_key_max)
53
59
ofp_con_host = cfg.CONF.OVS.openflow_controller
54
60
ofp_api_host = cfg.CONF.OVS.openflow_rest_api
56
62
if ofp_con_host is None or ofp_api_host is None:
57
raise q_exc.Invalid("invalid configuration. check ryu.ini")
63
raise q_exc.Invalid(_('invalid configuration. check ryu.ini'))
59
65
hosts = [(ofp_con_host, ofp_service_type.CONTROLLER),
60
66
(ofp_api_host, ofp_service_type.REST_API)]
61
67
db_api_v2.set_ofp_servers(hosts)
63
69
self.client = client.OFPClient(ofp_api_host)
64
self.client.update_network(rest_nw_id.NW_ID_EXTERNAL)
70
self.tun_client = client.TunnelClient(ofp_api_host)
71
for nw_id in rest_nw_id.RESERVED_NETWORK_IDS:
72
if nw_id != rest_nw_id.NW_ID_UNKNOWN:
73
self.client.update_network(nw_id)
67
76
# register known all network list on startup
75
84
self.conn.consume_in_thread()
77
86
def _create_all_tenant_network(self):
78
networks = db_api_v2.network_all_tenant_list()
87
for net in db_api_v2.network_all_tenant_list():
80
88
self.client.update_network(net.id)
89
for tun in self.tunnel_key.all_list():
90
self.tun_client.update_tunnel_key(tun.network_id, tun.tunnel_key)
91
session = db.get_session()
92
for port_binding in db_api_v2.port_binding_all_list(session):
93
network_id = port_binding.network_id
94
dpid = port_binding.dpid
95
port_no = port_binding.port_no
97
port = session.query(models_v2.Port).filter(
98
models_v2.Port.id == port_binding.port_id).one()
99
except orm_exc.NoResultFound:
101
except orm_exc.MultipleResultsFound:
104
self.client.update_port(network_id, dpid, port_no)
105
self.client.update_mac(network_id, dpid, port_no, port.mac_address)
107
def _client_create_network(self, net_id, tunnel_key):
108
self.client.create_network(net_id)
109
self.tun_client.create_tunnel_key(net_id, tunnel_key)
111
def _client_delete_network(self, net_id):
112
client.ignore_http_not_found(
113
lambda: self.client.delete_network(net_id))
114
client.ignore_http_not_found(
115
lambda: self.tun_client.delete_tunnel_key(net_id))
82
117
def create_network(self, context, network):
83
118
session = context.session
84
119
with session.begin(subtransactions=True):
85
120
net = super(RyuQuantumPluginV2, self).create_network(context,
87
self.client.create_network(net['id'])
88
122
self._process_l3_create(context, network['network'], net['id'])
89
123
self._extend_network_dict_l3(context, net)
125
tunnel_key = self.tunnel_key.allocate(session, net['id'])
127
self._client_create_network(net['id'], tunnel_key)
129
self._client_delete_network(net['id'])
92
134
def update_network(self, context, id, network):
101
143
def delete_network(self, context, id):
144
self._client_delete_network(id)
102
145
session = context.session
103
146
with session.begin(subtransactions=True):
147
self.tunnel_key.delete(session, id)
104
148
super(RyuQuantumPluginV2, self).delete_network(context, id)
105
self.client.delete_network(id)
107
150
def get_network(self, context, id, fields=None):
108
151
net = super(RyuQuantumPluginV2, self).get_network(context, id, None)
119
162
return [self._fields(net, fields) for net in nets]
121
164
def delete_port(self, context, id, l3_port_check=True):
165
with context.session.begin(subtransactions=True):
166
port = self._get_port(context, id)
167
net_id = port.network_id
169
port_binding = db_api_v2.port_binding_destroy(context.session,
171
datapath_id = port_binding.dpid
172
port_no = port_binding.port_no
173
ignore_http_not_found(
174
lambda: self.client.delete_port(net_id, datapath_id,
176
except q_exc.PortNotFound:
122
179
# if needed, check to see if this is a port owned by
123
180
# and l3-router. If so, we should prevent deletion.
124
181
if l3_port_check:
125
182
self.prevent_l3_port_deletion(context, id)
126
183
self.disassociate_floatingips(context, id)
127
184
return super(RyuQuantumPluginV2, self).delete_port(context, id)
186
def update_port(self, context, id, port):
187
p = super(RyuQuantumPluginV2, self).update_port(context, id, port)
188
net_id = p['network_id']
189
mac_address = p['mac_address']
191
deleted = port['port'].get('deleted', False)
193
session = context.session
195
db_api_v2.port_binding_destroy(session, id, net_id)
196
except q_exc.PortNotFound:
198
db_api_v2.set_port_status(session, id, q_const.PORT_STATUS_DOWN)
201
datapath_id = port['port'].get('datapath_id', None)
202
port_no = port['port'].get('port_no', None)
203
if datapath_id is None or port_no is None:
208
port_binding = db_api_v2.port_binding_get(id, net_id)
209
except orm_exc.NoResultFound:
211
db_api_v2.port_binding_create(id, net_id, datapath_id, port_no)
212
except IntegrityError:
213
# TODO:XXX should do transaction?
216
self.client.create_port(net_id, datapath_id, port_no)
217
self.client.create_mac(net_id, datapath_id, port_no,
220
if (port_binding.dpid != datapath_id or
221
port_binding.port_no != port_no):
222
variables = {'datapath_id': datapath_id,
224
'port_binding_dpid': port_binding.dpid,
225
'port_binding_port_no': port_binding.port_no}
226
raise q_exc.InvalidInput(
227
error_message=_('invalid (datapath_id, port_no) '
229
'(%(datapath_id)s, %(port_no)s), acutal'
230
'(%(port_binding_dpid)s, '
231
'%(port_binding_port_no)s)') % variables)
232
self.client.update_network(net_id)
233
self.client.update_port(net_id, datapath_id, port_no)
234
self.client.update_mac(net_id, datapath_id, port_no, mac_address)