mirror of https://github.com/apache/cloudstack.git
Netris FR1b: Support Remote Access VPN and Site-to-Site VPN in VPC VR (#41)
* Static Routes: support nexthop * Update api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateStaticRouteCmd.java Co-authored-by: Pearl Dsilva <pearl1594@gmail.com> * PR#10064 VR: apply iptables rules when add/remove static routes * PR#10065 UI: fix cannot open 'Edit tags' modal for static routes * PR#10066 Static Routes: fix check on wrong global configuration * PR#10067 VR: fix site-2-site VPN if split connections is enabled * PR#10081 server: do not allocate nic on public network for NSX VPC VR * PR#10082 UI: create VPC network offering with conserve mode * PR#10083 VR: allow outgoing traffic from RAS/VPN clients * PR#10086 server: fix typo removeaccessvpn in VirtualRouterElement * server: Add check on Public IP for remote access VPN * Revert "PR#10083 VR: allow outgoing traffic from RAS/VPN clients" This reverts commit 2f9b9f428947cac91de322fbdf4a980902a1c0a0. * VPC: fetch same used IP for domain router if VR is not Source NAT * VR: pass has_public_network to VR and configure RA/S2S VPN left peers * Revert "PR#10081 server: do not allocate nic on public network for NSX VPC VR" This reverts commit 809e269ed6b361d9df1fcef6537762c5612863e0. * VPC: fetch same used IP for domain router if VR is not Source NAT (v2) * VR: fix /etc/hosts and nameservers in dnsmasq.conf if VPC VR is not guest gateway prior to this PR ``` root@r-1167-VM:~# cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 r-1167-VM ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.21.1.33 dummy-vpc-vpn-001 172.21.1.1 r-1167-VM data-server root@r-1167-VM:~# cat /etc/dnsmasq.d/cloud.conf dhcp-hostsfile=/etc/dhcphosts.txt listen-address=127.0.0.1,172.21.1.234 dhcp-range=set:interface-eth1-0,172.21.1.234,static dhcp-option=tag:interface-eth1-0,15,cs2cloud.internal dhcp-option=tag:interface-eth1-0,6,172.21.1.1,10.0.32.1,8.8.8.8 dhcp-option=tag:interface-eth1-0,3,172.21.1.1 dhcp-option=eth1,26,1500 dhcp-option=tag:interface-eth1-0,1,255.255.255.0 ``` the lines should be ``` 172.21.1.234 r-1167-VM data-server dhcp-option=tag:interface-eth1-0,6,10.0.32.1,8.8.8.8 ``` * server: Enable static NAT for Domain router if it is not Source NAT * server: Enable static NAT for Domain router on UI * server: assign Public IP to VPC VR and enable static nat if VR is not Source NAT * server: configure dns1 if VR is not Source NAT * server: remove check on Firewall service when list network service providers * UI: remove dot from message.enabled.vpn * systemvm: add default route via first guest gateway if VR does not have public IP/interface * VR: add fw_dhcpserver for shared network * VR: pass has_public_network to VR and configure RA/S2S VPN left peers (v2) * UI: fix request error when create a VPC tier in a non-Netris/NSX env * systemvm: add default route via first guest gateway (v2) * VR: configure iptables rules for S2S vpn on first guest interface * VR: allow FORWARD to guest interfaces if VR is not Public * VR: configure remote access vpn on first guest interface if not public * VR: fix error 789 in RA VPN client when both RA and S2S are configured * server: Apply Static Route for RA/S2S VPN in VPC VR * VR: do not set mark for Public interface when VR is not really public * VPN: do not disable static nat if it is used by a RA/S2S VPN * server: skip check on network conserve mode if disable/enable RA VPN on Router IP * server: set forRouter to false when release a IP * VR: diable IP spoofing protection on default guest network * VR: fix iptables rules only when only S2S vpn is enabled * UI: show 'VPN Connections' section * VPC: new methods to configure/reconfigure Static NAT for VPC VR * API: set Type in ip address response to DomainRouter if it is used by VR * server: do not allow IP release if it is used by RA or S2S VPN gateway * VR: check if interface is added * VR: add default route only when ip is associated to first guest interface * VR: fix ipsec conf for l2tp and s2s vpn * server: save placeholder IP for VPC VR to fix the new VR IP when vpc tier is auto-shutdown * server: get non-placeholder NIC for VPC VR * VR: wait 15 seconds after starting password server * server: fix unable to configure static nat due to 'invalid virtual machine id' * UI: fix link of router in info card * VPC: apply static route for VPC VPN if needed (refactoring) * server: fix VR IP of first VPC tier is the VM gateway * server: update or remove all existing static routes when shutdown a network * server: update ipaddress after disabling static nat to fix vpc deletion issue * servr: disable remote access VPN as part of VPC dstroy * server: apply static routes when implement a vpc tier * server: apply static routes even if next hop is null * server: fix Cannot invoke "com.cloud.vm.NicProfile.getRequestedIPv4()" because "requested" is null * Netris: Update Vpn provider to VpcVirtualRouter * Netris: Add Vpn service to network offerings and networks * server: fix CIDR of VPN ip range * server: set isVrGuestGateway by SoureNat/Gateway service with Provider.VPCVirtualRouter * VR: password server takes 10-15 seconds to start if VR IP is not configured in /etc/hosts * Netris: add back routesPutBody.setStateStatus * engine/schema: remove SQL changes in schema-41910to42000.sql --------- Co-authored-by: Pearl Dsilva <pearl1594@gmail.com>
This commit is contained in:
parent
5ac35a2d8b
commit
8659d9691b
|
|
@ -99,4 +99,5 @@ public interface IpAddress extends ControlledEntity, Identity, InternalIdentity,
|
|||
|
||||
boolean isForSystemVms();
|
||||
|
||||
boolean isForRouter();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import org.apache.cloudstack.api.InternalIdentity;
|
|||
|
||||
public interface Site2SiteVpnConnection extends ControlledEntity, InternalIdentity, Displayable {
|
||||
enum State {
|
||||
Pending, Connecting, Connected, Disconnected, Error,
|
||||
Pending, Connecting, Connected, Disconnected, Error, Removed
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ public interface StaticRoute extends ControlledEntity, Identity, InternalIdentit
|
|||
/**
|
||||
* @return
|
||||
*/
|
||||
long getVpcGatewayId();
|
||||
Long getVpcGatewayId();
|
||||
|
||||
String getNextHop();
|
||||
|
||||
/**
|
||||
* @return
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ public class StaticRouteProfile implements StaticRoute {
|
|||
private String targetCidr;
|
||||
private long accountId;
|
||||
private long domainId;
|
||||
private long gatewayId;
|
||||
private Long gatewayId;
|
||||
private String nextHop;
|
||||
private StaticRoute.State state;
|
||||
private long vpcId;
|
||||
String vlanTag;
|
||||
|
|
@ -46,6 +47,18 @@ public class StaticRouteProfile implements StaticRoute {
|
|||
ipAddress = gateway.getIp4Address();
|
||||
}
|
||||
|
||||
public StaticRouteProfile(StaticRoute staticRoute) {
|
||||
id = staticRoute.getId();
|
||||
uuid = staticRoute.getUuid();
|
||||
targetCidr = staticRoute.getCidr();
|
||||
accountId = staticRoute.getAccountId();
|
||||
domainId = staticRoute.getDomainId();
|
||||
gatewayId = staticRoute.getVpcGatewayId();
|
||||
state = staticRoute.getState();
|
||||
vpcId = staticRoute.getVpcId();
|
||||
gateway = staticRoute.getNextHop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAccountId() {
|
||||
return accountId;
|
||||
|
|
@ -57,10 +70,15 @@ public class StaticRouteProfile implements StaticRoute {
|
|||
}
|
||||
|
||||
@Override
|
||||
public long getVpcGatewayId() {
|
||||
public Long getVpcGatewayId() {
|
||||
return gatewayId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNextHop() {
|
||||
return nextHop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCidr() {
|
||||
return targetCidr;
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ public interface VpcService {
|
|||
* @param cidr
|
||||
* @return
|
||||
*/
|
||||
StaticRoute createStaticRoute(long gatewayId, String cidr) throws NetworkRuleConflictException;
|
||||
StaticRoute createStaticRoute(Long gatewayId, Long vpcId, String nextHop, String cidr) throws NetworkRuleConflictException;
|
||||
|
||||
/**
|
||||
* Lists static routes based on parameters passed to the call
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ public class ApiConstants {
|
|||
public static final String PREVIOUS_OWNER_ID = "previousownerid";
|
||||
public static final String PREVIOUS_OWNER_NAME = "previousownername";
|
||||
public static final String NEXT_ACL_RULE_ID = "nextaclruleid";
|
||||
public static final String NEXT_HOP = "nexthop";
|
||||
public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash";
|
||||
public static final String IMAGE_PATH = "imagepath";
|
||||
public static final String INSTANCE_CONVERSION_SUPPORTED = "instanceconversionsupported";
|
||||
|
|
@ -863,6 +864,8 @@ public class ApiConstants {
|
|||
public static final String NETWORK = "network";
|
||||
public static final String VPC_ID = "vpcid";
|
||||
public static final String VPC_NAME = "vpcname";
|
||||
public static final String VPC_GATEWAY_ID = "vpcgatewayid";
|
||||
public static final String VPC_GATEWAY_IP = "vpcgatewayip";
|
||||
public static final String GATEWAY_ID = "gatewayid";
|
||||
public static final String CAN_USE_FOR_DEPLOY = "canusefordeploy";
|
||||
public static final String RESOURCE_IDS = "resourceids";
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.apache.cloudstack.api.Parameter;
|
|||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.PrivateGatewayResponse;
|
||||
import org.apache.cloudstack.api.response.StaticRouteResponse;
|
||||
import org.apache.cloudstack.api.response.VpcResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
|
||||
import com.cloud.event.EventTypes;
|
||||
|
|
@ -45,20 +46,38 @@ public class CreateStaticRouteCmd extends BaseAsyncCreateCmd {
|
|||
@Parameter(name = ApiConstants.GATEWAY_ID,
|
||||
type = CommandType.UUID,
|
||||
entityType = PrivateGatewayResponse.class,
|
||||
required = true,
|
||||
description = "the gateway id we are creating static route for")
|
||||
description = "the gateway id we are creating static route for. Mutually exclusive with the nexthop parameter")
|
||||
private Long gatewayId;
|
||||
|
||||
@Parameter(name = ApiConstants.VPC_ID,
|
||||
type = CommandType.UUID,
|
||||
entityType = VpcResponse.class,
|
||||
description = "the vpc id for which the static route is created. This is required for nexthop parameter")
|
||||
private Long vpcId;
|
||||
|
||||
@Parameter(name = ApiConstants.NEXT_HOP,
|
||||
type = CommandType.STRING,
|
||||
description = "the next hop of static route. Mutually exclusive with the gatewayid parameter")
|
||||
private String nextHop;
|
||||
|
||||
@Parameter(name = ApiConstants.CIDR, required = true, type = CommandType.STRING, description = "static route cidr")
|
||||
private String cidr;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
public long getGatewayId() {
|
||||
public Long getGatewayId() {
|
||||
return gatewayId;
|
||||
}
|
||||
|
||||
public Long getVpcId() {
|
||||
return vpcId;
|
||||
}
|
||||
|
||||
public String getNextHop() {
|
||||
return nextHop;
|
||||
}
|
||||
|
||||
public String getCidr() {
|
||||
return cidr;
|
||||
}
|
||||
|
|
@ -69,7 +88,7 @@ public class CreateStaticRouteCmd extends BaseAsyncCreateCmd {
|
|||
@Override
|
||||
public void create() throws ResourceAllocationException {
|
||||
try {
|
||||
StaticRoute result = _vpcService.createStaticRoute(getGatewayId(), getCidr());
|
||||
StaticRoute result = _vpcService.createStaticRoute(getGatewayId(), getVpcId(), getNextHop(), getCidr());
|
||||
setEntityId(result.getId());
|
||||
setEntityUuid(result.getUuid());
|
||||
} catch (NetworkRuleConflictException ex) {
|
||||
|
|
@ -114,11 +133,8 @@ public class CreateStaticRouteCmd extends BaseAsyncCreateCmd {
|
|||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
VpcGateway gateway = _entityMgr.findById(VpcGateway.class, gatewayId);
|
||||
if (gateway == null) {
|
||||
throw new InvalidParameterValueException("Invalid gateway id is specified");
|
||||
}
|
||||
return _entityMgr.findById(Vpc.class, gateway.getVpcId()).getAccountId();
|
||||
Long vpcId = getSyncObjId();
|
||||
return _entityMgr.findById(Vpc.class, vpcId).getAccountId();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -128,11 +144,20 @@ public class CreateStaticRouteCmd extends BaseAsyncCreateCmd {
|
|||
|
||||
@Override
|
||||
public Long getSyncObjId() {
|
||||
VpcGateway gateway = _entityMgr.findById(VpcGateway.class, gatewayId);
|
||||
if (gateway == null) {
|
||||
throw new InvalidParameterValueException("Invalid id is specified for the gateway");
|
||||
if (gatewayId != null) {
|
||||
VpcGateway gateway = _entityMgr.findById(VpcGateway.class, gatewayId);
|
||||
if (gateway == null) {
|
||||
throw new InvalidParameterValueException("Invalid id is specified for the gateway");
|
||||
}
|
||||
return gateway.getVpcId();
|
||||
} else if (vpcId != null) {
|
||||
Vpc vpc = _entityMgr.findById(Vpc.class, vpcId);
|
||||
if (vpc == null) {
|
||||
throw new InvalidParameterValueException("Invalid vpc id is specified");
|
||||
}
|
||||
return vpc.getId();
|
||||
}
|
||||
return gateway.getVpcId();
|
||||
throw new InvalidParameterValueException("One of vpcId or gatewayId must be specified");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -42,9 +42,17 @@ public class StaticRouteResponse extends BaseResponse implements ControlledEntit
|
|||
@Param(description = "VPC the static route belongs to")
|
||||
private String vpcId;
|
||||
|
||||
@SerializedName(ApiConstants.GATEWAY_ID)
|
||||
@SerializedName(ApiConstants.VPC_GATEWAY_ID)
|
||||
@Param(description = "VPC gateway the route is created for")
|
||||
private String gatewayId;
|
||||
private String vpcGatewayId;
|
||||
|
||||
@SerializedName(ApiConstants.VPC_GATEWAY_IP)
|
||||
@Param(description = "IP of VPC gateway the route is created for")
|
||||
private String vpcGatewayIp;
|
||||
|
||||
@SerializedName(ApiConstants.NEXT_HOP)
|
||||
@Param(description = "Next hop of the static route")
|
||||
private String nextHop;
|
||||
|
||||
@SerializedName(ApiConstants.CIDR)
|
||||
@Param(description = "static route CIDR")
|
||||
|
|
@ -95,8 +103,16 @@ public class StaticRouteResponse extends BaseResponse implements ControlledEntit
|
|||
this.vpcId = vpcId;
|
||||
}
|
||||
|
||||
public void setGatewayId(String gatewayId) {
|
||||
this.gatewayId = gatewayId;
|
||||
public void setVpcGatewayId(String vpcGatewayId) {
|
||||
this.vpcGatewayId = vpcGatewayId;
|
||||
}
|
||||
|
||||
public void setVpcGatewayIp(String vpcGatewayIp) {
|
||||
this.vpcGatewayIp = vpcGatewayIp;
|
||||
}
|
||||
|
||||
public void setNextHop(String nextHop) {
|
||||
this.nextHop = nextHop;
|
||||
}
|
||||
|
||||
public void setCidr(String cidr) {
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ public interface NetworkOrchestrationService {
|
|||
ConfigKey<Integer> NetworkLockTimeout = new ConfigKey<Integer>(Integer.class, NetworkLockTimeoutCK, "Network", "600",
|
||||
"Lock wait timeout (seconds) while implementing network", true, Scope.Global, null);
|
||||
|
||||
ConfigKey<String> DeniedRoutes = new ConfigKey<String>(String.class, "denied.routes", "Network", "",
|
||||
"Routes that are denied, can not be used for Static Routes creation for the VPC Private Gateway", true, ConfigKey.Scope.Zone, null);
|
||||
|
||||
ConfigKey<String> GuestDomainSuffix = new ConfigKey<String>(String.class, GuestDomainSuffixCK, "Network", "cloud.internal",
|
||||
"Default domain name for vms inside virtualized networks fronted by router", true, ConfigKey.Scope.Zone, null);
|
||||
|
||||
|
|
|
|||
|
|
@ -275,5 +275,9 @@ public class PublicIp implements PublicIpAddress {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForRouter() {
|
||||
return _addr.isForRouter();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ public interface RulesManager extends RulesService {
|
|||
|
||||
boolean disableStaticNat(long ipAddressId, Account caller, long callerUserId, boolean releaseIpIfElastic) throws ResourceUnavailableException;
|
||||
|
||||
boolean applyStaticNatForIp(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke);
|
||||
|
||||
/**
|
||||
* @param networkId
|
||||
* @param continueOnError
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import com.cloud.network.Network.Provider;
|
|||
import com.cloud.network.Network.Service;
|
||||
import com.cloud.network.PhysicalNetwork;
|
||||
import com.cloud.network.addr.PublicIp;
|
||||
import com.cloud.network.dao.IPAddressVO;
|
||||
import com.cloud.offering.NetworkOffering;
|
||||
import com.cloud.user.Account;
|
||||
|
||||
|
|
@ -174,4 +175,20 @@ public interface VpcManager {
|
|||
* @return
|
||||
*/
|
||||
boolean isSrcNatIpRequired(long vpcOfferingId);
|
||||
|
||||
boolean isSrcNatIpRequiredForVpcVr(long vpcOfferingId);
|
||||
|
||||
List<StaticRouteVO> getVpcStaticRoutes(Long vpcId);
|
||||
|
||||
List<StaticRouteProfile> getVpcStaticRoutes(List<? extends StaticRoute> routes);
|
||||
|
||||
boolean isProviderSupportServiceInVpc(long vpcId, Service service, Provider provider);
|
||||
|
||||
IPAddressVO getIpAddressForVpcVr(Vpc vpc, IPAddressVO ipAddress, boolean allocateIpIfNeeded);
|
||||
|
||||
boolean configStaticNatForVpcVr(Vpc vpc, IPAddressVO ipAddress);
|
||||
|
||||
void reconfigStaticNatForVpcVr(Long vpcId);
|
||||
|
||||
boolean applyStaticRouteForVpcVpnIfNeeded(Long vpcId, boolean updateAllVpn) throws ResourceUnavailableException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1058,7 +1058,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||
return Transaction.execute(new TransactionCallback<NicVO>() {
|
||||
@Override
|
||||
public NicVO doInTransaction(TransactionStatus status) {
|
||||
NicVO vo = _nicDao.findByIp4AddressAndNetworkId(profile.getIPv4Address(), networkId);
|
||||
NicVO vo = _nicDao.findNonPlaceHolderByIp4AddressAndNetworkId(profile.getIPv4Address(), networkId);
|
||||
if (vo == null) {
|
||||
applyProfileToNic(nic, profile, deviceId);
|
||||
vo = _nicDao.persist(nic);
|
||||
|
|
@ -1707,6 +1707,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||
}
|
||||
}
|
||||
}
|
||||
if (network.getVpcId() != null) {
|
||||
_vpcMgr.reconfigStaticNatForVpcVr(network.getVpcId());
|
||||
try {
|
||||
_vpcMgr.applyStaticRouteForVpcVpnIfNeeded(network.getVpcId(), true);
|
||||
} catch (ResourceUnavailableException e) {
|
||||
logger.error("Unable to apply static routes for vpc " + network.getVpcId() + " due to " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
for (final NetworkElement element : networkElements) {
|
||||
if (element instanceof AggregatedCommandExecutor && providersToImplement.contains(element.getProvider())) {
|
||||
|
|
@ -1952,6 +1960,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||
ip.setOneToOneNat(false);
|
||||
ip.setAssociatedWithVmId(null);
|
||||
ip.setVmIp(null);
|
||||
ip.setForRouter(false);
|
||||
_ipAddressDao.update(ip.getId(), ip);
|
||||
}
|
||||
}
|
||||
|
|
@ -3294,6 +3303,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||
}
|
||||
}
|
||||
}
|
||||
if (network.getVpcId() != null) {
|
||||
_vpcMgr.reconfigStaticNatForVpcVr(network.getVpcId());
|
||||
try {
|
||||
_vpcMgr.applyStaticRouteForVpcVpnIfNeeded(network.getVpcId(), true);
|
||||
} catch (ResourceUnavailableException e) {
|
||||
logger.error("Unable to apply static routes for vpc " + network.getVpcId() + " due to " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
@ -4874,7 +4891,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||
|
||||
@Override
|
||||
public ConfigKey<?>[] getConfigKeys() {
|
||||
return new ConfigKey<?>[]{NetworkGcWait, NetworkGcInterval, NetworkLockTimeout,
|
||||
return new ConfigKey<?>[]{NetworkGcWait, NetworkGcInterval, NetworkLockTimeout, DeniedRoutes,
|
||||
GuestDomainSuffix, NetworkThrottlingRate, MinVRVersion,
|
||||
PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RollingRestartEnabled,
|
||||
TUNGSTEN_ENABLED, NSX_ENABLED, NETRIS_ENABLED };
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, Long> implemen
|
|||
address.setSourceNat(false);
|
||||
address.setOneToOneNat(false);
|
||||
address.setAssociatedWithVmId(null);
|
||||
address.setForRouter(false);
|
||||
address.setState(State.Free);
|
||||
address.setAssociatedWithNetworkId(null);
|
||||
address.setVpcId(null);
|
||||
|
|
|
|||
|
|
@ -116,6 +116,9 @@ public class IPAddressVO implements IpAddress {
|
|||
@Column(name = "forsystemvms")
|
||||
private boolean forSystemVms = false;
|
||||
|
||||
@Column(name = "for_router")
|
||||
private boolean forRouter = false;
|
||||
|
||||
@Column(name= GenericDao.REMOVED_COLUMN)
|
||||
private Date removed;
|
||||
|
||||
|
|
@ -385,4 +388,13 @@ public class IPAddressVO implements IpAddress {
|
|||
public boolean isForSystemVms() {
|
||||
return forSystemVms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForRouter() {
|
||||
return forRouter;
|
||||
}
|
||||
|
||||
public void setForRouter(boolean forRouter) {
|
||||
this.forRouter = forRouter;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,4 +33,6 @@ public interface RemoteAccessVpnDao extends GenericDao<RemoteAccessVpnVO, Long>
|
|||
List<RemoteAccessVpnVO> findByAccount(Long accountId);
|
||||
|
||||
List<RemoteAccessVpnVO> listByNetworkId(Long networkId);
|
||||
|
||||
List<RemoteAccessVpnVO> listByVpcId(Long vpcId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,4 +85,11 @@ public class RemoteAccessVpnDaoImpl extends GenericDaoBase<RemoteAccessVpnVO, Lo
|
|||
sc.setParameters("networkId", networkId);
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RemoteAccessVpnVO> listByVpcId(Long vpcId) {
|
||||
SearchCriteria<RemoteAccessVpnVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("vpcId", vpcId);
|
||||
return listBy(sc);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,4 +20,6 @@ import com.cloud.utils.db.GenericDao;
|
|||
|
||||
public interface Site2SiteVpnGatewayDao extends GenericDao<Site2SiteVpnGatewayVO, Long> {
|
||||
Site2SiteVpnGatewayVO findByVpcId(long vpcId);
|
||||
|
||||
Site2SiteVpnGatewayVO findByPublicIpAddress(long ipAddressId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ public class Site2SiteVpnGatewayDaoImpl extends GenericDaoBase<Site2SiteVpnGatew
|
|||
protected Site2SiteVpnGatewayDaoImpl() {
|
||||
AllFieldsSearch = createSearchBuilder();
|
||||
AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), SearchCriteria.Op.EQ);
|
||||
AllFieldsSearch.and("ipAddressId", AllFieldsSearch.entity().getAddrId(), SearchCriteria.Op.EQ);
|
||||
AllFieldsSearch.done();
|
||||
}
|
||||
|
||||
|
|
@ -44,4 +45,11 @@ public class Site2SiteVpnGatewayDaoImpl extends GenericDaoBase<Site2SiteVpnGatew
|
|||
sc.setParameters("vpcId", vpcId);
|
||||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Site2SiteVpnGatewayVO findByPublicIpAddress(long ipAddressId) {
|
||||
SearchCriteria<Site2SiteVpnGatewayVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("ipAddressId", ipAddressId);
|
||||
return findOneBy(sc);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import javax.persistence.GeneratedValue;
|
|||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
|
|
@ -42,7 +43,10 @@ public class StaticRouteVO implements StaticRoute {
|
|||
String uuid;
|
||||
|
||||
@Column(name = "vpc_gateway_id", updatable = false)
|
||||
long vpcGatewayId;
|
||||
Long vpcGatewayId;
|
||||
|
||||
@Column(name = "next_hop")
|
||||
private String nextHop;
|
||||
|
||||
@Column(name = "cidr")
|
||||
private String cidr;
|
||||
|
|
@ -67,6 +71,9 @@ public class StaticRouteVO implements StaticRoute {
|
|||
uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
@Transient
|
||||
boolean forVpn = false;
|
||||
|
||||
/**
|
||||
* @param vpcGatewayId
|
||||
* @param cidr
|
||||
|
|
@ -74,7 +81,7 @@ public class StaticRouteVO implements StaticRoute {
|
|||
* @param accountId TODO
|
||||
* @param domainId TODO
|
||||
*/
|
||||
public StaticRouteVO(long vpcGatewayId, String cidr, Long vpcId, long accountId, long domainId) {
|
||||
public StaticRouteVO(Long vpcGatewayId, String cidr, Long vpcId, long accountId, long domainId, String nextHop) {
|
||||
super();
|
||||
this.vpcGatewayId = vpcGatewayId;
|
||||
this.cidr = cidr;
|
||||
|
|
@ -82,14 +89,32 @@ public class StaticRouteVO implements StaticRoute {
|
|||
this.vpcId = vpcId;
|
||||
this.accountId = accountId;
|
||||
this.domainId = domainId;
|
||||
this.nextHop = nextHop;
|
||||
uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public StaticRouteVO(String cidr, Long vpcId, long accountId, long domainId, String nextHop, State state, boolean forVpn) {
|
||||
super();
|
||||
this.cidr = cidr;
|
||||
this.state = state;
|
||||
this.vpcId = vpcId;
|
||||
this.accountId = accountId;
|
||||
this.domainId = domainId;
|
||||
this.nextHop = nextHop;
|
||||
uuid = UUID.randomUUID().toString();
|
||||
this.forVpn = forVpn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getVpcGatewayId() {
|
||||
public Long getVpcGatewayId() {
|
||||
return vpcGatewayId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNextHop() {
|
||||
return nextHop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCidr() {
|
||||
return cidr;
|
||||
|
|
@ -145,4 +170,8 @@ public class StaticRouteVO implements StaticRoute {
|
|||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isForVpn() {
|
||||
return forVpn;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,8 +68,15 @@ public class VpcServiceMapDaoImpl extends GenericDaoBase<VpcServiceMapVO, Long>
|
|||
|
||||
@Override
|
||||
public boolean canProviderSupportServiceInVpc(long vpcId, Service service, Provider provider) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
SearchCriteria<VpcServiceMapVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("vpcId", vpcId);
|
||||
sc.setParameters("service", service.getName());
|
||||
sc.setParameters("provider", provider.getName());
|
||||
if (findOneBy(sc) != null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -46,8 +46,12 @@ public interface NicDao extends GenericDao<NicVO, Long> {
|
|||
|
||||
NicVO findByNetworkIdAndTypeIncludingRemoved(long networkId, VirtualMachine.Type vmType);
|
||||
|
||||
NicVO findNonPlaceHolderByNetworkIdAndType(long networkId, VirtualMachine.Type vmType);
|
||||
|
||||
NicVO findByIp4AddressAndNetworkId(String ip4Address, long networkId);
|
||||
|
||||
NicVO findNonPlaceHolderByIp4AddressAndNetworkId(String ip4Address, long networkId);
|
||||
|
||||
NicVO findByNetworkIdAndMacAddress(long networkId, String mac);
|
||||
|
||||
NicVO findDefaultNicForVM(long instanceId);
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ public class NicDaoImpl extends GenericDaoBase<NicVO, Long> implements NicDao {
|
|||
AllFieldsSearch.and("secondaryip", AllFieldsSearch.entity().getSecondaryIp(), Op.EQ);
|
||||
AllFieldsSearch.and("nicid", AllFieldsSearch.entity().getId(), Op.EQ);
|
||||
AllFieldsSearch.and("strategy", AllFieldsSearch.entity().getReservationStrategy(), Op.EQ);
|
||||
AllFieldsSearch.and("strategyNEQ", AllFieldsSearch.entity().getReservationStrategy(), Op.NEQ);
|
||||
AllFieldsSearch.and("reserverName",AllFieldsSearch.entity().getReserver(),Op.EQ);
|
||||
AllFieldsSearch.and("macAddress", AllFieldsSearch.entity().getMacAddress(), Op.EQ);
|
||||
AllFieldsSearch.and("deviceid", AllFieldsSearch.entity().getDeviceId(), Op.EQ);
|
||||
|
|
@ -195,6 +196,15 @@ public class NicDaoImpl extends GenericDaoBase<NicVO, Long> implements NicDao {
|
|||
return findByNetworkIdAndTypeInternal(networkId, vmType, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NicVO findNonPlaceHolderByNetworkIdAndType(long networkId, VirtualMachine.Type vmType) {
|
||||
SearchCriteria<NicVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("network", networkId);
|
||||
sc.setParameters("vmType", vmType);
|
||||
sc.setParameters("strategyNEQ", Nic.ReservationStrategy.PlaceHolder.toString());
|
||||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NicVO findByNetworkIdTypeAndGateway(long networkId, VirtualMachine.Type vmType, String gateway) {
|
||||
SearchCriteria<NicVO> sc = AllFieldsSearch.create();
|
||||
|
|
@ -222,6 +232,16 @@ public class NicDaoImpl extends GenericDaoBase<NicVO, Long> implements NicDao {
|
|||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NicVO findNonPlaceHolderByIp4AddressAndNetworkId(String ip4Address, long networkId) {
|
||||
SearchCriteria<NicVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("address", ip4Address);
|
||||
sc.setParameters("network", networkId);
|
||||
sc.setParameters("strategyNEQ", Nic.ReservationStrategy.PlaceHolder.toString());
|
||||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NicVO findByNetworkIdAndMacAddress(long networkId, String mac) {
|
||||
SearchCriteria<NicVO> sc = AllFieldsSearch.create();
|
||||
|
|
|
|||
|
|
@ -453,3 +453,9 @@ ALTER TABLE `cloud`.`network_offerings` DROP COLUMN `for_nsx`;
|
|||
|
||||
-- Drop the Tungsten and NSX columns from the VPC offerings (replaced by checking the provider on the vpc_offering_service_map table)
|
||||
ALTER TABLE `cloud`.`vpc_offerings` DROP COLUMN `for_nsx`;
|
||||
|
||||
-- Add next_hop to the static_routes table
|
||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.static_routes', 'next_hop', 'varchar(50) COMMENT "next hop of the static route" AFTER `vpc_gateway_id`');
|
||||
|
||||
-- Add `for_router` to `user_ip_address` table
|
||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.user_ip_address', 'for_router', 'tinyint(1) DEFAULT 0 COMMENT "True if the ip address is used by Domain Router to expose services"');
|
||||
|
|
|
|||
|
|
@ -381,6 +381,7 @@ public class NetrisApiClientImpl implements NetrisApiClient {
|
|||
routesPutBody.setPrefix(prefix);
|
||||
routesPutBody.setNextHop(nextHop);
|
||||
routesPutBody.setSiteId(new BigDecimal(siteId));
|
||||
routesPutBody.setStateStatus(RoutesPutBody.StateStatusEnum.ACTIVE);
|
||||
|
||||
routesPutBody.setDescription(staticRouteId);
|
||||
routesPutBody.setSwitches(Collections.emptyList());
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import com.cloud.dc.dao.ASNumberDao;
|
|||
import com.cloud.dc.dao.ASNumberRangeDao;
|
||||
import com.cloud.dc.dao.VlanDetailsDao;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import com.cloud.network.vpc.VpcGateway;
|
||||
import com.cloud.storage.BucketVO;
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
||||
|
|
@ -1036,6 +1037,9 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
addSystemVmInfoToIpResponse(nic, response);
|
||||
}
|
||||
}
|
||||
if (ipAddress.isForRouter()) {
|
||||
response.setVirtualMachineType(Type.DomainRouter.toString());
|
||||
}
|
||||
if (ipAddress.getAssociatedWithVmId() != null) {
|
||||
addUserVmDetailsInIpResponse(response, ipAddress);
|
||||
}
|
||||
|
|
@ -1062,12 +1066,25 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
}
|
||||
|
||||
private void addUserVmDetailsInIpResponse(IPAddressResponse response, IpAddress ipAddress) {
|
||||
UserVm userVm = ApiDBUtils.findUserVmById(ipAddress.getAssociatedWithVmId());
|
||||
if (userVm != null) {
|
||||
response.setVirtualMachineId(userVm.getUuid());
|
||||
response.setVirtualMachineName(userVm.getHostName());
|
||||
response.setVirtualMachineType(userVm.getType().toString());
|
||||
response.setVirtualMachineDisplayName(ObjectUtils.firstNonNull(userVm.getDisplayName(), userVm.getHostName()));
|
||||
VirtualMachine vm = ApiDBUtils.findVMInstanceById(ipAddress.getAssociatedWithVmId());
|
||||
if (vm == null) {
|
||||
return;
|
||||
}
|
||||
if (vm.getType().equals(Type.User)) {
|
||||
UserVm userVm = ApiDBUtils.findUserVmById(ipAddress.getAssociatedWithVmId());
|
||||
if (userVm != null) {
|
||||
response.setVirtualMachineId(userVm.getUuid());
|
||||
response.setVirtualMachineName(userVm.getHostName());
|
||||
response.setVirtualMachineType(userVm.getType().toString());
|
||||
response.setVirtualMachineDisplayName(ObjectUtils.firstNonNull(userVm.getDisplayName(), userVm.getHostName()));
|
||||
}
|
||||
} else if (vm.getType().equals(Type.DomainRouter)) {
|
||||
final boolean isAdmin = Account.Type.ADMIN.equals(CallContext.current().getCallingAccount().getType());
|
||||
if (isAdmin) {
|
||||
response.setVirtualMachineId(vm.getUuid());
|
||||
response.setVirtualMachineName(vm.getHostName());
|
||||
}
|
||||
response.setVirtualMachineType(vm.getType().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1234,6 +1251,13 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
ipResponse.setVirtualMachineDisplayName(vm.getHostName());
|
||||
}
|
||||
}
|
||||
} else if (nic.getVmType() == Type.DomainRouter) {
|
||||
VirtualMachine vm = ApiDBUtils.findVMInstanceById(nic.getInstanceId());
|
||||
if (vm != null) {
|
||||
ipResponse.setVirtualMachineId(vm.getUuid());
|
||||
ipResponse.setVirtualMachineName(vm.getHostName());
|
||||
ipResponse.setVirtualMachineType(vm.getType().toString());
|
||||
}
|
||||
} else if (nic.getVmType().isUsedBySystem()) {
|
||||
ipResponse.setIsSystem(true);
|
||||
addSystemVmInfoToIpResponse(nic, ipResponse);
|
||||
|
|
@ -3156,12 +3180,6 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
List<? extends Network.Provider> serviceProviders = ApiDBUtils.getProvidersForService(service);
|
||||
List<ProviderResponse> serviceProvidersResponses = new ArrayList<ProviderResponse>();
|
||||
for (Network.Provider serviceProvider : serviceProviders) {
|
||||
// return only Virtual Router/JuniperSRX/CiscoVnmc as a provider for the firewall
|
||||
if (service == Service.Firewall
|
||||
&& !(serviceProvider == Provider.VirtualRouter || serviceProvider == Provider.CiscoVnmc || serviceProvider == Provider.PaloAlto || serviceProvider == Provider.BigSwitchBcf || serviceProvider == Provider.Tungsten)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ProviderResponse serviceProviderResponse = createServiceProviderResponse(serviceProvider);
|
||||
serviceProvidersResponses.add(serviceProviderResponse);
|
||||
}
|
||||
|
|
@ -3772,6 +3790,16 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
response.setVpcId(vpc.getUuid());
|
||||
}
|
||||
}
|
||||
if (result.getVpcGatewayId() != null) {
|
||||
VpcGateway vpcGateway = _entityMgr.findById(VpcGateway.class, result.getVpcGatewayId());
|
||||
if (vpcGateway != null) {
|
||||
response.setVpcGatewayId(vpcGateway.getUuid());
|
||||
response.setVpcGatewayIp(vpcGateway.getIp4Address());
|
||||
}
|
||||
}
|
||||
if (result.getNextHop() != null) {
|
||||
response.setNextHop(result.getNextHop());
|
||||
}
|
||||
response.setCidr(result.getCidr());
|
||||
|
||||
StaticRoute.State state = result.getState();
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ import com.cloud.dc.dao.VlanDetailsDao;
|
|||
import com.cloud.network.dao.NetrisProviderDao;
|
||||
import com.cloud.network.dao.NsxProviderDao;
|
||||
import com.cloud.network.dao.PublicIpQuarantineDao;
|
||||
import com.cloud.network.dao.RemoteAccessVpnDao;
|
||||
import com.cloud.network.dao.Site2SiteVpnGatewayDao;
|
||||
import com.cloud.network.element.NetrisProviderVO;
|
||||
import com.cloud.network.element.NsxProviderVO;
|
||||
import com.cloud.network.vo.PublicIpQuarantineVO;
|
||||
|
|
@ -329,6 +331,10 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
|
||||
@Inject
|
||||
PublicIpQuarantineDao publicIpQuarantineDao;
|
||||
@Inject
|
||||
RemoteAccessVpnDao remoteAccessVpnDao;
|
||||
@Inject
|
||||
Site2SiteVpnGatewayDao site2SiteVpnGatewayDao;
|
||||
|
||||
SearchBuilder<IPAddressVO> AssignIpAddressSearch;
|
||||
SearchBuilder<IPAddressVO> AssignIpAddressFromPodVlanSearch;
|
||||
|
|
@ -744,6 +750,21 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
throw new CloudRuntimeException("Unable to acquire lock on public IP.");
|
||||
}
|
||||
|
||||
if (ipToBeDisassociated.isForRouter()) {
|
||||
if (remoteAccessVpnDao.findByPublicIpAddress(ipToBeDisassociated.getId()) != null) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException("Can't release IP address as the IP address is used by a Remote Access VPN");
|
||||
ex.addProxyObject(ipToBeDisassociated.getUuid(), "ipId");
|
||||
throw ex;
|
||||
|
||||
}
|
||||
if (site2SiteVpnGatewayDao.findByPublicIpAddress(ipToBeDisassociated.getId()) != null) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException("Can't release IP address as the IP address is used by a VPC gateway");
|
||||
ex.addProxyObject(ipToBeDisassociated.getUuid(), "ipId");
|
||||
throw ex;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
PublicIpQuarantine publicIpQuarantine = null;
|
||||
// Cleanup all ip address resources - PF/LB/Static nat rules
|
||||
if (!cleanupIpResources(addrId, userId, caller)) {
|
||||
|
|
|
|||
|
|
@ -2300,6 +2300,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
|
|||
}
|
||||
if (capabilities != null && implementedProvider != null) {
|
||||
for (Service service : capabilities.keySet()) {
|
||||
logger.info("Add provider {} and service {}", implementedProvider.getName(), service.getName());
|
||||
if (s_serviceToImplementedProvidersMap.containsKey(service)) {
|
||||
List<Provider> providers = s_serviceToImplementedProvidersMap.get(service);
|
||||
providers.add(implementedProvider);
|
||||
|
|
|
|||
|
|
@ -543,7 +543,7 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
|
|||
// Set capabilities for vpn
|
||||
final Map<Capability, String> vpnCapabilities = new HashMap<Capability, String>();
|
||||
vpnCapabilities.put(Capability.SupportedVpnProtocols, "pptp,l2tp,ipsec");
|
||||
vpnCapabilities.put(Capability.VpnTypes, "removeaccessvpn");
|
||||
vpnCapabilities.put(Capability.VpnTypes, "remoteaccessvpn");
|
||||
capabilities.put(Service.Vpn, vpnCapabilities);
|
||||
|
||||
final Map<Capability, String> dnsCapabilities = new HashMap<Capability, String>();
|
||||
|
|
|
|||
|
|
@ -288,8 +288,9 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru {
|
|||
profile.setIPv4Netmask(null);
|
||||
}
|
||||
|
||||
if (config.getVpcId() == null && vm.getType() == VirtualMachine.Type.DomainRouter) {
|
||||
boolean isPublicNetwork = _networkModel.isProviderSupportServiceInNetwork(config.getId(), Service.SourceNat, Provider.VirtualRouter);
|
||||
if (vm.getType() == VirtualMachine.Type.DomainRouter) {
|
||||
boolean isPublicNetwork = _networkModel.isProviderSupportServiceInNetwork(config.getId(), Service.SourceNat, Provider.VirtualRouter)
|
||||
|| _networkModel.isProviderSupportServiceInNetwork(config.getId(), Service.SourceNat, Provider.VPCVirtualRouter);
|
||||
if (!isPublicNetwork) {
|
||||
Nic placeholderNic = _networkModel.getPlaceholderNicForRouter(config, null);
|
||||
if (placeholderNic == null) {
|
||||
|
|
|
|||
|
|
@ -1219,8 +1219,9 @@ public class CommandSetupHelper {
|
|||
final SetupGuestNetworkCommand setupCmd = new SetupGuestNetworkCommand(dhcpRange, networkDomain, router.getIsRedundantRouter(), defaultDns1, defaultDns2, add, _itMgr.toNicTO(nicProfile,
|
||||
router.getHypervisorType()));
|
||||
|
||||
boolean isForNsx = _networkModel.isProviderForNetworkOffering(Provider.Nsx, networkOfferingVO.getId());
|
||||
setupCmd.setVrGuestGateway(isForNsx);
|
||||
boolean isVrGuestGateway = _networkModel.isAnyServiceSupportedInNetwork(network.getId(), Provider.VPCVirtualRouter, Service.SourceNat, Service.Gateway);
|
||||
setupCmd.setVrGuestGateway(isVrGuestGateway);
|
||||
|
||||
NicVO publicNic = _nicDao.findDefaultNicForVM(router.getId());
|
||||
if (publicNic != null) {
|
||||
updateSetupGuestNetworkCommandIpv6(setupCmd, network, publicNic, defaultIp6Dns1, defaultIp6Dns2);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import java.util.Map;
|
|||
import javax.annotation.PostConstruct;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.network.vpc.VpcManager;
|
||||
import com.cloud.network.vpc.dao.VpcDao;
|
||||
import com.cloud.utils.validation.ChecksumUtil;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
|
|
@ -176,6 +177,8 @@ public class NetworkHelperImpl implements NetworkHelper {
|
|||
CapacityManager capacityMgr;
|
||||
@Inject
|
||||
VpcDao vpcDao;
|
||||
@Inject
|
||||
VpcManager vpcManager;
|
||||
|
||||
protected final Map<HypervisorType, ConfigKey<String>> hypervisorsMap = new HashMap<>();
|
||||
|
||||
|
|
@ -276,6 +279,10 @@ public class NetworkHelperImpl implements NetworkHelper {
|
|||
_itMgr.expunge(router.getUuid());
|
||||
_routerHealthCheckResultDao.expungeHealthChecks(router.getId());
|
||||
_routerDao.remove(router.getId());
|
||||
|
||||
if (router.getVpcId() != null) {
|
||||
vpcManager.reconfigStaticNatForVpcVr(router.getVpcId());
|
||||
}
|
||||
return router;
|
||||
}
|
||||
|
||||
|
|
@ -773,7 +780,7 @@ public class NetworkHelperImpl implements NetworkHelper {
|
|||
logger.debug("Adding nic for Virtual Router in Guest network " + guestNetwork);
|
||||
String defaultNetworkStartIp = null, defaultNetworkStartIpv6 = null;
|
||||
final Nic placeholder = _networkModel.getPlaceholderNicForRouter(guestNetwork, routerDeploymentDefinition.getPodId());
|
||||
if (!routerDeploymentDefinition.isPublicNetwork()) {
|
||||
if (!routerDeploymentDefinition.isPublicNetwork() || !vpcManager.isSrcNatIpRequiredForVpcVr(routerDeploymentDefinition.getVpc().getVpcOfferingId())) {
|
||||
if (guestNetwork.getCidr() != null) {
|
||||
if (placeholder != null && placeholder.getIPv4Address() != null) {
|
||||
logger.debug("Requesting ipv4 address " + placeholder.getIPv4Address() + " stored in placeholder nic for the network "
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@ public class NicProfileHelperImpl implements NicProfileHelper {
|
|||
public NicProfile createGuestNicProfileForVpcRouter(final RouterDeploymentDefinition vpcRouterDeploymentDefinition, final Network guestNetwork) {
|
||||
final NicProfile guestNic = new NicProfile();
|
||||
|
||||
if (BroadcastDomainType.NSX == guestNetwork.getBroadcastDomainType()) {
|
||||
if (BroadcastDomainType.NSX == guestNetwork.getBroadcastDomainType() ||
|
||||
BroadcastDomainType.Netris == guestNetwork.getBroadcastDomainType() ||
|
||||
!_vpcMgr.isSrcNatIpRequiredForVpcVr(vpcRouterDeploymentDefinition.getVpc().getVpcOfferingId())) {
|
||||
NicVO vrNic = _nicDao.findByNetworkIdAndTypeIncludingRemoved(guestNetwork.getId(), VirtualMachine.Type.DomainRouter);
|
||||
if (vrNic != null) {
|
||||
guestNic.setIPv4Address(vrNic.getIPv4Address());
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ import com.cloud.network.rules.StaticNatImpl;
|
|||
import com.cloud.network.rules.StaticNatRule;
|
||||
import com.cloud.network.rules.dao.PortForwardingRulesDao;
|
||||
import com.cloud.network.vpc.Vpc;
|
||||
import com.cloud.network.vpc.VpcManager;
|
||||
import com.cloud.network.vpc.VpcService;
|
||||
import com.cloud.network.vpc.dao.VpcDao;
|
||||
import com.cloud.network.vpn.Site2SiteVpnManager;
|
||||
|
|
@ -336,6 +337,7 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
|
|||
|
||||
@Inject private NetworkService networkService;
|
||||
@Inject private VpcService vpcService;
|
||||
@Inject private VpcManager vpcManager;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("networkHelper")
|
||||
|
|
@ -2039,6 +2041,12 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
|
|||
if (_disableRpFilter) {
|
||||
rpFilter = " disable_rp_filter=true";
|
||||
}
|
||||
Vpc vpc = vpcManager.getActiveVpc(router.getVpcId());
|
||||
if (vpcManager.isSrcNatIpRequiredForVpcVr(vpc.getVpcOfferingId())) {
|
||||
buf.append(" has_public_network=true");
|
||||
} else {
|
||||
buf.append(" has_public_network=false");
|
||||
}
|
||||
} else if (!publicNetwork) {
|
||||
type = "dhcpsrvr";
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -82,10 +82,9 @@ import com.cloud.network.vpc.NetworkACLManager;
|
|||
import com.cloud.network.vpc.PrivateGateway;
|
||||
import com.cloud.network.vpc.PrivateIpAddress;
|
||||
import com.cloud.network.vpc.PrivateIpVO;
|
||||
import com.cloud.network.vpc.StaticRoute;
|
||||
import com.cloud.network.vpc.StaticRouteVO;
|
||||
import com.cloud.network.vpc.StaticRouteProfile;
|
||||
import com.cloud.network.vpc.Vpc;
|
||||
import com.cloud.network.vpc.VpcGateway;
|
||||
import com.cloud.network.vpc.VpcManager;
|
||||
import com.cloud.network.vpc.VpcVO;
|
||||
import com.cloud.network.vpc.dao.PrivateIpDao;
|
||||
|
|
@ -321,17 +320,19 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian
|
|||
String defaultDns2 = null;
|
||||
String defaultIp6Dns1 = null;
|
||||
String defaultIp6Dns2 = null;
|
||||
boolean isDnsConfigured = false;
|
||||
// remove public and guest nics as we will plug them later
|
||||
final Iterator<NicProfile> it = profile.getNics().iterator();
|
||||
while (it.hasNext()) {
|
||||
final NicProfile nic = it.next();
|
||||
if (nic.getTrafficType() == TrafficType.Public || nic.getTrafficType() == TrafficType.Guest) {
|
||||
// save dns information
|
||||
if (nic.getTrafficType() == TrafficType.Public) {
|
||||
if (nic.getTrafficType() == TrafficType.Public || !isDnsConfigured) {
|
||||
defaultDns1 = nic.getIPv4Dns1();
|
||||
defaultDns2 = nic.getIPv4Dns2();
|
||||
defaultIp6Dns1 = nic.getIPv6Dns1();
|
||||
defaultIp6Dns2 = nic.getIPv6Dns2();
|
||||
isDnsConfigured = true;
|
||||
}
|
||||
logger.debug("Removing nic " + nic + " of type " + nic.getTrafficType() + " from the nics passed on vm start. " + "The nic will be plugged later");
|
||||
it.remove();
|
||||
|
|
@ -532,17 +533,8 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian
|
|||
}
|
||||
|
||||
// 4) RE-APPLY ALL STATIC ROUTE RULES
|
||||
final List<? extends StaticRoute> routes = _staticRouteDao.listByVpcId(domainRouterVO.getVpcId());
|
||||
final List<StaticRouteProfile> staticRouteProfiles = new ArrayList<StaticRouteProfile>(routes.size());
|
||||
final Map<Long, VpcGateway> gatewayMap = new HashMap<Long, VpcGateway>();
|
||||
for (final StaticRoute route : routes) {
|
||||
VpcGateway gateway = gatewayMap.get(route.getVpcGatewayId());
|
||||
if (gateway == null) {
|
||||
gateway = _entityMgr.findById(VpcGateway.class, route.getVpcGatewayId());
|
||||
gatewayMap.put(gateway.getId(), gateway);
|
||||
}
|
||||
staticRouteProfiles.add(new StaticRouteProfile(route, gateway));
|
||||
}
|
||||
final List<StaticRouteVO> routes = _vpcMgr.getVpcStaticRoutes(domainRouterVO.getVpcId());
|
||||
final List<StaticRouteProfile> staticRouteProfiles = _vpcMgr.getVpcStaticRoutes(routes);
|
||||
|
||||
logger.debug("Found " + staticRouteProfiles.size() + " static routes to apply as a part of vpc route " + domainRouterVO + " start");
|
||||
if (!staticRouteProfiles.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ import com.cloud.network.dao.IPAddressDao;
|
|||
import com.cloud.network.dao.IPAddressVO;
|
||||
import com.cloud.network.dao.LoadBalancerVMMapDao;
|
||||
import com.cloud.network.dao.LoadBalancerVMMapVO;
|
||||
import com.cloud.network.dao.RemoteAccessVpnDao;
|
||||
import com.cloud.network.dao.Site2SiteVpnGatewayDao;
|
||||
import com.cloud.network.rules.FirewallRule.FirewallRuleType;
|
||||
import com.cloud.network.rules.FirewallRule.Purpose;
|
||||
import com.cloud.network.rules.FirewallRule.State;
|
||||
|
|
@ -153,6 +155,10 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
|||
VpcService _vpcSvc;
|
||||
@Inject
|
||||
VMTemplateDao _templateDao;
|
||||
@Inject
|
||||
RemoteAccessVpnDao remoteAccessVpnDao;
|
||||
@Inject
|
||||
Site2SiteVpnGatewayDao site2SiteVpnGatewayDao;
|
||||
|
||||
protected void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller, Boolean ignoreVmState) {
|
||||
if (ipAddress == null || ipAddress.getAllocatedTime() == null || ipAddress.getAllocatedToAccountId() == null) {
|
||||
|
|
@ -1262,6 +1268,25 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
|||
throw ex;
|
||||
}
|
||||
|
||||
if (ipAddress.isForRouter()) {
|
||||
if (remoteAccessVpnDao.findByPublicIpAddress(ipAddress.getId()) != null) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException("Can't disable static nat as the IP address is used by a Remote Access VPN");
|
||||
ex.addProxyObject(ipAddress.getUuid(), "ipId");
|
||||
throw ex;
|
||||
|
||||
}
|
||||
if (site2SiteVpnGatewayDao.findByPublicIpAddress(ipAddress.getId()) != null) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException("Can't disable static nat as the IP address is used by a VPC gateway");
|
||||
ex.addProxyObject(ipAddress.getUuid(), "ipId");
|
||||
throw ex;
|
||||
|
||||
}
|
||||
if (disableStaticNat(ipId, caller, ctx.getCallingUserId(), false)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Long vmId = ipAddress.getAssociatedWithVmId();
|
||||
if (vmId == null) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException("Specified IP address id is not associated with any vm Id");
|
||||
|
|
@ -1294,7 +1319,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
|||
|
||||
IPAddressVO ipAddress = _ipAddressDao.findById(ipId);
|
||||
checkIpAndUserVm(ipAddress, null, caller, false);
|
||||
long networkId = ipAddress.getAssociatedWithNetworkId();
|
||||
Long networkId = ipAddress.getAssociatedWithNetworkId();
|
||||
|
||||
if (!ipAddress.isOneToOneNat()) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException("One to one nat is not enabled for the specified ip id");
|
||||
|
|
@ -1329,11 +1354,14 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
|||
ipAddress.setAssociatedWithVmId(null);
|
||||
ipAddress.setRuleState(null);
|
||||
ipAddress.setVmIp(null);
|
||||
ipAddress.setForRouter(false);
|
||||
if (isIpSystem && !releaseIpIfElastic) {
|
||||
ipAddress.setSystem(false);
|
||||
}
|
||||
_ipAddressDao.update(ipAddress.getId(), ipAddress);
|
||||
_vpcMgr.unassignIPFromVpcNetwork(ipAddress.getId(), networkId);
|
||||
if (networkId != null) {
|
||||
_vpcMgr.unassignIPFromVpcNetwork(ipAddress.getId(), networkId);
|
||||
}
|
||||
|
||||
if (isIpSystem && releaseIpIfElastic && !_ipAddrMgr.handleSystemIpRelease(ipAddress)) {
|
||||
logger.warn("Failed to release system ip address " + ipAddress);
|
||||
|
|
@ -1371,7 +1399,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
|||
return new StaticNatRuleImpl(ruleVO, dstIp);
|
||||
}
|
||||
|
||||
protected boolean applyStaticNatForIp(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke) {
|
||||
@Override
|
||||
public boolean applyStaticNatForIp(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke) {
|
||||
IpAddress sourceIp = _ipAddressDao.findById(sourceIpId);
|
||||
|
||||
List<StaticNat> staticNats = createStaticNatForIp(sourceIp, caller, forRevoke);
|
||||
|
|
|
|||
|
|
@ -48,11 +48,22 @@ import com.cloud.bgp.BGPService;
|
|||
import com.cloud.dc.ASNumberVO;
|
||||
import com.cloud.dc.dao.ASNumberDao;
|
||||
import com.cloud.dc.Vlan;
|
||||
import com.cloud.network.RemoteAccessVpn;
|
||||
import com.cloud.network.Site2SiteVpnConnection;
|
||||
import com.cloud.network.dao.NetrisProviderDao;
|
||||
import com.cloud.network.dao.NsxProviderDao;
|
||||
import com.cloud.network.dao.RemoteAccessVpnDao;
|
||||
import com.cloud.network.dao.RemoteAccessVpnVO;
|
||||
import com.cloud.network.dao.Site2SiteCustomerGatewayDao;
|
||||
import com.cloud.network.dao.Site2SiteCustomerGatewayVO;
|
||||
import com.cloud.network.dao.Site2SiteVpnConnectionDao;
|
||||
import com.cloud.network.dao.Site2SiteVpnConnectionVO;
|
||||
import com.cloud.network.element.NetrisProviderVO;
|
||||
import com.cloud.network.element.NsxProviderVO;
|
||||
import com.cloud.network.rules.RulesManager;
|
||||
import com.cloud.network.vpn.RemoteAccessVpnService;
|
||||
import com.cloud.resourcelimit.CheckedReservation;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
||||
import org.apache.cloudstack.alert.AlertService;
|
||||
|
|
@ -296,6 +307,20 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
private NetrisProviderDao netrisProviderDao;
|
||||
@Inject
|
||||
RoutedIpv4Manager routedIpv4Manager;
|
||||
@Inject
|
||||
DomainRouterDao domainRouterDao;
|
||||
@Inject
|
||||
RulesManager rulesManager;
|
||||
@Inject
|
||||
VMInstanceDao vmInstanceDao;
|
||||
@Inject
|
||||
RemoteAccessVpnDao remoteAccessVpnDao;
|
||||
@Inject
|
||||
RemoteAccessVpnService remoteAccessVpnMgr;
|
||||
@Inject
|
||||
Site2SiteVpnConnectionDao site2SiteVpnConnectionDao;
|
||||
@Inject
|
||||
Site2SiteCustomerGatewayDao site2SiteCustomerGatewayDao;
|
||||
|
||||
private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker"));
|
||||
private List<VpcProvider> vpcElements = null;
|
||||
|
|
@ -461,7 +486,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
final Map<Service, Set<Provider>> svcProviderMap = new HashMap<>();
|
||||
final Set<Provider> defaultProviders = Set.of(Provider.Netris);
|
||||
for (final Service svc : getSupportedServices()) {
|
||||
if (List.of(Service.UserData, Service.Dhcp, Service.Dns).contains(svc)) {
|
||||
if (List.of(Service.UserData, Service.Dhcp, Service.Dns, Service.Vpn).contains(svc)) {
|
||||
final Set<Provider> userDataProvider = Set.of(Provider.VPCVirtualRouter);
|
||||
svcProviderMap.put(svc, userDataProvider);
|
||||
} else {
|
||||
|
|
@ -2225,6 +2250,12 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
logger.debug("Cleaning up existed site to site VPN gateways");
|
||||
_s2sVpnMgr.cleanupVpnGatewayByVpc(vpcId);
|
||||
|
||||
List<RemoteAccessVpnVO> vpns = remoteAccessVpnDao.listByVpcId(vpcId);
|
||||
for (RemoteAccessVpnVO vpn : vpns) {
|
||||
logger.debug("Disabling remote access VPN on {}", vpn.getServerAddressId());
|
||||
remoteAccessVpnMgr.destroyRemoteAccessVpnForIp(vpn.getServerAddressId(), caller, true);
|
||||
}
|
||||
|
||||
// 2) release all ip addresses
|
||||
final List<IPAddressVO> ipsToRelease = _ipAddressDao.listByAssociatedVpc(vpcId, null);
|
||||
logger.debug("Releasing ips for vpc id=" + vpcId + " as a part of vpc cleanup");
|
||||
|
|
@ -2360,6 +2391,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
restartRequired = true;
|
||||
return false;
|
||||
}
|
||||
reconfigStaticNatForVpcVr(vpcId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2867,28 +2899,38 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
@Override
|
||||
public boolean applyStaticRoutesForVpc(final long vpcId) throws ResourceUnavailableException {
|
||||
final Account caller = CallContext.current().getCallingAccount();
|
||||
final List<? extends StaticRoute> routes = _staticRouteDao.listByVpcId(vpcId);
|
||||
final List<StaticRouteVO> routes = getVpcStaticRoutes(vpcId);
|
||||
return applyStaticRoutes(routes, caller, true);
|
||||
}
|
||||
|
||||
protected boolean applyStaticRoutes(final List<? extends StaticRoute> routes, final Account caller, final boolean updateRoutesInDB) throws ResourceUnavailableException {
|
||||
final boolean success = true;
|
||||
final List<StaticRouteProfile> staticRouteProfiles = new ArrayList<StaticRouteProfile>(routes.size());
|
||||
final Map<Long, VpcGateway> gatewayMap = new HashMap<Long, VpcGateway>();
|
||||
for (final StaticRoute route : routes) {
|
||||
VpcGateway gateway = gatewayMap.get(route.getVpcGatewayId());
|
||||
if (gateway == null) {
|
||||
gateway = _vpcGatewayDao.findById(route.getVpcGatewayId());
|
||||
gatewayMap.put(gateway.getId(), gateway);
|
||||
@Override
|
||||
public boolean applyStaticRouteForVpcVpnIfNeeded(final Long vpcId, boolean updateAllVpn) throws ResourceUnavailableException {
|
||||
if (isProviderSupportServiceInVpc(vpcId, Service.Vpn, Network.Provider.VPCVirtualRouter)) {
|
||||
boolean isVpcVRSourceNat = isProviderSupportServiceInVpc(vpcId, Service.SourceNat, Network.Provider.VPCVirtualRouter);
|
||||
if (isVpcVRSourceNat) {
|
||||
logger.debug("Skipping static route configuration as VPC VR is Source NAT");
|
||||
return true;
|
||||
}
|
||||
staticRouteProfiles.add(new StaticRouteProfile(route, gateway));
|
||||
logger.debug("Configuring static route for VPC VR of VPC " + vpcId);
|
||||
final Account caller = CallContext.current().getCallingAccount();
|
||||
final List<StaticRouteVO> routes = getVpcStaticRoutes(vpcId, updateAllVpn);
|
||||
return applyStaticRoutes(routes, caller, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean applyStaticRoutes(final List<StaticRouteVO> routes, final Account caller, final boolean updateRoutesInDB) throws ResourceUnavailableException {
|
||||
final boolean success = true;
|
||||
final List<StaticRouteProfile> staticRouteProfiles = getVpcStaticRoutes(routes);
|
||||
if (!applyStaticRoutes(staticRouteProfiles)) {
|
||||
logger.warn("Routes are not completely applied");
|
||||
return false;
|
||||
} else {
|
||||
if (updateRoutesInDB) {
|
||||
for (final StaticRoute route : routes) {
|
||||
for (final StaticRouteVO route : routes) {
|
||||
if (route.isForVpn()) {
|
||||
continue;
|
||||
}
|
||||
if (route.getState() == StaticRoute.State.Revoke) {
|
||||
_staticRouteDao.remove(route.getId());
|
||||
logger.debug("Removed route " + route + " from the DB");
|
||||
|
|
@ -2951,7 +2993,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
@DB
|
||||
protected boolean revokeStaticRoutesForVpc(final long vpcId, final Account caller) throws ResourceUnavailableException {
|
||||
// get all static routes for the vpc
|
||||
final List<StaticRouteVO> routes = _staticRouteDao.listByVpcId(vpcId);
|
||||
final List<StaticRouteVO> routes = getVpcStaticRoutes(vpcId);
|
||||
logger.debug("Found " + routes.size() + " to revoke for the vpc " + vpcId);
|
||||
if (!routes.isEmpty()) {
|
||||
// mark all of them as revoke
|
||||
|
|
@ -2972,23 +3014,46 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
@Override
|
||||
@DB
|
||||
@ActionEvent(eventType = EventTypes.EVENT_STATIC_ROUTE_CREATE, eventDescription = "creating static route", create = true)
|
||||
public StaticRoute createStaticRoute(final long gatewayId, final String cidr) throws NetworkRuleConflictException {
|
||||
public StaticRoute createStaticRoute(final Long gatewayId, Long vpcId, final String nextHop, final String cidr) throws NetworkRuleConflictException {
|
||||
final Account caller = CallContext.current().getCallingAccount();
|
||||
|
||||
// parameters validation
|
||||
final VpcGateway gateway = _vpcGatewayDao.findById(gatewayId);
|
||||
if (gateway == null) {
|
||||
throw new InvalidParameterValueException("Invalid gateway id is given");
|
||||
if (gatewayId == null && nextHop == null) {
|
||||
throw new InvalidParameterValueException("one of gatewayId and nextHop must be specified");
|
||||
}
|
||||
|
||||
if (gateway.getState() != VpcGateway.State.Ready) {
|
||||
throw new InvalidParameterValueException("Gateway is not in the " + VpcGateway.State.Ready + " state: " + gateway.getState());
|
||||
if (gatewayId != null && nextHop != null) {
|
||||
throw new InvalidParameterValueException("Only one of gatewayId and nextHop can be specified");
|
||||
}
|
||||
|
||||
final Vpc vpc = getActiveVpc(gateway.getVpcId());
|
||||
if (gatewayId != null) {
|
||||
final VpcGateway gateway = _vpcGatewayDao.findById(gatewayId);
|
||||
if (gateway == null) {
|
||||
throw new InvalidParameterValueException("Invalid gateway id is given");
|
||||
}
|
||||
|
||||
if (gateway.getState() != VpcGateway.State.Ready) {
|
||||
throw new InvalidParameterValueException("Gateway is not in the " + VpcGateway.State.Ready + " state: " + gateway.getState());
|
||||
}
|
||||
|
||||
if (vpcId != null) {
|
||||
if (!vpcId.equals(gateway.getVpcId())) {
|
||||
throw new InvalidParameterValueException("Invalid gateway id is given");
|
||||
}
|
||||
} else {
|
||||
vpcId = gateway.getVpcId();
|
||||
}
|
||||
} else if (nextHop != null) {
|
||||
if (vpcId == null) {
|
||||
throw new InvalidParameterValueException("vpcId must be specified");
|
||||
}
|
||||
}
|
||||
|
||||
final Vpc vpc = getActiveVpc(vpcId);
|
||||
if (vpc == null) {
|
||||
throw new InvalidParameterValueException("Can't add static route to VPC that is being deleted");
|
||||
}
|
||||
|
||||
_accountMgr.checkAccess(caller, null, false, vpc);
|
||||
|
||||
if (!NetUtils.isValidIp4Cidr(cidr)) {
|
||||
|
|
@ -3002,7 +3067,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
}
|
||||
|
||||
// 2) CIDR should be outside of link-local cidr
|
||||
if (NetUtils.isNetworksOverlap(vpc.getCidr(), NetUtils.getLinkLocalCIDR())) {
|
||||
if (NetUtils.isNetworksOverlap(cidr, NetUtils.getLinkLocalCIDR())) {
|
||||
throw new InvalidParameterValueException("CIDR should be outside of link local cidr " + NetUtils.getLinkLocalCIDR());
|
||||
}
|
||||
|
||||
|
|
@ -3011,10 +3076,15 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
throw new InvalidParameterValueException("The static gateway cidr overlaps with one of the denied routes of the zone the VPC belongs to");
|
||||
}
|
||||
|
||||
// 4) validate next hop
|
||||
if (nextHop != null && !isNextHopValid(nextHop, vpc)) {
|
||||
throw new InvalidParameterValueException(String.format("Next hop %s is invalid. It must be within VPC CIDR or on the same public or private network", nextHop));
|
||||
}
|
||||
|
||||
return Transaction.execute(new TransactionCallbackWithException<StaticRouteVO, NetworkRuleConflictException>() {
|
||||
@Override
|
||||
public StaticRouteVO doInTransaction(final TransactionStatus status) throws NetworkRuleConflictException {
|
||||
StaticRouteVO newRoute = new StaticRouteVO(gateway.getId(), cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId());
|
||||
StaticRouteVO newRoute = new StaticRouteVO(gatewayId, cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId(), nextHop);
|
||||
logger.debug("Adding static route " + newRoute);
|
||||
newRoute = _staticRouteDao.persist(newRoute);
|
||||
|
||||
|
|
@ -3030,8 +3100,46 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
});
|
||||
}
|
||||
|
||||
private boolean isNextHopValid(String nextHop, Vpc vpc) {
|
||||
// Scenario 1: VM as next hop
|
||||
if (NetUtils.isIpWithInCidrRange(nextHop, vpc.getCidr())) {
|
||||
logger.debug("The next Hop {} is valid as it is within the VPC cidr {}", nextHop, vpc.getCidr());
|
||||
return true;
|
||||
}
|
||||
// Scenario 2: Another public IP as next hop
|
||||
List<IPAddressVO> ips = _ipAddressDao.listByAssociatedVpc(vpc.getId(), null);
|
||||
List<Long> vlanIds = new ArrayList<>();
|
||||
for (IPAddressVO ip : ips) {
|
||||
if (vlanIds.contains(ip.getVlanId())) {
|
||||
continue;
|
||||
}
|
||||
VlanVO vlan = _vlanDao.findById(ip.getVlanId());
|
||||
if (vlan != null) {
|
||||
String vlanCidr = NetUtils.getCidrFromGatewayAndNetmask(vlan.getVlanGateway(), vlan.getVlanNetmask());
|
||||
if (NetUtils.isIpWithInCidrRange(nextHop, vlanCidr)) {
|
||||
logger.debug("The next Hop {} is valid as it is on the same network as Public IP address {} ", nextHop, ip.getAddress());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
vlanIds.add(ip.getVlanId());
|
||||
}
|
||||
|
||||
// Scenario 3: An IP on private gateway as next hop
|
||||
List<VpcGatewayVO> vpcGateways = _vpcGatewayDao.listByVpcId(vpc.getId());
|
||||
for (VpcGatewayVO vpcGateway : vpcGateways) {
|
||||
String vpcGatewayCidr = NetUtils.getCidrFromGatewayAndNetmask(vpcGateway.getGateway(), vpcGateway.getNetmask());
|
||||
if (NetUtils.isIpWithInCidrRange(nextHop, vpcGatewayCidr)) {
|
||||
logger.debug("The next Hop {} is valid as it is on the same network as private gateway {} ", nextHop, vpcGateway.getIp4Address());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("The next Hop {} is invalid", nextHop);
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isCidrDenylisted(final String cidr, final long zoneId) {
|
||||
final String routesStr = NetworkOrchestrationService.GuestDomainSuffix.valueIn(zoneId);
|
||||
final String routesStr = NetworkOrchestrationService.DeniedRoutes.valueIn(zoneId);
|
||||
if (routesStr != null && !routesStr.isEmpty()) {
|
||||
final String[] cidrDenyList = routesStr.split(",");
|
||||
|
||||
|
|
@ -3435,6 +3543,15 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
&& vpcOffSvcProvidersMap.get(Service.Gateway).contains(Network.Provider.VPCVirtualRouter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSrcNatIpRequiredForVpcVr(long vpcOfferingId) {
|
||||
final Map<Network.Service, Set<Network.Provider>> vpcOffSvcProvidersMap = getVpcOffSvcProvidersMap(vpcOfferingId);
|
||||
return (Objects.nonNull(vpcOffSvcProvidersMap.get(Network.Service.SourceNat))
|
||||
&& vpcOffSvcProvidersMap.get(Network.Service.SourceNat).contains(Network.Provider.VPCVirtualRouter))
|
||||
|| (Objects.nonNull(vpcOffSvcProvidersMap.get(Network.Service.Gateway))
|
||||
&& vpcOffSvcProvidersMap.get(Service.Gateway).contains(Network.Provider.VPCVirtualRouter));
|
||||
}
|
||||
|
||||
/**
|
||||
* rollingRestartVpc performs restart of routers of a VPC by first
|
||||
* deploying a new VR and then destroying old VRs in rolling fashion. For
|
||||
|
|
@ -3524,4 +3641,241 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
protected boolean isDefaultAcl(long aclId) {
|
||||
return aclId == NetworkACL.DEFAULT_ALLOW || aclId == NetworkACL.DEFAULT_DENY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StaticRouteProfile> getVpcStaticRoutes(final List<? extends StaticRoute> routes) {
|
||||
final List<StaticRouteProfile> staticRouteProfiles = new ArrayList<>(routes.size());
|
||||
final Map<Long, VpcGateway> gatewayMap = new HashMap<Long, VpcGateway>();
|
||||
for (final StaticRoute route : routes) {
|
||||
if (route.getVpcGatewayId() != null) {
|
||||
VpcGateway gateway = gatewayMap.get(route.getVpcGatewayId());
|
||||
if (gateway == null) {
|
||||
gateway = _entityMgr.findById(VpcGateway.class, route.getVpcGatewayId());
|
||||
gatewayMap.put(gateway.getId(), gateway);
|
||||
}
|
||||
staticRouteProfiles.add(new StaticRouteProfile(route, gateway));
|
||||
} else {
|
||||
staticRouteProfiles.add(new StaticRouteProfile(route));
|
||||
}
|
||||
}
|
||||
return staticRouteProfiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StaticRouteVO> getVpcStaticRoutes(Long vpcId) {
|
||||
return getVpcStaticRoutes(vpcId, false);
|
||||
}
|
||||
|
||||
public List<StaticRouteVO> getVpcStaticRoutes(Long vpcId, boolean updateAllVpn) {
|
||||
final List<StaticRouteVO> routes = _staticRouteDao.listByVpcId(vpcId);
|
||||
|
||||
if (isProviderSupportServiceInVpc(vpcId, Service.Vpn, Network.Provider.VPCVirtualRouter)
|
||||
&& !isProviderSupportServiceInVpc(vpcId, Service.SourceNat, Network.Provider.VPCVirtualRouter)) {
|
||||
|
||||
Vpc vpc = vpcDao.findById(vpcId);
|
||||
IPAddressVO ipAddressForVpcVR = getIpAddressForVpcVr(vpc, null, false);
|
||||
String nextHop = getFirstGuestIpAddressForVpcVr(vpc.getId());
|
||||
|
||||
if (ipAddressForVpcVR != null && (updateAllVpn || nextHop != null)) {
|
||||
// Add Static Routes for Remote Access VPN
|
||||
List<StaticRouteVO> staticRoutesForRemoteAccessVpn = new ArrayList<>();
|
||||
RemoteAccessVpnVO remoteAccessVpn = remoteAccessVpnDao.findByPublicIpAddress(ipAddressForVpcVR.getId());
|
||||
if (remoteAccessVpn != null) {
|
||||
String ipRange = remoteAccessVpn.getIpRange();
|
||||
String startIp = ipRange.split("-")[0];
|
||||
String endIp = ipRange.split("-")[1];
|
||||
int cidrSize = NetUtils.getBigCidrSizeOfIpRange(NetUtils.ip2Long(startIp), NetUtils.ip2Long(endIp));
|
||||
String cidr = NetUtils.transformCidr(startIp + "/" + cidrSize);
|
||||
if (nextHop == null || RemoteAccessVpn.State.Removed.equals(remoteAccessVpn.getState())) {
|
||||
StaticRouteVO newRoute = new StaticRouteVO(cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId(), null,
|
||||
StaticRoute.State.Revoke, true);
|
||||
staticRoutesForRemoteAccessVpn.add(newRoute);
|
||||
} else {
|
||||
StaticRoute.State state = updateAllVpn ? StaticRoute.State.Update : StaticRoute.State.Add;
|
||||
StaticRouteVO newRoute = new StaticRouteVO(cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId(), nextHop,
|
||||
state, true);
|
||||
staticRoutesForRemoteAccessVpn.add(newRoute);
|
||||
}
|
||||
}
|
||||
logger.debug("Adding {} static routes for Remote Access VPN", staticRoutesForRemoteAccessVpn.size());
|
||||
routes.addAll(staticRoutesForRemoteAccessVpn);
|
||||
|
||||
// Add Static Routes for Site-to-Site VPN connections
|
||||
List<StaticRouteVO> staticRoutesForSite2SiteVpn = new ArrayList<>();
|
||||
List<Site2SiteVpnConnectionVO> vpnConnections = site2SiteVpnConnectionDao.listByVpcId(vpcId);
|
||||
for (Site2SiteVpnConnectionVO vpnConnection : vpnConnections) {
|
||||
Site2SiteCustomerGatewayVO customerGateway = site2SiteCustomerGatewayDao.findById(vpnConnection.getCustomerGatewayId());
|
||||
if (nextHop == null || Site2SiteVpnConnection.State.Removed.equals(vpnConnection.getState())) {
|
||||
for (String cidr: customerGateway.getGuestCidrList().split(",")) {
|
||||
StaticRouteVO newRoute = new StaticRouteVO(cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId(), null,
|
||||
StaticRoute.State.Revoke, true);
|
||||
staticRoutesForSite2SiteVpn.add(newRoute);
|
||||
}
|
||||
} else {
|
||||
StaticRoute.State state = updateAllVpn ? StaticRoute.State.Update : StaticRoute.State.Add;
|
||||
for (String cidr : customerGateway.getGuestCidrList().split(",")) {
|
||||
StaticRouteVO newRoute = new StaticRouteVO(cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId(), nextHop,
|
||||
state, true);
|
||||
staticRoutesForSite2SiteVpn.add(newRoute);
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.debug("Adding {} static routes for {} Site-to-Site VPN connections",
|
||||
staticRoutesForSite2SiteVpn.size(), vpnConnections.size());
|
||||
routes.addAll(staticRoutesForSite2SiteVpn);
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("Found {} static routes for VPC {}", routes.size(), vpcId);
|
||||
return routes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProviderSupportServiceInVpc(long vpcId, Service service, Provider provider) {
|
||||
return _vpcSrvcDao.canProviderSupportServiceInVpc(vpcId, service, provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPAddressVO getIpAddressForVpcVr(Vpc vpc, IPAddressVO ipAddress, boolean allocateIpIfNeeded) {
|
||||
// Validate if the IP address is associated to a VPC VR
|
||||
final List<IPAddressVO> ips = _ipAddressDao.listByAssociatedVpc(vpc.getId(), null);
|
||||
IPAddressVO ipAddressForVR = ips.stream().filter(ip -> ip.isForRouter()).findFirst().orElse(null);
|
||||
if (ipAddressForVR != null) {
|
||||
if (ipAddress != null && ipAddressForVR.getId() != ipAddress.getId()) {
|
||||
throw new InvalidParameterValueException(String.format("Cannot assign Public IP %s to VPC VR as %s has been associated to the VPC VR.",
|
||||
ipAddress.getAddress().addr(), ipAddressForVR.getAddress().addr()));
|
||||
}
|
||||
return ipAddressForVR;
|
||||
} else if (ipAddress != null) {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
if (allocateIpIfNeeded) {
|
||||
Account account = _accountMgr.getAccount(vpc.getAccountId());
|
||||
DataCenter zone = _dcDao.findById(vpc.getZoneId());
|
||||
try {
|
||||
IpAddress ip = _ipAddrMgr.allocateIp(account, false, CallContext.current().getCallingAccount(),
|
||||
CallContext.current().getCallingUserId(), zone, null, null);
|
||||
this.associateIPToVpc(ip.getId(), vpc.getId());
|
||||
return _ipAddressDao.findById(ip.getId());
|
||||
} catch (InsufficientAddressCapacityException | ResourceAllocationException |
|
||||
ResourceUnavailableException ex) {
|
||||
throw new InvalidParameterValueException("Cannot assign Public IP to VPC VR: " + ex.getMessage());
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* This method configures the Static Nat for VPC VR if it is used for VPN but not Source NAT.
|
||||
* (1) Update forRouter to true and one-to-one to true
|
||||
* (2) Get current network and router ID/IP
|
||||
* (3) Get new network and router ID/IP
|
||||
* (4) If network or IP is changed (in case VPC tier is removed or shutdown), disable/apply Static NAT with new VM ID and VM IP
|
||||
* (5) otherwise, If VPC VR ID does not exist or is changed, update the VM ID.
|
||||
* (6) otherwise, do nothing
|
||||
*
|
||||
* This is used in the following processes
|
||||
* (1) create remote access VPN
|
||||
* (2) create S2S VPN
|
||||
* (3) destroy Router
|
||||
* (4) restart Vpc with cleanup
|
||||
* (5) add VPC tier
|
||||
* (6) delete VPC tier
|
||||
* (7) remove VPC
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean configStaticNatForVpcVr(Vpc vpc, IPAddressVO ipAddress) {
|
||||
logger.debug("Configuring static nat for VPC VR of VPC " + vpc.getId());
|
||||
// (1) Update forRouter to true and one-to-one to true
|
||||
if (!ipAddress.isForRouter()) {
|
||||
ipAddress.setForRouter(true);
|
||||
ipAddress.setOneToOneNat(true);
|
||||
_ipAddressDao.update(ipAddress.getId(), ipAddress);
|
||||
}
|
||||
|
||||
// (2) Get current network and router ID/IP
|
||||
Long currentNetworkId = ipAddress.getAssociatedWithNetworkId();
|
||||
Long currentRouterId = ipAddress.getAssociatedWithVmId();
|
||||
String currentRouterIp = ipAddress.getVmIp();
|
||||
|
||||
// (3) Get new network and router ID/IP
|
||||
Long newNetworkId = null;
|
||||
Long newRouterId = null;
|
||||
String newRouterIp = null;
|
||||
List<NetworkVO> networks = _ntwkDao.listByVpc(vpc.getId());
|
||||
for (NetworkVO network : networks) {
|
||||
NicVO newNic = nicDao.findNonPlaceHolderByNetworkIdAndType(network.getId(), VirtualMachine.Type.DomainRouter);
|
||||
if (newNic != null) {
|
||||
logger.debug("Got VPC VR NIC for network {}: {}", network.getId(), newNic);
|
||||
newNetworkId = network.getId();
|
||||
newRouterId = newNic.getInstanceId();
|
||||
newRouterIp = newNic.getIPv4Address();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Do nothing if the current and new network and router are Null
|
||||
if (ObjectUtils.allNull(currentNetworkId, currentRouterId, newNetworkId, newRouterId)) {
|
||||
logger.debug("The current and new network and router are Null, do nothing");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (currentNetworkId == null || !currentNetworkId.equals(newNetworkId)) {
|
||||
// (4) If network or IP is changed (in case VPC tier is removed or shutdown), disable/apply Static NAT with new VM ID and VM IP
|
||||
if (currentNetworkId != null) {
|
||||
// Disable Static NAT for current VPC VR
|
||||
logger.debug("Disabling static nat for VPC VR (network: {}, router: {})", currentNetworkId, currentRouterId);
|
||||
CallContext ctx = CallContext.current();
|
||||
if (!rulesManager.applyStaticNatForIp(ipAddress.getId(), false, ctx.getCallingAccount(),true)) {
|
||||
throw new CloudRuntimeException("Failed to disable static nat for VPC VR");
|
||||
}
|
||||
ipAddress.setAssociatedWithNetworkId(null);
|
||||
ipAddress.setAssociatedWithVmId(null);
|
||||
ipAddress.setVmIp(null);
|
||||
_ipAddressDao.update(ipAddress.getId(), ipAddress);
|
||||
}
|
||||
if (newNetworkId != null) {
|
||||
// Enable static nat for the new VPC VR
|
||||
logger.debug("Enabling static nat for VPC VR (network: {}, router: {})", newNetworkId, newRouterId);
|
||||
ipAddress.setAssociatedWithNetworkId(newNetworkId);
|
||||
ipAddress.setAssociatedWithVmId(newRouterId);
|
||||
ipAddress.setVmIp(newRouterIp);
|
||||
_ipAddressDao.update(ipAddress.getId(), ipAddress);
|
||||
CallContext ctx = CallContext.current();
|
||||
if (!rulesManager.applyStaticNatForIp(ipAddress.getId(), false, ctx.getCallingAccount(),false)) {
|
||||
throw new CloudRuntimeException("Failed to enable static nat for VPC VR");
|
||||
}
|
||||
}
|
||||
} else if (currentRouterId == null || !currentRouterId.equals(newRouterId)) {
|
||||
// (5) otherwise, If VPC VR ID does not exist or is changed, update the VM ID.
|
||||
ipAddress.setAssociatedWithVmId(newRouterId);
|
||||
ipAddress.setVmIp(newRouterIp);
|
||||
_ipAddressDao.update(ipAddress.getId(), ipAddress);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconfigStaticNatForVpcVr(Long vpcId) {
|
||||
Vpc vpc = vpcDao.findById(vpcId);
|
||||
IPAddressVO ipAddressForVpcVR = getIpAddressForVpcVr(vpc, null, false);
|
||||
if (ipAddressForVpcVR != null && !configStaticNatForVpcVr(vpc, ipAddressForVpcVR)) {
|
||||
throw new CloudRuntimeException("Failed to reconfig static nat for VPC VR as part of the process");
|
||||
}
|
||||
}
|
||||
|
||||
private String getFirstGuestIpAddressForVpcVr(Long vpcId) {
|
||||
String nextHop = null;
|
||||
List<NetworkVO> networks = _ntwkDao.listByVpc(vpcId);
|
||||
for (NetworkVO network : networks) {
|
||||
NicVO nic = nicDao.findNonPlaceHolderByNetworkIdAndType(network.getId(), VirtualMachine.Type.DomainRouter);
|
||||
if (nic != null) {
|
||||
nextHop = nic.getIPv4Address();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nextHop;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ import com.cloud.network.rules.FirewallRule.Purpose;
|
|||
import com.cloud.network.rules.FirewallRuleVO;
|
||||
import com.cloud.network.rules.RulesManager;
|
||||
import com.cloud.network.vpc.Vpc;
|
||||
import com.cloud.network.vpc.VpcManager;
|
||||
import com.cloud.network.vpc.dao.VpcDao;
|
||||
import com.cloud.projects.Project.ListProjectResourcesCriteria;
|
||||
import com.cloud.server.ConfigurationServer;
|
||||
|
|
@ -124,6 +125,9 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc
|
|||
UsageEventDao _usageEventDao;
|
||||
@Inject
|
||||
ConfigurationDao _configDao;
|
||||
@Inject
|
||||
VpcManager vpcManager;
|
||||
|
||||
List<RemoteAccessVPNServiceProvider> _vpnServiceProviders;
|
||||
|
||||
@Inject
|
||||
|
|
@ -181,7 +185,11 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc
|
|||
|
||||
Long networkId = ipAddress.getAssociatedWithNetworkId();
|
||||
if (networkId != null) {
|
||||
_networkMgr.checkIpForService(ipAddress, Service.Vpn, null);
|
||||
if (ipAddress.isForRouter()) {
|
||||
logger.debug("The IP address is reserved for Domain Router, skipping the check now");
|
||||
} else {
|
||||
_networkMgr.checkIpForService(ipAddress, Service.Vpn, null);
|
||||
}
|
||||
}
|
||||
|
||||
final Long vpcId = ipAddress.getVpcId();
|
||||
|
|
@ -232,9 +240,11 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc
|
|||
throw new InvalidParameterValueException("Vpn service is not supported in network id=" + ipAddr.getAssociatedWithNetworkId());
|
||||
}
|
||||
cidr = NetUtils.getCidr(network.getCidr());
|
||||
validateIpAddressForVpnServiceOnNetwork(network, ipAddress);
|
||||
} else {
|
||||
Vpc vpc = _vpcDao.findById(vpcId);
|
||||
cidr = NetUtils.getCidr(vpc.getCidr());
|
||||
validateIpAddressForVpnServiceOnVpc(vpc, ipAddress);
|
||||
}
|
||||
|
||||
String[] guestIpRange = NetUtils.getIpRangeFromCidr(cidr.first(), cidr.second());
|
||||
|
|
@ -257,13 +267,62 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc
|
|||
if (forDisplay != null) {
|
||||
remoteAccessVpnVO.setDisplay(forDisplay);
|
||||
}
|
||||
return _remoteAccessVpnDao.persist(remoteAccessVpnVO);
|
||||
remoteAccessVpnVO = _remoteAccessVpnDao.persist(remoteAccessVpnVO);
|
||||
if (vpcId != null) {
|
||||
try {
|
||||
vpcManager.applyStaticRouteForVpcVpnIfNeeded(vpcId, false);
|
||||
} catch (ResourceUnavailableException | CloudRuntimeException e) {
|
||||
logger.error("Unable to apply static routes for vpc " + vpcId + " due to " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return remoteAccessVpnVO;
|
||||
});
|
||||
} finally {
|
||||
_ipAddressDao.releaseFromLockTable(publicIpId);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateIpAddressForVpnServiceOnNetwork(Network network, IPAddressVO ipAddress) {
|
||||
Long networkId = network.getId();
|
||||
if (_networkMgr.isProviderSupportServiceInNetwork(networkId, Service.Vpn, Network.Provider.VirtualRouter)) {
|
||||
// if VR is the VPN provider,
|
||||
// (1) if VR is Source NAT, the IP address must be used as Source NAT
|
||||
// (2) if VR is not Source NAT, the IP address must not be used as Source NAT
|
||||
boolean isVRSourceNat = _networkMgr.isProviderSupportServiceInNetwork(networkId, Service.SourceNat, Network.Provider.VirtualRouter);
|
||||
if (isVRSourceNat && !ipAddress.isSourceNat()) {
|
||||
throw new InvalidParameterValueException("Vpn service can only be configured on the Source NAT IP of network id=" + ipAddress.getAssociatedWithNetworkId());
|
||||
}
|
||||
if (!isVRSourceNat && ipAddress.isSourceNat()) {
|
||||
throw new InvalidParameterValueException("Vpn service can not be configured on the Source NAT IP of network id=" + ipAddress.getAssociatedWithNetworkId());
|
||||
}
|
||||
if (!isVRSourceNat) {
|
||||
throw new InvalidParameterValueException("Currently it is not supported to create Vpn service on a non-Source NAT IP of network id=" + ipAddress.getAssociatedWithNetworkId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateIpAddressForVpnServiceOnVpc(Vpc vpc, IPAddressVO ipAddress) {
|
||||
Long vpcId = vpc.getId();
|
||||
if (vpcManager.isProviderSupportServiceInVpc(vpcId, Service.Vpn, Network.Provider.VPCVirtualRouter)) {
|
||||
// if VPC VR is the VPN provider,
|
||||
// (1) if VPC VR is Source NAT, the IP address must be used as Source NAT
|
||||
// (2) if VPC VR is not Source NAT, the IP address must not be used as Source NAT
|
||||
boolean isVpcVRSourceNat = vpcManager.isProviderSupportServiceInVpc(vpcId, Service.SourceNat, Network.Provider.VPCVirtualRouter);
|
||||
if (isVpcVRSourceNat && !ipAddress.isSourceNat()) {
|
||||
throw new InvalidParameterValueException("Vpn service can only be configured on the Source NAT IP of VPC id=" + ipAddress.getVpcId());
|
||||
}
|
||||
if (!isVpcVRSourceNat && ipAddress.isSourceNat()) {
|
||||
throw new InvalidParameterValueException("Vpn service can not be configured on the Source NAT IP of VPC id=" + ipAddress.getVpcId());
|
||||
}
|
||||
if (!isVpcVRSourceNat) {
|
||||
IPAddressVO ipAddressForVpcVR = vpcManager.getIpAddressForVpcVr(vpc, ipAddress, true);
|
||||
if (!vpcManager.configStaticNatForVpcVr(vpc, ipAddressForVpcVR)) {
|
||||
throw new CloudRuntimeException("Failed to enable static nat for VPC VR as part of remote access vpn creation");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRemoteAccessVpnConfiguration() throws ConfigurationException {
|
||||
String ipRange = RemoteAccessVpnClientIpRange.value();
|
||||
if (ipRange == null) {
|
||||
|
|
@ -365,6 +424,14 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc
|
|||
Transaction.execute(new TransactionCallbackNoReturn() {
|
||||
@Override
|
||||
public void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
if (vpn.getVpcId() != null) {
|
||||
try {
|
||||
vpcManager.applyStaticRouteForVpcVpnIfNeeded(vpn.getVpcId(), false);
|
||||
} catch (ResourceUnavailableException | CloudRuntimeException e) {
|
||||
logger.error("Unable to apply static routes for vpc " + vpn.getVpcId() + " due to " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
_remoteAccessVpnDao.remove(vpn.getId());
|
||||
|
||||
List<VpnUserVO> vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId());
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ import com.cloud.event.EventTypes;
|
|||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.PermissionDeniedException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.network.IpAddressManager;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.network.Site2SiteCustomerGateway;
|
||||
import com.cloud.network.Site2SiteVpnConnection;
|
||||
import com.cloud.network.Site2SiteVpnConnection.State;
|
||||
|
|
@ -61,9 +63,12 @@ import com.cloud.network.dao.Site2SiteVpnConnectionVO;
|
|||
import com.cloud.network.dao.Site2SiteVpnGatewayDao;
|
||||
import com.cloud.network.dao.Site2SiteVpnGatewayVO;
|
||||
import com.cloud.network.element.Site2SiteVpnServiceProvider;
|
||||
import com.cloud.network.vpc.Vpc;
|
||||
import com.cloud.network.vpc.VpcManager;
|
||||
import com.cloud.network.vpc.VpcVO;
|
||||
import com.cloud.network.vpc.VpcOfferingServiceMapVO;
|
||||
import com.cloud.network.vpc.dao.VpcDao;
|
||||
import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao;
|
||||
import com.cloud.projects.Project.ListProjectResourcesCriteria;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
|
|
@ -80,6 +85,7 @@ import com.cloud.utils.db.SearchCriteria;
|
|||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.net.NetUtils;
|
||||
import com.cloud.vm.DomainRouterVO;
|
||||
import com.cloud.vm.dao.DomainRouterDao;
|
||||
|
||||
@Component
|
||||
public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpnManager {
|
||||
|
|
@ -100,11 +106,17 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
|
|||
@Inject
|
||||
ConfigurationDao _configDao;
|
||||
@Inject
|
||||
VpcManager _vpcMgr;
|
||||
@Inject
|
||||
AccountManager _accountMgr;
|
||||
@Inject
|
||||
private AnnotationDao annotationDao;
|
||||
@Inject
|
||||
VpcOfferingServiceMapDao vpcOfferingServiceMapDao;
|
||||
@Inject
|
||||
private DomainRouterDao domainRouterDao;
|
||||
@Inject
|
||||
private IpAddressManager ipAddressManager;
|
||||
@Inject
|
||||
private VpcManager vpcManager;
|
||||
|
||||
int _connLimit;
|
||||
int _subnetsLimit;
|
||||
|
|
@ -136,13 +148,9 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
|
|||
if (gws != null) {
|
||||
throw new InvalidParameterValueException("The VPN gateway of VPC " + vpcId + " already existed!");
|
||||
}
|
||||
//Use source NAT ip for VPC
|
||||
List<IPAddressVO> ips = _ipAddressDao.listByAssociatedVpc(vpcId, true);
|
||||
if (ips.size() != 1) {
|
||||
throw new CloudRuntimeException("Cannot found source nat ip of vpc " + vpcId);
|
||||
}
|
||||
|
||||
Site2SiteVpnGatewayVO gw = new Site2SiteVpnGatewayVO(owner.getAccountId(), owner.getDomainId(), ips.get(0).getId(), vpcId);
|
||||
IPAddressVO ipAddress = getIpAddressIdForVpn(vpcId, vpc.getVpcOfferingId());
|
||||
Site2SiteVpnGatewayVO gw = new Site2SiteVpnGatewayVO(owner.getAccountId(), owner.getDomainId(), ipAddress.getId(), vpcId);
|
||||
|
||||
if (cmd.getDisplay() != null) {
|
||||
gw.setDisplay(cmd.getDisplay());
|
||||
|
|
@ -152,6 +160,29 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
|
|||
return gw;
|
||||
}
|
||||
|
||||
private IPAddressVO getIpAddressIdForVpn(Long vpcId, Long vpcOferingId) {
|
||||
VpcOfferingServiceMapVO mapForSourceNat = vpcOfferingServiceMapDao.findByServiceProviderAndOfferingId(Network.Service.SourceNat.getName(), Network.Provider.VPCVirtualRouter.getName(), vpcOferingId);
|
||||
VpcOfferingServiceMapVO mapForVpn = vpcOfferingServiceMapDao.findByServiceProviderAndOfferingId(Network.Service.Vpn.getName(), Network.Provider.VPCVirtualRouter.getName(), vpcOferingId);
|
||||
if (mapForSourceNat == null && mapForVpn != null) {
|
||||
// Use Static NAT IP of VPC VR
|
||||
logger.debug(String.format("The VPC VR provides %s Service, however it does not provide %s service, trying to configure using IP of VPC VR", Network.Service.Vpn.getName(), Network.Service.SourceNat.getName()));
|
||||
|
||||
Vpc vpc = _vpcDao.findById(vpcId);
|
||||
IPAddressVO ipAddressForVpcVR = vpcManager.getIpAddressForVpcVr(vpc, null, true);
|
||||
if (!vpcManager.configStaticNatForVpcVr(vpc, ipAddressForVpcVR)) {
|
||||
throw new CloudRuntimeException("Failed to enable static nat for VPC VR as part of vpn gateway");
|
||||
}
|
||||
return ipAddressForVpcVR;
|
||||
} else {
|
||||
//Use source NAT ip for VPC
|
||||
List<IPAddressVO> ips = _ipAddressDao.listByAssociatedVpc(vpcId, true);
|
||||
if (ips.size() != 1) {
|
||||
throw new CloudRuntimeException("Cannot found source nat ip of vpc " + vpcId);
|
||||
}
|
||||
return ips.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkCustomerGatewayCidrList(String guestCidrList) {
|
||||
String[] cidrList = guestCidrList.split(",");
|
||||
if (cidrList.length > _subnetsLimit) {
|
||||
|
|
@ -272,7 +303,8 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
|
|||
String[] cidrList = customerGateway.getGuestCidrList().split(",");
|
||||
|
||||
// Remote sub nets cannot overlap VPC's sub net
|
||||
String vpcCidr = _vpcDao.findById(vpnGateway.getVpcId()).getCidr();
|
||||
Vpc vpc = _vpcDao.findById(vpnGateway.getVpcId());
|
||||
String vpcCidr = vpc.getCidr();
|
||||
for (String cidr : cidrList) {
|
||||
if (NetUtils.isNetworksOverlap(vpcCidr, cidr)) {
|
||||
throw new InvalidParameterValueException("The subnets of customer gateway " + customerGatewayId + "'s subnet " + cidr + " is overlapped with VPC cidr " +
|
||||
|
|
@ -308,6 +340,13 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
|
|||
}
|
||||
|
||||
_vpnConnectionDao.persist(conn);
|
||||
|
||||
try {
|
||||
vpcManager.applyStaticRouteForVpcVpnIfNeeded(vpc.getId(), false);
|
||||
} catch (ResourceUnavailableException | CloudRuntimeException e) {
|
||||
logger.error("Unable to apply static routes for vpc " + vpc.getId() + " due to " + e.getMessage());
|
||||
}
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
|
@ -584,7 +623,19 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
|
|||
if (conn.getState() != State.Pending) {
|
||||
stopVpnConnection(id);
|
||||
}
|
||||
|
||||
conn.setState(State.Removed);
|
||||
_vpnConnectionDao.update(id, conn);
|
||||
|
||||
final Site2SiteVpnGateway vpnGateway = _vpnGatewayDao.findById(conn.getVpnGatewayId());
|
||||
try {
|
||||
vpcManager.applyStaticRouteForVpcVpnIfNeeded(vpnGateway.getVpcId(), false);
|
||||
} catch (ResourceUnavailableException | CloudRuntimeException e) {
|
||||
logger.error("Unable to apply static routes for vpc " + vpnGateway.getVpcId() + " due to " + e.getMessage());
|
||||
}
|
||||
|
||||
_vpnConnectionDao.remove(id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1255,6 +1255,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
|
|||
serviceProviderMap.put(Service.Dhcp, routerProvider);
|
||||
serviceProviderMap.put(Service.Dns, routerProvider);
|
||||
serviceProviderMap.put(Service.UserData, routerProvider);
|
||||
serviceProviderMap.put(Service.Vpn, routerProvider);
|
||||
if (forVpc) {
|
||||
serviceProviderMap.put(Service.NetworkACL, provider);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1021,13 +1021,20 @@ class CsSite2SiteVpn(CsDataBag):
|
|||
local_ip = self.dbag[vpn]['local_public_ip']
|
||||
dev = CsHelper.get_device(local_ip)
|
||||
|
||||
if not self.config.has_public_network():
|
||||
for interface in self.config.address().get_interfaces():
|
||||
if interface.is_guest() and interface.is_added():
|
||||
dev = interface.get_device()
|
||||
local_ip = interface.get_ip()
|
||||
break
|
||||
|
||||
if dev == "":
|
||||
logging.error("Request for ipsec to %s not possible because ip is not configured", local_ip)
|
||||
continue
|
||||
|
||||
CsHelper.start_if_stopped("ipsec")
|
||||
self.configure_iptables(dev, self.dbag[vpn])
|
||||
self.configure_ipsec(self.dbag[vpn])
|
||||
self.configure_iptables(dev, local_ip, self.dbag[vpn])
|
||||
self.configure_ipsec(local_ip, self.dbag[vpn])
|
||||
|
||||
# Delete vpns that are no longer in the configuration
|
||||
for ip in self.confips:
|
||||
|
|
@ -1043,10 +1050,10 @@ class CsSite2SiteVpn(CsDataBag):
|
|||
os.remove(vpnsecretsfile)
|
||||
CsHelper.execute("ipsec reload")
|
||||
|
||||
def configure_iptables(self, dev, obj):
|
||||
self.fw.append(["", "front", "-A INPUT -i %s -p udp -m udp --dport 500 -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], obj['local_public_ip'])])
|
||||
self.fw.append(["", "front", "-A INPUT -i %s -p udp -m udp --dport 4500 -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], obj['local_public_ip'])])
|
||||
self.fw.append(["", "front", "-A INPUT -i %s -p esp -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], obj['local_public_ip'])])
|
||||
def configure_iptables(self, dev, local_ip, obj):
|
||||
self.fw.append(["", "front", "-A INPUT -i %s -p udp -m udp --dport 500 -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], local_ip)])
|
||||
self.fw.append(["", "front", "-A INPUT -i %s -p udp -m udp --dport 4500 -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], local_ip)])
|
||||
self.fw.append(["", "front", "-A INPUT -i %s -p esp -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], local_ip)])
|
||||
self.fw.append(["nat", "front", "-A POSTROUTING -t nat -o %s -m mark --mark 0x525 -j ACCEPT" % dev])
|
||||
for net in obj['peer_guest_cidr_list'].lstrip().rstrip().split(','):
|
||||
self.fw.append(["mangle", "front",
|
||||
|
|
@ -1058,7 +1065,7 @@ class CsSite2SiteVpn(CsDataBag):
|
|||
self.fw.append(["mangle", "",
|
||||
"-A INPUT -s %s -d %s -j MARK --set-xmark 0x524/0xffffffff" % (net, obj['local_guest_cidr'])])
|
||||
|
||||
def configure_ipsec(self, obj):
|
||||
def configure_ipsec(self, local_ip, obj):
|
||||
leftpeer = obj['local_public_ip']
|
||||
rightpeer = obj['peer_gateway_ip']
|
||||
peerlist = obj['peer_guest_cidr_list'].replace(' ', '')
|
||||
|
|
@ -1080,7 +1087,8 @@ class CsSite2SiteVpn(CsDataBag):
|
|||
file.repopulate() # This avoids issues when switching off split_connections or removing subnets with split_connections == true
|
||||
file.add("#conn for vpn-%s" % rightpeer, 0)
|
||||
file.search("conn ", "conn vpn-%s" % rightpeer)
|
||||
file.addeq(" left=%s" % leftpeer)
|
||||
file.addeq(" left=%s" % local_ip)
|
||||
file.addeq(" leftid=%s" % leftpeer)
|
||||
file.addeq(" leftsubnet=%s" % obj['local_guest_cidr'])
|
||||
file.addeq(" right=%s" % rightpeer)
|
||||
file.addeq(" rightsubnet=%s" % peerlist)
|
||||
|
|
@ -1100,7 +1108,7 @@ class CsSite2SiteVpn(CsDataBag):
|
|||
file.addeq(" dpddelay=30")
|
||||
file.addeq(" dpdtimeout=120")
|
||||
file.addeq(" dpdaction=restart")
|
||||
if splitconnections and peerlistarr.count > 1:
|
||||
if splitconnections and len(peerlistarr) > 1:
|
||||
logging.debug('Splitting connections for rightsubnets %s' % peerlistarr)
|
||||
for peeridx in range(1, len(peerlistarr)):
|
||||
logging.debug('Adding split connection -%d for subnet %s' % (peeridx + 1, peerlistarr[peeridx]))
|
||||
|
|
@ -1221,9 +1229,17 @@ class CsRemoteAccessVpn(CsDataBag):
|
|||
logging.debug("Enabling remote access vpn on " + public_ip)
|
||||
|
||||
CsHelper.start_if_stopped("ipsec")
|
||||
self.configure_l2tpIpsec(public_ip, self.dbag[public_ip])
|
||||
|
||||
logging.debug("Remote accessvpn data bag %s", self.dbag)
|
||||
self.remoteaccessvpn_iptables(public_ip, self.dbag[public_ip])
|
||||
if not self.config.has_public_network():
|
||||
for interface in self.config.address().get_interfaces():
|
||||
if interface.is_guest() and interface.is_added():
|
||||
self.configure_l2tpIpsec(interface.get_ip(), self.dbag[public_ip])
|
||||
self.remoteaccessvpn_iptables(interface.get_device(), interface.get_ip(), self.dbag[public_ip])
|
||||
break
|
||||
else:
|
||||
self.configure_l2tpIpsec(public_ip, self.dbag[public_ip])
|
||||
self.remoteaccessvpn_iptables(self.dbag['public_interface'], public_ip, self.dbag[public_ip])
|
||||
|
||||
CsHelper.execute("ipsec update")
|
||||
CsHelper.execute("systemctl start xl2tpd")
|
||||
|
|
@ -1248,6 +1264,7 @@ class CsRemoteAccessVpn(CsDataBag):
|
|||
# Left
|
||||
l2tpfile = CsFile(l2tpconffile)
|
||||
l2tpfile.addeq(" left=%s" % left)
|
||||
l2tpfile.addeq(" leftid=%s" % obj['vpn_server_ip'])
|
||||
l2tpfile.commit()
|
||||
|
||||
secret = CsFile(vpnsecretfilte)
|
||||
|
|
@ -1264,8 +1281,7 @@ class CsRemoteAccessVpn(CsDataBag):
|
|||
xl2tpoptions.search("ms-dns ", "ms-dns %s" % localip)
|
||||
xl2tpoptions.commit()
|
||||
|
||||
def remoteaccessvpn_iptables(self, publicip, obj):
|
||||
publicdev = obj['public_interface']
|
||||
def remoteaccessvpn_iptables(self, publicdev, publicip, obj):
|
||||
localcidr = obj['local_cidr']
|
||||
local_ip = obj['local_ip']
|
||||
|
||||
|
|
@ -1640,7 +1656,7 @@ def main(argv):
|
|||
("dhcp", {"process_iptables": False, "executor": [CsDhcp("dhcpentry", config)]}),
|
||||
("load_balancer", {"process_iptables": True, "executor": []}),
|
||||
("monitor_service", {"process_iptables": False, "executor": [CsMonitor("monitorservice", config)]}),
|
||||
("static_routes", {"process_iptables": False, "executor": [CsStaticRoutes("staticroutes", config)]})
|
||||
("static_routes", {"process_iptables": True, "executor": [CsStaticRoutes("staticroutes", config)]})
|
||||
])
|
||||
|
||||
if not config.is_vpc():
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ class CsIP:
|
|||
|
||||
interfaces = [CsInterface(address, self.config)]
|
||||
CsHelper.reconfigure_interfaces(self.cl, interfaces)
|
||||
if self.get_type() in ['public'] and not self.config.is_routed():
|
||||
if self.get_type() in ['public'] and not self.config.is_routed() and self.config.has_public_network():
|
||||
self.set_mark()
|
||||
|
||||
if 'gateway' in self.address:
|
||||
|
|
@ -360,7 +360,14 @@ class CsIP:
|
|||
# The code looks redundant here, but we actually have to cater for routers and
|
||||
# VPC routers in a different manner. Please do not remove this block otherwise
|
||||
# The VPC default route will be broken.
|
||||
if self.get_type() in ["public"] and address["device"] == CsHelper.PUBLIC_INTERFACES[self.cl.get_type()]:
|
||||
if not self.config.has_public_network():
|
||||
for interface in self.config.address().get_interfaces():
|
||||
if interface.is_guest() and interface.is_added() and interface.get_device() == self.dev:
|
||||
gateway = interface.get_gateway()
|
||||
route.add_defaultroute(gateway)
|
||||
CsHelper.execute("sudo echo 0 > /proc/sys/net/ipv4/conf/%s/rp_filter" % interface.get_device())
|
||||
break
|
||||
elif self.get_type() in ["public"] and address["device"] == CsHelper.PUBLIC_INTERFACES[self.cl.get_type()]:
|
||||
gateway = str(address["gateway"])
|
||||
route.add_defaultroute(gateway)
|
||||
else:
|
||||
|
|
@ -426,7 +433,7 @@ class CsIP:
|
|||
self.fw.append(["filter", "", "-P FORWARD DROP"])
|
||||
|
||||
def fw_router(self):
|
||||
if self.config.is_vpc() or self.config.is_routed():
|
||||
if self.config.is_vpc() or self.config.is_routed() or self.config.is_dhcp():
|
||||
return
|
||||
|
||||
self.fw.append(["mangle", "front", "-A PREROUTING " +
|
||||
|
|
@ -523,20 +530,24 @@ class CsIP:
|
|||
self.fw.append(["mangle", "front", "-A PREROUTING " +
|
||||
" -i %s -m state --state RELATED,ESTABLISHED " % self.dev +
|
||||
"-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff"])
|
||||
guestNetworkCidr = self.address['network']
|
||||
self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" %
|
||||
(guestNetworkCidr, self.dev, self.dev)])
|
||||
self.fw.append(
|
||||
["filter", "front", "-A ACL_INBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev])
|
||||
self.fw.append(
|
||||
["filter", "front", "-A ACL_INBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev])
|
||||
self.fw.append(
|
||||
["filter", "", "-A ACL_INBOUND_%s -j DROP" % self.dev])
|
||||
|
||||
self.fw.append(
|
||||
["mangle", "front", "-A ACL_OUTBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev])
|
||||
self.fw.append(
|
||||
["mangle", "front", "-A ACL_OUTBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev])
|
||||
guestNetworkCidr = self.address['network']
|
||||
if self.config.has_public_network():
|
||||
self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" %
|
||||
(guestNetworkCidr, self.dev, self.dev)])
|
||||
self.fw.append(
|
||||
["filter", "front", "-A ACL_INBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev])
|
||||
self.fw.append(
|
||||
["filter", "front", "-A ACL_INBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev])
|
||||
self.fw.append(
|
||||
["filter", "", "-A ACL_INBOUND_%s -j DROP" % self.dev])
|
||||
self.fw.append(
|
||||
["mangle", "front", "-A ACL_OUTBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev])
|
||||
self.fw.append(
|
||||
["mangle", "front", "-A ACL_OUTBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev])
|
||||
else:
|
||||
self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACCEPT" % (guestNetworkCidr, self.dev)])
|
||||
|
||||
self.fw.append(
|
||||
["filter", "", "-A INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % self.dev])
|
||||
self.fw.append(
|
||||
|
|
@ -551,9 +562,11 @@ class CsIP:
|
|||
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 443 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)])
|
||||
self.fw.append(
|
||||
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 8080 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)])
|
||||
self.fw.append(["mangle", "",
|
||||
"-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" %
|
||||
(self.dev, guestNetworkCidr, self.address['gateway'], self.dev)])
|
||||
|
||||
if self.config.has_public_network():
|
||||
self.fw.append(["mangle", "",
|
||||
"-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" %
|
||||
(self.dev, guestNetworkCidr, self.address['gateway'], self.dev)])
|
||||
|
||||
if self.is_private_gateway():
|
||||
self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" %
|
||||
|
|
@ -686,6 +699,47 @@ class CsIP:
|
|||
self.nft_ipv4_acl.append({'type': "", 'chain': 'FORWARD',
|
||||
'rule': "iifname %s oifname %s ct state related,established counter accept" % (self.dev, self.dev)})
|
||||
|
||||
def fw_dhcpserver(self):
|
||||
if not self.config.is_dhcp():
|
||||
return
|
||||
|
||||
self.fw.append(["mangle", "front",
|
||||
"-A POSTROUTING " +
|
||||
"-p udp -m udp --dport 68 -j CHECKSUM --checksum-fill"])
|
||||
|
||||
self.fw.append(["filter", "", "-A INPUT -d 224.0.0.18/32 -j ACCEPT"])
|
||||
self.fw.append(["filter", "", "-A INPUT -d 225.0.0.50/32 -j ACCEPT"])
|
||||
self.fw.append(["filter", "", "-A INPUT -i %s -m state --state RELATED,ESTABLISHED -j ACCEPT" %
|
||||
self.dev])
|
||||
self.fw.append(["filter", "", "-A INPUT -p icmp -j ACCEPT"])
|
||||
self.fw.append(["filter", "", "-A INPUT -i lo -j ACCEPT"])
|
||||
|
||||
if self.config.is_vpc():
|
||||
self.fw.append(
|
||||
["filter", "", "-A INPUT -i eth0 -p tcp -m tcp --dport 3922 -m state --state NEW,ESTABLISHED -j ACCEPT"])
|
||||
else:
|
||||
self.fw.append(
|
||||
["filter", "", "-A INPUT -i eth1 -p tcp -m tcp --dport 3922 -m state --state NEW,ESTABLISHED -j ACCEPT"])
|
||||
|
||||
if self.get_type() in ["guest"]:
|
||||
guestNetworkCidr = self.address['network']
|
||||
self.fw.append(
|
||||
["filter", "", "-A INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % self.dev])
|
||||
self.fw.append(
|
||||
["filter", "", "-A INPUT -i %s -p udp -m udp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)])
|
||||
self.fw.append(
|
||||
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)])
|
||||
self.fw.append(
|
||||
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 80 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)])
|
||||
self.fw.append(
|
||||
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 443 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)])
|
||||
self.fw.append(
|
||||
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 8080 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)])
|
||||
self.fw.append(
|
||||
["filter", "", "-A FORWARD -i %s -o %s -m state --state RELATED,ESTABLISHED -j ACCEPT" % (self.dev, self.dev)])
|
||||
self.fw.append(
|
||||
["filter", "", "-A FORWARD -i %s -o %s -m state --state NEW -j ACCEPT" % (self.dev, self.dev)])
|
||||
|
||||
|
||||
def post_config_change(self, method):
|
||||
route = CsRoute()
|
||||
|
|
@ -735,6 +789,7 @@ class CsIP:
|
|||
self.fw_vpcrouter()
|
||||
self.fw_router_routing()
|
||||
self.fw_vpcrouter_routing()
|
||||
self.fw_dhcpserver()
|
||||
|
||||
cmdline = self.config.cmdline()
|
||||
|
||||
|
|
|
|||
|
|
@ -148,3 +148,6 @@ class CsConfig(object):
|
|||
return 'mangle'
|
||||
else:
|
||||
return ""
|
||||
|
||||
def has_public_network(self):
|
||||
return self.cmdline().idata().get('has_public_network', 'true') == 'true'
|
||||
|
|
|
|||
|
|
@ -142,9 +142,9 @@ class CsDhcp(CsDataBag):
|
|||
else:
|
||||
listen_address.append(ip)
|
||||
# Add localized "data-server" records in /etc/hosts for VPC routers
|
||||
if self.config.is_vpc() or self.config.is_router():
|
||||
if (self.config.is_vpc() and gn.is_vr_guest_gateway()) or self.config.is_router():
|
||||
self.add_host(gateway, "%s data-server" % CsHelper.get_hostname())
|
||||
elif self.config.is_dhcp():
|
||||
elif self.config.is_dhcp() or (self.config.is_vpc() and not gn.is_vr_guest_gateway()):
|
||||
self.add_host(ip, "%s data-server" % CsHelper.get_hostname())
|
||||
idx += 1
|
||||
|
||||
|
|
|
|||
|
|
@ -35,13 +35,19 @@ class CsGuestNetwork:
|
|||
def is_guestnetwork(self):
|
||||
return self.guest
|
||||
|
||||
def is_vr_guest_gateway(self):
|
||||
return self.guest and ('is_vr_guest_gateway' not in self.data or self.data['is_vr_guest_gateway'])
|
||||
|
||||
def get_dns(self):
|
||||
if not self.guest:
|
||||
return self.config.get_dns()
|
||||
|
||||
dns = []
|
||||
if 'router_guest_gateway' in self.data and not self.config.use_extdns() and ('is_vr_guest_gateway' not in self.data or not self.data['is_vr_guest_gateway']):
|
||||
dns.append(self.data['router_guest_gateway'])
|
||||
if not self.config.use_extdns():
|
||||
if 'router_guest_gateway' in self.data and self.is_vr_guest_gateway():
|
||||
dns.append(self.data['router_guest_gateway'])
|
||||
elif 'router_guest_ip' in self.data and not self.is_vr_guest_gateway():
|
||||
dns.append(self.data['router_guest_ip'])
|
||||
|
||||
if 'dns' in self.data:
|
||||
dns.extend(self.data['dns'].split(','))
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
import binascii
|
||||
import cgi
|
||||
import os
|
||||
import socketserver
|
||||
import sys
|
||||
import syslog
|
||||
import threading
|
||||
|
|
@ -97,9 +98,17 @@ def removePassword(ip):
|
|||
del passMap[ip]
|
||||
|
||||
|
||||
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
pass
|
||||
class CloudStackPasswordServer(socketserver.TCPServer):
|
||||
allow_reuse_address = 1
|
||||
def server_bind(self):
|
||||
"""Override server_bind to store the server name."""
|
||||
socketserver.TCPServer.server_bind(self)
|
||||
host, port = self.server_address[:2]
|
||||
self.server_name = host
|
||||
self.server_port = port
|
||||
|
||||
class ThreadedHTTPServer(ThreadingMixIn, CloudStackPasswordServer):
|
||||
pass
|
||||
|
||||
class PasswordRequestHandler(BaseHTTPRequestHandler):
|
||||
server_version = 'CloudStack Password Server'
|
||||
|
|
|
|||
|
|
@ -1547,6 +1547,7 @@
|
|||
"label.newinstance": "New Instance",
|
||||
"label.newname": "New name",
|
||||
"label.next": "Next",
|
||||
"label.nexthop": "Next hop",
|
||||
"label.nfs": "NFS",
|
||||
"label.nfsmountopts": "NFS mount options",
|
||||
"label.nfsserver": "NFS server",
|
||||
|
|
@ -2083,7 +2084,7 @@
|
|||
"label.simplified.chinese.keyboard": "Simplified Chinese keyboard",
|
||||
"label.site": "Netris Site",
|
||||
"label.site.to.site.vpn": "Site-to-site VPN",
|
||||
"label.site.to.site.vpn.connections": "Site-to-site VPN Connections",
|
||||
"label.site.to.site.vpn.connections": "VPN Connections",
|
||||
"label.size": "Size",
|
||||
"label.sizegb": "Size",
|
||||
"label.smb.domain": "SMB domain",
|
||||
|
|
@ -2546,6 +2547,7 @@
|
|||
"label.volumetype": "Volume Type",
|
||||
"label.vpc": "VPC",
|
||||
"label.vpcs": "VPCs",
|
||||
"label.vpc.gateway.ip": "VPC Gateway IP",
|
||||
"label.vpc.id": "VPC ID",
|
||||
"label.vpc.offerings": "VPC offerings",
|
||||
"label.vpc.virtual.router": "VPC virtual router",
|
||||
|
|
@ -3027,7 +3029,7 @@
|
|||
"message.enable.vpn": "Please confirm that you want remote access VPN enabled for this IP address.",
|
||||
"message.enable.vpn.failed": "Failed to enable VPN.",
|
||||
"message.enable.vpn.processing": "Enabling VPN...",
|
||||
"message.enabled.vpn": "Your remote access VPN is currently enabled and can be accessed via the IP.",
|
||||
"message.enabled.vpn": "Your remote access VPN is currently enabled and can be accessed via the IP",
|
||||
"message.enabled.vpn.ip.sec": "Your IPSec pre-shared key is",
|
||||
"message.enabling.security.group.provider": "Enabling security group provider",
|
||||
"message.enter.valid.nic.ip": "Please enter a valid IP address for NIC",
|
||||
|
|
|
|||
|
|
@ -443,7 +443,7 @@
|
|||
<div class="resource-detail-item__label">{{ $t('label.vmname') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<desktop-outlined />
|
||||
<router-link :to="{ path: createPathBasedOnVmType(resource.vmtype, resource.virtualmachineid) }">{{ resource.vmname || resource.vm || resource.virtualmachinename || resource.virtualmachineid }} </router-link>
|
||||
<router-link :to="{ path: createPathBasedOnVmType(resource.vmtype || resource.virtualmachinetype, resource.virtualmachineid) }">{{ resource.vmname || resource.vm || resource.virtualmachinename || resource.virtualmachineid }} </router-link>
|
||||
<status class="status status--end" :text="resource.vmstate" v-if="resource.vmstate"/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -794,7 +794,7 @@ export default {
|
|||
}, {
|
||||
name: 'vpn',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/VpnDetails.vue'))),
|
||||
show: (record) => { return record.issourcenat }
|
||||
show: (record) => { return record.issourcenat || record.virtualmachinetype === 'DomainRouter' || !record.hasrules }
|
||||
},
|
||||
{
|
||||
name: 'events',
|
||||
|
|
@ -1001,7 +1001,6 @@ export default {
|
|||
title: 'label.site.to.site.vpn.connections',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#setting-up-a-site-to-site-vpn-connection',
|
||||
icon: 'sync-outlined',
|
||||
hidden: true,
|
||||
permission: ['listVpnConnections'],
|
||||
columns: ['publicip', 'state', 'gateway', 'ipsecpsk', 'ikepolicy', 'esppolicy'],
|
||||
details: ['publicip', 'gateway', 'passive', 'cidrlist', 'ipsecpsk', 'ikepolicy', 'esppolicy', 'ikelifetime', 'ikeversion', 'esplifetime', 'dpd', 'splitconnections', 'forceencap', 'created'],
|
||||
|
|
|
|||
|
|
@ -134,21 +134,21 @@ export default {
|
|||
this.tabs = this.defaultTabs
|
||||
return
|
||||
}
|
||||
// VPC IPs with source nat have only VPN
|
||||
if (this.resource && this.resource.vpcid && this.resource.issourcenat) {
|
||||
this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
|
||||
return
|
||||
}
|
||||
// VPC IPs with vpnenabled have only VPN
|
||||
if (this.resource && this.resource.vpcid && this.resource.vpnenabled) {
|
||||
this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
|
||||
return
|
||||
}
|
||||
// VPC IPs with static nat have nothing
|
||||
if (this.resource && this.resource.vpcid && this.resource.isstaticnat) {
|
||||
return
|
||||
}
|
||||
if (this.resource && this.resource.vpcid) {
|
||||
// VPC IPs with source nat have only VPN
|
||||
if (this.resource.issourcenat) {
|
||||
this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
|
||||
return
|
||||
}
|
||||
|
||||
// VPC IPs with static nat have nothing
|
||||
if (this.resource.isstaticnat) {
|
||||
if (this.resource.virtualmachinetype === 'DomainRouter') {
|
||||
this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// VPC IPs don't have firewall
|
||||
let tabs = this.$route.meta.tabs.filter(tab => tab.name !== 'firewall')
|
||||
|
||||
|
|
@ -194,6 +194,9 @@ export default {
|
|||
this.actions = this.$route.meta.actions || []
|
||||
},
|
||||
fetchNetwork () {
|
||||
if (!this.resource.associatednetworkid) {
|
||||
return null
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
api('listNetworks', {
|
||||
listAll: true,
|
||||
|
|
|
|||
|
|
@ -17,29 +17,44 @@
|
|||
|
||||
<template>
|
||||
<a-spin :spinning="componentLoading">
|
||||
<div class="new-route" v-ctrl-enter="handleAdd">
|
||||
<a-input v-model:value="newRoute" :placeholder="$t('label.cidr.destination.network')" v-focus="true"></a-input>
|
||||
<div class="form" v-ctrl-enter="handleAdd">
|
||||
<div class="form__label">
|
||||
<a-input v-model:value="newRoute" :placeholder="$t('label.cidr.destination.network')" v-focus="true"></a-input>
|
||||
</div>
|
||||
<div class="form__label" v-if="this.$route.fullPath.startsWith('/vpc')">
|
||||
<div :span="24" class="form__label">via</div>
|
||||
</div>
|
||||
<div class="form__label" v-if="this.$route.fullPath.startsWith('/vpc')">
|
||||
<a-input v-model:value="nexthop" :placeholder="$t('label.nexthop')"></a-input>
|
||||
</div>
|
||||
<a-button type="primary" :disabled="!('createStaticRoute' in $store.getters.apis)" @click="handleAdd">{{ $t('label.add.route') }}</a-button>
|
||||
</div>
|
||||
|
||||
<div class="list">
|
||||
<div v-for="(route, index) in routes" :key="index" class="list__item">
|
||||
<div class="list__col">
|
||||
<div class="list__label">{{ $t('label.cidr.destination.network') }}</div>
|
||||
<div>{{ route.cidr }}</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<tooltip-button :tooltip="$t('label.edit.tags')" icon="tag-outlined" @onClick="() => openTagsModal(route)" />
|
||||
<a-divider/>
|
||||
<a-table
|
||||
size="small"
|
||||
style="overflow-y: auto"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:dataSource="routes"
|
||||
:pagination="false"
|
||||
:rowKey="record => record.id">
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<template v-if="column.key === 'vpcgatewayip'">
|
||||
<router-link :to="{ path: '/privategw/' + record.vpcgatewayid }" >{{ text }}</router-link>
|
||||
</template>
|
||||
<template v-if="column.key === 'actions'">
|
||||
<tooltip-button :tooltip="$t('label.edit.tags')" icon="tag-outlined" @onClick="() => openTagsModal(record)" />
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.delete')"
|
||||
:disabled="!('deleteStaticRoute' in $store.getters.apis)"
|
||||
icon="delete-outlined"
|
||||
type="primary"
|
||||
:danger="true"
|
||||
@onClick="() => handleDelete(route)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@onClick="() => handleDelete(record)" />
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<a-modal
|
||||
:title="$t('label.edit.tags')"
|
||||
|
|
@ -90,10 +105,12 @@
|
|||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel.vue'
|
||||
|
||||
export default {
|
||||
name: 'StaticRoutesTab',
|
||||
components: {
|
||||
TooltipLabel,
|
||||
TooltipButton
|
||||
},
|
||||
props: {
|
||||
|
|
@ -114,7 +131,27 @@ export default {
|
|||
tagsModalVisible: false,
|
||||
tags: [],
|
||||
tagsLoading: false,
|
||||
newRoute: null
|
||||
newRoute: null,
|
||||
nexthop: null,
|
||||
columns: [
|
||||
{
|
||||
title: this.$t('label.cidr.destination.network'),
|
||||
dataIndex: 'cidr'
|
||||
},
|
||||
{
|
||||
title: this.$t('label.vpc.gateway.ip'),
|
||||
key: 'vpcgatewayip',
|
||||
dataIndex: 'vpcgatewayip'
|
||||
},
|
||||
{
|
||||
title: this.$t('label.nexthop'),
|
||||
dataIndex: 'nexthop'
|
||||
},
|
||||
{
|
||||
title: this.$t('label.actions'),
|
||||
key: 'actions'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
|
@ -141,10 +178,15 @@ export default {
|
|||
},
|
||||
fetchData () {
|
||||
this.componentLoading = true
|
||||
api('listStaticRoutes', {
|
||||
gatewayid: this.resource.id,
|
||||
listall: true
|
||||
}).then(json => {
|
||||
var params = {
|
||||
listAll: true
|
||||
}
|
||||
if (this.$route.fullPath.startsWith('/vpc')) {
|
||||
params.vpcid = this.resource.id
|
||||
} else {
|
||||
params.gatewayid = this.resource.id
|
||||
}
|
||||
api('listStaticRoutes', params).then(json => {
|
||||
this.routes = json.liststaticroutesresponse.staticroute
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
|
|
@ -157,10 +199,18 @@ export default {
|
|||
if (!this.newRoute) return
|
||||
|
||||
this.componentLoading = true
|
||||
api('createStaticRoute', {
|
||||
cidr: this.newRoute,
|
||||
gatewayid: this.resource.id
|
||||
}).then(response => {
|
||||
var params = {
|
||||
cidr: this.newRoute
|
||||
}
|
||||
if (this.$route.fullPath.startsWith('/vpc')) {
|
||||
params.vpcid = this.resource.id
|
||||
if (this.nexthop) {
|
||||
params.nexthop = this.nexthop
|
||||
}
|
||||
} else {
|
||||
params.gatewayid = this.resource.id
|
||||
}
|
||||
api('createStaticRoute', params).then(response => {
|
||||
this.$pollJob({
|
||||
jobId: response.createstaticrouteresponse.jobid,
|
||||
title: this.$t('message.success.add.static.route'),
|
||||
|
|
@ -304,7 +354,6 @@ export default {
|
|||
},
|
||||
openTagsModal (route) {
|
||||
this.selectedRule = route
|
||||
this.rulesRef.value.resetFields()
|
||||
this.fetchTags(this.selectedRule)
|
||||
this.tagsModalVisible = true
|
||||
}
|
||||
|
|
@ -368,20 +417,38 @@ export default {
|
|||
margin-left: auto;
|
||||
}
|
||||
|
||||
.new-route {
|
||||
.form {
|
||||
display: flex;
|
||||
padding-top: 10px;
|
||||
margin-right: -20px;
|
||||
margin-bottom: 20px;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
input {
|
||||
margin-right: 10px;
|
||||
@media (min-width: 760px) {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
button {
|
||||
&:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
&__item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
padding-right: 20px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
@media (min-width: 760px) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
.ant-select {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -360,6 +360,9 @@
|
|||
</a-spin>
|
||||
</a-modal>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane :tab="$t('label.static.routes')" key="staticroutes">
|
||||
<StaticRoutesTab :resource="resource" :loading="loading" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane :tab="$t('label.virtual.routers')" key="vr" v-if="$store.getters.userInfo.roletype === 'Admin'">
|
||||
<RoutersTab :resource="resource" :loading="loading" />
|
||||
</a-tab-pane>
|
||||
|
|
@ -393,6 +396,7 @@ import EventsTab from '@/components/view/EventsTab'
|
|||
import AnnotationsTab from '@/components/view/AnnotationsTab'
|
||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||
import BgpPeersTab from '@/views/infra/zone/BgpPeersTab.vue'
|
||||
import StaticRoutesTab from './StaticRoutesTab'
|
||||
|
||||
export default {
|
||||
name: 'VpcTab',
|
||||
|
|
@ -404,6 +408,7 @@ export default {
|
|||
RoutersTab,
|
||||
VpcTiersTab,
|
||||
VnfAppliancesTab,
|
||||
StaticRoutesTab,
|
||||
EventsTab,
|
||||
AnnotationsTab,
|
||||
ResourceIcon
|
||||
|
|
|
|||
|
|
@ -637,7 +637,7 @@ export default {
|
|||
}
|
||||
}
|
||||
this.networkOfferings = filteredOfferings
|
||||
if (this.isNsxEnabled || ['netris', 'nsx'].includes(this.zoneExtNetProvider.toLowerCase())) {
|
||||
if (this.isNsxEnabled || (this.zoneExtNetProvider && ['netris', 'nsx'].includes(this.zoneExtNetProvider.toLowerCase()))) {
|
||||
this.networkOfferings = this.networkOfferings.filter(offering => offering.networkmode === (this.isOfferingNatMode ? 'NATTED' : 'ROUTED'))
|
||||
}
|
||||
if (this.resource.asnumberid) {
|
||||
|
|
|
|||
|
|
@ -464,7 +464,7 @@
|
|||
<a-form-item
|
||||
name="conservemode"
|
||||
ref="conservemode"
|
||||
v-if="(guestType === 'shared' || guestType === 'isolated') && !isVpcVirtualRouterForAtLeastOneService &&
|
||||
v-if="(guestType === 'shared' || guestType === 'isolated') &&
|
||||
(form.provider !== 'NSX' && form.provider !== 'Netris') && networkmode !== 'ROUTED'">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.conservemode')" :tooltip="apiParams.conservemode.description"/>
|
||||
|
|
|
|||
|
|
@ -1825,6 +1825,22 @@ public class NetUtils {
|
|||
return MAX_CIDR;
|
||||
}
|
||||
|
||||
/**
|
||||
Return the size of smallest CIDR which contains the IP range (startIp-endIp).
|
||||
*/
|
||||
public static int getBigCidrSizeOfIpRange(long startIp, long endIp) {
|
||||
assert startIp <= MAX_IPv4_ADDR : "Keep startIp smaller than or equals to " + MAX_IPv4_ADDR;
|
||||
assert endIp <= MAX_IPv4_ADDR : "Keep endIp smaller than or equals to " + MAX_IPv4_ADDR;
|
||||
for (int cidrSize = MAX_CIDR; cidrSize >= 1; cidrSize--) {
|
||||
long minStartIp = startIp & (((long) 0xffffffff) >> (MAX_CIDR - cidrSize) << (MAX_CIDR - cidrSize));
|
||||
long maxEndIp = (minStartIp | (((long) 0x1) << (MAX_CIDR - cidrSize)) - 1);
|
||||
if (minStartIp <= startIp && maxEndIp >= endIp) {
|
||||
return cidrSize;
|
||||
}
|
||||
}
|
||||
return MAX_CIDR;
|
||||
}
|
||||
|
||||
/**
|
||||
Return the list of pairs (Network Address, Network cidrsize)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -932,4 +932,15 @@ public class NetUtilsTest {
|
|||
Assert.assertEquals("192.168.0.0/24", NetUtils.transformCidr("192.168.0.100/24"));
|
||||
Assert.assertEquals("10.10.10.10/32", NetUtils.transformCidr("10.10.10.10/32"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVpnIpRange() {
|
||||
String ipRange = "10.1.2.1-10.1.2.8";
|
||||
String startIp = ipRange.split("-")[0];
|
||||
String endIp = ipRange.split("-")[1];
|
||||
int cidrSize = NetUtils.getBigCidrSizeOfIpRange(NetUtils.ip2Long(startIp), NetUtils.ip2Long(endIp));
|
||||
Assert.assertEquals(28, cidrSize);
|
||||
String cidr = NetUtils.transformCidr(startIp + "/" + cidrSize);
|
||||
Assert.assertEquals("10.1.2.0/28", cidr);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue