Add support for per-VRF SNAT IP allocation
The edge_nat = True use case requires allocation of an SNAT IP per VRF. This patch extends the allocation scheme to support VRF-based allocation of SNAT IPs. Closes-Bug: #1592518 Change-Id: Ic601a7d16476e75e5bed5d4db2997cacb4c60454 Signed-off-by: Thomas Bachman <tbachman@yahoo.com> (cherry picked from commit2897ab1705) (cherry picked from commit9be58f4760)
This commit is contained in:
@@ -456,14 +456,22 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
||||
details = {'device': kwargs.get('device')}
|
||||
return details
|
||||
|
||||
def _allocate_snat_ip_for_host_and_ext_net(self, context, host, network,
|
||||
es_name):
|
||||
"""Allocate SNAT IP for a host for an external network."""
|
||||
def get_snat_ip_for_vrf(self, context, vrf_id, network, es_name=None):
|
||||
"""Allocate SNAT IP for a VRF for an external network."""
|
||||
# This API supports getting SNAT IPs per VRF and populating
|
||||
# the dictionary eithe rwith the network name, or the name
|
||||
# of the external segment
|
||||
if es_name is None:
|
||||
es_name = network.get('name')
|
||||
return self._allocate_snat_ip(context, vrf_id, network, es_name)
|
||||
|
||||
def _allocate_snat_ip(self, context, host_or_vrf, network, es_name):
|
||||
"""Allocate SNAT IP for a host or VRF for an external network."""
|
||||
snat_subnets = self._get_subnets(context,
|
||||
filters={'name': [HOST_SNAT_POOL],
|
||||
'network_id': [network['id']]})
|
||||
if not snat_subnets:
|
||||
LOG.info(_("Subnet for host-SNAT-pool could not be found "
|
||||
LOG.info(_("Subnet for SNAT-pool could not be found "
|
||||
"for external network %(net_id)s. SNAT will not "
|
||||
"function on this network"), {'net_id': network['id']})
|
||||
return {}
|
||||
@@ -471,14 +479,14 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
||||
snat_ports = self._get_ports(context,
|
||||
filters={'name': [HOST_SNAT_POOL_PORT],
|
||||
'network_id': [network['id']],
|
||||
'device_id': [host]})
|
||||
'device_id': [host_or_vrf]})
|
||||
snat_ip = None
|
||||
if not snat_ports:
|
||||
# Note that the following port is created for only getting
|
||||
# an IP assignment in the
|
||||
attrs = {'device_id': host,
|
||||
attrs = {'device_id': host_or_vrf,
|
||||
'device_owner': DEVICE_OWNER_SNAT_PORT,
|
||||
'binding:host_id': host,
|
||||
'binding:host_id': host_or_vrf,
|
||||
'binding:vif_type': portbindings.VIF_TYPE_UNBOUND,
|
||||
'tenant_id': network['tenant_id'],
|
||||
'name': HOST_SNAT_POOL_PORT,
|
||||
@@ -493,18 +501,21 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
||||
LOG.warning(_("SNAT-port creation failed for subnet "
|
||||
"%(subnet_id)s on external network "
|
||||
"%(net_id)s. SNAT will not function on"
|
||||
"host %(host)s for this network"),
|
||||
"host or vrf %(host_or_vrf)s for this "
|
||||
"network"),
|
||||
{'subnet_id': snat_subnets[0]['id'],
|
||||
'net_id': network['id'], 'host': host})
|
||||
'net_id': network['id'],
|
||||
'host_or_vrf': host_or_vrf})
|
||||
return {}
|
||||
elif snat_ports[0]['fixed_ips']:
|
||||
snat_ip = snat_ports[0]['fixed_ips'][0]['ip_address']
|
||||
else:
|
||||
LOG.warning(_("SNAT-port %(port)s for external network "
|
||||
"%(net)s on host %(host)s doesn't have an "
|
||||
"IP-address"),
|
||||
"%(net)s on host or VRF %(host_or_vrf)s doesn't "
|
||||
"have an IP-address"),
|
||||
{'port': snat_ports[0]['id'],
|
||||
'net': network['id'], 'host': host})
|
||||
'net': network['id'],
|
||||
'host_or_vrf': host_or_vrf})
|
||||
return {}
|
||||
|
||||
return {'external_segment_name': es_name,
|
||||
@@ -566,7 +577,7 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
||||
ext_net_id)
|
||||
if host:
|
||||
host_snat_ip_allocation = (
|
||||
self._allocate_snat_ip_for_host_and_ext_net(
|
||||
self._allocate_snat_ip(
|
||||
context._plugin_context, host, ext_network,
|
||||
es['name']))
|
||||
if host_snat_ip_allocation:
|
||||
|
||||
@@ -451,6 +451,67 @@ class TestPolicyTarget(ApicMappingTestCase):
|
||||
mapping['host_snat_ips'][0]['host_snat_ip'])
|
||||
self.assertEqual(24, mapping['host_snat_ips'][0]['prefixlen'])
|
||||
|
||||
def test_get_snat_ip_for_vrf(self):
|
||||
TEST_VRF1 = 'testvrf1'
|
||||
TEST_VRF2 = 'testvrf2'
|
||||
self._mock_external_dict([('supported', '192.168.0.2/24')])
|
||||
self.driver.apic_manager.ext_net_dict[
|
||||
'supported']['host_pool_cidr'] = '192.168.200.1/24'
|
||||
es = self.create_external_segment(name='supported',
|
||||
cidr='192.168.0.2/24',
|
||||
expected_res_status=201, shared=False)['external_segment']
|
||||
self.create_nat_pool(external_segment_id=es['id'],
|
||||
ip_pool='20.20.20.0/24')
|
||||
l3p = self.create_l3_policy(name='myl3',
|
||||
external_segments={es['id']: ['']})['l3_policy']
|
||||
l2p = self.create_l2_policy(name='myl2',
|
||||
l3_policy_id=l3p['id'])['l2_policy']
|
||||
nsp = self.create_network_service_policy(
|
||||
network_service_params=[
|
||||
{"type": "ip_pool", "value": "nat_pool", "name": "test"}])[
|
||||
'network_service_policy']
|
||||
ptg = self.create_policy_target_group(
|
||||
name="ptg1", l2_policy_id=l2p['id'],
|
||||
network_service_policy_id=nsp['id'])['policy_target_group']
|
||||
pt1 = self.create_policy_target(
|
||||
policy_target_group_id=ptg['id'])['policy_target']
|
||||
self._bind_port_to_host(pt1['port_id'], 'h1')
|
||||
|
||||
subnet = self._db_plugin.get_subnet(context.get_admin_context(),
|
||||
es['subnet_id'])
|
||||
network = self._db_plugin.get_network(context.get_admin_context(),
|
||||
subnet['network_id'])
|
||||
details = self.driver.get_snat_ip_for_vrf(context.get_admin_context(),
|
||||
TEST_VRF1, network, es_name=es['name'])
|
||||
self.assertEqual(es['name'],
|
||||
details['external_segment_name'])
|
||||
self.assertEqual("192.168.200.1",
|
||||
details['gateway_ip'])
|
||||
self.assertEqual("192.168.200.2",
|
||||
details['host_snat_ip'])
|
||||
self.assertEqual(24, details['prefixlen'])
|
||||
|
||||
# Verify that the same VRF returns the same SNAT IP
|
||||
details2 = self.driver.get_snat_ip_for_vrf(context.get_admin_context(),
|
||||
TEST_VRF1, network, es_name=es['name'])
|
||||
self.assertEqual(details, details2)
|
||||
|
||||
# Create event on a second VRF to verify that the SNAT
|
||||
# port gets created for this second VRF
|
||||
pt2 = self.create_policy_target(
|
||||
policy_target_group_id=ptg['id'])['policy_target']
|
||||
self._bind_port_to_host(pt2['port_id'], 'h1')
|
||||
|
||||
details = self.driver.get_snat_ip_for_vrf(context.get_admin_context(),
|
||||
TEST_VRF2, network, es_name = es['name'])
|
||||
self.assertEqual(es['name'],
|
||||
details['external_segment_name'])
|
||||
self.assertEqual("192.168.200.1",
|
||||
details['gateway_ip'])
|
||||
self.assertEqual("192.168.200.3",
|
||||
details['host_snat_ip'])
|
||||
self.assertEqual(24, details['prefixlen'])
|
||||
|
||||
def test_snat_pool_subnet_deletion(self):
|
||||
self._mock_external_dict([('supported', '192.168.0.2/24')])
|
||||
self.driver.apic_manager.ext_net_dict[
|
||||
|
||||
Reference in New Issue
Block a user