12
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
13
# License for the specific language governing permissions and limitations
14
14
# under the License.
16
# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc.
17
# @author: Kevin Benton, Big Switch Networks, Inc.
25
23
from neutron.extensions import portbindings
26
24
from neutron.openstack.common import excutils
27
25
from neutron.openstack.common import log
26
from neutron.openstack.common import timeutils
28
27
from neutron.plugins.bigswitch import config as pl_config
29
28
from neutron.plugins.bigswitch import plugin
30
29
from neutron.plugins.bigswitch import servermanager
30
from neutron.plugins.common import constants as pconst
31
31
from neutron.plugins.ml2 import driver_api as api
34
EXTERNAL_PORT_OWNER = 'neutron:external_port'
34
35
LOG = log.getLogger(__name__)
36
put_context_in_serverpool = plugin.put_context_in_serverpool
38
# time in seconds to maintain existence of vswitch response
39
CACHE_VSWITCH_TIME = 60
37
42
class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
59
64
'get_floating_ips': False,
60
65
'get_routers': False}
61
66
self.segmentation_types = ', '.join(cfg.CONF.ml2.type_drivers)
67
# Track hosts running IVS to avoid excessive calls to the backend
68
self.ivs_host_cache = {}
62
70
LOG.debug(_("Initialization done"))
72
@put_context_in_serverpool
64
73
def create_network_postcommit(self, context):
65
74
# create network on the network controller
66
75
self._send_create_network(context.current)
77
@put_context_in_serverpool
68
78
def update_network_postcommit(self, context):
69
79
# update network on the network controller
70
80
self._send_update_network(context.current)
82
@put_context_in_serverpool
72
83
def delete_network_postcommit(self, context):
73
84
# delete network on the network controller
74
85
self._send_delete_network(context.current)
87
@put_context_in_serverpool
76
88
def create_port_postcommit(self, context):
77
89
# create port on the network controller
78
90
port = self._prepare_port_for_controller(context)
80
92
self.async_port_create(port["network"]["tenant_id"],
81
93
port["network"]["id"], port)
95
@put_context_in_serverpool
83
96
def update_port_postcommit(self, context):
84
97
# update port on the network controller
85
98
port = self._prepare_port_for_controller(context)
126
140
# the host_id set
128
142
return prepped_port
144
def bind_port(self, context):
145
"""Marks ports as bound.
147
Binds external ports and IVS ports.
148
Fabric configuration will occur on the subsequent port update.
149
Currently only vlan segments are supported.
151
if context.current['device_owner'] == EXTERNAL_PORT_OWNER:
152
# TODO(kevinbenton): check controller to see if the port exists
153
# so this driver can be run in parallel with others that add
154
# support for external port bindings
155
for segment in context.network.network_segments:
156
if segment[api.NETWORK_TYPE] == pconst.TYPE_VLAN:
158
segment[api.ID], portbindings.VIF_TYPE_BRIDGE,
159
{portbindings.CAP_PORT_FILTER: False,
160
portbindings.OVS_HYBRID_PLUG: False})
163
# IVS hosts will have a vswitch with the same name as the hostname
164
if self.does_vswitch_exist(context.host):
165
for segment in context.network.network_segments:
166
if segment[api.NETWORK_TYPE] == pconst.TYPE_VLAN:
168
segment[api.ID], portbindings.VIF_TYPE_IVS,
169
{portbindings.CAP_PORT_FILTER: True,
170
portbindings.OVS_HYBRID_PLUG: False})
172
def does_vswitch_exist(self, host):
173
"""Check if Indigo vswitch exists with the given hostname.
175
Returns True if switch exists on backend.
176
Returns False if switch does not exist.
177
Returns None if backend could not be reached.
178
Caches response from backend.
181
return self._get_cached_vswitch_existence(host)
183
# cache was empty for that switch or expired
187
self.servers.rest_get_switch(host)
189
except servermanager.RemoteRestError as e:
193
# Another error, return without caching to try again on
196
self.ivs_host_cache[host] = {
197
'timestamp': datetime.datetime.now(),
202
def _get_cached_vswitch_existence(self, host):
203
"""Returns cached existence. Old and non-cached raise ValueError."""
204
entry = self.ivs_host_cache.get(host)
206
raise ValueError(_('No cache entry for host %s') % host)
207
diff = timeutils.delta_seconds(entry['timestamp'],
208
datetime.datetime.now())
209
if diff > CACHE_VSWITCH_TIME:
210
self.ivs_host_cache.pop(host)
211
raise ValueError(_('Expired cache entry for host %s') % host)
212
return entry['exists']