Ignore disabled routers for advertising
currently if a router is set to disabled the dragents still advertise the routes. This causes the upstream routers to still know these routes and try to forward packets to a non existing router. By removing these routes we allow these upstream routers do directly drop the traffic to these addresses instead of trying to forward it to neutron routers. Closes-Bug: 2018737 Change-Id: Icd6803769f37a04bf7581afb9722c78a44737374
This commit is contained in:
parent
15d30d0263
commit
06232f0b2c
@ -670,6 +670,7 @@ class BgpDbMixin(object):
|
||||
next_hop_alias.network_id == speaker_binding.network_id,
|
||||
dest_alias.router_id == l3_db.Router.id,
|
||||
l3_db.Router.gw_port_id == next_hop_alias.port_id,
|
||||
l3_db.Router.admin_state_up == sa.sql.true(),
|
||||
next_hop_alias.subnet_id == models_v2.Subnet.id,
|
||||
models_v2.Subnet.ip_version == 4)
|
||||
query = query.outerjoin(router_attrs,
|
||||
@ -771,6 +772,7 @@ class BgpDbMixin(object):
|
||||
|
||||
fip_query = fip_query.filter(
|
||||
l3_db.FloatingIP.router_id == router_attrs.router_id,
|
||||
l3_db.Router.admin_state_up == sa.sql.true(),
|
||||
router_attrs.distributed == sa.sql.true())
|
||||
|
||||
#Create the join query
|
||||
@ -931,6 +933,8 @@ class BgpDbMixin(object):
|
||||
name='router_attrs')
|
||||
return [models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id,
|
||||
l3_db.RouterPort.router_id == router_attrs.router_id,
|
||||
l3_db.Router.id == router_attrs.router_id,
|
||||
l3_db.Router.admin_state_up == sa.sql.true(),
|
||||
l3_db.RouterPort.port_type != lib_consts.DEVICE_OWNER_ROUTER_GW,
|
||||
l3_db.RouterPort.port_type != lib_consts.DEVICE_OWNER_ROUTER_SNAT,
|
||||
models_v2.IPAllocation.subnet_id == models_v2.Subnet.id,
|
||||
|
@ -97,6 +97,9 @@ class BgpPlugin(service_base.ServicePluginBase,
|
||||
registry.subscribe(self.router_gateway_callback,
|
||||
resources.ROUTER_GATEWAY,
|
||||
events.AFTER_DELETE)
|
||||
registry.subscribe(self.router_callback,
|
||||
resources.ROUTER,
|
||||
events.AFTER_UPDATE)
|
||||
registry.subscribe(self.port_callback,
|
||||
resources.PORT,
|
||||
events.AFTER_UPDATE)
|
||||
@ -302,35 +305,24 @@ class BgpPlugin(service_base.ServicePluginBase,
|
||||
rl)
|
||||
|
||||
def router_gateway_callback(self, resource, event, trigger, payload=None):
|
||||
gw_network = payload.metadata.get('network_id')
|
||||
router_id = payload.resource_id
|
||||
gateway_ips = payload.metadata.get('gateway_ips')
|
||||
if event == events.AFTER_CREATE:
|
||||
self._handle_router_gateway_after_create(payload)
|
||||
self._handle_router_gateway_after_create(gw_network, router_id,
|
||||
gateway_ips)
|
||||
if event == events.AFTER_DELETE:
|
||||
gw_network = payload.metadata.get('network_id')
|
||||
router_id = payload.resource_id
|
||||
next_hops = self._next_hops_from_gateway_ips(
|
||||
payload.metadata.get('gateway_ips'))
|
||||
ctx = context.get_admin_context()
|
||||
speakers = self._bgp_speakers_for_gateway_network(ctx, gw_network)
|
||||
for speaker in speakers:
|
||||
if speaker.ip_version in next_hops:
|
||||
next_hop = next_hops[speaker.ip_version]
|
||||
prefixes = self._tenant_prefixes_by_router(ctx,
|
||||
router_id,
|
||||
speaker.id)
|
||||
routes = self._route_list_from_prefixes_and_next_hop(
|
||||
prefixes,
|
||||
next_hop)
|
||||
self._handle_router_interface_after_delete(gw_network, routes)
|
||||
self._handle_router_gateway_after_delete(gw_network, router_id,
|
||||
gateway_ips)
|
||||
|
||||
def _handle_router_gateway_after_create(self, payload):
|
||||
def _handle_router_gateway_after_create(self, gw_network, router_id,
|
||||
gateway_ips):
|
||||
ctx = context.get_admin_context()
|
||||
gw_network = payload.metadata.get('network_id')
|
||||
router_id = payload.resource_id
|
||||
with ctx.session.begin():
|
||||
speakers = self._bgp_speakers_for_gateway_network(ctx,
|
||||
gw_network)
|
||||
next_hops = self._next_hops_from_gateway_ips(
|
||||
payload.metadata.get('gateway_ips'))
|
||||
gateway_ips)
|
||||
|
||||
for speaker in speakers:
|
||||
if speaker.ip_version in next_hops:
|
||||
@ -344,6 +336,22 @@ class BgpPlugin(service_base.ServicePluginBase,
|
||||
self.start_route_advertisements(ctx, self._bgp_rpc,
|
||||
speaker.id, routes)
|
||||
|
||||
def _handle_router_gateway_after_delete(self, gw_network, router_id,
|
||||
gateway_ips):
|
||||
next_hops = self._next_hops_from_gateway_ips(gateway_ips)
|
||||
ctx = context.get_admin_context()
|
||||
speakers = self._bgp_speakers_for_gateway_network(ctx, gw_network)
|
||||
for speaker in speakers:
|
||||
if speaker.ip_version in next_hops:
|
||||
next_hop = next_hops[speaker.ip_version]
|
||||
prefixes = self._tenant_prefixes_by_router(ctx,
|
||||
router_id,
|
||||
speaker.id)
|
||||
routes = self._route_list_from_prefixes_and_next_hop(
|
||||
prefixes,
|
||||
next_hop)
|
||||
self._handle_router_interface_after_delete(gw_network, routes)
|
||||
|
||||
def _handle_router_interface_after_delete(self, gw_network, routes):
|
||||
if gw_network and routes:
|
||||
ctx = context.get_admin_context()
|
||||
@ -352,6 +360,32 @@ class BgpPlugin(service_base.ServicePluginBase,
|
||||
self.stop_route_advertisements(ctx, self._bgp_rpc,
|
||||
speaker.id, routes)
|
||||
|
||||
def router_callback(self, resource, event, trigger, payload):
|
||||
if event != events.AFTER_UPDATE:
|
||||
return
|
||||
|
||||
original_router = payload.states[0]
|
||||
updated_router = payload.latest_state
|
||||
external_gateway_info = updated_router.get("external_gateway_info")
|
||||
if external_gateway_info is None:
|
||||
return
|
||||
|
||||
gateway_ips = [
|
||||
info["ip_address"] for info in
|
||||
external_gateway_info["external_fixed_ips"]]
|
||||
|
||||
if "admin_state_up" in original_router and \
|
||||
original_router.get("admin_state_up") != \
|
||||
updated_router.get("admin_state_up"):
|
||||
router_id = updated_router["id"]
|
||||
gw_network = external_gateway_info["network_id"]
|
||||
if updated_router.get("admin_state_up"):
|
||||
self._handle_router_gateway_after_create(gw_network, router_id,
|
||||
gateway_ips)
|
||||
else:
|
||||
self._handle_router_gateway_after_delete(gw_network, router_id,
|
||||
gateway_ips)
|
||||
|
||||
def port_callback(self, resource, event, trigger, payload):
|
||||
if event != events.AFTER_UPDATE:
|
||||
return
|
||||
|
@ -134,35 +134,58 @@ class BgpEntityCreationMixin(object):
|
||||
ext_net_use_addr_scope=True,
|
||||
tenant_net_use_addr_scope=True):
|
||||
gw_ip_net = netaddr.IPNetwork(gw_prefix)
|
||||
tenant_ip_net = netaddr.IPNetwork(tenant_prefix)
|
||||
ext_pool_args = {'tenant_id': tenant_id,
|
||||
'name': 'bgp-pool'}
|
||||
tenant_pool_args = ext_pool_args.copy()
|
||||
|
||||
if address_scope and ext_net_use_addr_scope:
|
||||
ext_pool_args['address_scope_id'] = address_scope['id']
|
||||
|
||||
if address_scope and tenant_net_use_addr_scope:
|
||||
tenant_pool_args['address_scope_id'] = address_scope['id']
|
||||
|
||||
with self.gw_network(external=True) as ext_net, \
|
||||
self.network() as int_net, \
|
||||
self.subnetpool([gw_prefix], **ext_pool_args) as ext_pool, \
|
||||
self.subnetpool([tenant_prefix], **tenant_pool_args) as int_pool:
|
||||
self.subnetpool([gw_prefix], **ext_pool_args) as ext_pool:
|
||||
ext_subnetpool_id = ext_pool['subnetpool']['id']
|
||||
int_subnetpool_id = int_pool['subnetpool']['id']
|
||||
gw_net_id = ext_net['network']['id']
|
||||
with self.subnet(ext_net,
|
||||
cidr=gw_prefix,
|
||||
subnetpool_id=ext_subnetpool_id,
|
||||
ip_version=gw_ip_net.version,
|
||||
as_admin=True), \
|
||||
self.subnet(int_net,
|
||||
as_admin=True):
|
||||
with self.router_with_tenant_networks(
|
||||
tenant_id,
|
||||
external_network_id=gw_net_id,
|
||||
tenant_prefix=tenant_prefix,
|
||||
address_scope=address_scope,
|
||||
distributed=distributed,
|
||||
ha=ha,
|
||||
tenant_net_use_addr_scope=tenant_net_use_addr_scope
|
||||
) as (router, int_net):
|
||||
yield router, ext_net, int_net
|
||||
|
||||
@contextlib.contextmanager
|
||||
def router_with_tenant_networks(
|
||||
self,
|
||||
tenant_id,
|
||||
external_network_id,
|
||||
tenant_prefix='192.168.0.0/16',
|
||||
address_scope=None,
|
||||
distributed=False,
|
||||
ha=False,
|
||||
tenant_net_use_addr_scope=True):
|
||||
tenant_ip_net = netaddr.IPNetwork(tenant_prefix)
|
||||
tenant_pool_args = {'tenant_id': tenant_id,
|
||||
'name': 'bgp-pool'}
|
||||
|
||||
if address_scope and tenant_net_use_addr_scope:
|
||||
tenant_pool_args['address_scope_id'] = address_scope['id']
|
||||
|
||||
with self.network() as int_net, \
|
||||
self.subnetpool([tenant_prefix], **tenant_pool_args) as int_pool:
|
||||
int_subnetpool_id = int_pool['subnetpool']['id']
|
||||
with self.subnet(int_net,
|
||||
cidr=tenant_prefix,
|
||||
subnetpool_id=int_subnetpool_id,
|
||||
ip_version=tenant_ip_net.version,
|
||||
as_admin=True) as int_subnet:
|
||||
ext_gw_info = {'network_id': gw_net_id}
|
||||
ext_gw_info = {'network_id': external_network_id}
|
||||
with self.router(external_gateway_info=ext_gw_info,
|
||||
distributed=distributed,
|
||||
ha=ha) as router:
|
||||
@ -172,7 +195,7 @@ class BgpEntityCreationMixin(object):
|
||||
self.l3plugin.add_router_interface(self.context,
|
||||
router_id,
|
||||
router_interface_info)
|
||||
yield router, ext_net, int_net
|
||||
yield router, int_net
|
||||
|
||||
|
||||
class BgpTests(BgpEntityCreationMixin):
|
||||
@ -865,6 +888,141 @@ class BgpTests(BgpEntityCreationMixin):
|
||||
self.assertTrue(tenant_prefix_found)
|
||||
self.assertTrue(fip_prefix_found)
|
||||
|
||||
def test_get_routes_by_bgp_speaker_id_with_fip_router_disabled(self):
|
||||
gw_prefix = '172.16.10.0/24'
|
||||
tenant_prefix = '10.10.10.0/24'
|
||||
tenant_id = _uuid()
|
||||
scope_data = {'tenant_id': tenant_id, 'ip_version': 4,
|
||||
'shared': True, 'name': 'bgp-scope'}
|
||||
scope = self.plugin.create_address_scope(
|
||||
self.context,
|
||||
{'address_scope': scope_data})
|
||||
with self.router_with_external_and_tenant_networks(
|
||||
tenant_id=tenant_id,
|
||||
gw_prefix=gw_prefix,
|
||||
tenant_prefix=tenant_prefix,
|
||||
address_scope=scope) as res:
|
||||
router, ext_net, int_net = res
|
||||
self.l3plugin.update_router(
|
||||
self.context, router['id'],
|
||||
{'router': {'admin_state_up': False}})
|
||||
gw_net_id = ext_net['network']['id']
|
||||
tenant_net_id = int_net['network']['id']
|
||||
fixed_port_data = {'port':
|
||||
{'name': 'test',
|
||||
'network_id': tenant_net_id,
|
||||
'tenant_id': tenant_id,
|
||||
'admin_state_up': True,
|
||||
'device_id': _uuid(),
|
||||
'device_owner': 'compute:nova',
|
||||
'mac_address': n_const.ATTR_NOT_SPECIFIED,
|
||||
'fixed_ips': n_const.ATTR_NOT_SPECIFIED}}
|
||||
fixed_port = self.plugin.create_port(self.context,
|
||||
fixed_port_data)
|
||||
fip_data = {'floatingip': {'floating_network_id': gw_net_id,
|
||||
'tenant_id': tenant_id,
|
||||
'port_id': fixed_port['id']}}
|
||||
self.l3plugin.create_floatingip(self.context, fip_data)
|
||||
with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker:
|
||||
bgp_speaker_id = speaker['id']
|
||||
routes = self.bgp_plugin.get_routes_by_bgp_speaker_id(
|
||||
self.context,
|
||||
bgp_speaker_id)
|
||||
routes = list(routes)
|
||||
print(routes)
|
||||
self.assertEqual(0, len(routes))
|
||||
|
||||
def test_get_routes_by_bgp_speaker_id_with_fip_two_router_one_disabled(
|
||||
self):
|
||||
gw_prefix = '172.16.10.0/24'
|
||||
tenant_prefix1 = '10.10.10.0/24'
|
||||
tenant_prefix2 = '10.10.20.0/24'
|
||||
tenant_id = _uuid()
|
||||
scope_data = {'tenant_id': tenant_id, 'ip_version': 4,
|
||||
'shared': True, 'name': 'bgp-scope'}
|
||||
scope = self.plugin.create_address_scope(
|
||||
self.context,
|
||||
{'address_scope': scope_data})
|
||||
# network and router setup
|
||||
with self.router_with_external_and_tenant_networks(
|
||||
tenant_id=tenant_id,
|
||||
gw_prefix=gw_prefix,
|
||||
tenant_prefix=tenant_prefix1,
|
||||
address_scope=scope) as res:
|
||||
router1, ext_net, int_net1 = res
|
||||
gw_net_id = ext_net['network']['id']
|
||||
with self.router_with_tenant_networks(
|
||||
tenant_id=tenant_id,
|
||||
external_network_id=gw_net_id,
|
||||
tenant_prefix=tenant_prefix2,
|
||||
address_scope=scope
|
||||
) as (router2, int_net2):
|
||||
|
||||
# fip setup
|
||||
tenant_net_id1 = int_net1['network']['id']
|
||||
fixed_port_data1 = {'port':
|
||||
{'name': 'test',
|
||||
'network_id': tenant_net_id1,
|
||||
'tenant_id': tenant_id,
|
||||
'admin_state_up': True,
|
||||
'device_id': _uuid(),
|
||||
'device_owner': 'compute:nova',
|
||||
'mac_address': n_const.ATTR_NOT_SPECIFIED,
|
||||
'fixed_ips': n_const.ATTR_NOT_SPECIFIED}}
|
||||
fixed_port1 = self.plugin.create_port(self.context,
|
||||
fixed_port_data1)
|
||||
fip_data1 = {'floatingip': {'floating_network_id': gw_net_id,
|
||||
'tenant_id': tenant_id,
|
||||
'port_id': fixed_port1['id']}}
|
||||
fip1 = self.l3plugin.create_floatingip(self.context, fip_data1)
|
||||
|
||||
tenant_net_id2 = int_net2['network']['id']
|
||||
fixed_port_data2 = {'port':
|
||||
{'name': 'test',
|
||||
'network_id': tenant_net_id2,
|
||||
'tenant_id': tenant_id,
|
||||
'admin_state_up': True,
|
||||
'device_id': _uuid(),
|
||||
'device_owner': 'compute:nova',
|
||||
'mac_address': n_const.ATTR_NOT_SPECIFIED,
|
||||
'fixed_ips': n_const.ATTR_NOT_SPECIFIED}}
|
||||
fixed_port2 = self.plugin.create_port(self.context,
|
||||
fixed_port_data2)
|
||||
fip_data2 = {'floatingip': {'floating_network_id': gw_net_id,
|
||||
'tenant_id': tenant_id,
|
||||
'port_id': fixed_port2['id']}}
|
||||
self.l3plugin.create_floatingip(self.context, fip_data2)
|
||||
|
||||
# disable router2
|
||||
self.l3plugin.update_router(
|
||||
self.context, router2['id'],
|
||||
{'router': {'admin_state_up': False}})
|
||||
|
||||
# start bgp and validate
|
||||
ext_gw_info1 = router1['external_gateway_info']
|
||||
fip_prefix1 = fip1['floating_ip_address'] + '/32'
|
||||
|
||||
with self.bgp_speaker(4, 1234, networks=[gw_net_id]
|
||||
) as speaker:
|
||||
bgp_speaker_id = speaker['id']
|
||||
routes = self.bgp_plugin.get_routes_by_bgp_speaker_id(
|
||||
self.context,
|
||||
bgp_speaker_id)
|
||||
routes = list(routes)
|
||||
next_hop = ext_gw_info1[
|
||||
'external_fixed_ips'][0]['ip_address']
|
||||
self.assertEqual(2, len(routes))
|
||||
tenant_prefix_found = False
|
||||
fip_prefix_found = False
|
||||
for route in routes:
|
||||
self.assertEqual(next_hop, route['next_hop'])
|
||||
if route['destination'] == tenant_prefix1:
|
||||
tenant_prefix_found = True
|
||||
if route['destination'] == fip_prefix1:
|
||||
fip_prefix_found = True
|
||||
self.assertTrue(tenant_prefix_found)
|
||||
self.assertTrue(fip_prefix_found)
|
||||
|
||||
def test_get_routes_by_bgp_speaker_id_with_fip_dvr(self):
|
||||
gw_prefix = '172.16.10.0/24'
|
||||
tenant_prefix = '10.10.10.0/24'
|
||||
|
@ -72,6 +72,8 @@ class TestBgpPlugin(base.BaseTestCase):
|
||||
resources.ROUTER_GATEWAY, events.AFTER_CREATE),
|
||||
mock.call(plugin.router_gateway_callback,
|
||||
resources.ROUTER_GATEWAY, events.AFTER_DELETE),
|
||||
mock.call(plugin.router_callback,
|
||||
resources.ROUTER, events.AFTER_UPDATE),
|
||||
mock.call(plugin.port_callback,
|
||||
resources.PORT, events.AFTER_UPDATE),
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user