From a8b617c596b043be84bfcd001a5e0049a5a436a1 Mon Sep 17 00:00:00 2001 From: Alex Huang Date: Fri, 3 Dec 2010 08:47:29 -0800 Subject: [PATCH] port forwarding is now in --- api/src/com/cloud/network/NetworkService.java | 12 +- .../cloud/network/element/NetworkElement.java | 56 ++++++ .../com/cloud/network/NetworkManagerImpl.java | 175 ++++++++---------- .../cloud/network/dao/IPAddressDaoImpl.java | 9 +- .../network/element/DomainRouterElement.java | 14 ++ .../com/cloud/network/rules/RulesManager.java | 3 + .../cloud/network/rules/RulesManagerImpl.java | 58 +++++- 7 files changed, 215 insertions(+), 112 deletions(-) diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 249dcc7fe64..4d7357b4b69 100644 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -47,26 +47,26 @@ public interface NetworkService { * @throws ResourceAllocationException, InsufficientCapacityException */ IpAddress associateIP(AssociateIPAddrCmd cmd) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException; - public boolean disassociateIpAddress(DisassociateIPAddrCmd cmd); + boolean disassociateIpAddress(DisassociateIPAddrCmd cmd); /** - * Create a remote access vpn from the given public ip address and client ip range + * Create a remote access vpn from the given ip address and client ip range * @param cmd the command specifying the ip address, ip range * @return the newly created RemoteAccessVpnVO if successful, null otherwise * @throws InvalidParameterValueException * @throws PermissionDeniedException * @throws ConcurrentOperationException */ - public RemoteAccessVpn createRemoteAccessVpn(CreateRemoteAccessVpnCmd cmd) throws ConcurrentOperationException, InvalidParameterValueException, PermissionDeniedException; + RemoteAccessVpn createRemoteAccessVpn(CreateRemoteAccessVpnCmd cmd) throws ConcurrentOperationException, InvalidParameterValueException, PermissionDeniedException; /** - * Start a remote access vpn for the given public ip address and client ip range + * Start a remote access vpn for the given ip address and client ip range * @param cmd the command specifying the ip address, ip range * @return the RemoteAccessVpnVO if successful, null otherwise * @throws ConcurrentOperationException * @throws ResourceUnavailableException */ - public RemoteAccessVpn startRemoteAccessVpn(CreateRemoteAccessVpnCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException; + RemoteAccessVpn startRemoteAccessVpn(CreateRemoteAccessVpnCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException; /** * Destroy a previously created remote access VPN @@ -74,7 +74,7 @@ public interface NetworkService { * @return success if successful, false otherwise * @throws ConcurrentOperationException */ - public boolean destroyRemoteAccessVpn(DeleteRemoteAccessVpnCmd cmd) throws ConcurrentOperationException; + boolean destroyRemoteAccessVpn(DeleteRemoteAccessVpnCmd cmd) throws ConcurrentOperationException; VpnUser addVpnUser(AddVpnUserCmd cmd) throws ConcurrentOperationException, AccountLimitException; diff --git a/api/src/com/cloud/network/element/NetworkElement.java b/api/src/com/cloud/network/element/NetworkElement.java index cabdd12424c..fb620a7babf 100644 --- a/api/src/com/cloud/network/element/NetworkElement.java +++ b/api/src/com/cloud/network/element/NetworkElement.java @@ -14,6 +14,7 @@ import com.cloud.network.Network; import com.cloud.network.rules.FirewallRule; import com.cloud.offering.NetworkOffering; import com.cloud.utils.component.Adapter; +import com.cloud.utils.net.Ip; import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachine; @@ -31,11 +32,66 @@ public interface NetworkElement extends Adapter { */ boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException; + /** + * Prepare for a nic to be added into this network. + * @param network + * @param nic + * @param vm + * @param dest + * @param context + * @return + * @throws ConcurrentOperationException + * @throws ResourceUnavailableException + * @throws InsufficientNetworkCapacityException + */ boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientNetworkCapacityException; + /** + * A nic is released from this network. + * @param network + * @param nic + * @param vm + * @param context + * @return + * @throws ConcurrentOperationException + * @throws ResourceUnavailableException + */ boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException; + /** + * The network is being shutdown. + * @param network + * @param context + * @return + * @throws ConcurrentOperationException + * @throws ResourceUnavailableException + */ boolean shutdown(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException; + + /** + * Associate a new ip address to this network + * @param network + * @param ipAddress + * @return + * @throws ResourceUnavailableException + */ + boolean associate(Network network, Ip ipAddress) throws ResourceUnavailableException; + + /** + * Disassociate the ip address from this network + * @param network + * @param ipAddress + * @return + * @throws ResourceUnavailableException + */ + boolean disassociate(Network network, Ip ipAddress) throws ResourceUnavailableException; + /** + * Apply rules + * @param network + * @param rules + * @return + * @throws ResourceUnavailableException + */ boolean applyRules(Network network, List rules) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 011e6c032d3..0c363ff33c6 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -101,9 +101,11 @@ import com.cloud.network.dao.NetworkRuleConfigDao; import com.cloud.network.dao.RemoteAccessVpnDao; import com.cloud.network.dao.VpnUserDao; import com.cloud.network.element.NetworkElement; +import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.router.DomainRouterManager; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.RulesManager; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.GuestIpType; import com.cloud.offerings.NetworkOfferingVO; @@ -202,6 +204,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Inject RemoteAccessVpnDao _remoteAccessVpnDao = null; @Inject VpnUserDao _vpnUsersDao = null; @Inject DomainRouterManager _routerMgr; + @Inject RulesManager _rulesMgr; + @Inject LoadBalancingRulesManager _lbMgr; @Inject(adapter=NetworkGuru.class) Adapters _networkGurus; @@ -215,6 +219,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag SearchBuilder AccountsUsingNetworkConfigurationSearch; private Map _configs; + @Override public boolean sendSshKeysToHost(Long hostId, String pubKey, String prvKey) { @@ -805,78 +810,81 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return answers[0].getResult(); } - @Override @DB + @DB + protected IPAddressVO releaseOwnershipOfIpAddress(String ipAddress) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + IPAddressVO ip = _ipAddressDao.lockRow(ipAddress, true); + if (ip == null) { + s_logger.warn("Unable to find allocated ip: " + ipAddress); + return null; + } + + if (ip.getAllocated() == null) { + s_logger.debug("Ip Address is already rleeased: " + ipAddress); + return null; + } + + ip.setAccountId(null); + ip.setDomainId(null); + _ipAddressDao.update(ip.getAddress(), ip); + txn.commit(); + return ip; + } + + @Override public boolean releasePublicIpAddress(long userId, final String ipAddress) { - return false; // FIXME -// IPAddressVO ip = null; -// try { -// ip = _ipAddressDao.acquireInLockTable(ipAddress); -// -// if (ip == null) { -// s_logger.warn("Unable to find allocated ip: " + ipAddress); -// return false; -// } -// -// if(s_logger.isDebugEnabled()) { -// s_logger.debug("lock on ip " + ipAddress + " is acquired"); -// } -// -// if (ip.getAllocated() == null) { -// s_logger.warn("ip: " + ipAddress + " is already released"); -// return false; -// } -// -// if (s_logger.isDebugEnabled()) { -// s_logger.debug("Releasing ip " + ipAddress + "; sourceNat = " + ip.isSourceNat()); -// } -// -// -// final List ipAddrs = new ArrayList(); -// ipAddrs.add(ip.getAddress()); -// final List firewallRules = _rulesDao.listIPForwardingForUpdate(ipAddress); -// -// if (s_logger.isDebugEnabled()) { -// s_logger.debug("Found firewall rules: " + firewallRules.size()); -// } -// -// for (final PortForwardingRuleVO fw: firewallRules) { -// fw.setEnabled(false); -// } -// -// DomainRouterVO router = null; -// if (ip.isSourceNat()) { -// router = _routerMgr.getRouter(ipAddress); -// if (router != null) { -// if (router.getPublicIpAddress() != null) { -// return false; -// } -// } -// } else { -// router = _routerMgr.getRouter(ip.getAccountId(), ip.getDataCenterId()); -// } -// -// // Now send the updates down to the domR (note: we still hold locks on address and firewall) -// updateFirewallRules(ipAddress, firewallRules, router); -// -// for (final PortForwardingRuleVO rule: firewallRules) { -// _rulesDao.remove(rule.getId()); -// -// // Save and create the event -// String ruleName = (rule.isForwarding() ? "ip forwarding" : "load balancer"); -// String description = "deleted " + ruleName + " rule [" + rule.getSourceIpAddress() + ":" + rule.getSourcePort() -// + "]->[" + rule.getDestinationIpAddress() + ":" + rule.getDestinationPort() + "]" + " " -// + rule.getProtocol(); -// -// // save off an event for removing the network rule -// EventVO event = new EventVO(); -// event.setUserId(userId); -// event.setAccountId(ip.getAccountId()); -// event.setType(EventTypes.EVENT_NET_RULE_DELETE); -// event.setDescription(description); -// event.setLevel(EventVO.LEVEL_INFO); -// _eventDao.persist(event); -// } -// + IPAddressVO ip = releaseOwnershipOfIpAddress(ipAddress); + if (ip == null) { + return true; + } + + Ip addr = new Ip(ipAddress); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Releasing ip " + ipAddress + "; sourceNat = " + ip.isSourceNat()); + } + + boolean success = true; + try { + if (!_rulesMgr.revokeAllRules(addr, userId)) { + s_logger.warn("Unable to revoke all the port forwarding rules for ip " + ip); + success = false; + } + } catch (ResourceUnavailableException e) { + s_logger.warn("Unable to revoke all the port forwarding rules for ip " + ip, e); + success = false; + } + + if (!_lbMgr.removeAllLoadBalanacers(addr)) { + s_logger.warn("Unable to revoke all the load balancer rules for ip " + ip); + success = false; + } + + for (NetworkElement ne : _networkElements) { + try { + ne.disassociate(null, new Ip(ipAddress)); + } catch (ResourceUnavailableException e) { + s_logger.warn("Unable to release the ip address " + ip, e); + success = false; + } + } + + if (success) { + _ipAddressDao.unassignIpAddress(ipAddress); + s_logger.debug("released a public ip: " + ipAddress); + } + + final EventVO event = new EventVO(); + event.setUserId(userId); + event.setAccountId(ip.getAccountId()); + event.setType(EventTypes.EVENT_NET_IP_RELEASE); + event.setParameters("address=" + ipAddress + "\nsourceNat="+ip.isSourceNat()); + event.setDescription("released a public ip: " + ipAddress); + _eventDao.persist(event); + + return success; + // List loadBalancers = _loadBalancerDao.listByIpAddress(ipAddress); // for (LoadBalancerVO loadBalancer : loadBalancers) { // _loadBalancerDao.remove(loadBalancer.getId()); @@ -892,7 +900,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag // event.setLevel(EventVO.LEVEL_INFO); // _eventDao.persist(event); // } -// + // if ((router != null) && (router.getState() == State.Running)) { // if (s_logger.isDebugEnabled()) { // s_logger.debug("Disassociate ip " + router.getHostName()); @@ -917,29 +925,6 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag // return false; // } // } else { -// _ipAddressDao.unassignIpAddress(ipAddress); -// } -// s_logger.debug("released a public ip: " + ipAddress); -// final EventVO event = new EventVO(); -// event.setUserId(userId); -// event.setAccountId(ip.getAccountId()); -// event.setType(EventTypes.EVENT_NET_IP_RELEASE); -// event.setParameters("address=" + ipAddress + "\nsourceNat="+ip.isSourceNat()); -// event.setDescription("released a public ip: " + ipAddress); -// _eventDao.persist(event); -// -// return true; -// } catch (final Throwable e) { -// s_logger.warn("ManagementServer error", e); -// return false; -// } finally { -// if(ip != null) { -// if(s_logger.isDebugEnabled()) { -// s_logger.debug("Releasing lock on ip " + ipAddress); -// } -// _ipAddressDao.releaseFromLockTable(ipAddress); -// } -// } } @Override diff --git a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java index 3c85cc6dc00..01ae7a8a408 100644 --- a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -61,6 +61,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implem AccountSearch.done(); } + @Override public boolean mark(long dcId, String ip) { SearchCriteria sc = DcIpSearch.create(); sc.setParameters("dataCenterId", dcId); @@ -72,6 +73,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implem return update(vo, sc) >= 1; } + @Override @DB public List assignAcccountSpecificIps(long accountId, long domainId, Long vlanDbId, boolean sourceNat) { @@ -110,6 +112,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implem return null; } + @Override public void setIpAsSourceNat(String ipAddr){ IPAddressVO ip = createForUpdate(ipAddr); @@ -158,7 +161,8 @@ public class IPAddressDaoImpl extends GenericDaoBase implem address.setAccountId(null); address.setDomainId(null); address.setAllocated(null); - address.setSourceNat(false); + address.setSourceNat(false); + address.setOneToOneNat(false); update(ipAddress, address); } @@ -176,7 +180,8 @@ public class IPAddressDaoImpl extends GenericDaoBase implem return listIncludingRemovedBy(sc); } - public List listByDcIdIpAddress(long dcId, String ipAddress) { + @Override + public List listByDcIdIpAddress(long dcId, String ipAddress) { SearchCriteria sc = DcIpSearch.create(); sc.setParameters("dataCenterId", dcId); sc.setParameters("ipAddress", ipAddress); diff --git a/server/src/com/cloud/network/element/DomainRouterElement.java b/server/src/com/cloud/network/element/DomainRouterElement.java index 1e7197f679c..85714a8f6e1 100644 --- a/server/src/com/cloud/network/element/DomainRouterElement.java +++ b/server/src/com/cloud/network/element/DomainRouterElement.java @@ -39,6 +39,7 @@ import com.cloud.offering.NetworkOffering.GuestIpType; import com.cloud.uservm.UserVm; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.Inject; +import com.cloud.utils.net.Ip; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; @@ -123,6 +124,19 @@ public class DomainRouterElement extends AdapterBase implements NetworkElement { @Override public boolean applyRules(Network config, List rules) throws ResourceUnavailableException { + + return false; + } + + @Override + public boolean associate(Network network, Ip ipAddress) throws ResourceUnavailableException { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean disassociate(Network network, Ip ipAddress) throws ResourceUnavailableException { + // TODO Auto-generated method stub return false; } } diff --git a/server/src/com/cloud/network/rules/RulesManager.java b/server/src/com/cloud/network/rules/RulesManager.java index e0917837358..f275e7ffe4b 100644 --- a/server/src/com/cloud/network/rules/RulesManager.java +++ b/server/src/com/cloud/network/rules/RulesManager.java @@ -20,6 +20,7 @@ package com.cloud.network.rules; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.IpAddress; import com.cloud.user.Account; import com.cloud.uservm.UserVm; @@ -54,4 +55,6 @@ public interface RulesManager extends RulesService { void detectRulesConflict(FirewallRule newRule, IpAddress ipAddress) throws NetworkRuleConflictException; void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller) throws InvalidParameterValueException, PermissionDeniedException; + + boolean revokeAllRules(Ip ip, long userId) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index b1f72c8dfd0..dced749ee22 100644 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -29,6 +29,7 @@ import com.cloud.api.commands.ListPortForwardingRulesCmd; import com.cloud.event.EventTypes; import com.cloud.event.EventUtils; import com.cloud.event.EventVO; +import com.cloud.event.dao.EventDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.PermissionDeniedException; @@ -39,6 +40,7 @@ import com.cloud.network.Network; import com.cloud.network.NetworkManager; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.State; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.offering.NetworkOffering.GuestIpType; @@ -69,6 +71,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { @Inject UserVmDao _vmDao; @Inject AccountManager _accountMgr; @Inject NetworkManager _networkMgr; + @Inject EventDao _eventDao; @Override public void detectRulesConflict(FirewallRule newRule, IpAddress ipAddress) throws NetworkRuleConflictException { @@ -264,8 +267,10 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } @DB - protected void revokeRule(FirewallRuleVO rule, Account caller) { - _accountMgr.checkAccess(caller, rule); + protected void revokeRule(FirewallRuleVO rule, Account caller, long userId) { + if (caller != null) { + _accountMgr.checkAccess(caller, rule); + } Transaction txn = Transaction.currentTxn(); txn.start(); @@ -286,6 +291,24 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { ipAddress.setOneToOneNat(false); _ipAddressDao.update(ipAddress.getAddress(), ipAddress); } + + // Save and create the event + String ruleName = rule.getPurpose() == Purpose.Firewall ? "Firewall" : (rule.getProtocol().equals(NetUtils.NAT_PROTO) ? "ip forwarding" : "port forwarding"); + StringBuilder description = new StringBuilder("deleted ").append(ruleName).append(" rule [").append(rule.getSourceIpAddress()).append(":").append(rule.getSourcePortStart()).append("-").append(rule.getSourcePortEnd()).append("]"); + if (rule.getPurpose() == Purpose.PortForwarding) { + PortForwardingRuleVO pfRule = (PortForwardingRuleVO)rule; + description.append("->[").append(pfRule.getDestinationIpAddress()).append(":").append(pfRule.getDestinationPortStart()).append("-").append(pfRule.getDestinationPortEnd()).append("]"); + } + description.append(" ").append(rule.getProtocol()); + + // save off an event for removing the network rule + EventVO event = new EventVO(); + event.setUserId(userId); + event.setAccountId(rule.getAccountId()); + event.setType(EventTypes.EVENT_NET_RULE_DELETE); + event.setDescription(description.toString()); + event.setLevel(EventVO.LEVEL_INFO); + _eventDao.persist(event); } @Override @@ -299,13 +322,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } _accountMgr.checkAccess(caller, rule); - revokeRule(rule, caller); - String description; - String type = EventTypes.EVENT_NET_RULE_DELETE; - String level = EventVO.LEVEL_INFO; - - description = "deleted ip forwarding rule [" + rule.getSourceIpAddress() + ":" + rule.getSourcePortStart() + "]->[" + rule.getDestinationIpAddress() + ":" + rule.getDestinationPortStart() + "] " + rule.getProtocol(); - EventUtils.saveEvent(ctx.getUserId(), rule.getAccountId(), level, type, description); + revokeRule(rule, caller, ctx.getUserId()); if (apply) { applyPortForwardingRules(rule.getSourceIpAddress(), true); @@ -379,6 +396,29 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { public boolean applyPortForwardingRules(Ip ip, Account caller) throws ResourceUnavailableException { return applyPortForwardingRules(ip, false, caller); } + + @Override @DB + public boolean revokeAllRules(Ip ip, long userId) throws ResourceUnavailableException { + List rules = _forwardingDao.listByIpAndNotRevoked(ip); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Releasing " + rules.size() + " rules for " + ip); + } + + for (PortForwardingRuleVO rule : rules) { + revokeRule(rule, null, userId); + } + + applyPortForwardingRules(ip, true, null); + + // Now we check again in case more rules have been inserted. + rules = _forwardingDao.listByIpAndNotRevoked(ip); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Successfully released rules for " + ip + " and # of rules now = " + rules.size()); + } + + return rules.size() == 0; + } @Override public boolean configure(String name, Map params) throws ConfigurationException {