You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by hu...@apache.org on 2013/04/03 12:14:43 UTC

[1/4] git commit: updated refs/heads/master to 4456745

Updated Branches:
  refs/heads/master 213c16301 -> 44567453e


Rename MidoNetElement and MidoNetGuestNetworkGuru

- Creating this as a separate commit so that it is marked as a rename
- Over 50% code changed, so would count as a delete and add otherwise

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/d392445f
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/d392445f
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/d392445f

Branch: refs/heads/master
Commit: d392445f7e9adab7d6effd4daf0d76bb0e6f9bd9
Parents: 213c163
Author: Dave Cahill <dc...@midokura.com>
Authored: Wed Mar 13 17:27:09 2013 +0900
Committer: Hugo Trippaers <ht...@schubergphilis.com>
Committed: Wed Apr 3 12:03:05 2013 +0200

----------------------------------------------------------------------
 .../network/element/MidokuraMidonetElement.java    |  131 ---------------
 .../guru/MidokuraMidonetGuestNetworkGuru.java      |   48 ------
 .../com/cloud/network/element/MidoNetElement.java  |  131 +++++++++++++++
 .../network/guru/MidoNetGuestNetworkGuru.java      |   48 ++++++
 4 files changed, 179 insertions(+), 179 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d392445f/plugins/network-elements/midokura-midonet/src/com/cloud/network/element/MidokuraMidonetElement.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/midokura-midonet/src/com/cloud/network/element/MidokuraMidonetElement.java b/plugins/network-elements/midokura-midonet/src/com/cloud/network/element/MidokuraMidonetElement.java
