Add L3 Notifications To Enable BGP Dynamic Routing
This patch makes the L3 service generate notifications that enable BGP dynamic routing to react appropriately to user-initiated changes that affect prefixes that should be advertised and the corresponding next-hops. Partially-Implements: blueprint bgp-dynamic-routing Co-Authored-By: vikram.choudhary <vikram.choudhary@huawei.com> Change-Id: I96f14a31876efeca5881d97771e3263525522e36
This commit is contained in:
parent
fe8b3299d7
commit
53138b80f3
|
@ -11,6 +11,7 @@
|
|||
# under the License.
|
||||
|
||||
# String literals representing core resources.
|
||||
FLOATING_IP = 'floating_ip'
|
||||
PORT = 'port'
|
||||
PROCESS = 'process'
|
||||
ROUTER = 'router'
|
||||
|
|
|
@ -343,6 +343,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase):
|
|||
if not port_requires_deletion:
|
||||
return
|
||||
admin_ctx = context.elevated()
|
||||
old_network_id = router.gw_port['network_id']
|
||||
|
||||
if self.get_floatingips_count(
|
||||
admin_ctx, {'router_id': [router_id]}):
|
||||
|
@ -356,6 +357,10 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase):
|
|||
self._check_router_gw_port_in_use(context, router_id)
|
||||
self._core_plugin.delete_port(
|
||||
admin_ctx, gw_port['id'], l3_port_check=False)
|
||||
registry.notify(resources.ROUTER_GATEWAY,
|
||||
events.AFTER_DELETE, self,
|
||||
router_id=router_id,
|
||||
network_id=old_network_id)
|
||||
|
||||
def _check_router_gw_port_in_use(self, context, router_id):
|
||||
try:
|
||||
|
@ -383,6 +388,12 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase):
|
|||
subnet['cidr'])
|
||||
self._create_router_gw_port(context, router,
|
||||
new_network_id, ext_ips)
|
||||
registry.notify(resources.ROUTER_GATEWAY,
|
||||
events.AFTER_CREATE,
|
||||
self._create_gw_port,
|
||||
gw_ips=ext_ips,
|
||||
network_id=new_network_id,
|
||||
router_id=router_id)
|
||||
|
||||
def _update_current_gw_port(self, context, router_id, router, ext_ips):
|
||||
self._core_plugin.update_port(context, router.gw_port['id'], {'port':
|
||||
|
@ -667,6 +678,22 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase):
|
|||
)
|
||||
context.session.add(router_port)
|
||||
|
||||
gw_ips = []
|
||||
gw_network_id = None
|
||||
if router.gw_port:
|
||||
gw_network_id = router.gw_port.network_id
|
||||
gw_ips = router.gw_port.fixed_ips
|
||||
|
||||
registry.notify(resources.ROUTER_INTERFACE,
|
||||
events.AFTER_CREATE,
|
||||
self,
|
||||
network_id=gw_network_id,
|
||||
gateway_ips=gw_ips,
|
||||
cidrs=[x['cidr'] for x in subnets],
|
||||
port_id=port['id'],
|
||||
router_id=router_id,
|
||||
interface_info=interface_info)
|
||||
|
||||
return self._make_router_interface_info(
|
||||
router.id, port['tenant_id'], port['id'], subnets[-1]['id'],
|
||||
[subnet['id'] for subnet in subnets])
|
||||
|
@ -771,6 +798,16 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase):
|
|||
port, subnets = self._remove_interface_by_subnet(
|
||||
context, router_id, subnet_id, device_owner)
|
||||
|
||||
gw_network_id = None
|
||||
router = self._get_router(context, router_id)
|
||||
if router.gw_port:
|
||||
gw_network_id = router.gw_port.network_id
|
||||
|
||||
registry.notify(resources.ROUTER_INTERFACE,
|
||||
events.AFTER_DELETE,
|
||||
self,
|
||||
cidrs=[x['cidr'] for x in subnets],
|
||||
network_id=gw_network_id)
|
||||
return self._make_router_interface_info(router_id, port['tenant_id'],
|
||||
port['id'], subnets[0]['id'],
|
||||
[subnet['id'] for subnet in
|
||||
|
@ -948,6 +985,27 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase):
|
|||
'fixed_port_id': port_id,
|
||||
'router_id': router_id,
|
||||
'last_known_router_id': previous_router_id})
|
||||
next_hop = None
|
||||
if router_id:
|
||||
router = self._get_router(context, router_id)
|
||||
gw_port = router.gw_port
|
||||
for fixed_ip in gw_port.fixed_ips:
|
||||
addr = netaddr.IPAddress(fixed_ip.ip_address)
|
||||
if addr.version == l3_constants.IP_VERSION_4:
|
||||
next_hop = fixed_ip.ip_address
|
||||
break
|
||||
args = {'fixed_ip_address': internal_ip_address,
|
||||
'fixed_port_id': port_id,
|
||||
'router_id': router_id,
|
||||
'last_known_router_id': previous_router_id,
|
||||
'floating_ip_address': floatingip_db.floating_ip_address,
|
||||
'floating_network_id': floatingip_db.floating_network_id,
|
||||
'next_hop': next_hop,
|
||||
'context': context}
|
||||
registry.notify(resources.FLOATING_IP,
|
||||
events.AFTER_UPDATE,
|
||||
self._update_fip_assoc,
|
||||
**args)
|
||||
|
||||
def _is_ipv4_network(self, context, net_id):
|
||||
net = self._core_plugin._get_network(context, net_id)
|
||||
|
|
|
@ -1619,15 +1619,16 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
|
|||
exceptions.NotificationError(
|
||||
'foo_callback_id', n_exc.InUse()),
|
||||
]
|
||||
self._router_interface_action('add',
|
||||
r['router']['id'],
|
||||
s['subnet']['id'],
|
||||
None)
|
||||
|
||||
# we fail the first time, but not the second, when
|
||||
# the clean-up takes place
|
||||
notify.side_effect = [
|
||||
exceptions.CallbackFailure(errors=errors), None
|
||||
]
|
||||
self._router_interface_action('add',
|
||||
r['router']['id'],
|
||||
s['subnet']['id'],
|
||||
None)
|
||||
self._router_interface_action(
|
||||
'remove',
|
||||
r['router']['id'],
|
||||
|
@ -1643,11 +1644,12 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
|
|||
exceptions.NotificationError(
|
||||
'foo_callback_id', n_exc.InUse()),
|
||||
]
|
||||
notify.side_effect = exceptions.CallbackFailure(errors=errors)
|
||||
|
||||
self._set_net_external(s['subnet']['network_id'])
|
||||
self._add_external_gateway_to_router(
|
||||
r['router']['id'],
|
||||
s['subnet']['network_id'])
|
||||
notify.side_effect = exceptions.CallbackFailure(errors=errors)
|
||||
self._remove_external_gateway_from_router(
|
||||
r['router']['id'],
|
||||
s['subnet']['network_id'],
|
||||
|
@ -1912,7 +1914,7 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
|
|||
self.fmt,
|
||||
public_sub['subnet']['network_id'],
|
||||
port_id=private_port['port']['id'],
|
||||
set_context=True)
|
||||
set_context=False)
|
||||
self.assertTrue(agent_notification.called)
|
||||
|
||||
def test_floating_port_status_not_applicable(self):
|
||||
|
@ -2022,6 +2024,65 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
|
|||
self.assertEqual(str(ip_range[-2]),
|
||||
body_2['floatingip']['fixed_ip_address'])
|
||||
|
||||
def test_first_floatingip_associate_notification(self):
|
||||
with self.port() as p:
|
||||
private_sub = {'subnet': {'id':
|
||||
p['port']['fixed_ips'][0]['subnet_id']}}
|
||||
with self.floatingip_no_assoc(private_sub) as fip:
|
||||
port_id = p['port']['id']
|
||||
ip_address = p['port']['fixed_ips'][0]['ip_address']
|
||||
with mock.patch.object(registry, 'notify') as notify:
|
||||
body = self._update('floatingips',
|
||||
fip['floatingip']['id'],
|
||||
{'floatingip': {'port_id': port_id}})
|
||||
fip_addr = fip['floatingip']['floating_ip_address']
|
||||
fip_network_id = fip['floatingip']['floating_network_id']
|
||||
router_id = body['floatingip']['router_id']
|
||||
body = self._show('routers', router_id)
|
||||
ext_gw_info = body['router']['external_gateway_info']
|
||||
ext_fixed_ip = ext_gw_info['external_fixed_ips'][0]
|
||||
notify.assert_called_once_with(
|
||||
resources.FLOATING_IP,
|
||||
events.AFTER_UPDATE,
|
||||
mock.ANY,
|
||||
context=mock.ANY,
|
||||
fixed_ip_address=ip_address,
|
||||
fixed_port_id=port_id,
|
||||
floating_ip_address=fip_addr,
|
||||
floating_network_id=fip_network_id,
|
||||
last_known_router_id=None,
|
||||
router_id=router_id,
|
||||
next_hop=ext_fixed_ip['ip_address'])
|
||||
|
||||
def test_floatingip_disassociate_notification(self):
|
||||
with self.port() as p:
|
||||
private_sub = {'subnet': {'id':
|
||||
p['port']['fixed_ips'][0]['subnet_id']}}
|
||||
with self.floatingip_no_assoc(private_sub) as fip:
|
||||
port_id = p['port']['id']
|
||||
body = self._update('floatingips',
|
||||
fip['floatingip']['id'],
|
||||
{'floatingip': {'port_id': port_id}})
|
||||
with mock.patch.object(registry, 'notify') as notify:
|
||||
fip_addr = fip['floatingip']['floating_ip_address']
|
||||
fip_network_id = fip['floatingip']['floating_network_id']
|
||||
router_id = body['floatingip']['router_id']
|
||||
self._update('floatingips',
|
||||
fip['floatingip']['id'],
|
||||
{'floatingip': {'port_id': None}})
|
||||
notify.assert_called_once_with(
|
||||
resources.FLOATING_IP,
|
||||
events.AFTER_UPDATE,
|
||||
mock.ANY,
|
||||
context=mock.ANY,
|
||||
fixed_ip_address=None,
|
||||
fixed_port_id=None,
|
||||
floating_ip_address=fip_addr,
|
||||
floating_network_id=fip_network_id,
|
||||
last_known_router_id=router_id,
|
||||
router_id=None,
|
||||
next_hop=None)
|
||||
|
||||
def test_floatingip_update_different_router(self):
|
||||
# Create subnet with different CIDRs to account for plugins which
|
||||
# do not support overlapping IPs
|
||||
|
|
Loading…
Reference in New Issue