diff --git a/api/src/com/cloud/agent/api/routing/NetworkElementCommand.java b/api/src/com/cloud/agent/api/routing/NetworkElementCommand.java index ba812dadda3..960e21219ac 100644 --- a/api/src/com/cloud/agent/api/routing/NetworkElementCommand.java +++ b/api/src/com/cloud/agent/api/routing/NetworkElementCommand.java @@ -24,11 +24,15 @@ import com.cloud.agent.api.Command; public abstract class NetworkElementCommand extends Command { HashMap accessDetails = new HashMap(0); + public static final String ACCOUNT_ID = "account.id"; + public static final String GUEST_NETWORK_CIDR = "guest.network.cidr"; + public static final String GUEST_NETWORK_GATEWAY = "guest.network.gateway"; + public static final String GUEST_VLAN_TAG = "guest.vlan.tag"; public static final String ROUTER_NAME = "router.name"; public static final String ROUTER_IP = "router.ip"; public static final String ROUTER_GUEST_IP = "router.guest.ip"; public static final String ZONE_NETWORK_TYPE = "zone.network.type"; - + protected NetworkElementCommand() { super(); } diff --git a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java index 96e02d0afdb..a9db05b0dce 100644 --- a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java +++ b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java @@ -46,6 +46,7 @@ import com.cloud.utils.net.NetUtils; */ public class FirewallRuleTO { long id; + String srcVlanTag; String srcIp; String protocol; int[] srcPortRange; @@ -60,8 +61,9 @@ public class FirewallRuleTO { protected FirewallRuleTO() { } - public FirewallRuleTO(long id, String srcIp, String protocol, Integer srcPortStart, Integer srcPortEnd, boolean revoked, boolean alreadyAdded, FirewallRule.Purpose purpose, List sourceCidr,Integer icmpType,Integer icmpCode) { - this.srcIp = srcIp; + public FirewallRuleTO(long id, String srcVlanTag, String srcIp, String protocol, Integer srcPortStart, Integer srcPortEnd, boolean revoked, boolean alreadyAdded, FirewallRule.Purpose purpose, List sourceCidr,Integer icmpType,Integer icmpCode) { + this.srcVlanTag = srcVlanTag; + this.srcIp = srcIp; this.protocol = protocol; if (srcPortStart != null) { @@ -87,13 +89,17 @@ public class FirewallRuleTO { this.icmpCode = icmpCode; } - public FirewallRuleTO(FirewallRule rule, String srcIp) { - this(rule.getId(), srcIp, rule.getProtocol(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getState()==State.Revoke, rule.getState()==State.Active, rule.getPurpose(),rule.getSourceCidrList(),rule.getIcmpType(),rule.getIcmpCode()); + public FirewallRuleTO(FirewallRule rule, String srcVlanTag, String srcIp) { + this(rule.getId(), srcVlanTag, srcIp, rule.getProtocol(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getState()==State.Revoke, rule.getState()==State.Active, rule.getPurpose(),rule.getSourceCidrList(),rule.getIcmpType(),rule.getIcmpCode()); } public long getId() { return id; } + + public String getSrcVlanTag() { + return srcVlanTag; + } public String getSrcIp() { return srcIp; diff --git a/api/src/com/cloud/agent/api/to/IpAddressTO.java b/api/src/com/cloud/agent/api/to/IpAddressTO.java index f41f8f203ca..fcaddd8a10e 100644 --- a/api/src/com/cloud/agent/api/to/IpAddressTO.java +++ b/api/src/com/cloud/agent/api/to/IpAddressTO.java @@ -25,6 +25,7 @@ import com.cloud.network.Networks.TrafficType; public class IpAddressTO { + private long accountId; private String publicIp; private boolean sourceNat; private boolean add; @@ -39,8 +40,9 @@ public class IpAddressTO { private TrafficType trafficType; private String[] networkTags; - public IpAddressTO(String ipAddress, boolean add, boolean firstIP, boolean sourceNat, String vlanId, String vlanGateway, String vlanNetmask, String vifMacAddress, String guestIp, Integer networkRate, boolean isOneToOneNat) { - this.publicIp = ipAddress; + public IpAddressTO(long accountId, String ipAddress, boolean add, boolean firstIP, boolean sourceNat, String vlanId, String vlanGateway, String vlanNetmask, String vifMacAddress, String guestIp, Integer networkRate, boolean isOneToOneNat) { + this.accountId = accountId; + this.publicIp = ipAddress; this.add = add; this.firstIP = firstIP; this.sourceNat = sourceNat; @@ -55,6 +57,10 @@ public class IpAddressTO { protected IpAddressTO() { } + + public long getAccountId() { + return accountId; + } public String getGuestIp(){ return guestIp; diff --git a/api/src/com/cloud/agent/api/to/PortForwardingRuleTO.java b/api/src/com/cloud/agent/api/to/PortForwardingRuleTO.java index 4b6342b0c59..08bc05c08fa 100644 --- a/api/src/com/cloud/agent/api/to/PortForwardingRuleTO.java +++ b/api/src/com/cloud/agent/api/to/PortForwardingRuleTO.java @@ -38,14 +38,14 @@ public class PortForwardingRuleTO extends FirewallRuleTO { super(); } - public PortForwardingRuleTO(PortForwardingRule rule, String srcIp) { - super(rule, srcIp); + public PortForwardingRuleTO(PortForwardingRule rule, String srcVlanTag, String srcIp) { + super(rule, srcVlanTag, srcIp); this.dstIp = rule.getDestinationIpAddress().addr(); this.dstPortRange = new int[] { rule.getDestinationPortStart(), rule.getDestinationPortEnd() }; } - protected PortForwardingRuleTO(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.PortForwarding, null,0,0); + protected PortForwardingRuleTO(long id, String srcVlanTag, String srcIp, int srcPortStart, int srcPortEnd, String dstIp, int dstPortStart, int dstPortEnd, String protocol, boolean revoked, boolean brandNew) { + super(id, srcVlanTag, srcIp, protocol, srcPortStart, srcPortEnd, revoked, brandNew, FirewallRule.Purpose.PortForwarding, null,0,0); this.dstIp = dstIp; this.dstPortRange = new int[] { dstPortStart, dstPortEnd }; } diff --git a/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java b/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java index a4845989d7f..43c9d2286cc 100644 --- a/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java +++ b/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java @@ -35,14 +35,14 @@ public class StaticNatRuleTO extends FirewallRuleTO{ protected StaticNatRuleTO() { } - public StaticNatRuleTO(StaticNatRule rule, String scrIp, String dstIp) { - super(rule.getId(), scrIp, rule.getProtocol(), rule.getSourcePortStart(), rule.getSourcePortEnd(),rule.getState()==State.Revoke, rule.getState()==State.Active, rule.getPurpose(), null,0,0); + public StaticNatRuleTO(StaticNatRule rule, String srcVlanTag, String srcIp, String dstIp) { + super(rule.getId(), srcVlanTag, srcIp, rule.getProtocol(), rule.getSourcePortStart(), rule.getSourcePortEnd(),rule.getState()==State.Revoke, rule.getState()==State.Active, rule.getPurpose(), null,0,0); this.dstIp = dstIp; } - 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); + public StaticNatRuleTO(long id, String srcVlanTag, String srcIp, Integer srcPortStart, Integer srcPortEnd, String dstIp, Integer dstPortStart, Integer dstPortEnd, String protocol, boolean revoked, boolean alreadyAdded) { + super(id, srcVlanTag, srcIp, protocol, srcPortStart, srcPortEnd, revoked, alreadyAdded, FirewallRule.Purpose.StaticNat, null,0,0); this.dstIp = dstIp; } diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index bad53390612..09bae98f492 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -75,6 +75,7 @@ public class ApiConstants { public static final String HA_ENABLE = "haenable"; public static final String HOST_ID = "hostid"; public static final String HYPERVISOR = "hypervisor"; + public static final String INLINE = "inline"; public static final String INSTANCE = "instance"; public static final String ICMP_CODE = "icmpcode"; public static final String ICMP_TYPE = "icmptype"; diff --git a/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java b/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java index 4fa2c0d57fd..4dab7205f69 100644 --- a/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java +++ b/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java @@ -218,6 +218,11 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P public Ip getDestinationIpAddress() { return null; } + + @Override + public void setDestinationIpAddress(Ip destinationIpAddress) { + return; + } @Override public int getDestinationPortStart() { diff --git a/api/src/com/cloud/network/rules/PortForwardingRule.java b/api/src/com/cloud/network/rules/PortForwardingRule.java index aac906291ee..6c6be9f767c 100644 --- a/api/src/com/cloud/network/rules/PortForwardingRule.java +++ b/api/src/com/cloud/network/rules/PortForwardingRule.java @@ -28,6 +28,12 @@ public interface PortForwardingRule extends FirewallRule { */ Ip getDestinationIpAddress(); + + /** + * updates the destination ip address. + */ + void setDestinationIpAddress(Ip destinationIpAddress); + /** * @return start of destination port. */ diff --git a/core/src/com/cloud/network/resource/F5BigIpResource.java b/core/src/com/cloud/network/resource/F5BigIpResource.java index 1ab60bdca32..2de94a4bf58 100644 --- a/core/src/com/cloud/network/resource/F5BigIpResource.java +++ b/core/src/com/cloud/network/resource/F5BigIpResource.java @@ -1,5 +1,20 @@ /** - * Copyright (C) 2011 Cloud.com, Inc. All rights reserved. + * * Copyright (C) 2011 Citrix Systems, 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.resource; @@ -23,6 +38,7 @@ import iControl.LocalLBVirtualServerVirtualServerStatistics; import iControl.LocalLBVirtualServerVirtualServerType; import iControl.NetworkingMemberTagType; import iControl.NetworkingMemberType; +import iControl.NetworkingRouteDomainBindingStub; import iControl.NetworkingSelfIPBindingStub; import iControl.NetworkingVLANBindingStub; import iControl.NetworkingVLANMemberEntry; @@ -53,6 +69,7 @@ import com.cloud.agent.api.StartupExternalLoadBalancerCommand; import com.cloud.agent.api.routing.IpAssocCommand; import com.cloud.agent.api.routing.IpAssocAnswer; import com.cloud.agent.api.routing.LoadBalancerConfigCommand; +import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.agent.api.to.LoadBalancerTO.DestinationTO; @@ -99,6 +116,7 @@ public class F5BigIpResource implements ServerResource { private String _privateInterface; private Integer _numRetries; private String _guid; + private boolean _inline; private Interfaces _interfaces; private LocalLBVirtualServerBindingStub _virtualServerApi; @@ -106,8 +124,10 @@ public class F5BigIpResource implements ServerResource { private LocalLBNodeAddressBindingStub _nodeApi; private NetworkingVLANBindingStub _vlanApi; private NetworkingSelfIPBindingStub _selfIpApi; + private NetworkingRouteDomainBindingStub _routeDomainApi; private SystemConfigSyncBindingStub _configSyncApi; private String _objectNamePathSep = "-"; + private String _routeDomainIdentifier = "%"; private static final Logger s_logger = Logger.getLogger(F5BigIpResource.class); @@ -157,6 +177,8 @@ public class F5BigIpResource implements ServerResource { if (_guid == null) { throw new ConfigurationException("Unable to find the guid"); } + + _inline = Boolean.parseBoolean((String) params.get("inline")); if (!login()) { throw new ExecutionException("Failed to login to the F5 BigIp."); @@ -268,7 +290,7 @@ public class F5BigIpResource implements ServerResource { IpAddressTO[] ips = cmd.getIpAddresses(); for (IpAddressTO ip : ips) { long guestVlanTag = Long.valueOf(ip.getVlanId()); - String vlanSelfIp = ip.getVlanGateway(); + String vlanSelfIp = _inline ? tagAddressWithRouteDomain(ip.getVlanGateway(), guestVlanTag) : ip.getVlanGateway(); String vlanNetmask = ip.getVlanNetmask(); // Delete any existing guest VLAN with this tag, self IP, and netmask @@ -298,6 +320,7 @@ public class F5BigIpResource implements ServerResource { private synchronized Answer execute(LoadBalancerConfigCommand cmd, int numRetries) { try { + long guestVlanTag = Long.parseLong(cmd.getAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG)); LoadBalancerTO[] loadBalancers = cmd.getLoadBalancers(); for (LoadBalancerTO loadBalancer : loadBalancers) { LbProtocol lbProtocol; @@ -320,7 +343,7 @@ public class F5BigIpResource implements ServerResource { throw new ExecutionException("Got invalid algorithm: " + loadBalancer.getAlgorithm()); } - String srcIp = loadBalancer.getSrcIp(); + String srcIp = _inline ? tagAddressWithRouteDomain(loadBalancer.getSrcIp(), guestVlanTag) : loadBalancer.getSrcIp(); int srcPort = loadBalancer.getSrcPort(); String virtualServerName = genVirtualServerName(lbProtocol, srcIp, srcPort); @@ -340,8 +363,9 @@ public class F5BigIpResource implements ServerResource { List activePoolMembers = new ArrayList(); for (DestinationTO destination : loadBalancer.getDestinations()) { if (!destination.isRevoked()) { - addPoolMember(virtualServerName, destination.getDestIp(), destination.getDestPort()); - activePoolMembers.add(destination.getDestIp() + "-" + destination.getDestPort()); + String destIp = _inline ? tagAddressWithRouteDomain(destination.getDestIp(), guestVlanTag) : destination.getDestIp(); + addPoolMember(virtualServerName, destIp, destination.getDestPort()); + activePoolMembers.add(destIp + "-" + destination.getDestPort()); } } @@ -372,7 +396,7 @@ public class F5BigIpResource implements ServerResource { private synchronized ExternalNetworkResourceUsageAnswer execute(ExternalNetworkResourceUsageCommand cmd) { try { - return getPublicIpBytesSentAndReceived(cmd); + return getIpBytesSentAndReceived(cmd); } catch (ExecutionException e) { return new ExternalNetworkResourceUsageAnswer(cmd, e); } @@ -412,6 +436,21 @@ public class F5BigIpResource implements ServerResource { } } + if (_inline) { + List allRouteDomains = getRouteDomains(); + if (!allRouteDomains.contains(vlanTag)) { + long[] routeDomainIds = genLongArray(vlanTag); + String[][] vlanNames = new String[][]{genStringArray(genVlanName(vlanTag))}; + + s_logger.debug("Creating route domain " + vlanTag); + _routeDomainApi.create(routeDomainIds, vlanNames); + + if (!getRouteDomains().contains(vlanTag)) { + throw new ExecutionException("Failed to create route domain " + vlanTag); + } + } + } + List allSelfIps = getSelfIps(); if (!allSelfIps.contains(vlanSelfIp)) { String[] selfIpsToCreate = genStringArray(vlanSelfIp); @@ -439,8 +478,8 @@ public class F5BigIpResource implements ServerResource { // Delete all virtual servers and pools that use this guest VLAN deleteVirtualServersInGuestVlan(vlanSelfIp, vlanNetmask); - List selfIps = getSelfIps(); - if (selfIps.contains(vlanSelfIp)) { + List allSelfIps = getSelfIps(); + if (allSelfIps.contains(vlanSelfIp)) { s_logger.debug("Deleting self IP " + vlanSelfIp); _selfIpApi.delete_self_ip(genStringArray(vlanSelfIp)); @@ -448,6 +487,18 @@ public class F5BigIpResource implements ServerResource { throw new ExecutionException("Failed to delete self IP " + vlanSelfIp); } } + + if (_inline) { + List allRouteDomains = getRouteDomains(); + if (allRouteDomains.contains(vlanTag)) { + s_logger.debug("Deleting route domain " + vlanTag); + _routeDomainApi.delete_route_domain(genLongArray(vlanTag)); + + if (getRouteDomains().contains(vlanTag)) { + throw new ExecutionException("Failed to delete route domain " + vlanTag); + } + } + } String vlanName = genVlanName(vlanTag); List allVlans = getVlans(); @@ -464,6 +515,7 @@ public class F5BigIpResource implements ServerResource { } private void deleteVirtualServersInGuestVlan(String vlanSelfIp, String vlanNetmask) throws ExecutionException { + vlanSelfIp = stripRouteDomainFromAddress(vlanSelfIp); List virtualServersToDelete = new ArrayList(); List allVirtualServers = getVirtualServers(); @@ -471,7 +523,7 @@ public class F5BigIpResource implements ServerResource { // Check if the virtual server's default pool has members in this guest VLAN List poolMembers = getMembers(virtualServerName); for (String poolMemberName : poolMembers) { - String poolMemberIp = getIpAndPort(poolMemberName)[0]; + String poolMemberIp = stripRouteDomainFromAddress(getIpAndPort(poolMemberName)[0]); if (NetUtils.sameSubnet(vlanSelfIp, poolMemberIp, vlanNetmask)) { virtualServersToDelete.add(virtualServerName); break; @@ -489,6 +541,21 @@ public class F5BigIpResource implements ServerResource { return "vlan-" + String.valueOf(vlanTag); } + private List getRouteDomains() throws ExecutionException { + try { + List routeDomains = new ArrayList(); + long[] routeDomainsArray = _routeDomainApi.get_list(); + + for (long routeDomainName : routeDomainsArray) { + routeDomains.add(routeDomainName); + } + + return routeDomains; + } catch (RemoteException e) { + throw new ExecutionException(e.getMessage()); + } + } + private List getSelfIps() throws ExecutionException { try { List selfIps = new ArrayList(); @@ -534,6 +601,7 @@ public class F5BigIpResource implements ServerResource { _nodeApi = _interfaces.getLocalLBNodeAddress(); _vlanApi = _interfaces.getNetworkingVLAN(); _selfIpApi = _interfaces.getNetworkingSelfIP(); + _routeDomainApi = _interfaces.getNetworkingRouteDomain(); _configSyncApi = _interfaces.getSystemConfigSync(); return true; @@ -587,6 +655,7 @@ public class F5BigIpResource implements ServerResource { } private String genVirtualServerName(LbProtocol protocol, String srcIp, long srcPort) { + srcIp = stripRouteDomainFromAddress(srcIp); return genObjectName("vs", protocol, srcIp, srcPort); } @@ -834,14 +903,19 @@ public class F5BigIpResource implements ServerResource { // Stats methods - private ExternalNetworkResourceUsageAnswer getPublicIpBytesSentAndReceived(ExternalNetworkResourceUsageCommand cmd) throws ExecutionException { + private ExternalNetworkResourceUsageAnswer getIpBytesSentAndReceived(ExternalNetworkResourceUsageCommand cmd) throws ExecutionException { ExternalNetworkResourceUsageAnswer answer = new ExternalNetworkResourceUsageAnswer(cmd); try { LocalLBVirtualServerVirtualServerStatistics stats = _virtualServerApi.get_all_statistics(); for (LocalLBVirtualServerVirtualServerStatisticEntry entry : stats.getStatistics()) { - String publicIp = entry.getVirtual_server().getAddress(); - long[] bytesSentAndReceived = answer.ipBytes.get(publicIp); + String virtualServerIp = entry.getVirtual_server().getAddress(); + + if (_inline) { + virtualServerIp = stripRouteDomainFromAddress(virtualServerIp); + } + + long[] bytesSentAndReceived = answer.ipBytes.get(virtualServerIp); if (bytesSentAndReceived == null) { bytesSentAndReceived = new long[]{0, 0}; @@ -858,7 +932,7 @@ public class F5BigIpResource implements ServerResource { } if (bytesSentAndReceived[0] >= 0 && bytesSentAndReceived[1] >= 0) { - answer.ipBytes.put(publicIp, bytesSentAndReceived); + answer.ipBytes.put(virtualServerIp, bytesSentAndReceived); } } } catch (Exception e) { @@ -869,7 +943,21 @@ public class F5BigIpResource implements ServerResource { return answer; } - // Array util methods + // Misc methods + + private String tagAddressWithRouteDomain(String address, long vlanTag) { + return address + _routeDomainIdentifier + vlanTag; + } + + private String stripRouteDomainFromAddress(String address) { + int i = address.indexOf(_routeDomainIdentifier); + + if (i > 0) { + address = address.substring(0, i); + } + + return address; + } private String genObjectName(Object... args) { String objectName = ""; diff --git a/core/src/com/cloud/network/resource/JuniperSrxResource.java b/core/src/com/cloud/network/resource/JuniperSrxResource.java index 9fb6d6c1b4a..66ddddf602a 100644 --- a/core/src/com/cloud/network/resource/JuniperSrxResource.java +++ b/core/src/com/cloud/network/resource/JuniperSrxResource.java @@ -1,5 +1,20 @@ /** - * Copyright (C) 2011 Cloud.com, Inc. All rights reserved. + * * Copyright (C) 2011 Citrix Systems, 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.resource; @@ -10,17 +25,13 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringReader; -import java.math.BigInteger; import java.net.Socket; import java.net.SocketTimeoutException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.UUID; import javax.naming.ConfigurationException; import javax.xml.parsers.DocumentBuilderFactory; @@ -43,10 +54,14 @@ import com.cloud.agent.api.ReadyAnswer; import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupExternalFirewallCommand; -import com.cloud.agent.api.routing.IpAssocCommand; import com.cloud.agent.api.routing.IpAssocAnswer; +import com.cloud.agent.api.routing.IpAssocCommand; +import com.cloud.agent.api.routing.NetworkElementCommand; +import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; import com.cloud.agent.api.routing.SetStaticNatRulesCommand; +import com.cloud.agent.api.routing.VpnUsersCfgCommand; +import com.cloud.agent.api.routing.VpnUsersCfgCommand.UsernamePassword; import com.cloud.agent.api.to.FirewallRuleTO; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.PortForwardingRuleTO; @@ -55,9 +70,7 @@ import com.cloud.host.Host; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.resource.ServerResource; import com.cloud.utils.NumbersUtil; -import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExecutionException; -import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; import com.cloud.utils.script.Script; @@ -79,6 +92,11 @@ public class JuniperSrxResource implements ServerResource { private static String _publicInterface; private static String _usageInterface; private static String _privateInterface; + private static String _ikeProposalName; + private static String _ipsecPolicyName; + private static String _primaryDnsAddress; + private static String _ikeGatewayHostname; + private static String _vpnObjectPrefix; private static final Logger s_logger = Logger.getLogger(JuniperSrxResource.class); private enum SrxXml { @@ -88,6 +106,7 @@ public class JuniperSrxResource implements ServerResource { PRIVATE_INTERFACE_GETONE("private-interface-getone.xml"), PROXY_ARP_ADD("proxy-arp-add.xml"), PROXY_ARP_GETONE("proxy-arp-getone.xml"), + PROXY_ARP_GETALL("proxy-arp-getall.xml"), ZONE_INTERFACE_ADD("zone-interface-add.xml"), ZONE_INTERFACE_GETONE("zone-interface-getone.xml"), SRC_NAT_POOL_ADD("src-nat-pool-add.xml"), @@ -106,6 +125,7 @@ public class JuniperSrxResource implements ServerResource { STATIC_NAT_RULE_GETALL("static-nat-rule-getall.xml"), ADDRESS_BOOK_ENTRY_ADD("address-book-entry-add.xml"), ADDRESS_BOOK_ENTRY_GETONE("address-book-entry-getone.xml"), + ADDRESS_BOOK_ENTRY_GETALL("address-book-entry-getall.xml"), APPLICATION_ADD("application-add.xml"), APPLICATION_GETONE("application-getone.xml"), SECURITY_POLICY_ADD("security-policy-add.xml"), @@ -117,13 +137,31 @@ public class JuniperSrxResource implements ServerResource { FILTER_TERM_GETONE("filter-term-getone.xml"), FILTER_GETONE("filter-getone.xml"), FIREWALL_FILTER_BYTES_GETALL("firewall-filter-bytes-getall.xml"), + IKE_POLICY_ADD("ike-policy-add.xml"), + IKE_POLICY_GETONE("ike-policy-getone.xml"), + IKE_POLICY_GETALL("ike-policy-getall.xml"), + IKE_GATEWAY_ADD("ike-gateway-add.xml"), + IKE_GATEWAY_GETONE("ike-gateway-getone.xml"), + IKE_GATEWAY_GETALL("ike-gateway-getall.xml"), + IPSEC_VPN_ADD("ipsec-vpn-add.xml"), + IPSEC_VPN_GETONE("ipsec-vpn-getone.xml"), + IPSEC_VPN_GETALL("ipsec-vpn-getall.xml"), + DYNAMIC_VPN_CLIENT_ADD("dynamic-vpn-client-add.xml"), + DYNAMIC_VPN_CLIENT_GETONE("dynamic-vpn-client-getone.xml"), + DYNAMIC_VPN_CLIENT_GETALL("dynamic-vpn-client-getall.xml"), + ADDRESS_POOL_ADD("address-pool-add.xml"), + ADDRESS_POOL_GETONE("address-pool-getone.xml"), + ADDRESS_POOL_GETALL("address-pool-getall.xml"), + ACCESS_PROFILE_ADD("access-profile-add.xml"), + ACCESS_PROFILE_GETONE("access-profile-getone.xml"), + ACCESS_PROFILE_GETALL("access-profile-getall.xml"), OPEN_CONFIGURATION("open-configuration.xml"), CLOSE_CONFIGURATION("close-configuration.xml"), COMMIT("commit.xml"), ROLLBACK("rollback.xml"), TEST("test.xml"); - private String scriptsDir = "premium-scripts/network/juniper"; + private String scriptsDir = "scripts/network/juniper"; private String xml; private SrxXml(String filename) { @@ -214,7 +252,8 @@ public class JuniperSrxResource implements ServerResource { private enum SecurityPolicyType { STATIC_NAT("staticnat"), - DESTINATION_NAT("destnat"); + DESTINATION_NAT("destnat"), + VPN("vpn"); private String identifier; @@ -240,6 +279,10 @@ public class JuniperSrxResource implements ServerResource { return execute((SetPortForwardingRulesCommand) cmd); } else if (cmd instanceof ExternalNetworkResourceUsageCommand) { return execute((ExternalNetworkResourceUsageCommand) cmd); + } else if (cmd instanceof RemoteAccessVpnCfgCommand) { + return execute((RemoteAccessVpnCfgCommand) cmd); + } else if (cmd instanceof VpnUsersCfgCommand) { + return execute((VpnUsersCfgCommand) cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } @@ -304,6 +347,12 @@ public class JuniperSrxResource implements ServerResource { _timeoutInSeconds = NumbersUtil.parseInt((String) params.get("timeoutInSeconds"), 300); _objectNameWordSep = "-"; + + _ikeProposalName = "cloud-ike-proposal"; + _ipsecPolicyName = "cloud-ipsec-policy"; + _ikeGatewayHostname = "cloud"; + _vpnObjectPrefix = "vpn-a"; + _primaryDnsAddress = "4.2.2.2"; // Open a socket and login if (!refreshSrxConnection()) { @@ -482,22 +531,6 @@ public class JuniperSrxResource implements ServerResource { } } - private void rollbackConfiguration() { - String xml = SrxXml.ROLLBACK.getXml(); - String successMsg = "Rolled back configuration."; - String errorMsg = "Failed to roll back configuration."; - - try { - if (!sendRequestAndCheckResponse(SrxCommand.ROLLBACK, xml)) { - s_logger.error(errorMsg); - } - } catch (ExecutionException e) { - s_logger.error(errorMsg); - } - - s_logger.debug(successMsg); - } - /* * Guest networks */ @@ -530,19 +563,31 @@ public class JuniperSrxResource implements ServerResource { } } - long guestVlanTag = Long.valueOf(ip.getVlanId()); - String guestVlanGateway = ip.getVlanGateway(); - long cidrSize = NetUtils.getCidrSize(ip.getVlanNetmask()); + long guestVlanTag = Long.parseLong(cmd.getAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG)); + String guestVlanGateway = cmd.getAccessDetail(NetworkElementCommand.GUEST_NETWORK_GATEWAY); + String cidr = cmd.getAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR); + long cidrSize = NetUtils.cidrToLong(cidr)[1]; String guestVlanSubnet = NetUtils.getCidrSubNet(guestVlanGateway, cidrSize); + + Long publicVlanTag = null; + if (!ip.getVlanId().equals("untagged")) { + try { + publicVlanTag = Long.parseLong(ip.getVlanId()); + } catch (Exception e) { + throw new ExecutionException("Could not parse public VLAN tag: " + ip.getVlanId()); + } + } openConfiguration(); - // Remove the guest network and any source, static, and destination NAT rules for this guest VLAN - shutdownGuestNetwork(type, sourceNatIpAddress, guestVlanTag, guestVlanGateway, guestVlanSubnet, cidrSize); - + // Remove the guest network: + // Remove source, static, and destination NAT rules + // Remove VPN + shutdownGuestNetwork(type, ip.getAccountId(), publicVlanTag, sourceNatIpAddress, guestVlanTag, guestVlanGateway, guestVlanSubnet, cidrSize); + if (ip.isAdd()) { // Implement the guest network for this VLAN - implementGuestNetwork(type, sourceNatIpAddress, guestVlanTag, guestVlanGateway, guestVlanSubnet, cidrSize); + implementGuestNetwork(type, publicVlanTag, sourceNatIpAddress, guestVlanTag, guestVlanGateway, guestVlanSubnet, cidrSize); } commitConfiguration(); @@ -563,7 +608,7 @@ public class JuniperSrxResource implements ServerResource { return new IpAssocAnswer(cmd, results); } - private void implementGuestNetwork(GuestNetworkType type, String publicIp, long privateVlanTag, String privateGateway, String privateSubnet, long privateCidrNumber) throws ExecutionException { + private void implementGuestNetwork(GuestNetworkType type, Long publicVlanTag, String publicIp, long privateVlanTag, String privateGateway, String privateSubnet, long privateCidrNumber) throws ExecutionException { privateGateway = privateGateway + "/" + privateCidrNumber; privateSubnet = privateSubnet + "/" + privateCidrNumber; @@ -573,7 +618,7 @@ public class JuniperSrxResource implements ServerResource { if (type.equals(GuestNetworkType.SOURCE_NAT)) { manageSourceNatPool(SrxCommand.ADD, publicIp); manageSourceNatRule(SrxCommand.ADD, publicIp, privateSubnet); - manageProxyArp(SrxCommand.ADD, publicIp); + manageProxyArp(SrxCommand.ADD, publicVlanTag, publicIp); manageUsageFilter(SrxCommand.ADD, UsageFilter.IP_OUTPUT, privateSubnet, null, genIpFilterTermName(publicIp)); manageUsageFilter(SrxCommand.ADD, UsageFilter.IP_INPUT, publicIp, null, genIpFilterTermName(publicIp)); } else if (type.equals(GuestNetworkType.INTERFACE_NAT)){ @@ -586,7 +631,7 @@ public class JuniperSrxResource implements ServerResource { s_logger.debug(msg); } - private void shutdownGuestNetwork(GuestNetworkType type, String sourceNatIpAddress, long privateVlanTag, String privateGateway, String privateSubnet, long privateCidrSize) throws ExecutionException { + private void shutdownGuestNetwork(GuestNetworkType type, long accountId, Long publicVlanTag, String sourceNatIpAddress, long privateVlanTag, String privateGateway, String privateSubnet, long privateCidrSize) throws ExecutionException { // Remove static and destination NAT rules for the guest network removeStaticAndDestNatRulesInPrivateVlan(privateVlanTag, privateGateway, privateCidrSize); @@ -594,12 +639,13 @@ public class JuniperSrxResource implements ServerResource { privateSubnet = privateSubnet + "/" + privateCidrSize; managePrivateInterface(SrxCommand.DELETE, false, privateVlanTag, privateGateway); - manageZoneInterface(SrxCommand.DELETE, privateVlanTag); + manageZoneInterface(SrxCommand.DELETE, privateVlanTag); + deleteVpnObjectsForAccount(accountId); if (type.equals(GuestNetworkType.SOURCE_NAT)) { manageSourceNatRule(SrxCommand.DELETE, sourceNatIpAddress, privateSubnet); manageSourceNatPool(SrxCommand.DELETE, sourceNatIpAddress); - manageProxyArp(SrxCommand.DELETE, sourceNatIpAddress); + manageProxyArp(SrxCommand.DELETE, publicVlanTag, sourceNatIpAddress); manageUsageFilter(SrxCommand.DELETE, UsageFilter.IP_OUTPUT, privateSubnet, null, genIpFilterTermName(sourceNatIpAddress)); manageUsageFilter(SrxCommand.DELETE, UsageFilter.IP_INPUT, sourceNatIpAddress, null, genIpFilterTermName(sourceNatIpAddress)); } else if (type.equals(GuestNetworkType.INTERFACE_NAT)) { @@ -623,6 +669,7 @@ public class JuniperSrxResource implements ServerResource { private Answer execute(SetStaticNatRulesCommand cmd, int numRetries) { StaticNatRuleTO[] allRules = cmd.getRules(); Map> activeRules = getActiveRules(allRules); + Map vlanTagMap = getVlanTagMap(allRules); try { openConfiguration(); @@ -633,14 +680,15 @@ public class JuniperSrxResource implements ServerResource { String publicIp = ipPairComponents[0]; String privateIp = ipPairComponents[1]; - List activeRulesForIpPair = activeRules.get(ipPair); + List activeRulesForIpPair = activeRules.get(ipPair); + Long publicVlanTag = getVlanTag(vlanTagMap.get(publicIp)); // Delete the existing static NAT rule for this IP pair - removeStaticNatRule(publicIp, privateIp); + removeStaticNatRule(publicVlanTag, publicIp, privateIp); if (activeRulesForIpPair.size() > 0) { // If there are active FirewallRules for this IP pair, add the static NAT rule and open the specified port ranges - addStaticNatRule(publicIp, privateIp, activeRulesForIpPair); + addStaticNatRule(publicVlanTag, publicIp, privateIp, activeRulesForIpPair); } } @@ -660,11 +708,11 @@ public class JuniperSrxResource implements ServerResource { } } - private void addStaticNatRule(String publicIp, String privateIp, List rules) throws ExecutionException { - manageProxyArp(SrxCommand.ADD, publicIp); + private void addStaticNatRule(Long publicVlanTag, String publicIp, String privateIp, List rules) throws ExecutionException { + manageProxyArp(SrxCommand.ADD, publicVlanTag, publicIp); manageStaticNatRule(SrxCommand.ADD, publicIp, privateIp); manageUsageFilter(SrxCommand.ADD, UsageFilter.IP_INPUT, publicIp, null, genIpFilterTermName(publicIp)); - manageAddressBookEntry(SrxCommand.ADD, _privateZone, privateIp); + manageAddressBookEntry(SrxCommand.ADD, _privateZone, privateIp, null); // Add a new security policy with the current set of applications addSecurityPolicyAndApplications(SecurityPolicyType.STATIC_NAT, privateIp, extractApplications(rules)); @@ -672,31 +720,207 @@ public class JuniperSrxResource implements ServerResource { s_logger.debug("Added static NAT rule for public IP " + publicIp + ", and private IP " + privateIp); } - private void removeStaticNatRule(String publicIp, String privateIp) throws ExecutionException { + private void removeStaticNatRule(Long publicVlanTag, String publicIp, String privateIp) throws ExecutionException { manageStaticNatRule(SrxCommand.DELETE, publicIp, privateIp); - manageProxyArp(SrxCommand.DELETE, publicIp); + manageProxyArp(SrxCommand.DELETE, publicVlanTag, publicIp); manageUsageFilter(SrxCommand.DELETE, UsageFilter.IP_INPUT, publicIp, null, genIpFilterTermName(publicIp)); // Remove any existing security policy and clean up applications removeSecurityPolicyAndApplications(SecurityPolicyType.STATIC_NAT, privateIp); - manageAddressBookEntry(SrxCommand.DELETE, _privateZone, privateIp); + manageAddressBookEntry(SrxCommand.DELETE, _privateZone, privateIp, null); s_logger.debug("Removed static NAT rule for public IP " + publicIp + ", and private IP " + privateIp); } - private void removeStaticNatRules(Long privateVlanTag, List staticNatRules) throws ExecutionException { + private void removeStaticNatRules(Long privateVlanTag, Map publicVlanTags, List staticNatRules) throws ExecutionException { for (String[] staticNatRuleToRemove : staticNatRules) { String staticNatRulePublicIp = staticNatRuleToRemove[0]; String staticNatRulePrivateIp = staticNatRuleToRemove[1]; + + Long publicVlanTag = null; + if (publicVlanTags.containsKey(staticNatRulePublicIp)) { + publicVlanTag = publicVlanTags.get(staticNatRulePublicIp); + } if (privateVlanTag != null) { s_logger.warn("Found a static NAT rule (" + staticNatRulePublicIp + " <-> " + staticNatRulePrivateIp + ") for guest VLAN with tag " + privateVlanTag + " that is active when the guest network is being removed. Removing rule..."); } - removeStaticNatRule(staticNatRulePublicIp, staticNatRulePrivateIp); + removeStaticNatRule(publicVlanTag, staticNatRulePublicIp, staticNatRulePrivateIp); } } + + /* + * VPN + */ + + private synchronized Answer execute(RemoteAccessVpnCfgCommand cmd) { + return execute(cmd, _numRetries); + } + + private Answer execute(RemoteAccessVpnCfgCommand cmd, int numRetries) { + long accountId = Long.parseLong(cmd.getAccessDetail(NetworkElementCommand.ACCOUNT_ID)); + String guestNetworkCidr = cmd.getAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR); + String preSharedKey = cmd.getPresharedKey(); + String[] ipRange = cmd.getIpRange().split("-"); + + try { + openConfiguration(); + + // Delete existing VPN objects for this account + deleteVpnObjectsForAccount(accountId); + + if (cmd.isCreate()) { + // Add IKE policy + manageIkePolicy(SrxCommand.ADD, null, accountId, preSharedKey); + + // Add address pool + manageAddressPool(SrxCommand.ADD, null, accountId, guestNetworkCidr, ipRange[0], ipRange[1], _primaryDnsAddress); + } + + commitConfiguration(); + + return new Answer(cmd); + } catch (ExecutionException e) { + s_logger.error(e); + closeConfiguration(); + + if (numRetries > 0 && refreshSrxConnection()) { + int numRetriesRemaining = numRetries - 1; + s_logger.debug("Retrying RemoteAccessVpnCfgCommand. Number of retries remaining: " + numRetriesRemaining); + return execute(cmd, numRetriesRemaining); + } else { + return new Answer(cmd, e); + } + } + + } + + private void deleteVpnObjectsForAccount(long accountId) throws ExecutionException { + // Delete all IKE policies + for (String ikePolicyName : getVpnObjectNames(SrxXml.IKE_POLICY_GETALL, accountId)) { + manageIkePolicy(SrxCommand.DELETE, ikePolicyName, null, null); + } + + // Delete all address pools + for (String addressPoolName : getVpnObjectNames(SrxXml.ADDRESS_POOL_GETALL, accountId)) { + manageAddressPool(SrxCommand.DELETE, addressPoolName, null, null, null, null, null); + } + + // Delete all IKE gateways + for (String ikeGatewayName : getVpnObjectNames(SrxXml.IKE_GATEWAY_GETALL, accountId)) { + manageIkeGateway(SrxCommand.DELETE, ikeGatewayName, null, null, null, null); + } + + // Delete all IPsec VPNs + for (String ipsecVpnName : getVpnObjectNames(SrxXml.IPSEC_VPN_GETALL, accountId)) { + manageIpsecVpn(SrxCommand.DELETE, ipsecVpnName, null, null, null, null); + } + + // Delete all dynamic VPN clients + for (String dynamicVpnClientName : getVpnObjectNames(SrxXml.DYNAMIC_VPN_CLIENT_GETALL, accountId)) { + manageDynamicVpnClient(SrxCommand.DELETE, dynamicVpnClientName, null, null, null, null); + } + + // Delete all access profiles + for (String accessProfileName : getVpnObjectNames(SrxXml.ACCESS_PROFILE_GETALL, accountId)) { + manageAccessProfile(SrxCommand.DELETE, accessProfileName, null, null, null, null); + } + + // Delete all security policies + for (String securityPolicyName : getVpnObjectNames(SrxXml.SECURITY_POLICY_GETALL, accountId)) { + manageSecurityPolicy(SecurityPolicyType.VPN, SrxCommand.DELETE, accountId, null, null, null, securityPolicyName); + } + + // Delete all address book entries + for (String addressBookEntryName : getVpnObjectNames(SrxXml.ADDRESS_BOOK_ENTRY_GETALL, accountId)) { + manageAddressBookEntry(SrxCommand.DELETE, _privateZone, null, addressBookEntryName); + } + + } + + public List getVpnObjectNames(SrxXml xmlObj, long accountId) throws ExecutionException { + List vpnObjectNames = new ArrayList(); + + String xmlRequest = xmlObj.getXml(); + if (xmlObj.equals(SrxXml.SECURITY_POLICY_GETALL)) { + xmlRequest = replaceXmlValue(xmlRequest, "from-zone", _publicZone); + xmlRequest = replaceXmlValue(xmlRequest, "to-zone", _privateZone); + } else if (xmlObj.equals(SrxXml.ADDRESS_BOOK_ENTRY_GETALL)) { + xmlRequest = replaceXmlValue(xmlRequest, "zone", _privateZone); + } + + String xmlResponse = sendRequest(xmlRequest); + Document doc = getDocument(xmlResponse); + NodeList vpnObjectNameNodes = doc.getElementsByTagName("name"); + for (int i = 0; i < vpnObjectNameNodes.getLength(); i++) { + NodeList vpnObjectNameEntries = vpnObjectNameNodes.item(i).getChildNodes(); + for (int j = 0; j < vpnObjectNameEntries.getLength(); j++) { + String vpnObjectName = vpnObjectNameEntries.item(j).getNodeValue(); + if (vpnObjectName.startsWith(genObjectName(_vpnObjectPrefix, String.valueOf(accountId)))) { + vpnObjectNames.add(vpnObjectName); + } + } + } + + return vpnObjectNames; + } + + private synchronized Answer execute(VpnUsersCfgCommand cmd) { + return execute(cmd, _numRetries); + } + + private Answer execute(VpnUsersCfgCommand cmd, int numRetries) { + long accountId = Long.parseLong(cmd.getAccessDetail(NetworkElementCommand.ACCOUNT_ID)); + String guestNetworkCidr = cmd.getAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR); + String ikePolicyName = genIkePolicyName(accountId); + UsernamePassword[] users = cmd.getUserpwds(); + + try { + openConfiguration(); + + for (UsernamePassword user : users) { + SrxCommand srxCmd = user.isAdd() ? SrxCommand.ADD : SrxCommand.DELETE; + + String ipsecVpnName = genIpsecVpnName(accountId, user.getUsername()); + + // IKE gateway + manageIkeGateway(srxCmd, null, accountId, ikePolicyName, _ikeGatewayHostname , user.getUsername()); + + // IPSec VPN + manageIpsecVpn(srxCmd, null, accountId, guestNetworkCidr, user.getUsername(), _ipsecPolicyName); + + // Dynamic VPN client + manageDynamicVpnClient(srxCmd, null, accountId, guestNetworkCidr, ipsecVpnName, user.getUsername()); + + // Access profile + manageAccessProfile(srxCmd, null, accountId, user.getUsername(), user.getPassword(), genAddressPoolName(accountId)); + + // Address book entry + manageAddressBookEntry(srxCmd, _privateZone , guestNetworkCidr, ipsecVpnName); + + // Security policy + manageSecurityPolicy(SecurityPolicyType.VPN, srxCmd, null, null, guestNetworkCidr, null, ipsecVpnName); + } + + commitConfiguration(); + + return new Answer(cmd); + } catch (ExecutionException e) { + s_logger.error(e); + closeConfiguration(); + + if (numRetries > 0 && refreshSrxConnection()) { + int numRetriesRemaining = numRetries - 1; + s_logger.debug("Retrying RemoteAccessVpnCfgCommand. Number of retries remaining: " + numRetriesRemaining); + return execute(cmd, numRetriesRemaining); + } else { + return new Answer(cmd, e); + } + } + + } /* * Destination NAT @@ -723,14 +947,16 @@ public class JuniperSrxResource implements ServerResource { // Get a list of all destination NAT rules for the public/private IP address pair List destNatRules = getDestNatRules(RuleMatchCondition.PUBLIC_PRIVATE_IPS, publicIp, privateIp, null, null); + Map publicVlanTags = getPublicVlanTagsForNatRules(destNatRules); // Delete all of these rules, along with the destination NAT pools and security policies they use - removeDestinationNatRules(null, destNatRules); + removeDestinationNatRules(null, publicVlanTags, destNatRules); // If there are active rules for the public/private IP address pair, add them back for (FirewallRuleTO rule : activeRulesForIpPair) { + Long publicVlanTag = getVlanTag(rule.getSrcVlanTag()); PortForwardingRuleTO portForwardingRule = (PortForwardingRuleTO) rule; - addDestinationNatRule(getProtocol(rule.getProtocol()), portForwardingRule.getSrcIp(), portForwardingRule.getDstIp(), + addDestinationNatRule(getProtocol(rule.getProtocol()), publicVlanTag, portForwardingRule.getSrcIp(), portForwardingRule.getDstIp(), portForwardingRule.getSrcPortRange()[0], portForwardingRule.getSrcPortRange()[1], portForwardingRule.getDstPortRange()[0], portForwardingRule.getDstPortRange()[1]); } @@ -752,8 +978,8 @@ public class JuniperSrxResource implements ServerResource { } } - private void addDestinationNatRule(Protocol protocol, String publicIp, String privateIp, int srcPortStart, int srcPortEnd, int destPortStart, int destPortEnd) throws ExecutionException { - manageProxyArp(SrxCommand.ADD, publicIp); + private void addDestinationNatRule(Protocol protocol, Long publicVlanTag, String publicIp, String privateIp, int srcPortStart, int srcPortEnd, int destPortStart, int destPortEnd) throws ExecutionException { + manageProxyArp(SrxCommand.ADD, publicVlanTag, publicIp); int offset = 0; for (int srcPort = srcPortStart; srcPort <= srcPortEnd; srcPort++) { @@ -763,7 +989,7 @@ public class JuniperSrxResource implements ServerResource { offset += 1; } - manageAddressBookEntry(SrxCommand.ADD, _privateZone, privateIp); + manageAddressBookEntry(SrxCommand.ADD, _privateZone, privateIp, null); List applications = new ArrayList(); applications.add(new Object[]{protocol, destPortStart, destPortEnd}); @@ -774,25 +1000,30 @@ public class JuniperSrxResource implements ServerResource { s_logger.debug("Added destination NAT rule for protocol " + protocol + ", public IP " + publicIp + ", private IP " + privateIp + ", source port range " + srcPortRange + ", and dest port range " + destPortRange); } - private void removeDestinationNatRule(String publicIp, String privateIp, int srcPort, int destPort) throws ExecutionException { + private void removeDestinationNatRule(Long publicVlanTag, String publicIp, String privateIp, int srcPort, int destPort) throws ExecutionException { manageDestinationNatRule(SrxCommand.DELETE, publicIp, privateIp, srcPort, destPort); manageDestinationNatPool(SrxCommand.DELETE, privateIp, destPort); - manageProxyArp(SrxCommand.DELETE, publicIp); + manageProxyArp(SrxCommand.DELETE, publicVlanTag, publicIp); removeSecurityPolicyAndApplications(SecurityPolicyType.DESTINATION_NAT, privateIp); - manageAddressBookEntry(SrxCommand.DELETE, _privateZone, privateIp); + manageAddressBookEntry(SrxCommand.DELETE, _privateZone, privateIp, null); s_logger.debug("Removed destination NAT rule for public IP " + publicIp + ", private IP " + privateIp + ", source port " + srcPort + ", and dest port " + destPort); } - private void removeDestinationNatRules(Long privateVlanTag, List destNatRules) throws ExecutionException { + private void removeDestinationNatRules(Long privateVlanTag, Map publicVlanTags, List destNatRules) throws ExecutionException { for (String[] destNatRule : destNatRules) { String publicIp = destNatRule[0]; String privateIp = destNatRule[1]; int srcPort = Integer.valueOf(destNatRule[2]); int destPort = Integer.valueOf(destNatRule[3]); + + Long publicVlanTag = null; + if (publicVlanTags.containsKey(publicIp)) { + publicVlanTag = publicVlanTags.get(publicIp); + } if (privateVlanTag != null) { s_logger.warn("Found a destination NAT rule (public IP: " + publicIp + ", private IP: " + privateIp + @@ -800,7 +1031,7 @@ public class JuniperSrxResource implements ServerResource { privateVlanTag + " that is active when the guest network is being removed. Removing rule..."); } - removeDestinationNatRule(publicIp, privateIp, srcPort, destPort); + removeDestinationNatRule(publicVlanTag, publicIp, privateIp, srcPort, destPort); } } @@ -817,10 +1048,16 @@ public class JuniperSrxResource implements ServerResource { private void removeStaticAndDestNatRulesInPrivateVlan(long privateVlanTag, String privateGateway, long privateCidrSize) throws ExecutionException { List staticNatRulesToRemove = getStaticNatRules(RuleMatchCondition.PRIVATE_SUBNET, privateGateway, privateCidrSize); - removeStaticNatRules(privateVlanTag, staticNatRulesToRemove); - List destNatRulesToRemove = getDestNatRules(RuleMatchCondition.PRIVATE_SUBNET, null, null, privateGateway, privateCidrSize); - removeDestinationNatRules(privateVlanTag, destNatRulesToRemove); + + List publicIps = new ArrayList(); + addPublicIpsToList(staticNatRulesToRemove, publicIps); + addPublicIpsToList(destNatRulesToRemove, publicIps); + + Map publicVlanTags = getPublicVlanTagsForPublicIps(publicIps); + + removeStaticNatRules(privateVlanTag, publicVlanTags, staticNatRulesToRemove); + removeDestinationNatRules(privateVlanTag, publicVlanTags, destNatRulesToRemove); } private Map> getActiveRules(FirewallRuleTO[] allRules) { @@ -854,6 +1091,364 @@ public class JuniperSrxResource implements ServerResource { return activeRules; } + + private Map getVlanTagMap(FirewallRuleTO[] allRules) { + Map vlanTagMap = new HashMap(); + + for (FirewallRuleTO rule : allRules) { + vlanTagMap.put(rule.getSrcIp(), rule.getSrcVlanTag()); + } + + return vlanTagMap; + } + + /* + * VPN + */ + + private String genIkePolicyName(long accountId) { + return genObjectName(_vpnObjectPrefix, String.valueOf(accountId)); + } + + private boolean manageIkePolicy(SrxCommand command, String ikePolicyName, Long accountId, String preSharedKey) throws ExecutionException { + if (ikePolicyName == null) { + ikePolicyName = genIkePolicyName(accountId); + } + + String xml; + + switch(command) { + + case CHECK_IF_EXISTS: + xml = SrxXml.IKE_GATEWAY_GETONE.getXml(); + xml = setDelete(xml, false); + xml = replaceXmlValue(xml, "policy-name", ikePolicyName); + return sendRequestAndCheckResponse(command, xml, "name", ikePolicyName); + + case ADD: + if (manageIkePolicy(SrxCommand.CHECK_IF_EXISTS, ikePolicyName, accountId, preSharedKey)) { + return true; + } + + xml = SrxXml.IKE_POLICY_ADD.getXml(); + xml = replaceXmlValue(xml, "policy-name", ikePolicyName); + xml = replaceXmlValue(xml, "proposal-name", _ikeProposalName); + xml = replaceXmlValue(xml, "pre-shared-key", preSharedKey); + + if (!sendRequestAndCheckResponse(command, xml)) { + throw new ExecutionException("Failed to add IKE policy: " + ikePolicyName); + } else { + return true; + } + + case DELETE: + if (!manageIkePolicy(SrxCommand.CHECK_IF_EXISTS, ikePolicyName, accountId, preSharedKey)) { + return true; + } + + xml = SrxXml.IKE_GATEWAY_GETONE.getXml(); + xml = setDelete(xml, true); + xml = replaceXmlValue(xml, "policy-name", ikePolicyName); + + if (!sendRequestAndCheckResponse(command, xml, "name", ikePolicyName)) { + throw new ExecutionException("Failed to delete IKE policy: " + ikePolicyName); + } else { + return true; + } + + default: + s_logger.debug("Unrecognized command."); + return false; + } + + } + + private String genIkeGatewayName(long accountId, String username) { + return genObjectName(_vpnObjectPrefix, String.valueOf(accountId), username); + } + + private boolean manageIkeGateway(SrxCommand command, String ikeGatewayName, Long accountId, String ikePolicyName, String ikeGatewayHostname, String username) throws ExecutionException { + if (ikeGatewayName == null) { + ikeGatewayName = genIkeGatewayName(accountId, username); + } + + String xml; + + switch(command) { + + case CHECK_IF_EXISTS: + xml = SrxXml.IKE_GATEWAY_GETONE.getXml(); + xml = setDelete(xml, false); + xml = replaceXmlValue(xml, "gateway-name", ikeGatewayName); + return sendRequestAndCheckResponse(command, xml, "name", ikeGatewayName); + + case ADD: + if (manageIkeGateway(SrxCommand.CHECK_IF_EXISTS, ikeGatewayName, accountId, ikePolicyName, ikeGatewayHostname, username)) { + return true; + } + + xml = SrxXml.IKE_GATEWAY_ADD.getXml(); + xml = replaceXmlValue(xml, "gateway-name", ikeGatewayName); + xml = replaceXmlValue(xml, "ike-policy-name", ikePolicyName); + xml = replaceXmlValue(xml, "ike-gateway-hostname", ikeGatewayHostname); + xml = replaceXmlValue(xml, "public-interface-name", _publicInterface); + xml = replaceXmlValue(xml, "access-profile-name", genAccessProfileName(accountId, username)); + + if (!sendRequestAndCheckResponse(command, xml)) { + throw new ExecutionException("Failed to add IKE gateway: " + ikeGatewayName); + } else { + return true; + } + + case DELETE: + if (!manageIkeGateway(SrxCommand.CHECK_IF_EXISTS, ikeGatewayName, accountId, ikePolicyName, ikeGatewayHostname, username)) { + return true; + } + + xml = SrxXml.IKE_GATEWAY_GETONE.getXml(); + xml = setDelete(xml, true); + xml = replaceXmlValue(xml, "gateway-name", ikeGatewayName); + + if (!sendRequestAndCheckResponse(command, xml, "name", ikeGatewayName)) { + throw new ExecutionException("Failed to delete IKE gateway: " + ikeGatewayName); + } else { + return true; + } + + default: + s_logger.debug("Unrecognized command."); + return false; + } + } + + private String genIpsecVpnName(long accountId, String username) { + return genObjectName(_vpnObjectPrefix, String.valueOf(accountId), username); + } + + private boolean manageIpsecVpn(SrxCommand command, String ipsecVpnName, Long accountId, String guestNetworkCidr, String username, String ipsecPolicyName) throws ExecutionException { + if (ipsecVpnName == null) { + ipsecVpnName = genIpsecVpnName(accountId, username); + } + + String xml; + + switch(command) { + + case CHECK_IF_EXISTS: + xml = SrxXml.IPSEC_VPN_GETONE.getXml(); + xml = setDelete(xml, false); + xml = replaceXmlValue(xml, "ipsec-vpn-name", ipsecVpnName); + return sendRequestAndCheckResponse(command, xml, "name", ipsecVpnName); + + case ADD: + if (manageIpsecVpn(SrxCommand.CHECK_IF_EXISTS, ipsecVpnName, accountId, guestNetworkCidr, username, ipsecPolicyName)) { + return true; + } + + xml = SrxXml.IPSEC_VPN_ADD.getXml(); + xml = replaceXmlValue(xml, "ipsec-vpn-name", ipsecVpnName); + xml = replaceXmlValue(xml, "ike-gateway", genIkeGatewayName(accountId, username)); + xml = replaceXmlValue(xml, "ipsec-policy-name", ipsecPolicyName); + + if (!sendRequestAndCheckResponse(command, xml)) { + throw new ExecutionException("Failed to add IPSec VPN: " + ipsecVpnName); + } else { + return true; + } + + case DELETE: + if (!manageIpsecVpn(SrxCommand.CHECK_IF_EXISTS, ipsecVpnName, accountId, guestNetworkCidr, username, ipsecPolicyName)) { + return true; + } + + xml = SrxXml.IPSEC_VPN_GETONE.getXml(); + xml = setDelete(xml, true); + xml = replaceXmlValue(xml, "ipsec-vpn-name", ipsecVpnName); + + if (!sendRequestAndCheckResponse(command, xml, "name", ipsecVpnName)) { + throw new ExecutionException("Failed to delete IPSec VPN: " + ipsecVpnName); + } else { + return true; + } + + default: + s_logger.debug("Unrecognized command."); + return false; + } + } + + private String genDynamicVpnClientName(long accountId, String username) { + return genObjectName(_vpnObjectPrefix, String.valueOf(accountId), username); + } + + private boolean manageDynamicVpnClient(SrxCommand command, String clientName, Long accountId, String guestNetworkCidr, String ipsecVpnName, String username) throws ExecutionException { + if (clientName == null) { + clientName = genDynamicVpnClientName(accountId, username); + } + + String xml; + + switch(command) { + + case CHECK_IF_EXISTS: + xml = SrxXml.DYNAMIC_VPN_CLIENT_GETONE.getXml(); + xml = setDelete(xml, false); + xml = replaceXmlValue(xml, "client-name", clientName); + return sendRequestAndCheckResponse(command, xml, "name", clientName); + + case ADD: + if (manageDynamicVpnClient(SrxCommand.CHECK_IF_EXISTS, clientName, accountId, guestNetworkCidr, ipsecVpnName, username)) { + return true; + } + + xml = SrxXml.DYNAMIC_VPN_CLIENT_ADD.getXml(); + xml = replaceXmlValue(xml, "client-name", clientName); + xml = replaceXmlValue(xml, "guest-network-cidr", guestNetworkCidr); + xml = replaceXmlValue(xml, "ipsec-vpn-name", ipsecVpnName); + xml = replaceXmlValue(xml, "username", username); + + if (!sendRequestAndCheckResponse(command, xml)) { + throw new ExecutionException("Failed to add dynamic VPN client: " + clientName); + } else { + return true; + } + + case DELETE: + if (!manageDynamicVpnClient(SrxCommand.CHECK_IF_EXISTS, clientName, accountId, guestNetworkCidr, ipsecVpnName, username)) { + return true; + } + + xml = SrxXml.DYNAMIC_VPN_CLIENT_GETONE.getXml(); + xml = setDelete(xml, true); + xml = replaceXmlValue(xml, "client-name", clientName); + + if (!sendRequestAndCheckResponse(command, xml, "name", clientName)) { + throw new ExecutionException("Failed to delete dynamic VPN client: " + clientName); + } else { + return true; + } + + default: + s_logger.debug("Unrecognized command."); + return false; + } + } + + private String genAddressPoolName(long accountId) { + return genObjectName(_vpnObjectPrefix, String.valueOf(accountId)); + } + + private boolean manageAddressPool(SrxCommand command, String addressPoolName, Long accountId, String guestNetworkCidr, String lowAddress, String highAddress, String primaryDnsAddress) throws ExecutionException { + if (addressPoolName == null) { + addressPoolName = genAddressPoolName(accountId); + } + + String xml; + + switch(command) { + + case CHECK_IF_EXISTS: + xml = SrxXml.ADDRESS_POOL_GETONE.getXml(); + xml = setDelete(xml, false); + xml = replaceXmlValue(xml, "address-pool-name", addressPoolName); + return sendRequestAndCheckResponse(command, xml, "name", addressPoolName); + + case ADD: + if (manageAddressPool(SrxCommand.CHECK_IF_EXISTS, addressPoolName, accountId, guestNetworkCidr, lowAddress, highAddress, primaryDnsAddress)) { + return true; + } + + xml = SrxXml.ADDRESS_POOL_ADD.getXml(); + xml = replaceXmlValue(xml, "address-pool-name", addressPoolName); + xml = replaceXmlValue(xml, "guest-network-cidr", guestNetworkCidr); + xml = replaceXmlValue(xml, "address-range-name", "r-" + addressPoolName); + xml = replaceXmlValue(xml, "low-address", lowAddress); + xml = replaceXmlValue(xml, "high-address", highAddress); + xml = replaceXmlValue(xml, "primary-dns-address", primaryDnsAddress); + + if (!sendRequestAndCheckResponse(command, xml)) { + throw new ExecutionException("Failed to add address pool: " + addressPoolName); + } else { + return true; + } + + case DELETE: + if (!manageAddressPool(SrxCommand.CHECK_IF_EXISTS, addressPoolName, accountId, guestNetworkCidr, lowAddress, highAddress, primaryDnsAddress)) { + return true; + } + + xml = SrxXml.ADDRESS_POOL_GETONE.getXml(); + xml = setDelete(xml, true); + xml = replaceXmlValue(xml, "address-pool-name", addressPoolName); + + if (!sendRequestAndCheckResponse(command, xml, "name", addressPoolName)) { + throw new ExecutionException("Failed to delete address pool: " + addressPoolName); + } else { + return true; + } + + default: + s_logger.debug("Unrecognized command."); + return false; + } + } + + private String genAccessProfileName(long accountId, String username) { + return genObjectName(_vpnObjectPrefix, String.valueOf(accountId), username); + } + + private boolean manageAccessProfile(SrxCommand command, String accessProfileName, Long accountId, String username, String password, String addressPoolName) throws ExecutionException { + if (accessProfileName == null) { + accessProfileName = genAccessProfileName(accountId, username); + } + + String xml; + + switch(command) { + + case CHECK_IF_EXISTS: + xml = SrxXml.ACCESS_PROFILE_GETONE.getXml(); + xml = setDelete(xml, false); + xml = replaceXmlValue(xml, "access-profile-name", accessProfileName); + return sendRequestAndCheckResponse(command, xml, "name", username); + + case ADD: + if (manageAccessProfile(SrxCommand.CHECK_IF_EXISTS, accessProfileName, accountId, username, password, addressPoolName)) { + return true; + } + + xml = SrxXml.ACCESS_PROFILE_ADD.getXml(); + xml = replaceXmlValue(xml, "access-profile-name", accessProfileName); + xml = replaceXmlValue(xml, "username", username); + xml = replaceXmlValue(xml, "password", password); + xml = replaceXmlValue(xml, "address-pool-name", addressPoolName); + + if (!sendRequestAndCheckResponse(command, xml)) { + throw new ExecutionException("Failed to add access profile: " + accessProfileName); + } else { + return true; + } + + case DELETE: + if (!manageAccessProfile(SrxCommand.CHECK_IF_EXISTS, accessProfileName, accountId, username, password, addressPoolName)) { + return true; + } + + xml = SrxXml.ACCESS_PROFILE_GETONE.getXml(); + xml = setDelete(xml, true); + xml = replaceXmlValue(xml, "access-profile-name", accessProfileName); + + if (!sendRequestAndCheckResponse(command, xml, "name", username)) { + throw new ExecutionException("Failed to delete access profile: " + accessProfileName); + } else { + return true; + } + + default: + s_logger.debug("Unrecognized command."); + return false; + } + } /* * Private interfaces @@ -914,12 +1509,31 @@ public class JuniperSrxResource implements ServerResource { } } + + private Long getVlanTagFromInterfaceName(String interfaceName) throws ExecutionException { + Long vlanTag = null; + + if (interfaceName.contains(".")) { + try { + String unitNum = interfaceName.split("\\.")[1]; + if (!unitNum.equals("0")) { + vlanTag = Long.parseLong(unitNum); + } + } catch (Exception e) { + s_logger.error(e); + throw new ExecutionException("Unable to parse VLAN tag from interface name: " + interfaceName); + } + } + + return vlanTag; + } /* * Proxy ARP */ - private boolean manageProxyArp(SrxCommand command, String publicIp) throws ExecutionException { + private boolean manageProxyArp(SrxCommand command, Long publicVlanTag, String publicIp) throws ExecutionException { + String publicInterface = genPublicInterface(publicVlanTag); String xml; switch (command) { @@ -927,7 +1541,7 @@ public class JuniperSrxResource implements ServerResource { case CHECK_IF_EXISTS: xml = SrxXml.PROXY_ARP_GETONE.getXml(); xml = setDelete(xml, false); - xml = replaceXmlValue(xml, "public-interface-name", _publicInterface); + xml = replaceXmlValue(xml, "public-interface-name", publicInterface); xml = replaceXmlValue(xml, "public-ip-address", publicIp); return sendRequestAndCheckResponse(command, xml, "name", publicIp + "/32"); @@ -945,12 +1559,12 @@ public class JuniperSrxResource implements ServerResource { return false; case ADD: - if (manageProxyArp(SrxCommand.CHECK_IF_EXISTS, publicIp)) { + if (manageProxyArp(SrxCommand.CHECK_IF_EXISTS, publicVlanTag, publicIp)) { return true; } xml = SrxXml.PROXY_ARP_ADD.getXml(); - xml = replaceXmlValue(xml, "public-interface-name", _publicInterface); + xml = replaceXmlValue(xml, "public-interface-name", publicInterface); xml = replaceXmlValue(xml, "public-ip-address", publicIp); if (!sendRequestAndCheckResponse(command, xml)) { @@ -960,17 +1574,17 @@ public class JuniperSrxResource implements ServerResource { } case DELETE: - if (!manageProxyArp(SrxCommand.CHECK_IF_EXISTS, publicIp)) { + if (!manageProxyArp(SrxCommand.CHECK_IF_EXISTS, publicVlanTag, publicIp)) { return true; } - if (manageProxyArp(SrxCommand.CHECK_IF_IN_USE, publicIp)) { + if (manageProxyArp(SrxCommand.CHECK_IF_IN_USE, publicVlanTag, publicIp)) { return true; } xml = SrxXml.PROXY_ARP_GETONE.getXml(); xml = setDelete(xml, true); - xml = replaceXmlValue(xml, "public-interface-name", _publicInterface); + xml = replaceXmlValue(xml, "public-interface-name", publicInterface); xml = replaceXmlValue(xml, "public-ip-address", publicIp); if (!sendRequestAndCheckResponse(command, xml, "name", publicIp)) { @@ -987,6 +1601,86 @@ public class JuniperSrxResource implements ServerResource { } + private Map getPublicVlanTagsForPublicIps(List publicIps) throws ExecutionException { + Map publicVlanTags = new HashMap(); + + List interfaceNames = new ArrayList(); + + String xmlRequest = SrxXml.PROXY_ARP_GETALL.getXml(); + xmlRequest = replaceXmlValue(xmlRequest, "interface-name", ""); + String xmlResponse = sendRequest(xmlRequest); + + Document doc = getDocument(xmlResponse); + NodeList interfaces = doc.getElementsByTagName("interface"); + for (int i = 0; i < interfaces.getLength(); i++) { + String interfaceName = null; + NodeList interfaceEntries = interfaces.item(i).getChildNodes(); + for (int j = 0; j < interfaceEntries.getLength(); j++) { + Node interfaceEntry = interfaceEntries.item(j); + if (interfaceEntry.getNodeName().equals("name")) { + interfaceName = interfaceEntry.getFirstChild().getNodeValue(); + break; + } + } + + if (interfaceName != null) { + interfaceNames.add(interfaceName); + } + } + + if (interfaceNames.size() == 1) { + populatePublicVlanTagsMap(xmlResponse, interfaceNames.get(0), publicIps, publicVlanTags); + } else if (interfaceNames.size() > 1) { + for (String interfaceName : interfaceNames) { + xmlRequest = SrxXml.PROXY_ARP_GETALL.getXml(); + xmlRequest = replaceXmlValue(xmlRequest, "interface-name", interfaceName); + xmlResponse = sendRequest(xmlRequest); + populatePublicVlanTagsMap(xmlResponse, interfaceName, publicIps, publicVlanTags); + } + } + + return publicVlanTags; + } + + private void populatePublicVlanTagsMap(String xmlResponse, String interfaceName, List publicIps, Map publicVlanTags) throws ExecutionException { + Long publicVlanTag = getVlanTagFromInterfaceName(interfaceName); + if (publicVlanTag != null) { + for (String publicIp : publicIps) { + if (xmlResponse.contains(publicIp)) { + publicVlanTags.put(publicIp, publicVlanTag); + } + } + } + } + + private Map getPublicVlanTagsForNatRules(List natRules) throws ExecutionException { + List publicIps = new ArrayList(); + addPublicIpsToList(natRules, publicIps); + return getPublicVlanTagsForPublicIps(publicIps); + } + + private void addPublicIpsToList(List natRules, List publicIps) { + for (String[] natRule : natRules) { + if (!publicIps.contains(natRule[0])) { + publicIps.add(natRule[0]); + } + } + } + + private String genPublicInterface(Long vlanTag) { + String publicInterface = _publicInterface; + + if (!publicInterface.contains(".")) { + if (vlanTag == null) { + publicInterface += ".0"; + } else { + publicInterface += "." + vlanTag; + } + } + + return publicInterface; + } + /* * Zone interfaces */ @@ -1522,12 +2216,15 @@ public class JuniperSrxResource implements ServerResource { } } - private boolean manageAddressBookEntry(SrxCommand command, String zone, String ip) throws ExecutionException { + private boolean manageAddressBookEntry(SrxCommand command, String zone, String ip, String entryName) throws ExecutionException { if (!zone.equals(_publicZone) && !zone.equals(_privateZone)) { throw new ExecutionException("Invalid zone."); } - String entryName = genAddressBookEntryName(ip); + if (entryName == null) { + entryName = genAddressBookEntryName(ip); + } + String xml; switch (command) { @@ -1548,7 +2245,7 @@ public class JuniperSrxResource implements ServerResource { return sendRequestAndCheckResponse(command, xml, "destination-address", entryName); case ADD: - if (manageAddressBookEntry(SrxCommand.CHECK_IF_EXISTS, zone, ip)) { + if (manageAddressBookEntry(SrxCommand.CHECK_IF_EXISTS, zone, ip, entryName)) { return true; } @@ -1564,11 +2261,11 @@ public class JuniperSrxResource implements ServerResource { } case DELETE: - if (!manageAddressBookEntry(SrxCommand.CHECK_IF_EXISTS, zone, ip)) { + if (!manageAddressBookEntry(SrxCommand.CHECK_IF_EXISTS, zone, ip, entryName)) { return true; } - if (manageAddressBookEntry(SrxCommand.CHECK_IF_IN_USE, zone, ip)) { + if (manageAddressBookEntry(SrxCommand.CHECK_IF_IN_USE, zone, ip, entryName)) { return true; } @@ -1704,7 +2401,7 @@ public class JuniperSrxResource implements ServerResource { private List getApplicationsForSecurityPolicy(SecurityPolicyType type, String privateIp) throws ExecutionException { String fromZone = _publicZone; String toZone = _privateZone; - String policyName = genSecurityPolicyName(type, fromZone, toZone, privateIp); + String policyName = genSecurityPolicyName(type, null, null, fromZone, toZone, privateIp); String xml = SrxXml.SECURITY_POLICY_GETONE.getXml(); xml = setDelete(xml, false); xml = replaceXmlValue(xml, "from-zone", fromZone); @@ -1743,15 +2440,28 @@ public class JuniperSrxResource implements ServerResource { * Security policies */ - private String genSecurityPolicyName(SecurityPolicyType type, String fromZone, String toZone, String translatedIp) { - return genObjectName(type.getIdentifier(), fromZone, toZone, genIpIdentifier(translatedIp)); + private String genSecurityPolicyName(SecurityPolicyType type, Long accountId, String username, String fromZone, String toZone, String translatedIp) { + if (type.equals(SecurityPolicyType.VPN)) { + return genObjectName(_vpnObjectPrefix, String.valueOf(accountId), username); + } else { + return genObjectName(type.getIdentifier(), fromZone, toZone, genIpIdentifier(translatedIp)); + } } - private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command, String privateIp, List applicationNames) throws ExecutionException { + private boolean manageSecurityPolicy(SecurityPolicyType type, SrxCommand command, Long accountId, String username, String privateIp, List applicationNames, String ipsecVpnName) throws ExecutionException { String fromZone = _publicZone; String toZone = _privateZone; - String securityPolicyName = genSecurityPolicyName(type, fromZone, toZone, privateIp); - String addressBookEntryName = genAddressBookEntryName(privateIp); + + String securityPolicyName; + String addressBookEntryName; + + if (type.equals(SecurityPolicyType.VPN) && ipsecVpnName != null) { + securityPolicyName = ipsecVpnName; + addressBookEntryName = ipsecVpnName; + } else { + securityPolicyName = genSecurityPolicyName(type, accountId, username, fromZone, toZone, privateIp); + addressBookEntryName = genAddressBookEntryName(privateIp); + } String xml; @@ -1763,6 +2473,7 @@ public class JuniperSrxResource implements ServerResource { xml = replaceXmlValue(xml, "from-zone", fromZone); xml = replaceXmlValue(xml, "to-zone", toZone); xml = replaceXmlValue(xml, "policy-name", securityPolicyName); + return sendRequestAndCheckResponse(command, xml, "name", securityPolicyName); case CHECK_IF_IN_USE: @@ -1787,21 +2498,32 @@ public class JuniperSrxResource implements ServerResource { return false; case ADD: - if (!manageAddressBookEntry(SrxCommand.CHECK_IF_EXISTS, toZone, privateIp)) { - throw new ExecutionException("No address book entry for: " + privateIp); + if (!manageAddressBookEntry(SrxCommand.CHECK_IF_EXISTS, toZone, privateIp, ipsecVpnName)) { + throw new ExecutionException("No address book entry for policy: " + securityPolicyName); } - xml = SrxXml.SECURITY_POLICY_ADD.getXml(); + xml = SrxXml.SECURITY_POLICY_ADD.getXml(); xml = replaceXmlValue(xml, "from-zone", fromZone); - xml = replaceXmlValue(xml, "to-zone", toZone); - xml = replaceXmlValue(xml, "policy-name", securityPolicyName); - xml = replaceXmlValue(xml, "src-address", "any"); + xml = replaceXmlValue(xml, "to-zone", toZone); + xml = replaceXmlValue(xml, "policy-name", securityPolicyName); + xml = replaceXmlValue(xml, "src-address", "any"); xml = replaceXmlValue(xml, "dest-address", addressBookEntryName); - - String applications = ""; - for (String applicationName : applicationNames) { - applications += "" + applicationName + ""; + + if (type.equals(SecurityPolicyType.VPN) && ipsecVpnName != null) { + xml = replaceXmlValue(xml, "tunnel", "" + ipsecVpnName + ""); + } else { + xml = replaceXmlValue(xml, "tunnel", ""); } + + String applications; + if (applicationNames == null) { + applications = "any"; + } else { + applications = ""; + for (String applicationName : applicationNames) { + applications += "" + applicationName + ""; + } + } xml = replaceXmlValue(xml, "applications", applications); @@ -1812,11 +2534,11 @@ public class JuniperSrxResource implements ServerResource { } case DELETE: - if (!manageSecurityPolicy(type, SrxCommand.CHECK_IF_EXISTS, privateIp, applicationNames)) { + if (!manageSecurityPolicy(type, SrxCommand.CHECK_IF_EXISTS, null, null, privateIp, applicationNames, ipsecVpnName)) { return true; } - if (manageSecurityPolicy(type, SrxCommand.CHECK_IF_IN_USE, privateIp, applicationNames)) { + if (manageSecurityPolicy(type, SrxCommand.CHECK_IF_IN_USE, null, null, privateIp, applicationNames, ipsecVpnName)) { return true; } @@ -1825,6 +2547,7 @@ public class JuniperSrxResource implements ServerResource { xml = replaceXmlValue(xml, "from-zone", fromZone); xml = replaceXmlValue(xml, "to-zone", toZone); xml = replaceXmlValue(xml, "policy-name", securityPolicyName); + boolean success = sendRequestAndCheckResponse(command, xml); if (success) { @@ -1880,17 +2603,17 @@ public class JuniperSrxResource implements ServerResource { } // Add a new security policy - manageSecurityPolicy(type, SrxCommand.ADD, privateIp, applicationNames); + manageSecurityPolicy(type, SrxCommand.ADD, null, null, privateIp, applicationNames, null); return true; } private boolean removeSecurityPolicyAndApplications(SecurityPolicyType type, String privateIp) throws ExecutionException { - if (!manageSecurityPolicy(type, SrxCommand.CHECK_IF_EXISTS, privateIp, null)) { + if (!manageSecurityPolicy(type, SrxCommand.CHECK_IF_EXISTS, null, null, privateIp, null, null)) { return true; } - if (manageSecurityPolicy(type, SrxCommand.CHECK_IF_IN_USE, privateIp, null)) { + if (manageSecurityPolicy(type, SrxCommand.CHECK_IF_IN_USE, null, null, privateIp, null, null)) { return true; } @@ -1898,7 +2621,7 @@ public class JuniperSrxResource implements ServerResource { List applications = getApplicationsForSecurityPolicy(type, privateIp); // Remove the security policy - manageSecurityPolicy(type, SrxCommand.DELETE, privateIp, null); + manageSecurityPolicy(type, SrxCommand.DELETE, null, null, privateIp, null, null); // Remove any applications for the removed security policy that are no longer in use List unusedApplications = getUnusedApplications(applications); @@ -2036,7 +2759,7 @@ public class JuniperSrxResource implements ServerResource { } if (byteCount >= 0) { - updateUsageAnswer(answer, counterName, byteCount); + updateUsageAnswer(answer, counterName, byteCount); } } } @@ -2134,8 +2857,7 @@ public class JuniperSrxResource implements ServerResource { } else { s_logger.debug("Sending login request"); } - - + boolean timedOut = false; StringBuffer xmlResponseBuffer = new StringBuffer(""); try { @@ -2170,8 +2892,7 @@ public class JuniperSrxResource implements ServerResource { } else if (!xmlResponse.contains("")) { errorMsg = "Didn't find the rpc-reply tag in the XML response."; } - - + if (errorMsg == null) { return xmlResponse; } else { @@ -2299,7 +3020,20 @@ public class JuniperSrxResource implements ServerResource { /* * Misc - */ + */ + + private Long getVlanTag(String vlan) throws ExecutionException { + Long publicVlanTag = null; + if (!vlan.equals("untagged")) { + try { + publicVlanTag = Long.parseLong(vlan); + } catch (Exception e) { + throw new ExecutionException("Unable to parse VLAN tag: " + vlan); + } + } + + return publicVlanTag; + } private String genObjectName(String... args) { String objectName = ""; @@ -2346,6 +3080,6 @@ public class JuniperSrxResource implements ServerResource { } else { return doc; } - } - + } + } \ No newline at end of file diff --git a/scripts/network/juniper/security-policy-add.xml b/scripts/network/juniper/security-policy-add.xml index 509ed17c88d..02c88e389c8 100644 --- a/scripts/network/juniper/security-policy-add.xml +++ b/scripts/network/juniper/security-policy-add.xml @@ -15,6 +15,7 @@ +%tunnel% diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index b56e554894a..b7e9dd855e9 100755 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -73,6 +73,7 @@ import com.cloud.maint.dao.AgentUpgradeDaoImpl; import com.cloud.network.NetworkManagerImpl; import com.cloud.network.dao.FirewallRulesCidrsDaoImpl; import com.cloud.network.dao.FirewallRulesDaoImpl; +import com.cloud.network.dao.InlineLoadBalancerNicMapDaoImpl; import com.cloud.network.dao.IPAddressDaoImpl; import com.cloud.network.dao.LoadBalancerDaoImpl; import com.cloud.network.dao.LoadBalancerVMMapDaoImpl; @@ -270,8 +271,9 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com addDao("DcDetailsDao", DcDetailsDaoImpl.class); addDao("SwiftDao", SwiftDaoImpl.class); addDao("AgentTransferMapDao", HostTransferMapDaoImpl.class); + addDao("InlineLoadBalancerNicMapDao", InlineLoadBalancerNicMapDaoImpl.class); addDao("ElasticLbVmMap", ElasticLbVmMapDaoImpl.class); - + } @Override diff --git a/server/src/com/cloud/network/ExternalFirewallManager.java b/server/src/com/cloud/network/ExternalFirewallManager.java index 54dbedabd68..de17c7c031b 100644 --- a/server/src/com/cloud/network/ExternalFirewallManager.java +++ b/server/src/com/cloud/network/ExternalFirewallManager.java @@ -9,6 +9,7 @@ import java.util.List; import com.cloud.api.commands.AddExternalFirewallCmd; import com.cloud.api.commands.DeleteExternalFirewallCmd; import com.cloud.api.commands.ListExternalFirewallsCmd; +import com.cloud.dc.DataCenterVO; import com.cloud.exception.ResourceUnavailableException; import com.cloud.host.Host; import com.cloud.host.HostVO; @@ -29,6 +30,8 @@ public interface ExternalFirewallManager extends ExternalNetworkManager { public boolean manageGuestNetwork(boolean add, Network network, NetworkOffering offering) throws ResourceUnavailableException; public boolean applyFirewallRules(Network network, List rules) throws ResourceUnavailableException; + + public void applyStaticNatRuleForInlineLBRule(DataCenterVO zone, Network network, HostVO externalFirewall, boolean revoked, String publicIp, String privateIp) throws ResourceUnavailableException; public boolean applyIps(Network network, List ipAddresses) throws ResourceUnavailableException; diff --git a/server/src/com/cloud/network/ExternalNetworkManager.java b/server/src/com/cloud/network/ExternalNetworkManager.java index ce5e8b47d5f..ec5ed58b93c 100644 --- a/server/src/com/cloud/network/ExternalNetworkManager.java +++ b/server/src/com/cloud/network/ExternalNetworkManager.java @@ -18,5 +18,6 @@ import com.cloud.utils.net.NetUtils; import com.cloud.vm.NicVO; public interface ExternalNetworkManager extends Manager { - + public int getVlanOffset(DataCenter zone, int vlanTag); + public int getGloballyConfiguredCidrSize(); } diff --git a/server/src/com/cloud/network/ExternalNetworkManagerImpl.java b/server/src/com/cloud/network/ExternalNetworkManagerImpl.java index adeea6aecf9..41a5efc694b 100644 --- a/server/src/com/cloud/network/ExternalNetworkManagerImpl.java +++ b/server/src/com/cloud/network/ExternalNetworkManagerImpl.java @@ -24,13 +24,16 @@ import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.VlanDao; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.DetailVO; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDetailsDao; import com.cloud.host.dao.HostDao; import com.cloud.network.Network.GuestIpType; import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.InlineLoadBalancerNicMapDao; import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.rules.PortForwardingRuleVO; @@ -49,7 +52,11 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExecutionException; import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.NicVO; +import com.cloud.vm.Nic.ReservationStrategy; +import com.cloud.vm.Nic.State; import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; @Local(value = {ExternalNetworkManager.class}) public class ExternalNetworkManagerImpl implements ExternalNetworkManager { @@ -65,13 +72,16 @@ public class ExternalNetworkManagerImpl implements ExternalNetworkManager { @Inject AccountDao _accountDao; @Inject DomainRouterDao _routerDao; @Inject IPAddressDao _ipAddressDao; + @Inject VlanDao _vlanDao; @Inject UserStatisticsDao _userStatsDao; @Inject NetworkDao _networkDao; @Inject PortForwardingRulesDao _portForwardingRulesDao; @Inject LoadBalancerDao _loadBalancerDao; + @Inject InlineLoadBalancerNicMapDao _inlineLoadBalancerNicMapDao; @Inject ConfigurationDao _configDao; @Inject HostDetailsDao _detailsDao; @Inject NetworkOfferingDao _networkOfferingDao; + @Inject NicDao _nicDao; ScheduledExecutorService _executor; int _externalNetworkStatsInterval; @@ -126,7 +136,39 @@ public class ExternalNetworkManagerImpl implements ExternalNetworkManager { } } - protected class ExternalNetworkUsageTask implements Runnable { + public NicVO savePlaceholderNic(Network network, String ipAddress) { + NicVO nic = new NicVO(null, null, network.getId(), null); + nic.setIp4Address(ipAddress); + nic.setReservationStrategy(ReservationStrategy.PlaceHolder); + nic.setState(State.Reserved); + return _nicDao.persist(nic); + } + + protected boolean externalLoadBalancerIsInline(HostVO externalLoadBalancer) { + DetailVO detail = _detailsDao.findDetail(externalLoadBalancer.getId(), "inline"); + return (detail != null && detail.getValue().equals("true")); + } + + public int getGloballyConfiguredCidrSize() { + try { + String globalVlanBits = _configDao.getValue(Config.GuestVlanBits.key()); + return 8 + Integer.parseInt(globalVlanBits); + } catch (Exception e) { + throw new CloudRuntimeException("Failed to read the globally configured VLAN bits size."); + } + } + + public int getVlanOffset(DataCenter zone, int vlanTag) { + if (zone.getVnet() == null) { + throw new CloudRuntimeException("Could not find vlan range for zone " + zone.getName() + "."); + } + + String vlanRange[] = zone.getVnet().split("-"); + int lowestVlanTag = Integer.valueOf(vlanRange[0]); + return vlanTag - lowestVlanTag; + } + +protected class ExternalNetworkUsageTask implements Runnable { public ExternalNetworkUsageTask() { } @@ -180,15 +222,28 @@ public class ExternalNetworkManagerImpl implements ExternalNetworkManager { long newCurrentBytesReceived = 0; if (publicIp != null) { - long[] bytesSentAndReceived = answer.ipBytes.get(publicIp); - statsEntryIdentifier += ", public IP: " + publicIp; - - if (bytesSentAndReceived == null) { - s_logger.debug("Didn't get an external network usage answer for public IP " + publicIp); - } else { - newCurrentBytesSent += bytesSentAndReceived[0]; - newCurrentBytesReceived += bytesSentAndReceived[1]; - } + long[] bytesSentAndReceived = null; + statsEntryIdentifier += ", public IP: " + publicIp; + + if (host.getType().equals(Host.Type.ExternalLoadBalancer) && externalLoadBalancerIsInline(host)) { + // Look up stats for the guest IP address that's mapped to the public IP address + InlineLoadBalancerNicMapVO mapping = _inlineLoadBalancerNicMapDao.findByPublicIpAddress(publicIp); + + if (mapping != null) { + NicVO nic = _nicDao.findById(mapping.getNicId()); + String loadBalancingIpAddress = nic.getIp4Address(); + bytesSentAndReceived = answer.ipBytes.get(loadBalancingIpAddress); + } + } else { + bytesSentAndReceived = answer.ipBytes.get(publicIp); + } + + if (bytesSentAndReceived == null) { + s_logger.debug("Didn't get an external network usage answer for public IP " + publicIp); + } else { + newCurrentBytesSent += bytesSentAndReceived[0]; + newCurrentBytesReceived += bytesSentAndReceived[1]; + } } else { URI broadcastURI = network.getBroadcastUri(); if (broadcastURI == null) { diff --git a/server/src/com/cloud/network/F5BigIpManagerImpl.java b/server/src/com/cloud/network/F5BigIpManagerImpl.java index 3e75bf86ab1..13554377840 100644 --- a/server/src/com/cloud/network/F5BigIpManagerImpl.java +++ b/server/src/com/cloud/network/F5BigIpManagerImpl.java @@ -18,6 +18,7 @@ import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; import com.cloud.agent.api.routing.IpAssocCommand; import com.cloud.agent.api.routing.LoadBalancerConfigCommand; +import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.api.commands.AddExternalLoadBalancerCmd; @@ -31,9 +32,11 @@ import com.cloud.dc.dao.DataCenterDao; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.DetailVO; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.dao.InlineLoadBalancerNicMapDao; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.resource.F5BigIpResource; @@ -72,6 +75,8 @@ public class F5BigIpManagerImpl extends ExternalNetworkManagerImpl implements Ex ConfigurationManager _configMgr; @Inject AccountManager _accountMgr; + @Inject + ExternalFirewallManager _externalFirewallMgr; private static final org.apache.log4j.Logger s_logger = Logger.getLogger(F5BigIpManagerImpl.class); @@ -108,6 +113,7 @@ public class F5BigIpManagerImpl extends ExternalNetworkManagerImpl implements Ex String publicInterface = params.get("publicinterface"); String privateInterface = params.get("privateinterface"); String numRetries = params.get("numretries"); + boolean inline = Boolean.parseBoolean(params.get("inline")); if (publicInterface == null) { throw new InvalidParameterValueException("Please specify a public interface."); @@ -134,6 +140,7 @@ public class F5BigIpManagerImpl extends ExternalNetworkManagerImpl implements Ex hostDetails.put("numRetries", numRetries); hostDetails.put("guid", guid); hostDetails.put("name", guid); + hostDetails.put("inline", String.valueOf(inline)); try { resource.configure(guid, hostDetails); @@ -196,6 +203,7 @@ public class F5BigIpManagerImpl extends ExternalNetworkManagerImpl implements Ex response.setPublicInterface(lbDetails.get("publicInterface")); response.setPrivateInterface(lbDetails.get("privateInterface")); response.setNumRetries(lbDetails.get("numRetries")); + response.setInline(lbDetails.get("inline")); return response; } @@ -221,7 +229,7 @@ public class F5BigIpManagerImpl extends ExternalNetworkManagerImpl implements Ex String guestVlanNetmask = NetUtils.cidr2Netmask(guestConfig.getCidr()); Integer networkRate = _networkMgr.getNetworkRate(guestConfig.getId(), null); - IpAddressTO ip = new IpAddressTO(null, add, false, true, String.valueOf(guestVlanTag), selfIp, guestVlanNetmask, null, null, networkRate, false); + IpAddressTO ip = new IpAddressTO(guestConfig.getAccountId(), null, add, false, true, String.valueOf(guestVlanTag), selfIp, guestVlanNetmask, null, null, networkRate, false); IpAddressTO[] ips = new IpAddressTO[1]; ips[0] = ip; IpAssocCommand cmd = new IpAssocCommand(ips); @@ -238,11 +246,7 @@ public class F5BigIpManagerImpl extends ExternalNetworkManagerImpl implements Ex List reservedIpAddressesForGuestNetwork = _nicDao.listIpAddressInNetwork(guestConfig.getId()); if (add && (!reservedIpAddressesForGuestNetwork.contains(selfIp))) { // Insert a new NIC for this guest network to reserve the self IP - NicVO nic = new NicVO(null, null, guestConfig.getId(), null); - nic.setIp4Address(selfIp); - nic.setReservationStrategy(ReservationStrategy.PlaceHolder); - nic.setState(Nic.State.Reserved); - _nicDao.persist(nic); + savePlaceholderNic(guestConfig, selfIp); } Account account = _accountDao.findByIdIncludingRemoved(guestConfig.getAccountId()); @@ -262,6 +266,18 @@ public class F5BigIpManagerImpl extends ExternalNetworkManagerImpl implements Ex if (externalLoadBalancer == null) { return false; } + + // If the load balancer is inline, find the external firewall in this zone + boolean externalLoadBalancerIsInline = externalLoadBalancerIsInline(externalLoadBalancer); + HostVO externalFirewall = null; + if (externalLoadBalancerIsInline) { + externalFirewall = getExternalNetworkAppliance(zoneId, Host.Type.ExternalFirewall); + if (externalFirewall == null) { + String msg = "External load balancer in zone " + zone.getName() + " is inline, but no external firewall in this zone."; + s_logger.error(msg); + throw new ResourceUnavailableException(msg, DataCenter.class, network.getDataCenterId()); + } + } if (network.getState() == Network.State.Allocated) { s_logger.debug("F5BigIpManager was asked to apply LB rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands."); @@ -276,7 +292,7 @@ public class F5BigIpManagerImpl extends ExternalNetworkManagerImpl implements Ex } } - LoadBalancerTO[] loadBalancers = new LoadBalancerTO[loadBalancingRules.size()]; + List loadBalancersToApply = new ArrayList(); for (int i = 0; i < loadBalancingRules.size(); i++) { LoadBalancingRule rule = loadBalancingRules.get(i); @@ -287,13 +303,73 @@ public class F5BigIpManagerImpl extends ExternalNetworkManagerImpl implements Ex int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); - LoadBalancerTO loadBalancer = new LoadBalancerTO(srcIp, srcPort, protocol, algorithm, revoked, false, destinations); - loadBalancers[i] = loadBalancer; + if (externalLoadBalancerIsInline) { + InlineLoadBalancerNicMapVO mapping = _inlineLoadBalancerNicMapDao.findByPublicIpAddress(srcIp); + NicVO loadBalancingIpNic = null; + + if (!revoked) { + if (mapping == null) { + // Acquire a new guest IP address and save it as the load balancing IP address + String loadBalancingIpAddress = _networkMgr.acquireGuestIpAddress(network, null); + + if (loadBalancingIpAddress == null) { + String msg = "Ran out of guest IP addresses."; + s_logger.error(msg); + throw new ResourceUnavailableException(msg, DataCenter.class, network.getDataCenterId()); + } + + // If a NIC doesn't exist for the load balancing IP address, create one + loadBalancingIpNic = _nicDao.findByIp4Address(loadBalancingIpAddress); + if (loadBalancingIpNic == null) { + loadBalancingIpNic = savePlaceholderNic(network, loadBalancingIpAddress); + } + + // Save a mapping between the source IP address and the load balancing IP address NIC + mapping = new InlineLoadBalancerNicMapVO(rule.getId(), srcIp, loadBalancingIpNic.getId()); + _inlineLoadBalancerNicMapDao.persist(mapping); + + // On the external firewall, create a static NAT rule between the source IP address and the load balancing IP address + _externalFirewallMgr.applyStaticNatRuleForInlineLBRule(zone, network, externalFirewall, revoked, srcIp, loadBalancingIpNic.getIp4Address()); + } else { + loadBalancingIpNic = _nicDao.findById(mapping.getNicId()); + } + } else { + if (mapping != null) { + // Find the NIC that the mapping refers to + loadBalancingIpNic = _nicDao.findById(mapping.getNicId()); + + // On the external firewall, delete the static NAT rule between the source IP address and the load balancing IP address + _externalFirewallMgr.applyStaticNatRuleForInlineLBRule(zone, network, externalFirewall, revoked, srcIp, loadBalancingIpNic.getIp4Address()); + + // Delete the mapping between the source IP address and the load balancing IP address + _inlineLoadBalancerNicMapDao.expunge(mapping.getId()); + + // Delete the NIC + _nicDao.expunge(loadBalancingIpNic.getId()); + } else { + s_logger.debug("Revoking a rule for an inline load balancer that has not been programmed yet."); + continue; + } + } + + // Change the source IP address for the load balancing rule to be the load balancing IP address + srcIp = loadBalancingIpNic.getIp4Address(); + } + + if (destinations != null && !destinations.isEmpty()) { + LoadBalancerTO loadBalancer = new LoadBalancerTO(srcIp, srcPort, protocol, algorithm, revoked, false, destinations); + loadBalancersToApply.add(loadBalancer); + } } - if (loadBalancers.length > 0) { - LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(loadBalancers); - Answer answer = _agentMgr.easySend(externalLoadBalancer.getId(), cmd); + if (loadBalancersToApply.size() > 0) { + int numLoadBalancersForCommand = loadBalancersToApply.size(); + LoadBalancerTO[] loadBalancersForCommand = loadBalancersToApply.toArray(new LoadBalancerTO[numLoadBalancersForCommand]); + LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(loadBalancersForCommand); + long guestVlanTag = Integer.parseInt(network.getBroadcastUri().getHost()); + cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, String.valueOf(guestVlanTag)); + + Answer answer = _agentMgr.easySend(externalLoadBalancer.getId(), cmd); if (answer == null || !answer.getResult()) { String details = (answer != null) ? answer.getDetails() : "details unavailable"; String msg = "Unable to apply load balancer rules to the F5 BigIp appliance in zone " + zone.getName() + " due to: " + details + "."; @@ -304,4 +380,5 @@ public class F5BigIpManagerImpl extends ExternalNetworkManagerImpl implements Ex return true; } + } diff --git a/server/src/com/cloud/network/JuniperSrxManagerImpl.java b/server/src/com/cloud/network/JuniperSrxManagerImpl.java index 75c02674306..19dafb465e8 100644 --- a/server/src/com/cloud/network/JuniperSrxManagerImpl.java +++ b/server/src/com/cloud/network/JuniperSrxManagerImpl.java @@ -17,6 +17,7 @@ import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; import com.cloud.agent.api.routing.IpAssocCommand; +import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; import com.cloud.agent.api.routing.SetStaticNatRulesCommand; import com.cloud.agent.api.to.IpAddressTO; @@ -28,20 +29,27 @@ import com.cloud.api.commands.ListExternalFirewallsCmd; import com.cloud.configuration.ConfigurationManager; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; +import com.cloud.dc.Vlan; +import com.cloud.dc.VlanVO; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.VlanDao; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.DetailVO; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.network.Networks.TrafficType; import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.InlineLoadBalancerNicMapDao; import com.cloud.network.resource.JuniperSrxResource; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.StaticNatRule; +import com.cloud.network.rules.StaticNatRuleImpl; import com.cloud.offering.NetworkOffering; import com.cloud.server.api.response.ExternalFirewallResponse; import com.cloud.user.Account; @@ -75,6 +83,8 @@ public class JuniperSrxManagerImpl extends ExternalNetworkManagerImpl implements @Inject UserStatisticsDao _userStatsDao; @Inject + VlanDao _vlanDao; + @Inject ConfigurationManager _configMgr; @Inject AccountManager _accountMgr; @@ -119,11 +129,7 @@ public class JuniperSrxManagerImpl extends ExternalNetworkManagerImpl implements String numRetries = params.get("numretries"); String timeout = params.get("timeout"); - if (publicInterface != null) { - if (!publicInterface.contains(".")) { - publicInterface += ".0"; - } - } else { + if (publicInterface == null) { throw new InvalidParameterValueException("Please specify a public interface."); } @@ -300,31 +306,39 @@ public class JuniperSrxManagerImpl extends ExternalNetworkManagerImpl implements Account account = _accountDao.findByIdIncludingRemoved(network.getAccountId()); boolean sharedSourceNat = offering.isSharedSourceNatService(); - String sourceNatIp = null; + IPAddressVO sourceNatIp = null; if (!sharedSourceNat) { // Get the source NAT IP address for this network List sourceNatIps = _networkMgr.listPublicIpAddressesInVirtualNetwork(network.getAccountId(), zoneId, true, null); if (sourceNatIps.size() != 1) { String errorMsg = "JuniperSrxManager was unable to find the source NAT IP address for account " + account.getAccountName(); + s_logger.error(errorMsg); return true; } else { - sourceNatIp = sourceNatIps.get(0).getAddress().addr(); + sourceNatIp = sourceNatIps.get(0); } } // Send a command to the external firewall to implement or shutdown the guest network long guestVlanTag = Long.parseLong(network.getBroadcastUri().getHost()); String guestVlanGateway = network.getGateway(); - String guestVlanNetmask = NetUtils.cidr2Netmask(network.getCidr()); + String guestVlanCidr = network.getCidr(); + String sourceNatIpAddress = sourceNatIp.getAddress().addr(); + + VlanVO publicVlan = _vlanDao.findById(sourceNatIp.getVlanId()); + String publicVlanTag = publicVlan.getVlanTag(); // Get network rate Integer networkRate = _networkMgr.getNetworkRate(network.getId(), null); - IpAddressTO ip = new IpAddressTO(sourceNatIp, add, false, !sharedSourceNat, String.valueOf(guestVlanTag), guestVlanGateway, guestVlanNetmask, null, null, networkRate, false); + IpAddressTO ip = new IpAddressTO(account.getId(), sourceNatIpAddress, add, false, !sharedSourceNat, publicVlanTag, null, null, null, null, networkRate, sourceNatIp.isOneToOneNat()); IpAddressTO[] ips = new IpAddressTO[1]; ips[0] = ip; IpAssocCommand cmd = new IpAssocCommand(ips); + cmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_GATEWAY, guestVlanGateway); + cmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR, guestVlanCidr); + cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, String.valueOf(guestVlanTag)); Answer answer = _agentMgr.easySend(externalFirewall.getId(), cmd); if (answer == null || !answer.getResult()) { @@ -338,11 +352,17 @@ public class JuniperSrxManagerImpl extends ExternalNetworkManagerImpl implements List reservedIpAddressesForGuestNetwork = _nicDao.listIpAddressInNetwork(network.getId()); if (add && (!reservedIpAddressesForGuestNetwork.contains(network.getGateway()))) { // Insert a new NIC for this guest network to reserve the gateway address - NicVO nic = new NicVO(null, null, network.getId(), null); - nic.setIp4Address(network.getGateway()); - nic.setReservationStrategy(ReservationStrategy.PlaceHolder); - nic.setState(State.Reserved); - _nicDao.persist(nic); + savePlaceholderNic(network, network.getGateway()); + } + + // Delete any mappings used for inline external load balancers in this network + List nicsInNetwork = _nicDao.listByNetworkId(network.getId()); + for (NicVO nic : nicsInNetwork) { + InlineLoadBalancerNicMapVO mapping = _inlineLoadBalancerNicMapDao.findByNicId(nic.getId()); + if (mapping != null) { + _nicDao.expunge(mapping.getNicId()); + _inlineLoadBalancerNicMapDao.expunge(mapping.getId()); + } } String action = add ? "implemented" : "shut down"; @@ -350,6 +370,20 @@ public class JuniperSrxManagerImpl extends ExternalNetworkManagerImpl implements return true; } + + public void applyStaticNatRuleForInlineLBRule(DataCenterVO zone, Network network, HostVO externalFirewall, boolean revoked, String publicIp, String privateIp) throws ResourceUnavailableException { + List staticNatRules = new ArrayList(); + IPAddressVO ipVO = _ipAddressDao.listByDcIdIpAddress(zone.getId(), publicIp).get(0); + VlanVO vlan = _vlanDao.findById(ipVO.getVlanId()); + FirewallRuleVO fwRule = new FirewallRuleVO(null, ipVO.getId(), -1, -1, "any", network.getId(), network.getAccountId(), network.getDomainId(), Purpose.StaticNat, null, null, null, null); + FirewallRule.State state = !revoked ? FirewallRule.State.Add : FirewallRule.State.Revoke; + fwRule.setState(state); + StaticNatRule rule = new StaticNatRuleImpl(fwRule, privateIp); + StaticNatRuleTO ruleTO = new StaticNatRuleTO(rule, vlan.getVlanTag(), publicIp, privateIp); + staticNatRules.add(ruleTO); + + applyStaticNatRules(staticNatRules, zone, externalFirewall.getId()); + } @Override public boolean applyFirewallRules(Network network, List rules) throws ResourceUnavailableException { @@ -372,12 +406,14 @@ public class JuniperSrxManagerImpl extends ExternalNetworkManagerImpl implements for (FirewallRule rule : rules) { IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId()); + Vlan vlan = _vlanDao.findById(sourceIp.getVlanId()); + if (rule.getPurpose() == Purpose.StaticNat) { StaticNatRule staticNatRule = (StaticNatRule) rule; - StaticNatRuleTO ruleTO = new StaticNatRuleTO(staticNatRule, sourceIp.getAddress().addr(), staticNatRule.getDestIpAddress()); + StaticNatRuleTO ruleTO = new StaticNatRuleTO(staticNatRule, vlan.getVlanTag(), sourceIp.getAddress().addr(), staticNatRule.getDestIpAddress()); staticNatRules.add(ruleTO); } else if (rule.getPurpose() == Purpose.PortForwarding) { - PortForwardingRuleTO ruleTO = new PortForwardingRuleTO((PortForwardingRule) rule, sourceIp.getAddress().addr()); + PortForwardingRuleTO ruleTO = new PortForwardingRuleTO((PortForwardingRule) rule, vlan.getVlanTag(), sourceIp.getAddress().addr()); portForwardingRules.add(ruleTO); } } diff --git a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java index c774d8815a1..9e16c53eada 100644 --- a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -1,5 +1,20 @@ /** - * Copyright (C) 2011 Cloud.com, Inc. All rights reserved. + * * Copyright (C) 2011 Citrix Systems, 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.guru; @@ -8,7 +23,6 @@ import java.util.List; import javax.ejb.Local; -import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenter; import com.cloud.dc.dao.DataCenterDao; @@ -19,6 +33,7 @@ import com.cloud.event.EventUtils; import com.cloud.event.EventVO; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.network.ExternalNetworkManager; import com.cloud.network.Network; import com.cloud.network.Network.State; import com.cloud.network.NetworkManager; @@ -27,11 +42,14 @@ import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.dao.NetworkDao; import com.cloud.network.ovs.OvsNetworkManager; import com.cloud.network.ovs.OvsTunnelManager; +import com.cloud.network.rules.PortForwardingRuleVO; +import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.offering.NetworkOffering; import com.cloud.user.Account; import com.cloud.user.UserContext; import com.cloud.utils.component.Inject; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; import com.cloud.vm.Nic.ReservationStrategy; import com.cloud.vm.NicProfile; @@ -46,12 +64,16 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { @Inject NetworkManager _networkMgr; @Inject + ExternalNetworkManager _externalNetworkMgr; + @Inject NetworkDao _networkDao; @Inject DataCenterDao _zoneDao; @Inject ConfigurationDao _configDao; @Inject + PortForwardingRulesDao _pfRulesDao; + @Inject OvsNetworkManager _ovsNetworkMgr; @Inject OvsTunnelManager _tunnelMgr; @@ -108,12 +130,12 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { } // Determine the offset from the lowest vlan tag - int offset = getVlanOffset(zone, vlanTag); + int offset = _externalNetworkMgr.getVlanOffset(zone, vlanTag); // Determine the new gateway and CIDR String[] oldCidr = config.getCidr().split("/"); String oldCidrAddress = oldCidr[0]; - int cidrSize = getGloballyConfiguredCidrSize(); + int cidrSize = _externalNetworkMgr.getGloballyConfiguredCidrSize(); // If the offset has more bits than there is room for, return null long bitsInOffset = 32 - Integer.numberOfLeadingZeros(offset); @@ -130,10 +152,21 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { List nicsInNetwork = _nicDao.listByNetworkId(config.getId()); for (NicVO nic : nicsInNetwork) { if (nic.getIp4Address() != null) { - long ipMask = NetUtils.ip2Long(nic.getIp4Address()) & ~(0xffffffffffffffffl << (32 - cidrSize)); + long ipMask = getIpMask(nic.getIp4Address(), cidrSize); nic.setIp4Address(NetUtils.long2Ip(newCidrAddress | ipMask)); _nicDao.persist(nic); } + } + + // Mask the destination address of all port forwarding rules in this network with the new guest VLAN offset + List pfRulesInNetwork = _pfRulesDao.listByNetwork(config.getId()); + for (PortForwardingRuleVO pfRule : pfRulesInNetwork) { + if (pfRule.getDestinationIpAddress() != null) { + long ipMask = getIpMask(pfRule.getDestinationIpAddress().addr(), cidrSize); + String maskedDestinationIpAddress = NetUtils.long2Ip(newCidrAddress | ipMask); + pfRule.setDestinationIpAddress(new Ip(maskedDestinationIpAddress)); + _pfRulesDao.update(pfRule.getId(), pfRule); + } } return implemented; @@ -195,7 +228,7 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { nic.setDns2(dc.getDns2()); nic.setNetmask(NetUtils.cidr2Netmask(config.getCidr())); long cidrAddress = NetUtils.ip2Long(config.getCidr().split("/")[0]); - int cidrSize = getGloballyConfiguredCidrSize(); + int cidrSize = _externalNetworkMgr.getGloballyConfiguredCidrSize(); nic.setGateway(config.getGateway()); if (nic.getIp4Address() == null) { @@ -229,23 +262,9 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { return super.release(nic, vm, reservationId); } } - - private int getGloballyConfiguredCidrSize() { - try { - String globalVlanBits = _configDao.getValue(Config.GuestVlanBits.key()); - return 8 + Integer.parseInt(globalVlanBits); - } catch (Exception e) { - throw new CloudRuntimeException("Failed to read the globally configured VLAN bits size."); - } + + private long getIpMask(String ipAddress, long cidrSize) { + return NetUtils.ip2Long(ipAddress) & ~(0xffffffffffffffffl << (32 - cidrSize)); } - private int getVlanOffset(DataCenter zone, int vlanTag) { - if (zone.getVnet() == null) { - throw new CloudRuntimeException("Could not find vlan range for zone " + zone.getName() + "."); - } - - String vlanRange[] = zone.getVnet().split("-"); - int lowestVlanTag = Integer.valueOf(vlanRange[0]); - return vlanTag - lowestVlanTag; - } } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 8c269b75792..2630f15ce99 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -454,13 +454,17 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager, throw new CloudRuntimeException("Unable to add rule for ip address id=" + newRule.getSourceIpAddressId(), e); } finally { if (!success) { + txn.start(); - //no need to apply the rule as it wasn't programmed on the backend yet - _firewallMgr.revokeRelatedFirewallRule(newRule.getId(), false); + _firewallDao.remove(_firewallDao.findByRelatedId(newRule.getId()).getId()); _lbDao.remove(newRule.getId()); txn.commit(); + + _lbDao.remove(newRule.getId()); } } + + } @Override @@ -488,10 +492,8 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager, for (LoadBalancerVO lb : lbs) { List dstList = getExistingDestinations(lb.getId()); - if (dstList != null && !dstList.isEmpty()) { - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList); - rules.add(loadBalancing); - } + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList); + rules.add(loadBalancing); } if (!_networkMgr.applyRules(rules, false)) { diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index e1726ef24bd..b44a4c25b9b 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1506,8 +1506,11 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian List lbRules = new ArrayList(); for (LoadBalancerVO lb : lbs) { List dstList = _lbMgr.getExistingDestinations(lb.getId()); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList); - lbRules.add(loadBalancing); + + if (dstList != null && !dstList.isEmpty()) { + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList); + lbRules.add(loadBalancing); + } } s_logger.debug("Found " + lbRules.size() + " load balancing rule(s) to apply as a part of domR " + router + " start."); @@ -1968,7 +1971,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian String vmGuestAddress = null; - IpAddressTO ip = new IpAddressTO(ipAddr.getAddress().addr(), add, firstIP, sourceNat, vlanId, vlanGateway, vlanNetmask, vifMacAddress, vmGuestAddress, networkRate, ipAddr.isOneToOneNat()); + IpAddressTO ip = new IpAddressTO(ipAddr.getAccountId(), ipAddr.getAddress().addr(), add, firstIP, sourceNat, vlanId, vlanGateway, vlanNetmask, vifMacAddress, vmGuestAddress, networkRate, ipAddr.isOneToOneNat()); ip.setTrafficType(network.getTrafficType()); ip.setNetworkTags(network.getTags()); ipsToSend[i++] = ip; @@ -1991,7 +1994,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian rulesTO = new ArrayList(); for (PortForwardingRule rule : rules) { IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId()); - PortForwardingRuleTO ruleTO = new PortForwardingRuleTO(rule, sourceIp.getAddress().addr()); + PortForwardingRuleTO ruleTO = new PortForwardingRuleTO(rule, null, sourceIp.getAddress().addr()); rulesTO.add(ruleTO); } } @@ -2012,7 +2015,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian rulesTO = new ArrayList(); for (StaticNatRule rule : rules) { IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId()); - StaticNatRuleTO ruleTO = new StaticNatRuleTO(rule, sourceIp.getAddress().addr(), rule.getDestIpAddress()); + StaticNatRuleTO ruleTO = new StaticNatRuleTO(rule, null, sourceIp.getAddress().addr(), rule.getDestIpAddress()); rulesTO.add(ruleTO); } } @@ -2354,7 +2357,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian rulesTO = new ArrayList(); for (FirewallRule rule : rules) { IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId()); - FirewallRuleTO ruleTO = new FirewallRuleTO(rule, sourceIp.getAddress().addr()); + FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, sourceIp.getAddress().addr()); rulesTO.add(ruleTO); } } @@ -2446,7 +2449,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian 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); + StaticNatRuleTO ruleTO = new StaticNatRuleTO(0, null, sourceIp.getAddress().addr(), null, null, rule.getDestIpAddress(), null, null, null, rule.isForRevoke(), false); rulesTO.add(ruleTO); } } diff --git a/server/src/com/cloud/network/rules/PortForwardingRuleVO.java b/server/src/com/cloud/network/rules/PortForwardingRuleVO.java index d6a26dac192..63fc68a862b 100644 --- a/server/src/com/cloud/network/rules/PortForwardingRuleVO.java +++ b/server/src/com/cloud/network/rules/PortForwardingRuleVO.java @@ -51,7 +51,7 @@ public class PortForwardingRuleVO extends FirewallRuleVO implements PortForwardi public PortForwardingRuleVO() { } - + public PortForwardingRuleVO(String xId, long srcIpId, int srcPortStart, int srcPortEnd, Ip dstIp, int dstPortStart, int dstPortEnd, String protocol, long networkId, long accountId, long domainId, long instanceId) { super(xId, srcIpId, srcPortStart, srcPortEnd, protocol, networkId, accountId, domainId, Purpose.PortForwarding, null, null, null, null); this.destinationIpAddress = dstIp; @@ -67,6 +67,11 @@ public class PortForwardingRuleVO extends FirewallRuleVO implements PortForwardi @Override public Ip getDestinationIpAddress() { return destinationIpAddress; + } + + @Override + public void setDestinationIpAddress(Ip destinationIpAddress) { + this.destinationIpAddress = destinationIpAddress; } @Override @@ -88,5 +93,6 @@ public class PortForwardingRuleVO extends FirewallRuleVO implements PortForwardi public Long getRelated() { return null; } + } diff --git a/server/src/com/cloud/server/api/response/ExternalLoadBalancerResponse.java b/server/src/com/cloud/server/api/response/ExternalLoadBalancerResponse.java index a003b5c5799..dfc7323b9c7 100644 --- a/server/src/com/cloud/server/api/response/ExternalLoadBalancerResponse.java +++ b/server/src/com/cloud/server/api/response/ExternalLoadBalancerResponse.java @@ -31,6 +31,9 @@ public class ExternalLoadBalancerResponse extends BaseResponse { @SerializedName(ApiConstants.NUM_RETRIES) @Param(description="the number of times to retry requests to the external load balancer") private String numRetries; + + @SerializedName(ApiConstants.INLINE) @Param(description="configures the external load balancer to be inline with an external firewall") + private String inline; public Long getId() { return id; @@ -88,4 +91,11 @@ public class ExternalLoadBalancerResponse extends BaseResponse { this.numRetries = numRetries; } + public String getInline() { + return inline; + } + + public void setInline(String inline) { + this.inline = inline; + } } diff --git a/server/src/com/cloud/vm/dao/NicDao.java b/server/src/com/cloud/vm/dao/NicDao.java index e2408d08bfb..35f3e6f1f98 100644 --- a/server/src/com/cloud/vm/dao/NicDao.java +++ b/server/src/com/cloud/vm/dao/NicDao.java @@ -42,4 +42,6 @@ public interface NicDao extends GenericDao { void removeNicsForInstance(long instanceId); NicVO findByNetworkIdAndType(long networkId, VirtualMachine.Type vmType); + + NicVO findByIp4Address(String ip4Address); } diff --git a/server/src/com/cloud/vm/dao/NicDaoImpl.java b/server/src/com/cloud/vm/dao/NicDaoImpl.java index a8c89b5cadf..d030d02ffdd 100644 --- a/server/src/com/cloud/vm/dao/NicDaoImpl.java +++ b/server/src/com/cloud/vm/dao/NicDaoImpl.java @@ -46,6 +46,7 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { AllFieldsSearch.and("instance", AllFieldsSearch.entity().getInstanceId(), Op.EQ); AllFieldsSearch.and("network", AllFieldsSearch.entity().getNetworkId(), Op.EQ); AllFieldsSearch.and("vmType", AllFieldsSearch.entity().getVmType(), Op.EQ); + AllFieldsSearch.and("address", AllFieldsSearch.entity().getIp4Address(), Op.EQ); AllFieldsSearch.done(); IpSearch = createSearchBuilder(String.class); @@ -114,4 +115,11 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { sc.setParameters("vmType", vmType); return findOneBy(sc); } + + @Override + public NicVO findByIp4Address(String ip4Address) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("address", ip4Address); + return findOneBy(sc); + } } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index f6489f9e1ea..b2bc889bbe3 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -61,6 +61,7 @@ DROP TABLE IF EXISTS `cloud`.`sync_queue`; DROP TABLE IF EXISTS `cloud`.`sync_queue_item`; DROP TABLE IF EXISTS `cloud`.`security_group_vm_map`; DROP TABLE IF EXISTS `cloud`.`load_balancer_vm_map`; +DROP TABLE IF EXISTS `cloud`.`load_balancer_inline_ip_map`; DROP TABLE IF EXISTS `cloud`.`storage_pool`; DROP TABLE IF EXISTS `cloud`.`storage_pool_host_ref`; DROP TABLE IF EXISTS `cloud`.`template_spool_ref`; @@ -630,6 +631,17 @@ CREATE TABLE `cloud`.`load_balancer_vm_map` ( CONSTRAINT `fk_load_balancer_vm_map__instance_id` FOREIGN KEY(`instance_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `cloud`.`inline_load_balancer_nic_map` ( + `id` bigint unsigned NOT NULL auto_increment, + `load_balancer_id` bigint unsigned NOT NULL, + `public_ip_address` char(40) NOT NULL, + `nic_id` bigint unsigned NULL COMMENT 'nic id', + PRIMARY KEY (`id`), + UNIQUE KEY (`nic_id`), + CONSTRAINT `fk_inline_load_balancer_nic_map__load_balancer_id` FOREIGN KEY(`load_balancer_id`) REFERENCES `load_balancing_rules`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_inline_load_balancer_nic_map__nic_id` FOREIGN KEY(`nic_id`) REFERENCES `nics`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CREATE TABLE `cloud`.`port_forwarding_rules` ( `id` bigint unsigned NOT NULL COMMENT 'id', `instance_id` bigint unsigned NOT NULL COMMENT 'vm instance id',