You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by pr...@apache.org on 2013/04/05 23:03:12 UTC
[17/50] [abbrv] git commit: updated refs/heads/affinity_groups to
ca1a794
MidoNet Networking Plugin
- Supports DHCP, Source NAT, Static NAT, Firewall rules, Port Forwarding
- Renamed MidokuraMidonet to MidoNet
- Related Jira ticket is CLOUDSTACK-996
Signed-off-by: Dave Cahill <dc...@midokura.com>
Signed-off-by: Hugo Trippaers <ht...@schubergphilis.com>
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/eddf7b93
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/eddf7b93
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/eddf7b93
Branch: refs/heads/affinity_groups
Commit: eddf7b9357bc18497b8cb16a6c6f3382ac52f61c
Parents: d392445
Author: Dave Cahill <dc...@midokura.com>
Authored: Mon Mar 25 10:56:13 2013 +0900
Committer: Hugo Trippaers <ht...@schubergphilis.com>
Committed: Wed Apr 3 12:03:11 2013 +0200
----------------------------------------------------------------------
api/src/com/cloud/network/Network.java | 3 +-
api/src/com/cloud/network/Networks.java | 1 +
api/src/com/cloud/network/PhysicalNetwork.java | 3 +-
.../network/ExternalNetworkDeviceManager.java | 1 -
client/pom.xml | 5 +
.../kvm/resource/LibvirtDomainXMLParser.java | 3 +
.../hypervisor/kvm/resource/LibvirtVMDef.java | 11 +-
plugins/network-elements/midokura-midonet/pom.xml | 30 -
plugins/network-elements/midonet/pom.xml | 66 +
.../com/cloud/network/element/MidoNetElement.java | 1622 ++++++++++++++-
.../cloud/network/element/SimpleFirewallRule.java | 192 ++
.../network/guru/MidoNetGuestNetworkGuru.java | 144 ++-
.../network/guru/MidoNetPublicNetworkGuru.java | 223 ++
.../cloud/network/resource/MidoNetVifDriver.java | 179 ++
.../cloud/network/element/MidoNetElementTest.java | 178 ++
plugins/pom.xml | 1 +
server/src/com/cloud/configuration/Config.java | 4 +
.../src/com/cloud/network/NetworkManagerImpl.java | 20 +
ui/scripts/system.js | 114 +
19 files changed, 2720 insertions(+), 80 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/api/src/com/cloud/network/Network.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java
index c2ab655..c0b0117 100644
--- a/api/src/com/cloud/network/Network.java
+++ b/api/src/com/cloud/network/Network.java
@@ -136,8 +136,7 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I
public static final Provider VPCVirtualRouter = new Provider("VpcVirtualRouter", false);
public static final Provider None = new Provider("None", false);
// NiciraNvp is not an "External" provider, otherwise we get in trouble with NetworkServiceImpl.providersConfiguredForExternalNetworking
- public static final Provider NiciraNvp = new Provider("NiciraNvp", false);
- public static final Provider MidokuraMidonet = new Provider("MidokuraMidonet", true);
+ public static final Provider NiciraNvp = new Provider("NiciraNvp", false);
private String name;
private boolean isExternal;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/api/src/com/cloud/network/Networks.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java
index e3d2158..f085e9f 100755
--- a/api/src/com/cloud/network/Networks.java
+++ b/api/src/com/cloud/network/Networks.java
@@ -62,6 +62,7 @@ public class Networks {
Vnet("vnet", Long.class),
Storage("storage", Integer.class),
Lswitch("lswitch", String.class),
+ Mido("mido", String.class),
UnDecided(null, null);
private String scheme;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/api/src/com/cloud/network/PhysicalNetwork.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/network/PhysicalNetwork.java b/api/src/com/cloud/network/PhysicalNetwork.java
index 343a2b1..a2044a6 100644
--- a/api/src/com/cloud/network/PhysicalNetwork.java
+++ b/api/src/com/cloud/network/PhysicalNetwork.java
@@ -36,7 +36,8 @@ public interface PhysicalNetwork extends Identity, InternalIdentity {
L3,
GRE,
STT,
- VNS;
+ VNS,
+ MIDO;
}
public enum BroadcastDomainRange {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java b/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java
index bc22804..aeed81d 100644
--- a/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java
+++ b/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java
@@ -43,7 +43,6 @@ public interface ExternalNetworkDeviceManager extends Manager {
public static final NetworkDevice F5BigIpLoadBalancer = new NetworkDevice("F5BigIpLoadBalancer", Network.Provider.F5BigIp.getName());
public static final NetworkDevice JuniperSRXFirewall = new NetworkDevice("JuniperSRXFirewall", Network.Provider.JuniperSRX.getName());
public static final NetworkDevice NiciraNvp = new NetworkDevice("NiciraNvp", Network.Provider.NiciraNvp.getName());
- public static final NetworkDevice MidokuraMidonet = new NetworkDevice("MidokuraMidonet", Network.Provider.MidokuraMidonet.getName());
public NetworkDevice(String deviceName, String ntwkServiceprovider) {
_name = deviceName;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/client/pom.xml
----------------------------------------------------------------------
diff --git a/client/pom.xml b/client/pom.xml
index 05934f4..ff861b7 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -82,6 +82,11 @@
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-plugin-network-midonet</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-hypervisor-xen</artifactId>
<version>${project.version}</version>
</dependency>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
index 403ed37..ac4baf1 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
@@ -111,6 +111,9 @@ public class LibvirtDomainXMLParser {
String bridge = getAttrValue("source", "bridge", nic);
def.defBridgeNet(bridge, dev, mac,
nicModel.valueOf(model.toUpperCase()));
+ } else if (type.equalsIgnoreCase("ethernet")) {
+ String scriptPath = getAttrValue("script", "path", nic);
+ def.defEthernet(dev, mac, nicModel.valueOf(model.toUpperCase()), scriptPath);
}
interfaces.add(def);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
index 63133a8..9cddb2e 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
@@ -711,13 +711,19 @@ public class LibvirtVMDef {
_model = model;
}
- public void defEthernet(String targetName, String macAddr, nicModel model) {
+ public void defEthernet(String targetName, String macAddr, nicModel model, String scriptPath) {
_netType = guestNetType.ETHERNET;
_networkName = targetName;
+ _sourceName = targetName;
_macAddr = macAddr;
_model = model;
+ _scriptPath = scriptPath;
}
+ public void defEthernet(String targetName, String macAddr, nicModel model) {
+ defEthernet(targetName, macAddr, model, null);
+ }
+
public void setHostNetType(hostNicType hostNetType) {
_hostNetType = hostNetType;
}
@@ -790,6 +796,9 @@ public class LibvirtVMDef {
if (_model != null) {
netBuilder.append("<model type='" + _model + "'/>\n");
}
+ if (_scriptPath != null) {
+ netBuilder.append("<script path='" + _scriptPath + "'/>\n");
+ }
if (_virtualPortType != null) {
netBuilder.append("<virtualport type='" + _virtualPortType + "'>\n");
if (_virtualPortInterfaceId != null) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/plugins/network-elements/midokura-midonet/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/network-elements/midokura-midonet/pom.xml b/plugins/network-elements/midokura-midonet/pom.xml
deleted file mode 100644
index 7f2e2d3..0000000
--- a/plugins/network-elements/midokura-midonet/pom.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <artifactId>cloud-plugin-network-midonet</artifactId>
- <name>Apache CloudStack Plugin - Midokura Midonet</name>
- <parent>
- <groupId>org.apache.cloudstack</groupId>
- <artifactId>cloudstack-plugins</artifactId>
- <version>4.0.0-SNAPSHOT</version>
- <relativePath>../../pom.xml</relativePath>
- </parent>
-</project>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/plugins/network-elements/midonet/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/network-elements/midonet/pom.xml b/plugins/network-elements/midonet/pom.xml
new file mode 100644
index 0000000..bfd59a9
--- /dev/null
+++ b/plugins/network-elements/midonet/pom.xml
@@ -0,0 +1,66 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>cloud-plugin-network-midonet</artifactId>
+ <name>Apache CloudStack Plugin - Midokura Midonet</name>
+ <parent>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloudstack-plugins</artifactId>
+ <version>4.2.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+<repositories>
+ <repository>
+ <id>mido-maven-public-releases</id>
+ <name>mido-maven-public-releases</name>
+ <url>https://googledrive.com/host/0B7iVfAZ_5GmJTk9PUDFNLTl5MVk/releases</url>
+ </repository>
+</repositories>
+ <dependencies>
+ <dependency>
+ <groupId>com.midokura</groupId>
+ <artifactId>midonet-client</artifactId>
+ <version>12.12.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-plugin-hypervisor-kvm</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ <version>1.9.3</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ <version>1.9.3</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java b/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java
index 48833b3..804e4a6 100644
--- a/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java
+++ b/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java
@@ -19,113 +19,1667 @@
package com.cloud.network.element;
+import com.cloud.network.*;
+import com.cloud.network.element.SimpleFirewallRule;
+import com.cloud.agent.api.to.FirewallRuleTO;
+import com.cloud.agent.api.to.NetworkACLTO;
+import com.cloud.agent.api.to.PortForwardingRuleTO;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.network.dao.NetworkServiceMapDao;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.network.Network;
import com.cloud.network.Network.Capability;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
-import com.cloud.network.PhysicalNetworkServiceProvider;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.StaticNat;
+import com.cloud.network.rules.PortForwardingRule;
+import com.cloud.network.addr.PublicIp;
import com.cloud.offering.NetworkOffering;
+import com.cloud.utils.Pair;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.component.PluggableService;
-import com.cloud.vm.NicProfile;
-import com.cloud.vm.ReservationContext;
-import com.cloud.vm.VirtualMachine;
-import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.*;
+import com.cloud.vm.dao.NicDao;
+import com.google.common.collect.*;
+import com.cloud.user.AccountManager;
+import com.midokura.midonet.client.MidonetApi;
+import com.midokura.midonet.client.dto.DtoRule;
+import com.midokura.midonet.client.resource.*;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
import org.apache.log4j.Logger;
+import com.cloud.network.vpc.PrivateGateway;
+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 org.springframework.stereotype.Component;
import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.inject.Inject;
+import java.util.*;
import java.lang.Class;
import java.util.Map;
import java.util.Set;
@Component
-@Local(value = NetworkElement.class)
-public class MidokuraMidonetElement extends AdapterBase implements ConnectivityProvider, PluggableService {
- private static final Logger s_logger = Logger.getLogger(MidokuraMidonetElement.class);
+@Local(value = {NetworkElement.class,
+ ConnectivityProvider.class,
+ FirewallServiceProvider.class,
+ SourceNatServiceProvider.class,
+ DhcpServiceProvider.class,
+ StaticNatServiceProvider.class,
+ PortForwardingServiceProvider.class,
+ IpDeployer.class} )
+public class MidoNetElement extends AdapterBase implements
+ ConnectivityProvider,
+ DhcpServiceProvider,
+ SourceNatServiceProvider,
+ StaticNatServiceProvider,
+ IpDeployer,
+ PortForwardingServiceProvider,
+ FirewallServiceProvider,
+ PluggableService {
+
+ private static final Logger s_logger = Logger.getLogger(MidoNetElement.class);
+
+ private static final Map<Service, Map<Capability, String>> capabilities = setCapabilities();
+
+ protected UUID _providerRouterId = null;
+
+ protected MidonetApi api;
+
+ private static final Provider MidoNet = new Provider("MidoNet", false);
+
+ public enum RuleChainCode {
+ TR_PRE,
+ TR_PRENAT,
+ TR_PREFILTER,
+ TR_POST,
+ ACL_INGRESS,
+ ACL_EGRESS
+ }
+
+ @Inject
+ ConfigurationDao _configDao;
+ @Inject
+ protected NicDao _nicDao;
+ @Inject
+ NetworkModel _networkModel;
+ @Inject
+ VpcManager _vpcMgr;
+ @Inject
+ AccountManager _accountMgr;
+ @Inject
+ NetworkServiceMapDao _ntwkSrvcDao;
+
+ public void setMidonetApi(MidonetApi api) {
+ this.api = api;
+ }
+
+ public void setNtwkSrvcDao(NetworkServiceMapDao ntwkSrvcDao){
+ this._ntwkSrvcDao = ntwkSrvcDao;
+ }
@Override
public Map<Service, Map<Capability, String>> getCapabilities() {
- // TODO: implement this.
- return null;
+ return capabilities;
+ }
+
+ @Override
+ public boolean configure(String name, Map<String, Object> params)
+ throws ConfigurationException {
+ super.configure(name, params);
+
+ String routerIdValue = (String) _configDao.getValue(Config.MidoNetProviderRouterId.key());
+ if(routerIdValue != null)
+ _providerRouterId = UUID.fromString(routerIdValue);
+
+ String value = (String) _configDao.getValue(Config.MidoNetAPIServerAddress.key());
+
+ if (value == null) {
+ throw new ConfigurationException(
+ "Could not find midonet API location in config");
+ }
+
+ if (this.api == null) {
+ s_logger.info("midonet API server address is " + value);
+ setMidonetApi(new MidonetApi(value));
+ this.api.enableLogging();
+ }
+
+ return true;
+ }
+
+ public boolean midoInNetwork(Network network) {
+ for (String pname : _ntwkSrvcDao.getDistinctProviders(network.getId())) {
+ if (pname.equals(getProvider().getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected boolean canHandle(Network network, Service service) {
+ Long physicalNetworkId = _networkModel.getPhysicalNetworkId(network);
+ if (physicalNetworkId == null) {
+ return false;
+ }
+
+ if (!_networkModel.isProviderEnabledInPhysicalNetwork(physicalNetworkId, getProvider().getName())) {
+ return false;
+ }
+
+ if (service == null) {
+ if (!_networkModel.isProviderForNetwork(getProvider(), network.getId())) {
+ s_logger.trace("Element " + getProvider().getName() + " is not a provider for the network " + network);
+ return false;
+ }
+ } else {
+ if (!_networkModel.isProviderSupportServiceInNetwork(network.getId(), service, getProvider())) {
+ s_logger.trace("Element " + getProvider().getName() + " doesn't support service " + service.getName()
+ + " in the network " + network);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void applySourceNat(Router tenantRouter, Router providerRouter,
+ RouterPort tenantUplink, RouterPort providerDownlink,
+ RuleChain pre, RuleChain post, PublicIpAddress addr) {
+
+ boolean needAdd = true;
+ String SNtag = "/SourceNat";
+ String SNkey = "CS_nat";
+
+ String snatIp = addr.getAddress().addr();
+
+ String CsDesc = snatIp + SNtag;
+
+ //determine, by use of the properties, if we already
+ //added this rule. If we did, then we can skip it
+ //by setting needAdd = false
+ for (Rule rule : pre.getRules()) {
+ Map<String, String> props = rule.getProperties();
+ if (props == null) {
+ continue;
+ }
+ String snatTag = props.get(SNkey);
+ if (snatTag == null) {
+ continue;
+ }
+
+ if (!snatTag.equals(CsDesc)) {
+ continue;
+ } else {
+ needAdd = false;
+ break;
+ }
+ }
+
+ if (needAdd == false) {
+ //we found that this rule exists already,
+ // so lets skip adding it
+ return;
+ }
+
+ Map<String, String> ruleProps = new HashMap<String, String>();
+ ruleProps.put(SNkey, CsDesc);
+
+ DtoRule.DtoNatTarget[] targets = new DtoRule.DtoNatTarget[]{
+ new DtoRule.DtoNatTarget(snatIp,
+ snatIp, 1, 65535)};
+
+ // Set inbound (reverse SNAT) rule
+ pre.addRule().type(DtoRule.RevSNAT).flowAction(DtoRule.Accept)
+ .nwDstAddress(snatIp).nwDstLength(32)
+ .inPorts(new UUID[] {tenantUplink.getId()}).position(1)
+ .properties(ruleProps).create();
+
+ // Set outbound (SNAT) rule
+ post.addRule().type(DtoRule.SNAT).flowAction(DtoRule.Accept)
+ .outPorts(new UUID[]{tenantUplink.getId()})
+ .natTargets(targets).position(1)
+ .properties(ruleProps).create();
+
+ // Set up default route from tenant router to provider router
+ tenantRouter.addRoute().type("Normal").weight(100)
+ .srcNetworkAddr("0.0.0.0").srcNetworkLength(0)
+ .dstNetworkAddr("0.0.0.0").dstNetworkLength(0)
+ .nextHopPort(tenantUplink.getId()).create();
+
+ // Set routes for traffic to the SNAT IP to come back from provider router
+ providerRouter.addRoute().type("Normal").weight(100)
+ .srcNetworkAddr("0.0.0.0").srcNetworkLength(0)
+ .dstNetworkAddr(snatIp).dstNetworkLength(32)
+ .nextHopPort(providerDownlink.getId()).create();
+
+ // Default rule to accept traffic that has been DNATed
+ post.addRule().type(DtoRule.RevDNAT).flowAction(DtoRule.Accept).create();
+ }
+
+ public boolean associatePublicIP(Network network, final List<? extends PublicIpAddress> ipAddress)
+ throws ResourceUnavailableException {
+
+ s_logger.debug("associatePublicIP called with network: " + network.toString());
+ /*
+ * Get Mido Router for this network and set source rules
+ * These should only be allocated inside the for loop, because
+ * this function could be called as a part of network cleanup. In
+ * that case, we do not want to recreate the guest network or
+ * any ports.
+ */
+ boolean resources = false;
+ Router tenantRouter = null;
+ Router providerRouter = null;
+ RouterPort[] ports = null;
+
+ RouterPort tenantUplink = null;
+ RouterPort providerDownlink = null;
+
+ RuleChain preNat = null;
+ RuleChain post = null;
+ String accountIdStr = null;
+ String routerName = null;
+
+ // Set Source NAT rules on router
+ for (PublicIpAddress ip : ipAddress) {
+ // ip is the external one we sourcenat to
+ if(ip.isSourceNat()){
+ if (resources == false) {
+ tenantRouter = getOrCreateGuestNetworkRouter(network);
+ providerRouter = api.getRouter(_providerRouterId);
+ ports = getOrCreateProviderRouterPorts(tenantRouter, providerRouter);
+
+ tenantUplink = ports[0];
+ providerDownlink = ports[1];
+
+ accountIdStr = String.valueOf(network.getAccountId());
+ boolean isVpc = getIsVpc(network);
+ long id = getRouterId(network, isVpc);
+ routerName = getRouterName(isVpc, id);
+
+ preNat = getChain(accountIdStr, routerName, RuleChainCode.TR_PRENAT);
+ post = api.getChain(tenantRouter.getOutboundFilterId());
+ resources = true;
+ }
+
+ applySourceNat(tenantRouter, providerRouter, // Routers
+ tenantUplink, providerDownlink, // Ports
+ preNat, post, // Chains
+ ip); // The IP
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * From interface IpDeployer
+ *
+ * @param network
+ * @param ipAddress
+ * @param services
+ * @return
+ * @throws ResourceUnavailableException
+ */
+ @Override
+ public boolean applyIps(Network network,
+ List<? extends PublicIpAddress> ipAddress, Set<Service> services)
+ throws ResourceUnavailableException {
+
+ s_logger.debug("applyIps called with network: " + network.toString());
+ if (!this.midoInNetwork(network)) {
+ return false;
+ }
+
+ boolean canHandle = true;
+ for (Service service : services) {
+ if (!canHandle(network, service)) {
+ canHandle = false;
+ break;
+ }
+ }
+ if(canHandle) {
+ return associatePublicIP(network, ipAddress);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * From interface SourceNatServiceProvider
+ */
+ @Override
+ public IpDeployer getIpDeployer(Network network) {
+ s_logger.debug("getIpDeployer called with network " + network.toString());
+ return this;
+ }
+
+ /**
+ * From interface DHCPServiceProvider
+ */
+ @Override
+ public boolean addDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm,
+ DeployDestination dest, ReservationContext context)
+ throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
+
+ s_logger.debug("addDhcpEntry called with network: " + network.toString() + " nic: " + nic.toString() + " vm: " + vm.toString());
+ if (!this.midoInNetwork(network)) {
+ return false;
+ }
+ if (vm.getType() != VirtualMachine.Type.User) {
+ return false;
+ }
+
+ // Get MidoNet bridge
+ Bridge netBridge = getOrCreateNetworkBridge(network);
+
+ // On bridge, get DHCP subnet (ensure it exists)
+ ResourceCollection res = netBridge.getDhcpSubnets();
+
+ DhcpSubnet sub = null;
+
+ if(!res.isEmpty()){
+ sub = (DhcpSubnet) res.get(0);
+ } else {
+ Pair<String,Integer> cidrInfo = NetUtils.getCidr(network.getCidr());
+ sub = netBridge.addDhcpSubnet();
+
+ sub.subnetLength(cidrInfo.second());
+ sub.subnetPrefix(cidrInfo.first());
+ sub.defaultGateway(network.getGateway());
+ sub.dnsServerAddr(dest.getDataCenter().getDns1());
+
+ sub.create();
+ }
+
+ // On DHCP subnet, add host using host details
+ if(sub == null){
+ s_logger.error("Failed to create DHCP subnet on Midonet bridge");
+ return false;
+ } else {
+ // Check if the host already exists - we may just be restarting an existing VM
+ boolean isNewDhcpHost = true;
+
+ for (DhcpHost dhcpHost : sub.getDhcpHosts()) {
+ if(dhcpHost.getIpAddr().equals(nic.getIp4Address())){
+ isNewDhcpHost = false;
+ break;
+ }
+ }
+
+ if(isNewDhcpHost){
+ DhcpHost host = sub.addDhcpHost();
+ host.ipAddr(nic.getIp4Address());
+ host.macAddr(nic.getMacAddress());
+ // This only sets the cloudstack internal name
+ host.name(vm.getHostName());
+
+ host.create();
+ }
+ }
+
+ return true;
+ }
+
+ private void removeMidonetStaticNAT(RuleChain preFilter, RuleChain preNat, RuleChain postNat,
+ String floatingIp, String fixedIp,
+ Router providerRouter) {
+
+ // Delete filter (firewall) rules for this IP
+ for (Rule rule : preFilter.getRules()) {
+ String destAddr = rule.getNwDstAddress();
+ if (destAddr != null && destAddr.equals(floatingIp)) {
+ rule.delete();
+ }
+ }
+
+ // Delete DNAT rules for this IP
+ for (Rule rule : preNat.getRules()) {
+ String destAddr = rule.getNwDstAddress();
+ if (destAddr != null && destAddr.equals(floatingIp)) {
+ rule.delete();
+ }
+ }
+ // Delete SNAT rules for this IP
+ for (Rule rule : postNat.getRules()) {
+ String srcAddr = rule.getNwSrcAddress();
+ if (srcAddr != null && srcAddr.equals(fixedIp)) {
+ rule.delete();
+ }
+ }
+
+ //we also created a route to go with this rule. That needs to be
+ //deleted as well.
+ for (Route route : providerRouter.getRoutes(new MultivaluedMapImpl())) {
+ String routeDstAddr = route.getDstNetworkAddr();
+ if (routeDstAddr != null && routeDstAddr.equals(floatingIp)) {
+ route.delete();
+ }
+ }
+ }
+
+ private void addMidonetStaticNAT(RuleChain preFilter, RuleChain preNat, RuleChain postNat,
+ String floatingIp, String fixedIp,
+ RouterPort tenantUplink,
+ RouterPort providerDownlink,
+ Router providerRouter,
+ Network network) {
+
+ DtoRule.DtoNatTarget[] preTargets = new DtoRule.DtoNatTarget[]{
+ new DtoRule.DtoNatTarget(fixedIp, fixedIp, 0, 0)};
+
+ // Set inbound filter rule (allow return traffic to this IP)
+ // Implemented as "jump to NAT chain" instead of ACCEPT;
+ // this is to enforce that filter / firewall rules are evaluated
+ // before NAT rules.
+ preFilter.addRule().type(DtoRule.Jump)
+ .jumpChainId(preNat.getId())
+ .nwDstAddress(floatingIp)
+ .nwDstLength(32)
+ .matchReturnFlow(true)
+ .position(1)
+ .create();
+
+ // Allow ICMP replies (ICMP type 0, code 0 is ICMP reply)
+ preFilter.addRule().type(DtoRule.Jump)
+ .jumpChainId(preNat.getId())
+ .nwDstAddress(floatingIp)
+ .nwDstLength(32)
+ .nwProto(SimpleFirewallRule.stringToProtocolNumber("icmp"))
+ .tpSrcStart(0)
+ .tpSrcEnd(0)
+ .tpDstStart(0)
+ .tpDstEnd(0)
+ .position(2)
+ .create();
+
+ // We only want to set the default DROP rule for static NAT if
+ // Firewall is handled by the Midonet plugin.
+ // Set inbound filter rule (drop all traffic to this IP)
+ if (canHandle(network, Service.Firewall)) {
+ preFilter.addRule().type(DtoRule.Drop)
+ .nwDstAddress(floatingIp)
+ .nwDstLength(32)
+ .position(3)
+ .create();
+ }
+
+ // Set inbound (DNAT) rule
+ preNat.addRule().type(DtoRule.DNAT)
+ .flowAction(DtoRule.Accept)
+ .nwDstAddress(floatingIp)
+ .nwDstLength(32)
+ .inPorts(new UUID[] {tenantUplink.getId()})
+ .natTargets(preTargets)
+ .position(1)
+ .create();
+
+ DtoRule.DtoNatTarget[] postTargets = new DtoRule.DtoNatTarget[]{
+ new DtoRule.DtoNatTarget(floatingIp, floatingIp, 0, 0)};
+
+ // Set outbound (SNAT) rule
+ // Match forward flow so that return traffic will be recognized
+ postNat.addRule().type(DtoRule.SNAT)
+ .flowAction(DtoRule.Accept)
+ .matchForwardFlow(true)
+ .nwSrcAddress(fixedIp)
+ .nwSrcLength(32)
+ .outPorts(new UUID[]{tenantUplink.getId()})
+ .natTargets(postTargets)
+ .position(1)
+ .create();
+
+ // Set outbound (SNAT) rule
+ // Match return flow to also allow out traffic which was marked as forward flow on way in
+ postNat.addRule().type(DtoRule.SNAT)
+ .flowAction(DtoRule.Accept)
+ .matchReturnFlow(true)
+ .nwSrcAddress(fixedIp)
+ .nwSrcLength(32)
+ .outPorts(new UUID[]{tenantUplink.getId()})
+ .natTargets(postTargets)
+ .position(2)
+ .create();
+
+ // Set routes for traffic to the SNAT IP to come back from provider router
+ providerRouter.addRoute().type("Normal").weight(100)
+ .srcNetworkAddr("0.0.0.0").srcNetworkLength(0)
+ .dstNetworkAddr(floatingIp).dstNetworkLength(32)
+ .nextHopPort(providerDownlink.getId()).create();
+ }
+
+
+ /**
+ * From interface StaticNatServiceProvider
+ */
+ @Override
+ public boolean applyStaticNats(Network network,
+ List<? extends StaticNat> rules)
+ throws ResourceUnavailableException {
+ s_logger.debug("applyStaticNats called with network: " + network.toString());
+ if (!midoInNetwork(network)) {
+ return false;
+ }
+ if (!canHandle(network, Service.StaticNat)) {
+ return false;
+ }
+
+ boolean resources = false;
+ Router tenantRouter = null;
+ Router providerRouter = null;
+
+ RouterPort[] ports = null;
+
+ RouterPort tenantUplink = null;
+ RouterPort providerDownlink = null;
+
+ RuleChain preFilter = null;
+ RuleChain preNat = null;
+ RuleChain post = null;
+
+ String accountIdStr = String.valueOf(network.getAccountId());
+ String networkUUIDStr = String.valueOf(network.getId());
+
+ for (StaticNat rule : rules) {
+ IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId());
+ String sourceIpAddr = sourceIp.getAddress().addr();
+
+ if (resources == false) {
+ tenantRouter = getOrCreateGuestNetworkRouter(network);
+ providerRouter = api.getRouter(_providerRouterId);
+
+ ports = getOrCreateProviderRouterPorts(tenantRouter, providerRouter);
+
+ tenantUplink = ports[0];
+ providerDownlink = ports[1];
+
+ boolean isVpc = getIsVpc(network);
+ long id = getRouterId(network, isVpc);
+ String routerName = getRouterName(isVpc, id);
+
+ preFilter = getChain(accountIdStr, routerName, RuleChainCode.TR_PREFILTER);
+ preNat = getChain(accountIdStr, routerName, RuleChainCode.TR_PRENAT);
+ post = api.getChain(tenantRouter.getOutboundFilterId());
+ resources = true;
+ }
+
+ if (rule.isForRevoke()) {
+ removeMidonetStaticNAT(preFilter, preNat, post,
+ sourceIpAddr, rule.getDestIpAddress(),
+ providerRouter);
+ } else {
+ addMidonetStaticNAT(preFilter, preNat, post,
+ sourceIpAddr, rule.getDestIpAddress(),
+ tenantUplink, providerDownlink,
+ providerRouter,
+ network);
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean applyFWRules(Network config, List<? extends FirewallRule> rulesToApply) throws ResourceUnavailableException {
+ if (!midoInNetwork(config)) {
+ return false;
+ }
+ if (canHandle(config, Service.Firewall)) {
+ String accountIdStr = String.valueOf(config.getAccountId());
+ String networkUUIDStr = String.valueOf(config.getId());
+ RuleChain preFilter = getChain(accountIdStr, networkUUIDStr, RuleChainCode.TR_PREFILTER);
+ RuleChain preNat = getChain(accountIdStr, networkUUIDStr, RuleChainCode.TR_PRENAT);
+
+ // Create a map of Rule description -> Rule for quicker lookups
+ Map<String, Rule> existingRules = new HashMap<String, Rule>();
+
+ for (Rule existingRule : preFilter.getRules()) {
+ // The "whitelist" rules we're interested in are the Jump rules where src address is specified
+ if(existingRule.getType().equals(DtoRule.Jump) && existingRule.getNwSrcAddress() != null){
+ String ruleString = new SimpleFirewallRule(existingRule).toStringArray()[0];
+ existingRules.put(ruleString, existingRule);
+ }
+ }
+
+ for (FirewallRule rule : rulesToApply) {
+ IpAddress dstIp = _networkModel.getIp(rule.getSourceIpAddressId());
+ FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, dstIp.getAddress().addr());
+
+ // Convert to string representation
+ SimpleFirewallRule fwRule = new SimpleFirewallRule(ruleTO);
+ String[] ruleStrings = fwRule.toStringArray();
+
+ if (rule.getState() == FirewallRule.State.Revoke) {
+ // Lookup in existingRules, delete if present
+ for(String revokeRuleString : ruleStrings){
+ Rule foundRule = existingRules.get(revokeRuleString);
+ if(foundRule != null){
+ foundRule.delete();
+ }
+ }
+ } else if (rule.getState() == FirewallRule.State.Add) {
+ // Lookup in existingRules, add if not present
+ for(int i = 0; i < ruleStrings.length; i++){
+ String ruleString = ruleStrings[i];
+ Rule foundRule = existingRules.get(ruleString);
+ if(foundRule == null){
+ // Get the cidr for the related entry in the Source Cidrs list
+ String relatedCidr = fwRule.sourceCidrs.get(i);
+ Pair<String,Integer> cidrParts = NetUtils.getCidr(relatedCidr);
+
+ // Create rule with correct proto, cidr, ACCEPT, dst IP
+ Rule toApply = preFilter.addRule()
+ .type(DtoRule.Jump)
+ .jumpChainId(preNat.getId())
+ .position(1)
+ .nwSrcAddress(cidrParts.first())
+ .nwSrcLength(cidrParts.second())
+ .nwDstAddress(ruleTO.getSrcIp())
+ .nwDstLength(32)
+ .nwProto(SimpleFirewallRule.stringToProtocolNumber(rule.getProtocol()));
+
+ if(rule.getProtocol().equals("icmp")){
+ // ICMP rules - reuse port fields
+ toApply.tpSrcStart(fwRule.icmpType).tpSrcEnd(fwRule.icmpType)
+ .tpDstStart(fwRule.icmpCode).tpDstEnd(fwRule.icmpCode);
+ } else {
+ toApply.tpDstStart(fwRule.dstPortStart)
+ .tpDstEnd(fwRule.dstPortEnd);
+ }
+
+ toApply.create();
+ }
+ }
+ }
+ }
+ return true;
+ } else {
+ return true;
+ }
}
@Override
public Provider getProvider() {
- // TODO: implement this.
- return null;
+ return MidoNet;
}
@Override
public boolean implement(Network network, NetworkOffering offering, DeployDestination dest,
ReservationContext context)
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
- // TODO: implement this.
- return false;
+ s_logger.debug("implement called with network: " + network.toString());
+ if (!midoInNetwork(network)) {
+ return false;
+ }
+
+ if(network.getTrafficType() == Networks.TrafficType.Guest){
+ // Create the Midonet bridge for this network
+ Bridge netBridge = getOrCreateNetworkBridge(network);
+ Router tenantRouter = getOrCreateGuestNetworkRouter(network);
+
+ // connect router and bridge
+ ensureBridgeConnectedToRouter(network, netBridge, tenantRouter);
+ }
+
+ return true;
}
@Override
public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm,
DeployDestination dest, ReservationContext context)
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
- // TODO: implement this.
- return false;
+ s_logger.debug("prepare called with network: " + network.toString() + " nic: " + nic.toString() + " vm: " + vm.toString());
+ if (!midoInNetwork(network)) {
+ return false;
+ }
+
+ if (nic.getTrafficType() == Networks.TrafficType.Guest &&
+ !canHandle(network, Service.StaticNat)) {
+ return false;
+ }
+
+ if (nic.getTrafficType() == Networks.TrafficType.Guest ||
+ nic.getTrafficType() == Networks.TrafficType.Public &&
+ nic.getBroadcastType() == Networks.BroadcastDomainType.Mido){
+ Bridge netBridge = getOrCreateNetworkBridge(network);
+ if(nic.getTrafficType() == Networks.TrafficType.Public &&
+ vm.getVirtualMachine().getType() != VirtualMachine.Type.DomainRouter){
+ // Get provider router
+ Router providerRouter = api.getRouter(_providerRouterId);
+
+ Port[] ports = getOrCreatePublicBridgePorts(nic, netBridge, providerRouter);
+
+ RouterPort providerDownlink = (RouterPort) ports[1];
+
+ // Set route from router to bridge for this particular IP. Prepare
+ // is called in both starting a new VM and restarting a VM, so the
+ // NIC may
+ boolean routeExists = false;
+ for (Route route : providerRouter.getRoutes(new MultivaluedMapImpl())) {
+ String ip4 = route.getDstNetworkAddr();
+ if (ip4 != null && ip4.equals(nic.getIp4Address())) {
+ routeExists = true;
+ break;
+ }
+ }
+
+ if (!routeExists) {
+ providerRouter.addRoute()
+ .type("Normal")
+ .weight(100)
+ .srcNetworkAddr("0.0.0.0")
+ .srcNetworkLength(0)
+ .dstNetworkAddr(nic.getIp4Address())
+ .dstNetworkLength(32)
+ .nextHopPort(providerDownlink.getId())
+ .nextHopGateway(null)
+ .create();
+ }
+ }
+
+ // Add port on bridge
+ BridgePort newPort = netBridge.addExteriorPort().create(); // returns wrapper resource of port
+
+ // Set MidoNet port VIF ID to UUID of nic
+ UUID nicUUID = getNicUUID(nic);
+ newPort.vifId(nicUUID).update();
+ }
+
+ return true;
}
@Override
public boolean release(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm,
ReservationContext context)
throws ConcurrentOperationException, ResourceUnavailableException {
- // TODO: implement this.
- return false;
+ s_logger.debug("release called with network: " + network.toString() + " nic: " + nic.toString() + " vm: " + vm.toString());
+ if (!midoInNetwork(network)) {
+ return false;
+ }
+
+ UUID nicUUID = getNicUUID(nic);
+ if(nic.getTrafficType() == Networks.TrafficType.Guest ||
+ (nic.getTrafficType() == Networks.TrafficType.Public &&
+ nic.getBroadcastType() == Networks.BroadcastDomainType.Mido)) {
+ // Seems like a good place to remove the port in midonet
+ Bridge netBridge = getOrCreateNetworkBridge(network);
+
+ Router providerRouter = api.getRouter(_providerRouterId);
+
+ //remove the routes associated with this IP address
+ for (Route route : providerRouter.getRoutes(new MultivaluedMapImpl())) {
+ String routeDstAddr = route.getDstNetworkAddr();
+ if (routeDstAddr != null && routeDstAddr.equals(nic.getIp4Address())) {
+ route.delete();
+ }
+ }
+
+ for (BridgePort p : netBridge.getPorts()) {
+ UUID vifID = p.getVifId();
+ if(vifID != null && vifID.equals(nicUUID)){
+ // This is the MidoNet port which corresponds to the NIC we are releasing
+
+ // Set VIF ID to null
+ p.vifId(null).update();
+
+ // Delete port
+ p.delete();
+ }
+ }
+ }
+
+ return true;
}
@Override
public boolean shutdown(Network network, ReservationContext context, boolean cleanup)
throws ConcurrentOperationException, ResourceUnavailableException {
- // TODO: implement this.
- return false;
+ s_logger.debug("shutdown called with network: " + network.toString());
+ if (!midoInNetwork(network)) {
+ return false;
+ }
+
+ // Find Mido API server, remove ports from this network's bridge, remove bridge itself
+ deleteNetworkBridges(network);
+ if (network.getVpcId() == null) {
+ deleteGuestNetworkRouters(network);
+ }
+
+ return true;
}
@Override
- public boolean destroy(Network network) throws ConcurrentOperationException, ResourceUnavailableException {
- // TODO: implement this.
- return false;
+ public boolean destroy(Network network, ReservationContext context)
+ throws ConcurrentOperationException, ResourceUnavailableException {
+ s_logger.debug("destroy called with network: " + network.toString());
+ if (!midoInNetwork(network)) {
+ return false;
+ }
+
+ deleteNetworkBridges(network);
+ // if This is part of a VPC, then we do not want to delete the router.
+ // we only delete the router when the VPC is destroyed
+ if (network.getVpcId() == null) {
+ deleteGuestNetworkRouters(network);
+ }
+
+ return true;
}
@Override
public boolean isReady(PhysicalNetworkServiceProvider provider) {
- // TODO: implement this.
- return false;
+ // We are always ready.
+ return true;
}
@Override
public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context)
throws ConcurrentOperationException, ResourceUnavailableException {
- // TODO: implement this.
- return false;
+ // Nothing to do here because the cleanup of the networks themselves clean up the resources.
+ return true;
}
@Override
public boolean canEnableIndividualServices() {
- // TODO: implement this.
- return false;
+ // We can enable individual services, though this is still subject to
+ // "VerifyServicesCombination
+ return true;
}
@Override
public boolean verifyServicesCombination(Set<Service> services) {
- // TODO: implement this.
- return false;
+ if (services.contains(Service.Vpn) ||
+ services.contains(Service.Dns) ||
+ services.contains(Service.Lb) ||
+ services.contains(Service.UserData) ||
+ services.contains(Service.SecurityGroup) ||
+ services.contains(Service.NetworkACL)) {
+ // We don't implement any of these services, and we don't
+ // want anyone else to do it for us. So if these services
+ // exist, we can't handle it.
+ return false;
+ }
+ return true;
}
@Override
- public List<Class<?>> getCommands() {
- // TODO: implement this.
+ public boolean applyPFRules(Network network, List<PortForwardingRule> rules)
+ throws ResourceUnavailableException {
+ s_logger.debug("applyPFRules called with network " + network.toString());
+ if (!midoInNetwork(network)) {
+ return false;
+ }
+ if (!canHandle(network, Service.PortForwarding)) {
+ return false;
+ }
+
+ String accountIdStr = String.valueOf(network.getAccountId());
+ String networkUUIDStr = String.valueOf(network.getId());
+ RuleChain preNat = getChain(accountIdStr, networkUUIDStr, RuleChainCode.TR_PRENAT);
+ RuleChain postNat = getChain(accountIdStr, networkUUIDStr, RuleChainCode.TR_POST);
+ RuleChain preFilter = getChain(accountIdStr, networkUUIDStr, RuleChainCode.TR_PREFILTER);
+ Router providerRouter = api.getRouter(_providerRouterId);
+ Router tenantRouter = getOrCreateGuestNetworkRouter(network);
+ RouterPort[] ports = getOrCreateProviderRouterPorts(tenantRouter, providerRouter);
+ RouterPort providerDownlink = ports[1];
+
+ // Rules in the preNat table
+ Map<String, Rule> existingPreNatRules = new HashMap<String, Rule>();
+ for (Rule existingRule : preNat.getRules()) {
+ String ruleString = new SimpleFirewallRule(existingRule).toStringArray()[0];
+ existingPreNatRules.put(ruleString, existingRule);
+ }
+
+ /*
+ * Counts of rules associated with an IP address. Use this to check
+ * how many rules we have of a given IP address. When it reaches 0,
+ * we can delete the route associated with it.
+ */
+ Map<String, Integer> ipRuleCounts = new HashMap<String, Integer>();
+ for (Rule rule : preNat.getRules()) {
+ String ip = rule.getNwDstAddress();
+ if (ip != null && rule.getNwDstLength() == 32) {
+ if (ipRuleCounts.containsKey(ip)) {
+ ipRuleCounts.put(ip, new Integer(ipRuleCounts.get(ip).intValue() + 1));
+ } else {
+ ipRuleCounts.put(ip, new Integer(1));
+ }
+ }
+ }
+
+ /*
+ * Routes associated with IP. When we delete all the rules associated
+ * with a given IP, we can delete the route associated with it.
+ */
+ Map<String, Route> routes = new HashMap<String, Route>();
+ for (Route route : providerRouter.getRoutes(new MultivaluedMapImpl())) {
+ String ip = route.getDstNetworkAddr();
+ if (ip != null && route.getDstNetworkLength() == 32) {
+ routes.put(ip, route);
+ }
+ }
+
+ for (PortForwardingRule rule : rules) {
+ IpAddress dstIp = _networkModel.getIp(rule.getSourceIpAddressId());
+ PortForwardingRuleTO ruleTO = new PortForwardingRuleTO(rule, null, dstIp.getAddress().addr());
+ SimpleFirewallRule fwRule = new SimpleFirewallRule(ruleTO);
+ String[] ruleStrings = fwRule.toStringArray();
+
+ if (rule.getState() == FirewallRule.State.Revoke) {
+ /*
+ * Lookup in existingRules, delete if present
+ * We need to delete from both the preNat table and the
+ * postNat table.
+ */
+ for(String revokeRuleString : ruleStrings){
+ Rule foundPreNatRule = existingPreNatRules.get(revokeRuleString);
+ if(foundPreNatRule != null){
+ String ip = foundPreNatRule.getNwDstAddress();
+ // is this the last rule associated with this IP?
+ Integer cnt = ipRuleCounts.get(ip);
+ if (cnt != null) {
+ if (cnt == 1) {
+ ipRuleCounts.remove(ip);
+ // no more rules for this IP. delete the route.
+ Route route = routes.remove(ip);
+ route.delete();
+ } else {
+ ipRuleCounts.put(ip, new Integer(ipRuleCounts.get(ip).intValue() - 1));
+ }
+ }
+ foundPreNatRule.delete();
+ }
+ }
+ } else if (rule.getState() == FirewallRule.State.Add) {
+ for(int i = 0; i < ruleStrings.length; i++){
+ String ruleString = ruleStrings[i];
+ Rule foundRule = existingPreNatRules.get(ruleString);
+ if(foundRule == null){
+
+ String vmIp = ruleTO.getDstIp();
+ String publicIp = dstIp.getAddress().addr();
+ int privPortStart = ruleTO.getDstPortRange()[0];
+ int privPortEnd = ruleTO.getDstPortRange()[1];
+ int pubPortStart = ruleTO.getSrcPortRange()[0];
+ int pubPortEnd = ruleTO.getSrcPortRange()[1];
+
+ DtoRule.DtoNatTarget[] preTargets = new DtoRule.DtoNatTarget[]{
+ new DtoRule.DtoNatTarget(vmIp, vmIp, privPortStart, privPortEnd)};
+
+ Rule preNatRule = preNat.addRule()
+ .type(DtoRule.DNAT)
+ .flowAction(DtoRule.Accept)
+ .nwDstAddress(publicIp)
+ .nwDstLength(32)
+ .tpDstStart(pubPortStart)
+ .tpDstEnd(pubPortEnd)
+ .natTargets(preTargets)
+ .nwProto(SimpleFirewallRule.stringToProtocolNumber(rule.getProtocol()))
+ .position(1);
+
+ Integer cnt = ipRuleCounts.get(publicIp);
+ if (cnt != null) {
+ ipRuleCounts.put(publicIp, new Integer(cnt.intValue() + 1));
+ } else {
+ ipRuleCounts.put(publicIp, new Integer(1));
+ }
+ String preNatRuleStr = new SimpleFirewallRule(preNatRule).toStringArray()[0];
+ existingPreNatRules.put(preNatRuleStr, preNatRule);
+ preNatRule.create();
+
+ if (routes.get(publicIp) == null) {
+ Route route = providerRouter.addRoute()
+ .type("Normal")
+ .weight(100)
+ .srcNetworkAddr("0.0.0.0")
+ .srcNetworkLength(0)
+ .dstNetworkAddr(publicIp)
+ .dstNetworkLength(32)
+ .nextHopPort(providerDownlink.getId());
+ route.create();
+ routes.put(publicIp, route);
+ }
+
+ // If Firewall is in our service offering, set up the
+ // default firewall rule
+ if (canHandle(network, Service.Firewall)) {
+ boolean defaultBlock = false;
+ for (Rule filterRule : preFilter.getRules()) {
+ String pfDstIp = filterRule.getNwDstAddress();
+ if (pfDstIp != null && filterRule.getNwDstAddress().equals(publicIp)) {
+ defaultBlock = true;
+ break;
+ }
+ }
+ if (!defaultBlock) {
+ preFilter.addRule().type(DtoRule.Drop)
+ .nwDstAddress(publicIp)
+ .nwDstLength(32)
+ .create();
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+
+ private static Map<Service, Map<Capability, String>> setCapabilities() {
+ Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>();
+
+ // L2 Support : SDN provisioning
+ capabilities.put(Service.Connectivity, null);
+
+ // L3 Support : Generic?
+ capabilities.put(Service.Gateway, null);
+
+ // L3 Support : DHCP
+ capabilities.put(Service.Dhcp, null);
+
+ // L3 Support : SourceNat
+ Map<Capability, String> sourceNatCapabilities = new HashMap<Capability, String>();
+ //sourceNatCapabilities.putAll(capabilities.get(Service.SourceNat));
+ sourceNatCapabilities.put(Capability.SupportedSourceNatTypes,
+ "peraccount");
+ //sourceNatCapabilities.putAll(capabilities.get(Service.SourceNat));
+ sourceNatCapabilities.put(Capability.RedundantRouter, "false");
+ capabilities.put(Service.SourceNat, sourceNatCapabilities);
+
+ // L3 Support : Port Forwarding
+ capabilities.put(Service.PortForwarding, null);
+
+ // L3 support : StaticNat
+ capabilities.put(Service.StaticNat, null);
+
+ // Set capabilities for Firewall service
+ Map<Capability, String> firewallCapabilities = new HashMap<Capability, String>();
+ firewallCapabilities.put(Capability.TrafficStatistics, "per public ip");
+ firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp,icmp");
+ firewallCapabilities.put(Capability.SupportedTrafficDirection, "ingress");
+ firewallCapabilities.put(Capability.MultipleIps, "true");
+ capabilities.put(Service.Firewall, firewallCapabilities);
+
+ return capabilities;
+ }
+
+ private String getChainName(String routerName, RuleChainCode chainCode){
+ return getChainName("", routerName, chainCode);
+ }
+
+ private String getChainName(String networkId, String routerName, RuleChainCode chainCode) {
+
+ String chain = "";
+
+ switch (chainCode){
+ case TR_PRE:
+ chain = "pre-routing";
+ break;
+ case TR_PREFILTER:
+ chain = "pre-filter";
+ break;
+ case TR_PRENAT:
+ chain = "pre-nat";
+ break;
+ case TR_POST:
+ chain = "post-routing";
+ break;
+ case ACL_INGRESS:
+ chain = "ACL-ingress-" + networkId;
+ break;
+ case ACL_EGRESS:
+ chain = "ACL-egress-" + networkId;
+ break;
+ }
+
+ return routerName + "-tenantrouter-" + chain;
+ }
+
+ protected RuleChain getChain(String accountID, String routerName, RuleChainCode chainCode){
+ return getChain("", accountID, routerName, chainCode);
+ }
+
+ protected RuleChain getChain(String networkId, String accountID,
+ String routerName, RuleChainCode chainCode){
+ String chainName = getChainName(networkId, routerName, chainCode);
+
+ MultivaluedMap findChain = new MultivaluedMapImpl();
+ findChain.add("tenant_id", accountID);
+
+ ResourceCollection<RuleChain> ruleChains = api.getChains(findChain);
+
+ for(RuleChain chain : ruleChains){
+ if(chain.getName().equals(chainName)){
+ return chain;
+ }
+ }
+
return null;
}
+
+ protected RouterPort[] getOrCreateProviderRouterPorts(Router tenantRouter, Router providerRouter){
+ RouterPort[] ports = new RouterPort[2];
+
+ RouterPort tenantUplink = null;
+ RouterPort providerDownlink = null;
+
+ // Check if the ports and connection already exist
+ for(Port peerPort : tenantRouter.getPeerPorts((new MultivaluedMapImpl()))){
+ if(peerPort != null && peerPort instanceof RouterPort){
+ RouterPort checkPort = (RouterPort) peerPort;
+ if(checkPort.getDeviceId().compareTo(providerRouter.getId()) == 0){
+ providerDownlink = checkPort;
+ tenantUplink = (RouterPort) api.getPort(checkPort.getPeerId());
+ break;
+ }
+ }
+ }
+
+ // Create the ports and connection if they don't exist
+ if(providerDownlink == null){
+ // Add interior port on router side, with network details
+ providerDownlink = providerRouter.addInteriorRouterPort().networkAddress("169.254.255.0").networkLength(32)
+ .portAddress("169.254.255.1").create();
+ tenantUplink = tenantRouter.addInteriorRouterPort().networkAddress("169.254.255.0").networkLength(32)
+ .portAddress("169.254.255.2").create();
+
+ // Link them up
+ providerDownlink.link(tenantUplink.getId()).update();
+ }
+
+ ports[0] = tenantUplink;
+ ports[1] = providerDownlink;
+
+ return ports;
+ }
+
+ private Port[] getOrCreatePublicBridgePorts(NicProfile nic, Bridge publicBridge, Router providerRouter){
+ Port[] ports = new Port[2];
+
+ BridgePort bridgeUplink = null;
+ RouterPort providerDownlink = null;
+
+ // Check if the ports and connection already exist
+ for(Port peerPort : publicBridge.getPeerPorts()){
+ if(peerPort != null && peerPort instanceof RouterPort){
+ RouterPort checkPort = (RouterPort) peerPort;
+ // Check it's a port on the providerRouter with the right gateway address
+ if(checkPort.getDeviceId().compareTo(providerRouter.getId()) == 0
+ && checkPort.getPortAddress().equals(nic.getGateway())){
+ providerDownlink = checkPort;
+ bridgeUplink = (BridgePort) api.getPort(checkPort.getPeerId());
+ break;
+ }
+ }
+ }
+
+ // Create the ports and connection if they don't exist
+ if(providerDownlink == null){
+ String cidr = NetUtils.ipAndNetMaskToCidr(nic.getGateway(), nic.getNetmask());
+ String cidrSubnet = NetUtils.getCidrSubNet(cidr);
+ int cidrSize = (int) NetUtils.getCidrSize(NetUtils.cidr2Netmask(cidr));
+ String gateway = nic.getGateway();
+
+
+ // Add interior port on router side, with network details
+ providerDownlink = providerRouter.addInteriorRouterPort().networkAddress(cidrSubnet).networkLength(cidrSize)
+ .portAddress(gateway).create();
+ bridgeUplink = publicBridge.addInteriorPort().create();
+
+ // Link them up
+ providerDownlink.link(bridgeUplink.getId()).update();
+
+
+ }
+
+ ports[0] = bridgeUplink;
+ ports[1] = providerDownlink;
+
+ return ports;
+ }
+
+ private void ensureBridgeConnectedToRouter(Network network, Bridge netBridge, Router netRouter){
+ if(getBridgeToRouterPort(network, netBridge, netRouter) == null){
+ connectBridgeToRouter(network, netBridge, netRouter);
+ }
+ }
+
+ private BridgePort getBridgeToRouterPort(Network network, Bridge netBridge, Router netRouter){
+ for (Port p : netBridge.getPeerPorts()) {
+ if(p.getClass().equals(BridgePort.class)){
+ BridgePort bp = (BridgePort) p;
+ if(bp.getPeerId().compareTo(netRouter.getId()) == 0){
+ return bp;
+ }
+ }
+ }
+ return null;
+ }
+
+ /*
+ * resetEgressACLFilter sets the Egress ACL Filter back to its initial
+ * state - drop everything. This needs to be called when all Egress
+ * ACL rules are deleted, so we can start allowing all Egress traffic
+ * again
+ */
+ protected void resetEgressACLFilter(Network network) {
+ boolean isVpc = getIsVpc(network);
+ long id = getRouterId(network, isVpc);
+ String routerName = getRouterName(isVpc, id);
+
+ RuleChain egressChain = getChain(String.valueOf(network.getId()),
+ String.valueOf(network.getAccountId()),
+ routerName,
+ RuleChainCode.ACL_EGRESS);
+
+ // Clear all the rules out
+ for (Rule rule : egressChain.getRules()) {
+ rule.delete();
+ }
+
+ // Add a matchForwardFlow rule so that we can accept all return traffic
+ egressChain.addRule().type(DtoRule.Accept)
+ .matchForwardFlow(true)
+ .position(1)
+ .create();
+ }
+
+ protected RuleChain getOrInitEgressACLFilter(Network network) {
+ boolean isVpc = getIsVpc(network);
+ long id = getRouterId(network, isVpc);
+ String routerName = getRouterName(isVpc, id);
+
+ RuleChain egressChain = getChain(String.valueOf(network.getId()),
+ String.valueOf(network.getAccountId()),
+ routerName,
+ RuleChainCode.ACL_EGRESS);
+
+ // Rules set by the user will have a protocol, so we count the ACL
+ // rules by counting how much have the nwProto field set.
+ int totalRules = 0;
+ for (Rule rule : egressChain.getRules()) {
+ if (rule.getNwProto() != 0) {
+ totalRules++;
+ }
+ }
+
+ if (totalRules > 0) {
+ // There are already rules present, no need to init.
+ return egressChain;
+ } else {
+ // We need to delete any placeholder rules
+ for (Rule rule : egressChain.getRules()) {
+ rule.delete();
+ }
+ }
+
+ int pos = 1;
+ // If it is ARP, accept it
+ egressChain.addRule().type(DtoRule.Accept)
+ .dlType((short)0x0806)
+ .position(pos++)
+ .create();
+
+ // Everything else gets dropped
+ egressChain.addRule()
+ .type(DtoRule.Drop)
+ .position(pos)
+ .create();
+
+ return egressChain;
+ }
+
+ private void connectBridgeToRouter(Network network, Bridge netBridge, Router netRouter){
+
+ boolean isVpc = getIsVpc(network);
+ long id = getRouterId(network, isVpc);
+ String routerName = getRouterName(isVpc, id);
+ String accountIdStr = String.valueOf(network.getAccountId());
+
+ // Add interior port on bridge side
+ BridgePort bridgePort = netBridge.addInteriorPort().create();
+
+ // Add interior port on router side, with network details
+ RouterPort routerPort = netRouter.addInteriorRouterPort();
+ String cidr = network.getCidr();
+ String cidrSubnet = NetUtils.getCidrSubNet(cidr);
+ int cidrSize = (int) NetUtils.getCidrSize(NetUtils.cidr2Netmask(cidr));
+
+ routerPort.networkAddress(cidrSubnet);
+ routerPort.networkLength(cidrSize);
+ routerPort.portAddress(network.getGateway());
+
+
+ // If this is a VPC, then we will be using NetworkACLs, which is
+ // implemented via chains on the router port to that network.
+ if (getIsVpc(network)) {
+ // Create ACL filter chain for traffic coming INTO the network
+ // (outbound from the port
+ int pos = 1;
+
+ RuleChain inc = api.addChain()
+ .name(getChainName(String.valueOf(network.getId()),
+ routerName,
+ RuleChainCode.ACL_INGRESS))
+ .tenantId(accountIdStr)
+ .create();
+
+
+ // If it is ARP, accept it
+ inc.addRule().type(DtoRule.Accept)
+ .dlType((short)0x0806)
+ .position(pos++)
+ .create();
+
+ // If it is connection tracked, accept that as well
+ inc.addRule().type(DtoRule.Accept)
+ .matchReturnFlow(true)
+ .position(pos++)
+ .create();
+
+ inc.addRule().type(DtoRule.Drop)
+ .position(pos)
+ .create();
+
+ //
+ RuleChain out = api.addChain()
+ .name(getChainName(String.valueOf(network.getId()),
+ routerName,
+ RuleChainCode.ACL_EGRESS))
+ .tenantId(accountIdStr)
+ .create();
+
+ // Creating the first default rule here that does nothing
+ // but start connection tracking.
+ out.addRule().type(DtoRule.Accept)
+ .matchForwardFlow(true)
+ .position(1)
+ .create();
+
+ routerPort.outboundFilterId(inc.getId());
+ routerPort.inboundFilterId(out.getId());
+ }
+
+ routerPort.create();
+
+ // Link them up
+ bridgePort.link(routerPort.getId()).update();
+
+ // Set up default route from router to subnet
+ netRouter.addRoute().type("Normal").weight(100)
+ .srcNetworkAddr("0.0.0.0").srcNetworkLength(0)
+ .dstNetworkAddr(cidrSubnet).dstNetworkLength(cidrSize)
+ .nextHopPort(routerPort.getId()).nextHopGateway(null).create();
+ }
+
+ private Bridge getOrCreateNetworkBridge(Network network){
+ // Find the single bridge for this network, create if doesn't exist
+ return getOrCreateNetworkBridge(network.getId(), network.getAccountId());
+ }
+
+ private Bridge getOrCreateNetworkBridge(long networkID, long accountID){
+ Bridge netBridge = getNetworkBridge(networkID, accountID);
+ if(netBridge == null){
+
+ String accountIdStr = String.valueOf(accountID);
+ String networkUUIDStr = String.valueOf(networkID);
+
+ netBridge = api.addBridge().tenantId(accountIdStr).name(networkUUIDStr).create();
+ }
+ return netBridge;
+ }
+
+ private Bridge getNetworkBridge(long networkID, long accountID){
+
+ MultivaluedMap qNetBridge = new MultivaluedMapImpl();
+ String accountIdStr = String.valueOf(accountID);
+ String networkUUIDStr = String.valueOf(networkID);
+ qNetBridge.add("tenant_id", accountIdStr);
+
+ for (Bridge b : this. api.getBridges(qNetBridge)) {
+ if(b.getName().equals(networkUUIDStr)){
+ return b;
+ }
+ }
+
+ return null;
+ }
+
+ protected boolean getIsVpc(Network network) {
+ return (network.getVpcId() != null);
+ }
+
+ protected long getRouterId(Network network, boolean isVpc) {
+ if (isVpc) {
+ return network.getVpcId();
+ } else {
+ return network.getId();
+ }
+ }
+
+ private Router getOrCreateGuestNetworkRouter(Network network){
+ // Find the single bridge for this (isolated) guest network, create if doesn't exist
+ boolean isVpc = getIsVpc(network);
+ long id = getRouterId(network, isVpc);
+
+ return getOrCreateGuestNetworkRouter(id, network.getAccountId(), isVpc);
+
+ }
+
+ protected String getRouterName(boolean isVpc, long id) {
+ if (isVpc) {
+ return "VPC" + String.valueOf(id);
+ } else {
+ return String.valueOf(id);
+ }
+ }
+
+ protected Router createRouter(long id, long accountID, boolean isVpc) {
+
+ String accountIdStr = String.valueOf(accountID);
+ String routerName = getRouterName(isVpc, id);
+
+ //Set up rule chains
+ RuleChain pre = api.addChain()
+ .name(getChainName(routerName, RuleChainCode.TR_PRE))
+ .tenantId(accountIdStr)
+ .create();
+ RuleChain post = api.addChain()
+ .name(getChainName(routerName, RuleChainCode.TR_POST))
+ .tenantId(accountIdStr)
+ .create();
+
+ // Set up NAT and filter chains for pre-routing
+ RuleChain preFilter = api.addChain()
+ .name(getChainName(routerName, RuleChainCode.TR_PREFILTER))
+ .tenantId(accountIdStr)
+ .create();
+ RuleChain preNat = api.addChain()
+ .name(getChainName(routerName, RuleChainCode.TR_PRENAT))
+ .tenantId(accountIdStr)
+ .create();
+
+ // Hook the chains in - first jump to Filter chain, then jump to Nat chain
+ pre.addRule().type(DtoRule.Jump)
+ .jumpChainId(preFilter.getId())
+ .position(1)
+ .create();
+ pre.addRule().type(DtoRule.Jump)
+ .jumpChainId(preNat.getId())
+ .position(2)
+ .create();
+
+ return api.addRouter()
+ .tenantId(accountIdStr)
+ .name(routerName)
+ .inboundFilterId(pre.getId())
+ .outboundFilterId(post.getId())
+ .create();
+ }
+
+ private Router getOrCreateGuestNetworkRouter(long id, long accountID, boolean isVpc) {
+ Router tenantRouter = getGuestNetworkRouter(id, accountID, isVpc);
+ if(tenantRouter == null){
+ tenantRouter = createRouter(id, accountID, isVpc);
+ }
+ return tenantRouter;
+ }
+
+ private Router getGuestNetworkRouter(long id, long accountID, boolean isVpc){
+
+ MultivaluedMap qNetRouter = new MultivaluedMapImpl();
+ String accountIdStr = String.valueOf(accountID);
+ String routerName = getRouterName(isVpc, id);
+
+ qNetRouter.add("tenant_id", accountIdStr);
+
+ for (Router router : api.getRouters(qNetRouter)) {
+ if(router.getName().equals(routerName)){
+ return router;
+ }
+ }
+
+ return null;
+ }
+
+ private UUID getNicUUID(NicProfile nic){
+ NicVO nicvo = _nicDao.findById(nic.getId());
+ return UUID.fromString(nicvo.getUuid());
+ }
+
+ private void cleanBridge(Bridge br) {
+
+ for(Port peerPort : br.getPeerPorts()) {
+ if(peerPort != null && peerPort instanceof RouterPort){
+ RouterPort checkPort = (RouterPort) peerPort;
+ if(checkPort.getType().equals("ExteriorRouter")) {
+ checkPort.vifId(null).update();
+ } else if (checkPort.getType().equals("InteriorRouter")) {
+ checkPort.unlink();
+ }
+ checkPort.delete();
+ }
+ }
+
+ for(BridgePort p : br.getPorts()) {
+
+ if(p.getType().equals("ExteriorBridge")) {
+ // Set VIF ID to null
+ p.vifId(null).update();
+ }
+
+ if(p.getType().equals("InteriorBridge")) {
+ p.unlink();
+ }
+
+ // Delete port
+ p.delete();
+ }
+ }
+
+ private void deleteNetworkBridges(Network network){
+ long accountID = network.getAccountId();
+ long networkID = network.getId();
+
+ Bridge netBridge = getNetworkBridge(networkID, accountID);
+ if(netBridge != null){
+
+ cleanBridge(netBridge);
+
+ // Delete DHCP subnets
+ for(Object dhcpSubnet : netBridge.getDhcpSubnets()){
+ DhcpSubnet sub = (DhcpSubnet) dhcpSubnet;
+ sub.delete();
+ }
+
+ netBridge.delete();
+ }
+ }
+
+ private void deleteGuestNetworkRouters(Network network){
+ long accountID = network.getAccountId();
+ boolean isVpc = getIsVpc(network);
+ long id = getRouterId(network, isVpc);
+
+ Router tenantRouter = getGuestNetworkRouter(id, accountID, isVpc);
+
+ // Delete any peer ports corresponding to this router
+ for(Port peerPort : tenantRouter.getPeerPorts((new MultivaluedMapImpl()))){
+ if(peerPort != null && peerPort instanceof RouterPort){
+ RouterPort checkPort = (RouterPort) peerPort;
+ if(checkPort.getType().equals("ExteriorRouter")) {
+ checkPort.vifId(null).update();
+ } else if (checkPort.getType().equals("InteriorRouter")) {
+ checkPort.unlink();
+ }
+ checkPort.delete();
+ } else if (peerPort != null && peerPort instanceof BridgePort) {
+ BridgePort checkPort = (BridgePort) peerPort;
+ if(checkPort.getType().equals("ExteriorBridge")) {
+ checkPort.vifId(null).update();
+ } else if (checkPort.getType().equals("InteriorBridge")) {
+ checkPort.unlink();
+ }
+ checkPort.delete();
+ }
+ }
+
+ if(tenantRouter != null){
+ // Remove all peer ports if any exist
+ for(RouterPort p : tenantRouter.getPorts(new MultivaluedMapImpl())) {
+ if(p.getType().equals("ExteriorRouter")) {
+ // Set VIF ID to null
+ p.vifId(null).update();
+ // the port might have some chains associated with it
+ }
+
+ if(p.getType().equals("InteriorRouter")) {
+ p.unlink();
+ }
+
+ // Delete port
+ p.delete();
+ }
+
+ // Remove inbound and outbound filter chains
+ String accountIdStr = String.valueOf(accountID);
+ String routerName = getRouterName(isVpc, id);
+
+ RuleChain pre = api.getChain(tenantRouter.getInboundFilterId());
+ RuleChain preFilter = getChain(accountIdStr, routerName, RuleChainCode.TR_PREFILTER);
+ RuleChain preNat = getChain(accountIdStr, routerName, RuleChainCode.TR_PRENAT);
+ RuleChain post = api.getChain(tenantRouter.getOutboundFilterId());
+
+ pre.delete();
+ preFilter.delete();
+ preNat.delete();
+ post.delete();
+
+
+ // Remove routes
+ for(Route r : tenantRouter.getRoutes(new MultivaluedMapImpl())) {
+ r.delete();
+ }
+
+ tenantRouter.delete();
+ }
+ }
+
+ @Override
+ public List<Class<?>> getCommands() {
+ // MidoNet does not implement any commands, so we return an empty list.
+ return new ArrayList<Class<?>>();
+ }
}