CLOUDSTACK-2035: Fix source NAT configuration with Cisco VNMC/ASA

Due to VNMC limitation source nat ip cannot be assigned to ASA 1000v outside interface. Working around this issue by acquiring additional public ip during network implement and assigning that to outside interface of ASA. Also made changes to ensure that source nat policy comes after pf and static nat policies in terms of evaluation by assigning a high 'order' value for it.
This commit is contained in:
Koushik Das 2013-05-10 16:35:15 +05:30
parent dfad178a9e
commit c704c90b11
2 changed files with 50 additions and 18 deletions

View File

@ -279,7 +279,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
String xml = VnmcXml.CREATE_VDC.getXml();
String service = VnmcXml.CREATE_VDC.getService();
xml = replaceXmlValue(xml, "cookie", _cookie);
xml = replaceXmlValue(xml, "descr", "VDC for Tenant" + tenantName);
xml = replaceXmlValue(xml, "descr", "VDC for Tenant " + tenantName);
xml = replaceXmlValue(xml, "name", getNameForTenantVDC(tenantName));
xml = replaceXmlValue(xml, "dn", getDnForTenantVDC(tenantName));
@ -304,7 +304,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
String xml = VnmcXml.CREATE_EDGE_DEVICE_PROFILE.getXml();
String service = VnmcXml.CREATE_EDGE_DEVICE_PROFILE.getService();
xml = replaceXmlValue(xml, "cookie", _cookie);
xml = replaceXmlValue(xml, "descr", "Edge Device Profile for Tenant VDC" + tenantName);
xml = replaceXmlValue(xml, "descr", "Edge Device Profile for Tenant VDC " + tenantName);
xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceServiceProfile(tenantName));
xml = replaceXmlValue(xml, "dn", getDnForTenantVDCEdgeDeviceProfile(tenantName));
@ -407,7 +407,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
String xml = VnmcXml.CREATE_EDGE_SECURITY_PROFILE.getXml();
String service = VnmcXml.CREATE_EDGE_SECURITY_PROFILE.getService();
xml = replaceXmlValue(xml, "cookie", _cookie);
xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName);
xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC " + tenantName);
xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName));
xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName));
xml = replaceXmlValue(xml, "egressref", "default-egress");
@ -505,7 +505,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
return createTenantVDCNatPolicyRef(
getDnForSourceNatPolicyRef(tenantName),
getNameForSourceNatPolicy(tenantName),
tenantName);
tenantName,
true);
}
@Override
@ -545,7 +546,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
String xml = VnmcXml.RESOLVE_NAT_POLICY_SET.getXml();
String service = VnmcXml.RESOLVE_NAT_POLICY_SET.getService();
xml = replaceXmlValue(xml, "cookie", _cookie);
xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName);
xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC " + tenantName);
xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName));
xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName));
xml = replaceXmlValue(xml, "natpolicysetname", getNameForNatPolicySet(tenantName));
@ -656,7 +657,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
String xml = VnmcXml.RESOLVE_ACL_POLICY_SET.getXml();
String service = VnmcXml.RESOLVE_ACL_POLICY_SET.getService();
xml = replaceXmlValue(xml, "cookie", _cookie);
xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName);
xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC " + tenantName);
xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName));
xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName));
//xml = replaceXmlValue(xml, "egresspolicysetname", getNameForAclPolicySet(tenantName, false));
@ -838,17 +839,23 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
return verifySuccess(response);
}
private boolean createTenantVDCNatPolicyRef(String policyRefDn, String name, String tenantName) throws ExecutionException {
private boolean createTenantVDCNatPolicyRef(String policyRefDn, String name, String tenantName, boolean isSourceNat) throws ExecutionException {
String xml = VnmcXml.CREATE_NAT_POLICY_REF.getXml();
String service = VnmcXml.CREATE_NAT_POLICY_REF.getService();
xml = replaceXmlValue(xml, "cookie", _cookie);
xml = replaceXmlValue(xml, "natpolicyrefdn", policyRefDn);
xml = replaceXmlValue(xml, "natpolicyname", name);
List<String> policies = listNatPolicies(tenantName);
int order = 100;
if (policies != null) {
order += policies.size();
// PF and static NAT policies need to come before source NAT, so leaving buffer
// and creating source NAT with a high order value.
// Initially tried setting MAX_INT as the order but VNMC complains about it
int order = 10000; // TODO: For now value should be sufficient, if required may need to increase
if (!isSourceNat) {
List<String> policies = listNatPolicies(tenantName);
order = 100; // order starts at 100
if (policies != null) {
order += policies.size();
}
}
xml = replaceXmlValue(xml, "order", Integer.toString(order));
@ -1062,7 +1069,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
return createTenantVDCNatPolicyRef(
getDnForPFPolicyRef(tenantName, identifier),
getNameForPFPolicy(tenantName, identifier),
tenantName);
tenantName,
false);
}
@Override
@ -1180,7 +1188,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
return createTenantVDCNatPolicyRef(
getDnForDNatPolicyRef(tenantName, identifier),
getNameForDNatPolicy(tenantName, identifier),
tenantName);
tenantName,
false);
}
@Override

