Merge "NSXv BGP support"
This commit is contained in:
commit
232fb88221
@ -107,6 +107,19 @@ Add neutron-fwaas repo as an external repository and configure following flags i
|
||||
driver = vmware_nsx.services.fwaas.nsx_v.edge_fwaas_driver.EdgeFwaasDriver
|
||||
|
||||
|
||||
Neutron dynamic routing plugin (bgp)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Add neutron-dynamic-routing repo as an external repository and configure following flags in ``local.conf``::
|
||||
|
||||
[[local|localrc]]
|
||||
enable_plugin neutron-dynamic-routing https://git.openstack.org/openstack/neutron-dynamic-routing
|
||||
DR_MODE=dr_plugin
|
||||
|
||||
[[post-config|$NEUTRON_CONF]]
|
||||
[DEFAULT]
|
||||
api_extensions_path = $DEST/neutron-dynamic-routing/neutron_dynamic_routing/extensions
|
||||
|
||||
|
||||
NSXv3
|
||||
-----
|
||||
|
||||
|
@ -9,6 +9,7 @@ ${DIR}/tox_install_project.sh networking-sfc networking_sfc $*
|
||||
${DIR}/tox_install_project.sh neutron-lbaas neutron_lbaas $*
|
||||
${DIR}/tox_install_project.sh vmware-nsxlib vmware_nsxlib $*
|
||||
${DIR}/tox_install_project.sh neutron-fwaas neutron_fwaas $*
|
||||
${DIR}/tox_install_project.sh neutron-dynamic-routing neutron-dynamic-routing $*
|
||||
|
||||
CONSTRAINTS_FILE=$1
|
||||
shift
|
||||
|
@ -1 +1 @@
|
||||
7c4704ad37df
|
||||
8699700cd95c
|
||||
|
@ -0,0 +1,51 @@
|
||||
# Copyright 2017 VMware, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""nsxv_bgp_speaker_mapping
|
||||
|
||||
Revision ID: 8699700cd95c
|
||||
Revises: 7c4704ad37df
|
||||
Create Date: 2017-02-16 03:13:39.775670
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '8699700cd95c'
|
||||
down_revision = '7c4704ad37df'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'nsxv_bgp_speaker_bindings',
|
||||
sa.Column('edge_id', sa.String(36), nullable=False),
|
||||
sa.Column('bgp_speaker_id', sa.String(36), nullable=False),
|
||||
sa.Column('bgp_identifier', sa.String(64), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['bgp_speaker_id'], ['bgp_speakers.id'],
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('edge_id'))
|
||||
|
||||
op.create_table(
|
||||
'nsxv_bgp_peer_edge_bindings',
|
||||
sa.Column('peer_id', sa.String(36), nullable=False),
|
||||
sa.Column('edge_id', sa.String(36), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['peer_id'], ['bgp_peers.id'],
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('peer_id'))
|
@ -894,3 +894,56 @@ def update_nsxv_port_ext_attributes(session, port_id,
|
||||
except exc.NoResultFound:
|
||||
return add_nsxv_port_ext_attributes(
|
||||
session, port_id, vnic_type=vnic_type)
|
||||
|
||||
|
||||
def add_nsxv_bgp_speaker_binding(session, edge_id, speaker_id,
|
||||
bgp_identifier):
|
||||
with session.begin(subtransactions=True):
|
||||
binding = nsxv_models.NsxvBgpSpeakerBinding(
|
||||
edge_id=edge_id,
|
||||
bgp_speaker_id=speaker_id,
|
||||
bgp_identifier=bgp_identifier)
|
||||
session.add(binding)
|
||||
return binding
|
||||
|
||||
|
||||
def get_nsxv_bgp_speaker_binding(session, edge_id):
|
||||
try:
|
||||
binding = (session.query(nsxv_models.NsxvBgpSpeakerBinding).
|
||||
filter_by(edge_id=edge_id).
|
||||
one())
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
LOG.debug("No dynamic routing enabled on edge %s.", edge_id)
|
||||
|
||||
|
||||
def get_nsxv_bgp_speaker_bindings(session, speaker_id):
|
||||
try:
|
||||
return (session.query(nsxv_models.NsxvBgpSpeakerBinding).
|
||||
filter_by(bgp_speaker_id=speaker_id).all())
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def delete_nsxv_bgp_speaker_binding(session, edge_id):
|
||||
binding = session.query(
|
||||
nsxv_models.NsxvBgpSpeakerBinding).filter_by(edge_id=edge_id)
|
||||
if binding:
|
||||
binding.delete()
|
||||
|
||||
|
||||
def add_nsxv_bgp_peer_edge_binding(session, peer_id, edge_id):
|
||||
with session.begin(subtransactions=True):
|
||||
binding = nsxv_models.NsxvBgpPeerEdgeBinding(edge_id=edge_id,
|
||||
peer_id=peer_id)
|
||||
session.add(binding)
|
||||
return binding
|
||||
|
||||
|
||||
def get_nsxv_bgp_peer_edge_binding(session, peer_id):
|
||||
try:
|
||||
binding = (session.query(nsxv_models.NsxvBgpPeerEdgeBinding).
|
||||
filter_by(peer_id=peer_id).one())
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
|
@ -381,3 +381,28 @@ class NsxvPortExtAttributes(model_base.BASEV2, models.TimestampMixin):
|
||||
models_v2.Port,
|
||||
backref=orm.backref("nsx_port_attributes", lazy='joined',
|
||||
uselist=False, cascade='delete'))
|
||||
|
||||
|
||||
class NsxvBgpSpeakerBinding(model_base.BASEV2, models.TimestampMixin):
|
||||
# Maps bgp_speaker_id to NSXv edge id
|
||||
__tablename__ = 'nsxv_bgp_speaker_bindings'
|
||||
|
||||
edge_id = sa.Column(sa.String(36), primary_key=True)
|
||||
bgp_speaker_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('bgp_speakers.id',
|
||||
ondelete='CASCADE'),
|
||||
nullable=False)
|
||||
# A given BGP speaker sets the value of its BGP Identifier to an IP address
|
||||
# that is assigned to that BGP speaker.
|
||||
bgp_identifier = sa.Column(sa.String(64), nullable=False)
|
||||
|
||||
|
||||
class NsxvBgpPeerEdgeBinding(model_base.BASEV2, models.TimestampMixin):
|
||||
# Maps between bgp-peer and edges service gateway.
|
||||
__tablename__ = 'nsxv_bgp_peer_edge_bindings'
|
||||
peer_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('bgp_peers.id',
|
||||
ondelete='CASCADE'),
|
||||
primary_key=True,
|
||||
nullable=False)
|
||||
edge_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
98
vmware_nsx/extensions/edge_service_gateway_bgp_peer.py
Normal file
98
vmware_nsx/extensions/edge_service_gateway_bgp_peer.py
Normal file
@ -0,0 +1,98 @@
|
||||
# Copyright 2017 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.
|
||||
|
||||
import re
|
||||
|
||||
from neutron_lib.api import extensions
|
||||
from neutron_lib.api import validators
|
||||
from neutron_lib import exceptions as nexception
|
||||
|
||||
from vmware_nsx._i18n import _
|
||||
|
||||
EDGE_SERVICE_GW = 'esg_id'
|
||||
ESG_BGP_PEER_EXT_ALIAS = 'edge-service-gateway-bgp-peer'
|
||||
|
||||
|
||||
def _validate_edge_service_gw_id(esg_id, valid_values=None):
|
||||
if re.match(r'^edge-[1-9]+[0-9]*$', esg_id) is None:
|
||||
msg = _("'%s' is not a valid edge service gateway id.") % esg_id
|
||||
return msg
|
||||
|
||||
|
||||
validators.add_validator('validate_edge_service_gw_id',
|
||||
_validate_edge_service_gw_id)
|
||||
|
||||
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
'bgp-peers': {
|
||||
EDGE_SERVICE_GW: {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'default': None,
|
||||
'validate': {'type:validate_edge_service_gw_id': None},
|
||||
'enforce_policy': True,
|
||||
'is_visible': True,
|
||||
'required_by_policy': False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class BgpDisabledOnEsgPeer(nexception.InvalidInput):
|
||||
message = _("To add this peer to BGP speaker you must first enable BGP on "
|
||||
"the associated ESG - '%(esg_id)s'.")
|
||||
|
||||
|
||||
class EsgRemoteASDoNotMatch(nexception.InvalidInput):
|
||||
message = _("Specified remote AS is '%(remote_as)s', but ESG '%(esg_id)s' "
|
||||
"is configured on AS %(esg_as)s.")
|
||||
|
||||
|
||||
class ExternalSubnetHasGW(nexception.InvalidInput):
|
||||
message = _("Subnet '%(subnet_id)s' on external network '%(network_id)s' "
|
||||
"is configured with gateway IP, set to None before enabling "
|
||||
"BGP on the network.")
|
||||
|
||||
|
||||
class Edge_service_gateway_bgp_peer(extensions.ExtensionDescriptor):
|
||||
"""Extension class to allow identifying of-peer with specificN SXv edge
|
||||
service gateway.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Edge service gateway bgp peer"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return ESG_BGP_PEER_EXT_ALIAS
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return ("Adding a new (optional) attribute 'esg_id' to bgp-peer "
|
||||
"resource, where esg_id is a valid NSXv Edge service gateway "
|
||||
"id.")
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2017-04-01T10:00:00-00:00"
|
||||
|
||||
def get_required_extensions(self):
|
||||
return ["bgp"]
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return RESOURCE_ATTRIBUTE_MAP
|
||||
else:
|
||||
return {}
|
200
vmware_nsx/plugins/nsx_v/vshield/edge_dynamic_routing_driver.py
Normal file
200
vmware_nsx/plugins/nsx_v/vshield/edge_dynamic_routing_driver.py
Normal file
@ -0,0 +1,200 @@
|
||||
# Copyright 2017 VMware, Inc
|
||||
#
|
||||
# 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 oslo_log import log as logging
|
||||
|
||||
from vmware_nsx.common import locking
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EdgeDynamicRoutingDriver(object):
|
||||
|
||||
"""Edge driver API to implement the dynamic routing"""
|
||||
|
||||
def __init__(self):
|
||||
# it will be initialized at subclass
|
||||
self.vcns = None
|
||||
|
||||
def _get_routing_global_config(self, edge_id):
|
||||
h, config = self.vcns.get_dynamic_routing_service(edge_id)
|
||||
global_config = config if config else {}
|
||||
global_config.setdefault('ipPrefixes', {'ipPrefixes': []})
|
||||
curr_prefixes = [{'ipPrefix': prx}
|
||||
for prx in global_config['ipPrefixes']['ipPrefixes']]
|
||||
global_config['ipPrefixes'] = curr_prefixes
|
||||
return {'routingGlobalConfig': global_config}
|
||||
|
||||
def _update_global_routing_config(self, edge_id, **kwargs):
|
||||
global_config = self._get_routing_global_config(edge_id)
|
||||
current_prefixes = global_config['routingGlobalConfig']['ipPrefixes']
|
||||
|
||||
global_config['routingGlobalConfig']['ecmp'] = True
|
||||
|
||||
if 'router_id' in kwargs:
|
||||
global_config['routingGlobalConfig']['routerId'] = (
|
||||
kwargs['router_id'])
|
||||
|
||||
current_prefixes[:] = [p for p in current_prefixes
|
||||
if p['ipPrefix']['name'] not in
|
||||
kwargs.get('prefixes_to_remove', [])]
|
||||
# Avoid adding duplicate rules when shared router relocation
|
||||
current_prefixes.extend([p for p in kwargs.get('prefixes_to_add', [])
|
||||
if p not in current_prefixes])
|
||||
|
||||
self.vcns.update_dynamic_routing_service(edge_id, global_config)
|
||||
|
||||
def _reset_routing_global_config(self, edge_id):
|
||||
global_config = self._get_routing_global_config(edge_id)
|
||||
global_config['routingGlobalConfig']['ecmp'] = False
|
||||
global_config['routingGlobalConfig'].pop('routerId', None)
|
||||
global_config['routingGlobalConfig'].pop('ipPrefixes', None)
|
||||
self.vcns.update_dynamic_routing_service(edge_id, global_config)
|
||||
|
||||
def get_routing_bgp_config(self, edge_id):
|
||||
h, config = self.vcns.get_bgp_routing_config(edge_id)
|
||||
bgp_config = config if config else {}
|
||||
bgp_config.setdefault('enabled', False)
|
||||
bgp_config.setdefault('bgpNeighbours', {'bgpNeighbours': []})
|
||||
bgp_config.setdefault('redistribution', {'rules': {'rules': []}})
|
||||
|
||||
curr_neighbours = [{'bgpNeighbour': nbr} for nbr in
|
||||
bgp_config['bgpNeighbours']['bgpNeighbours']]
|
||||
bgp_config['bgpNeighbours'] = curr_neighbours
|
||||
for nbr in curr_neighbours:
|
||||
bgp_filters = [{'bgpFilter': bf} for bf
|
||||
in nbr['bgpNeighbour']['bgpFilters']['bgpFilters']]
|
||||
nbr['bgpNeighbour']['bgpFilters'] = bgp_filters
|
||||
redistribution_rules = [{'rule': rule} for rule in
|
||||
bgp_config['redistribution']['rules']['rules']]
|
||||
bgp_config['redistribution']['rules'] = redistribution_rules
|
||||
return {'bgp': bgp_config}
|
||||
|
||||
def _update_bgp_routing_config(self, edge_id, **kwargs):
|
||||
bgp_config = self.get_routing_bgp_config(edge_id)
|
||||
curr_neighbours = bgp_config['bgp']['bgpNeighbours']
|
||||
curr_rules = bgp_config['bgp']['redistribution']['rules']
|
||||
|
||||
bgp_config['bgp']['enabled'] = True
|
||||
|
||||
if 'local_as' in kwargs:
|
||||
bgp_config['bgp']['localAS'] = kwargs['local_as']
|
||||
|
||||
if 'enabled' in kwargs:
|
||||
bgp_config['bgp']['redistribution']['enabled'] = kwargs['enabled']
|
||||
|
||||
curr_rules[:] = [rule for rule in curr_rules
|
||||
if rule['rule'].get('prefixName') not in
|
||||
kwargs.get('rules_to_remove', [])]
|
||||
# Avoid adding duplicate rules when shared router relocation
|
||||
curr_rules_prefixes = [r['rule'].get('prefixName') for r in curr_rules]
|
||||
curr_rules.extend([r for r in kwargs.get('rules_to_add', [])
|
||||
if r['rule'].get('prefixName') not in
|
||||
curr_rules_prefixes])
|
||||
|
||||
neighbours_to_remove = [nbr['bgpNeighbour']['ipAddress'] for nbr in
|
||||
kwargs.get('neighbours_to_remove', [])]
|
||||
curr_neighbours[:] = [nbr for nbr in curr_neighbours
|
||||
if nbr['bgpNeighbour']['ipAddress']
|
||||
not in neighbours_to_remove]
|
||||
curr_neighbours.extend(kwargs.get('neighbours_to_add', []))
|
||||
|
||||
self.vcns.update_bgp_dynamic_routing(edge_id, bgp_config)
|
||||
|
||||
def _get_edge_static_routes(self, edge_id):
|
||||
h, routes = self.vcns.get_routes(edge_id)
|
||||
static_routes = routes if routes else {}
|
||||
static_routes.setdefault('staticRoutes', {'staticRoutes': []})
|
||||
return static_routes
|
||||
|
||||
def _remove_default_static_routes(self, edge_id, droutes=None):
|
||||
routes = self._get_edge_static_routes(edge_id)
|
||||
# if droutes is empty or None, then remove all default static routes
|
||||
droutes = droutes or routes['staticRoutes']['staticRoutes']
|
||||
droutes = [r['nextHop'] for r in droutes]
|
||||
routes['staticRoutes']['staticRoutes'] = [
|
||||
r for r in routes['staticRoutes']['staticRoutes']
|
||||
if r['network'] != '0.0.0.0/0' or r['nextHop'] not in droutes]
|
||||
self.vcns.update_routes(edge_id, routes)
|
||||
|
||||
def _add_default_static_routes(self, edge_id, default_routes):
|
||||
routes = self._get_edge_static_routes(edge_id)
|
||||
routes['staticRoutes']['staticRoutes'].extend(default_routes)
|
||||
self.vcns.update_routes(edge_id, routes)
|
||||
|
||||
def add_bgp_speaker_config(self, edge_id, prot_router_id, local_as,
|
||||
enabled, default_routes, bgp_neighbours,
|
||||
prefixes, redistribution_rules):
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
self._update_global_routing_config(edge_id,
|
||||
router_id=prot_router_id,
|
||||
prefixes_to_add=prefixes)
|
||||
self._update_bgp_routing_config(edge_id, enabled=enabled,
|
||||
local_as=local_as,
|
||||
neighbours_to_add=bgp_neighbours,
|
||||
prefixes_to_add=prefixes,
|
||||
rules_to_add=redistribution_rules)
|
||||
self._add_default_static_routes(edge_id, default_routes)
|
||||
|
||||
def delete_bgp_speaker_config(self, edge_id):
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
self.vcns.delete_bgp_routing_config(edge_id)
|
||||
self._remove_default_static_routes(edge_id)
|
||||
self._reset_routing_global_config(edge_id)
|
||||
|
||||
def add_bgp_neighbours(self, edge_id, bgp_neighbours,
|
||||
default_routes=None):
|
||||
# Query the bgp config first and update the bgpNeighbour
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
self._update_bgp_routing_config(edge_id,
|
||||
neighbours_to_add=bgp_neighbours)
|
||||
if default_routes:
|
||||
self._add_default_static_routes(edge_id, default_routes)
|
||||
|
||||
def remove_bgp_neighbours(self, edge_id, bgp_neighbours,
|
||||
default_routes=None):
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
self._update_bgp_routing_config(
|
||||
edge_id, neighbours_to_remove=bgp_neighbours)
|
||||
if default_routes:
|
||||
self._remove_default_static_routes(edge_id, default_routes)
|
||||
|
||||
def update_bgp_neighbour(self, edge_id, bgp_neighbour):
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
self._update_bgp_routing_config(
|
||||
edge_id,
|
||||
neighbours_to_remove=[bgp_neighbour],
|
||||
neighbours_to_add=[bgp_neighbour])
|
||||
|
||||
def update_routing_redistribution(self, edge_id, enabled):
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
self._update_bgp_routing_config(edge_id, enabled=enabled)
|
||||
|
||||
def add_bgp_redistribution_rules(self, edge_id, prefixes, rules):
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
self._update_global_routing_config(edge_id,
|
||||
prefixes_to_add=prefixes)
|
||||
self._update_bgp_routing_config(edge_id, rules_to_add=rules)
|
||||
LOG.debug("Added redistribution rules %s on edge %s", rules, edge_id)
|
||||
|
||||
def remove_bgp_redistribution_rules(self, edge_id, prefixes):
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
self._update_bgp_routing_config(edge_id, rules_to_remove=prefixes)
|
||||
self._update_global_routing_config(edge_id,
|
||||
prefixes_to_remove=prefixes)
|
||||
LOG.debug("Removed redistribution rules for prefixes %s on edge %s",
|
||||
prefixes, edge_id)
|
||||
|
||||
def update_router_id(self, edge_id, router_id):
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
self._update_global_routing_config(edge_id, router_id=router_id)
|
@ -83,6 +83,10 @@ CERTIFICATE = "certificate"
|
||||
|
||||
NETWORK_TYPES = ['Network', 'VirtualWire', 'DistributedVirtualPortgroup']
|
||||
|
||||
# Dynamic routing constants
|
||||
GLOBAL_ROUTING_CONFIG = "routing/config/global"
|
||||
BGP_ROUTING_CONFIG = "routing/config/bgp"
|
||||
|
||||
|
||||
def retry_upon_exception_exclude_error_codes(
|
||||
exc, excluded_errors, delay=0.5, max_delay=4, max_attempts=0):
|
||||
@ -1065,3 +1069,27 @@ class Vcns(object):
|
||||
uri = '%s/scope/globalroot-0' % APPLICATION_PREFIX
|
||||
h, apps = self.do_request(HTTP_GET, uri, decode=True)
|
||||
return apps
|
||||
|
||||
def update_dynamic_routing_service(self, edge_id, request_config):
|
||||
uri = self._build_uri_path(edge_id, GLOBAL_ROUTING_CONFIG)
|
||||
return self.do_request(HTTP_PUT, uri,
|
||||
VcnsApiClient.xmldumps(request_config),
|
||||
format='xml')
|
||||
|
||||
def get_dynamic_routing_service(self, edge_id):
|
||||
uri = self._build_uri_path(edge_id, GLOBAL_ROUTING_CONFIG)
|
||||
return self.do_request(HTTP_GET, uri)
|
||||
|
||||
def update_bgp_dynamic_routing(self, edge_id, bgp_request):
|
||||
uri = self._build_uri_path(edge_id, BGP_ROUTING_CONFIG)
|
||||
return self.do_request(HTTP_PUT, uri,
|
||||
VcnsApiClient.xmldumps(bgp_request),
|
||||
format='xml')
|
||||
|
||||
def get_bgp_routing_config(self, edge_id):
|
||||
uri = self._build_uri_path(edge_id, BGP_ROUTING_CONFIG)
|
||||
return self.do_request(HTTP_GET, uri)
|
||||
|
||||
def delete_bgp_routing_config(self, edge_id):
|
||||
uri = self._build_uri_path(edge_id, BGP_ROUTING_CONFIG)
|
||||
return self.do_request(HTTP_DELETE, uri)
|
||||
|
@ -18,6 +18,7 @@ from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vmware_nsx.plugins.nsx_v.vshield import edge_appliance_driver
|
||||
from vmware_nsx.plugins.nsx_v.vshield import edge_dynamic_routing_driver
|
||||
from vmware_nsx.plugins.nsx_v.vshield import edge_firewall_driver
|
||||
from vmware_nsx.plugins.nsx_v.vshield.tasks import tasks
|
||||
from vmware_nsx.plugins.nsx_v.vshield import vcns
|
||||
@ -29,7 +30,8 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
class VcnsDriver(edge_appliance_driver.EdgeApplianceDriver,
|
||||
lbaas_v2.EdgeLoadbalancerDriverV2,
|
||||
edge_firewall_driver.EdgeFirewallDriver):
|
||||
edge_firewall_driver.EdgeFirewallDriver,
|
||||
edge_dynamic_routing_driver.EdgeDynamicRoutingDriver):
|
||||
|
||||
def __init__(self, callbacks):
|
||||
super(VcnsDriver, self).__init__()
|
||||
|
0
vmware_nsx/services/dynamic_routing/__init__.py
Normal file
0
vmware_nsx/services/dynamic_routing/__init__.py
Normal file
256
vmware_nsx/services/dynamic_routing/bgp_plugin.py
Normal file
256
vmware_nsx/services/dynamic_routing/bgp_plugin.py
Normal file
@ -0,0 +1,256 @@
|
||||
# Copyright 2017 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 oslo_log import log as logging
|
||||
|
||||
from neutron.callbacks import events
|
||||
from neutron.callbacks import registry
|
||||
from neutron.callbacks import resources
|
||||
from neutron_dynamic_routing.db import bgp_db
|
||||
from neutron_dynamic_routing.extensions import bgp as bgp_ext
|
||||
from neutron_lib import context as n_context
|
||||
from neutron_lib.services import base as service_base
|
||||
|
||||
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
|
||||
from vmware_nsx.services.dynamic_routing.nsx_v import driver as nsxv_driver
|
||||
|
||||
PLUGIN_NAME = bgp_ext.BGP_EXT_ALIAS + '_nsx_svc_plugin'
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin):
|
||||
|
||||
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)
|
||||
self._register_callbacks()
|
||||
|
||||
def get_plugin_name(self):
|
||||
return PLUGIN_NAME
|
||||
|
||||
def get_plugin_type(self):
|
||||
return bgp_ext.BGP_EXT_ALIAS
|
||||
|
||||
def get_plugin_description(self):
|
||||
"""returns string description of the plugin."""
|
||||
return ("BGP dynamic routing service for announcement of next-hops "
|
||||
"for project networks, floating IP's, and DVR host routes.")
|
||||
|
||||
def _register_callbacks(self):
|
||||
registry.subscribe(self.router_interface_callback,
|
||||
resources.ROUTER_INTERFACE,
|
||||
events.AFTER_CREATE)
|
||||
registry.subscribe(self.router_interface_callback,
|
||||
resources.ROUTER_INTERFACE,
|
||||
events.AFTER_DELETE)
|
||||
registry.subscribe(self.router_gateway_callback,
|
||||
resources.ROUTER_GATEWAY,
|
||||
events.AFTER_CREATE)
|
||||
registry.subscribe(self.router_gateway_callback,
|
||||
resources.ROUTER_GATEWAY,
|
||||
events.AFTER_DELETE)
|
||||
registry.subscribe(self._after_service_edge_create_callback,
|
||||
nsxv_constants.SERVICE_EDGE,
|
||||
events.AFTER_CREATE)
|
||||
registry.subscribe(self._before_service_edge_delete_callback,
|
||||
nsxv_constants.SERVICE_EDGE,
|
||||
events.BEFORE_DELETE)
|
||||
|
||||
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)
|
||||
|
||||
def update_bgp_speaker(self, context, bgp_speaker_id, bgp_speaker):
|
||||
with locking.LockManager.get_lock(str(bgp_speaker_id)):
|
||||
self.nsxv_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(
|
||||
context, bgp_speaker_id, bgp_speaker)
|
||||
|
||||
def delete_bgp_speaker(self, 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)
|
||||
|
||||
def _get_esg_peer_info(self, context, bgp_peer_id):
|
||||
binding = nsxv_db.get_nsxv_bgp_peer_edge_binding(context.session,
|
||||
bgp_peer_id)
|
||||
if binding:
|
||||
return 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)
|
||||
if fields is None or 'esg_id' in fields:
|
||||
peer['esg_id'] = self._get_esg_peer_info(context, bgp_peer_id)
|
||||
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(
|
||||
context, bgp_speaker_id, fields=fields)
|
||||
if fields is None or 'esg_id' in fields:
|
||||
for peer in ret:
|
||||
peer['esg_id'] = self._get_esg_peer_info(context, peer['id'])
|
||||
return ret
|
||||
|
||||
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)
|
||||
esg_id = bgp_peer['bgp_peer'].get('esg_id')
|
||||
if esg_id:
|
||||
nsxv_db.add_nsxv_bgp_peer_edge_binding(context.session, peer['id'],
|
||||
esg_id)
|
||||
peer['esg_id'] = esg_id
|
||||
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)
|
||||
return self.get_bgp_peer(context, bgp_peer_id)
|
||||
|
||||
def delete_bgp_peer(self, 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(
|
||||
context, bgp_peer_id)
|
||||
for speaker_id in bgp_speaker_ids:
|
||||
self.remove_bgp_peer(context, speaker_id, bgp_peer_info)
|
||||
super(NSXvBgpPlugin, self).delete_bgp_peer(context, bgp_peer_id)
|
||||
|
||||
def add_bgp_peer(self, context, bgp_speaker_id, bgp_peer_info):
|
||||
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)
|
||||
|
||||
def remove_bgp_peer(self, context, bgp_speaker_id, bgp_peer_info):
|
||||
with locking.LockManager.get_lock(str(bgp_speaker_id)):
|
||||
speaker = self._get_bgp_speaker(context, bgp_speaker_id)
|
||||
if bgp_peer_info['bgp_peer_id'] not in speaker['peers']:
|
||||
return
|
||||
self.nsxv_driver.remove_bgp_peer(context,
|
||||
bgp_speaker_id, bgp_peer_info)
|
||||
return super(NSXvBgpPlugin, self).remove_bgp_peer(
|
||||
context, bgp_speaker_id, bgp_peer_info)
|
||||
|
||||
def add_gateway_network(self, context, bgp_speaker_id, 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(
|
||||
context, bgp_speaker_id, network_info)
|
||||
|
||||
def remove_gateway_network(self, context, bgp_speaker_id, network_info):
|
||||
with locking.LockManager.get_lock(str(bgp_speaker_id)):
|
||||
super(NSXvBgpPlugin, self).remove_gateway_network(
|
||||
context, bgp_speaker_id, network_info)
|
||||
self.nsxv_driver.remove_gateway_network(context,
|
||||
bgp_speaker_id,
|
||||
network_info)
|
||||
|
||||
def get_advertised_routes(self, context, bgp_speaker_id):
|
||||
return super(NSXvBgpPlugin, self).get_advertised_routes(
|
||||
context, bgp_speaker_id)
|
||||
|
||||
def router_interface_callback(self, resource, event, trigger, **kwargs):
|
||||
if not kwargs['network_id']:
|
||||
# No GW network, hence no BGP speaker associated
|
||||
return
|
||||
|
||||
context = kwargs['context']
|
||||
router_id = kwargs['router_id']
|
||||
subnets = kwargs.get('subnets')
|
||||
network_id = kwargs['network_id']
|
||||
port = kwargs['port']
|
||||
|
||||
speakers = self._bgp_speakers_for_gateway_network(context,
|
||||
network_id)
|
||||
for speaker in speakers:
|
||||
speaker_id = speaker.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_CREATE:
|
||||
self.nsxv_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)
|
||||
|
||||
def router_gateway_callback(self, resource, event, trigger, **kwargs):
|
||||
context = kwargs.get('context') or n_context.get_admin_context()
|
||||
router_id = kwargs['router_id']
|
||||
network_id = kwargs['network_id']
|
||||
speakers = self._bgp_speakers_for_gateway_network(context, network_id)
|
||||
|
||||
for speaker in speakers:
|
||||
speaker_id = speaker.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])
|
||||
|
||||
def _before_service_edge_delete_callback(self, resource, event,
|
||||
trigger, **kwargs):
|
||||
context = kwargs['context']
|
||||
router = kwargs['router']
|
||||
ext_net_id = router.gw_port and router.gw_port['network_id']
|
||||
gw_ip = router.gw_port and router.gw_port['fixed_ips'][0]['ip_address']
|
||||
edge_id = kwargs.get('edge_id')
|
||||
speakers = self._bgp_speakers_for_gateway_network(context, ext_net_id)
|
||||
for speaker in speakers:
|
||||
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)
|
||||
|
||||
def _after_service_edge_create_callback(self, resource, event,
|
||||
trigger, **kwargs):
|
||||
context = kwargs['context']
|
||||
router = kwargs['router']
|
||||
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:
|
||||
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'])
|
541
vmware_nsx/services/dynamic_routing/nsx_v/driver.py
Normal file
541
vmware_nsx/services/dynamic_routing/nsx_v/driver.py
Normal file
@ -0,0 +1,541 @@
|
||||
# Copyright 2017 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.
|
||||
import netaddr
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
from neutron_lib import constants as n_const
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from neutron_lib.plugins import directory
|
||||
from vmware_nsx._i18n import _
|
||||
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.plugins.nsx_v.vshield.common import exceptions as vcns_exc
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def ip_prefix(name, ip_address):
|
||||
return {'ipPrefix': {'name': name, 'ipAddress': ip_address}}
|
||||
|
||||
|
||||
def redistribution_rule(advertise_static_routes, prefix_name, action='permit'):
|
||||
rule = {
|
||||
'prefixName': prefix_name,
|
||||
'action': action,
|
||||
'from': {
|
||||
'ospf': False,
|
||||
'bgp': False,
|
||||
'connected': not advertise_static_routes,
|
||||
'static': advertise_static_routes
|
||||
}
|
||||
}
|
||||
return {'rule': rule}
|
||||
|
||||
|
||||
def bgp_neighbour(bgp_peer):
|
||||
bgp_filter = {'bgpFilter': [{'direction': 'out', 'action': 'permit'}]}
|
||||
nbr = {
|
||||
'ipAddress': bgp_peer['peer_ip'],
|
||||
'remoteAS': bgp_peer['remote_as'],
|
||||
'bgpFilters': bgp_filter,
|
||||
'password': bgp_peer['password']
|
||||
}
|
||||
return {'bgpNeighbour': nbr}
|
||||
|
||||
|
||||
def gw_bgp_neighbour(ip_address, remote_as, password):
|
||||
bgp_filter = {'bgpFilter': [{'direction': 'in', 'action': 'permit'}]}
|
||||
nbr = {
|
||||
'ipAddress': ip_address,
|
||||
'remoteAS': remote_as,
|
||||
'bgpFilters': bgp_filter,
|
||||
'password': password
|
||||
}
|
||||
return {'bgpNeighbour': nbr}
|
||||
|
||||
|
||||
def default_route(nexthop):
|
||||
return {'network': '0.0.0.0/0',
|
||||
'nextHop': nexthop}
|
||||
|
||||
|
||||
class NSXvBgpDriver(object):
|
||||
"""Class driver to address the neutron_dynamic_routing API"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
super(NSXvBgpDriver, self).__init__()
|
||||
self._edge_password = cfg.CONF.nsxv.edge_appliance_password
|
||||
self._plugin = plugin
|
||||
self._core_plugin = directory.get_plugin()
|
||||
self._nsxv = self._core_plugin.nsx_v
|
||||
self._edge_manager = self._core_plugin.edge_manager
|
||||
|
||||
def prefix_name(self, subnet_id):
|
||||
return 'subnet-%s' % subnet_id
|
||||
|
||||
def _get_router_edge_info(self, context, router_id):
|
||||
edge_binding = nsxv_db.get_nsxv_router_binding(context.session,
|
||||
router_id)
|
||||
if not edge_binding:
|
||||
return None, None
|
||||
|
||||
# Idicates which routes should be advertised - connected or static.
|
||||
advertise_static_routes = False
|
||||
if edge_binding['edge_type'] != nsxv_constants.SERVICE_EDGE:
|
||||
# Distributed router
|
||||
plr_id = self._edge_manager.get_plr_by_tlr_id(context, router_id)
|
||||
edge_binding = nsxv_db.get_nsxv_router_binding(context.session,
|
||||
plr_id)
|
||||
if not edge_binding:
|
||||
# Distributed router isn't bound to plr
|
||||
return None, None
|
||||
# PLR for distributed router, advertise static routes.
|
||||
advertise_static_routes = True
|
||||
return edge_binding['edge_id'], advertise_static_routes
|
||||
|
||||
def _get_dynamic_routing_edge_list(self, context, gateway_network_id):
|
||||
# Filter the routers attached this network as gateway interface
|
||||
filters = {'network_id': [gateway_network_id],
|
||||
'device_owner': [n_const.DEVICE_OWNER_ROUTER_GW]}
|
||||
fields = ['device_id', 'fixed_ips']
|
||||
gateway_ports = self._core_plugin.get_ports(context, filters=filters,
|
||||
fields=fields)
|
||||
edge_router_dict = {}
|
||||
for port in gateway_ports:
|
||||
router_id = port['device_id']
|
||||
router = self._core_plugin._get_router(context, router_id)
|
||||
bgp_identifier = port['fixed_ips'][0]['ip_address']
|
||||
edge_id, advertise_static_routes = (
|
||||
self._get_router_edge_info(context, router_id))
|
||||
if not edge_id:
|
||||
# Shared router is not attached on any edge
|
||||
continue
|
||||
if edge_id not in edge_router_dict:
|
||||
edge_router_dict[edge_id] = {'no_snat_routers': [],
|
||||
'bgp_identifier':
|
||||
bgp_identifier,
|
||||
'advertise_static_routes':
|
||||
advertise_static_routes}
|
||||
if not router.enable_snat:
|
||||
edge_router_dict[edge_id]['no_snat_routers'].append(router_id)
|
||||
return edge_router_dict
|
||||
|
||||
def _query_tenant_subnets(self, context, router_ids):
|
||||
# Query subnets attached to all of routers attached to same edge
|
||||
subnets = []
|
||||
for router_id in router_ids:
|
||||
filters = {'device_id': [router_id],
|
||||
'device_owner': [n_const.DEVICE_OWNER_ROUTER_INTF]}
|
||||
int_ports = self._core_plugin.get_ports(context,
|
||||
filters=filters,
|
||||
fields=['fixed_ips'])
|
||||
for p in int_ports:
|
||||
subnet_id = p['fixed_ips'][0]['subnet_id']
|
||||
subnet = self._core_plugin.get_subnet(context, subnet_id)
|
||||
subnets.append({'id': subnet_id,
|
||||
'cidr': subnet['cidr']})
|
||||
LOG.debug("Got related subnets %s", subnets)
|
||||
return subnets
|
||||
|
||||
def _get_bgp_speakers_by_bgp_peer(self, context, bgp_peer_id):
|
||||
fields = ['id', 'peers']
|
||||
bgp_speakers = self._plugin.get_bgp_speakers(context, fields=fields)
|
||||
bgp_speaker_ids = [bgp_speaker['id'] for bgp_speaker in bgp_speakers
|
||||
if bgp_peer_id in bgp_speaker['peers']]
|
||||
return bgp_speaker_ids
|
||||
|
||||
def _get_prefixes_and_redistribution_rules(self, subnets,
|
||||
advertise_static_routes):
|
||||
prefixes = []
|
||||
redis_rules = []
|
||||
for subnet in subnets:
|
||||
prefix_name = self.prefix_name(subnet['id'])
|
||||
prefix = ip_prefix(prefix_name, subnet['cidr'])
|
||||
prefixes.append(prefix)
|
||||
rule = redistribution_rule(advertise_static_routes, prefix_name)
|
||||
redis_rules.append(rule)
|
||||
return prefixes, redis_rules
|
||||
|
||||
def create_bgp_speaker(self, context, bgp_speaker):
|
||||
bgp_speaker_data = bgp_speaker['bgp_speaker']
|
||||
ip_version = bgp_speaker_data.get('ip_version')
|
||||
if ip_version and ip_version == 6:
|
||||
err_msg = _("NSXv BGP does not support for IPv6")
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
|
||||
def update_bgp_speaker(self, context, bgp_speaker_id, bgp_speaker):
|
||||
bgp_obj = bgp_speaker['bgp_speaker']
|
||||
old_speaker_info = self._plugin.get_bgp_speaker(context,
|
||||
bgp_speaker_id)
|
||||
enabled_state = old_speaker_info['advertise_tenant_networks']
|
||||
new_enabled_state = bgp_obj.get('advertise_tenant_networks',
|
||||
enabled_state)
|
||||
if new_enabled_state == enabled_state:
|
||||
return
|
||||
|
||||
bgp_bindings = nsxv_db.get_nsxv_bgp_speaker_bindings(
|
||||
context.session, bgp_speaker_id)
|
||||
edge_ids = [bgp_binding['edge_id'] for bgp_binding in bgp_bindings]
|
||||
action = 'Enabling' if new_enabled_state else 'Disabling'
|
||||
LOG.info("%s BGP route redistribution on edges: %s.", action, edge_ids)
|
||||
for edge_id in edge_ids:
|
||||
try:
|
||||
self._nsxv.update_routing_redistribution(edge_id,
|
||||
new_enabled_state)
|
||||
except vcns_exc.VcnsApiException:
|
||||
LOG.warning("Failed to update BGP on edge %s.", edge_id)
|
||||
|
||||
def delete_bgp_speaker(self, context, bgp_speaker_id):
|
||||
bgp_bindings = nsxv_db.get_nsxv_bgp_speaker_bindings(
|
||||
context.session, bgp_speaker_id)
|
||||
self._stop_bgp_on_edges(context, bgp_bindings, bgp_speaker_id)
|
||||
|
||||
def _validate_bgp_configuration_on_peer_esg(self, bgp_peer):
|
||||
if not bgp_peer.get('esg_id'):
|
||||
return
|
||||
# TBD(roeyc): Validate peer_ip is on subnet
|
||||
|
||||
bgp_config = self._nsxv.get_routing_bgp_config(bgp_peer['esg_id'])
|
||||
remote_as = bgp_peer['remote_as']
|
||||
esg_id = bgp_peer['esg_id']
|
||||
esg_as = bgp_config['bgp'].get('localAS')
|
||||
if not bgp_config['bgp']['enabled']:
|
||||
raise ext_esg_peer.BgpDisabledOnEsgPeer(esg_id=esg_id)
|
||||
if esg_as != int(remote_as):
|
||||
raise ext_esg_peer.EsgRemoteASDoNotMatch(remote_as=remote_as,
|
||||
esg_id=esg_id,
|
||||
esg_as=esg_as)
|
||||
|
||||
def create_bgp_peer(self, context, bgp_peer):
|
||||
bgp_peer = bgp_peer['bgp_peer']
|
||||
remote_ip = bgp_peer['peer_ip']
|
||||
if not netaddr.valid_ipv4(remote_ip):
|
||||
err_msg = _("NSXv BGP does not support for IPv6")
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
self._validate_bgp_configuration_on_peer_esg(bgp_peer)
|
||||
|
||||
def update_bgp_peer(self, context, bgp_peer_id, bgp_peer):
|
||||
password = bgp_peer['bgp_peer'].get('password')
|
||||
old_bgp_peer = self._plugin.get_bgp_peer(context, bgp_peer_id)
|
||||
|
||||
# Only password update is relevant for backend.
|
||||
if old_bgp_peer['password'] == password:
|
||||
return
|
||||
|
||||
bgp_speaker_ids = self._get_bgp_speakers_by_bgp_peer(context,
|
||||
bgp_peer_id)
|
||||
# Update the password for the old bgp peer and update NSX
|
||||
old_bgp_peer['password'] = password
|
||||
neighbour = bgp_neighbour(old_bgp_peer)
|
||||
for bgp_speaker_id in bgp_speaker_ids:
|
||||
with locking.LockManager.get_lock(bgp_speaker_id):
|
||||
speaker = self._plugin.get_bgp_speaker(context, bgp_speaker_id)
|
||||
if bgp_peer_id not in speaker['peers']:
|
||||
continue
|
||||
bgp_bindings = nsxv_db.get_nsxv_bgp_speaker_bindings(
|
||||
context.session, bgp_speaker_id)
|
||||
for binding in bgp_bindings:
|
||||
try:
|
||||
self._nsxv.update_bgp_neighbour(binding['edge_id'],
|
||||
neighbour)
|
||||
except vcns_exc.VcnsApiException:
|
||||
LOG.error("Failed to update BGP neighbor '%s' on "
|
||||
"edge '%s'", old_bgp_peer['peer_ip'],
|
||||
binding['edge_id'])
|
||||
|
||||
def add_bgp_peer(self, context, bgp_speaker_id, bgp_peer_info):
|
||||
bgp_peer_obj = self._plugin.get_bgp_peer(context,
|
||||
bgp_peer_info['bgp_peer_id'])
|
||||
|
||||
nbr = bgp_neighbour(bgp_peer_obj)
|
||||
bgp_bindings = nsxv_db.get_nsxv_bgp_speaker_bindings(context.session,
|
||||
bgp_speaker_id)
|
||||
speaker = self._plugin.get_bgp_speaker(context, bgp_speaker_id)
|
||||
# list of tenant edge routers to be removed as bgp-neighbours to this
|
||||
# peer if it's associated with specific ESG.
|
||||
neighbours = []
|
||||
droute = default_route(nbr['bgpNeighbour']['ipAddress'])
|
||||
for binding in bgp_bindings:
|
||||
try:
|
||||
self._nsxv.add_bgp_neighbours(binding['edge_id'], [nbr],
|
||||
default_routes=[droute])
|
||||
except vcns_exc.VcnsApiException:
|
||||
LOG.error("Failed to add BGP neighbour on '%s'",
|
||||
binding['edge_id'])
|
||||
else:
|
||||
nbr = gw_bgp_neighbour(binding['bgp_identifier'],
|
||||
speaker['local_as'],
|
||||
self._edge_password)
|
||||
neighbours.append(nbr)
|
||||
LOG.debug("Succesfully added BGP neighbor '%s' on '%s'",
|
||||
bgp_peer_obj['peer_ip'], binding['edge_id'])
|
||||
|
||||
if bgp_peer_obj.get('esg_id'):
|
||||
edge_gw = bgp_peer_obj['esg_id']
|
||||
try:
|
||||
self._nsxv.add_bgp_neighbours(edge_gw, neighbours)
|
||||
except vcns_exc.VcnsApiException:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error("Failed to add BGP neighbour on GW Edge '%s'",
|
||||
edge_gw)
|
||||
|
||||
def remove_bgp_peer(self, context, bgp_speaker_id, bgp_peer_info):
|
||||
bgp_peer_id = bgp_peer_info['bgp_peer_id']
|
||||
bgp_peer_obj = self._plugin.get_bgp_peer(context, bgp_peer_id)
|
||||
nbr = bgp_neighbour(bgp_peer_obj)
|
||||
bgp_bindings = nsxv_db.get_nsxv_bgp_speaker_bindings(
|
||||
context.session, bgp_speaker_id)
|
||||
speaker = self._plugin.get_bgp_speaker(context, bgp_speaker_id)
|
||||
# list of tenant edge routers to be removed as bgp-neighbours to this
|
||||
# peer if it's associated with specific ESG.
|
||||
neighbours = []
|
||||
droute = default_route(nbr['bgpNeighbour']['ipAddress'])
|
||||
for binding in bgp_bindings:
|
||||
try:
|
||||
self._nsxv.remove_bgp_neighbours(binding['edge_id'], [nbr],
|
||||
default_routes=[droute])
|
||||
except vcns_exc.VcnsApiException:
|
||||
LOG.error("Failed to remove BGP neighbour on '%s'",
|
||||
binding['edge_id'])
|
||||
else:
|
||||
nbr = gw_bgp_neighbour(binding['bgp_identifier'],
|
||||
speaker['local_as'],
|
||||
self._edge_password)
|
||||
neighbours.append(nbr)
|
||||
LOG.debug("Succesfully removed BGP neighbor '%s' on '%s'",
|
||||
bgp_peer_obj['peer_ip'], binding['edge_id'])
|
||||
|
||||
if bgp_peer_obj.get('esg_id'):
|
||||
edge_gw = bgp_peer_obj['esg_id']
|
||||
try:
|
||||
self._nsxv.remove_bgp_neighbours(edge_gw, neighbours)
|
||||
except vcns_exc.VcnsApiException:
|
||||
LOG.error("Failed to remove BGP neighbour on GW Edge '%s'",
|
||||
edge_gw)
|
||||
|
||||
def add_gateway_network(self, context, bgp_speaker_id, network_info):
|
||||
gateway_network_id = network_info['network_id']
|
||||
ext_net = self._core_plugin.get_network(context, gateway_network_id)
|
||||
|
||||
if not ext_net['subnets']:
|
||||
return
|
||||
|
||||
subnet_id = ext_net['subnets'][0]
|
||||
ext_subnet = self._core_plugin.get_subnet(context, subnet_id)
|
||||
|
||||
if ext_subnet.get('gateway_ip'):
|
||||
raise ext_esg_peer.ExternalSubnetHasGW(
|
||||
network_id=gateway_network_id, subnet_id=subnet_id)
|
||||
|
||||
edge_router_dict = self._get_dynamic_routing_edge_list(
|
||||
context, gateway_network_id)
|
||||
|
||||
speaker = self._plugin.get_bgp_speaker(context, bgp_speaker_id)
|
||||
bgp_peers = self._plugin.get_bgp_peers_by_bgp_speaker(
|
||||
context, bgp_speaker_id)
|
||||
neighbours = []
|
||||
for edge_id, edge_router_config in edge_router_dict.items():
|
||||
router_ids = edge_router_config['no_snat_routers']
|
||||
advertise_static_routes = (
|
||||
edge_router_config['advertise_static_routes'])
|
||||
subnets = self._query_tenant_subnets(context, router_ids)
|
||||
# router_id here is in IP address format and is required for
|
||||
# the BGP configuration.
|
||||
bgp_identifier = edge_router_config['bgp_identifier']
|
||||
try:
|
||||
self._start_bgp_on_edge(context, edge_id, speaker,
|
||||
bgp_peers, bgp_identifier, subnets,
|
||||
advertise_static_routes)
|
||||
except vcns_exc.VcnsApiException:
|
||||
LOG.error("Failed to configure BGP speaker %s on edge '%s'.",
|
||||
bgp_speaker_id)
|
||||
else:
|
||||
nbr = gw_bgp_neighbour(bgp_identifier, speaker['local_as'],
|
||||
self._edge_password)
|
||||
neighbours.append(nbr)
|
||||
|
||||
for edge_gw in [peer['esg_id'] for peer in bgp_peers
|
||||
if peer.get('esg_id')]:
|
||||
try:
|
||||
self._nsxv.add_bgp_neighbours(edge_gw, neighbours)
|
||||
except vcns_exc.VcnsApiException:
|
||||
LOG.error("Failed to add BGP neighbour on GW Edge '%s'",
|
||||
edge_gw)
|
||||
|
||||
def _start_bgp_on_edge(self, context, edge_id, speaker, bgp_peers,
|
||||
bgp_identifier, subnets, advertise_static_routes):
|
||||
enabled_state = speaker['advertise_tenant_networks']
|
||||
local_as = speaker['local_as']
|
||||
prefixes, redis_rules = self._get_prefixes_and_redistribution_rules(
|
||||
subnets, advertise_static_routes)
|
||||
|
||||
bgp_neighbours = [bgp_neighbour(bgp_peer) for bgp_peer in bgp_peers]
|
||||
default_routes = [default_route(peer['peer_ip']) for peer in bgp_peers]
|
||||
try:
|
||||
self._nsxv.add_bgp_speaker_config(edge_id, bgp_identifier,
|
||||
local_as, enabled_state,
|
||||
default_routes,
|
||||
bgp_neighbours, prefixes,
|
||||
redis_rules)
|
||||
except vcns_exc.VcnsApiException:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error("Failed to configure BGP speaker %s on edge '%s'.",
|
||||
speaker['id'], edge_id)
|
||||
else:
|
||||
nsxv_db.add_nsxv_bgp_speaker_binding(context.session, edge_id,
|
||||
speaker['id'], bgp_identifier)
|
||||
|
||||
def _stop_bgp_on_edges(self, context, bgp_bindings, speaker_id):
|
||||
neighbours_to_remove = []
|
||||
speaker = self._plugin.get_bgp_speaker(context, speaker_id)
|
||||
for bgp_binding in bgp_bindings:
|
||||
edge_id = bgp_binding['edge_id']
|
||||
try:
|
||||
self._nsxv.delete_bgp_speaker_config(edge_id)
|
||||
except vcns_exc.VcnsApiException:
|
||||
LOG.error("Failed to delete BGP speaker %s config on edge "
|
||||
"%s.", speaker_id, edge_id)
|
||||
else:
|
||||
nsxv_db.delete_nsxv_bgp_speaker_binding(context.session,
|
||||
edge_id)
|
||||
nbr = gw_bgp_neighbour(bgp_binding['bgp_identifier'],
|
||||
speaker['local_as'],
|
||||
self._edge_password)
|
||||
neighbours_to_remove.append(nbr)
|
||||
|
||||
# We should also remove all bgp neighbours on gw-edges which
|
||||
# corresponds with tenant routers that are associated with this bgp
|
||||
# speaker.
|
||||
bgp_peers = self._plugin.get_bgp_peers_by_bgp_speaker(context,
|
||||
speaker_id)
|
||||
gw_edges = [peer['esg_id'] for peer in bgp_peers if peer.get('esg_id')]
|
||||
for gw_edge in gw_edges:
|
||||
try:
|
||||
self._nsxv.remove_bgp_neighbours(gw_edge, neighbours_to_remove)
|
||||
except vcns_exc.VcnsApiException:
|
||||
LOG.error("Failed to remove BGP neighbour on GW edge '%s'.",
|
||||
gw_edge)
|
||||
|
||||
def remove_gateway_network(self, context, bgp_speaker_id, network_info):
|
||||
bgp_bindings = nsxv_db.get_nsxv_bgp_speaker_bindings(
|
||||
context.session, bgp_speaker_id)
|
||||
self._stop_bgp_on_edges(context, bgp_bindings, bgp_speaker_id)
|
||||
|
||||
def enable_bgp_on_router(self, context, speaker, router_id):
|
||||
edge_id, advertise_static_routes = (
|
||||
self._get_router_edge_info(context, router_id))
|
||||
if not edge_id:
|
||||
# shared router is not attached on any edge
|
||||
return
|
||||
router = self._core_plugin._get_router(context, router_id)
|
||||
if router.enable_snat:
|
||||
subnets = []
|
||||
else:
|
||||
subnets = self._query_tenant_subnets(context, [router_id])
|
||||
|
||||
bgp_peers = self._plugin.get_bgp_peers_by_bgp_speaker(
|
||||
context, speaker['id'])
|
||||
bgp_binding = nsxv_db.get_nsxv_bgp_speaker_binding(
|
||||
context.session, edge_id)
|
||||
|
||||
if bgp_binding and subnets:
|
||||
# Edge already configured with BGP (e.g - shared router edge),
|
||||
# Add the router attached subnets.
|
||||
prefixes, redis_rules = (
|
||||
self._get_prefixes_and_redistribution_rules(
|
||||
subnets, advertise_static_routes))
|
||||
self._nsxv.add_bgp_redistribution_rules(edge_id, prefixes,
|
||||
redis_rules)
|
||||
elif not bgp_binding:
|
||||
gw_port = router.gw_port['fixed_ips'][0]
|
||||
bgp_identifier = gw_port['ip_address']
|
||||
self._start_bgp_on_edge(context, edge_id, speaker, bgp_peers,
|
||||
bgp_identifier, subnets,
|
||||
advertise_static_routes)
|
||||
nbr = gw_bgp_neighbour(bgp_identifier, speaker['local_as'],
|
||||
self._edge_password)
|
||||
for gw_edge_id in [peer['esg_id'] for peer in bgp_peers
|
||||
if peer['esg_id']]:
|
||||
self._nsxv.add_bgp_neighbours(gw_edge_id, [nbr])
|
||||
|
||||
def disable_bgp_on_router(self, context, speaker, router_id, gw_ip,
|
||||
edge_id=None):
|
||||
speaker = self._plugin.get_bgp_speaker(context, speaker['id'])
|
||||
current_edge_id, advertise_static_routes = (
|
||||
self._get_router_edge_info(context, router_id))
|
||||
edge_id = edge_id or current_edge_id
|
||||
|
||||
if not edge_id:
|
||||
return
|
||||
|
||||
routers_ids = (
|
||||
self._core_plugin.edge_manager.get_routers_on_same_edge(
|
||||
context, router_id))
|
||||
bgp_binding = nsxv_db.get_nsxv_bgp_speaker_binding(context.session,
|
||||
edge_id)
|
||||
if not bgp_binding:
|
||||
return
|
||||
|
||||
if len(routers_ids) > 1:
|
||||
routers_ids.remove(router_id)
|
||||
# Shared router, only remove prefixes and redistribution
|
||||
# rules.
|
||||
subnets = self._query_tenant_subnets(context, [router_id])
|
||||
prefixes = [self.prefix_name(subnet['id'])
|
||||
for subnet in subnets]
|
||||
self._nsxv.remove_bgp_redistribution_rules(edge_id, prefixes)
|
||||
if bgp_binding['bgp_identifier'] == gw_ip:
|
||||
router = self._core_plugin._get_router(context, routers_ids[0])
|
||||
new_bgp_identifier = (
|
||||
router.gw_port['fixed_ips'][0]['ip_address'])
|
||||
with context.session.begin(subtransactions=True):
|
||||
bgp_binding['bgp_identifier'] = new_bgp_identifier
|
||||
self._nsxv.update_router_id(edge_id, new_bgp_identifier)
|
||||
else:
|
||||
self._stop_bgp_on_edges(context, [bgp_binding], speaker['id'])
|
||||
|
||||
def advertise_subnet(self, context, speaker_id, router_id, subnet):
|
||||
router = self._core_plugin._get_router(context, router_id)
|
||||
if router.enable_snat:
|
||||
# Do nothing, by default, only when advertisement is needed we add
|
||||
# a new redistribution rule
|
||||
return
|
||||
|
||||
edge_id, advertise_static_routes = (
|
||||
self._get_router_edge_info(context, router_id))
|
||||
if not edge_id:
|
||||
# shared router is not attached on any edge
|
||||
return
|
||||
prefixes, redis_rules = self._get_prefixes_and_redistribution_rules(
|
||||
[subnet], advertise_static_routes)
|
||||
self._nsxv.add_bgp_redistribution_rules(edge_id, prefixes, redis_rules)
|
||||
|
||||
def withdraw_subnet(self, context, speaker_id, router_id, subnet_id):
|
||||
router = self._core_plugin._get_router(context, router_id)
|
||||
if router.enable_snat:
|
||||
# Do nothing, by default, only when advertisement is needed we add
|
||||
# a new redistribution rule
|
||||
return
|
||||
|
||||
edge_id, advertise_static_routes = (
|
||||
self._get_router_edge_info(context, router_id))
|
||||
prefix_name = self.prefix_name(subnet_id)
|
||||
self._nsxv.remove_bgp_redistribution_rules(edge_id, [prefix_name])
|
@ -1474,3 +1474,128 @@ class FakeVcns(object):
|
||||
'objectID': 'application-1001'}]
|
||||
|
||||
return applications
|
||||
|
||||
def update_dynamic_routing_service(self, edge_id, request_config):
|
||||
header = {'status': 201}
|
||||
response = {
|
||||
'routerId': '172.24.4.12',
|
||||
'ipPrefixes': {
|
||||
'ipPrefixes': [
|
||||
{'ipAddress': '10.0.0.0/24',
|
||||
'name': 'prefix-name'}
|
||||
]
|
||||
}
|
||||
}
|
||||
return self.return_helper(header, response)
|
||||
|
||||
def get_dynamic_routing_service(self, edge_id):
|
||||
header = {'status': 200}
|
||||
response = {
|
||||
'routerId': '172.24.4.12',
|
||||
'ipPrefixes': {
|
||||
'ipPrefixes': [
|
||||
{'ipAddress': '10.0.0.0/24',
|
||||
'name': 'prefix-name'}
|
||||
]
|
||||
},
|
||||
'logging': {
|
||||
'logLevel': 'info',
|
||||
'enable': False
|
||||
},
|
||||
'ecmp': False
|
||||
}
|
||||
return self.return_helper(header, response)
|
||||
|
||||
def update_bgp_dynamic_routing(self, edge_id, bgp_request):
|
||||
header = {"status": 201}
|
||||
response = {
|
||||
"localAS": 65000,
|
||||
"enabled": True,
|
||||
"bgpNeighbours": {
|
||||
"bgpNeighbours": [
|
||||
{
|
||||
"bgpFilters": {
|
||||
"bgpFilters": [
|
||||
{
|
||||
"action": "deny",
|
||||
"direction": "in"
|
||||
}
|
||||
]
|
||||
},
|
||||
"password": None,
|
||||
"ipAddress": "172.24.4.253",
|
||||
"remoteAS": 65000
|
||||
}
|
||||
]
|
||||
},
|
||||
"redistribution": {
|
||||
"rules": {
|
||||
"rules": [
|
||||
{
|
||||
"action": "deny",
|
||||
"from": {
|
||||
"bgp": False,
|
||||
"connected": False,
|
||||
"static": False,
|
||||
"ospf": False
|
||||
},
|
||||
"id": 0
|
||||
},
|
||||
{
|
||||
"action": "permit",
|
||||
"from": {
|
||||
"bgp": False,
|
||||
"connected": True,
|
||||
"static": True,
|
||||
"ospf": False
|
||||
},
|
||||
"id": 1,
|
||||
"prefixName": "eee4eb79-359e-4416"
|
||||
}
|
||||
]
|
||||
},
|
||||
"enabled": True
|
||||
}
|
||||
}
|
||||
return self.return_helper(header, response)
|
||||
|
||||
def get_bgp_routing_config(self, edge_id):
|
||||
header = {'status': 200}
|
||||
response = {
|
||||
"localAS": 65000,
|
||||
"enabled": True,
|
||||
"redistribution": {
|
||||
"rules": {
|
||||
"rules": [
|
||||
{
|
||||
"action": "deny",
|
||||
"from": {
|
||||
"bgp": False,
|
||||
"connected": False,
|
||||
"static": False,
|
||||
"ospf": False
|
||||
},
|
||||
"id": 0
|
||||
},
|
||||
{
|
||||
"action": "permit",
|
||||
"from": {
|
||||
"bgp": False,
|
||||
"connected": True,
|
||||
"static": True,
|
||||
"ospf": False
|
||||
},
|
||||
"id": 1,
|
||||
"prefixName": "eee4eb79-359e-4416"
|
||||
}
|
||||
]
|
||||
},
|
||||
"enabled": True
|
||||
}
|
||||
}
|
||||
return self.return_helper(header, response)
|
||||
|
||||
def delete_bgp_routing_config(self, edge_id):
|
||||
header = {'status': 200}
|
||||
response = ''
|
||||
return header, response
|
||||
|
@ -0,0 +1,59 @@
|
||||
# Copyright 2017 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.
|
||||
|
||||
import mock
|
||||
|
||||
from neutron.tests import base
|
||||
from neutron_dynamic_routing.db import bgp_db # noqa
|
||||
from neutron_lib import context
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from neutron_lib.plugins import directory
|
||||
|
||||
from vmware_nsx.services.dynamic_routing.nsx_v import driver as nsxv_driver
|
||||
|
||||
|
||||
class TestNSXvBgpDriver(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestNSXvBgpDriver, self).setUp()
|
||||
self.context = context.get_admin_context()
|
||||
with mock.patch.object(directory, 'get_plugin',
|
||||
new=mock.Mock()):
|
||||
self.provider = nsxv_driver.NSXvBgpDriver(mock.MagicMock())
|
||||
|
||||
def test_create_v6_bgp_speaker(self):
|
||||
fake_bgp_speaker = {
|
||||
"bgp_speaker": {
|
||||
"ip_version": 6,
|
||||
"local_as": "1000",
|
||||
"name": "bgp-speaker"
|
||||
}
|
||||
}
|
||||
self.assertRaises(n_exc.InvalidInput,
|
||||
self.provider.create_bgp_speaker,
|
||||
self.context, fake_bgp_speaker)
|
||||
|
||||
def test_create_v6_bgp_peer(self):
|
||||
fake_bgp_peer = {
|
||||
"bgp_peer": {
|
||||
"auth_type": "none",
|
||||
"remote_as": "1000",
|
||||
"name": "bgp-peer",
|
||||
"peer_ip": "fc00::/7"
|
||||
}
|
||||
}
|
||||
self.assertRaises(n_exc.InvalidInput,
|
||||
self.provider.create_bgp_peer,
|
||||
self.context, fake_bgp_peer)
|
Loading…
Reference in New Issue
Block a user