deleted file mode 100644
index 48833b3..0000000
--- a/plugins/network-elements/midokura-midonet/src/com/cloud/network/element/MidokuraMidonetElement.java
+++ /dev/null
@@ -1,131 +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.
- */
-
-package com.cloud.network.element;
-
-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.offering.NetworkOffering;
-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 org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
-
-import javax.ejb.Local;
-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);
-
-    @Override
-    public Map<Service, Map<Capability, String>> getCapabilities() {
-        // TODO: implement this.
-        return null;
-    }
-
-    @Override
-    public Provider getProvider() {
-        // TODO: implement this.
-        return null;
-    }
-
-    @Override
-    public boolean implement(Network network, NetworkOffering offering, DeployDestination dest,
-                             ReservationContext context)
-            throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
-        // TODO: implement this.
-        return false;
-    }
-
-    @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;
-    }
-
-    @Override
-    public boolean release(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm,
-                           ReservationContext context)
-            throws ConcurrentOperationException, ResourceUnavailableException {
-        // TODO: implement this.
-        return false;
-    }
-
-    @Override
-    public boolean shutdown(Network network, ReservationContext context, boolean cleanup)
-            throws ConcurrentOperationException, ResourceUnavailableException {
-        // TODO: implement this.
-        return false;
-    }
-
-    @Override
-    public boolean destroy(Network network) throws ConcurrentOperationException, ResourceUnavailableException {
-        // TODO: implement this.
-        return false;
-    }
-
-    @Override
-    public boolean isReady(PhysicalNetworkServiceProvider provider) {
-        // TODO: implement this.
-        return false;
-    }
-
-    @Override
-    public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context)
-            throws ConcurrentOperationException, ResourceUnavailableException {
-        // TODO: implement this.
-        return false;
-    }
-
-    @Override
-    public boolean canEnableIndividualServices() {
-        // TODO: implement this.
-        return false;
-    }
-
-    @Override
-    public boolean verifyServicesCombination(Set<Service> services) {
-        // TODO: implement this.
-        return false;
-    }
-
-    @Override
-    public List<Class<?>> getCommands() {
-        // TODO: implement this.
-        return null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d392445f/plugins/network-elements/midokura-midonet/src/com/cloud/network/guru/MidokuraMidonetGuestNetworkGuru.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/midokura-midonet/src/com/cloud/network/guru/MidokuraMidonetGuestNetworkGuru.java b/plugins/network-elements/midokura-midonet/src/com/cloud/network/guru/MidokuraMidonetGuestNetworkGuru.java
deleted file mode 100644
index ed0eb3c..0000000
--- a/plugins/network-elements/midokura-midonet/src/com/cloud/network/guru/MidokuraMidonetGuestNetworkGuru.java
+++ /dev/null
@@ -1,48 +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.
- */
-
-package com.cloud.network.guru;
-
-import com.cloud.dc.DataCenter.NetworkType;
-import com.cloud.network.PhysicalNetwork;
-import com.cloud.offering.NetworkOffering;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
-
-import javax.ejb.Local;
-
-/**
- * User: tomoe
- * Date: 8/8/12
- * Time: 10:46 AM
- */
-
-@Component
-@Local(value = NetworkGuru.class)
-public class MidokuraMidonetGuestNetworkGuru extends GuestNetworkGuru {
-    private static final Logger s_logger = Logger.getLogger(MidokuraMidonetGuestNetworkGuru.class);
-
-
-    @Override
-    protected boolean canHandle(NetworkOffering offering, NetworkType networkType,
-                                PhysicalNetwork physicalNetwork) {
-        // TODO: implement this.
-        return false;
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d392445f/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
new file mode 100644
index 0000000..48833b3
--- /dev/null
+++ b/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+package com.cloud.network.element;
+
+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.offering.NetworkOffering;
+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 org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import javax.ejb.Local;
+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);
+
+    @Override
+    public Map<Service, Map<Capability, String>> getCapabilities() {
+        // TODO: implement this.
+        return null;
+    }
+
+    @Override
+    public Provider getProvider() {
+        // TODO: implement this.
+        return null;
+    }
+
+    @Override
+    public boolean implement(Network network, NetworkOffering offering, DeployDestination dest,
+                             ReservationContext context)
+            throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
+        // TODO: implement this.
+        return false;
+    }
+
+    @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;
+    }
+
+    @Override
+    public boolean release(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm,
+                           ReservationContext context)
+            throws ConcurrentOperationException, ResourceUnavailableException {
+        // TODO: implement this.
+        return false;
+    }
+
+    @Override
+    public boolean shutdown(Network network, ReservationContext context, boolean cleanup)
+            throws ConcurrentOperationException, ResourceUnavailableException {
+        // TODO: implement this.
+        return false;
+    }
+
+    @Override
+    public boolean destroy(Network network) throws ConcurrentOperationException, ResourceUnavailableException {
+        // TODO: implement this.
+        return false;
+    }
+
+    @Override
+    public boolean isReady(PhysicalNetworkServiceProvider provider) {
+        // TODO: implement this.
+        return false;
+    }
+
+    @Override
+    public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context)
+            throws ConcurrentOperationException, ResourceUnavailableException {
+        // TODO: implement this.
+        return false;
+    }
+
+    @Override
+    public boolean canEnableIndividualServices() {
+        // TODO: implement this.
+        return false;
+    }
+
+    @Override
+    public boolean verifyServicesCombination(Set<Service> services) {
+        // TODO: implement this.
+        return false;
+    }
+
+    @Override
+    public List<Class<?>> getCommands() {
+        // TODO: implement this.
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d392445f/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java
new file mode 100644
index 0000000..ed0eb3c
--- /dev/null
+++ b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package com.cloud.network.guru;
+
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.network.PhysicalNetwork;
+import com.cloud.offering.NetworkOffering;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import javax.ejb.Local;
+
+/**
+ * User: tomoe
+ * Date: 8/8/12
+ * Time: 10:46 AM
+ */
+
+@Component
+@Local(value = NetworkGuru.class)
+public class MidokuraMidonetGuestNetworkGuru extends GuestNetworkGuru {
+    private static final Logger s_logger = Logger.getLogger(MidokuraMidonetGuestNetworkGuru.class);
+
+
+    @Override
+    protected boolean canHandle(NetworkOffering offering, NetworkType networkType,
+                                PhysicalNetwork physicalNetwork) {
+        // TODO: implement this.
+        return false;
+    }
+}
\ No newline at end of file


[4/4] git commit: updated refs/heads/master to 4456745

Posted by hu...@apache.org.
Enable the midonet plugin


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/44567453
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/44567453
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/44567453

Branch: refs/heads/master
Commit: 44567453e0511e3090ac22518113b283cfa26b4b
Parents: eddf7b9
Author: Hugo Trippaers <ht...@schubergphilis.com>
Authored: Wed Apr 3 12:04:58 2013 +0200
Committer: Hugo Trippaers <ht...@schubergphilis.com>
Committed: Wed Apr 3 12:04:58 2013 +0200

----------------------------------------------------------------------
 client/tomcatconf/componentContext.xml.in       |   13 +++++++++++++
 client/tomcatconf/nonossComponentContext.xml.in |   15 +++++++++++++++
 2 files changed, 28 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/44567453/client/tomcatconf/componentContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in
index 51980c9..6c7c7d4 100644
--- a/client/tomcatconf/componentContext.xml.in
+++ b/client/tomcatconf/componentContext.xml.in
@@ -141,6 +141,7 @@
           <ref bean="OvsGuestNetworkGuru"/>
           <ref bean="PrivateNetworkGuru"/>
           <ref bean="NiciraNvpGuestNetworkGuru"/>
+          <ref bean="MidoNetGuestNetworkGuru"/>
       </list>
     </property>
     <property name="NetworkElements">
@@ -150,6 +151,7 @@
           <ref bean="SecurityGroupProvider"/>
           <ref bean="VpcVirtualRouter"/>
           <ref bean="NiciraNvp"/>
+          <ref bean="MidoNetElement"/>
 <!--
           <ref bean="BareMetalDhcp"/>
           <ref bean="BareMetalPxe"/>
@@ -183,6 +185,7 @@
           <ref bean="SecurityGroupProvider"/>
           <ref bean="VpcVirtualRouter"/>
           <ref bean="NiciraNvp" />
+          <ref bean="MidoNetElement"/>
 <!--
           <ref bean="BareMetalDhcp"/>
           <ref bean="BareMetalPxe"/>
@@ -206,6 +209,16 @@
   <bean id="NiciraNvp" class="com.cloud.network.element.NiciraNvpElement">
     <property name="name" value="NiciraNvp"/>
   </bean>
+
+  <!-- 
+    Midonet support components
+  -->
+  <bean id="MidoNetGuestNetworkGuru" class="com.cloud.network.guru.MidoNetGuestNetworkGuru">
+    <property name="name" value="MidoNetGuestNetworkGuru"/>
+  </bean>
+  <bean id="MidoNetElement" class="com.cloud.network.element.MidoNetElement">
+    <property name="name" value="MidoNetElement"/>
+  </bean>
   
 
 </beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/44567453/client/tomcatconf/nonossComponentContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in
index a9418d7..479c03f 100644
--- a/client/tomcatconf/nonossComponentContext.xml.in
+++ b/client/tomcatconf/nonossComponentContext.xml.in
@@ -235,6 +235,7 @@
           <ref bean="OvsGuestNetworkGuru"/>
           <ref bean="PrivateNetworkGuru"/>
           <ref bean="NiciraNvpGuestNetworkGuru" />
+          <ref bean="MidoNetGuestNetworkGuru" />
       </list>
     </property>
     <property name="NetworkElements">
@@ -244,6 +245,7 @@
           <ref bean="F5BigIP"/>
           <ref bean="CiscoNexus1000vVSM"/>
           <ref bean="NiciraNvp" />
+          <ref bean="MidoNetElement" />
           <ref bean="bigSwitchVnsElement"/>
           <ref bean="VirtualRouter"/>
           <ref bean="Ovs"/>
@@ -282,6 +284,7 @@
           <ref bean="F5BigIP"/>
           <ref bean="CiscoNexus1000vVSM"/>
           <ref bean="NiciraNvp" />
+          <ref bean="MidoNetElement" />
           <ref bean="bigSwitchVnsElement"/>
           <ref bean="VirtualRouter"/>
           <ref bean="Ovs"/>
@@ -296,4 +299,16 @@
     </property>
   </bean>
 
+  <!--
+    Midonet support components
+  -->
+  <bean id="MidoNetGuestNetworkGuru" class="com.cloud.network.guru.MidoNetGuestNetworkGuru">
+    <property name="name" value="MidoNetGuestNetworkGuru"/>
+  </bean>
+  <bean id="MidoNetElement" class="com.cloud.network.element.MidoNetElement">
+    <property name="name" value="MidoNetElement"/>
+  </bean>
+
+
+
 </beans>


[3/4] git commit: updated refs/heads/master to 4456745

Posted by hu...@apache.org.
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/master
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<?>>();
+    }
 }


[2/4] MidoNet Networking Plugin

Posted by hu...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/plugins/network-elements/midonet/src/com/cloud/network/element/SimpleFirewallRule.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/midonet/src/com/cloud/network/element/SimpleFirewallRule.java b/plugins/network-elements/midonet/src/com/cloud/network/element/SimpleFirewallRule.java
new file mode 100644
index 0000000..4c04445
--- /dev/null
+++ b/plugins/network-elements/midonet/src/com/cloud/network/element/SimpleFirewallRule.java
@@ -0,0 +1,192 @@
+package com.cloud.network.element;
+
+import com.cloud.agent.api.to.FirewallRuleTO;
+import com.cloud.agent.api.to.NetworkACLTO;
+import com.cloud.agent.api.to.PortForwardingRuleTO;
+import com.midokura.midonet.client.dto.DtoRule;
+import com.google.common.collect.*;
+import com.midokura.midonet.client.resource.*;
+
+import java.util.*;
+// Used for translation between MidoNet firewall rules and
+// CloudStack firewall rules
+public class SimpleFirewallRule {
+
+    public List<String> sourceCidrs;
+    public String protocol;
+    public String dstIp;
+    public int dstPortStart = 0;
+    public int dstPortEnd = 0;
+    public int icmpType = 0;
+    public int icmpCode = 0;
+
+    private static BiMap<Integer,String> protocolNumberToString;
+    static {
+        protocolNumberToString = HashBiMap.create();
+        protocolNumberToString.put(1, "icmp");
+        protocolNumberToString.put(6, "tcp");
+        protocolNumberToString.put(17, "udp");
+        protocolNumberToString.put(0, "none");
+    }
+
+    public SimpleFirewallRule(FirewallRuleTO rule){
+        // Destination IP (confusingly called SourceIP in FirewallRule attributes)
+        dstIp = rule.getSrcIp();
+        protocol = rule.getProtocol();
+
+        if("icmp".equals(protocol)){
+            icmpType = rule.getIcmpType();
+            icmpCode = rule.getIcmpCode();
+        } else {
+            int[] portNumbers = rule.getSrcPortRange();
+
+            // if port start and end are not set, they
+            // should be 0,0, and that's already the case
+            if(portNumbers != null && portNumbers.length == 2){
+                dstPortStart = portNumbers[0];
+                dstPortEnd = portNumbers[1];
+            }
+        }
+
+        sourceCidrs = rule.getSourceCidrList();
+
+        // If no CIDRs specified, it is an "all sources" rule
+        if (sourceCidrs == null || sourceCidrs.isEmpty())
+        {
+            sourceCidrs = new ArrayList<String>();
+            sourceCidrs.add("0.0.0.0/0");
+        }
+    }
+
+    public SimpleFirewallRule(NetworkACLTO rule) {
+        dstIp = "null";
+        protocol = rule.getProtocol();
+
+        if("icmp".equals(protocol)){
+            icmpType = rule.getIcmpType();
+            icmpCode = rule.getIcmpCode();
+        } else {
+            int[] portNumbers = rule.getSrcPortRange();
+
+            // if port start and end are not set, they
+            // should be 0,0, and that's already the case
+            if(portNumbers != null && portNumbers.length == 2){
+                dstPortStart = portNumbers[0];
+                dstPortEnd = portNumbers[1];
+            }
+        }
+
+        sourceCidrs = rule.getSourceCidrList();
+
+        // If no CIDRs specified, it is an "all sources" rule
+        if (sourceCidrs == null || sourceCidrs.isEmpty())
+        {
+            sourceCidrs = new ArrayList<String>();
+            sourceCidrs.add("0.0.0.0/0");
+        }
+    }
+
+    public SimpleFirewallRule(PortForwardingRuleTO rule) {
+        dstIp = rule.getSrcIp();
+        protocol = rule.getProtocol();
+
+        int[] srcPortNumbers = rule.getSrcPortRange();
+        int[] dstPortNumbers = rule.getDstPortRange();
+
+        // if port start and end are not set, they
+        // should be 0,0, and that's already the case
+        if(srcPortNumbers != null && srcPortNumbers.length == 2 &&
+           dstPortNumbers != null && dstPortNumbers.length == 2){
+            dstPortStart = dstPortNumbers[0];
+            dstPortEnd = srcPortNumbers[0];
+        }
+
+        sourceCidrs = new ArrayList<String>();
+        sourceCidrs.add(rule.getDstIp());
+    }
+
+    public SimpleFirewallRule(Rule rule){
+
+        String sourceIP = rule.getNwSrcAddress();
+        int sourceLength = rule.getNwSrcLength();
+
+        sourceCidrs = new ArrayList<String>();
+        /*
+         * Only one IP in the CIDR list
+         * Port Forwarding Rules don't have sourceCidrs, but they do have
+         * targets. Use those instead if they exist.
+         */
+        DtoRule.DtoNatTarget[] targets = rule.getNatTargets();
+        if (targets != null) {
+            sourceCidrs.add(targets[0].addressFrom);
+        } else {
+            sourceCidrs.add(String.format("%s/%d", sourceIP, sourceLength));
+        }
+
+        int protoNum = rule.getNwProto();
+        protocol = SimpleFirewallRule.protocolNumberToString(protoNum);
+
+        dstIp = rule.getNwDstAddress();
+
+        if("icmp".equals(protocol)){
+            icmpType = rule.getTpSrcStart();
+            icmpCode = rule.getTpDstStart();
+        } else {
+            /*
+             * If this is port forwarding, we want to take the start
+             * port for the public port range, and the start port for
+             * the private port range to uniquely identify this rule.
+             */
+            if (targets != null) {
+                dstPortStart = targets[0].portFrom;
+            } else {
+                dstPortStart = rule.getTpDstStart();
+            }
+            dstPortEnd = rule.getTpDstEnd();
+        }
+
+        // cidr, protocol, dstIp, dstPortStart, dstPortEnd, icmpType, icmpCode);
+    }
+
+    public static String protocolNumberToString(int protocolNumber){
+        return protocolNumberToString.get(protocolNumber);
+    }
+
+    public static int stringToProtocolNumber(String protoString){
+        return protocolNumberToString.inverse().get(protoString);
+    }
+
+    public int getFieldOne(){
+        if(protocol.equals("icmp")){
+            return icmpType;
+        } else {
+            return dstPortStart;
+        }
+    }
+
+    public int getFieldTwo(){
+        if(protocol.equals("icmp")){
+            return icmpCode;
+        } else {
+            return dstPortEnd;
+        }
+    }
+
+    public String[] toStringArray() {
+        List<String> stringRules = new ArrayList<String>();
+
+        // Create a rule string per source CIDR, since each MidoNet
+        // rule is for one CIDR
+        for(String sourceCidr : sourceCidrs){
+
+            // Follows the rule String format defined in SetFirewallRulesCommand.java::generateFirewallRules()
+            int field1 = getFieldOne();
+            int field2 = getFieldTwo();
+
+            String stringRule = String.format("%s:%s:%d:%d:%s:", dstIp, protocol, field1, field2, sourceCidr);
+            stringRules.add(stringRule);
+        }
+        String[] stringArray = new String[stringRules.size()];
+        return stringRules.toArray(stringArray);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java
index ed0eb3c..20b74b9 100644
--- a/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java
+++ b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java
@@ -19,30 +19,152 @@
 
 package com.cloud.network.guru;
 
+import com.cloud.network.element.MidoNetElement;
+import com.cloud.dc.DataCenter;
 import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.deploy.DeploymentPlan;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
+import com.cloud.network.*;
 import com.cloud.network.PhysicalNetwork;
 import com.cloud.offering.NetworkOffering;
+import com.cloud.user.Account;
+import com.cloud.vm.*;
+import com.midokura.midonet.client.resource.Bridge;
+import com.cloud.utils.net.NetUtils;
+
+import com.cloud.network.Networks.AddressFormat;
+import com.midokura.midonet.client.resource.BridgePort;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.PhysicalNetworkVO;
 
-import javax.ejb.Local;
 
-/**
- * User: tomoe
- * Date: 8/8/12
- * Time: 10:46 AM
- */
+import com.cloud.vm.Nic.ReservationStrategy;
+
+import javax.ejb.Local;
+import java.util.UUID;
 
 @Component
 @Local(value = NetworkGuru.class)
-public class MidokuraMidonetGuestNetworkGuru extends GuestNetworkGuru {
-    private static final Logger s_logger = Logger.getLogger(MidokuraMidonetGuestNetworkGuru.class);
+public class MidoNetGuestNetworkGuru extends GuestNetworkGuru {
+    private static final Logger s_logger = Logger.getLogger(MidoNetGuestNetworkGuru.class);
 
+    public MidoNetGuestNetworkGuru() {
+        super();
+        _isolationMethods = new PhysicalNetwork.IsolationMethod[] { PhysicalNetwork.IsolationMethod.MIDO };
+    }
 
     @Override
     protected boolean canHandle(NetworkOffering offering, NetworkType networkType,
                                 PhysicalNetwork physicalNetwork) {
-        // TODO: implement this.
-        return false;
+        // This guru handles only Guest Isolated network that supports Source nat service
+        if (networkType == NetworkType.Advanced
+                && isMyTrafficType(offering.getTrafficType())
+                && offering.getGuestType() == Network.GuestType.Isolated
+                && isMyIsolationMethod(physicalNetwork)) {
+            return true;
+        } else {
+            s_logger.trace("We only take care of Guest networks of type   " + Network.GuestType.Isolated + " in zone of type " + NetworkType.Advanced + " using isolation method MIDO.");
+            return false;
+        }
+    }
+
+
+    @Override
+    public Network design(NetworkOffering offering, DeploymentPlan plan,
+                          Network userSpecified, Account owner) {
+        s_logger.debug("design called");
+        // Check if the isolation type of the related physical network is MIDO
+        PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId());
+        if (physnet == null || physnet.getIsolationMethods() == null || !physnet.getIsolationMethods().contains("MIDO")) {
+            s_logger.debug("Refusing to design this network, the physical isolation type is not MIDO");
+            return null;
+        }
+
+        s_logger.debug("Physical isolation type is MIDO, asking GuestNetworkGuru to design this network");
+        NetworkVO networkObject = (NetworkVO) super.design(offering, plan, userSpecified, owner);
+        if (networkObject == null) {
+            return null;
+        }
+        // Override the broadcast domain type - do we need to do this?
+        networkObject.setBroadcastDomainType(Networks.BroadcastDomainType.Mido);
+
+        return networkObject;
+    }
+
+    @Override
+    public Network implement(Network network, NetworkOffering offering,
+                             DeployDestination dest, ReservationContext context)
+            throws InsufficientVirtualNetworkCapcityException {
+        assert (network.getState() == Network.State.Implementing) : "Why are we implementing " + network;
+        s_logger.debug("implement called network: " + network.toString());
+
+        long dcId = dest.getDataCenter().getId();
+
+        //get physical network id
+        long physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType());
+
+        NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), network.getBroadcastDomainType(), network.getNetworkOfferingId(), Network.State.Allocated,
+                network.getDataCenterId(), physicalNetworkId);
+
+        if (network.getGateway() != null) {
+            implemented.setGateway(network.getGateway());
+        }
+
+        if (network.getCidr() != null) {
+            implemented.setCidr(network.getCidr());
+        }
+
+        String accountIdStr = String.valueOf(network.getAccountId());
+        String routerName = "";
+        if (network.getVpcId() != null) {
+            routerName = "VPC" + String.valueOf(network.getVpcId());
+        } else {
+            routerName = String.valueOf(network.getId());
+        }
+
+        String broadcastUriStr = accountIdStr + "." + String.valueOf(network.getId()) + ":" + routerName;
+
+        implemented.setBroadcastUri(Networks.BroadcastDomainType.Mido.toUri(broadcastUriStr));
+        s_logger.debug("Broadcast URI set to " + broadcastUriStr);
+
+        return implemented;
+    }
+
+    @Override
+    public void reserve(NicProfile nic, Network network,
+                        VirtualMachineProfile<? extends VirtualMachine> vm,
+                        DeployDestination dest, ReservationContext context)
+            throws InsufficientVirtualNetworkCapcityException,
+            InsufficientAddressCapacityException {
+        s_logger.debug("reserve called with network: " + network.toString() + " nic: " + nic.toString() + " vm: " + vm.toString());
+
+        super.reserve(nic, network, vm, dest, context);
+    }
+
+    @Override
+    public boolean release(NicProfile nic,
+                           VirtualMachineProfile<? extends VirtualMachine> vm,
+                           String reservationId) {
+        s_logger.debug("release called with nic: " + nic.toString() + " vm: " + vm.toString());
+        return super.release(nic, vm, reservationId);
+    }
+
+    @Override
+    public void shutdown(NetworkProfile profile, NetworkOffering offering) {
+        s_logger.debug("shutdown called");
+
+        super.shutdown(profile, offering);
+    }
+
+    @Override
+    public boolean trash(Network network, NetworkOffering offering,
+                         Account owner) {
+        s_logger.debug("trash called with network: " + network.toString());
+
+        return super.trash(network, offering, owner);
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetPublicNetworkGuru.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetPublicNetworkGuru.java b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetPublicNetworkGuru.java
new file mode 100644
index 0000000..e6869d0
--- /dev/null
+++ b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetPublicNetworkGuru.java
@@ -0,0 +1,223 @@
+package com.cloud.network.guru;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.Vlan;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.deploy.DeploymentPlan;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
+import com.cloud.network.*;
+import com.cloud.network.Network;
+import com.cloud.network.addr.PublicIp;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.user.Account;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.IPAddressVO;
+import com.cloud.vm.*;
+import org.apache.log4j.Logger;
+import java.net.URI;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+
+@Local(value = NetworkGuru.class)
+public class MidoNetPublicNetworkGuru extends PublicNetworkGuru {
+    private static final Logger s_logger = Logger.getLogger(MidoNetPublicNetworkGuru.class);
+
+    // Inject any stuff we need to use (DAOs etc)
+    @Inject
+    NetworkModel _networkModel;
+
+    // Don't need to change traffic type stuff, public is fine
+
+    // Only change is to make broadcast domain type Mido
+    @Override
+    public Network design(NetworkOffering offering, DeploymentPlan plan, Network network, Account owner) {
+        s_logger.debug("design called with network: " + network.toString());
+        if (!canHandle(offering)) {
+            return null;
+        }
+
+        if (offering.getTrafficType() == Networks.TrafficType.Public) {
+            NetworkVO ntwk = new NetworkVO(offering.getTrafficType(), Networks.Mode.Static, Networks.BroadcastDomainType.Mido,
+                    offering.getId(), Network.State.Allocated, plan.getDataCenterId(), plan.getPhysicalNetworkId());
+            return ntwk;
+        } else {
+            return null;
+        }
+    }
+
+    protected MidoNetPublicNetworkGuru() {
+        super();
+    }
+
+    protected void getIp(NicProfile nic, DataCenter dc, VirtualMachineProfile<? extends VirtualMachine> vm, Network network) throws InsufficientVirtualNetworkCapcityException,
+            InsufficientAddressCapacityException, ConcurrentOperationException {
+        if (nic.getIp4Address() == null) {
+            PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), Vlan.VlanType.VirtualNetwork, null, null, false);
+            nic.setIp4Address(ip.getAddress().toString());
+
+            nic.setGateway(ip.getGateway());
+
+            // Set netmask to /24 for now
+            // TDO make it /32 and go via router for anything else on the subnet
+            nic.setNetmask("255.255.255.0");
+
+            // Make it the default nic so that a default route is set up.
+            nic.setDefaultNic(true);
+
+            //nic.setIsolationUri(Networks.IsolationType..Mido.toUri(ip.getVlanTag()));
+            nic.setBroadcastUri(network.getBroadcastUri());
+            //nic.setBroadcastType(Networks.BroadcastDomainType.Vlan);
+            nic.setFormat(Networks.AddressFormat.Ip4);
+            nic.setReservationId(String.valueOf(ip.getVlanTag()));
+            nic.setMacAddress(ip.getMacAddress());
+        }
+
+        nic.setDns1(dc.getDns1());
+        nic.setDns2(dc.getDns2());
+    }
+
+    @Override
+    public void updateNicProfile(NicProfile profile, Network network) {
+        s_logger.debug("updateNicProfile called with network: " + network.toString() + " profile: " + profile.toString());
+
+        DataCenter dc = _dcDao.findById(network.getDataCenterId());
+        if (profile != null) {
+            profile.setDns1(dc.getDns1());
+            profile.setDns2(dc.getDns2());
+        }
+    }
+
+    @Override
+    public NicProfile allocate(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm)
+            throws InsufficientVirtualNetworkCapcityException,
+            InsufficientAddressCapacityException, ConcurrentOperationException {
+
+        s_logger.debug("allocate called with network: " + network.toString() + " nic: " + nic.toString() + " vm: " + vm.toString());
+        DataCenter dc = _dcDao.findById(network.getDataCenterId());
+
+        if (nic != null && nic.getRequestedIpv4() != null) {
+            throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic);
+        }
+
+        if (nic == null) {
+            nic = new NicProfile(Nic.ReservationStrategy.Create, null, null, null, null);
+        }
+
+        getIp(nic, dc, vm, network);
+
+        if (nic.getIp4Address() == null) {
+            nic.setStrategy(Nic.ReservationStrategy.Start);
+        } else if (vm.getVirtualMachine().getType() == VirtualMachine.Type.DomainRouter){
+            nic.setStrategy(Nic.ReservationStrategy.Managed);
+        } else {
+            nic.setStrategy(Nic.ReservationStrategy.Create);
+        }
+
+        nic.setBroadcastUri(generateBroadcastUri(network));
+
+        return nic;
+    }
+
+    @Override
+    public void reserve(NicProfile nic, Network network, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest, ReservationContext context)
+            throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException {
+        s_logger.debug("reserve called with network: " + network.toString() + " nic: " + nic.toString() + " vm: " + vm.toString());
+        if (nic.getIp4Address() == null) {
+            getIp(nic, dest.getDataCenter(), vm, network);
+        }
+    }
+
+    @Override
+    public boolean release(NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, String reservationId) {
+        s_logger.debug("release called with nic: " + nic.toString() + " vm: " + vm.toString());
+        return true;
+    }
+
+    @Override
+    public Network implement(Network network, NetworkOffering offering, DeployDestination destination, ReservationContext context)
+            throws InsufficientVirtualNetworkCapcityException {
+        s_logger.debug("implement called with network: " + network.toString());
+        long dcId = destination.getDataCenter().getId();
+
+        //get physical network id
+        long physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType());
+
+        NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), network.getBroadcastDomainType(), network.getNetworkOfferingId(), Network.State.Allocated,
+                network.getDataCenterId(), physicalNetworkId);
+
+        if (network.getGateway() != null) {
+            implemented.setGateway(network.getGateway());
+        }
+
+        if (network.getCidr() != null) {
+            implemented.setCidr(network.getCidr());
+        }
+
+        implemented.setBroadcastUri(generateBroadcastUri(network));
+
+        return implemented;
+
+    }
+
+    @Override @DB
+    public void deallocate(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm) {
+        s_logger.debug("deallocate called with network: " + network.toString() + " nic: " + nic.toString() + " vm: " + vm.toString());
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("public network deallocate network: networkId: " + nic.getNetworkId() + ", ip: " + nic.getIp4Address());
+        }
+
+        IPAddressVO ip = _ipAddressDao.findByIpAndSourceNetworkId(nic.getNetworkId(), nic.getIp4Address());
+        if (ip != null && nic.getReservationStrategy() != Nic.ReservationStrategy.Managed) {
+
+            Transaction txn = Transaction.currentTxn();
+            txn.start();
+
+            _networkMgr.markIpAsUnavailable(ip.getId());
+            _ipAddressDao.unassignIpAddress(ip.getId());
+
+            txn.commit();
+        }
+        nic.deallocate();
+
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Deallocated nic: " + nic);
+        }
+    }
+
+    @Override
+    public void shutdown(NetworkProfile network, NetworkOffering offering) {
+        s_logger.debug("shutdown called with network: " + network.toString());
+    }
+
+    @Override
+    public boolean trash(Network network, NetworkOffering offering, Account owner) {
+        s_logger.debug("trash called with network: " + network.toString());
+        return true;
+    }
+
+    @Override
+    public void updateNetworkProfile(NetworkProfile networkProfile) {
+        DataCenter dc = _dcDao.findById(networkProfile.getDataCenterId());
+        networkProfile.setDns1(dc.getDns1());
+        networkProfile.setDns2(dc.getDns2());
+    }
+
+    private URI generateBroadcastUri(Network network){
+        String accountIdStr = String.valueOf(network.getAccountId());
+        String networkUUIDStr = String.valueOf(network.getId());
+        return Networks.BroadcastDomainType.Mido.toUri(accountIdStr +
+                                                       "." +
+                                                       networkUUIDStr +
+                                                       ":" +
+                                                       networkUUIDStr);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/plugins/network-elements/midonet/src/com/cloud/network/resource/MidoNetVifDriver.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/midonet/src/com/cloud/network/resource/MidoNetVifDriver.java b/plugins/network-elements/midonet/src/com/cloud/network/resource/MidoNetVifDriver.java
new file mode 100644
index 0000000..3c7c23d
--- /dev/null
+++ b/plugins/network-elements/midonet/src/com/cloud/network/resource/MidoNetVifDriver.java
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+package com.cloud.network.resource;
+
+import com.cloud.hypervisor.kvm.resource.*;
+import com.cloud.agent.api.to.NicTO;
+import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource;
+import com.cloud.exception.InternalErrorException;
+import com.cloud.network.Networks;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.utils.script.OutputInterpreter;
+import com.cloud.utils.script.Script;
+import com.midokura.midonet.client.resource.Bridge;
+import com.midokura.midonet.client.resource.Router;
+import com.midokura.midonet.client.resource.BridgePort;
+import com.midokura.midonet.client.resource.RouterPort;
+import com.midokura.midonet.client.resource.Host;
+import org.apache.log4j.Logger;
+import org.libvirt.LibvirtException;
+
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+import com.midokura.midonet.client.MidonetApi;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import javax.naming.ConfigurationException;
+import javax.ws.rs.core.MultivaluedMap;
+import java.net.URI;
+import java.util.Map;
+import java.util.UUID;
+
+public class MidoNetVifDriver extends VifDriverBase {
+
+    private static final Logger s_logger = Logger
+            .getLogger(MidoNetVifDriver.class);
+    private int _timeout;
+    private String _midoApiLocation = "http://localhost:8081/";
+    private static final String midoPostfix = "mnet";
+
+    @Override
+    public void configure(Map<String, Object> params) throws ConfigurationException {
+
+        super.configure(params);
+
+        String value = (String) params.get("scripts.timeout");
+        _timeout = NumbersUtil.parseInt(value, 30 * 60) * 1000;
+
+        // Load Midonet API server location
+        String midoLoc = (String) params.get("midonet.apiserver.address");
+        if (midoLoc != null) {
+            _midoApiLocation = midoLoc;
+        }
+    }
+
+    /*
+     * Grab our host id in a file written by Midonet, then
+     * return a Host.
+     */
+    private Host getMyHost(MidonetApi api) {
+        Script command = new Script("/bin/bash", _timeout);
+        command.add("-c");
+        command.add("awk -F'=' '{if ($1~/host/) print $2}' /etc/midolman/host_uuid.properties");
+
+        OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser();
+        command.execute(parser);
+        String host_uuid = parser.getLines().split("\\n")[0];
+        for (Host host : api.getHosts()) {
+            if (host.getId().toString().equals(host_uuid)) {
+                return host;
+            }
+        }
+        return null;
+    }
+
+    /*
+     * simple script to add the tap to the host and bring it up.
+     */
+    private String addTap() {
+        OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser();
+        Script command = new Script("/bin/bash", _timeout);
+        command.add("-c");
+        command.add("ip tuntap add mode tap dev '%d" + midoPostfix + "' && ip link | grep " + midoPostfix + " | sort -n | tail -1 | awk -F': ' '{print $2}'");
+        command.execute(parser);
+        String tapName = parser.getLines().split("\\n")[0];
+        command = new Script("/bin/bash", _timeout);
+        command.add("-c");
+        command.add("ip link set " + tapName + " up");
+        command.execute();
+        return tapName;
+    }
+
+    @Override
+    public LibvirtVMDef.InterfaceDef plug(NicTO nic, String guestOsType)
+            throws InternalErrorException, LibvirtException {
+
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("nic=" + nic);
+        }
+
+        LibvirtVMDef.InterfaceDef intf = new LibvirtVMDef.InterfaceDef();
+
+        String trafficLabel = nic.getName();
+
+        if (nic.getBroadcastType() == Networks.BroadcastDomainType.Mido &&
+                (nic.getType() == Networks.TrafficType.Guest || nic.getType() == Networks.TrafficType.Public)){
+            /*
+            * create the tap.
+            */
+            String tapName = addTap();
+
+            /*
+            * grab the tenant id and the network id from the Broadcast URI.
+            * We need to pluck the values out of the String. The string
+            * should look like "mido://[tenant_id].[bridge_name]"
+            */
+            MultivaluedMap qNet = new MultivaluedMapImpl();
+            String nicAuthority= nic.getBroadcastUri().getAuthority();
+            String tenantId = nicAuthority.split("\\.")[0];
+            qNet.add("tenant_id", tenantId);
+            String url = nicAuthority.split("\\.")[1];
+            String netName = url.split(":")[0];
+
+            MidonetApi api = new MidonetApi(_midoApiLocation);
+            api.enableLogging();
+
+            for (Bridge b : api.getBridges(qNet)) {
+                if (b.getName().equals(netName)) {
+                    for (BridgePort p : b.getPorts()) {
+                        UUID pvif = p.getVifId();
+                        if (pvif != null && p.getVifId().toString().equals(nic.getUuid())){
+                            getMyHost(api).addHostInterfacePort()
+                                    .interfaceName(tapName)
+                                    .portId(p.getId())
+                                    .create();
+                            break;
+                        }
+                    }
+                }
+            }
+
+            intf.defEthernet(tapName, nic.getMac(), getGuestNicModel(guestOsType), "");
+
+        } else {
+            throw new InternalErrorException("Only NICs of BroadcastDomain type Mido are supported by the MidoNetVifDriver");
+        }
+
+        return intf;
+    }
+
+    @Override
+    public void unplug(LibvirtVMDef.InterfaceDef iface) {
+        String netName = iface.getBrName();
+
+        if (netName != null && netName.contains(midoPostfix)) {
+            Script command = new Script("/bin/bash", _timeout);
+            command.add("-c");
+            command.add("ip tuntap del " + iface.getBrName() + " mode tap");
+            command.execute();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/plugins/network-elements/midonet/test/com/cloud/network/element/MidoNetElementTest.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/midonet/test/com/cloud/network/element/MidoNetElementTest.java b/plugins/network-elements/midonet/test/com/cloud/network/element/MidoNetElementTest.java
new file mode 100644
index 0000000..aec9c2d
--- /dev/null
+++ b/plugins/network-elements/midonet/test/com/cloud/network/element/MidoNetElementTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+import com.cloud.network.element.MidoNetElement;
+import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.*;
+import com.midokura.midonet.client.MidonetApi;
+import com.midokura.midonet.client.resource.*;
+import com.cloud.network.dao.NetworkServiceMapDao;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+import com.cloud.network.*;
+import com.cloud.vm.*;
+import com.cloud.network.rules.StaticNat;
+import com.cloud.network.element.MidoNetElement;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceUnavailableException;
+import sun.security.util.Resources_es;
+
+import java.util.*;
+
+
+public class MidoNetElementTest extends TestCase {
+
+    /*
+     * Test the standard case of addDhcpEntry with no errors.
+     */
+    public void testAddDhcpEntry() {
+
+        //mockMgmt
+        MidonetApi api = mock(MidonetApi.class, RETURNS_DEEP_STUBS);
+        ArrayList<String> arr = new ArrayList<String>();
+        arr.add("MidoNet");
+        NetworkServiceMapDao mockNSMD = mock(NetworkServiceMapDao.class);
+        when(mockNSMD.getDistinctProviders(anyLong())).thenReturn(arr);
+
+        //mockDhcpHost
+        DhcpHost mockDhcpHost = mock(DhcpHost.class);
+
+        //mockHostCollection
+        ResourceCollection<DhcpHost> hosts =
+                new ResourceCollection<DhcpHost>(new ArrayList<DhcpHost>());
+
+        //mockDhcpSubnet
+        DhcpSubnet mockSub = mock(DhcpSubnet.class);
+        when(mockSub.addDhcpHost()).thenReturn(mockDhcpHost);
+        when(mockSub.getDhcpHosts()).thenReturn(hosts);
+
+        //mockSubnetCollection
+        ResourceCollection mockSubnetCollection = mock(ResourceCollection.class);
+        when(mockSubnetCollection.get(anyInt())).thenReturn(mockSub);
+
+        //mockBridge
+        Bridge mockBridge = mock(Bridge.class);
+        when(api.addBridge().tenantId(anyString()).name(anyString()).create()).thenReturn(mockBridge);
+        when(mockBridge.getDhcpSubnets()).thenReturn(mockSubnetCollection);
+
+        //mockRouter
+        Router mockRouter = mock(Router.class);
+        when(api.addRouter().tenantId(anyString()).name(anyString()).create()).thenReturn(mockRouter);
+
+        //mockNetwork
+        Network mockNetwork = mock(Network.class);
+        when(mockNetwork.getAccountId()).thenReturn((long)1);
+        when(mockNetwork.getGateway()).thenReturn("1.2.3.4");
+        when(mockNetwork.getCidr()).thenReturn("1.2.3.0/24");
+        when(mockNetwork.getId()).thenReturn((long)2);
+
+        //mockNic
+        NicProfile mockNic = mock(NicProfile.class);
+        when(mockNic.getIp4Address()).thenReturn("10.10.10.170");
+        when(mockNic.getMacAddress()).thenReturn("02:00:73:3e:00:01");
+        when(mockNic.getName()).thenReturn("Fake Name");
+
+        //mockVm
+        @SuppressWarnings("unchecked")
+        VirtualMachineProfile<? extends VirtualMachine> mockVm =
+                (VirtualMachineProfile<? extends VirtualMachine>)mock(VirtualMachineProfile.class);
+        when(mockVm.getType()).thenReturn(VirtualMachine.Type.User);
+
+        MidoNetElement elem = new MidoNetElement();
+        elem.setNtwkSrvcDao(mockNSMD);
+        elem.setMidonetApi(api);
+
+        boolean result = false;
+        try {
+            result = elem.addDhcpEntry(mockNetwork, mockNic, mockVm, null, null);
+        } catch (ConcurrentOperationException e) {
+            fail(e.getMessage());
+        } catch (InsufficientCapacityException e) {
+            fail(e.getMessage());
+        } catch (ResourceUnavailableException e) {
+            fail(e.getMessage());
+        }
+
+        assertEquals(result, true);
+    }
+
+    /*
+     * Test the standard case of implement with no errors.
+     */
+    public void testImplement() {
+        //mock
+        MidonetApi api = mock(MidonetApi.class, RETURNS_DEEP_STUBS);
+        ArrayList<String> arr = new ArrayList<String>();
+        arr.add("MidoNet");
+        NetworkServiceMapDao mockNSMD = mock(NetworkServiceMapDao.class);
+        when(mockNSMD.getDistinctProviders(anyLong())).thenReturn(arr);
+
+        MidoNetElement elem = new MidoNetElement();
+        elem.setNtwkSrvcDao(mockNSMD);
+        elem.setMidonetApi(api);
+
+        //mockRPort
+        RouterPort mockRPort = mock(RouterPort.class);
+        when(mockRPort.getId()).thenReturn(UUID.fromString("550e8400-e29b-41d4-a716-446655440000"));
+
+        //mockBPort
+        BridgePort mockBPort = mock(BridgePort.class);
+        when(mockBPort.link(any(UUID.class))).thenReturn(mockBPort);
+
+        //mockPort
+        Port mockPort = mock(Port.class);
+
+        ResourceCollection<Port> peerPorts =
+            new ResourceCollection<Port>(new ArrayList<Port>());
+
+        peerPorts.add(mockPort);
+
+        //mockBridge
+        Bridge mockBridge = mock(Bridge.class, RETURNS_DEEP_STUBS);
+        when(api.addBridge().tenantId(anyString()).name(anyString()).create()).thenReturn(mockBridge);
+        when(mockBridge.addInteriorPort().create()).thenReturn(mockBPort);
+        when(mockBridge.getPeerPorts()).thenReturn(peerPorts);
+
+        //mockRouter
+        Router mockRouter = mock(Router.class, RETURNS_DEEP_STUBS);
+        when(api.addRouter().tenantId(anyString()).name(anyString()).create()).thenReturn(mockRouter);
+        when(mockRouter.addInteriorRouterPort().create()).thenReturn(mockRPort);
+
+        //mockNetwork
+        Network mockNetwork = mock(Network.class);
+        when(mockNetwork.getAccountId()).thenReturn((long)1);
+        when(mockNetwork.getGateway()).thenReturn("1.2.3.4");
+        when(mockNetwork.getCidr()).thenReturn("1.2.3.0/24");
+        when(mockNetwork.getId()).thenReturn((long)2);
+
+        boolean result = false;
+        try {
+            result = elem.implement(mockNetwork, null, null, null);
+        } catch (ConcurrentOperationException e) {
+            fail(e.getMessage());
+        } catch (InsufficientCapacityException e) {
+            fail(e.getMessage());
+        } catch (ResourceUnavailableException e) {
+            fail(e.getMessage());
+        }
+
+        assertEquals(result, true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/plugins/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/pom.xml b/plugins/pom.xml
index 348ffa2..607c50c 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -50,6 +50,7 @@
     <module>network-elements/ovs</module>
     <module>network-elements/nicira-nvp</module>
     <module>network-elements/bigswitch-vns</module>
+    <module>network-elements/midonet</module>
     <module>storage-allocators/random</module>
     <module>user-authenticators/ldap</module>
     <module>user-authenticators/md5</module>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/server/src/com/cloud/configuration/Config.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java
index 8ec5a41..200943b 100755
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -277,6 +277,10 @@ public enum Config {
     VmwareSystemVmNicDeviceType("Advanced", ManagementServer.class, String.class, "vmware.systemvm.nic.device.type", "E1000", "Specify the default network device type for system VMs, valid values are E1000, PCNet32, Vmxnet2, Vmxnet3", null),
     VmwareRecycleHungWorker("Advanced", ManagementServer.class, Boolean.class, "vmware.recycle.hung.wokervm", "false", "Specify whether or not to recycle hung worker VMs", null),
 
+    // Midonet
+    MidoNetAPIServerAddress("Network", ManagementServer.class, String.class, "midonet.apiserver.address", "http://localhost:8081", "Specify the address at which the Midonet API server can be contacted (if using Midonet)", null),
+    MidoNetProviderRouterId("Network", ManagementServer.class, String.class, "midonet.providerrouter.id", "d7c5e6a3-e2f4-426b-b728-b7ce6a0448e5", "Specifies the UUID of the Midonet provider router (if using Midonet)", null),
+
     // KVM
     KvmPublicNetwork("Hidden", ManagementServer.class, String.class, "kvm.public.network.device", null, "Specify the public bridge on host for public network", null),
     KvmPrivateNetwork("Hidden", ManagementServer.class, String.class, "kvm.private.network.device", null, "Specify the private bridge on host for private network", null),

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/server/src/com/cloud/network/NetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java
index c0685ba..a16288f 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -1823,6 +1823,26 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
         NetworkVO network = _networksDao.findById(nic.getNetworkId());
         NicProfile profile = new NicProfile(nic, network, null, null, null,
                 _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network));
+
+        /*
+         * We need to release the nics with a Create ReservationStrategy here
+         * because the nic is now being removed.
+         */
+        if (nic.getReservationStrategy() == Nic.ReservationStrategy.Create) {
+            for (NetworkElement element : _networkElements) {
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Asking " + element.getName() + " to release " + nic);
+                }
+                try {
+                    element.release(network, profile, vm, null);
+                } catch (ConcurrentOperationException ex) {
+                    s_logger.warn("release failed during the nic " +  nic.toString() + " removeNic due to ", ex);
+                } catch (ResourceUnavailableException ex) {
+                    s_logger.warn("release failed during the nic " +  nic.toString() + " removeNic due to ", ex);
+                }
+            }
+        }
+
         NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName());
         guru.deallocate(network, profile, vm);
         _nicDao.remove(nic.getId());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eddf7b93/ui/scripts/system.js
----------------------------------------------------------------------
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index 2fdf5f9..62b4c76 100644
--- a/ui/scripts/system.js
+++ b/ui/scripts/system.js
@@ -4315,6 +4315,110 @@
                 notification: { poll: pollAsyncJobResult }
               }
             }
+          },
+
+
+          // MidoNet provider detailView
+          midoNet: {
+          id: 'midoNet',
+          label: 'label.midoNet',
+          isMaximized: true,
+          type: 'detailView',
+          fields: {
+            name: { label: 'label.name' },
+            //ipaddress: { label: 'label.ip.address' },
+            state: { label: 'label.status', indicator: { 'Enabled': 'on' } }
+          },
+          tabs: {
+            details: {
+              title: 'label.network',
+              fields: [
+                {
+                  name: { label: 'label.name' }
+                },
+                {
+                  id: { label: 'label.id' },
+                  state: { label: 'label.state' },
+                  physicalnetworkid: { label: 'label.physical.network.ID' },
+                  destinationphysicalnetworkid: { label: 'label.destination.physical.network.id' },
+                  supportedServices: { label: 'label.supported.services' }
+                }
+                ],
+                dataProvider: function(args) {
+                  refreshNspData("MidoNet");
+                  args.response.success({
+                    actionFilter: virtualRouterProviderActionFilter,
+                    data: $.extend(nspMap["midoNet"], {
+                      supportedServices: nspMap["midoNet"].servicelist.join(', ')
+                    })
+                  });
+                }
+              },
+            },
+            actions: {
+              enable: {
+                label: 'label.enable.provider',
+                action: function(args) {
+                  $.ajax({
+                    url: createURL("updateNetworkServiceProvider&id=" + nspMap["midoNet"].id + "&state=Enabled"),
+                    dataType: "json",
+                    success: function(json) {
+                      var jid = json.updatenetworkserviceproviderresponse.jobid;
+                      args.response.success(
+                        {_custom:
+                          {
+                            jobId: jid,
+                            getUpdatedItem: function(json) {
+                              $(window).trigger('cloudStack.fullRefresh');
+                            }
+                          }
+                        }
+                      );
+                    }
+                  });
+                },
+                messages: {
+                  confirm: function(args) {
+                    return 'message.confirm.enable.provider';
+                  },
+                  notification: function() {
+                    return 'label.enable.provider';
+                  }
+               },
+               notification: { poll: pollAsyncJobResult }
+             },
+             disable: {
+               label: 'label.disable.provider',
+               action: function(args) {
+               $.ajax({
+                 url: createURL("updateNetworkServiceProvider&id=" + nspMap["midoNet"].id + "&state=Disabled"),
+                 dataType: "json",
+                 success: function(json) {
+                   var jid = json.updatenetworkserviceproviderresponse.jobid;
+                     args.response.success(
+                        {_custom:
+                          {
+                            jobId: jid,
+                            getUpdatedItem: function(json) {
+                              $(window).trigger('cloudStack.fullRefresh');
+                            }
+                          }
+                        }
+                      );
+                    }
+                  });
+                },
+                messages: {
+                  confirm: function(args) {
+                    return 'message.confirm.disable.provider';
+                  },
+                  notification: function() {
+                    return 'label.disable.provider';
+                  }
+                },
+                notification: { poll: pollAsyncJobResult }
+              }
+            }
           }          
         }
       }
@@ -11353,6 +11457,9 @@
 							case "Netscaler":
 								nspMap["netscaler"] = items[i];
 								break;
+                            case "MidoNet":
+                                nspMap["midoNet"] = items[i];
+                                break;
 							case "F5BigIp":
 								nspMap["f5"] = items[i];
 								break;
@@ -11409,6 +11516,13 @@
 		else if(selectedZoneObj.networktype == "Advanced"){
 		  nspHardcodingArray.push(
 				{
+                    id: 'midoNet',
+                    name: 'MidoNet',
+                    state: nspMap.midoNet? nspMap.midoNet.state : 'Disabled'
+                }
+            );
+            nspHardcodingArray.push(
+                {
 					id: 'vpcVirtualRouter',
 					name: 'VPC Virtual Router',
 					state: nspMap.vpcVirtualRouter ? nspMap.vpcVirtualRouter.state : 'Disabled'