diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index c539066bdaa..d3c29e93028 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -398,6 +398,8 @@ public class EventTypes {
public static final String EVENT_EXTERNAL_NVP_CONTROLLER_ADD = "PHYSICAL.NVPCONTROLLER.ADD";
public static final String EVENT_EXTERNAL_NVP_CONTROLLER_DELETE = "PHYSICAL.NVPCONTROLLER.DELETE";
public static final String EVENT_EXTERNAL_NVP_CONTROLLER_CONFIGURE = "PHYSICAL.NVPCONTROLLER.CONFIGURE";
+ public static final String EVENT_EXTERNAL_OVS_CONTROLLER_ADD = "PHYSICAL.OVSCONTROLLER.ADD";
+ public static final String EVENT_EXTERNAL_OVS_CONTROLLER_DELETE = "PHYSICAL.OVSCONTROLLER.DELETE";
// AutoScale
public static final String EVENT_COUNTER_CREATE = "COUNTER.CREATE";
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index efdff12b0c6..0cde5bad113 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -409,6 +409,10 @@ public class ApiConstants {
public static final String VSWITCH_TYPE_PUBLIC_TRAFFIC = "publicvswitchtype";
public static final String VSWITCH_NAME_GUEST_TRAFFIC = "guestvswitchname";
public static final String VSWITCH_NAME_PUBLIC_TRAFFIC = "publicvswitchname";
+ // Ovs controller
+ public static final String OVS_DEVICE_ID = "ovsdeviceid";
+ public static final String OVS_DEVICE_NAME = "ovsdevicename";
+
public static final String EXTERNAL_SWITCH_MGMT_DEVICE_ID = "vsmdeviceid";
public static final String EXTERNAL_SWITCH_MGMT_DEVICE_NAME = "vsmdevicename";
public static final String EXTERNAL_SWITCH_MGMT_DEVICE_STATE = "vsmdevicestate";
diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in
new file mode 100644
index 00000000000..1f3571c990b
--- /dev/null
+++ b/client/tomcatconf/applicationContext.xml.in
@@ -0,0 +1,941 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.cloudstack.framework
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index 10afdcc7e63..da4c03fc71c 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -591,6 +591,12 @@ addBigSwitchVnsDevice=1
deleteBigSwitchVnsDevice=1
listBigSwitchVnsDevices=1
+#### ovs commands
+
+addOvsDevice=1
+deleteOvsDevice=1
+listOvsDevices=1
+
#### host simulator commands
configureSimulator=1
diff --git a/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml b/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml
index 9180eebd040..e60d93e08a1 100644
--- a/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml
+++ b/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml
@@ -36,5 +36,7 @@
+
+
diff --git a/plugins/network-elements/ovs/src/com/cloud/api/response/OvsDeviceResponse.java b/plugins/network-elements/ovs/src/com/cloud/api/response/OvsDeviceResponse.java
new file mode 100644
index 00000000000..c0901b224e1
--- /dev/null
+++ b/plugins/network-elements/ovs/src/com/cloud/api/response/OvsDeviceResponse.java
@@ -0,0 +1,65 @@
+// 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.api.response;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
+
+import com.cloud.network.ovs.dao.OvsDeviceVO;
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+@EntityReference(value = OvsDeviceVO.class)
+public class OvsDeviceResponse extends BaseResponse {
+
+ @SerializedName(ApiConstants.OVS_DEVICE_ID)
+ @Param(description = "device id of the Ovs")
+ private String id;
+
+ @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID)
+ @Param(description = "the physical network to which this device belongs to")
+ private String physicalNetworkId;
+
+ @SerializedName(ApiConstants.OVS_DEVICE_NAME)
+ @Param(description = "device name")
+ private String deviceName;
+
+ @SerializedName(ApiConstants.HOST_NAME)
+ @Param(description = "the controller Ip address")
+ private String hostName;
+
+ public String getId() {
+ return this.id;
+ }
+
+ public void setId(String vnsDeviceId) {
+ this.id = vnsDeviceId;
+ }
+
+ public void setPhysicalNetworkId(String physicalNetworkId) {
+ this.physicalNetworkId = physicalNetworkId;
+ }
+
+ public void setDeviceName(String deviceName) {
+ this.deviceName = deviceName;
+ }
+
+ public void setHostName(String hostName) {
+ this.hostName = hostName;
+ }
+}
diff --git a/plugins/network-elements/ovs/src/com/cloud/network/commands/AddOvsDeviceCmd.java b/plugins/network-elements/ovs/src/com/cloud/network/commands/AddOvsDeviceCmd.java
new file mode 100644
index 00000000000..1abc32475d5
--- /dev/null
+++ b/plugins/network-elements/ovs/src/com/cloud/network/commands/AddOvsDeviceCmd.java
@@ -0,0 +1,116 @@
+// 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.commands;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
+
+import com.cloud.api.response.OvsDeviceResponse;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.element.OvsElementService;
+import com.cloud.network.ovs.dao.OvsDeviceVO;
+import com.cloud.user.UserContext;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "addDevice", responseObject = OvsDeviceResponse.class, description = "Adds a Ovs controller device")
+public class AddOvsDeviceCmd extends BaseAsyncCmd {
+ private static final String s_name = "adddeviceresponse";
+ @Inject
+ OvsElementService _ovsElementService;
+
+ // ///////////////////////////////////////////////////
+ // ////////////// API parameters /////////////////////
+ // ///////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.PHYSICAL_NETWORK_ID, type = CommandType.UUID, entityType = PhysicalNetworkResponse.class, required = true, description = "the Physical Network ID")
+ private Long physicalNetworkId;
+
+ @Parameter(name = ApiConstants.HOST_NAME, type = CommandType.STRING, required = true, description = "Hostname of ip address of the BigSwitch VNS Controller.")
+ private String host;
+
+ // ///////////////////////////////////////////////////
+ // ///////////////// Accessors ///////////////////////
+ // ///////////////////////////////////////////////////
+
+ public Long getPhysicalNetworkId() {
+ return physicalNetworkId;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ // ///////////////////////////////////////////////////
+ // ///////////// API Implementation///////////////////
+ // ///////////////////////////////////////////////////
+ @Override
+ public void execute() throws ResourceUnavailableException,
+ InsufficientCapacityException, ServerApiException,
+ ConcurrentOperationException, ResourceAllocationException,
+ NetworkRuleConflictException {
+ try {
+ OvsDeviceVO ovsDeviceVO = _ovsElementService.addOvsDevice(this);
+ if (ovsDeviceVO != null) {
+ OvsDeviceResponse response = _ovsElementService
+ .createOvsDeviceResponse(ovsDeviceVO);
+ response.setObjectName("ovsdevice");
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+ } catch (InvalidParameterValueException invalidParamExcp) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
+ invalidParamExcp.getMessage());
+ } catch (CloudRuntimeException runtimeExcp) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
+ runtimeExcp.getMessage());
+ }
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_EXTERNAL_OVS_CONTROLLER_ADD;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "Adding an Ovs Controller";
+ }
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return UserContext.current().getCaller().getId();
+ }
+
+}
diff --git a/plugins/network-elements/ovs/src/com/cloud/network/commands/DeleteOvsDeviceCmd.java b/plugins/network-elements/ovs/src/com/cloud/network/commands/DeleteOvsDeviceCmd.java
new file mode 100644
index 00000000000..87eedfb6a1a
--- /dev/null
+++ b/plugins/network-elements/ovs/src/com/cloud/network/commands/DeleteOvsDeviceCmd.java
@@ -0,0 +1,110 @@
+// 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.commands;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+
+import com.cloud.api.response.OvsDeviceResponse;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.element.OvsElementService;
+import com.cloud.user.UserContext;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "deleteOvsDevice", responseObject = SuccessResponse.class, description = " delete a ovs device")
+public class DeleteOvsDeviceCmd extends BaseAsyncCmd {
+ private static final String s_name = "deleteovsdeviceresponse";
+ @Inject
+ OvsElementService _ovsElementService;
+
+ // ///////////////////////////////////////////////////
+ // ////////////// API parameters /////////////////////
+ // ///////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.OVS_DEVICE_ID, type = CommandType.UUID, entityType = OvsDeviceResponse.class, required = true, description = "Ovs device ID")
+ private Long ovsDeviceId;
+
+ // ///////////////////////////////////////////////////
+ // ///////////////// Accessors ///////////////////////
+ // ///////////////////////////////////////////////////
+
+ public Long getOvsDeviceId() {
+ return ovsDeviceId;
+ }
+
+ // ///////////////////////////////////////////////////
+ // ///////////// API Implementation///////////////////
+ // ///////////////////////////////////////////////////
+ @Override
+ public void execute() throws ResourceUnavailableException,
+ InsufficientCapacityException, ServerApiException,
+ ConcurrentOperationException, ResourceAllocationException,
+ NetworkRuleConflictException {
+ try {
+ boolean result = _ovsElementService.deleteOvsDevice(this);
+ if (result) {
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
+ "Failed to delete Ovs device.");
+ }
+
+ } catch (InvalidParameterValueException invalidParamExcp) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
+ invalidParamExcp.getMessage());
+ } catch (CloudRuntimeException runtimeExcp) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
+ runtimeExcp.getMessage());
+ }
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_EXTERNAL_OVS_CONTROLLER_DELETE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "Deleting Ovs Controller";
+ }
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return UserContext.current().getCaller().getId();
+ }
+
+}
diff --git a/plugins/network-elements/ovs/src/com/cloud/network/commands/ListOvsDevicesCmd.java b/plugins/network-elements/ovs/src/com/cloud/network/commands/ListOvsDevicesCmd.java
new file mode 100644
index 00000000000..2adb33af482
--- /dev/null
+++ b/plugins/network-elements/ovs/src/com/cloud/network/commands/ListOvsDevicesCmd.java
@@ -0,0 +1,114 @@
+// 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.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
+import org.apache.log4j.Logger;
+
+import com.cloud.api.response.OvsDeviceResponse;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.element.OvsElementService;
+import com.cloud.network.ovs.dao.OvsDeviceVO;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "listOvsDevices", responseObject = OvsDeviceResponse.class, description = "Lists Ovs devices")
+public class ListOvsDevicesCmd extends BaseListCmd {
+ public static final Logger s_logger = Logger
+ .getLogger(ListOvsDevicesCmd.class.getName());
+ private static final String s_name = "listovsdeviceresponse";
+ @Inject
+ OvsElementService _ovsElementService;
+
+ // ///////////////////////////////////////////////////
+ // ////////////// API parameters /////////////////////
+ // ///////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.PHYSICAL_NETWORK_ID, type = CommandType.UUID, entityType = PhysicalNetworkResponse.class, description = "the Physical Network ID")
+ private Long physicalNetworkId;
+
+ @Parameter(name = ApiConstants.OVS_DEVICE_ID, type = CommandType.UUID, entityType = OvsDeviceResponse.class, description = "ovs device ID")
+ private Long ovsDeviceId;
+
+ // ///////////////////////////////////////////////////
+ // ///////////////// Accessors ///////////////////////
+ // ///////////////////////////////////////////////////
+
+ public Long getOvsDeviceId() {
+ return ovsDeviceId;
+ }
+
+ public Long getPhysicalNetworkId() {
+ return physicalNetworkId;
+ }
+
+ // ///////////////////////////////////////////////////
+ // ///////////// API Implementation///////////////////
+ // ///////////////////////////////////////////////////
+ @Override
+ public void execute() throws ResourceUnavailableException,
+ InsufficientCapacityException, ServerApiException,
+ ConcurrentOperationException, ResourceAllocationException,
+ NetworkRuleConflictException {
+ try {
+ List ovsDevices = _ovsElementService
+ .listOvsDevices(this);
+ ListResponse response = new ListResponse();
+ List ovsDevicesResponse = new ArrayList();
+
+ if (ovsDevices != null && !ovsDevices.isEmpty()) {
+ for (OvsDeviceVO ovsDeviceVO : ovsDevices) {
+ OvsDeviceResponse ovsDeviceResponse = _ovsElementService
+ .createOvsDeviceResponse(ovsDeviceVO);
+ ovsDevicesResponse.add(ovsDeviceResponse);
+ }
+ }
+
+ response.setResponses(ovsDevicesResponse);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ } catch (InvalidParameterValueException invalidParamExcp) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
+ invalidParamExcp.getMessage());
+ } catch (CloudRuntimeException runtimeExcp) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
+ runtimeExcp.getMessage());
+ }
+ }
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+}
diff --git a/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java b/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java
index 18b7a90829f..0ec54e35657 100644
--- a/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java
+++ b/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java
@@ -16,12 +16,14 @@
// under the License.
package com.cloud.network.element;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ejb.Local;
import javax.inject.Inject;
+import com.cloud.api.response.OvsDeviceResponse;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
@@ -32,9 +34,14 @@ import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
import com.cloud.network.Networks;
import com.cloud.network.PhysicalNetworkServiceProvider;
+import com.cloud.network.commands.AddOvsDeviceCmd;
+import com.cloud.network.commands.DeleteOvsDeviceCmd;
+import com.cloud.network.commands.ListOvsDevicesCmd;
import com.cloud.network.ovs.OvsTunnelManager;
+import com.cloud.network.ovs.dao.OvsDeviceVO;
import com.cloud.offering.NetworkOffering;
import com.cloud.utils.component.AdapterBase;
+import com.cloud.utils.db.DB;
import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.VirtualMachineProfile;
diff --git a/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElementService.java b/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElementService.java
new file mode 100644
index 00000000000..b55fe6b6c92
--- /dev/null
+++ b/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElementService.java
@@ -0,0 +1,22 @@
+package com.cloud.network.element;
+
+import java.util.List;
+
+import com.cloud.api.response.OvsDeviceResponse;
+import com.cloud.network.commands.AddOvsDeviceCmd;
+import com.cloud.network.commands.DeleteOvsDeviceCmd;
+import com.cloud.network.commands.ListOvsDevicesCmd;
+import com.cloud.network.ovs.dao.OvsDeviceVO;
+import com.cloud.utils.component.PluggableService;
+
+public interface OvsElementService extends PluggableService {
+
+ public OvsDeviceVO addOvsDevice(AddOvsDeviceCmd cmd);
+
+ public OvsDeviceResponse createOvsDeviceResponse(OvsDeviceVO ovsDeviceVO);
+
+ public boolean deleteOvsDevice(DeleteOvsDeviceCmd cmd);
+
+ public List listOvsDevices(ListOvsDevicesCmd cmd);
+
+}
diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsApi.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsApi.java
new file mode 100644
index 00000000000..b5333122edc
--- /dev/null
+++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsApi.java
@@ -0,0 +1,78 @@
+// 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.ovs;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.cookie.CookiePolicy;
+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.log4j.Logger;
+
+public class OvsApi {
+ private static final Logger s_logger = Logger.getLogger(OvsApi.class);
+ private final static String _protocol = "http";
+ private final static MultiThreadedHttpConnectionManager s_httpClientManager = new MultiThreadedHttpConnectionManager();
+
+ private String _host;
+
+ private final HttpClient _client;
+
+ protected HttpClient createHttpClient() {
+ return new HttpClient(s_httpClientManager);
+ }
+
+ protected HttpMethod createMethod(String type, String uri, int port)
+ throws OvsApiException {
+ String url;
+ try {
+ url = new URL(_protocol, _host, port, uri).toString();
+ } catch (MalformedURLException e) {
+ s_logger.error("Unable to build Ovs API URL", e);
+ throw new OvsApiException("Unable to Ovs API URL", e);
+ }
+
+ if ("post".equalsIgnoreCase(type)) {
+ return new PostMethod(url);
+ } else if ("get".equalsIgnoreCase(type)) {
+ return new GetMethod(url);
+ } else if ("delete".equalsIgnoreCase(type)) {
+ return new DeleteMethod(url);
+ } else if ("put".equalsIgnoreCase(type)) {
+ return new PutMethod(url);
+ } else {
+ throw new OvsApiException("Requesting unknown method type");
+ }
+ }
+
+ public OvsApi() {
+ _client = createHttpClient();
+ _client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
+ }
+
+ public void setControllerAddress(String address) {
+ this._host = address;
+ }
+
+ // TODO: implement requests
+}
diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsApiException.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsApiException.java
new file mode 100644
index 00000000000..20603e01eff
--- /dev/null
+++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsApiException.java
@@ -0,0 +1,35 @@
+// 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.ovs;
+
+public class OvsApiException extends Exception {
+
+ public OvsApiException() {
+ }
+
+ public OvsApiException(String message) {
+ super(message);
+ }
+
+ public OvsApiException(Throwable cause) {
+ super(cause);
+ }
+
+ public OvsApiException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/StartupOvsCommand.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/StartupOvsCommand.java
new file mode 100644
index 00000000000..b85331ef70e
--- /dev/null
+++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/StartupOvsCommand.java
@@ -0,0 +1,27 @@
+// 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.ovs;
+
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.host.Host;
+
+public class StartupOvsCommand extends StartupCommand {
+
+ public StartupOvsCommand() {
+ super(Host.Type.L2Networking);
+ }
+}
diff --git a/plugins/network-elements/ovs/src/com/cloud/network/resource/OvsResource.java b/plugins/network-elements/ovs/src/com/cloud/network/resource/OvsResource.java
new file mode 100644
index 00000000000..a94e4f8d456
--- /dev/null
+++ b/plugins/network-elements/ovs/src/com/cloud/network/resource/OvsResource.java
@@ -0,0 +1,175 @@
+package com.cloud.network.resource;
+
+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.Command;
+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.StartupCommand;
+import com.cloud.host.Host;
+import com.cloud.host.Host.Type;
+import com.cloud.network.ovs.OvsApi;
+import com.cloud.network.ovs.StartupOvsCommand;
+import com.cloud.resource.ServerResource;
+import com.cloud.utils.component.ManagerBase;
+
+public class OvsResource extends ManagerBase implements ServerResource {
+ private static final Logger s_logger = Logger.getLogger(OvsResource.class);
+
+ private String _name;
+ private String _guid;
+ private String _zoneId;
+ private int _numRetries;
+
+ private OvsApi _ovsApi;
+
+ protected OvsApi createOvsApi() {
+ return new OvsApi();
+ }
+
+ @Override
+ public boolean configure(String name, Map 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 ip = (String) params.get("ip");
+ if (ip == null) {
+ throw new ConfigurationException("Unable to find IP");
+ }
+
+ _ovsApi = createOvsApi();
+ _ovsApi.setControllerAddress(ip);
+
+ 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() {
+ StartupOvsCommand sc = new StartupOvsCommand();
+ 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) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Answer executeRequest(Command cmd) {
+ return executeRequest(cmd, _numRetries);
+ }
+
+ private Answer executeRequest(ReadyCommand cmd) {
+ return new ReadyAnswer(cmd);
+ }
+
+ private Answer executeRequest(MaintainCommand cmd) {
+ return new MaintainAnswer(cmd);
+ }
+
+ public Answer executeRequest(Command cmd, int numRetries) {
+ if (cmd instanceof ReadyCommand) {
+ return executeRequest((ReadyCommand) cmd);
+ } else if (cmd instanceof MaintainCommand) {
+ return executeRequest((MaintainCommand) cmd);
+ }
+ // TODO: implement services request
+ // else if (cmd instanceof CreateOvsNetworkCommand) {
+ // return executeRequest((CreateOvsNetworkCommand)cmd, numRetries);
+ // }
+ // else if (cmd instanceof DeleteOvsNetworkCommand) {
+ // return executeRequest((DeleteOvsNetworkCommand) cmd, numRetries);
+ // }
+ // else if (cmd instanceof CreateOvsPortCommand) {
+ // return executeRequest((CreateOvsPortCommand) cmd, numRetries);
+ // }
+ // else if (cmd instanceof DeleteOvsPortCommand) {
+ // return executeRequest((DeleteOvsPortCommand) cmd, numRetries);
+ // }
+ // else if (cmd instanceof UpdateOvsPortCommand) {
+ // return executeRequest((UpdateOvsPortCommand) cmd, numRetries);
+ // }
+ s_logger.debug("Received unsupported command " + cmd.toString());
+ return Answer.createUnsupportedCommandAnswer(cmd);
+ }
+
+ @Override
+ public void disconnected() {
+ }
+
+ 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);
+ }
+ }
+
+ @Override
+ public IAgentControl getAgentControl() {
+ return null;
+ }
+
+ @Override
+ public void setAgentControl(IAgentControl agentControl) {
+ }
+
+}
diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql
index 55cb4cce7b9..bf32b8d7869 100755
--- a/setup/db/create-schema.sql
+++ b/setup/db/create-schema.sql
@@ -196,6 +196,8 @@ DROP TABLE IF EXISTS `cloud`.`vm_network_map`;
DROP TABLE IF EXISTS `cloud`.`netapp_volume`;
DROP TABLE IF EXISTS `cloud`.`netapp_pool`;
DROP TABLE IF EXISTS `cloud`.`netapp_lun`;
+DROP TABLE IF EXISTS `cloud`.`ovs_devices`;
+DROP TABLE IF EXISTS `cloud`.`ovs_nic_map`;
CREATE TABLE `cloud`.`version` (
`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id',
@@ -2475,5 +2477,25 @@ CREATE TABLE `cloud`.`nicira_nvp_nic_map` (
CONSTRAINT `fk_nicira_nvp_nic_map__nic` FOREIGN KEY(`nic`) REFERENCES `nics`(`uuid`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE `cloud`.`ovs_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 ovs device is added',
+ `device_name` varchar(255) NOT NULL COMMENT 'name of the ovs device',
+ `host_id` bigint unsigned NOT NULL COMMENT 'host id coresponding to the ovs device',
+ PRIMARY KEY (`id`),
+ CONSTRAINT `fk_ovs_devices__host_id` FOREIGN KEY (`host_id`) REFERENCES `host`(`id`) ON DELETE CASCADE,
+ CONSTRAINT `fk_ovs_devices__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE `cloud`.`ovs_nic_map` (
+ `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+ `logicalswitch` varchar(255) NOT NULL COMMENT 'uuid of logical switch this port is provisioned on',
+ `logicalswitchport` varchar(255) UNIQUE COMMENT 'uuid of this logical switch port',
+ `nic` varchar(255) UNIQUE COMMENT 'cloudstack uuid of the nic connected to this logical switch port',
+ PRIMARY KEY (`id`),
+ CONSTRAINT `fk_ovs_nic_map__nic` FOREIGN KEY(`nic`) REFERENCES `nics`(`uuid`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
SET foreign_key_checks = 1;