NSX|v: Handle address scope change on subnetpool
Address scope is mutable on subnetpool after subnets were allocated. When address scope changes, neutron fires AFTER_CHANGE event. Upon catching this notification: 1. Log warning if no-nat router resulted with mixed address scopes 2. Recalculate snat rules if needed 3. Recalculate firewall rules A fix for nsx-v3 was already introduced in commit I1de25868db0d77fbcb7ebc588c6ab9493a3dadf4 Change-Id: I2696f0ba0edf0409993455b7a9e6e478383f3276
This commit is contained in:
parent
803a6bffe4
commit
345e5ea10b
@ -202,6 +202,13 @@ class NsxPluginBase(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def recalculate_fw_rules_for_router(self, context, router, subnets):
|
||||||
|
"""Method to recalculate router FW rules for specific subnets.
|
||||||
|
Invoked when subnetpool address scope changes.
|
||||||
|
Implemented in child plugin classes
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
def _filter_subnets_by_subnetpool(self, subnets, subnetpool_id):
|
def _filter_subnets_by_subnetpool(self, subnets, subnetpool_id):
|
||||||
return [subnet for subnet in subnets
|
return [subnet for subnet in subnets
|
||||||
if subnet['subnetpool_id'] == subnetpool_id]
|
if subnet['subnetpool_id'] == subnetpool_id]
|
||||||
@ -236,7 +243,10 @@ class NsxPluginBase(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# (all router subnets were allocated from subnetpool_id)
|
# (all router subnets were allocated from subnetpool_id)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# TODO(annak): handle east-west FW rules
|
# Update east-west FW rules
|
||||||
|
self.recalculate_fw_rules_for_router(context, rtr,
|
||||||
|
affected_subnets)
|
||||||
|
|
||||||
if not rtr['external_gateway_info']:
|
if not rtr['external_gateway_info']:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -294,6 +294,11 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
|||||||
fc_utils.SERVICE_INSERTION_RESOURCE,
|
fc_utils.SERVICE_INSERTION_RESOURCE,
|
||||||
events.AFTER_CREATE)
|
events.AFTER_CREATE)
|
||||||
|
|
||||||
|
# Subscribe to subnet pools changes
|
||||||
|
registry.subscribe(
|
||||||
|
self.on_subnetpool_address_scope_updated,
|
||||||
|
resources.SUBNETPOOL_ADDRESS_SCOPE, events.AFTER_UPDATE)
|
||||||
|
|
||||||
if c_utils.is_nsxv_version_6_2(self.nsx_v.vcns.get_version()):
|
if c_utils.is_nsxv_version_6_2(self.nsx_v.vcns.get_version()):
|
||||||
self.supported_extension_aliases.append("provider-security-group")
|
self.supported_extension_aliases.append("provider-security-group")
|
||||||
|
|
||||||
@ -3455,6 +3460,22 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
|||||||
edge_utils.update_nat_rules(
|
edge_utils.update_nat_rules(
|
||||||
self.nsx_v, context, router_id, snat, dnat)
|
self.nsx_v, context, router_id, snat, dnat)
|
||||||
|
|
||||||
|
def recalculate_snat_rules_for_router(self, context, router, subnets):
|
||||||
|
"""Recalculate router snat rules for specific subnets.
|
||||||
|
Invoked when subnetpool address scope changes.
|
||||||
|
"""
|
||||||
|
# Recalculate all nat rules for all subnets of the router
|
||||||
|
router_db = self._get_router(context, router['id'])
|
||||||
|
self._update_nat_rules(context, router_db)
|
||||||
|
|
||||||
|
def recalculate_fw_rules_for_router(self, context, router, subnets):
|
||||||
|
"""Recalculate router fw rules for specific subnets.
|
||||||
|
Invoked when subnetpool address scope changes.
|
||||||
|
"""
|
||||||
|
# Recalculate all fw rules for all subnets of the router
|
||||||
|
router_db = self._get_router(context, router['id'])
|
||||||
|
self._update_subnets_and_dnat_firewall(context, router_db)
|
||||||
|
|
||||||
def _check_intf_number_of_router(self, context, router_id):
|
def _check_intf_number_of_router(self, context, router_id):
|
||||||
intf_ports = self._get_port_by_device_id(
|
intf_ports = self._get_port_by_device_id(
|
||||||
context, router_id, l3_db.DEVICE_OWNER_ROUTER_INTF)
|
context, router_id, l3_db.DEVICE_OWNER_ROUTER_INTF)
|
||||||
|
@ -3731,7 +3731,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
net_res[az_ext.AVAILABILITY_ZONES] = [az_name]
|
net_res[az_ext.AVAILABILITY_ZONES] = [az_name]
|
||||||
|
|
||||||
def recalculate_snat_rules_for_router(self, context, router, subnets):
|
def recalculate_snat_rules_for_router(self, context, router, subnets):
|
||||||
"""Rrecalculate router snat rules for specific subnets.
|
"""Recalculate router snat rules for specific subnets.
|
||||||
Invoked when subnetpool address scope changes.
|
Invoked when subnetpool address scope changes.
|
||||||
"""
|
"""
|
||||||
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
|
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
|
||||||
|
@ -3490,6 +3490,26 @@ class TestExclusiveRouterTestCase(L3NatTest, L3NatTestCaseBase,
|
|||||||
None,
|
None,
|
||||||
err_code)
|
err_code)
|
||||||
|
|
||||||
|
def _create_subnet_and_add_to_router(self, subnetpool_id, router_id):
|
||||||
|
# create a regular network on the given subnet pool
|
||||||
|
with self.network() as net:
|
||||||
|
data = {'subnet': {
|
||||||
|
'network_id': net['network']['id'],
|
||||||
|
'subnetpool_id': subnetpool_id,
|
||||||
|
'ip_version': 4,
|
||||||
|
'tenant_id': net['network']['tenant_id']}}
|
||||||
|
req = self.new_create_request('subnets', data)
|
||||||
|
int_subnet = self.deserialize(
|
||||||
|
self.fmt, req.get_response(self.api))
|
||||||
|
|
||||||
|
# Add the interface to the router
|
||||||
|
self._router_interface_action(
|
||||||
|
'add',
|
||||||
|
router_id,
|
||||||
|
int_subnet['subnet']['id'],
|
||||||
|
None)
|
||||||
|
return int_subnet
|
||||||
|
|
||||||
def test_router_no_snat_with_same_address_scope(self):
|
def test_router_no_snat_with_same_address_scope(self):
|
||||||
"""Test that if the router has no snat, you can add an interface
|
"""Test that if the router has no snat, you can add an interface
|
||||||
from the same address scope as the gateway.
|
from the same address scope as the gateway.
|
||||||
@ -3514,31 +3534,19 @@ class TestExclusiveRouterTestCase(L3NatTest, L3NatTestCaseBase,
|
|||||||
ext_subnet = self.deserialize(self.fmt, req.get_response(self.api))
|
ext_subnet = self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
|
|
||||||
# create a regular network on the same address scope
|
# create a regular network on the same address scope
|
||||||
with self.network() as net:
|
# and create a no snat router with this gateway
|
||||||
data = {'subnet': {
|
with self.router() as r:
|
||||||
'network_id': net['network']['id'],
|
self._add_external_gateway_to_router(
|
||||||
'subnetpool_id': subnetpool_id,
|
r['router']['id'],
|
||||||
'ip_version': 4,
|
ext_subnet['subnet']['network_id'])
|
||||||
'tenant_id': net['network']['tenant_id']}}
|
self._update_router_enable_snat(
|
||||||
req = self.new_create_request('subnets', data)
|
r['router']['id'],
|
||||||
int_subnet = self.deserialize(
|
ext_subnet['subnet']['network_id'],
|
||||||
self.fmt, req.get_response(self.api))
|
False)
|
||||||
|
|
||||||
# create a no snat router with this gateway
|
# should succeed adding the interface to the router
|
||||||
with self.router() as r:
|
self._create_subnet_and_add_to_router(
|
||||||
self._add_external_gateway_to_router(
|
subnetpool_id, r['router']['id'])
|
||||||
r['router']['id'],
|
|
||||||
ext_subnet['subnet']['network_id'])
|
|
||||||
self._update_router_enable_snat(
|
|
||||||
r['router']['id'],
|
|
||||||
ext_subnet['subnet']['network_id'],
|
|
||||||
False)
|
|
||||||
|
|
||||||
# should succeed adding the interface to the router
|
|
||||||
self._router_interface_action('add',
|
|
||||||
r['router']['id'],
|
|
||||||
int_subnet['subnet']['id'],
|
|
||||||
None)
|
|
||||||
|
|
||||||
def test_router_address_scope_snat_rules(self):
|
def test_router_address_scope_snat_rules(self):
|
||||||
"""Test that if the router interface had the same address scope
|
"""Test that if the router interface had the same address scope
|
||||||
@ -3564,48 +3572,37 @@ class TestExclusiveRouterTestCase(L3NatTest, L3NatTestCaseBase,
|
|||||||
ext_subnet = self.deserialize(self.fmt, req.get_response(self.api))
|
ext_subnet = self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
|
|
||||||
# create a regular network on the same address scope
|
# create a regular network on the same address scope
|
||||||
with self.network() as net:
|
# and create a router with this gateway
|
||||||
data = {'subnet': {
|
with self.router() as r:
|
||||||
'network_id': net['network']['id'],
|
self._add_external_gateway_to_router(
|
||||||
'subnetpool_id': subnetpool_id,
|
r['router']['id'],
|
||||||
'ip_version': 4,
|
ext_subnet['subnet']['network_id'])
|
||||||
'tenant_id': net['network']['tenant_id']}}
|
|
||||||
req = self.new_create_request('subnets', data)
|
|
||||||
int_subnet = self.deserialize(
|
|
||||||
self.fmt, req.get_response(self.api))
|
|
||||||
|
|
||||||
# create a router with this gateway
|
# Add the interface to the router
|
||||||
with self.router() as r:
|
with mock.patch.object(
|
||||||
self._add_external_gateway_to_router(
|
edge_utils, 'update_nat_rules') as update_nat,\
|
||||||
r['router']['id'],
|
mock.patch.object(
|
||||||
ext_subnet['subnet']['network_id'])
|
edge_utils, 'update_firewall') as update_fw:
|
||||||
|
|
||||||
# Add the interface to the router
|
int_subnet = self._create_subnet_and_add_to_router(
|
||||||
with mock.patch.object(
|
subnetpool_id, r['router']['id'])
|
||||||
edge_utils, 'update_nat_rules') as update_nat,\
|
|
||||||
mock.patch.object(
|
|
||||||
edge_utils, 'update_firewall') as update_fw:
|
|
||||||
self._router_interface_action(
|
|
||||||
'add',
|
|
||||||
r['router']['id'],
|
|
||||||
int_subnet['subnet']['id'],
|
|
||||||
None)
|
|
||||||
# make sure snat rules are not added
|
|
||||||
update_nat.assert_called_once_with(
|
|
||||||
mock.ANY, mock.ANY, r['router']['id'], [], [])
|
|
||||||
|
|
||||||
# check fw rules
|
# make sure snat rules are not added
|
||||||
fw_rules = update_fw.call_args[0][3][
|
update_nat.assert_called_once_with(
|
||||||
'firewall_rule_list']
|
mock.ANY, mock.ANY, r['router']['id'], [], [])
|
||||||
self.assertEqual(2, len(fw_rules))
|
|
||||||
self.assertEqual('Allocation Pool Rule',
|
# check fw rules
|
||||||
fw_rules[1]['name'])
|
fw_rules = update_fw.call_args[0][3][
|
||||||
self.assertEqual('allow', fw_rules[1]['action'])
|
'firewall_rule_list']
|
||||||
self.assertEqual(
|
self.assertEqual(2, len(fw_rules))
|
||||||
int_subnet['subnet']['cidr'],
|
self.assertEqual('Allocation Pool Rule',
|
||||||
fw_rules[1]['destination_ip_address'][0])
|
fw_rules[1]['name'])
|
||||||
self.assertEqual('external',
|
self.assertEqual('allow', fw_rules[1]['action'])
|
||||||
fw_rules[1]['source_vnic_groups'][0])
|
self.assertEqual(
|
||||||
|
int_subnet['subnet']['cidr'],
|
||||||
|
fw_rules[1]['destination_ip_address'][0])
|
||||||
|
self.assertEqual('external',
|
||||||
|
fw_rules[1]['source_vnic_groups'][0])
|
||||||
|
|
||||||
def test_router_address_scope_fw_rules(self):
|
def test_router_address_scope_fw_rules(self):
|
||||||
"""Test that if the router interfaces has different address scope
|
"""Test that if the router interfaces has different address scope
|
||||||
@ -3613,9 +3610,8 @@ class TestExclusiveRouterTestCase(L3NatTest, L3NatTestCaseBase,
|
|||||||
"""
|
"""
|
||||||
# create a router, networks, and address scopes
|
# create a router, networks, and address scopes
|
||||||
with self.address_scope(name='as1') as addr_scope1, \
|
with self.address_scope(name='as1') as addr_scope1, \
|
||||||
self.address_scope(name='as2') as addr_scope2,\
|
self.address_scope(name='as2') as addr_scope2, \
|
||||||
self.network() as net1, self.network() as net2,\
|
self.router() as r:
|
||||||
self.network() as net3, self.router() as r:
|
|
||||||
|
|
||||||
as1_id = addr_scope1['address_scope']['id']
|
as1_id = addr_scope1['address_scope']['id']
|
||||||
as2_id = addr_scope2['address_scope']['id']
|
as2_id = addr_scope2['address_scope']['id']
|
||||||
@ -3630,61 +3626,31 @@ class TestExclusiveRouterTestCase(L3NatTest, L3NatTestCaseBase,
|
|||||||
subnetpool_id1 = subnetpool1['subnetpool']['id']
|
subnetpool_id1 = subnetpool1['subnetpool']['id']
|
||||||
subnetpool_id2 = subnetpool2['subnetpool']['id']
|
subnetpool_id2 = subnetpool2['subnetpool']['id']
|
||||||
|
|
||||||
# create subnets on the 2 subnet pools
|
|
||||||
data = {'subnet': {
|
|
||||||
'network_id': net1['network']['id'],
|
|
||||||
'subnetpool_id': subnetpool_id1,
|
|
||||||
'ip_version': 4,
|
|
||||||
'tenant_id': net1['network']['tenant_id']}}
|
|
||||||
req = self.new_create_request('subnets', data)
|
|
||||||
subnet1 = self.deserialize(
|
|
||||||
self.fmt, req.get_response(self.api))
|
|
||||||
|
|
||||||
data = {'subnet': {
|
|
||||||
'network_id': net2['network']['id'],
|
|
||||||
'subnetpool_id': subnetpool_id2,
|
|
||||||
'ip_version': 4,
|
|
||||||
'tenant_id': net2['network']['tenant_id']}}
|
|
||||||
req = self.new_create_request('subnets', data)
|
|
||||||
subnet2 = self.deserialize(
|
|
||||||
self.fmt, req.get_response(self.api))
|
|
||||||
|
|
||||||
data = {'subnet': {
|
|
||||||
'network_id': net3['network']['id'],
|
|
||||||
'subnetpool_id': subnetpool_id2,
|
|
||||||
'ip_version': 4,
|
|
||||||
'tenant_id': net3['network']['tenant_id']}}
|
|
||||||
req = self.new_create_request('subnets', data)
|
|
||||||
subnet3 = self.deserialize(
|
|
||||||
self.fmt, req.get_response(self.api))
|
|
||||||
|
|
||||||
expected_rules = [
|
|
||||||
{'enabled': True,
|
|
||||||
'destination_ip_address': [subnet1['subnet']['cidr']],
|
|
||||||
'action': 'allow',
|
|
||||||
'name': 'Subnet Rule',
|
|
||||||
'source_ip_address': [subnet1['subnet']['cidr']]},
|
|
||||||
{'enabled': True,
|
|
||||||
'destination_ip_address': [subnet2['subnet']['cidr'],
|
|
||||||
subnet3['subnet']['cidr']],
|
|
||||||
'action': 'allow',
|
|
||||||
'name': 'Subnet Rule',
|
|
||||||
'source_ip_address': [subnet2['subnet']['cidr'],
|
|
||||||
subnet3['subnet']['cidr']]}]
|
|
||||||
|
|
||||||
# Add the interfaces to the router
|
# Add the interfaces to the router
|
||||||
with mock.patch.object(
|
with mock.patch.object(
|
||||||
edge_utils, 'update_nat_rules'),\
|
edge_utils, 'update_nat_rules'),\
|
||||||
mock.patch.object(edge_utils, 'update_firewall') as update_fw:
|
mock.patch.object(edge_utils, 'update_firewall') as update_fw:
|
||||||
self._router_interface_action(
|
# create subnets on the 2 subnet pools, and attach to router
|
||||||
'add', r['router']['id'],
|
subnet1 = self._create_subnet_and_add_to_router(
|
||||||
subnet1['subnet']['id'], None)
|
subnetpool_id1, r['router']['id'])
|
||||||
self._router_interface_action(
|
subnet2 = self._create_subnet_and_add_to_router(
|
||||||
'add', r['router']['id'],
|
subnetpool_id2, r['router']['id'])
|
||||||
subnet2['subnet']['id'], None)
|
subnet3 = self._create_subnet_and_add_to_router(
|
||||||
self._router_interface_action(
|
subnetpool_id2, r['router']['id'])
|
||||||
'add', r['router']['id'],
|
|
||||||
subnet3['subnet']['id'], None)
|
expected_rules = [
|
||||||
|
{'enabled': True,
|
||||||
|
'destination_ip_address': [subnet1['subnet']['cidr']],
|
||||||
|
'action': 'allow',
|
||||||
|
'name': 'Subnet Rule',
|
||||||
|
'source_ip_address': [subnet1['subnet']['cidr']]},
|
||||||
|
{'enabled': True,
|
||||||
|
'destination_ip_address': [subnet2['subnet']['cidr'],
|
||||||
|
subnet3['subnet']['cidr']],
|
||||||
|
'action': 'allow',
|
||||||
|
'name': 'Subnet Rule',
|
||||||
|
'source_ip_address': [subnet2['subnet']['cidr'],
|
||||||
|
subnet3['subnet']['cidr']]}]
|
||||||
|
|
||||||
# check the final fw rules
|
# check the final fw rules
|
||||||
fw_rules = update_fw.call_args[0][3][
|
fw_rules = update_fw.call_args[0][3][
|
||||||
@ -3693,6 +3659,84 @@ class TestExclusiveRouterTestCase(L3NatTest, L3NatTestCaseBase,
|
|||||||
self.assertEqual(self._recursive_sort_list(expected_rules),
|
self.assertEqual(self._recursive_sort_list(expected_rules),
|
||||||
self._recursive_sort_list(fw_rules))
|
self._recursive_sort_list(fw_rules))
|
||||||
|
|
||||||
|
def _prepare_external_subnet_on_address_scope(self,
|
||||||
|
ext_net,
|
||||||
|
address_scope):
|
||||||
|
|
||||||
|
self._set_net_external(ext_net['network']['id'])
|
||||||
|
as_id = address_scope['address_scope']['id']
|
||||||
|
subnet = netaddr.IPNetwork('10.10.10.0/21')
|
||||||
|
subnetpool = self._test_create_subnetpool(
|
||||||
|
[subnet.cidr], name='sp1',
|
||||||
|
min_prefixlen='24', address_scope_id=as_id)
|
||||||
|
subnetpool_id = subnetpool['subnetpool']['id']
|
||||||
|
data = {'subnet': {
|
||||||
|
'network_id': ext_net['network']['id'],
|
||||||
|
'subnetpool_id': subnetpool_id,
|
||||||
|
'ip_version': 4,
|
||||||
|
'enable_dhcp': False,
|
||||||
|
'tenant_id': ext_net['network']['tenant_id']}}
|
||||||
|
req = self.new_create_request('subnets', data)
|
||||||
|
ext_subnet = self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
|
return ext_subnet['subnet']
|
||||||
|
|
||||||
|
def _test_router_address_scope_change(self, change_gw=False):
|
||||||
|
"""When subnetpool address scope changes, and router that was
|
||||||
|
originally under same address scope, results having different
|
||||||
|
address scopes, relevant snat rules are added.
|
||||||
|
"""
|
||||||
|
# create an external network on one address scope
|
||||||
|
with self.address_scope(name='as1') as addr_scope, \
|
||||||
|
self.network() as ext_net:
|
||||||
|
ext_subnet = self._prepare_external_subnet_on_address_scope(
|
||||||
|
ext_net, addr_scope)
|
||||||
|
|
||||||
|
# create a router with this gateway
|
||||||
|
with self.router() as r:
|
||||||
|
self._add_external_gateway_to_router(
|
||||||
|
r['router']['id'],
|
||||||
|
ext_subnet['network_id'])
|
||||||
|
|
||||||
|
# create a regular network on same address scope
|
||||||
|
# and verify no snat change
|
||||||
|
as_id = addr_scope['address_scope']['id']
|
||||||
|
subnet2 = netaddr.IPNetwork('40.10.10.0/24')
|
||||||
|
subnetpool2 = self._test_create_subnetpool(
|
||||||
|
[subnet2.cidr], name='sp2',
|
||||||
|
min_prefixlen='24', address_scope_id=as_id)
|
||||||
|
subnetpool2_id = subnetpool2['subnetpool']['id']
|
||||||
|
|
||||||
|
self._create_subnet_and_add_to_router(
|
||||||
|
subnetpool2_id, r['router']['id'])
|
||||||
|
|
||||||
|
# change address scope of the first subnetpool
|
||||||
|
with self.address_scope(name='as2') as addr_scope2,\
|
||||||
|
mock.patch.object(edge_utils, 'update_nat_rules') as update_nat,\
|
||||||
|
mock.patch.object(edge_utils, 'update_firewall') as update_fw:
|
||||||
|
|
||||||
|
as2_id = addr_scope2['address_scope']['id']
|
||||||
|
data = {'subnetpool': {
|
||||||
|
'address_scope_id': as2_id}}
|
||||||
|
|
||||||
|
if change_gw:
|
||||||
|
subnetpool_to_update = ext_subnet['subnetpool_id']
|
||||||
|
else:
|
||||||
|
subnetpool_to_update = subnetpool2_id
|
||||||
|
|
||||||
|
req = self.new_update_request('subnetpools', data,
|
||||||
|
subnetpool_to_update)
|
||||||
|
req.get_response(self.api)
|
||||||
|
|
||||||
|
# Verify that the snat & fw rule are being updated
|
||||||
|
update_nat.assert_called_once()
|
||||||
|
update_fw.assert_called_once()
|
||||||
|
|
||||||
|
def test_router_address_scope_change(self):
|
||||||
|
self._test_router_address_scope_change()
|
||||||
|
|
||||||
|
def test_router_address_scope_gw_change(self):
|
||||||
|
self._test_router_address_scope_change(change_gw=True)
|
||||||
|
|
||||||
|
|
||||||
class ExtGwModeTestCase(NsxVPluginV2TestCase,
|
class ExtGwModeTestCase(NsxVPluginV2TestCase,
|
||||||
test_ext_gw_mode.ExtGwModeIntTestCase):
|
test_ext_gw_mode.ExtGwModeIntTestCase):
|
||||||
|
@ -1026,7 +1026,7 @@ class TestL3NatTestCase(L3NatTest,
|
|||||||
router_id,
|
router_id,
|
||||||
assert_snat_deleted=False,
|
assert_snat_deleted=False,
|
||||||
assert_snat_added=False):
|
assert_snat_added=False):
|
||||||
# create a regular network on the same address scope
|
# create a regular network on the given subnet pool
|
||||||
with self.network() as net:
|
with self.network() as net:
|
||||||
data = {'subnet': {
|
data = {'subnet': {
|
||||||
'network_id': net['network']['id'],
|
'network_id': net['network']['id'],
|
||||||
@ -1239,8 +1239,8 @@ class TestL3NatTestCase(L3NatTest,
|
|||||||
def test_3leg_router_address_scope_change(self):
|
def test_3leg_router_address_scope_change(self):
|
||||||
self._test_3leg_router_address_scope_change()
|
self._test_3leg_router_address_scope_change()
|
||||||
|
|
||||||
def test_3leg_router_address_scope_change_to_gw(self, change_2gw=True):
|
def test_3leg_router_address_scope_change_to_gw(self):
|
||||||
self._test_3leg_router_address_scope_change()
|
self._test_3leg_router_address_scope_change(change_2gw=True)
|
||||||
|
|
||||||
def test_3leg_router_gw_address_scope_change(self):
|
def test_3leg_router_gw_address_scope_change(self):
|
||||||
self._test_3leg_router_address_scope_change(change_gw=True)
|
self._test_3leg_router_address_scope_change(change_gw=True)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user