26f855f9c9
Change-Id: I2047f083af01dd0452f61d9fb807098e0514ff36
521 lines
24 KiB
Python
521 lines
24 KiB
Python
# Copyright 2015 VMware, Inc.
|
|
#
|
|
# All Rights Reserved
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from networking_l2gw.db.l2gateway import l2gateway_db
|
|
from networking_l2gw.services.l2gateway.common import constants as l2gw_const
|
|
from networking_l2gw.services.l2gateway import exceptions as l2gw_exc
|
|
from oslo_config import cfg
|
|
from oslo_db import exception as db_exc
|
|
from oslo_log import log as logging
|
|
from oslo_utils import excutils
|
|
from oslo_utils import uuidutils
|
|
|
|
from neutron_lib.api.definitions import provider_net as providernet
|
|
from neutron_lib.callbacks import events
|
|
from neutron_lib.callbacks import registry
|
|
from neutron_lib.callbacks import resources
|
|
from neutron_lib import constants
|
|
from neutron_lib import context
|
|
from neutron_lib.db import api as db_api
|
|
from neutron_lib import exceptions as n_exc
|
|
from neutron_lib.plugins import directory
|
|
from neutron_lib.plugins import utils as plugin_utils
|
|
|
|
from vmware_nsx._i18n import _
|
|
from vmware_nsx.common import utils as nsx_utils
|
|
from vmware_nsx.db import db as nsx_db
|
|
from vmware_nsx.extensions import projectpluginmap
|
|
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
|
from vmware_nsxlib.v3 import nsx_constants
|
|
from vmware_nsxlib.v3 import utils as nsxlib_utils
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class _NotUniqueL2GW(Exception):
|
|
"""Raised if validation of default L2 GW uniqueness fails."""
|
|
|
|
|
|
class NsxV3Driver(l2gateway_db.L2GatewayMixin):
|
|
|
|
"""Class to handle API calls for L2 gateway and NSXv3 backend."""
|
|
gateway_resource = l2gw_const.GATEWAY_RESOURCE_NAME
|
|
|
|
def __init__(self, plugin):
|
|
super(NsxV3Driver, self).__init__()
|
|
self._plugin = plugin
|
|
LOG.debug("Starting service plugin for NSX L2Gateway")
|
|
self.subscribe_callback_notifications()
|
|
LOG.debug("Initialization complete for NSXv3 driver for "
|
|
"L2 gateway service plugin.")
|
|
self.__core_plugin = None
|
|
|
|
@property
|
|
def _core_plugin(self):
|
|
if not self.__core_plugin:
|
|
self.__core_plugin = directory.get_plugin()
|
|
if self.__core_plugin.is_tvd_plugin():
|
|
self.__core_plugin = self.__core_plugin.get_plugin_by_type(
|
|
projectpluginmap.NsxPlugins.NSX_T)
|
|
return self.__core_plugin
|
|
|
|
def subscribe_callback_notifications(self):
|
|
registry.subscribe(self._prevent_l2gw_port_delete, resources.PORT,
|
|
events.BEFORE_DELETE)
|
|
registry.subscribe(self._ensure_default_l2_gateway, resources.PROCESS,
|
|
events.BEFORE_SPAWN)
|
|
|
|
def _find_default_l2_gateway(self, admin_ctx, def_device_id):
|
|
for l2gateway in self._get_l2_gateways(admin_ctx):
|
|
if l2gateway['devices'][0]['device_name'] == def_device_id:
|
|
return l2gateway
|
|
|
|
@nsxlib_utils.retry_random_upon_exception(_NotUniqueL2GW, max_attempts=10)
|
|
def _create_default_l2_gateway(self, admin_ctx, l2gw_dict, def_device_id):
|
|
LOG.debug("Creating default layer-2 gateway with: %s", l2gw_dict)
|
|
def_l2gw = super(NsxV3Driver, self).create_l2_gateway(admin_ctx,
|
|
l2gw_dict)
|
|
# Verify that no other instance of neutron-server had the same
|
|
# brilliant idea...
|
|
l2gateways = self._get_l2_gateways(admin_ctx)
|
|
for l2gateway in l2gateways:
|
|
# Since we ensure L2 gateway is created with only 1 device, we use
|
|
# the first device in the list.
|
|
if l2gateway['devices'][0]['device_name'] == def_device_id:
|
|
if l2gateway['id'] == def_l2gw['id']:
|
|
# Nothing to worry about, that's our gateway
|
|
continue
|
|
LOG.info("Default L2 gateway is already created with "
|
|
"id %s, deleting L2 gateway with id %s",
|
|
l2gateway['id'], def_l2gw['id'])
|
|
# Commit suicide!
|
|
self.validate_l2_gateway_for_delete(
|
|
admin_ctx, def_l2gw)
|
|
# We can be sure the gateway is not in use...
|
|
super(NsxV3Driver, self).delete_l2_gateway(
|
|
admin_ctx, def_l2gw['id'])
|
|
# The operation should be retried to avoid the situation where
|
|
# every instance deletes the gateway it created
|
|
raise _NotUniqueL2GW
|
|
|
|
return def_l2gw
|
|
|
|
def _get_bridge_vlan_tz_id(self, bep_data):
|
|
nsxlib = self._core_plugin.nsxlib
|
|
# Edge cluster Id is mandatory, do not fear KeyError
|
|
edge_cluster_id = bep_data['edge_cluster_id']
|
|
member_indexes = bep_data.get('edge_cluster_member_indexes', [])
|
|
# NSX should not allow bridge endpoint profiles attached to
|
|
# non-existing edge clusters
|
|
edge_cluster = nsxlib.edge_cluster.get(edge_cluster_id)
|
|
member_map = dict((member['member_index'],
|
|
member['transport_node_id'])
|
|
for member in edge_cluster['members'])
|
|
# By default consider all transport nodes in the cluster for
|
|
# retrieving the VLAN transprtzone
|
|
tn_ids = member_map.values()
|
|
if member_indexes:
|
|
try:
|
|
tn_ids = [member_map[idx] for idx in member_indexes]
|
|
except KeyError:
|
|
LOG.warning("Invalid member indexes specified in bridge "
|
|
"endpoint profile: %(bep_id)s: %(indexes)s",
|
|
{'bep_id': bep_data['id'],
|
|
'indexes': member_indexes})
|
|
|
|
# Retrieve VLAN transport zones
|
|
vlan_transport_zones = nsxlib.search_all_resource_by_attributes(
|
|
nsxlib.transport_zone.resource_type,
|
|
transport_type='VLAN')
|
|
vlan_tz_map = dict((vlan_tz['id'], [])
|
|
for vlan_tz in vlan_transport_zones)
|
|
for tn_id in tn_ids:
|
|
tn_data = nsxlib.transport_node.get(tn_id)
|
|
for tz_endpoint in tn_data.get('transport_zone_endpoints', []):
|
|
tz_id = tz_endpoint['transport_zone_id']
|
|
if tz_id in vlan_tz_map:
|
|
vlan_tz_map[tz_id].append(tn_id)
|
|
|
|
# Find the VLAN transport zone that is used by all transport nodes
|
|
results = []
|
|
for (tz_id, nodes) in vlan_tz_map.items():
|
|
if set(nodes) != set(tn_ids):
|
|
continue
|
|
results.append(tz_id)
|
|
|
|
return results
|
|
|
|
def _ensure_default_l2_gateway(self, resource, event,
|
|
trigger, payload=None):
|
|
"""
|
|
Create a default logical L2 gateway.
|
|
|
|
Create a logical L2 gateway in the neutron database for the
|
|
default bridge endpoint profile, if specified in the configuration.
|
|
Ensure only one gateway is configured in presence of multiple
|
|
neutron servers.
|
|
"""
|
|
if cfg.CONF.nsx_v3.default_bridge_cluster:
|
|
LOG.warning("Attention! The default_bridge_cluster option is "
|
|
"still set to %s. This option won't have any effect "
|
|
"as L2 gateways based on bridge clusters are not "
|
|
"implemented anymore",
|
|
cfg.CONF.nsx_v3.default_bridge_cluster)
|
|
def_bep = cfg.CONF.nsx_v3.default_bridge_endpoint_profile
|
|
# Return if no default_endpoint_profile set in config
|
|
if not def_bep:
|
|
LOG.info("NSX Default bridge endpoint profile not set. "
|
|
"Default L2 gateway will not be processed.")
|
|
return
|
|
admin_ctx = context.get_admin_context()
|
|
nsx_bep_client = self._core_plugin.nsxlib.bridge_endpoint_profile
|
|
bep_id = nsx_bep_client.get_id_by_name_or_id(def_bep)
|
|
def_l2gw = self._find_default_l2_gateway(admin_ctx, bep_id)
|
|
# If there is already an existing gateway, use that one
|
|
if def_l2gw:
|
|
LOG.info("A default L2 gateway for bridge endpoint profile "
|
|
"%(bep_id)s already exists. Reusing L2 gateway "
|
|
"%(def_l2gw_id)s)",
|
|
{'bep_id': bep_id, 'def_l2gw_id': def_l2gw['id']})
|
|
return def_l2gw
|
|
bep_data = nsx_bep_client.get(bep_id)
|
|
vlan_tzs = self._get_bridge_vlan_tz_id(bep_data)
|
|
if not vlan_tzs:
|
|
LOG.info("No NSX VLAN transport zone could be used for bridge "
|
|
"endpoint profile: %s. Default L2 gateway will not "
|
|
"be processed", bep_id)
|
|
return
|
|
# TODO(salv-orlando): Implement support for multiple VLAN TZ
|
|
vlan_tz = vlan_tzs[0]
|
|
if len(vlan_tzs) > 1:
|
|
LOG.info("The NSX L2 gateway driver currenly supports a single "
|
|
"VLAN transport zone for bridging, but %(num_tz)d "
|
|
"were specified. Transport zone %(tz)s will be used "
|
|
"for L2 gateways",
|
|
{'num_tz': len(vlan_tzs), 'tz': vlan_tz})
|
|
device = {'device_name': bep_id,
|
|
'interfaces': [{'name': vlan_tz}]}
|
|
# TODO(asarfaty): Add a default v3 tenant-id to allow TVD filtering
|
|
l2gw_dict = {self.gateway_resource: {
|
|
'name': 'default-nsxedge-l2gw',
|
|
'devices': [device]}}
|
|
self._create_default_l2_gateway(admin_ctx, l2gw_dict, bep_id)
|
|
return def_l2gw
|
|
|
|
def _prevent_l2gw_port_delete(self, resource, event,
|
|
trigger, payload=None):
|
|
ctx = payload.context
|
|
port_id = payload.resource_id
|
|
port_check = payload.metadata['port_check']
|
|
if port_check:
|
|
self.prevent_l2gw_port_deletion(ctx, port_id)
|
|
|
|
def _validate_device_list(self, devices, check_backend=True):
|
|
# In NSXv3, one L2 gateway is mapped to one bridge endpoint profle.
|
|
# So we expect only one device to be configured as part of
|
|
# a L2 gateway resource. The name of the device must be the bridge
|
|
# endpoint profile UUID.
|
|
if len(devices) != 1:
|
|
msg = _("Only a single device is supported by the NSX L2"
|
|
"gateway driver")
|
|
raise n_exc.InvalidInput(error_message=msg)
|
|
dev_name = devices[0]['device_name']
|
|
if not uuidutils.is_uuid_like(dev_name):
|
|
msg = _("Device name must be configured with a UUID")
|
|
raise n_exc.InvalidInput(error_message=msg)
|
|
# Ensure the L2GW device is a valid bridge endpoint profile in NSX
|
|
if check_backend:
|
|
try:
|
|
self._core_plugin.nsxlib.bridge_endpoint_profile.get(
|
|
dev_name)
|
|
except nsxlib_exc.ResourceNotFound:
|
|
msg = _("Could not find Bridge Endpoint Profile for L2 "
|
|
"gateway device %s on NSX backend") % dev_name
|
|
LOG.error(msg)
|
|
raise n_exc.InvalidInput(error_message=msg)
|
|
# One L2 gateway must have only one interface defined.
|
|
interfaces = devices[0].get(l2gw_const.IFACE_NAME_ATTR)
|
|
if len(interfaces) > 1:
|
|
msg = _("Maximum of one interface is supported by the NSX L2 "
|
|
"gateway driver")
|
|
raise n_exc.InvalidInput(error_message=msg)
|
|
|
|
def create_l2_gateway(self, ctx, l2_gateway):
|
|
"""Create a logical L2 gateway."""
|
|
gw = l2_gateway[self.gateway_resource]
|
|
devices = gw['devices']
|
|
self._validate_device_list(devices)
|
|
|
|
def create_l2_gateway_precommit(self, ctx, l2_gateway):
|
|
pass
|
|
|
|
def create_l2_gateway_postcommit(self, ctx, l2_gateway):
|
|
pass
|
|
|
|
def update_l2_gateway_precommit(self, ctx, l2_gateway):
|
|
pass
|
|
|
|
def update_l2_gateway_postcommit(self, ctx, l2_gateway):
|
|
pass
|
|
|
|
def delete_l2_gateway(self, ctx, l2_gateway_id):
|
|
pass
|
|
|
|
def delete_l2_gateway_precommit(self, ctx, l2_gateway_id):
|
|
pass
|
|
|
|
def delete_l2_gateway_postcommit(self, ctx, l2_gateway_id):
|
|
pass
|
|
|
|
def _validate_network(self, ctx, network_id):
|
|
network = self._core_plugin.get_network(ctx, network_id)
|
|
network_type = network.get(providernet.NETWORK_TYPE)
|
|
# If network is a provider network, verify whether it is of type GENEVE
|
|
if network_type and network_type != nsx_utils.NsxV3NetworkTypes.GENEVE:
|
|
msg = (_("Unsupported network type %s for L2 gateway connection") %
|
|
network_type)
|
|
raise n_exc.InvalidInput(error_message=msg)
|
|
|
|
def _validate_segment_id(self, seg_id):
|
|
if not seg_id:
|
|
raise l2gw_exc.L2GatewaySegmentationRequired
|
|
return plugin_utils.is_valid_vlan_tag(seg_id)
|
|
|
|
def create_l2_gateway_connection(self, ctx, l2_gateway_connection):
|
|
gw_connection = l2_gateway_connection.get(self.connection_resource)
|
|
network_id = gw_connection.get(l2gw_const.NETWORK_ID)
|
|
self._validate_network(ctx, network_id)
|
|
|
|
def _get_bep(self, ctx, l2gw_id):
|
|
# In NSXv3, there will be only one device configured per L2 gateway.
|
|
# The name of the device shall carry the bridge endpoint profile id.
|
|
devices = self._get_l2_gateway_devices(ctx, l2gw_id)
|
|
return devices[0].get('device_name')
|
|
|
|
def _get_conn_parameters(self, ctx, gw_connection):
|
|
"""Return interface and segmentation id for a connection. """
|
|
if not gw_connection:
|
|
return
|
|
l2gw_id = gw_connection.get(l2gw_const.L2GATEWAY_ID)
|
|
seg_id = gw_connection.get(l2gw_const.SEG_ID)
|
|
devices = self._get_l2_gateway_devices(ctx, l2gw_id)
|
|
# TODO(salv-orlando): support more than a single interface
|
|
interface = self._get_l2_gw_interfaces(ctx, devices[0]['id'])[0]
|
|
if not seg_id:
|
|
# Seg-id was not passed as part of connection-create. Retrieve
|
|
# seg-id from L2 gateway's interface.
|
|
seg_id = interface.get('segmentation_id')
|
|
return interface['interface_name'], seg_id
|
|
|
|
def create_l2_gateway_connection_precommit(self, ctx, gw_connection):
|
|
"""Validate the L2 gateway connection
|
|
Do not allow another connection with the same bride cluster and seg_id
|
|
"""
|
|
admin_ctx = ctx.elevated()
|
|
nsxlib = self._core_plugin.nsxlib
|
|
l2gw_id = gw_connection.get(l2gw_const.L2GATEWAY_ID)
|
|
devices = self._get_l2_gateway_devices(ctx, l2gw_id)
|
|
bep_id = devices[0].get('device_name')
|
|
# Check for bridge endpoint profile existence
|
|
# if bridge endpoint profile is not found, this is likely an old
|
|
# connection, fail with error.
|
|
try:
|
|
nsxlib.bridge_endpoint_profile.get_id_by_name_or_id(bep_id)
|
|
except nsxlib_exc.ManagerError as e:
|
|
msg = (_("Error while retrieving bridge endpoint profile "
|
|
"%(bep_id)s from NSX backend. Check that the profile "
|
|
"exits and there are not multiple profiles with "
|
|
"the given name. Exception: %(exc)s") %
|
|
{'bep_id': bep_id, 'exc': e})
|
|
raise n_exc.InvalidInput(error_message=msg)
|
|
|
|
interface_name, seg_id = self._get_conn_parameters(
|
|
admin_ctx, gw_connection)
|
|
try:
|
|
# Use search API for listing bridge endpoints on NSX for provided
|
|
# VLAN id, transport zone id, and Bridge endpoint profile
|
|
endpoints = nsxlib.search_all_resource_by_attributes(
|
|
nsxlib.bridge_endpoint.resource_type,
|
|
bridge_endpoint_profile_id=bep_id,
|
|
vlan_transport_zone_id=interface_name,
|
|
vlan=seg_id)
|
|
endpoint_map = dict((endpoint['id'],
|
|
endpoint['bridge_endpoint_profile_id'])
|
|
for endpoint in endpoints)
|
|
except nsxlib_exc.ManagerError as e:
|
|
msg = (_("Error while retrieving endpoints for bridge endpoint "
|
|
"profile %(bep_id)s s from NSX backend. "
|
|
"Exception: %(exc)s") % {'bep_id': bep_id, 'exc': e})
|
|
raise n_exc.InvalidInput(error_message=msg)
|
|
|
|
# get all bridge endpoint ports
|
|
with db_api.CONTEXT_WRITER.using(admin_ctx):
|
|
port_filters = {'device_owner': [nsx_constants.BRIDGE_ENDPOINT]}
|
|
ports = self._core_plugin.get_ports(
|
|
admin_ctx, filters=port_filters)
|
|
for port in ports:
|
|
device_id = port.get('device_id')
|
|
if endpoint_map.get(device_id) == bep_id:
|
|
# This device is using the same vlan id and bridge endpoint
|
|
# profile as the one requested. Not ok.
|
|
msg = (_("Cannot create multiple connections with the "
|
|
"same segmentation id %(seg_id)s for bridge "
|
|
"endpoint profile %(bep_id)s") %
|
|
{'seg_id': seg_id,
|
|
'bep_id': bep_id})
|
|
raise n_exc.InvalidInput(error_message=msg)
|
|
|
|
def create_l2_gateway_connection_postcommit(self, ctx, gw_connection):
|
|
"""Create a L2 gateway connection on the backend"""
|
|
nsxlib = self._core_plugin.nsxlib
|
|
l2gw_id = gw_connection.get(l2gw_const.L2GATEWAY_ID)
|
|
network_id = gw_connection.get(l2gw_const.NETWORK_ID)
|
|
device_name = self._get_bep(ctx, l2gw_id)
|
|
interface_name, seg_id = self._get_conn_parameters(
|
|
ctx, gw_connection)
|
|
self._validate_segment_id(seg_id)
|
|
tenant_id = gw_connection['tenant_id']
|
|
if ctx.is_admin and not tenant_id:
|
|
tenant_id = ctx.tenant_id
|
|
gw_connection['tenant_id'] = tenant_id
|
|
try:
|
|
tags = nsxlib.build_v3_tags_payload(
|
|
gw_connection, resource_type='os-neutron-l2gw-id',
|
|
project_name=ctx.tenant_name)
|
|
bridge_endpoint = nsxlib.bridge_endpoint.create(
|
|
device_name=device_name,
|
|
vlan_transport_zone_id=interface_name,
|
|
vlan_id=seg_id,
|
|
tags=tags)
|
|
except nsxlib_exc.ManagerError as e:
|
|
LOG.exception("Unable to create bridge endpoint. "
|
|
"Exception is %s", e)
|
|
raise l2gw_exc.L2GatewayServiceDriverError(
|
|
method='create_l2_gateway_connection_postcommit')
|
|
|
|
port_dict = {'port': {
|
|
'name': 'l2gw-conn-%s-%s' % (
|
|
l2gw_id, seg_id),
|
|
'tenant_id': tenant_id,
|
|
'network_id': network_id,
|
|
'mac_address': constants.ATTR_NOT_SPECIFIED,
|
|
'admin_state_up': True,
|
|
'fixed_ips': [],
|
|
'device_id': bridge_endpoint['id'],
|
|
'device_owner': nsx_constants.BRIDGE_ENDPOINT}}
|
|
try:
|
|
#TODO(abhiraut): Consider adding UT for port check once UTs are
|
|
# refactored
|
|
port = self._core_plugin.create_port(ctx, port_dict,
|
|
l2gw_port_check=True)
|
|
# Deallocate IP address from the port.
|
|
for fixed_ip in port.get('fixed_ips', []):
|
|
self._core_plugin._delete_ip_allocation(ctx, network_id,
|
|
fixed_ip['subnet_id'],
|
|
fixed_ip['ip_address'])
|
|
LOG.debug("IP addresses deallocated on port %s", port['id'])
|
|
except (nsxlib_exc.ManagerError,
|
|
n_exc.NeutronException) as e:
|
|
with excutils.save_and_reraise_exception():
|
|
LOG.exception("Unable to create L2 gateway port, "
|
|
"rolling back changes on backend: %s", e)
|
|
self._core_plugin.nsxlib.bridge_endpoint.delete(
|
|
bridge_endpoint['id'])
|
|
super(NsxV3Driver,
|
|
self).delete_l2_gateway_connection(
|
|
ctx,
|
|
gw_connection['id'])
|
|
|
|
try:
|
|
with db_api.CONTEXT_WRITER.using(ctx):
|
|
# Update neutron's database with the mappings.
|
|
nsx_db.add_l2gw_connection_mapping(
|
|
session=ctx.session,
|
|
connection_id=gw_connection['id'],
|
|
bridge_endpoint_id=bridge_endpoint['id'],
|
|
port_id=port['id'])
|
|
# If no segmentation_id was passed as a part of the
|
|
# connection object, update it with the one inherited
|
|
# from the device spec
|
|
if seg_id and not gw_connection.get(l2gw_const.SEG_ID):
|
|
conn_db = self._plugin._get_l2_gateway_connection(
|
|
ctx, gw_connection['id'])
|
|
conn_db['segmentation_id'] = seg_id
|
|
# Ensure the object is updated as well so the
|
|
# create response returns the segmentation_id
|
|
gw_connection[l2gw_const.SEG_ID] = seg_id
|
|
except db_exc.DBError:
|
|
with excutils.save_and_reraise_exception():
|
|
LOG.exception("Unable to add L2 gateway connection "
|
|
"mappings for %(conn_id)s on network "
|
|
"%(net_id)s. rolling back changes.",
|
|
{'conn_id': gw_connection['id'],
|
|
'net_id': network_id})
|
|
self._core_plugin.nsxlib.bridge_endpoint.delete(
|
|
bridge_endpoint['id'])
|
|
super(NsxV3Driver,
|
|
self).delete_l2_gateway_connection(
|
|
ctx,
|
|
gw_connection['id'])
|
|
return gw_connection
|
|
|
|
def delete_l2_gateway_connection_postcommit(self, ctx, gw_connection):
|
|
pass
|
|
|
|
def delete_l2_gateway_connection_precommit(self, ctx, gw_connection):
|
|
pass
|
|
|
|
def delete_l2_gateway_connection(self, ctx, gw_connection):
|
|
"""Delete a L2 gateway connection."""
|
|
conn_mapping = nsx_db.get_l2gw_connection_mapping(
|
|
session=ctx.session,
|
|
connection_id=gw_connection)
|
|
if not conn_mapping:
|
|
LOG.error("Unable to delete gateway connection %(id)s: mapping "
|
|
"not found", {'id': gw_connection})
|
|
# Do not block the deletion
|
|
return
|
|
bridge_endpoint_id = conn_mapping.get('bridge_endpoint_id')
|
|
# Delete the logical port from the bridge endpoint.
|
|
self._core_plugin.delete_port(context=ctx,
|
|
port_id=conn_mapping.get('port_id'),
|
|
l2gw_port_check=False)
|
|
try:
|
|
self._core_plugin.nsxlib.bridge_endpoint.delete(bridge_endpoint_id)
|
|
except nsxlib_exc.ManagerError as e:
|
|
LOG.exception("Unable to delete bridge endpoint %(id)s on the "
|
|
"backend due to exc: %(exc)s",
|
|
{'id': bridge_endpoint_id, 'exc': e})
|
|
raise l2gw_exc.L2GatewayServiceDriverError(
|
|
method='delete_l2_gateway_connection')
|
|
|
|
def prevent_l2gw_port_deletion(self, ctx, port_id):
|
|
"""Prevent core plugin from deleting L2 gateway port."""
|
|
try:
|
|
port = self._core_plugin.get_port(ctx, port_id)
|
|
except n_exc.PortNotFound:
|
|
return
|
|
if port['device_owner'] == nsx_constants.BRIDGE_ENDPOINT:
|
|
reason = _("has device owner %s") % port['device_owner']
|
|
raise n_exc.ServicePortInUse(port_id=port_id, reason=reason)
|
|
|
|
def add_port_mac(self, ctx, port_dict):
|
|
"""Process a created Neutron port."""
|
|
|
|
def delete_port_mac(self, ctx, port):
|
|
"""Process a deleted Neutron port."""
|