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

[16/50] [abbrv] MidoNet Networking Plugin

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'