You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by bh...@apache.org on 2015/04/09 09:45:38 UTC

[2/8] git commit: updated refs/heads/master to 770297e

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/01864ef7/plugins/network-elements/bigswitch/src/com/cloud/network/resource/BigSwitchBcfResource.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/bigswitch/src/com/cloud/network/resource/BigSwitchBcfResource.java b/plugins/network-elements/bigswitch/src/com/cloud/network/resource/BigSwitchBcfResource.java
new file mode 100644
index 0000000..c5407bc
--- /dev/null
+++ b/plugins/network-elements/bigswitch/src/com/cloud/network/resource/BigSwitchBcfResource.java
@@ -0,0 +1,589 @@
+//
+// 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 java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.IAgentControl;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.UpdateBcfRouterCommand;
+import com.cloud.agent.api.BcfAnswer;
+import com.cloud.agent.api.CacheBcfTopologyCommand;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.CreateBcfRouterCommand;
+import com.cloud.agent.api.CreateBcfRouterInterfaceCommand;
+import com.cloud.agent.api.CreateBcfSegmentCommand;
+import com.cloud.agent.api.CreateBcfAttachmentCommand;
+import com.cloud.agent.api.CreateBcfStaticNatCommand;
+import com.cloud.agent.api.DeleteBcfSegmentCommand;
+import com.cloud.agent.api.DeleteBcfAttachmentCommand;
+import com.cloud.agent.api.DeleteBcfStaticNatCommand;
+import com.cloud.agent.api.GetControllerDataAnswer;
+import com.cloud.agent.api.GetControllerDataCommand;
+import com.cloud.agent.api.MaintainAnswer;
+import com.cloud.agent.api.MaintainCommand;
+import com.cloud.agent.api.PingCommand;
+import com.cloud.agent.api.ReadyAnswer;
+import com.cloud.agent.api.ReadyCommand;
+import com.cloud.agent.api.StartupBigSwitchBcfCommand;
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.SyncBcfTopologyCommand;
+import com.cloud.agent.api.UpdateBcfAttachmentCommand;
+import com.cloud.host.Host;
+import com.cloud.host.Host.Type;
+import com.cloud.network.bigswitch.AclData;
+import com.cloud.network.bigswitch.BigSwitchBcfApi;
+import com.cloud.network.bigswitch.BigSwitchBcfApiException;
+import com.cloud.network.bigswitch.Capabilities;
+import com.cloud.network.bigswitch.ControlClusterStatus;
+import com.cloud.network.bigswitch.ControllerData;
+import com.cloud.network.bigswitch.FloatingIpData;
+import com.cloud.network.bigswitch.NetworkData;
+import com.cloud.network.bigswitch.AttachmentData;
+import com.cloud.network.bigswitch.RouterData;
+import com.cloud.network.bigswitch.RouterInterfaceData;
+import com.cloud.network.bigswitch.TopologyData;
+import com.cloud.resource.ServerResource;
+import com.cloud.utils.component.ManagerBase;
+
+public class BigSwitchBcfResource extends ManagerBase implements ServerResource {
+    private static final Logger s_logger = Logger.getLogger(BigSwitchBcfResource.class);
+
+    private String _name;
+    private String _guid;
+    private String _zoneId;
+    private int _numRetries;
+
+    private BigSwitchBcfApi _bigswitchBcfApi;
+    private TopologyData _latestTopology = null;
+    private boolean initTopologySyncDone = false;
+
+    protected BigSwitchBcfApi createBigSwitchBcfApi() {
+        return new BigSwitchBcfApi();
+    }
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+
+        _name = (String)params.get("name");
+        if (_name == null) {
+            throw new ConfigurationException("Unable to find name");
+        }
+
+        _guid = (String)params.get("guid");
+        if (_guid == null) {
+            throw new ConfigurationException("Unable to find the guid");
+        }
+
+        _zoneId = (String)params.get("zoneId");
+        if (_zoneId == null) {
+            throw new ConfigurationException("Unable to find zone");
+        }
+
+        _numRetries = 2;
+
+        String hostname = (String)params.get("hostname");
+        if (hostname == null) {
+            throw new ConfigurationException("Missing host name from params: " + params);
+        }
+
+        String username = (String) params.get("username");
+        if (username == null) {
+            throw new ConfigurationException("Missing user name from params: " + params);
+        }
+
+        String password = (String) params.get("password");
+        if (password == null) {
+            throw new ConfigurationException("Missing password from params: " + params);
+        }
+
+        Boolean nat = Boolean.parseBoolean((String) params.get("nat"));
+        if (nat == null) {
+            throw new ConfigurationException("Missing password from params: " + params);
+        }
+
+        _bigswitchBcfApi = createBigSwitchBcfApi();
+        _bigswitchBcfApi.setControllerAddress(hostname);
+        _bigswitchBcfApi.setControllerUsername(username);
+        _bigswitchBcfApi.setControllerPassword(password);
+        _bigswitchBcfApi.setControllerNat(nat);
+        _bigswitchBcfApi.setZoneId(_zoneId);
+
+        return true;
+    }
+
+    @Override
+    public boolean start() {
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return _name;
+    }
+
+    @Override
+    public Type getType() {
+        return Host.Type.L2Networking;
+    }
+
+    @Override
+    public StartupCommand[] initialize() {
+        StartupBigSwitchBcfCommand sc = new StartupBigSwitchBcfCommand();
+        sc.setGuid(_guid);
+        sc.setName(_name);
+        sc.setDataCenter(_zoneId);
+        sc.setPod("");
+        sc.setPrivateIpAddress("");
+        sc.setStorageIpAddress("");
+        sc.setVersion("");
+        return new StartupCommand[] {sc};
+    }
+
+    @Override
+    public PingCommand getCurrentStatus(long id) {
+        if(!initTopologySyncDone && _latestTopology != null){
+            initTopologySyncDone = true;
+            if(_bigswitchBcfApi.isNatEnabled()){
+                try{
+                    executeRequest(new SyncBcfTopologyCommand(true, true), _numRetries);
+                } catch(Exception e){
+                    s_logger.error("BigSwitch BCF sync error", e);
+                }
+            } else {
+                try{
+                    executeRequest(new SyncBcfTopologyCommand(true, false), _numRetries);
+                } catch (Exception e){
+                    s_logger.error("BigSwitch BCF sync error", e);
+                }
+            }
+        }
+        try {
+            ControlClusterStatus ccs = _bigswitchBcfApi.getControlClusterStatus();
+            if (!ccs.getStatus()) {
+                s_logger.error("ControlCluster state is not ready: " + ccs.getStatus());
+                return null;
+            }
+            if (ccs.isTopologySyncRequested()) {
+                if(_latestTopology != null) {
+                    if(_bigswitchBcfApi.isNatEnabled()){
+                        executeRequest(new SyncBcfTopologyCommand(true, true), _numRetries);
+                    } else {
+                        executeRequest(new SyncBcfTopologyCommand(true, false), _numRetries);
+                    }
+                } else {
+                    s_logger.debug("topology sync needed but no topology history");
+                }
+            }
+        } catch (BigSwitchBcfApiException e) {
+            s_logger.error("getControlClusterStatus failed", e);
+            return null;
+        }
+        try {
+            Capabilities cap = _bigswitchBcfApi.getCapabilities();
+
+            // TODO: update controller status display, enable/disable service accordingly
+            if (cap.isTopologySyncRequested()) {
+                if(_latestTopology != null) {
+                    if(_bigswitchBcfApi.isNatEnabled()){
+                        executeRequest(new SyncBcfTopologyCommand(true, true), _numRetries);
+                    } else {
+                        executeRequest(new SyncBcfTopologyCommand(true, false), _numRetries);
+                    }
+                }
+            }
+
+        } catch (BigSwitchBcfApiException e) {
+            s_logger.error("getCapabilities failed", e);
+        }
+        return new PingCommand(Host.Type.L2Networking, id);
+    }
+
+    @Override
+    public Answer executeRequest(Command cmd) {
+        return executeRequest(cmd, _numRetries);
+    }
+
+    public Answer executeRequest(Command cmd, int numRetries) {
+        if (cmd instanceof ReadyCommand) {
+            return executeRequest((ReadyCommand)cmd);
+        } else if (cmd instanceof MaintainCommand) {
+            return executeRequest((MaintainCommand)cmd);
+        } else if (cmd instanceof CreateBcfSegmentCommand) {
+            _latestTopology = ((CreateBcfSegmentCommand) cmd).getTopology();
+            return executeRequest((CreateBcfSegmentCommand)cmd, numRetries);
+        } else if (cmd instanceof DeleteBcfSegmentCommand) {
+            _latestTopology = ((DeleteBcfSegmentCommand) cmd).getTopology();
+            return executeRequest((DeleteBcfSegmentCommand)cmd, numRetries);
+        } else if (cmd instanceof CreateBcfAttachmentCommand) {
+            _latestTopology = ((CreateBcfAttachmentCommand) cmd).getTopology();
+            return executeRequest((CreateBcfAttachmentCommand)cmd, numRetries);
+        } else if (cmd instanceof DeleteBcfAttachmentCommand) {
+            _latestTopology = ((DeleteBcfAttachmentCommand) cmd).getTopology();
+            return executeRequest((DeleteBcfAttachmentCommand)cmd, numRetries);
+        } else if (cmd instanceof UpdateBcfAttachmentCommand) {
+            _latestTopology = ((UpdateBcfAttachmentCommand) cmd).getTopology();
+            return executeRequest((UpdateBcfAttachmentCommand)cmd, numRetries);
+        } else if (cmd instanceof CreateBcfRouterCommand) {
+            _latestTopology = ((CreateBcfRouterCommand) cmd).getTopology();
+            return executeRequest((CreateBcfRouterCommand)cmd, numRetries);
+        } else if (cmd instanceof CreateBcfRouterInterfaceCommand) {
+            _latestTopology = ((CreateBcfRouterInterfaceCommand) cmd).getTopology();
+            return executeRequest((CreateBcfRouterInterfaceCommand)cmd, numRetries);
+        } else if (cmd instanceof CreateBcfStaticNatCommand) {
+            _latestTopology = ((CreateBcfStaticNatCommand) cmd).getTopology();
+            return executeRequest((CreateBcfStaticNatCommand)cmd, numRetries);
+        } else if (cmd instanceof DeleteBcfStaticNatCommand) {
+            _latestTopology = ((DeleteBcfStaticNatCommand) cmd).getTopology();
+            return executeRequest((DeleteBcfStaticNatCommand)cmd, numRetries);
+        } else if (cmd instanceof UpdateBcfRouterCommand) {
+            _latestTopology = ((UpdateBcfRouterCommand) cmd).getTopology();
+            return executeRequest((UpdateBcfRouterCommand)cmd, numRetries);
+        } else if (cmd instanceof SyncBcfTopologyCommand) {
+            return executeRequest((SyncBcfTopologyCommand)cmd, numRetries);
+        } else if (cmd instanceof CacheBcfTopologyCommand) {
+            return executeRequest((CacheBcfTopologyCommand)cmd, numRetries);
+        } else if (cmd instanceof GetControllerDataCommand) {
+            return executeRequest((GetControllerDataCommand)cmd, numRetries);
+        }
+        s_logger.debug("Received unsupported command " + cmd.toString());
+        return Answer.createUnsupportedCommandAnswer(cmd);
+    }
+
+    @Override
+    public void disconnected() {
+    }
+
+    @Override
+    public IAgentControl getAgentControl() {
+        return null;
+    }
+
+    @Override
+    public void setAgentControl(IAgentControl agentControl) {
+    }
+
+    public void setTopology(TopologyData topology){
+        _latestTopology = topology;
+    }
+
+    public TopologyData getTopology(){
+        return _latestTopology;
+    }
+
+    private Answer executeRequest(CreateBcfSegmentCommand cmd, int numRetries) {
+        NetworkData network = new NetworkData();
+        network.getNetwork().setTenantId(cmd.getTenantId());
+        network.getNetwork().setTenantName(cmd.getTenantName());
+        network.getNetwork().setId(cmd.getNetworkId());
+        network.getNetwork().setName(truncate("segment-cloudstack-" + cmd.getNetworkName(), 64));
+        network.getNetwork().setVlan(cmd.getVlan());
+
+        try {
+            String hash =_bigswitchBcfApi.createNetwork(network);
+            return new BcfAnswer(cmd, true, "Segment " + network.getNetwork().getId() + " created", hash);
+        } catch (BigSwitchBcfApiException e) {
+            if (e.is_topologySyncRequested()) {
+                cmd.set_topologySyncRequested(true);
+                return new BcfAnswer(cmd, true, "Segment " + network.getNetwork().getId() + " created; topology sync required.");
+            } else {
+                if (numRetries > 0) {
+                    return retry(cmd, --numRetries);
+                } else {
+                    return new BcfAnswer(cmd, e);
+                }
+            }
+        }
+
+    }
+
+    private Answer executeRequest(DeleteBcfSegmentCommand cmd, int numRetries) {
+        try {
+            String hash = _bigswitchBcfApi.deleteNetwork(cmd.get_tenantUuid(), cmd.getNetworkUuid());
+            return new BcfAnswer(cmd, true, "Segment " + cmd.getNetworkUuid() + " deleted", hash);
+        } catch (BigSwitchBcfApiException e) {
+            if (e.is_topologySyncRequested()) {
+                cmd.set_topologySyncRequested(true);
+                return new BcfAnswer(cmd, true, "Segment " + cmd.getNetworkUuid() + " deleted; topology sync required.");
+            } else {
+                if (numRetries > 0) {
+                    return retry(cmd, --numRetries);
+                } else {
+                    return new BcfAnswer(cmd, e);
+                }
+            }
+        }
+    }
+
+    private Answer executeRequest(CreateBcfAttachmentCommand cmd, int numRetries) {
+        AttachmentData attachment = new AttachmentData();
+        attachment.getAttachment().setId(cmd.getNicId());
+        attachment.getAttachment().setHostId(cmd.getPortId());
+        attachment.getAttachment().setTenantName(cmd.getTenantName());
+        attachment.getAttachment().setVlan(cmd.getVlan());
+        attachment.getAttachment().addIpv4(cmd.getIpv4());
+        attachment.getAttachment().setMac(cmd.getMac());
+
+        try {
+            String hash = _bigswitchBcfApi.createAttachment(cmd.getTenantId(), cmd.getNetworkId(), attachment);
+            return new BcfAnswer(cmd, true, "network attachment " + cmd.getPortId() + " created", hash);
+        } catch (BigSwitchBcfApiException e) {
+            if (e.is_topologySyncRequested()) {
+                cmd.set_topologySyncRequested(true);
+                return new BcfAnswer(cmd, true, "network attachment " + cmd.getPortId() + " created; topology sync required.");
+            } else {
+                if (numRetries > 0) {
+                    return retry(cmd, --numRetries);
+                } else {
+                    return new BcfAnswer(cmd, e);
+                }
+            }
+        }
+    }
+
+    private Answer executeRequest(DeleteBcfAttachmentCommand cmd, int numRetries) {
+        String nicName = cmd.getAttachmentId();
+        try {
+            String hash = _bigswitchBcfApi.deleteAttachment(cmd.getTenantId(), cmd.getNetworkId(), nicName);
+            return new BcfAnswer(cmd, true, "network attachment " + nicName + " deleted", hash);
+        } catch (BigSwitchBcfApiException e) {
+            if (e.is_topologySyncRequested()) {
+                cmd.set_topologySyncRequested(true);
+                return new BcfAnswer(cmd, true, "network attachment " + nicName + " deleted; topology sync required.");
+            } else {
+                if (numRetries > 0) {
+                    return retry(cmd, --numRetries);
+                } else {
+                    return new BcfAnswer(cmd, e);
+                }
+            }
+        }
+    }
+
+    private Answer executeRequest(UpdateBcfAttachmentCommand cmd, int numRetries) {
+        AttachmentData attachment = new AttachmentData();
+        attachment.getAttachment().setId(cmd.getAttachmentId());
+        attachment.getAttachment().setTenantName(cmd.getTenantId());
+
+        try {
+            String hash = _bigswitchBcfApi.modifyAttachment(cmd.getTenantId(), cmd.getNetworkId(), attachment);
+            return new BcfAnswer(cmd, true, "Network attachment  " + cmd.getAttachmentId() + " updated", hash);
+        } catch (BigSwitchBcfApiException e) {
+            if (e.is_topologySyncRequested()) {
+                cmd.set_topologySyncRequested(true);
+                return new BcfAnswer(cmd, true, "Network attachment  " + cmd.getAttachmentId() + " updated; topology sync required.");
+            } else {
+                if (numRetries > 0) {
+                    return retry(cmd, --numRetries);
+                } else {
+                    return new BcfAnswer(cmd, e);
+                }
+            }
+        }
+    }
+
+    private Answer executeRequest(CreateBcfStaticNatCommand cmd, int numRetries) {
+        FloatingIpData fip = new FloatingIpData();
+        fip.setTenantId(cmd.get_tenantId());
+        fip.setNetworkId(cmd.get_networkId());
+        fip.setFixedIp(cmd.get_privateIp());
+        fip.setFloatingIpAndId(cmd.get_publicIp());
+        fip.setMac(cmd.get_mac());
+
+        try {
+            String hash = _bigswitchBcfApi.createFloatingIp(cmd.get_tenantId(), fip);
+            return new BcfAnswer(cmd, true, "floating ip " + cmd.get_publicIp() + ":" +
+                    cmd.get_privateIp() + " created", hash);
+        } catch (BigSwitchBcfApiException e) {
+            if (e.is_topologySyncRequested()) {
+                cmd.set_topologySyncRequested(true);
+                return new BcfAnswer(cmd, true, "floating ip " + cmd.get_publicIp() + ":" +
+                        cmd.get_privateIp() + " created; topology sync required.");
+            } else {
+                if (numRetries > 0) {
+                    return retry(cmd, --numRetries);
+                } else {
+                    return new BcfAnswer(cmd, e);
+                }
+            }
+        }
+    }
+
+    private Answer executeRequest(DeleteBcfStaticNatCommand cmd, int numRetries) {
+        try {
+            String hash = _bigswitchBcfApi.deleteFloatingIp(cmd.get_tenantId(), cmd.get_floatingIpId());
+            return new BcfAnswer(cmd, true, "floating ip " + cmd.get_publicIp() + " deleted", hash);
+        } catch (BigSwitchBcfApiException e) {
+            if (e.is_topologySyncRequested()) {
+                cmd.set_topologySyncRequested(true);
+                return new BcfAnswer(cmd, true, "floating ip " + cmd.get_publicIp() + " deleted; topology sync required.");
+            } else {
+                if (numRetries > 0) {
+                    return retry(cmd, --numRetries);
+                } else {
+                    return new BcfAnswer(cmd, e);
+                }
+            }
+        }
+    }
+
+    private Answer executeRequest(CreateBcfRouterCommand cmd, int numRetries) {
+        RouterData router = new RouterData(cmd.get_tenantId());
+        try {
+            String hash;
+            hash = _bigswitchBcfApi.createRouter(cmd.get_tenantId(), router);
+
+            return new BcfAnswer(cmd, true, "router " + cmd.get_tenantId() +
+                    " created.", hash);
+        } catch (BigSwitchBcfApiException e) {
+            if (e.is_topologySyncRequested()) {
+                cmd.set_topologySyncRequested(true);
+                return new BcfAnswer(cmd, true, " created; topology sync required.");
+            } else {
+                if (numRetries > 0) {
+                    return retry(cmd, --numRetries);
+                } else {
+                    return new BcfAnswer(cmd, e);
+                }
+            }
+        }
+    }
+
+    private Answer executeRequest(CreateBcfRouterInterfaceCommand cmd, int numRetries) {
+        RouterInterfaceData routerInterface = new RouterInterfaceData(cmd.get_tenantId(),
+                cmd.get_gateway(), cmd.get_cidr(), cmd.get_networkId(), cmd.get_networkName());
+        try {
+            String hash;
+            hash = _bigswitchBcfApi.createRouterInterface(cmd.get_tenantId(),
+                    cmd.get_tenantId(), routerInterface);
+
+            return new BcfAnswer(cmd, true, "router " + cmd.get_tenantId() +
+                    " created.", hash);
+        } catch (BigSwitchBcfApiException e) {
+            if (e.is_topologySyncRequested()) {
+                cmd.set_topologySyncRequested(true);
+                return new BcfAnswer(cmd, true, " created; topology sync required.");
+            } else {
+                if (numRetries > 0) {
+                    return retry(cmd, --numRetries);
+                } else {
+                    return new BcfAnswer(cmd, e);
+                }
+            }
+        }
+    }
+
+    private Answer executeRequest(UpdateBcfRouterCommand cmd, int numRetries){
+        RouterData routerData = new RouterData(cmd.getTenantId());
+
+        List<AclData> acls = new ArrayList<AclData>();
+        acls.addAll(cmd.getAcls());
+        routerData.getRouter().getAcls().addAll(acls);
+
+        routerData.getRouter().addExternalGateway(cmd.getPublicIp());
+
+        try {
+            String hash = _bigswitchBcfApi.modifyRouter(cmd.getTenantId(), routerData);
+            return new BcfAnswer(cmd, true, "tenant " + cmd.getTenantId() + " router updated", hash);
+        } catch (BigSwitchBcfApiException e) {
+            if (e.is_topologySyncRequested()) {
+                cmd.set_topologySyncRequested(true);
+                return new BcfAnswer(cmd, true, "tenant " + cmd.getTenantId() + " router updated but topology sync required.");
+            } else {
+                if (numRetries > 0) {
+                    return retry(cmd, --numRetries);
+                } else {
+                    return new BcfAnswer(cmd, e);
+                }
+            }
+        } catch (IllegalArgumentException e1){
+            return new BcfAnswer(cmd, false, "Illegal argument in BCF router update");
+        }
+    }
+
+    private Answer executeRequest(SyncBcfTopologyCommand cmd, int numRetries) {
+        try {
+            TopologyData topo = _latestTopology;
+            if (!cmd.isNetworkIncluded()) {
+                topo.clearNetworks();
+            }
+            if(!cmd.isRouterIncluded()) {
+                topo.clearRouters();
+            }
+            String hash = _bigswitchBcfApi.syncTopology(topo);
+            if(!initTopologySyncDone){
+                initTopologySyncDone=true;
+            }
+            return new BcfAnswer(cmd, true, "BCF topology synced", hash);
+        } catch (BigSwitchBcfApiException e) {
+            if (numRetries > 0) {
+                return retry(cmd, --numRetries);
+            } else {
+                return new BcfAnswer(cmd, e);
+            }
+        } catch (IllegalArgumentException e1){
+            return new BcfAnswer(cmd, false, "Illegal argument in BCF topology sync");
+        }
+    }
+
+    private Answer executeRequest(CacheBcfTopologyCommand cmd, int numRetries) {
+        _latestTopology = cmd.getTopology();
+        return new Answer(cmd, true, "BCF topology cached");
+    }
+
+    private Answer executeRequest(GetControllerDataCommand cmd, int numRetries) {
+        ControllerData controller = _bigswitchBcfApi.getControllerData();
+        return new GetControllerDataAnswer(cmd,
+                controller.getIpAddress(),
+                controller.isMaster());
+    }
+
+    private Answer executeRequest(ReadyCommand cmd) {
+        return new ReadyAnswer(cmd);
+    }
+
+    private Answer executeRequest(MaintainCommand cmd) {
+        return new MaintainAnswer(cmd);
+    }
+
+    private Answer retry(Command cmd, int numRetries) {
+        s_logger.warn("Retrying " + cmd.getClass().getSimpleName() + ". Number of retries remaining: " + numRetries);
+        return executeRequest(cmd, numRetries);
+    }
+
+    private String truncate(String string, int length) {
+        if (string.length() <= length) {
+            return string;
+        } else {
+            return string.substring(0, length);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/01864ef7/plugins/network-elements/bigswitch/test/com/cloud/network/bigswitch/BigSwitchApiTest.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/bigswitch/test/com/cloud/network/bigswitch/BigSwitchApiTest.java b/plugins/network-elements/bigswitch/test/com/cloud/network/bigswitch/BigSwitchApiTest.java
new file mode 100644
index 0000000..5d40e5d
--- /dev/null
+++ b/plugins/network-elements/bigswitch/test/com/cloud/network/bigswitch/BigSwitchApiTest.java
@@ -0,0 +1,433 @@
+//
+// 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.bigswitch;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.UUID;
+
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpMethodBase;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.commons.httpclient.params.HttpClientParams;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.gson.reflect.TypeToken;
+
+public class BigSwitchApiTest {
+    BigSwitchBcfApi _api;
+    HttpClient _client = mock(HttpClient.class);
+    HttpMethod _method;
+
+    @Before
+    public void setUp() {
+        HttpClientParams hmp = mock(HttpClientParams.class);
+        when(_client.getParams()).thenReturn(hmp);
+        _api = new BigSwitchBcfApi(){
+            @Override
+            protected HttpClient createHttpClient() {
+                return _client;
+            }
+
+            @Override
+            protected HttpMethod createMethod(String type, String uri, int port) {
+                return _method;
+            }
+        };
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword("mypassword");
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteUpdateObjectWithoutHostname() throws BigSwitchBcfApiException {
+        _api.setControllerAddress(null);
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword("mypassword");
+        _api.executeUpdateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteUpdateObjectWithEmptyHostname() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("");
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword("mypassword");
+        _api.executeUpdateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteUpdateObjectWithoutUsername() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername(null);
+        _api.setControllerPassword("mypassword");
+        _api.executeUpdateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteUpdateObjectWithEmptyUsername() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername("");
+        _api.setControllerPassword("mypassword");
+        _api.executeUpdateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteUpdateObjectWithoutPassword() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword(null);
+        _api.executeUpdateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteUpdateObjectWithEmptyPassword() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword("");
+        _api.executeUpdateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteCreateObjectWithoutHostname() throws BigSwitchBcfApiException {
+        _api.setControllerAddress(null);
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword("mypassword");
+        _api.executeCreateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteCreateObjectWithEmptyHostname() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("");
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword("mypassword");
+        _api.executeCreateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteCreateObjectWithoutUsername() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername(null);
+        _api.setControllerPassword("mypassword");
+        _api.executeCreateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteCreateObjectWithEmptyUsername() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername("");
+        _api.setControllerPassword("mypassword");
+        _api.executeCreateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteCreateObjectWithoutPassword() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword(null);
+        _api.executeCreateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteCreateObjectWithEmptyPassword() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword("");
+        _api.executeCreateObject(new String(), "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteDeleteObjectWithoutHostname() throws BigSwitchBcfApiException {
+        _api.setControllerAddress(null);
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword("mypassword");
+        _api.executeDeleteObject("/");
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteDeleteObjectWithEmptyHostname() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("");
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword("mypassword");
+        _api.executeDeleteObject("/");
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteDeleteObjectWithoutUsername() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername(null);
+        _api.setControllerPassword("mypassword");
+        _api.executeDeleteObject("/");
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteDeleteObjectWithEmptyUsername() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername("");
+        _api.setControllerPassword("mypassword");
+        _api.executeDeleteObject("/");
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteDeleteObjectWithoutPassword() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword(null);
+        _api.executeDeleteObject("/");
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteDeleteObjectWithEmptyPassword() throws BigSwitchBcfApiException {
+        _api.setControllerAddress("10.10.0.10");
+        _api.setControllerUsername("myname");
+        _api.setControllerPassword("");
+        _api.executeDeleteObject("/");
+    }
+
+    @Test
+    public void executeMethodTestOK() throws BigSwitchBcfApiException, HttpException, IOException {
+        GetMethod gm = mock(GetMethod.class);
+        when(gm.getStatusCode()).thenReturn(HttpStatus.SC_OK);
+        _api.executeMethod(gm);
+        verify(gm, times(1)).getStatusCode();
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void executeMethodTestUnauthorized() throws BigSwitchBcfApiException, IOException {
+        GetMethod gm = mock(GetMethod.class);
+        when(_client.executeMethod((HttpMethod)any())).thenThrow(new HttpException());
+        when(gm.getStatusCode()).thenReturn(HttpStatus.SC_UNAUTHORIZED);
+        _api.executeMethod(gm);
+    }
+
+    @Test
+    public void testExecuteCreateObjectOK() throws BigSwitchBcfApiException, IOException {
+        NetworkData network = new NetworkData();
+        _method = mock(PostMethod.class);
+        when(_method.getResponseHeader("X-BSN-BVS-HASH-MATCH")).thenReturn(new Header("X-BSN-BVS-HASH-MATCH", UUID.randomUUID().toString()));
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
+        String hash = _api.executeCreateObject(network, "/", Collections.<String, String> emptyMap());
+        verify(_method, times(1)).releaseConnection();
+        verify(_client, times(1)).executeMethod(_method);assertNotEquals(hash, "");
+        assertNotEquals(hash, BigSwitchBcfApi.HASH_CONFLICT);
+        assertNotEquals(hash, BigSwitchBcfApi.HASH_IGNORE);
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteCreateObjectConflict() throws BigSwitchBcfApiException, IOException {
+        NetworkData network = new NetworkData();
+        _method = mock(PostMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_CONFLICT);
+        _api.executeCreateObject(network, "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test
+    public void testExecuteCreateObjectSlave() throws BigSwitchBcfApiException, IOException {
+        NetworkData network = new NetworkData();
+        _method = mock(PostMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_SEE_OTHER);
+        String hash = _api.executeCreateObject(network, "/", Collections.<String, String> emptyMap());
+        assertEquals(hash, BigSwitchBcfApi.HASH_IGNORE);
+        assertEquals(_api.getControllerData().isMaster(), false);
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteCreateObjectFailure() throws BigSwitchBcfApiException, IOException {
+        NetworkData network = new NetworkData();
+        _method = mock(PostMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR);
+        Header header = mock(Header.class);
+        when(header.getValue()).thenReturn("text/html");
+        when(_method.getResponseHeader("Content-type")).thenReturn(header);
+        when(_method.getResponseBodyAsString()).thenReturn("Off to timbuktu, won't be back later.");
+        when(_method.isRequestSent()).thenReturn(true);
+        try {
+            _api.executeCreateObject(network, "/", Collections.<String, String> emptyMap());
+        } finally {
+            verify(_method, times(1)).releaseConnection();
+        }
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteCreateObjectException() throws BigSwitchBcfApiException, IOException {
+        NetworkData network = new NetworkData();
+        when(_client.executeMethod((HttpMethod)any())).thenThrow(new HttpException());
+        _method = mock(PostMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR);
+        Header header = mock(Header.class);
+        when(header.getValue()).thenReturn("text/html");
+        when(_method.getResponseHeader("Content-type")).thenReturn(header);
+        when(_method.getResponseBodyAsString()).thenReturn("Off to timbuktu, won't be back later.");
+        try {
+            _api.executeCreateObject(network, "/", Collections.<String, String> emptyMap());
+        } finally {
+            verify(_method, times(1)).releaseConnection();
+        }
+    }
+
+    @Test
+    public void testExecuteUpdateObjectOK() throws BigSwitchBcfApiException, IOException {
+        NetworkData network = new NetworkData();
+        _method = mock(PutMethod.class);
+        when(_method.getResponseHeader("X-BSN-BVS-HASH-MATCH")).thenReturn(new Header("X-BSN-BVS-HASH-MATCH", UUID.randomUUID().toString()));
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
+        String hash = _api.executeUpdateObject(network, "/", Collections.<String, String> emptyMap());
+        verify(_method, times(1)).releaseConnection();
+        verify(_client, times(1)).executeMethod(_method);
+        assertNotEquals(hash, "");
+        assertNotEquals(hash, BigSwitchBcfApi.HASH_CONFLICT);
+        assertNotEquals(hash, BigSwitchBcfApi.HASH_IGNORE);
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteUpdateObjectConflict() throws BigSwitchBcfApiException, IOException {
+        NetworkData network = new NetworkData();
+        _method = mock(PutMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_CONFLICT);
+        _api.executeUpdateObject(network, "/", Collections.<String, String> emptyMap());
+    }
+
+    @Test
+    public void testExecuteUpdateObjectSlave() throws BigSwitchBcfApiException, IOException {
+        NetworkData network = new NetworkData();
+        _method = mock(PutMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_SEE_OTHER);
+        String hash = _api.executeUpdateObject(network, "/", Collections.<String, String> emptyMap());
+        assertEquals(hash, BigSwitchBcfApi.HASH_IGNORE);
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteUpdateObjectFailure() throws BigSwitchBcfApiException, IOException {
+        NetworkData network = new NetworkData();
+        _method = mock(PutMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR);
+        Header header = mock(Header.class);
+        when(header.getValue()).thenReturn("text/html");
+        when(_method.getResponseHeader("Content-type")).thenReturn(header);
+        when(_method.getResponseBodyAsString()).thenReturn("Off to timbuktu, won't be back later.");
+        when(_method.isRequestSent()).thenReturn(true);
+        try {
+            _api.executeUpdateObject(network, "/", Collections.<String, String> emptyMap());
+        } finally {
+            verify(_method, times(1)).releaseConnection();
+        }
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteUpdateObjectException() throws BigSwitchBcfApiException, IOException {
+        NetworkData network = new NetworkData();
+        _method = mock(PutMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
+        when(_client.executeMethod((HttpMethod)any())).thenThrow(new IOException());
+        try {
+            _api.executeUpdateObject(network, "/", Collections.<String, String> emptyMap());
+        } finally {
+            verify(_method, times(1)).releaseConnection();
+        }
+    }
+
+    @Test
+    public void testExecuteDeleteObject() throws BigSwitchBcfApiException, IOException {
+        _method = mock(DeleteMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
+        _api.executeDeleteObject("/");
+        verify(_method, times(1)).releaseConnection();
+        verify(_client, times(1)).executeMethod(_method);
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteDeleteObjectFailure() throws BigSwitchBcfApiException, IOException {
+        _method = mock(DeleteMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR);
+        Header header = mock(Header.class);
+        when(header.getValue()).thenReturn("text/html");
+        when(_method.getResponseHeader("Content-type")).thenReturn(header);
+        when(_method.getResponseBodyAsString()).thenReturn("Off to timbuktu, won't be back later.");
+        when(_method.isRequestSent()).thenReturn(true);
+        try {
+            _api.executeDeleteObject("/");
+        } finally {
+            verify(_method, times(1)).releaseConnection();
+        }
+    }
+
+    @Test(expected = BigSwitchBcfApiException.class)
+    public void testExecuteDeleteObjectException() throws BigSwitchBcfApiException, IOException {
+        _method = mock(DeleteMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
+        when(_client.executeMethod((HttpMethod)any())).thenThrow(new HttpException());
+        try {
+            _api.executeDeleteObject("/");
+        } finally {
+            verify(_method, times(1)).releaseConnection();
+        }
+    }
+
+    @Test
+    public void testExecuteRetrieveControllerMasterStatus() throws BigSwitchBcfApiException, IOException {
+        _method = mock(GetMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
+        when(((HttpMethodBase)_method).getResponseBodyAsString(2048)).thenReturn("{'healthy': true, 'topologySyncRequested': false}");
+        _api.executeRetrieveObject(new TypeToken<ControlClusterStatus>() {
+        }.getType(), "/", null);
+        verify(_method, times(1)).releaseConnection();
+        verify(_client, times(1)).executeMethod(_method);
+        assertEquals(_api.getControllerData().isMaster(), true);
+    }
+
+    @Test
+    public void testExecuteRetrieveControllerMasterStatusWithTopoConflict() throws BigSwitchBcfApiException, IOException {
+        _method = mock(GetMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_CONFLICT);
+        when(((HttpMethodBase)_method).getResponseBodyAsString(2048)).thenReturn("{'healthy': true, 'topologySyncRequested': true}");
+        _api.executeRetrieveObject(new TypeToken<ControlClusterStatus>() {
+        }.getType(), "/", null);
+        verify(_method, times(1)).releaseConnection();
+        verify(_client, times(1)).executeMethod(_method);
+        assertEquals(_api.getControllerData().isMaster(), true);
+    }
+
+    @Test
+    public void testExecuteRetrieveControllerSlaveStatus() throws BigSwitchBcfApiException, IOException {
+        _method = mock(GetMethod.class);
+        when(_method.getStatusCode()).thenReturn(HttpStatus.SC_SEE_OTHER);
+        when(((HttpMethodBase)_method).getResponseBodyAsString(1024)).thenReturn("{'healthy': true, 'topologySyncRequested': false}");
+        _api.executeRetrieveObject(new TypeToken<ControlClusterStatus>() {
+        }.getType(), "/", null);
+        verify(_method, times(1)).releaseConnection();
+        verify(_client, times(1)).executeMethod(_method);
+        assertEquals(_api.getControllerData().isMaster(), false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/01864ef7/plugins/network-elements/bigswitch/test/com/cloud/network/resource/BigSwitchBcfResourceTest.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/bigswitch/test/com/cloud/network/resource/BigSwitchBcfResourceTest.java b/plugins/network-elements/bigswitch/test/com/cloud/network/resource/BigSwitchBcfResourceTest.java
new file mode 100644
index 0000000..005e2f6
--- /dev/null
+++ b/plugins/network-elements/bigswitch/test/com/cloud/network/resource/BigSwitchBcfResourceTest.java
@@ -0,0 +1,431 @@
+//
+// 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.naming.ConfigurationException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.cloud.agent.api.BcfAnswer;
+import com.cloud.agent.api.CreateBcfRouterCommand;
+import com.cloud.agent.api.CreateBcfSegmentCommand;
+import com.cloud.agent.api.CreateBcfAttachmentCommand;
+import com.cloud.agent.api.CreateBcfStaticNatCommand;
+import com.cloud.agent.api.DeleteBcfSegmentCommand;
+import com.cloud.agent.api.DeleteBcfAttachmentCommand;
+import com.cloud.agent.api.DeleteBcfStaticNatCommand;
+import com.cloud.agent.api.PingCommand;
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.SyncBcfTopologyCommand;
+import com.cloud.agent.api.UpdateBcfAttachmentCommand;
+import com.cloud.agent.api.UpdateBcfRouterCommand;
+import com.cloud.host.Host;
+import com.cloud.network.bigswitch.BigSwitchBcfApi;
+import com.cloud.network.bigswitch.BigSwitchBcfApiException;
+import com.cloud.network.bigswitch.Capabilities;
+import com.cloud.network.bigswitch.ControlClusterStatus;
+import com.cloud.network.bigswitch.FloatingIpData;
+import com.cloud.network.bigswitch.NetworkData;
+import com.cloud.network.bigswitch.AttachmentData;
+import com.cloud.network.bigswitch.RouterData;
+import com.cloud.network.bigswitch.TopologyData;
+
+public class BigSwitchBcfResourceTest {
+    BigSwitchBcfApi _bigswitchBcfApi = mock(BigSwitchBcfApi.class);
+    BigSwitchBcfResource _resource;
+    Map<String, Object> _parameters;
+
+    String bcfAddress = "127.0.0.1";
+    String bcfUserName = "myname";
+    String bcfPassword = "mypassword";
+
+    @Before
+    public void setUp() throws ConfigurationException {
+        _resource = new BigSwitchBcfResource() {
+            @Override
+            protected BigSwitchBcfApi createBigSwitchBcfApi() {
+                return _bigswitchBcfApi;
+            }
+        };
+
+        _parameters = new HashMap<String, Object>();
+        _parameters.put("name", "bigswitchbcftestdevice");
+        _parameters.put("hostname", bcfAddress);
+        _parameters.put("guid", "aaaaa-bbbbb-ccccc");
+        _parameters.put("zoneId", "blublub");
+        _parameters.put("username", bcfUserName);
+        _parameters.put("password", bcfPassword);
+    }
+
+    @Test(expected = ConfigurationException.class)
+    public void resourceConfigureFailure() throws ConfigurationException {
+        _resource.configure("BigSwitchBcfResource", Collections.<String, Object> emptyMap());
+    }
+
+    @Test
+    public void resourceConfigure() throws ConfigurationException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        verify(_bigswitchBcfApi).setControllerAddress(bcfAddress);
+        verify(_bigswitchBcfApi).setControllerUsername(bcfUserName);
+        verify(_bigswitchBcfApi).setControllerPassword(bcfPassword);
+
+        assertTrue("bigswitchbcftestdevice".equals(_resource.getName()));
+
+        /* Pretty lame test, but here to assure this plugin fails
+         * if the type name ever changes from L2Networking
+         */
+        assertTrue(_resource.getType() == Host.Type.L2Networking);
+    }
+
+    @Test
+    public void testInitialization() throws ConfigurationException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        StartupCommand[] sc = _resource.initialize();
+        assertTrue(sc.length == 1);
+        assertTrue("aaaaa-bbbbb-ccccc".equals(sc[0].getGuid()));
+        assertTrue("bigswitchbcftestdevice".equals(sc[0].getName()));
+        assertTrue("blublub".equals(sc[0].getDataCenter()));
+    }
+
+    @Test
+    public void testPingCommandStatusOk() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        ControlClusterStatus ccs = mock(ControlClusterStatus.class);
+        when(ccs.getStatus()).thenReturn(true);
+        when(_bigswitchBcfApi.getControlClusterStatus()).thenReturn(ccs);
+
+        Capabilities cap = mock(Capabilities.class);
+        when(_bigswitchBcfApi.getCapabilities()).thenReturn(cap);
+
+        PingCommand ping = _resource.getCurrentStatus(42);
+        assertTrue(ping != null);
+        assertTrue(ping.getHostId() == 42);
+        assertTrue(ping.getHostType() == Host.Type.L2Networking);
+    }
+
+    @Test
+    public void testPingCommandStatusFail() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        ControlClusterStatus ccs = mock(ControlClusterStatus.class);
+        when(ccs.getStatus()).thenReturn(false);
+        when(_bigswitchBcfApi.getControlClusterStatus()).thenReturn(ccs);
+
+        PingCommand ping = _resource.getCurrentStatus(42);
+        assertTrue(ping == null);
+    }
+
+    @Test
+    public void testPingCommandStatusApiException() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        ControlClusterStatus ccs = mock(ControlClusterStatus.class);
+        when(ccs.getStatus()).thenReturn(false);
+        when(_bigswitchBcfApi.getControlClusterStatus()).thenThrow(new BigSwitchBcfApiException());
+
+        PingCommand ping = _resource.getCurrentStatus(42);
+        assertTrue(ping == null);
+    }
+
+    @Test
+    public void testCreateNetworkRetryOnce() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        NetworkData networkdata = mock(NetworkData.class);
+        NetworkData.Network network = mock(NetworkData.Network.class);
+        when(networkdata.getNetwork()).thenReturn(network);
+        when(network.getId()).thenReturn("cccc");
+        when(_bigswitchBcfApi.createNetwork((NetworkData)any())).thenThrow(new BigSwitchBcfApiException())
+        .thenReturn(UUID.randomUUID().toString());
+
+        CreateBcfSegmentCommand cmd = new CreateBcfSegmentCommand("tenantid", "tenantname",
+                (String)_parameters.get("guid"), "networkName", 0);
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertTrue(ans.getResult());
+    }
+
+    @Test
+    public void testCreateNetworkApiException() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        NetworkData networkdata = mock(NetworkData.class);
+        NetworkData.Network network = mock(NetworkData.Network.class);
+        when(networkdata.getNetwork()).thenReturn(network);
+        when(network.getId()).thenReturn("cccc");
+        doThrow(new BigSwitchBcfApiException()).when(_bigswitchBcfApi).createNetwork((NetworkData)any());
+
+        CreateBcfSegmentCommand cmd = new CreateBcfSegmentCommand("tenantid", "tenantname",
+                (String)_parameters.get("guid"), "networkName", 0);
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertFalse(ans.getResult());
+        verify(_bigswitchBcfApi, times(3)).createNetwork((NetworkData)any());
+    }
+
+    @Test
+    public void testDeleteNetworkRetryOnce() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+        when(_bigswitchBcfApi.deleteNetwork((String)any(), (String)any())).thenThrow(new BigSwitchBcfApiException())
+        .thenReturn(UUID.randomUUID().toString());
+
+        DeleteBcfSegmentCommand cmd = new DeleteBcfSegmentCommand("tenantid", "networkid");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertTrue(ans.getResult());
+    }
+
+    @Test
+    public void testDeleteNetworkApiException() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        doThrow(new BigSwitchBcfApiException()).when(_bigswitchBcfApi).deleteNetwork((String)any(), (String)any());
+
+        DeleteBcfSegmentCommand cmd = new DeleteBcfSegmentCommand("tenantid", "networkid");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertFalse(ans.getResult());
+        verify(_bigswitchBcfApi, times(3)).deleteNetwork((String)any(), (String)any());
+    }
+
+    @Test
+    public void testCreateAttachmentRetryOnce() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        AttachmentData attachmentData = mock(AttachmentData.class);
+        AttachmentData.Attachment attachment = mock(AttachmentData.Attachment.class);
+        when(attachmentData.getAttachment()).thenReturn(attachment);
+        when(attachment.getId()).thenReturn("eeee");
+        when(_bigswitchBcfApi.createAttachment((String)any(), (String)any(), (AttachmentData)any())).thenThrow(new BigSwitchBcfApiException())
+        .thenReturn(UUID.randomUUID().toString());
+
+        CreateBcfAttachmentCommand cmd = new CreateBcfAttachmentCommand("tenantid", "tenantname",
+                "networkid", "portid", "nicId", 100, "1.2.3.4", "aa:bb:cc:dd:ee:ff");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertTrue(ans.getResult());
+    }
+
+    @Test
+    public void testCreateAttachmentApiException() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        AttachmentData attachmentData = mock(AttachmentData.class);
+        AttachmentData.Attachment attachment = mock(AttachmentData.Attachment.class);
+        when(attachmentData.getAttachment()).thenReturn(attachment);
+        when(attachment.getId()).thenReturn("eeee");
+        doThrow(new BigSwitchBcfApiException()).when(_bigswitchBcfApi).createAttachment((String)any(), (String)any(), (AttachmentData)any());
+
+        CreateBcfAttachmentCommand cmd = new CreateBcfAttachmentCommand("tenantid", "tenantname",
+                "networkid", "portid", "nicId", 100, "1.2.3.4", "aa:bb:cc:dd:ee:ff");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertFalse(ans.getResult());
+        verify(_bigswitchBcfApi, times(3)).createAttachment((String)any(), (String)any(), (AttachmentData)any());
+    }
+
+    @Test
+    public void testDeleteAttachmentRetryOnce() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        when(_bigswitchBcfApi.deleteAttachment((String)any(), (String)any(), (String)any())).thenThrow(new BigSwitchBcfApiException())
+        .thenReturn(UUID.randomUUID().toString());
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(new DeleteBcfAttachmentCommand("networkId", "portid", "tenantid"));
+        assertTrue(ans.getResult());
+    }
+
+    @Test
+    public void testDeleteAttachmentException() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        doThrow(new BigSwitchBcfApiException()).when(_bigswitchBcfApi).deleteAttachment((String)any(), (String)any(), (String)any());
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(new DeleteBcfAttachmentCommand("networkId", "portid", "tenantid"));
+        assertFalse(ans.getResult());
+        verify(_bigswitchBcfApi, times(3)).deleteAttachment((String)any(), (String)any(), (String)any());
+    }
+
+    @Test
+    public void testUpdateAttachmentRetryOnce() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        when(_bigswitchBcfApi.modifyAttachment((String)any(), (String)any(), (AttachmentData)any())).thenThrow(new BigSwitchBcfApiException())
+        .thenReturn(UUID.randomUUID().toString());
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(new UpdateBcfAttachmentCommand("networkId", "portId", "tenantId", "portname"));
+        assertTrue(ans.getResult());
+    }
+
+    @Test
+    public void testUpdateAttachmentException() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        doThrow(new BigSwitchBcfApiException()).when(_bigswitchBcfApi).modifyAttachment((String)any(), (String)any(), (AttachmentData)any());
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(new UpdateBcfAttachmentCommand("networkId", "portId", "tenantId", "portname"));
+        assertFalse(ans.getResult());
+        verify(_bigswitchBcfApi, times(3)).modifyAttachment((String)any(), (String)any(), (AttachmentData)any());
+    }
+
+    @Test
+    public void testCreateStaticNatRetryOnce() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        when(_bigswitchBcfApi.createFloatingIp((String)any(), (FloatingIpData)any())).thenThrow(new BigSwitchBcfApiException())
+        .thenReturn(UUID.randomUUID().toString());
+
+        CreateBcfStaticNatCommand cmd = new CreateBcfStaticNatCommand("tenantid",
+                "networkid", "192.168.0.10", "10.4.4.100", "90:b1:1c:49:d8:56");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertTrue(ans.getResult());
+    }
+
+    @Test
+    public void testCreateStaticNatApiException() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        doThrow(new BigSwitchBcfApiException()).when(_bigswitchBcfApi).createFloatingIp((String)any(), (FloatingIpData)any());
+
+        CreateBcfStaticNatCommand cmd = new CreateBcfStaticNatCommand("tenantid",
+                "networkid", "192.168.0.10", "10.4.4.100", "90:b1:1c:49:d8:56");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertFalse(ans.getResult());
+        verify(_bigswitchBcfApi, times(3)).createFloatingIp((String)any(), (FloatingIpData)any());
+    }
+
+    @Test
+    public void testDeleteStaticNatRetryOnce() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        when(_bigswitchBcfApi.deleteFloatingIp((String)any(), (String)any())).thenThrow(new BigSwitchBcfApiException())
+        .thenReturn(UUID.randomUUID().toString());
+
+        DeleteBcfStaticNatCommand cmd = new DeleteBcfStaticNatCommand("tenantid",
+                "10.4.4.100");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertTrue(ans.getResult());
+    }
+
+    @Test
+    public void testDeleteStaticNatApiException() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        doThrow(new BigSwitchBcfApiException()).when(_bigswitchBcfApi).deleteFloatingIp((String)any(), (String)any());
+
+        DeleteBcfStaticNatCommand cmd = new DeleteBcfStaticNatCommand("tenantid",
+                "10.4.4.100");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertFalse(ans.getResult());
+        verify(_bigswitchBcfApi, times(3)).deleteFloatingIp((String)any(), (String)any());
+    }
+
+    @Test
+    public void testCreateRouterRetryOnce() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        when(_bigswitchBcfApi.createRouter((String)any(), (RouterData)any())).thenThrow(new BigSwitchBcfApiException())
+        .thenReturn(UUID.randomUUID().toString());
+
+        CreateBcfRouterCommand cmd = new CreateBcfRouterCommand("tenantid");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertTrue(ans.getResult());
+    }
+
+    @Test
+    public void testCreateRouterApiException() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        doThrow(new BigSwitchBcfApiException()).when(_bigswitchBcfApi).createRouter((String)any(), (RouterData)any());
+
+        CreateBcfRouterCommand cmd = new CreateBcfRouterCommand("tenantid");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertFalse(ans.getResult());
+        verify(_bigswitchBcfApi, times(3)).createRouter((String)any(), (RouterData)any());
+    }
+
+    @Test
+    public void testCreateSourceNatRetryOnce() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        when(_bigswitchBcfApi.modifyRouter((String)any(), (RouterData)any())).thenThrow(new BigSwitchBcfApiException())
+        .thenReturn(UUID.randomUUID().toString());
+
+        UpdateBcfRouterCommand cmd = new UpdateBcfRouterCommand("tenantid");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertTrue(ans.getResult());
+    }
+
+    @Test
+    public void testCreateSourceNatApiException() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        doThrow(new BigSwitchBcfApiException()).when(_bigswitchBcfApi).modifyRouter((String)any(), (RouterData)any());
+
+        UpdateBcfRouterCommand cmd = new UpdateBcfRouterCommand("tenantid");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertFalse(ans.getResult());
+        verify(_bigswitchBcfApi, times(3)).modifyRouter((String)any(), (RouterData)any());
+    }
+
+    @Test
+    public void testDeleteSourceNatRetryOnce() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        when(_bigswitchBcfApi.modifyRouter((String)any(), (RouterData)any())).thenThrow(new BigSwitchBcfApiException())
+        .thenReturn(UUID.randomUUID().toString());
+
+        UpdateBcfRouterCommand cmd = new UpdateBcfRouterCommand("tenantid");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertTrue(ans.getResult());
+    }
+
+    @Test
+    public void testDeleteSourceNatApiException() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+
+        doThrow(new BigSwitchBcfApiException()).when(_bigswitchBcfApi).modifyRouter((String)any(), (RouterData)any());
+
+        UpdateBcfRouterCommand cmd = new UpdateBcfRouterCommand("tenantid");
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(cmd);
+        assertFalse(ans.getResult());
+        verify(_bigswitchBcfApi, times(3)).modifyRouter((String)any(), (RouterData)any());
+    }
+
+    @Test
+    public void testSyncTopologyRetryOnce() throws ConfigurationException, BigSwitchBcfApiException {
+        _resource.configure("BigSwitchBcfResource", _parameters);
+        _resource.setTopology(new TopologyData());
+
+        when(_bigswitchBcfApi.syncTopology((TopologyData)any())).thenThrow(new BigSwitchBcfApiException())
+        .thenReturn(UUID.randomUUID().toString());
+        BcfAnswer ans = (BcfAnswer)_resource.executeRequest(new SyncBcfTopologyCommand(true, false));
+        assertTrue(ans.getResult());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/01864ef7/plugins/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/pom.xml b/plugins/pom.xml
index ccda955..a547e1e 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -65,7 +65,7 @@
     <module>network-elements/palo-alto</module>
     <module>network-elements/netscaler</module>
     <module>network-elements/nicira-nvp</module>
-    <module>network-elements/bigswitch-vns</module>
+    <module>network-elements/bigswitch</module>
     <module>network-elements/brocade-vcs</module>
     <module>network-elements/midonet</module>
     <module>network-elements/stratosphere-ssp</module>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/01864ef7/scripts/util/qemu-ivs-ifup
----------------------------------------------------------------------
diff --git a/scripts/util/qemu-ivs-ifup b/scripts/util/qemu-ivs-ifup
new file mode 100755
index 0000000..6830d23
--- /dev/null
+++ b/scripts/util/qemu-ivs-ifup
@@ -0,0 +1,20 @@
+#!/bin/bash
+# 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.
+
+/sbin/ifconfig $1 0.0.0.0 up
+/usr/sbin/ivs-ctl add-port $1

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/01864ef7/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index 65d9a21..ef4c19a 100644
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -2401,7 +2401,7 @@ public class ApiResponseHelper implements ResponseGenerator {
         for (Network.Provider serviceProvider : serviceProviders) {
             // return only Virtual Router/JuniperSRX/CiscoVnmc as a provider for the firewall
             if (service == Service.Firewall
-                    && !(serviceProvider == Provider.VirtualRouter || serviceProvider == Provider.JuniperSRX || serviceProvider == Provider.CiscoVnmc || serviceProvider == Provider.PaloAlto || serviceProvider == Provider.NuageVsp)) {
+                    && !(serviceProvider == Provider.VirtualRouter || serviceProvider == Provider.JuniperSRX || serviceProvider == Provider.CiscoVnmc || serviceProvider == Provider.PaloAlto || serviceProvider == Provider.NuageVsp || serviceProvider == Provider.BigSwitchBcf)) {
                 continue;
             }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/01864ef7/server/src/com/cloud/network/rules/RulesManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java
index 39e0c1b..1ec531a 100644
--- a/server/src/com/cloud/network/rules/RulesManagerImpl.java
+++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java
@@ -1406,7 +1406,14 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
             throw new InvalidParameterValueException("Vm ip is not set as dnat ip for this public ip");
         }
 
-        StaticNatImpl staticNat = new StaticNatImpl(sourceIp.getAllocatedToAccountId(), sourceIp.getAllocatedInDomainId(), networkId, sourceIp.getId(), dstIp, forRevoke);
+        String srcMac = null;
+        try {
+            srcMac = _networkModel.getNextAvailableMacAddressInNetwork(networkId);
+        } catch (InsufficientAddressCapacityException e) {
+            throw new CloudRuntimeException("Insufficient MAC address for static NAT instantiation.");
+        }
+
+        StaticNatImpl staticNat = new StaticNatImpl(sourceIp.getAllocatedToAccountId(), sourceIp.getAllocatedInDomainId(), networkId, sourceIp.getId(), dstIp, srcMac, forRevoke);
         staticNats.add(staticNat);
         return staticNats;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/01864ef7/server/src/com/cloud/network/rules/StaticNatImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/rules/StaticNatImpl.java b/server/src/com/cloud/network/rules/StaticNatImpl.java
index 49e9b78..f07b45e 100644
--- a/server/src/com/cloud/network/rules/StaticNatImpl.java
+++ b/server/src/com/cloud/network/rules/StaticNatImpl.java
@@ -22,6 +22,7 @@ public class StaticNatImpl implements StaticNat {
     long networkId;
     long sourceIpAddressId;
     String destIpAddress;
+    String sourceMacAddress;
     boolean forRevoke;
 
     public StaticNatImpl(long accountId, long domainId, long networkId, long sourceIpAddressId, String destIpAddress, boolean forRevoke) {
@@ -31,6 +32,18 @@ public class StaticNatImpl implements StaticNat {
         this.networkId = networkId;
         this.sourceIpAddressId = sourceIpAddressId;
         this.destIpAddress = destIpAddress;
+        this.sourceMacAddress = null;
+        this.forRevoke = forRevoke;
+    }
+
+    public StaticNatImpl(long accountId, long domainId, long networkId, long sourceIpAddressId, String destIpAddress, String sourceMacAddress, boolean forRevoke) {
+        super();
+        this.accountId = accountId;
+        this.domainId = domainId;
+        this.networkId = networkId;
+        this.sourceIpAddressId = sourceIpAddressId;
+        this.destIpAddress = destIpAddress;
+        this.sourceMacAddress = sourceMacAddress;
         this.forRevoke = forRevoke;
     }
 
@@ -60,6 +73,11 @@ public class StaticNatImpl implements StaticNat {
     }
 
     @Override
+    public String getSourceMacAddress() {
+        return sourceMacAddress;
+    }
+
+    @Override
     public boolean isForRevoke() {
         return forRevoke;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/01864ef7/server/src/com/cloud/network/vpc/VpcManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java
index abd779b..2a07895 100644
--- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java
@@ -224,7 +224,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
     private final List<Service> nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall);
     private final List<Provider> supportedProviders = Arrays.asList(Provider.VPCVirtualRouter,
             Provider.NiciraNvp, Provider.InternalLbVm, Provider.Netscaler, Provider.JuniperContrailVpcRouter,
-            Provider.Ovs, Provider.NuageVsp);
+            Provider.Ovs, Provider.NuageVsp, Provider.BigSwitchBcf);
 
     int _cleanupInterval;
     int _maxNetworks;
@@ -2431,4 +2431,4 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
         final StaticRoute route = _staticRouteDao.findById(routeId);
         return applyStaticRoutesForVpc(route.getVpcId());
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/01864ef7/setup/db/create-schema.sql
----------------------------------------------------------------------
diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql
index b4786c0..7665aec 100755
--- a/setup/db/create-schema.sql
+++ b/setup/db/create-schema.sql
@@ -150,6 +150,7 @@ DROP TABLE IF EXISTS `cloud`.`nicira_nvp_nic_map`;
 DROP TABLE IF EXISTS `cloud`.`s3`;
 DROP TABLE IF EXISTS `cloud`.`template_s3_ref`;
 DROP TABLE IF EXISTS `cloud`.`nicira_nvp_router_map`;
+DROP TABLE IF EXISTS `cloud`.`external_bigswitch_bcf_devices`;
 DROP TABLE IF EXISTS `cloud`.`external_bigswitch_vns_devices`;
 DROP TABLE IF EXISTS `cloud`.`autoscale_vmgroup_policy_map`;
 DROP TABLE IF EXISTS `cloud`.`autoscale_vmgroup_vm_map`;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/01864ef7/setup/db/db/schema-442to450.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-442to450.sql b/setup/db/db/schema-442to450.sql
index 4a8f250..5dee6c6 100644
--- a/setup/db/db/schema-442to450.sql
+++ b/setup/db/db/schema-442to450.sql
@@ -284,6 +284,24 @@ CREATE TABLE `cloud`.`brocade_network_vlan_map` (
    CONSTRAINT `fk_brocade_network_vlan_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`) ON DELETE CASCADE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
+DROP TABLE IF EXISTS `cloud`.`external_bigswitch_vns_devices`;
+CREATE TABLE `cloud`.`external_bigswitch_bcf_devices` (
+  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `uuid` varchar(255) UNIQUE,
+  `physical_network_id` bigint unsigned NOT NULL COMMENT 'id of the physical network in to which bigswitch bcf device is added',
+  `provider_name` varchar(255) NOT NULL COMMENT 'Service Provider name corresponding to this bigswitch bcf device',
+  `device_name` varchar(255) NOT NULL COMMENT 'name of the bigswitch bcf device',
+  `host_id` bigint unsigned NOT NULL COMMENT 'host id coresponding to the external bigswitch bcf device',
+  `hostname` varchar(255) NOT NULL COMMENT 'host name or IP address for the bigswitch bcf device',
+  `username` varchar(255) NOT NULL COMMENT 'username for the bigswitch bcf device',
+  `password` varchar(255) NOT NULL COMMENT 'password for the bigswitch bcf device',
+  `nat` boolean NOT NULL COMMENT 'NAT support for the bigswitch bcf device',
+  `hash` varchar(255) NOT NULL COMMENT 'topology hash for the bigswitch bcf networks',
+  PRIMARY KEY  (`id`),
+  CONSTRAINT `fk_external_bigswitch_bcf_devices__host_id` FOREIGN KEY (`host_id`) REFERENCES `host`(`id`) ON DELETE CASCADE,
+  CONSTRAINT `fk_external_bigswitch_bcf_devices__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
 /* As part of the separation of Xen and XenServer, update the column for the network labels */
 ALTER TABLE `cloud`.`physical_network_traffic_types` CHANGE `xen_network_label` `xenserver_network_label` varchar(255) COMMENT 'The network name label of the physical device dedicated to this traffic on a XenServer host';