From 2c21c6170995d8e36cff421640baf9cda6b89c1a Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Sun, 24 Dec 2017 11:30:13 +0200 Subject: [PATCH] TVD+BGP: adapt the nsx bgp plugin to be used in TVD The BGP plugin and driver used for NSX-v should be used for TVD as well. This plugin suports only NSX-V under the TVD plugin. Change-Id: I95be40fe0f58f0ff2b06590400d708ee95294b82 --- .../services/dynamic_routing/bgp_plugin.py | 226 ++++++++++++++---- .../services/dynamic_routing/nsx_v/driver.py | 9 +- .../dynamic_routing/test_nsxv_bgp_driver.py | 61 ++++- 3 files changed, 232 insertions(+), 64 deletions(-) diff --git a/vmware_nsx/services/dynamic_routing/bgp_plugin.py b/vmware_nsx/services/dynamic_routing/bgp_plugin.py index 9f14f3fd28..cbadc538b5 100644 --- a/vmware_nsx/services/dynamic_routing/bgp_plugin.py +++ b/vmware_nsx/services/dynamic_routing/bgp_plugin.py @@ -20,27 +20,46 @@ from neutron_lib.callbacks import events from neutron_lib.callbacks import registry from neutron_lib.callbacks import resources from neutron_lib import context as n_context +from neutron_lib import exceptions as n_exc +from neutron_lib.plugins import directory from neutron_lib.services import base as service_base from oslo_log import log as logging from vmware_nsx.common import locking from vmware_nsx.common import nsxv_constants +from vmware_nsx.db import db as nsx_db from vmware_nsx.db import nsxv_db from vmware_nsx.extensions import edge_service_gateway_bgp_peer as ext_esg +from vmware_nsx.extensions import projectpluginmap from vmware_nsx.services.dynamic_routing.nsx_v import driver as nsxv_driver LOG = logging.getLogger(__name__) PLUGIN_NAME = bgp_ext.BGP_EXT_ALIAS + '_nsx_svc_plugin' -class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin): +class NSXBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin): + """BGP service plugin for NSX-V as well as TVD plugins. + + Currently only the nsx-v is supported. other plugins will be refused. + """ supported_extension_aliases = [bgp_ext.BGP_EXT_ALIAS, ext_esg.ESG_BGP_PEER_EXT_ALIAS] def __init__(self): - super(NSXvBgpPlugin, self).__init__() - self.nsxv_driver = nsxv_driver.NSXvBgpDriver(self) + super(NSXBgpPlugin, self).__init__() + self._core_plugin = directory.get_plugin() + + # initialize the supported drivers (currently only NSX-v) + self.drivers = {} + try: + self.drivers[projectpluginmap.NsxPlugins.NSX_V] = ( + nsxv_driver.NSXvBgpDriver(self)) + except Exception: + # No driver found + LOG.warning("NSXBgpPlugin failed to initialize the NSX-V driver") + self.drivers[projectpluginmap.NsxPlugins.NSX_V] = None + self._register_callbacks() def get_plugin_name(self): @@ -74,50 +93,105 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin): nsxv_constants.SERVICE_EDGE, events.BEFORE_DELETE) + def _get_driver_by_project(self, context, project): + # Check if the current project id has a matching driver + # Currently only NSX-V is supported + if self._core_plugin.is_tvd_plugin(): + mapping = nsx_db.get_project_plugin_mapping( + context.session, project) + if mapping: + plugin_type = mapping['plugin'] + else: + msg = (_("Couldn't find the plugin project %s is " + "using") % project) + raise n_exc.InvalidInput(error_message=msg) + + # make sure the core plugin is supported + if not self._core_plugin.get_plugin_by_type(plugin_type): + msg = (_("Plugin %(plugin)s for project %(project)s is not " + "supported by the core plugin") % { + 'project': project, + 'plugin': plugin_type}) + raise n_exc.InvalidInput(error_message=msg) + else: + plugin_type = self._core_plugin.plugin_type() + + if not self.drivers.get(plugin_type): + msg = (_("Project %(project)s with plugin %(plugin)s has no " + "support for dynamic routing") % { + 'project': project, + 'plugin': plugin_type}) + raise n_exc.InvalidInput(error_message=msg) + + return self.drivers[plugin_type] + + def _get_driver_by_speaker(self, context, bgp_speaker_id): + try: + speaker = self.get_bgp_speaker(context, bgp_speaker_id) + except Exception: + msg = _("BGP speaker %s could not be found") % bgp_speaker_id + raise n_exc.BadRequest(resource=bgp_ext.BGP_SPEAKER_RESOURCE_NAME, + msg=msg) + return self._get_driver_by_project(context, speaker['tenant_id']) + def create_bgp_speaker(self, context, bgp_speaker): - self.nsxv_driver.create_bgp_speaker(context, bgp_speaker) - return super(NSXvBgpPlugin, self).create_bgp_speaker(context, - bgp_speaker) + driver = self._get_driver_by_project( + context, bgp_speaker['bgp_speaker']['tenant_id']) + driver.create_bgp_speaker(context, bgp_speaker) + return super(NSXBgpPlugin, self).create_bgp_speaker(context, + bgp_speaker) def update_bgp_speaker(self, context, bgp_speaker_id, bgp_speaker): + driver = self._get_driver_by_speaker(context, bgp_speaker_id) with locking.LockManager.get_lock(str(bgp_speaker_id)): - self.nsxv_driver.update_bgp_speaker(context, bgp_speaker_id, - bgp_speaker) + driver.update_bgp_speaker(context, bgp_speaker_id, bgp_speaker) # TBD(roeyc): rolling back changes on edges base class call failed. - return super(NSXvBgpPlugin, self).update_bgp_speaker( + return super(NSXBgpPlugin, self).update_bgp_speaker( context, bgp_speaker_id, bgp_speaker) def delete_bgp_speaker(self, context, bgp_speaker_id): + driver = self._get_driver_by_speaker(context, bgp_speaker_id) with locking.LockManager.get_lock(str(bgp_speaker_id)): - self.nsxv_driver.delete_bgp_speaker(context, bgp_speaker_id) - super(NSXvBgpPlugin, self).delete_bgp_speaker(context, - bgp_speaker_id) + driver.delete_bgp_speaker(context, bgp_speaker_id) + super(NSXBgpPlugin, self).delete_bgp_speaker(context, + bgp_speaker_id) def _add_esg_peer_info(self, context, peer): + # TODO(asarfaty): only if nsxv driver, or do it in the driver itself binding = nsxv_db.get_nsxv_bgp_peer_edge_binding(context.session, peer['id']) if binding: peer['esg_id'] = binding['edge_id'] def get_bgp_peer(self, context, bgp_peer_id, fields=None): - peer = super(NSXvBgpPlugin, self).get_bgp_peer(context, - bgp_peer_id, fields) + peer = super(NSXBgpPlugin, self).get_bgp_peer(context, + bgp_peer_id, fields) if not fields or 'esg_id' in fields: self._add_esg_peer_info(context, peer) return peer def get_bgp_peers_by_bgp_speaker(self, context, bgp_speaker_id, fields=None): - ret = super(NSXvBgpPlugin, self).get_bgp_peers_by_bgp_speaker( + ret = super(NSXBgpPlugin, self).get_bgp_peers_by_bgp_speaker( context, bgp_speaker_id, fields=fields) if fields is None or 'esg_id' in fields: for peer in ret: self._add_esg_peer_info(context, peer) return ret + def _get_driver_by_peer(self, context, bgp_peer_id): + try: + peer = self.get_bgp_peer(context, bgp_peer_id) + except Exception: + raise bgp_ext.BgpPeerNotFound(id=bgp_peer_id) + return self._get_driver_by_project(context, peer['tenant_id']) + def create_bgp_peer(self, context, bgp_peer): - self.nsxv_driver.create_bgp_peer(context, bgp_peer) - peer = super(NSXvBgpPlugin, self).create_bgp_peer(context, bgp_peer) + driver = self._get_driver_by_project( + context, bgp_peer['bgp_peer']['tenant_id']) + driver.create_bgp_peer(context, bgp_peer) + peer = super(NSXBgpPlugin, self).create_bgp_peer(context, bgp_peer) + # TODO(asarfaty): only if nsxv driver, or do it in the driver itself esg_id = bgp_peer['bgp_peer'].get('esg_id') if esg_id: nsxv_db.add_nsxv_bgp_peer_edge_binding(context.session, peer['id'], @@ -126,14 +200,16 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin): return peer def update_bgp_peer(self, context, bgp_peer_id, bgp_peer): - super(NSXvBgpPlugin, self).update_bgp_peer(context, - bgp_peer_id, bgp_peer) - self.nsxv_driver.update_bgp_peer(context, bgp_peer_id, bgp_peer) + driver = self._get_driver_by_peer(context, bgp_peer_id) + super(NSXBgpPlugin, self).update_bgp_peer(context, + bgp_peer_id, bgp_peer) + driver.update_bgp_peer(context, bgp_peer_id, bgp_peer) return self.get_bgp_peer(context, bgp_peer_id) def delete_bgp_peer(self, context, bgp_peer_id): + driver = self._get_driver_by_peer(context, bgp_peer_id) bgp_peer_info = {'bgp_peer_id': bgp_peer_id} - bgp_speaker_ids = self.nsxv_driver._get_bgp_speakers_by_bgp_peer( + bgp_speaker_ids = driver._get_bgp_speakers_by_bgp_peer( context, bgp_peer_id) for speaker_id in bgp_speaker_ids: try: @@ -141,42 +217,74 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin): except bgp_ext.BgpSpeakerPeerNotAssociated: LOG.debug("Couldn't find bgp speaker %s peer binding while " "deleting bgp peer %s", speaker_id, bgp_peer_id) - super(NSXvBgpPlugin, self).delete_bgp_peer(context, bgp_peer_id) + super(NSXBgpPlugin, self).delete_bgp_peer(context, bgp_peer_id) def add_bgp_peer(self, context, bgp_speaker_id, bgp_peer_info): + # speaker & peer must belong to the same driver + if not bgp_peer_info.get('bgp_peer_id'): + msg = _("bgp_peer_id must be specified") + raise n_exc.BadRequest(resource='bgp-peer', msg=msg) + peer_driver = self._get_driver_by_peer( + context, bgp_peer_info['bgp_peer_id']) + speaker_driver = self._get_driver_by_speaker(context, bgp_speaker_id) + if peer_driver != speaker_driver: + msg = _("Peer and Speaker must belong to the same plugin") + raise n_exc.InvalidInput(error_message=msg) with locking.LockManager.get_lock(str(bgp_speaker_id)): - self.nsxv_driver.add_bgp_peer(context, - bgp_speaker_id, bgp_peer_info) - return super(NSXvBgpPlugin, self).add_bgp_peer(context, - bgp_speaker_id, - bgp_peer_info) + speaker_driver.add_bgp_peer(context, + bgp_speaker_id, bgp_peer_info) + return super(NSXBgpPlugin, self).add_bgp_peer(context, + bgp_speaker_id, + bgp_peer_info) def remove_bgp_peer(self, context, bgp_speaker_id, bgp_peer_info): + driver = self._get_driver_by_speaker(context, bgp_speaker_id) with locking.LockManager.get_lock(str(bgp_speaker_id)): - ret = super(NSXvBgpPlugin, self).remove_bgp_peer( + ret = super(NSXBgpPlugin, self).remove_bgp_peer( context, bgp_speaker_id, bgp_peer_info) - self.nsxv_driver.remove_bgp_peer(context, - bgp_speaker_id, bgp_peer_info) + driver.remove_bgp_peer(context, bgp_speaker_id, bgp_peer_info) return ret + def _validate_network_plugin( + self, context, network_info, + plugin_type=projectpluginmap.NsxPlugins.NSX_V): + """Make sure the network belongs to the NSX0-V plugin""" + if not network_info.get('network_id'): + msg = _("network_id must be specified") + raise n_exc.BadRequest(resource=bgp_ext.BGP_SPEAKER_RESOURCE_NAME, + msg=msg) + net_id = network_info['network_id'] + p = self._core_plugin._get_plugin_from_net_id(context, net_id) + if p.plugin_type() != plugin_type: + msg = (_('Network should belong to the %s plugin as the bgp ' + 'speaker') % plugin_type) + raise n_exc.InvalidInput(error_message=msg) + def add_gateway_network(self, context, bgp_speaker_id, network_info): + driver = self._get_driver_by_speaker(context, bgp_speaker_id) + if self._core_plugin.is_tvd_plugin(): + # The plugin of the network and speaker must be the same + self._validate_network_plugin(context, network_info) + with locking.LockManager.get_lock(str(bgp_speaker_id)): - self.nsxv_driver.add_gateway_network(context, - bgp_speaker_id, - network_info) - return super(NSXvBgpPlugin, self).add_gateway_network( + driver.add_gateway_network(context, + bgp_speaker_id, + network_info) + return super(NSXBgpPlugin, self).add_gateway_network( context, bgp_speaker_id, network_info) def remove_gateway_network(self, context, bgp_speaker_id, network_info): + driver = self._get_driver_by_speaker(context, bgp_speaker_id) with locking.LockManager.get_lock(str(bgp_speaker_id)): - super(NSXvBgpPlugin, self).remove_gateway_network( + super(NSXBgpPlugin, self).remove_gateway_network( context, bgp_speaker_id, network_info) - self.nsxv_driver.remove_gateway_network(context, - bgp_speaker_id, - network_info) + driver.remove_gateway_network(context, + bgp_speaker_id, + network_info) def get_advertised_routes(self, context, bgp_speaker_id): - return self.nsxv_driver.get_advertised_routes(context, bgp_speaker_id) + driver = self._get_driver_by_speaker(context, bgp_speaker_id) + return driver.get_advertised_routes(context, bgp_speaker_id) def router_interface_callback(self, resource, event, trigger, **kwargs): if not kwargs['network_id']: @@ -195,15 +303,17 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin): speaker_id = speaker.id with locking.LockManager.get_lock(str(speaker_id)): speaker = self.get_bgp_speaker(context, speaker_id) + driver = self._get_driver_by_project( + context, speaker['tenant_id']) if network_id not in speaker['networks']: continue if event == events.AFTER_CREATE: - self.nsxv_driver.advertise_subnet(context, speaker_id, - router_id, subnets[0]) + driver.advertise_subnet(context, speaker_id, + router_id, subnets[0]) if event == events.AFTER_DELETE: subnet_id = port['fixed_ips'][0]['subnet_id'] - self.nsxv_driver.withdraw_subnet(context, speaker_id, - router_id, subnet_id) + driver.withdraw_subnet(context, speaker_id, + router_id, subnet_id) def router_gateway_callback(self, resource, event, trigger, **kwargs): context = kwargs.get('context') or n_context.get_admin_context() @@ -214,20 +324,22 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin): for speaker in speakers: speaker_id = speaker.id + driver = self._get_driver_by_project( + context, speaker['tenant_id']) with locking.LockManager.get_lock(str(speaker_id)): speaker = self.get_bgp_speaker(context, speaker_id) if network_id not in speaker['networks']: continue if event == events.AFTER_DELETE: gw_ips = kwargs['gateway_ips'] - self.nsxv_driver.disable_bgp_on_router(context, - speaker, - router_id, - gw_ips[0]) + driver.disable_bgp_on_router(context, + speaker, + router_id, + gw_ips[0]) if event == events.AFTER_UPDATE: updated_port = kwargs['updated_port'] router = kwargs['router'] - self.nsxv_driver.process_router_gw_port_update( + driver.process_router_gw_port_update( context, speaker, router, updated_port) def _before_service_edge_delete_callback(self, resource, event, @@ -239,13 +351,15 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin): edge_id = kwargs.get('edge_id') speakers = self._bgp_speakers_for_gateway_network(context, ext_net_id) for speaker in speakers: + driver = self._get_driver_by_project( + context, speaker['tenant_id']) with locking.LockManager.get_lock(speaker.id): speaker = self.get_bgp_speaker(context, speaker.id) if ext_net_id not in speaker['networks']: continue - self.nsxv_driver.disable_bgp_on_router(context, speaker, - router['id'], - gw_ip, edge_id) + driver.disable_bgp_on_router(context, speaker, + router['id'], + gw_ip, edge_id) def _after_service_edge_create_callback(self, resource, event, trigger, **kwargs): @@ -254,9 +368,15 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin): ext_net_id = router.gw_port and router.gw_port['network_id'] speakers = self._bgp_speakers_for_gateway_network(context, ext_net_id) for speaker in speakers: + driver = self._get_driver_by_project( + context, speaker['tenant_id']) with locking.LockManager.get_lock(speaker.id): speaker = self.get_bgp_speaker(context, speaker.id) if ext_net_id not in speaker['networks']: continue - self.nsxv_driver.enable_bgp_on_router(context, speaker, - router['id']) + driver.enable_bgp_on_router(context, speaker, router['id']) + + +class NSXvBgpPlugin(NSXBgpPlugin): + """Defined for backwards compatibility only""" + pass diff --git a/vmware_nsx/services/dynamic_routing/nsx_v/driver.py b/vmware_nsx/services/dynamic_routing/nsx_v/driver.py index 3434139fec..c21a5f528f 100644 --- a/vmware_nsx/services/dynamic_routing/nsx_v/driver.py +++ b/vmware_nsx/services/dynamic_routing/nsx_v/driver.py @@ -31,6 +31,7 @@ from vmware_nsx.common import locking from vmware_nsx.common import nsxv_constants from vmware_nsx.db import nsxv_db from vmware_nsx.extensions import edge_service_gateway_bgp_peer as ext_esg_peer +from vmware_nsx.extensions import projectpluginmap from vmware_nsx.plugins.nsx_v.vshield.common import exceptions as vcns_exc LOG = logging.getLogger(__name__) @@ -87,6 +88,12 @@ class NSXvBgpDriver(object): super(NSXvBgpDriver, self).__init__() self._plugin = 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_V) + if not self._core_plugin: + err_msg = _("NSXv BGP cannot work without the NSX-V core plugin") + raise n_exc.InvalidInput(error_message=err_msg) self._nsxv = self._core_plugin.nsx_v self._edge_manager = self._core_plugin.edge_manager @@ -99,7 +106,7 @@ class NSXvBgpDriver(object): if not edge_binding: return None, None - # Idicates which routes should be advertised - connected or static. + # Indicates which routes should be advertised - connected or static. advertise_static_routes = False if edge_binding['edge_type'] != nsxv_constants.SERVICE_EDGE: # Distributed router diff --git a/vmware_nsx/tests/unit/services/dynamic_routing/test_nsxv_bgp_driver.py b/vmware_nsx/tests/unit/services/dynamic_routing/test_nsxv_bgp_driver.py index a9e426eb18..f3125ab1a0 100644 --- a/vmware_nsx/tests/unit/services/dynamic_routing/test_nsxv_bgp_driver.py +++ b/vmware_nsx/tests/unit/services/dynamic_routing/test_nsxv_bgp_driver.py @@ -43,13 +43,15 @@ class TestNSXvBgpPlugin(test_plugin.NsxVPluginV2TestCase, service_plugins = {ext_bgp.BGP_EXT_ALIAS: BGP_PLUGIN} super(TestNSXvBgpPlugin, self).setUp(service_plugins=service_plugins) self.bgp_plugin = bgp_plugin.NSXvBgpPlugin() - self.bgp_plugin.nsxv_driver._validate_gateway_network = mock.Mock() - self.bgp_plugin.nsxv_driver._validate_bgp_configuration_on_peer_esg = ( + self.nsxv_driver = self.bgp_plugin.drivers['nsx-v'] + self.nsxv_driver._validate_gateway_network = mock.Mock() + self.nsxv_driver._validate_bgp_configuration_on_peer_esg = ( mock.Mock()) self.plugin = directory.get_plugin() self.l3plugin = self.plugin self.plugin.init_is_complete = True self.context = context.get_admin_context() + self.project_id = 'dummy_project' @contextlib.contextmanager def gw_network(self, external=True, **kwargs): @@ -85,18 +87,46 @@ class TestNSXvBgpPlugin(test_plugin.NsxVPluginV2TestCase, 'esg_id': esg_id, 'auth_type': 'none', 'password': '', - 'tenant_id': ''} + 'tenant_id': self.project_id} bgp_peer = self.bgp_plugin.create_bgp_peer(self.context, {'bgp_peer': data}) yield bgp_peer self.bgp_plugin.delete_bgp_peer(self.context, bgp_peer['id']) + @contextlib.contextmanager + def bgp_speaker(self, ip_version, local_as, name='my-speaker', + advertise_fip_host_routes=True, + advertise_tenant_networks=True, + networks=None, peers=None): + data = {'ip_version': ip_version, + test_bgp_db.ADVERTISE_FIPS_KEY: advertise_fip_host_routes, + 'advertise_tenant_networks': advertise_tenant_networks, + 'local_as': local_as, 'name': name, + 'tenant_id': self.project_id} + bgp_speaker = self.bgp_plugin.create_bgp_speaker(self.context, + {'bgp_speaker': data}) + bgp_speaker_id = bgp_speaker['id'] + + if networks: + for network_id in networks: + self.bgp_plugin.add_gateway_network( + self.context, + bgp_speaker_id, + {'network_id': network_id}) + if peers: + for peer_id in peers: + self.bgp_plugin.add_bgp_peer(self.context, bgp_speaker_id, + {'bgp_peer_id': peer_id}) + + yield self.bgp_plugin.get_bgp_speaker(self.context, bgp_speaker_id) + def test_create_v6_bgp_speaker(self): fake_bgp_speaker = { "bgp_speaker": { "ip_version": 6, "local_as": "1000", - "name": "bgp-speaker" + "name": "bgp-speaker", + "tenant_id": self.project_id } } self.assertRaises(n_exc.InvalidInput, @@ -109,7 +139,8 @@ class TestNSXvBgpPlugin(test_plugin.NsxVPluginV2TestCase, "auth_type": "none", "remote_as": "1000", "name": "bgp-peer", - "peer_ip": "fc00::/7" + "peer_ip": "fc00::/7", + "tenant_id": self.project_id } } self.assertRaises(n_exc.InvalidInput, @@ -128,13 +159,14 @@ class TestNSXvBgpPlugin(test_plugin.NsxVPluginV2TestCase, def test_create_bgp_peer_md5_auth_no_password(self): bgp_peer = {'bgp_peer': {'auth_type': 'md5', 'password': None, - 'peer_ip': '10.0.0.3'}} + 'peer_ip': '10.0.0.3', + 'tenant_id': self.project_id}} self.assertRaises(ext_bgp.InvalidBgpPeerMd5Authentication, self.bgp_plugin.create_bgp_peer, self.context, bgp_peer) def test_add_non_external_gateway_network(self): - self.bgp_plugin.nsxv_driver._validate_gateway_network = ( + self.nsxv_driver._validate_gateway_network = ( bgp_driver.NSXvBgpDriver( self.bgp_plugin)._validate_gateway_network) with self.gw_network(external=False) as net,\ @@ -170,15 +202,14 @@ class TestNSXvBgpPlugin(test_plugin.NsxVPluginV2TestCase, with self.router(external_gateway_info=gw_info1) as rtr1,\ self.router(external_gateway_info=gw_info2) as rtr2,\ mock.patch.object( - self.bgp_plugin.nsxv_driver, - '_get_router_edge_info', + self.nsxv_driver, '_get_router_edge_info', return_value=('edge-1', False)),\ mock.patch.object( self.plugin.edge_manager, 'get_routers_on_same_edge', return_value=[rtr1['id'], rtr2['id']]),\ mock.patch.object( - self.bgp_plugin.nsxv_driver, + self.nsxv_driver, '_update_edge_bgp_identifier') as up_bgp: gw_clear = {u'router': {u'external_gateway_info': {}}} self.plugin.update_router(self.context, @@ -246,3 +277,13 @@ class TestNSXvBgpPlugin(test_plugin.NsxVPluginV2TestCase, def test__get_routes_by_router_with_fip(self): # base class tests uses no-snat router with floating ips self.skipTest('No SNAT with floating ips not supported') + + def test_add_bgp_peer_with_bad_id(self): + with self.subnetpool_with_address_scope( + 4, prefixes=['8.0.0.0/8']) as sp: + with self.bgp_speaker(sp['ip_version'], 1234) as speaker: + self.assertRaises(ext_bgp.BgpPeerNotFound, + self.bgp_plugin.add_bgp_peer, + self.context, + speaker['id'], + {'bgp_peer_id': 'aaa'})