View File

@ -70,6 +70,7 @@ import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.host.DetailVO;
import com.cloud.host.Host;
@ -113,6 +114,7 @@ import com.cloud.resource.ResourceStateAdapter;
import com.cloud.resource.ServerResource;
import com.cloud.resource.UnableDeleteHostException;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
@ -338,10 +340,31 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro
publicGateways.add(vlanVO.getVlanGateway());
}
// due to VNMC limitation of not allowing source NAT ip as the outside ip of firewall,
// an additional public ip needs to acquired for assigning as firewall outside ip
IpAddress outsideIp = null;
try {
Account caller = UserContext.current().getCaller();
long callerUserId = UserContext.current().getCallerUserId();
outsideIp = _networkMgr.allocateIp(owner, false, caller, callerUserId, zone);
} catch (ResourceAllocationException e) {
s_logger.error("Unable to allocate additional public Ip address. Exception details " + e);
return false;
}
try {
outsideIp = _networkMgr.associateIPToGuestNetwork(outsideIp.getId(), network.getId(), true);
} catch (ResourceAllocationException e) {
s_logger.error("Unable to assign allocated additional public Ip " + outsideIp.getAddress().addr() + " to network with vlan " + vlanId + ". Exception details " + e);
return false;
}
// create logical edge firewall in VNMC
String gatewayNetmask = NetUtils.getCidrNetmask(network.getCidr());
// due to ASA limitation of allowing single subnet to be assigned to firewall interfaces,
// all public ip addresses must be from same subnet, this essentially means single public subnet in zone
if (!createLogicalEdgeFirewall(vlanId, network.getGateway(), gatewayNetmask,
sourceNatIp.getAddress().addr(), sourceNatIp.getNetmask(), publicGateways, ciscoVnmcHost.getId())) {
outsideIp.getAddress().addr(), sourceNatIp.getNetmask(), publicGateways, ciscoVnmcHost.getId())) {
s_logger.error("Failed to create logical edge firewall in Cisco VNMC device for network " + network.getName());
return false;
}
@ -356,10 +379,10 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro
}
// configure source NAT
//if (!configureSourceNat(vlanId, network.getCidr(), sourceNatIp, ciscoVnmcHost.getId())) {
// s_logger.error("Failed to configure source NAT in Cisco VNMC device for network " + network.getName());
// return false;
//}
if (!configureSourceNat(vlanId, network.getCidr(), sourceNatIp, ciscoVnmcHost.getId())) {
s_logger.error("Failed to configure source NAT in Cisco VNMC device for network " + network.getName());
return false;
}
// associate Asa 1000v instance with logical edge firewall
if (!associateAsaWithLogicalEdgeFirewall(vlanId, assignedAsa.getManagementIp(), ciscoVnmcHost.getId())) {