vmware-nsx/vmware_nsx/services/dynamic_routing/nsx_v/driver.py
Adit Sarfaty 2c21c61709 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
2017-12-24 15:11:37 +02:00

701 lines
32 KiB
Python

# 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 neutron_dynamic_routing.extensions import bgp as bgp_ext
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
from neutron_lib.api.definitions import address_scope
from neutron_lib.api.definitions import external_net as extnet_apidef
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 exceptions as nsx_exc
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__)
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 _get_bgp_neighbour(ip_address, remote_as, password, direction):
bgp_filter = {'bgpFilter': [{'direction': direction, 'action': 'permit'}]}
nbr = {
'ipAddress': ip_address,
'remoteAS': remote_as,
'bgpFilters': bgp_filter,
'holdDownTimer': cfg.CONF.nsxv.bgp_neighbour_hold_down_timer,
'keepAliveTimer': cfg.CONF.nsxv.bgp_neighbour_keep_alive_timer
}
if password:
nbr['password'] = password
return {'bgpNeighbour': nbr}
def bgp_neighbour_from_peer(bgp_peer):
return _get_bgp_neighbour(bgp_peer['peer_ip'],
bgp_peer['remote_as'],
bgp_peer['password'],
direction='out')
def gw_bgp_neighbour(ip_address, remote_as, password):
return _get_bgp_neighbour(ip_address, remote_as, password,
direction='in')
class NSXvBgpDriver(object):
"""Class driver to address the neutron_dynamic_routing API"""
def __init__(self, plugin):
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
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
# Indicates 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_advertised_routes(self, context, bgp_speaker_id):
routes = []
bgp_speaker = self._plugin.get_bgp_speaker(context, bgp_speaker_id)
edge_router_dict = (
self._get_dynamic_routing_edge_list(context,
bgp_speaker['networks'][0],
bgp_speaker_id))
for edge_id, edge_router_config in edge_router_dict.items():
bgp_identifier = edge_router_config['bgp_identifier']
subnets = self._query_tenant_subnets(
context, edge_router_config['no_snat_routers'])
routes.extend([(subnet['cidr'], bgp_identifier)
for subnet in subnets])
routes = self._plugin._make_advertised_routes_list(routes)
return self._plugin._make_advertised_routes_dict(routes)
def _get_dynamic_routing_edge_list(self, context,
gateway_network_id, bgp_speaker_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)
bgp_bindings = nsxv_db.get_nsxv_bgp_speaker_bindings(
context.session, bgp_speaker_id)
binding_info = {bgp_binding['edge_id']: bgp_binding['bgp_identifier']
for bgp_binding in bgp_bindings}
edge_router_dict = {}
for port in gateway_ports:
router_id = port['device_id']
router = self._core_plugin._get_router(context, 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
continue
if edge_id not in edge_router_dict:
bgp_identifier = binding_info.get(
edge_id, port['fixed_ips'][0]['ip_address'])
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 _get_md_proxy_for_router(self, context, router_id):
binding = nsxv_db.get_nsxv_router_binding(context.session,
router_id)
md_proxy = None
if binding:
az_name = binding['availability_zone']
md_proxy = self._core_plugin.get_metadata_proxy_handler(
az_name)
return md_proxy
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'])
# We need to skip metadata subnets
md_proxy = self._get_md_proxy_for_router(context, router_id)
for p in int_ports:
subnet_id = p['fixed_ips'][0]['subnet_id']
if md_proxy and md_proxy.is_md_subnet(subnet_id):
continue
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)
h, resp = self._nsxv.vcns.get_interfaces(esg_id)
for iface in resp['vnics']:
address_groups = iface['addressGroups']['addressGroups']
matching_iface = [ag for ag in address_groups
if ag['primaryAddress'] == bgp_peer['peer_ip']]
if matching_iface:
break
else:
raise ext_esg_peer.EsgInternalIfaceDoesNotMatch(esg_id=esg_id)
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_from_peer(old_bgp_peer)
for bgp_speaker_id in bgp_speaker_ids:
with locking.LockManager.get_lock(bgp_speaker_id):
peers = self._plugin.get_bgp_peers_by_bgp_speaker(
context, bgp_speaker_id)
if bgp_peer_id not in [p['id'] for p in peers]:
continue
bgp_bindings = nsxv_db.get_nsxv_bgp_speaker_bindings(
context.session, bgp_speaker_id)
for binding in bgp_bindings:
try:
# Neighbours are identified by their ip address
self._nsxv.update_bgp_neighbours(binding['edge_id'],
[neighbour],
[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 _validate_bgp_peer(self, context, bgp_speaker_id, new_peer_id):
new_peer = self._plugin._get_bgp_peer(context, new_peer_id)
peers = self._plugin._get_bgp_peers_by_bgp_speaker_binding(
context, bgp_speaker_id)
self._plugin._validate_peer_ips(bgp_speaker_id, peers, new_peer)
def add_bgp_peer(self, context, bgp_speaker_id, bgp_peer_info):
bgp_peer_id = self._plugin._get_id_for(bgp_peer_info, 'bgp_peer_id')
bgp_peer_obj = self._plugin.get_bgp_peer(context,
bgp_peer_id)
nbr = bgp_neighbour_from_peer(bgp_peer_obj)
bgp_bindings = nsxv_db.get_nsxv_bgp_speaker_bindings(context.session,
bgp_speaker_id)
self._validate_bgp_peer(context, bgp_speaker_id, bgp_peer_obj['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 = []
for binding in bgp_bindings:
try:
self._nsxv.add_bgp_neighbours(binding['edge_id'], [nbr])
except vcns_exc.VcnsApiException:
LOG.error("Failed to add BGP neighbour on '%s'",
binding['edge_id'])
else:
gw_nbr = gw_bgp_neighbour(binding['bgp_identifier'],
speaker['local_as'],
bgp_peer_obj['password'])
neighbours.append(gw_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_from_peer(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 = []
for binding in bgp_bindings:
try:
self._nsxv.remove_bgp_neighbours(binding['edge_id'], [nbr])
except vcns_exc.VcnsApiException:
LOG.error("Failed to remove BGP neighbour on '%s'",
binding['edge_id'])
else:
gw_nbr = gw_bgp_neighbour(binding['bgp_identifier'],
speaker['local_as'],
bgp_peer_obj['password'])
neighbours.append(gw_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 _validate_gateway_network(self, context, speaker_id, network_id):
ext_net = self._core_plugin.get_network(context, network_id)
if not ext_net.get(extnet_apidef.EXTERNAL):
raise nsx_exc.NsxBgpNetworkNotExternal(net_id=network_id)
if not ext_net['subnets']:
raise nsx_exc.NsxBgpGatewayNetworkHasNoSubnets(net_id=network_id)
# REVISIT(roeyc): Currently not allowing more than one bgp speaker per
# gateway network.
speakers_on_network = self._plugin._bgp_speakers_for_gateway_network(
context, network_id)
if speakers_on_network:
raise bgp_ext.BgpSpeakerNetworkBindingError(
network_id=network_id,
bgp_speaker_id=speakers_on_network[0]['id'])
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=network_id, subnet_id=subnet_id)
if not ext_net[address_scope.IPV4_ADDRESS_SCOPE]:
raise nsx_exc.NsxBgpSpeakerUnableToAddGatewayNetwork(
network_id=network_id, bgp_speaker_id=speaker_id)
return True
def add_gateway_network(self, context, bgp_speaker_id, network_info):
gateway_network_id = network_info['network_id']
if not self._validate_gateway_network(context, bgp_speaker_id,
gateway_network_id):
return
edge_router_dict = self._get_dynamic_routing_edge_list(
context, gateway_network_id, bgp_speaker_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)
local_as = speaker['local_as']
peers = []
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, edge_id)
else:
peers.append(bgp_identifier)
for edge_gw, password in [(peer['esg_id'], peer['password'])
for peer in bgp_peers if peer.get('esg_id')]:
neighbours = [gw_bgp_neighbour(bgp_id, local_as, password)
for bgp_id in peers]
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_from_peer(bgp_peer)
for bgp_peer in bgp_peers]
try:
self._nsxv.add_bgp_speaker_config(edge_id, bgp_identifier,
local_as, enabled_state,
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):
peers_to_remove = []
speaker = self._plugin.get_bgp_speaker(context, speaker_id)
local_as = speaker['local_as']
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)
peers_to_remove.append(bgp_binding['bgp_identifier'])
# 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'], peer['password'])
for peer in bgp_peers if peer.get('esg_id')]
for gw_edge, password in gw_edges:
neighbours_to_remove = [gw_bgp_neighbour(bgp_identifier,
local_as,
password)
for bgp_identifier in peers_to_remove]
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 _update_edge_bgp_identifier(self, context, bgp_binding, speaker,
new_bgp_identifier):
local_as = speaker['local_as']
bgp_peers = self._plugin.get_bgp_peers_by_bgp_speaker(context,
speaker['id'])
self._nsxv.update_router_id(bgp_binding['edge_id'], new_bgp_identifier)
for gw_edge_id, password in [(peer['esg_id'], peer['password'])
for peer in bgp_peers
if peer.get('esg_id')]:
nbr_to_remove = gw_bgp_neighbour(bgp_binding['bgp_identifier'],
local_as, password)
nbr_to_add = gw_bgp_neighbour(new_bgp_identifier, local_as,
password)
self._nsxv.update_bgp_neighbours(gw_edge_id,
[nbr_to_add],
[nbr_to_remove])
with context.session.begin(subtransactions=True):
bgp_binding['bgp_identifier'] = new_bgp_identifier
def process_router_gw_port_update(self, context, speaker,
router, updated_port):
router_id = router['id']
gw_fixed_ip = router.gw_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
return
bgp_binding = nsxv_db.get_nsxv_bgp_speaker_binding(
context.session, edge_id)
if bgp_binding:
new_fixed_ip = updated_port['fixed_ips'][0]['ip_address']
fixed_ip_updated = gw_fixed_ip != new_fixed_ip
subnets = self._query_tenant_subnets(context, [router_id])
prefixes, redis_rules = (
self._get_prefixes_and_redistribution_rules(
subnets, advertise_static_routes))
# Handle possible snat/no-nat update
if router.enable_snat:
self._nsxv.remove_bgp_redistribution_rules(edge_id, prefixes)
else:
self._nsxv.add_bgp_redistribution_rules(edge_id, prefixes,
redis_rules)
if bgp_binding['bgp_identifier'] == gw_fixed_ip:
if fixed_ip_updated:
self._update_edge_bgp_identifier(context,
bgp_binding,
speaker,
new_fixed_ip)
def enable_bgp_on_router(self, context, speaker, router_id):
local_as = speaker['local_as']
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)
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.
if router.enable_snat:
prefixes = [self.prefix_name(subnet['id'])
for subnet in subnets]
self._nsxv.remove_bgp_redistribution_rules(edge_id, prefixes)
else:
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:
if router.enable_snat:
subnets = []
bgp_identifier = router.gw_port['fixed_ips'][0]['ip_address']
self._start_bgp_on_edge(context, edge_id, speaker, bgp_peers,
bgp_identifier, subnets,
advertise_static_routes)
for gw_edge_id, password in [(peer['esg_id'], peer['password'])
for peer in bgp_peers
if peer.get('esg_id')]:
nbr = gw_bgp_neighbour(bgp_identifier, local_as, password)
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
bgp_binding = nsxv_db.get_nsxv_bgp_speaker_binding(context.session,
edge_id)
if not bgp_binding:
return
# Need to ensure that we do not use the metadata IP's
md_proxy = self._get_md_proxy_for_router(context, router_id)
routers_ids = (
self._core_plugin.edge_manager.get_routers_on_same_edge(
context, router_id))
routers_ids.remove(router_id)
# We need to find out what other routers are hosted on the edges and
# whether they have a gw addresses that could replace the current
# bgp-identifier (if required).
filters = {'device_owner': [n_const.DEVICE_OWNER_ROUTER_GW],
'device_id': routers_ids}
edge_gw_ports = self._core_plugin.get_ports(context, filters=filters)
alt_bgp_identifiers = [
p['fixed_ips'][0]['ip_address'] for p in edge_gw_ports
if (not md_proxy or
not md_proxy.is_md_subnet(
p['fixed_ips'][0]['subnet_id']))]
if alt_bgp_identifiers:
# 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:
self._update_edge_bgp_identifier(context, bgp_binding, speaker,
alt_bgp_identifiers[0])
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])