NSX|V3+P: Ensure router GW & interfaces do not overlap
The NSX backend will fail to add NAT rules in case the GW network and the interface networks overlap. This patch will ensure that the GW and interfaces do not overlap Change-Id: I6a6c6be865dc05a1f73f17f47e182c7087cb8a21
This commit is contained in:
parent
8b48578f69
commit
1a607f7941
|
@ -1189,6 +1189,26 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||
self._validate_router_tz(context, new_tier0_uuid,
|
||||
router_subnets)
|
||||
|
||||
def _validate_gw_overlap_interfaces(self, context, gateway_net,
|
||||
interfaces_networks):
|
||||
# Ensure that interface subnets cannot overlap with the GW subnet
|
||||
gw_subnets = self._get_subnets_by_network(
|
||||
context.elevated(), gateway_net)
|
||||
gw_cidrs = [subnet['cidr'] for subnet in gw_subnets]
|
||||
gw_ip_set = netaddr.IPSet(gw_cidrs)
|
||||
|
||||
if_subnets = []
|
||||
for net in interfaces_networks:
|
||||
if_subnets.extend(self._get_subnets_by_network(
|
||||
context.elevated(), net))
|
||||
if_cidrs = [subnet['cidr'] for subnet in if_subnets]
|
||||
if_ip_set = netaddr.IPSet(if_cidrs)
|
||||
|
||||
if gw_ip_set & if_ip_set:
|
||||
msg = _("Interface network cannot overlap with router GW network")
|
||||
LOG.error(msg)
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
|
||||
def _get_update_router_gw_actions(
|
||||
self,
|
||||
org_tier0_uuid, orgaddr, org_enable_snat,
|
||||
|
|
|
@ -1364,6 +1364,11 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
|
|||
context.elevated(), router_id)
|
||||
self._validate_router_gw_and_tz(context, router_id, info,
|
||||
org_enable_snat, router_subnets)
|
||||
# Interface subnets cannot overlap with the GW external subnet
|
||||
if info and info.get('network_id'):
|
||||
self._validate_gw_overlap_interfaces(
|
||||
context, info['network_id'],
|
||||
[sub['network_id'] for sub in router_subnets])
|
||||
|
||||
# First update the neutron DB
|
||||
super(NsxPolicyPlugin, self)._update_router_gw_info(
|
||||
|
@ -1612,6 +1617,10 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
|
|||
"must have an external network assigned")
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
|
||||
# Interface subnets cannot overlap with the GW external subnet
|
||||
self._validate_gw_overlap_interfaces(context, gw_network_id,
|
||||
[network_id])
|
||||
|
||||
# Update the interface of the neutron router
|
||||
info = super(NsxPolicyPlugin, self).add_router_interface(
|
||||
context, router_id, interface_info)
|
||||
|
|
|
@ -2144,6 +2144,11 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
|
|||
context.elevated(), router_id)
|
||||
self._validate_router_gw_and_tz(context, router_id, info,
|
||||
org_enable_snat, router_subnets)
|
||||
# Interface subnets cannot overlap with the GW external subnet
|
||||
if info and info.get('network_id'):
|
||||
self._validate_gw_overlap_interfaces(
|
||||
context, info['network_id'],
|
||||
[sub['network_id'] for sub in router_subnets])
|
||||
|
||||
# TODO(berlin): For nonat use case, we actually don't need a gw port
|
||||
# which consumes one external ip. But after looking at the DB logic
|
||||
|
@ -2688,6 +2693,10 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
|
|||
"must have an external network assigned")
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
|
||||
# Interface subnets cannot overlap with the GW external subnet
|
||||
self._validate_gw_overlap_interfaces(context, gw_network_id,
|
||||
[network_id])
|
||||
|
||||
# Update the interface of the neutron router
|
||||
info = self._add_router_interface_wrapper(context, router_id,
|
||||
interface_info)
|
||||
|
|
|
@ -1679,8 +1679,13 @@ class NsxPTestL3NatTestCase(NsxPTestL3NatTest,
|
|||
|
||||
@common_v3.with_external_subnet_once
|
||||
def test_router_update_gateway_with_existed_floatingip(self):
|
||||
super(NsxPTestL3NatTestCase,
|
||||
self).test_router_update_gateway_with_existed_floatingip()
|
||||
with self.subnet(cidr='20.0.0.0/24') as subnet:
|
||||
self._set_net_external(subnet['subnet']['network_id'])
|
||||
with self.floatingip_with_assoc() as fip:
|
||||
self._add_external_gateway_to_router(
|
||||
fip['floatingip']['router_id'],
|
||||
subnet['subnet']['network_id'],
|
||||
expected_code=exc.HTTPConflict.code)
|
||||
|
||||
@common_v3.with_external_network
|
||||
def test_router_update_gateway_add_multiple_prefixes_ipv6(self):
|
||||
|
@ -1692,11 +1697,6 @@ class NsxPTestL3NatTestCase(NsxPTestL3NatTest,
|
|||
super(NsxPTestL3NatTestCase,
|
||||
self).test_router_concurrent_delete_upon_subnet_create()
|
||||
|
||||
@common_v3.with_external_subnet_second_time
|
||||
def test_router_add_interface_cidr_overlapped_with_gateway(self):
|
||||
super(NsxPTestL3NatTestCase,
|
||||
self).test_router_add_interface_cidr_overlapped_with_gateway()
|
||||
|
||||
@common_v3.with_external_subnet
|
||||
def test_router_add_gateway_dup_subnet2_returns_400(self):
|
||||
super(NsxPTestL3NatTestCase,
|
||||
|
@ -1737,11 +1737,6 @@ class NsxPTestL3NatTestCase(NsxPTestL3NatTest,
|
|||
super(NsxPTestL3NatTestCase,
|
||||
self).test_router_add_and_remove_gateway_tenant_ctx()
|
||||
|
||||
@common_v3.with_external_subnet_second_time
|
||||
def test_router_add_interface_by_port_cidr_overlapped_with_gateway(self):
|
||||
super(NsxPTestL3NatTestCase, self).\
|
||||
test_router_add_interface_by_port_cidr_overlapped_with_gateway()
|
||||
|
||||
@common_v3.with_external_subnet
|
||||
def test_router_add_and_remove_gateway(self):
|
||||
super(NsxPTestL3NatTestCase,
|
||||
|
@ -1950,3 +1945,51 @@ class NsxPTestL3NatTestCase(NsxPTestL3NatTest,
|
|||
s['subnet']['network_id'])
|
||||
add_srv_router.assert_called_once_with(
|
||||
mock.ANY, '%s%s' % (path_prefix, edge_cluster))
|
||||
|
||||
def test_router_add_interface_cidr_overlapped_with_gateway(self):
|
||||
with self.router() as r,\
|
||||
self._create_l3_ext_network() as ext_net,\
|
||||
self.subnet(cidr='10.0.1.0/24') as s1,\
|
||||
self.subnet(network=ext_net, cidr='10.0.0.0/16',
|
||||
enable_dhcp=False) as s2:
|
||||
self._add_external_gateway_to_router(
|
||||
r['router']['id'],
|
||||
s2['subnet']['network_id'])
|
||||
res = self._router_interface_action(
|
||||
'add', r['router']['id'],
|
||||
s1['subnet']['id'], None,
|
||||
expected_code=exc.HTTPBadRequest.code)
|
||||
self.assertIn('NeutronError', res)
|
||||
|
||||
def test_router_add_gateway_overlapped_with_interface_cidr(self):
|
||||
with self.router() as r,\
|
||||
self._create_l3_ext_network() as ext_net,\
|
||||
self.subnet(cidr='10.0.1.0/24') as s1,\
|
||||
self.subnet(network=ext_net, cidr='10.0.0.0/16',
|
||||
enable_dhcp=False) as s2:
|
||||
self._router_interface_action(
|
||||
'add', r['router']['id'],
|
||||
s1['subnet']['id'], None)
|
||||
res = self._add_external_gateway_to_router(
|
||||
r['router']['id'],
|
||||
s2['subnet']['network_id'],
|
||||
expected_code=exc.HTTPBadRequest.code)
|
||||
self.assertIn('NeutronError', res)
|
||||
|
||||
def test_router_add_interface_by_port_cidr_overlapped_with_gateway(self):
|
||||
with self.router() as r,\
|
||||
self._create_l3_ext_network() as ext_net,\
|
||||
self.subnet(cidr='10.0.1.0/24') as s1,\
|
||||
self.subnet(network=ext_net, cidr='10.0.0.0/16',
|
||||
enable_dhcp=False) as s2,\
|
||||
self.port(subnet=s1) as p:
|
||||
self._add_external_gateway_to_router(
|
||||
r['router']['id'],
|
||||
s2['subnet']['network_id'])
|
||||
|
||||
res = self._router_interface_action(
|
||||
'add', r['router']['id'],
|
||||
None,
|
||||
p['port']['id'],
|
||||
expected_code=exc.HTTPBadRequest.code)
|
||||
self.assertIn('NeutronError', res)
|
||||
|
|
|
@ -2038,8 +2038,13 @@ class TestL3NatTestCase(L3NatTest,
|
|||
|
||||
@common_v3.with_external_subnet_once
|
||||
def test_router_update_gateway_with_existed_floatingip(self):
|
||||
super(TestL3NatTestCase,
|
||||
self).test_router_update_gateway_with_existed_floatingip()
|
||||
with self.subnet(cidr='20.0.0.0/24') as subnet:
|
||||
self._set_net_external(subnet['subnet']['network_id'])
|
||||
with self.floatingip_with_assoc() as fip:
|
||||
self._add_external_gateway_to_router(
|
||||
fip['floatingip']['router_id'],
|
||||
subnet['subnet']['network_id'],
|
||||
expected_code=exc.HTTPConflict.code)
|
||||
|
||||
@common_v3.with_external_network
|
||||
def test_router_update_gateway_add_multiple_prefixes_ipv6(self):
|
||||
|
@ -2056,11 +2061,6 @@ class TestL3NatTestCase(L3NatTest,
|
|||
super(TestL3NatTestCase,
|
||||
self).test_router_update_gateway_upon_subnet_create_ipv6()
|
||||
|
||||
@common_v3.with_external_subnet_second_time
|
||||
def test_router_add_interface_cidr_overlapped_with_gateway(self):
|
||||
super(TestL3NatTestCase,
|
||||
self).test_router_add_interface_cidr_overlapped_with_gateway()
|
||||
|
||||
@common_v3.with_external_subnet
|
||||
def test_router_add_gateway_dup_subnet2_returns_400(self):
|
||||
super(TestL3NatTestCase,
|
||||
|
@ -2101,11 +2101,6 @@ class TestL3NatTestCase(L3NatTest,
|
|||
super(TestL3NatTestCase,
|
||||
self).test_router_add_and_remove_gateway_tenant_ctx()
|
||||
|
||||
@common_v3.with_external_subnet_second_time
|
||||
def test_router_add_interface_by_port_cidr_overlapped_with_gateway(self):
|
||||
super(TestL3NatTestCase, self).\
|
||||
test_router_add_interface_by_port_cidr_overlapped_with_gateway()
|
||||
|
||||
@common_v3.with_external_subnet
|
||||
def test_router_add_and_remove_gateway(self):
|
||||
super(TestL3NatTestCase,
|
||||
|
@ -3058,6 +3053,54 @@ class TestL3NatTestCase(L3NatTest,
|
|||
enable_standby_relocation=True)
|
||||
self.mock_get_edge_cluster.start()
|
||||
|
||||
def test_router_add_interface_cidr_overlapped_with_gateway(self):
|
||||
with self.router() as r,\
|
||||
self._create_l3_ext_network() as ext_net,\
|
||||
self.subnet(cidr='10.0.1.0/24') as s1,\
|
||||
self.subnet(network=ext_net, cidr='10.0.0.0/16',
|
||||
enable_dhcp=False) as s2:
|
||||
self._add_external_gateway_to_router(
|
||||
r['router']['id'],
|
||||
s2['subnet']['network_id'])
|
||||
res = self._router_interface_action(
|
||||
'add', r['router']['id'],
|
||||
s1['subnet']['id'], None,
|
||||
expected_code=exc.HTTPBadRequest.code)
|
||||
self.assertIn('NeutronError', res)
|
||||
|
||||
def test_router_add_gateway_overlapped_with_interface_cidr(self):
|
||||
with self.router() as r,\
|
||||
self._create_l3_ext_network() as ext_net,\
|
||||
self.subnet(cidr='10.0.1.0/24') as s1,\
|
||||
self.subnet(network=ext_net, cidr='10.0.0.0/16',
|
||||
enable_dhcp=False) as s2:
|
||||
self._router_interface_action(
|
||||
'add', r['router']['id'],
|
||||
s1['subnet']['id'], None)
|
||||
res = self._add_external_gateway_to_router(
|
||||
r['router']['id'],
|
||||
s2['subnet']['network_id'],
|
||||
expected_code=exc.HTTPBadRequest.code)
|
||||
self.assertIn('NeutronError', res)
|
||||
|
||||
def test_router_add_interface_by_port_cidr_overlapped_with_gateway(self):
|
||||
with self.router() as r,\
|
||||
self._create_l3_ext_network() as ext_net,\
|
||||
self.subnet(cidr='10.0.1.0/24') as s1,\
|
||||
self.subnet(network=ext_net, cidr='10.0.0.0/16',
|
||||
enable_dhcp=False) as s2,\
|
||||
self.port(subnet=s1) as p:
|
||||
self._add_external_gateway_to_router(
|
||||
r['router']['id'],
|
||||
s2['subnet']['network_id'])
|
||||
|
||||
res = self._router_interface_action(
|
||||
'add', r['router']['id'],
|
||||
None,
|
||||
p['port']['id'],
|
||||
expected_code=exc.HTTPBadRequest.code)
|
||||
self.assertIn('NeutronError', res)
|
||||
|
||||
|
||||
class ExtGwModeTestCase(test_ext_gw_mode.ExtGwModeIntTestCase,
|
||||
L3NatTest):
|
||||
|
|
|
@ -613,7 +613,7 @@ class TestVpnaasDriver(test_plugin.NsxV3PluginTestCaseMixin):
|
|||
return_value=tier0_uuid),\
|
||||
self.router(external_gateway_info={'network_id':
|
||||
ext_net['network']['id']}) as router,\
|
||||
self.subnet() as sub:
|
||||
self.subnet(cidr='1.1.0.0/24') as sub:
|
||||
# add an interface to the router
|
||||
self.l3plugin.add_router_interface(
|
||||
self.context,
|
||||
|
@ -665,7 +665,7 @@ class TestVpnaasDriver(test_plugin.NsxV3PluginTestCaseMixin):
|
|||
return_value=tier0_rtr_id),\
|
||||
self.router(external_gateway_info={'network_id':
|
||||
ext_net['network']['id']}) as router,\
|
||||
self.subnet() as sub:
|
||||
self.subnet(cidr='1.1.0.0/24') as sub:
|
||||
# add an interface to the router
|
||||
self.l3plugin.add_router_interface(
|
||||
self.context,
|
||||
|
|
Loading…
Reference in New Issue