diff --git a/core/src/com/cloud/network/IPAddressVO.java b/core/src/com/cloud/network/IPAddressVO.java index 39527f6e5b8..c55764a2a0c 100644 --- a/core/src/com/cloud/network/IPAddressVO.java +++ b/core/src/com/cloud/network/IPAddressVO.java @@ -58,7 +58,10 @@ public class IPAddressVO { @Column(name="vlan_db_id") private long vlanDbId; - + + @Column(name="one_to_one_nat") + private boolean oneToOneNat; + protected IPAddressVO() { } @@ -115,6 +118,14 @@ public class IPAddressVO { public void setVlanDbId(long vlanDbId) { this.vlanDbId = vlanDbId; + } + + public boolean isOneToOneNat() { + return oneToOneNat; + } + + public void setOneToOneNat(boolean oneToOneNat) { + this.oneToOneNat = oneToOneNat; } } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index e1ec0773218..dfd6962e7d3 100644 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -736,7 +736,8 @@ public class ApiResponseHelper { } ipResponse.setForVirtualNetwork(forVirtualNetworks); - + ipResponse.setOneToOneNat(ipAddress.isOneToOneNat()); + //show this info to admin only Account account = UserContext.current().getAccount(); if ((account == null) || account.getType() == Account.ACCOUNT_TYPE_ADMIN) { diff --git a/server/src/com/cloud/api/response/IPAddressResponse.java b/server/src/com/cloud/api/response/IPAddressResponse.java index dc780f89559..92fdc714530 100644 --- a/server/src/com/cloud/api/response/IPAddressResponse.java +++ b/server/src/com/cloud/api/response/IPAddressResponse.java @@ -56,6 +56,9 @@ public class IPAddressResponse extends BaseResponse { @SerializedName("vlanname") @Param(description="the VLAN associated with the IP address") private String vlanName; + @SerializedName("onetoonenat") @Param(description="whether this ip is for one-to-one nat") + private Boolean oneToOneNat; + public String getIpAddress() { return ipAddress; } @@ -143,4 +146,12 @@ public class IPAddressResponse extends BaseResponse { public void setVlanName(String vlanName) { this.vlanName = vlanName; } + + public Boolean getOneToOneNat() { + return oneToOneNat; + } + + public void setOneToOneNat(Boolean oneToOneNat) { + this.oneToOneNat = oneToOneNat; + } } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index df00b541e6b..fcc4d0e5b28 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -2934,53 +2934,76 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return mac; } - @Override + @Override @DB public NetworkConfiguration getNetworkConfiguration(long id) { return _networkConfigDao.findById(id); } - @Override + @Override @DB public FirewallRuleVO createIpForwardingRuleOnDomr(Long ruleId) throws ServerApiException{ + Transaction txn = Transaction.currentTxn(); + txn.start(); boolean success = false; - //get the rule - FirewallRuleVO rule = _rulesDao.findById(ruleId); + FirewallRuleVO rule = null; + IPAddressVO ipAddress = null; + boolean locked = false; + try { + //get the rule + rule = _rulesDao.findById(ruleId); + + if(rule == null){ + throw new PermissionDeniedException("Cannot create ip forwarding rule in db"); + } + + //get ip address + ipAddress = _ipAddressDao.findById(rule.getPublicIpAddress()); + if (ipAddress == null) { + throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid IP address specified."); + } + + //sync point + ipAddress = _ipAddressDao.acquireInLockTable(ipAddress.getAddress()); + + if(ipAddress == null){ + s_logger.warn("Unable to acquire lock on ipAddress for creating 1-1 NAT rule"); + return rule; + }else{ + locked = true; + } - if(rule == null){ - throw new PermissionDeniedException("Cannot create ip forwarding rule in db"); - } - - //get ip address - IPAddressVO ipAddress = _ipAddressDao.findById(rule.getPublicIpAddress()); - if (ipAddress == null) { - throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid IP address specified."); - } - - //get the domain router object - DomainRouterVO router = _routerMgr.getRouter(ipAddress.getAccountId(), ipAddress.getDataCenterId()); - success = createOrDeleteIpForwardingRuleOnDomr(rule,router,rule.getPrivateIpAddress(),true); //true +> create - - if(!success){ - //corner case; delete record from db as domR rule creation failed - try { + //get the domain router object + DomainRouterVO router = _routerMgr.getRouter(ipAddress.getAccountId(), ipAddress.getDataCenterId()); + success = createOrDeleteIpForwardingRuleOnDomr(rule,router,rule.getPrivateIpAddress(),true); //true +> create + + if(!success){ + //corner case; delete record from db as domR rule creation failed _rulesDao.remove(ruleId); throw new PermissionDeniedException("Cannot create ip forwarding rule on domr, hence deleting created record in db"); - } catch (Exception e) { - throw new ServerApiException(BaseCmd.NET_CREATE_IPFW_RULE_ERROR, e.getMessage()); + } + + //update the user_ip_address record + ipAddress.setOneToOneNat(true); + _ipAddressDao.update(ipAddress.getAddress(),ipAddress); + + // Save and create the event + String description; + String ruleName = "ip forwarding"; + String level = EventVO.LEVEL_INFO; + + description = "created new " + ruleName + " rule [" + rule.getPublicIpAddress() + "]->[" + + rule.getPrivateIpAddress() + "]" + ":" + rule.getProtocol(); + + EventUtils.saveEvent(UserContext.current().getUserId(), ipAddress.getAccountId(), level, EventTypes.EVENT_NET_RULE_ADD, description); + txn.commit(); + } catch (Exception e) { + txn.rollback(); + throw new ServerApiException(BaseCmd.NET_CREATE_IPFW_RULE_ERROR, e.getMessage()); + }finally{ + if(locked){ + _ipAddressDao.releaseFromLockTable(ipAddress.getAddress()); } } - - // Save and create the event - String description; - String ruleName = "ip forwarding"; - String level = EventVO.LEVEL_INFO; - - description = "created new " + ruleName + " rule [" + rule.getPublicIpAddress() + "]->[" - + rule.getPrivateIpAddress() + "]" + ":" + rule.getProtocol(); - - EventUtils.saveEvent(UserContext.current().getUserId(), ipAddress.getAccountId(), level, EventTypes.EVENT_NET_RULE_ADD, description); - return rule; - } @Override @DB @@ -3124,6 +3147,10 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag success = createOrDeleteIpForwardingRuleOnDomr(rule, router, rule.getPrivateIpAddress(), false); _firewallRulesDao.remove(ruleId); + //update the ip_address record + ipAddress.setOneToOneNat(false); + _ipAddressDao.persist(ipAddress); + String description; String type = EventTypes.EVENT_NET_RULE_DELETE; String level = EventVO.LEVEL_INFO; diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index fed523c8d63..4602ff830f4 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -555,6 +555,7 @@ CREATE TABLE `cloud`.`user_ip_address` ( `source_nat` int(1) unsigned NOT NULL default '0', `allocated` datetime NULL COMMENT 'Date this ip was allocated to someone', `vlan_db_id` bigint unsigned NOT NULL, + `one_to_one_nat` int(1) unsigned NOT NULL default '0', PRIMARY KEY (`public_ip_address`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/setup/db/schema-21to22.sql b/setup/db/schema-21to22.sql index 6a7dad582b7..8b2a9b3467d 100644 --- a/setup/db/schema-21to22.sql +++ b/setup/db/schema-21to22.sql @@ -53,6 +53,7 @@ ALTER TABLE `cloud`.`volumes` ADD COLUMN `source_id` bigint unsigned; -- id for ALTER TABLE `cloud`.`volumes` ADD COLUMN `source_type` varchar(32); --source from which the volume is created i.e. snapshot, diskoffering, template, blank ALTER TABLE `cloud`.`volumes` ADD COLUMN 'attached' datetime; --date and time the volume was attached ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `customized` tinyint(1) unsigned NOT NULL DEFAULT 0;-- 0 implies not customized by default +ALTER TABLE `cloud`.`user_ip_address` ADD COLUMN `one_to_one_nat` int(1) unsigned NOT NULL default '0'; -- new column for NAT ip