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 xml = VnmcXml.CREATE_VDC.getXml();
String service = VnmcXml.CREATE_VDC.getService(); String service = VnmcXml.CREATE_VDC.getService();
xml = replaceXmlValue(xml, "cookie", _cookie); 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, "name", getNameForTenantVDC(tenantName));
xml = replaceXmlValue(xml, "dn", getDnForTenantVDC(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 xml = VnmcXml.CREATE_EDGE_DEVICE_PROFILE.getXml();
String service = VnmcXml.CREATE_EDGE_DEVICE_PROFILE.getService(); String service = VnmcXml.CREATE_EDGE_DEVICE_PROFILE.getService();
xml = replaceXmlValue(xml, "cookie", _cookie); 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, "name", getNameForEdgeDeviceServiceProfile(tenantName));
xml = replaceXmlValue(xml, "dn", getDnForTenantVDCEdgeDeviceProfile(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 xml = VnmcXml.CREATE_EDGE_SECURITY_PROFILE.getXml();
String service = VnmcXml.CREATE_EDGE_SECURITY_PROFILE.getService(); String service = VnmcXml.CREATE_EDGE_SECURITY_PROFILE.getService();
xml = replaceXmlValue(xml, "cookie", _cookie); 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, "name", getNameForEdgeDeviceSecurityProfile(tenantName));
xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName));
xml = replaceXmlValue(xml, "egressref", "default-egress"); xml = replaceXmlValue(xml, "egressref", "default-egress");
@ -505,7 +505,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
return createTenantVDCNatPolicyRef( return createTenantVDCNatPolicyRef(
getDnForSourceNatPolicyRef(tenantName), getDnForSourceNatPolicyRef(tenantName),
getNameForSourceNatPolicy(tenantName), getNameForSourceNatPolicy(tenantName),
tenantName); tenantName,
true);
} }
@Override @Override
@ -545,7 +546,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
String xml = VnmcXml.RESOLVE_NAT_POLICY_SET.getXml(); String xml = VnmcXml.RESOLVE_NAT_POLICY_SET.getXml();
String service = VnmcXml.RESOLVE_NAT_POLICY_SET.getService(); String service = VnmcXml.RESOLVE_NAT_POLICY_SET.getService();
xml = replaceXmlValue(xml, "cookie", _cookie); 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, "name", getNameForEdgeDeviceSecurityProfile(tenantName));
xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName));
xml = replaceXmlValue(xml, "natpolicysetname", getNameForNatPolicySet(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 xml = VnmcXml.RESOLVE_ACL_POLICY_SET.getXml();
String service = VnmcXml.RESOLVE_ACL_POLICY_SET.getService(); String service = VnmcXml.RESOLVE_ACL_POLICY_SET.getService();
xml = replaceXmlValue(xml, "cookie", _cookie); 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, "name", getNameForEdgeDeviceSecurityProfile(tenantName));
xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName));
//xml = replaceXmlValue(xml, "egresspolicysetname", getNameForAclPolicySet(tenantName, false)); //xml = replaceXmlValue(xml, "egresspolicysetname", getNameForAclPolicySet(tenantName, false));
@ -838,18 +839,24 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
return verifySuccess(response); 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 xml = VnmcXml.CREATE_NAT_POLICY_REF.getXml();
String service = VnmcXml.CREATE_NAT_POLICY_REF.getService(); String service = VnmcXml.CREATE_NAT_POLICY_REF.getService();
xml = replaceXmlValue(xml, "cookie", _cookie); xml = replaceXmlValue(xml, "cookie", _cookie);
xml = replaceXmlValue(xml, "natpolicyrefdn", policyRefDn); xml = replaceXmlValue(xml, "natpolicyrefdn", policyRefDn);
xml = replaceXmlValue(xml, "natpolicyname", name); xml = replaceXmlValue(xml, "natpolicyname", name);
// 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); List<String> policies = listNatPolicies(tenantName);
int order = 100; order = 100; // order starts at 100
if (policies != null) { if (policies != null) {
order += policies.size(); order += policies.size();
} }
}
xml = replaceXmlValue(xml, "order", Integer.toString(order)); xml = replaceXmlValue(xml, "order", Integer.toString(order));
String response = sendRequest(service, xml); String response = sendRequest(service, xml);
@ -1062,7 +1069,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
return createTenantVDCNatPolicyRef( return createTenantVDCNatPolicyRef(
getDnForPFPolicyRef(tenantName, identifier), getDnForPFPolicyRef(tenantName, identifier),
getNameForPFPolicy(tenantName, identifier), getNameForPFPolicy(tenantName, identifier),
tenantName); tenantName,
false);
} }
@Override @Override
@ -1180,7 +1188,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection {
return createTenantVDCNatPolicyRef( return createTenantVDCNatPolicyRef(
getDnForDNatPolicyRef(tenantName, identifier), getDnForDNatPolicyRef(tenantName, identifier),
getNameForDNatPolicy(tenantName, identifier), getNameForDNatPolicy(tenantName, identifier),
tenantName); tenantName,
false);
} }
@Override @Override

View File

@ -70,6 +70,7 @@ import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.host.DetailVO; import com.cloud.host.DetailVO;
import com.cloud.host.Host; import com.cloud.host.Host;
@ -113,6 +114,7 @@ import com.cloud.resource.ResourceStateAdapter;
import com.cloud.resource.ServerResource; import com.cloud.resource.ServerResource;
import com.cloud.resource.UnableDeleteHostException; import com.cloud.resource.UnableDeleteHostException;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.db.Transaction; import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
@ -338,10 +340,31 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro
publicGateways.add(vlanVO.getVlanGateway()); 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 // create logical edge firewall in VNMC
String gatewayNetmask = NetUtils.getCidrNetmask(network.getCidr()); 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, 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()); s_logger.error("Failed to create logical edge firewall in Cisco VNMC device for network " + network.getName());
return false; return false;
} }
@ -356,10 +379,10 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro
} }
// configure source NAT // configure source NAT
//if (!configureSourceNat(vlanId, network.getCidr(), sourceNatIp, ciscoVnmcHost.getId())) { if (!configureSourceNat(vlanId, network.getCidr(), sourceNatIp, ciscoVnmcHost.getId())) {
// s_logger.error("Failed to configure source NAT in Cisco VNMC device for network " + network.getName()); s_logger.error("Failed to configure source NAT in Cisco VNMC device for network " + network.getName());
// return false; return false;
//} }
// associate Asa 1000v instance with logical edge firewall // associate Asa 1000v instance with logical edge firewall
if (!associateAsaWithLogicalEdgeFirewall(vlanId, assignedAsa.getManagementIp(), ciscoVnmcHost.getId())) { if (!associateAsaWithLogicalEdgeFirewall(vlanId, assignedAsa.getManagementIp(), ciscoVnmcHost.getId())) {