NSXv BGP: Update edge bgp identifier on router GW updates
When rotuer GW port ip address is changed, we must check if the old address was used for the edge bgp identifier, if so, update it with new GW address. Also takes care of router GW info NAT enable/disable updates. Change-Id: I5ae25152f06d55b4d631735376df94a7eedb7d95
This commit is contained in:
parent
d85dd105b8
commit
82d045405e
@ -26,44 +26,7 @@ class EdgeDynamicRoutingDriver(object):
|
||||
# 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 {}
|
||||
def _prepare_bgp_config(self, bgp_config):
|
||||
bgp_config.setdefault('enabled', False)
|
||||
bgp_config.setdefault('bgpNeighbours', {'bgpNeighbours': []})
|
||||
bgp_config.setdefault('redistribution', {'rules': {'rules': []}})
|
||||
@ -78,6 +41,60 @@ class EdgeDynamicRoutingDriver(object):
|
||||
redistribution_rules = [{'rule': rule} for rule in
|
||||
bgp_config['redistribution']['rules']['rules']]
|
||||
bgp_config['redistribution']['rules'] = redistribution_rules
|
||||
|
||||
def _get_routing_config(self, edge_id):
|
||||
h, config = self.vcns.get_edge_routing_config(edge_id)
|
||||
# Backend complains when adding this in the request.
|
||||
config.pop('featureType')
|
||||
config.pop('ospf')
|
||||
global_config = config['routingGlobalConfig']
|
||||
bgp_config = config.get('bgp', {})
|
||||
|
||||
self._prepare_bgp_config(bgp_config)
|
||||
|
||||
global_config.setdefault('ipPrefixes', {'ipPrefixes': []})
|
||||
curr_prefixes = [{'ipPrefix': prx}
|
||||
for prx in global_config['ipPrefixes']['ipPrefixes']]
|
||||
global_config['ipPrefixes'] = curr_prefixes
|
||||
|
||||
static_routing = config.get('staticRouting', {})
|
||||
static_routes = static_routing.get('staticRoutes', {})
|
||||
current_routes = [{'route': route}
|
||||
for route in static_routes.get('staticRoutes', [])]
|
||||
static_routing['staticRoutes'] = current_routes
|
||||
return {'routing': config}
|
||||
|
||||
def _update_routing_config(self, edge_id, **kwargs):
|
||||
routing_config = self._get_routing_config(edge_id)
|
||||
global_config = routing_config['routing']['routingGlobalConfig']
|
||||
current_prefixes = global_config['ipPrefixes']
|
||||
|
||||
global_config['ecmp'] = True
|
||||
|
||||
if 'router_id' in kwargs:
|
||||
global_config['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_edge_routing_config(edge_id, routing_config)
|
||||
|
||||
def _reset_routing_global_config(self, edge_id):
|
||||
routing_config = self._get_routing_config(edge_id)
|
||||
global_config = routing_config['routing']['routingGlobalConfig']
|
||||
global_config['ecmp'] = False
|
||||
global_config.pop('routerId')
|
||||
global_config.pop('ipPrefixes')
|
||||
self.vcns.update_edge_routing_config(edge_id, routing_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 {}
|
||||
self._prepare_bgp_config(bgp_config)
|
||||
return {'bgp': bgp_config}
|
||||
|
||||
def _update_bgp_routing_config(self, edge_id, **kwargs):
|
||||
@ -136,9 +153,9 @@ class EdgeDynamicRoutingDriver(object):
|
||||
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_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,
|
||||
@ -169,12 +186,13 @@ class EdgeDynamicRoutingDriver(object):
|
||||
if default_routes:
|
||||
self._remove_default_static_routes(edge_id, default_routes)
|
||||
|
||||
def update_bgp_neighbour(self, edge_id, bgp_neighbour):
|
||||
def update_bgp_neighbours(self, edge_id, neighbours_to_add=None,
|
||||
neighbours_to_remove=None):
|
||||
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])
|
||||
neighbours_to_add=neighbours_to_add,
|
||||
neighbours_to_remove=neighbours_to_remove)
|
||||
|
||||
def update_routing_redistribution(self, edge_id, enabled):
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
@ -182,19 +200,17 @@ class EdgeDynamicRoutingDriver(object):
|
||||
|
||||
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_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)
|
||||
self._update_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)
|
||||
self._update_routing_config(edge_id, router_id=router_id)
|
||||
|
@ -84,7 +84,7 @@ CERTIFICATE = "certificate"
|
||||
NETWORK_TYPES = ['Network', 'VirtualWire', 'DistributedVirtualPortgroup']
|
||||
|
||||
# Dynamic routing constants
|
||||
GLOBAL_ROUTING_CONFIG = "routing/config/global"
|
||||
ROUTING_CONFIG = "routing/config"
|
||||
BGP_ROUTING_CONFIG = "routing/config/bgp"
|
||||
|
||||
|
||||
@ -1070,14 +1070,14 @@ class Vcns(object):
|
||||
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)
|
||||
def update_edge_routing_config(self, edge_id, request_config):
|
||||
uri = self._build_uri_path(edge_id, 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)
|
||||
def get_edge_routing_config(self, edge_id):
|
||||
uri = self._build_uri_path(edge_id, ROUTING_CONFIG)
|
||||
return self.do_request(HTTP_GET, uri)
|
||||
|
||||
def update_bgp_dynamic_routing(self, edge_id, bgp_request):
|
||||
|
@ -61,7 +61,7 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin):
|
||||
events.AFTER_DELETE)
|
||||
registry.subscribe(self.router_gateway_callback,
|
||||
resources.ROUTER_GATEWAY,
|
||||
events.AFTER_CREATE)
|
||||
events.AFTER_UPDATE)
|
||||
registry.subscribe(self.router_gateway_callback,
|
||||
resources.ROUTER_GATEWAY,
|
||||
events.AFTER_DELETE)
|
||||
@ -80,7 +80,7 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin):
|
||||
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)
|
||||
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)
|
||||
@ -124,9 +124,9 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin):
|
||||
return peer
|
||||
|
||||
def update_bgp_peer(self, context, bgp_peer_id, bgp_peer):
|
||||
self.nsxv_driver.update_bgp_peer(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):
|
||||
@ -140,7 +140,7 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin):
|
||||
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)
|
||||
bgp_speaker_id, bgp_peer_info)
|
||||
return super(NSXvBgpPlugin, self).add_bgp_peer(context,
|
||||
bgp_speaker_id,
|
||||
bgp_peer_info)
|
||||
@ -151,15 +151,15 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin):
|
||||
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)
|
||||
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)
|
||||
bgp_speaker_id,
|
||||
network_info)
|
||||
return super(NSXvBgpPlugin, self).add_gateway_network(
|
||||
context, bgp_speaker_id, network_info)
|
||||
|
||||
@ -168,8 +168,8 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin):
|
||||
super(NSXvBgpPlugin, self).remove_gateway_network(
|
||||
context, bgp_speaker_id, network_info)
|
||||
self.nsxv_driver.remove_gateway_network(context,
|
||||
bgp_speaker_id,
|
||||
network_info)
|
||||
bgp_speaker_id,
|
||||
network_info)
|
||||
|
||||
def get_advertised_routes(self, context, bgp_speaker_id):
|
||||
return super(NSXvBgpPlugin, self).get_advertised_routes(
|
||||
@ -196,11 +196,11 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin):
|
||||
continue
|
||||
if event == events.AFTER_CREATE:
|
||||
self.nsxv_driver.advertise_subnet(context, speaker_id,
|
||||
router_id, subnets[0])
|
||||
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)
|
||||
router_id, subnet_id)
|
||||
|
||||
def router_gateway_callback(self, resource, event, trigger, **kwargs):
|
||||
context = kwargs.get('context') or n_context.get_admin_context()
|
||||
@ -217,9 +217,14 @@ class NSXvBgpPlugin(service_base.ServicePluginBase, bgp_db.BgpDbMixin):
|
||||
if event == events.AFTER_DELETE:
|
||||
gw_ips = kwargs['gateway_ips']
|
||||
self.nsxv_driver.disable_bgp_on_router(context,
|
||||
speaker,
|
||||
router_id,
|
||||
gw_ips[0])
|
||||
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(
|
||||
context, speaker, router, updated_port)
|
||||
|
||||
def _before_service_edge_delete_callback(self, resource, event,
|
||||
trigger, **kwargs):
|
||||
|
@ -254,8 +254,10 @@ class NSXvBgpDriver(object):
|
||||
context.session, bgp_speaker_id)
|
||||
for binding in bgp_bindings:
|
||||
try:
|
||||
self._nsxv.update_bgp_neighbour(binding['edge_id'],
|
||||
neighbour)
|
||||
# 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'],
|
||||
@ -439,6 +441,59 @@ class NSXvBgpDriver(object):
|
||||
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):
|
||||
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)
|
||||
nbr_to_remove = gw_bgp_neighbour(bgp_binding['bgp_identifier'],
|
||||
speaker['local_as'],
|
||||
self._edge_password)
|
||||
nbr_to_add = gw_bgp_neighbour(new_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.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):
|
||||
edge_id, advertise_static_routes = (
|
||||
self._get_router_edge_info(context, router_id))
|
||||
@ -446,10 +501,7 @@ class NSXvBgpDriver(object):
|
||||
# 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])
|
||||
subnets = self._query_tenant_subnets(context, [router_id])
|
||||
|
||||
bgp_peers = self._plugin.get_bgp_peers_by_bgp_speaker(
|
||||
context, speaker['id'])
|
||||
@ -459,14 +511,20 @@ class NSXvBgpDriver(object):
|
||||
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)
|
||||
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:
|
||||
gw_port = router.gw_port['fixed_ips'][0]
|
||||
bgp_identifier = gw_port['ip_address']
|
||||
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)
|
||||
@ -506,9 +564,8 @@ class NSXvBgpDriver(object):
|
||||
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)
|
||||
self._update_edge_bgp_identifier(context, bgp_binding, speaker,
|
||||
new_bgp_identifier)
|
||||
else:
|
||||
self._stop_bgp_on_edges(context, [bgp_binding], speaker['id'])
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user