diff --git a/api/src/com/cloud/agent/api/routing/SetStaticNatRulesAnswer.java b/api/src/com/cloud/agent/api/routing/SetStaticNatRulesAnswer.java index d7942e0cf7a..f393e8d31de 100644 --- a/api/src/com/cloud/agent/api/routing/SetStaticNatRulesAnswer.java +++ b/api/src/com/cloud/agent/api/routing/SetStaticNatRulesAnswer.java @@ -25,8 +25,8 @@ public class SetStaticNatRulesAnswer extends Answer { super(); } - public SetStaticNatRulesAnswer(SetStaticNatRulesCommand cmd, String[] results) { - super(cmd, true, null); + public SetStaticNatRulesAnswer(SetStaticNatRulesCommand cmd, String[] results, Boolean success) { + super(cmd, success, null); assert(cmd.getRules().length == results.length) : "Shouldn't the results match the commands?"; this.results = results; diff --git a/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java b/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java index c0359dbb0d7..a4845989d7f 100644 --- a/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java +++ b/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java @@ -41,8 +41,8 @@ public class StaticNatRuleTO extends FirewallRuleTO{ } - protected StaticNatRuleTO(long id, String srcIp, int srcPortStart, int srcPortEnd, String dstIp, int dstPortStart, int dstPortEnd, String protocol, boolean revoked, boolean brandNew) { - super(id, srcIp, protocol, srcPortStart, srcPortEnd, revoked, brandNew, FirewallRule.Purpose.StaticNat, null,0,0); + public StaticNatRuleTO(long id, String srcIp, Integer srcPortStart, Integer srcPortEnd, String dstIp, Integer dstPortStart, Integer dstPortEnd, String protocol, boolean revoked, boolean alreadyAdded) { + super(id, srcIp, protocol, srcPortStart, srcPortEnd, revoked, alreadyAdded, FirewallRule.Purpose.StaticNat, null,0,0); this.dstIp = dstIp; } diff --git a/api/src/com/cloud/api/commands/DisableStaticNatCmd.java b/api/src/com/cloud/api/commands/DisableStaticNatCmd.java index 258cbd6b021..afc68cd7d66 100644 --- a/api/src/com/cloud/api/commands/DisableStaticNatCmd.java +++ b/api/src/com/cloud/api/commands/DisableStaticNatCmd.java @@ -76,7 +76,7 @@ public class DisableStaticNatCmd extends BaseAsyncCmd { @Override public void execute() throws ResourceUnavailableException { - boolean result = _rulesService.disableOneToOneNat(ipAddressId); + boolean result = _rulesService.disableStaticNat(ipAddressId); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); diff --git a/api/src/com/cloud/api/commands/EnableStaticNatCmd.java b/api/src/com/cloud/api/commands/EnableStaticNatCmd.java index 3b6262b8259..e8f1879e7ab 100644 --- a/api/src/com/cloud/api/commands/EnableStaticNatCmd.java +++ b/api/src/com/cloud/api/commands/EnableStaticNatCmd.java @@ -80,7 +80,7 @@ public class EnableStaticNatCmd extends BaseCmd{ @Override public void execute(){ try { - boolean result = _rulesService.enableOneToOneNat(ipAddressId, virtualMachineId); + boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/com/cloud/network/element/NetworkElement.java b/api/src/com/cloud/network/element/NetworkElement.java index c14b06db9b6..a4f42dffd9d 100644 --- a/api/src/com/cloud/network/element/NetworkElement.java +++ b/api/src/com/cloud/network/element/NetworkElement.java @@ -35,6 +35,7 @@ import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.PublicIpAddress; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.utils.component.Adapter; import com.cloud.vm.NicProfile; @@ -132,5 +133,14 @@ public interface NetworkElement extends Adapter { * @throws ResourceUnavailableException */ boolean applyRules(Network network, List rules) throws ResourceUnavailableException; + + /** + * Creates static nat rule (public IP to private IP mapping) on the network element + * @param config + * @param rules + * @return + * @throws ResourceUnavailableException + */ + boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException; } diff --git a/api/src/com/cloud/network/rules/RulesService.java b/api/src/com/cloud/network/rules/RulesService.java index 7af02a291fd..61e912ae5e0 100644 --- a/api/src/com/cloud/network/rules/RulesService.java +++ b/api/src/com/cloud/network/rules/RulesService.java @@ -54,9 +54,9 @@ public interface RulesService { boolean applyPortForwardingRules(long ipAdddressId, Account caller) throws ResourceUnavailableException; - boolean enableOneToOneNat(long ipAddressId, long vmId) throws NetworkRuleConflictException; + boolean enableStaticNat(long ipAddressId, long vmId) throws NetworkRuleConflictException; - boolean disableOneToOneNat(long ipAddressId) throws ResourceUnavailableException; + boolean disableStaticNat(long ipAddressId) throws ResourceUnavailableException; PortForwardingRule getPortForwardigRule(long ruleId); FirewallRule getFirewallRule(long ruleId); diff --git a/api/src/com/cloud/network/rules/StaticNat.java b/api/src/com/cloud/network/rules/StaticNat.java new file mode 100644 index 00000000000..430eaf42094 --- /dev/null +++ b/api/src/com/cloud/network/rules/StaticNat.java @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.network.rules; + + +public interface StaticNat{ + + long getAccountId(); + + long getDomainId(); + + long getNetworkId(); + + long getSourceIpAddressId(); + + String getDestIpAddress(); + + boolean isForRevoke(); +} diff --git a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java index f8ff6766ecb..d51ca001c1e 100755 --- a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java +++ b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java @@ -193,6 +193,7 @@ public class VirtualRoutingResource implements Manager { String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); String[] results = new String[cmd.getRules().length]; int i = 0; + boolean endResult = true; for (StaticNatRuleTO rule : cmd.getRules()) { String result = null; final Script command = new Script(_firewallPath, _timeout, s_logger); @@ -207,10 +208,15 @@ public class VirtualRoutingResource implements Manager { command.add(" -G ") ; result = command.execute(); - results[i++] = (!(result == null || result.isEmpty())) ? "Failed" : null; + if (result == null || result.isEmpty()) { + results[i++] = "Failed"; + endResult = false; + } else { + results[i++] = null; + } } - return new SetStaticNatRulesAnswer(cmd, results); + return new SetStaticNatRulesAnswer(cmd, results, endResult); } diff --git a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 0a720014021..a5fcc203484 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -1269,6 +1269,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe //String args = routerIp; String[] results = new String[cmd.getRules().length]; int i = 0; + boolean endResult = true; for (StaticNatRuleTO rule : cmd.getRules()) { //1:1 NAT needs instanceip;publicip;domrip;op StringBuilder args = new StringBuilder(); @@ -1276,15 +1277,23 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe args.append(rule.revoked() ? " -D " : " -A "); args.append(" -l ").append(rule.getSrcIp()); args.append(" -r ").append(rule.getDstIp()); - args.append(" -P ").append(rule.getProtocol().toLowerCase()); + if (rule.getProtocol() != null) { + args.append(" -P ").append(rule.getProtocol().toLowerCase()); + } + args.append(" -d ").append(rule.getStringSrcPortRange()); args.append(" -G "); String result = callHostPlugin(conn, "vmops", "setFirewallRule", "args", args.toString()); - results[i++] = (result == null || result.isEmpty()) ? "Failed" : null; + if (result == null || result.isEmpty()) { + results[i++] = "Failed"; + endResult = false; + } else { + results[i++] = null; + } } - return new SetStaticNatRulesAnswer(cmd, results); + return new SetStaticNatRulesAnswer(cmd, results, endResult); } protected Answer execute(final LoadBalancerConfigCommand cmd) { diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index c46f2b6728e..163c428cc10 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -35,6 +35,7 @@ import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.network.vpn.PasswordResetElement; import com.cloud.network.vpn.RemoteAccessVpnElement; import com.cloud.offerings.NetworkOfferingVO; @@ -210,4 +211,6 @@ public interface NetworkManager extends NetworkService { String getGlobalGuestDomainSuffix(); String getStartIpAddress(long networkId); + + boolean applyStaticNats(List staticNats, boolean continueOnError) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index e30225f3a69..3cb30dea9af 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -102,6 +102,7 @@ import com.cloud.network.guru.NetworkGuru; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.rules.FirewallManager; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.RulesManager; @@ -3190,4 +3191,29 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return startIP; } + + @Override + public boolean applyStaticNats(List staticNats, boolean continueOnError) throws ResourceUnavailableException { + if (staticNats == null || staticNats.size() == 0) { + s_logger.debug("There are no static nat rules for the network elements"); + return true; + } + + boolean success = true; + Network network = _networksDao.findById(staticNats.get(0).getNetworkId()); + for (NetworkElement ne : _networkElements) { + try { + boolean handled = ne.applyStaticNats(network, staticNats); + s_logger.debug("Static Nat for network " + network.getId() + " were " + (handled ? "" : " not") + " handled by " + ne.getName()); + } catch (ResourceUnavailableException e) { + if (!continueOnError) { + throw e; + } + s_logger.warn("Problems with " + ne.getName() + " but pushing on", e); + success = false; + } + } + + return success; + } } diff --git a/server/src/com/cloud/network/element/DhcpElement.java b/server/src/com/cloud/network/element/DhcpElement.java index 97dff205318..42efc838cad 100644 --- a/server/src/com/cloud/network/element/DhcpElement.java +++ b/server/src/com/cloud/network/element/DhcpElement.java @@ -45,6 +45,7 @@ import com.cloud.network.dao.NetworkDao; import com.cloud.network.router.VirtualNetworkApplianceManager; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.network.vpn.PasswordResetElement; import com.cloud.offering.NetworkOffering; import com.cloud.user.AccountManager; @@ -245,4 +246,9 @@ public class DhcpElement extends AdapterBase implements NetworkElement, Password return _routerMgr.savePasswordToRouter(network, nic, uservm); } + + @Override + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + return false; + } } diff --git a/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java index 63824448330..c096325814d 100644 --- a/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java +++ b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java @@ -42,6 +42,7 @@ import com.cloud.network.PublicIpAddress; import com.cloud.network.dao.NetworkDao; import com.cloud.network.lb.ElasticLoadBalancerManager; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.utils.component.AdapterBase; @@ -166,4 +167,9 @@ public class ElasticLoadBalancerElement extends AdapterBase implements NetworkEl } return true; } + + @Override + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + return false; + } } diff --git a/server/src/com/cloud/network/element/OvsElement.java b/server/src/com/cloud/network/element/OvsElement.java index ed51c0291bc..4cfe1ef50e2 100644 --- a/server/src/com/cloud/network/element/OvsElement.java +++ b/server/src/com/cloud/network/element/OvsElement.java @@ -38,6 +38,7 @@ import com.cloud.network.element.NetworkElement; import com.cloud.network.ovs.OvsNetworkManager; import com.cloud.network.ovs.OvsTunnelManager; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.Inject; @@ -142,5 +143,10 @@ public class OvsElement extends AdapterBase implements NetworkElement { throws ConcurrentOperationException, ResourceUnavailableException { return true; } + + @Override + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + return false; + } } diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index d4bfa290c99..f7fe4354b53 100644 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -49,6 +49,7 @@ import com.cloud.network.router.VirtualNetworkApplianceManager; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.RulesManager; +import com.cloud.network.rules.StaticNat; import com.cloud.network.vpn.RemoteAccessVpnElement; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -284,4 +285,21 @@ public class VirtualRouterElement extends DhcpElement implements NetworkElement, return capabilities; } + + @Override + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + DataCenter dc = _configMgr.getZone(config.getDataCenterId()); + if (canHandle(config.getGuestType(),dc)) { + long networkId = config.getId(); + List routers = _routerDao.findByNetwork(networkId); + if (routers == null || routers.isEmpty()) { + s_logger.debug("Virtual router elemnt doesn't need to apply static nat on the backend; virtual router doesn't exist in the network " + config.getId()); + return true; + } + + return _routerMgr.applyStaticNats(config, rules); + } else { + return true; + } + } } diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java index ea9712e33cb..d6105b65d79 100644 --- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -317,7 +317,6 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma throw new InvalidParameterValueException("Protocol " + proto + " is currently supported only for rules with purpose " + Purpose.Firewall); } } - } @Override @@ -516,4 +515,5 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma return rules.size() == 0; } + } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java index 2fc0902d21f..dbae1f1e4a3 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java @@ -30,6 +30,7 @@ import com.cloud.network.RemoteAccessVpn; import com.cloud.network.VirtualNetworkApplianceService; import com.cloud.network.VpnUser; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.uservm.UserVm; @@ -89,4 +90,7 @@ public interface VirtualNetworkApplianceManager extends Manager, VirtualNetworkA VirtualRouter stop(VirtualRouter router, boolean forced, User callingUser, Account callingAccount) throws ConcurrentOperationException, ResourceUnavailableException; String getDnsBasicZoneUpdate(); + + boolean applyStaticNats(Network network, List rules) throws ResourceUnavailableException; + } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index bf60675a1ee..90a40472733 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -135,6 +135,7 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.RulesManager; +import com.cloud.network.rules.StaticNat; import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.offering.NetworkOffering; @@ -2087,8 +2088,8 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian public boolean applyFirewallRules(Network network, List rules) throws ResourceUnavailableException { List routers = _routerDao.findByNetwork(network.getId()); if (routers == null || routers.isEmpty()) { - s_logger.warn("Unable to apply lb rules, virtual router doesn't exist in the network " + network.getId()); - throw new ResourceUnavailableException("Unable to apply lb rules", DataCenter.class, network.getDataCenterId()); + s_logger.warn("Unable to apply firewall rules, virtual router doesn't exist in the network " + network.getId()); + throw new ResourceUnavailableException("Unable to apply firewall rules", DataCenter.class, network.getDataCenterId()); } boolean result = true; @@ -2197,4 +2198,62 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian return _dnsBasicZoneUpdates; } + + @Override + public boolean applyStaticNats(Network network, List rules) throws ResourceUnavailableException { + List routers = _routerDao.findByNetwork(network.getId()); + if (routers == null || routers.isEmpty()) { + s_logger.warn("Unable to create static nat, virtual router doesn't exist in the network " + network.getId()); + throw new ResourceUnavailableException("Unable to create static nat", DataCenter.class, network.getDataCenterId()); + } + + boolean result = true; + for (DomainRouterVO router : routers) { + if (router.getState() == State.Running) { + s_logger.debug("Applying " + rules.size() + " static nat in network " + network); + result = applyStaticNat(router, rules); + + //If rules fail to apply on one domR, no need to proceed with the rest + if (!result) { + throw new ResourceUnavailableException("Unable to apply static nat on router ", VirtualRouter.class, router.getId()); + } + + } else if (router.getState() == State.Stopped || router.getState() == State.Stopping) { + s_logger.debug("Router is in " + router.getState() + ", so not sending apply firewall rules commands to the backend"); + } else { + s_logger.warn("Unable to apply static nat, virtual router is not in the right state " + router.getState()); + throw new ResourceUnavailableException("Unable to apply static nat, virtual router is not in the right state", VirtualRouter.class, router.getId()); + } + } + + return result; + } + + + protected boolean applyStaticNat(DomainRouterVO router, List rules) throws ResourceUnavailableException { + Commands cmds = new Commands(OnError.Continue); + createApplyStaticNatCommands(rules, router, cmds); + // Send commands to router + return sendCommandsToRouter(router, cmds); + } + + private void createApplyStaticNatCommands(List rules, DomainRouterVO router, Commands cmds) { + List rulesTO = null; + if (rules != null) { + rulesTO = new ArrayList(); + for (StaticNat rule : rules) { + IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId()); + StaticNatRuleTO ruleTO = new StaticNatRuleTO(0, sourceIp.getAddress().addr(), null, null, rule.getDestIpAddress(), null, null, null, rule.isForRevoke(), false); + rulesTO.add(ruleTO); + } + } + + SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(rulesTO); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, router.getPrivateIpAddress()); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, router.getGuestIpAddress()); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + DataCenterVO dcVo = _dcDao.findById(router.getDataCenterIdToDeployIn()); + cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); + cmds.addCommand(cmd); + } } diff --git a/server/src/com/cloud/network/rules/RulesManager.java b/server/src/com/cloud/network/rules/RulesManager.java index 8872d2c1b95..1f83b1ca320 100644 --- a/server/src/com/cloud/network/rules/RulesManager.java +++ b/server/src/com/cloud/network/rules/RulesManager.java @@ -66,6 +66,8 @@ public interface RulesManager extends RulesService { boolean releasePorts(long ipId, String protocol, FirewallRule.Purpose purpose, int... ports); List listByNetworkId(long networkId); + + boolean applyStaticNat(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke); } diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 972d7816e51..d1130dad42b 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -291,7 +291,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } @Override - public boolean enableOneToOneNat(long ipId, long vmId) throws NetworkRuleConflictException { + public boolean enableStaticNat(long ipId, long vmId) throws NetworkRuleConflictException { Account caller = UserContext.current().getCaller(); @@ -351,7 +351,22 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { ipAddress.setOneToOneNat(true); ipAddress.setAssociatedWithVmId(vmId); - return _ipAddressDao.update(ipAddress.getId(), ipAddress); + if (_ipAddressDao.update(ipAddress.getId(), ipAddress)) { + //enable static nat on the backend + s_logger.trace("Enabling static nat for ip address " + ipAddress + " and vm id=" + vmId + " on the backend"); + if (applyStaticNat(ipId, false, caller, false)) { + return true; + } else { + ipAddress.setOneToOneNat(false); + ipAddress.setAssociatedWithVmId(null); + _ipAddressDao.update(ipAddress.getId(), ipAddress); + s_logger.warn("Failed to enable static nat rule for ip address " + ipId + " on the backend"); + return false; + } + } else { + s_logger.warn("Failed to update ip address " + ipAddress + " in the DB as a part of enableStaticNat"); + return false; + } } @@ -797,10 +812,14 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { s_logger.debug("Releasing " + staticNatRules.size() + " static nat rules for ip id=" + ipId); } + for (FirewallRuleVO rule : staticNatRules) { // Mark all static nat rules as Revoke, but don't revoke them yet revokeStaticNatRuleInternal(rule.getId(), caller, userId, false); } + + //revoke static nat for the ip address + boolean staticNatRevoked = applyStaticNat(ipId, false, caller, true); // revoke all port forwarding rules applyPortForwardingRules(ipId, true, caller); @@ -816,7 +835,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { s_logger.debug("Successfully released rules for ip id=" + ipId + " and # of rules now = " + rules.size()); } - return rules.size() == 0; + return (rules.size() == 0 && staticNatRevoked); } @Override @@ -955,7 +974,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } @Override - public boolean disableOneToOneNat(long ipId) throws ResourceUnavailableException { + public boolean disableStaticNat(long ipId) throws ResourceUnavailableException { boolean success = true; Account caller = UserContext.current().getCaller(); @@ -1007,4 +1026,50 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { return new StaticNatRuleImpl(ruleVO, guestNic.getIp4Address()); } + @Override + public boolean applyStaticNat(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke) { + + List staticNats = new ArrayList(); + IpAddress sourceIp = _ipAddressDao.findById(sourceIpId); + + Long networkId = sourceIp.getAssociatedWithNetworkId(); + if (networkId == null) { + throw new CloudRuntimeException("Ip address is not associated with any network"); + } + + UserVmVO vm = _vmDao.findById(sourceIp.getAssociatedWithVmId()); + Network network = _networkMgr.getNetwork(networkId); + if (network == null) { + throw new CloudRuntimeException("Unable to find ip address to map to in vm id=" + vm.getId()); + } + + if (!sourceIp.isOneToOneNat()) { + s_logger.debug("Source ip id=" + sourceIpId + " is not one to one nat"); + return true; + } + + if (caller != null) { + _accountMgr.checkAccess(caller, sourceIp); + } + + //create new static nat rule + // Get nic IP4 address + Nic guestNic = _networkMgr.getNicInNetwork(sourceIp.getAssociatedWithVmId(), networkId); + assert (guestNic != null && guestNic.getIp4Address() != null) : "Vm doesn't belong to network associated with ipAddress or ip4 address is null...how is it possible?"; + String dstIp = guestNic.getIp4Address(); + StaticNatImpl staticNat = new StaticNatImpl(sourceIp.getAccountId(), sourceIp.getDomainId(), networkId, sourceIpId, dstIp, forRevoke); + staticNats.add(staticNat); + + try { + if (!_networkMgr.applyStaticNats(staticNats, continueOnError)) { + return false; + } + } catch (ResourceUnavailableException ex) { + s_logger.warn("Failed to create static nat rule due to ", ex); + return false; + } + + return true; + } + } diff --git a/server/src/com/cloud/network/rules/StaticNatImpl.java b/server/src/com/cloud/network/rules/StaticNatImpl.java new file mode 100644 index 00000000000..b8ebf2a002e --- /dev/null +++ b/server/src/com/cloud/network/rules/StaticNatImpl.java @@ -0,0 +1,71 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.network.rules; + +public class StaticNatImpl implements StaticNat{ + long accountId; + long domainId; + long networkId; + long sourceIpAddressId; + String destIpAddress; + boolean forRevoke; + + + + public StaticNatImpl(long accountId, long domainId, long networkId, long sourceIpAddressId, String destIpAddress, boolean forRevoke) { + super(); + this.accountId = accountId; + this.domainId = domainId; + this.networkId = networkId; + this.sourceIpAddressId = sourceIpAddressId; + this.destIpAddress = destIpAddress; + this.forRevoke = forRevoke; + } + + @Override + public long getAccountId() { + return accountId; + } + + @Override + public long getDomainId() { + return domainId; + } + + @Override + public long getNetworkId() { + return networkId; + } + + @Override + public long getSourceIpAddressId() { + return sourceIpAddressId; + } + + @Override + public String getDestIpAddress() { + return destIpAddress; + } + + @Override + public boolean isForRevoke() { + return forRevoke; + } + +} diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index a9cd7c16841..9866e252e80 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1254,7 +1254,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager IPAddressVO ip = _ipAddressDao.findByAssociatedVmId(vmId); try { if (ip != null) { - if (_rulesMgr.disableOneToOneNat(ip.getId())) { + if (_rulesMgr.disableStaticNat(ip.getId())) { s_logger.debug("Disabled 1-1 nat for ip address " + ip + " as a part of vm id=" + vmId + " expunge"); } else { s_logger.warn("Failed to disable static nat for ip address " + ip + " as a part of vm id=" + vmId + " expunge");