Adds a REST interface application to ovsdb
Change-Id: Ife8adac92ed8dc3fda6ffd97bdd783ecc3af9f35
diff --git a/ovsdb-rest/README.md b/ovsdb-rest/README.md
new file mode 100644
index 0000000..393e63d
--- /dev/null
+++ b/ovsdb-rest/README.md
@@ -0,0 +1,87 @@
+# OVSDBREST ONOS APPLICATION
+
+This application provides a ***minimal*** interface to an ovsdb device by exposing REST APIs.
+The API allows to create/delete a bridge, attach/remove ports from an existing bridge, create peer patch and setup GRE tunnels.
+
+## Install
+To install the application on a running onos instance run the following steps.
+
+- first of all, if it is not ready installed, you need to install the ovsdb driver provided by onos. On your onos root directory run:
+
+ cd drivers/ovsdb/
+ onos-app {onos-address} reinstall target/onos-drivers-ovsdb-1.7.0-SNAPSHOT.oar
+
+- then build the source code of the ovsdbrest application through maven:
+
+ git clone https://github.com/netgroup-polito/onos-applications
+ cd onos-applications/ovsdbrest
+ mvn clean install
+
+- Finally you can install the application through the command:
+
+ onos-app {onos-address} reinstall target/onos-app-ovsdbrest-1.7.0-SNAPSHOT.oar
+
+(onos-address is the ip-address of onos server, for example 192.168.123.1)
+
+
+## Activate
+After installing the application, you can activate it through the onos cli by typing:
+
+ app activate org.onosproject.ovsdbrest
+
+To check that the app has been activated type log:tail from the onos cli.
+
+
+## Configure
+After activating the application you need to configure the ovsdb node IP. This is done by using the onos Network Configuration system.
+
+- Send a REST request as follows:
+
+ **POST http://{onos-address}:8181/onos/v1/network/configuration/**
+
+ ```json
+ {
+ "apps": {
+ "org.onosproject.ovsdbrest": {
+ "ovsdbrest": {
+ "nodes": [
+ {
+ "ovsdbIp": "192.168.123.2",
+ "ovsdbPort": "6632"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ```
+
+Check your ovsdb configuration to get the correct ip and port for the ovsdb node.
+The request uses basic HTTP authentication, so you need to provide onos username and password.
+To verify that the configuration has been correctly pushed you can type log:tail from the onos cli.
+The app will start contacting the ovsdb nodes and you should see some related logs from the onos cli.
+
+
+## API
+
+- Create/Delete bridge:
+
+ **POST http://{onos-address}:8181/onos/ovsdb/{ovsdb-ip}/bridge/{bridge-name}**
+
+ **DELETE http://{onos-address}:8181/onos/ovsdb/{ovsdb-ip}/bridge/{bridge-name}**
+
+- Add/Remove a port in a bridge:
+
+ **POST http://{onos-address}:8181/onos/ovsdb/{ovsdb-ip}/bridge/{bridge-name}/port/{port-name}**
+
+ **DELETE http://{onos-address}:8181/onos/ovsdb/{ovsdb-ip}/bridge/{bridge-name}/port/{port-name}**
+
+- Create patch port:
+
+ **POST http://{onos-address}:8181/onos/ovsdb/{ovsdb-ip}/bridge/{bridge-name}/port/{port-name}/patch_peer/{peer-port}**
+
+- Create/Delete a GRE tunnel:
+
+ **POST http://{onos-address}:8181/onos/ovsdb/{ovsdb-ip}/bridge/{bridge-name}/port/{port-name}/gre/{local-ip}/{remote-ip}/{key}**
+
+ **DELETE http://{onos-address}:8181/onos/ovsdb/{ovsdb-ip}/bridge/{bridge-name}/port/{port-name}/gre**
diff --git a/ovsdb-rest/pom.xml b/ovsdb-rest/pom.xml
new file mode 100644
index 0000000..20ee632
--- /dev/null
+++ b/ovsdb-rest/pom.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-dependencies</artifactId>
+ <version>1.9.0-rc2</version>
+ <relativePath/><!-- parent is remote -->
+ </parent>
+
+ <artifactId>ovsdb-rest</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <description>REST apis for bridge and GRE port setup in ovs</description>
+
+ <properties>
+ <onos.app.name>org.onosproject.ovsdbrest</onos.app.name>
+ <web.context>/onos/ovsdb</web.context>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <onos.app.url>http://onosproject.org</onos.app.url>
+ <onos.app.title>REST apis for bridge and GRE port setup in ovs</onos.app.title>
+ <onos.app.requires>
+ org.onosproject.ovsdb-base,
+ org.onosproject.drivers.ovsdb
+ </onos.app.requires>
+ <onos.version>1.9.0-rc2</onos.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-core-serializers</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-core-common</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-misc</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-ovsdb-rfc</artifactId>
+ <version>1.6.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-ovsdb-api</artifactId>
+ <version>1.6.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>javax.ws.rs-api</artifactId>
+ <version>2.0.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-rest</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.glassfish.jersey.containers</groupId>
+ <artifactId>jersey-container-servlet</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.containers</groupId>
+ <artifactId>jersey-container-servlet-core</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <_wab>src/main/webapp/</_wab>
+ <Bundle-SymbolicName>
+ ${project.groupId}.${project.artifactId}
+ </Bundle-SymbolicName>
+ <Import-Package>
+ *,org.glassfish.jersey.servlet
+ </Import-Package>
+ <Web-ContextPath>${web.context}</Web-ContextPath>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <repositories>
+ <repository>
+ <id>ovsdb-api</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots/org/onosproject/onos-ovsdb-api/1.8.0-SNAPSHOT/</url>
+ </repository>
+ <repository>
+ <id>ovsdb-rfc</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots/org/onosproject/onos-ovsdb-rfc/1.8.0-SNAPSHOT/</url>
+ </repository>
+ </repositories>
+</project>
diff --git a/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/ConnectionHandler.java b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/ConnectionHandler.java
new file mode 100644
index 0000000..e00eb28
--- /dev/null
+++ b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/ConnectionHandler.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed 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 org.onosproject.ovsdbrest;
+
+/**
+ * Entity capable of handling a subject connected and disconnected situation.
+ */
+public interface ConnectionHandler<T> {
+
+ /**
+ * Processes the connected subject.
+ *
+ * @param subject subject
+ */
+ void connected(T subject);
+
+ /**
+ * Processes the disconnected subject.
+ *
+ * @param subject subject.
+ */
+ void disconnected(T subject);
+}
+
diff --git a/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbBridgeManager.java b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbBridgeManager.java
new file mode 100644
index 0000000..85eef31
--- /dev/null
+++ b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbBridgeManager.java
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed 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 org.onosproject.ovsdbrest;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Reference;
+import org.onlab.packet.IpAddress;
+import org.onlab.util.ItemNotFoundException;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.BridgeConfig;
+import org.onosproject.net.behaviour.BridgeDescription;
+import org.onosproject.net.behaviour.BridgeName;
+import org.onosproject.net.behaviour.ControllerConfig;
+import org.onosproject.net.behaviour.ControllerInfo;
+import org.onosproject.net.behaviour.DefaultBridgeDescription;
+import org.onosproject.net.behaviour.DefaultPatchDescription;
+import org.onosproject.net.behaviour.DefaultTunnelDescription;
+import org.onosproject.net.behaviour.InterfaceConfig;
+import org.onosproject.net.behaviour.PatchDescription;
+import org.onosproject.net.behaviour.TunnelDescription;
+import org.onosproject.net.behaviour.TunnelEndPoints;
+import org.onosproject.net.behaviour.TunnelKey;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.basics.SubjectFactories;
+import org.onosproject.net.device.DeviceAdminService;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
+import org.onosproject.ovsdb.controller.OvsdbController;
+import org.onosproject.ovsdb.controller.OvsdbNodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.Optional;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.onosproject.ovsdbrest.OvsdbNodeConfig.OvsdbNode;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.ovsdbrest.OvsdbRestException.BridgeAlreadyExistsException;
+import static org.onosproject.ovsdbrest.OvsdbRestException.BridgeNotFoundException;
+import static org.onosproject.ovsdbrest.OvsdbRestException.OvsdbDeviceException;
+
+/**
+ * Bridge and port controller.
+ */
+@Component(immediate = true)
+@Service
+public class OvsdbBridgeManager implements OvsdbBridgeService {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private ApplicationId appId;
+ private static final int DPID_BEGIN = 4;
+ private static final int OFPORT = 6653;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ClusterService clusterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigRegistry configRegistry;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigService configService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OvsdbController controller;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceAdminService adminService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DriverService driverService;
+
+ private Set<OvsdbNode> ovsdbNodes;
+
+ // {bridgeName: datapathId} structure to manage the creation/deletion of bridges
+ private Map<String, DeviceId> bridgeIds = Maps.newConcurrentMap();
+
+ private Map<OvsdbNode, Set<DeviceId>> ovsdbNodeDevIdsSetMap = Maps.newConcurrentMap();
+
+ private final ExecutorService eventExecutor =
+ newSingleThreadExecutor(groupedThreads("onos/ovsdb-rest-ctl", "event-handler", log));
+ private final NetworkConfigListener configListener = new InternalConfigListener();
+ private final AtomicLong datapathId = new AtomicLong(DPID_BEGIN);
+
+
+ private final ConfigFactory configFactory =
+ new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, OvsdbNodeConfig.class, "ovsdbrest") {
+ @Override
+ public OvsdbNodeConfig createConfig() {
+ return new OvsdbNodeConfig();
+ }
+ };
+
+ @Activate
+ protected void activate() {
+ appId = coreService.getAppId("org.onosproject.ovsdbrest");
+ configService.addListener(configListener);
+ configRegistry.registerConfigFactory(configFactory);
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ configService.removeListener(configListener);
+ configRegistry.unregisterConfigFactory(configFactory);
+ eventExecutor.shutdown();
+ log.info("Stopped");
+ }
+
+ @Override
+ public void createBridge(IpAddress ovsdbAddress, String bridgeName)
+ throws OvsdbDeviceException, BridgeAlreadyExistsException {
+
+ OvsdbNode ovsdbNode;
+ log.debug("Creating bridge {} at {}", bridgeName, ovsdbAddress);
+ try {
+ // gets the target ovsdb node
+ ovsdbNode = ovsdbNodes.stream().filter(node -> node.ovsdbIp().equals(ovsdbAddress)).findFirst().get();
+ } catch (NoSuchElementException nsee) {
+ log.info(nsee.getMessage());
+ throw new OvsdbDeviceException(nsee.getMessage());
+ }
+
+ // construct a unique dev id'
+ DeviceId dpid = getNextUniqueDatapathId(datapathId);
+
+
+ if (isBridgeCreated(bridgeName)) {
+ log.warn("A bridge with this name already exists, aborting.");
+ throw new BridgeAlreadyExistsException();
+ }
+ List<ControllerInfo> controllers = new ArrayList<>();
+ Sets.newHashSet(clusterService.getNodes()).forEach(controller -> {
+ ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp");
+ controllers.add(ctrlInfo);
+ log.info("controller {}:{} added", ctrlInfo.ip().toString(), ctrlInfo.port());
+ });
+ try {
+ Device device = deviceService.getDevice(ovsdbNode.ovsdbId());
+ if (device == null) {
+ log.warn("Ovsdb device not found, aborting.");
+ throw new OvsdbDeviceException("Ovsdb device not found");
+ }
+ if (device.is(BridgeConfig.class)) {
+ BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
+ BridgeDescription bridgeDescription = DefaultBridgeDescription.builder()
+ .name(bridgeName)
+ .datapathId(dpid.toString())
+ .controllers(controllers)
+ .build();
+ bridgeConfig.addBridge(bridgeDescription);
+ bridgeIds.put(bridgeName, bridgeDescription.deviceId().get());
+ log.info("Correctly created bridge {} at {}", bridgeName, ovsdbAddress);
+ } else {
+ log.warn("The bridging behaviour is not supported in device {}", device.id());
+ throw new OvsdbDeviceException(
+ "The bridging behaviour is not supported in device " + device.id()
+ );
+ }
+ } catch (ItemNotFoundException e) {
+ log.warn("Failed to create integration bridge on {}", ovsdbNode.ovsdbIp());
+ throw new OvsdbDeviceException("Error with ovsdb device: item not found");
+ }
+ }
+
+ @Override
+ public void deleteBridge(IpAddress ovsdbAddress, String bridgeName)
+ throws OvsdbDeviceException, BridgeNotFoundException {
+
+ OvsdbNode ovsdbNode;
+ log.debug("Deleting bridge {} at {}", bridgeName, ovsdbAddress);
+
+ try {
+ // gets the target ovsdb node
+ ovsdbNode = ovsdbNodes.stream().filter(node -> node.ovsdbIp().equals(ovsdbAddress)).findFirst().get();
+ } catch (NoSuchElementException nsee) {
+ log.warn(nsee.getMessage());
+ throw new OvsdbDeviceException(nsee.getMessage());
+ }
+
+ DeviceId deviceId = bridgeIds.get(bridgeName);
+ if (deviceId == null) {
+ log.warn("No bridge with this name, aborting.");
+ throw new BridgeNotFoundException();
+ }
+
+ log.debug("Device id is: " + deviceId.toString());
+
+ try {
+ Device device = deviceService.getDevice(ovsdbNode.ovsdbId());
+ if (device == null) {
+ log.warn("Ovsdb device not found, aborting.");
+ throw new OvsdbDeviceException("Ovsdb device not found");
+ }
+ if (device.is(BridgeConfig.class)) {
+
+ // unregister bridge from its controllers
+ deviceId = DeviceId.deviceId(deviceId.uri());
+ DriverHandler h = driverService.createHandler(deviceId);
+ ControllerConfig controllerConfig = h.behaviour(ControllerConfig.class);
+ controllerConfig.setControllers(new ArrayList<>());
+
+ // remove bridge from ovsdb
+ BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
+ bridgeConfig.deleteBridge(BridgeName.bridgeName(bridgeName));
+ bridgeIds.remove(bridgeName);
+
+ // remove bridge from onos devices
+ adminService.removeDevice(deviceId);
+
+ log.info("Correctly deleted bridge {} at {}", bridgeName, ovsdbAddress);
+ } else {
+ log.warn("The bridging behaviour is not supported in device {}", device.id());
+ throw new OvsdbDeviceException(
+ "The bridging behaviour is not supported in device " + device.id()
+ );
+ }
+ } catch (ItemNotFoundException e) {
+ log.warn("Failed to delete bridge on {}", ovsdbNode.ovsdbIp());
+ throw new OvsdbDeviceException("Error with ovsdb device: item not found");
+ }
+ }
+
+ @Override
+ public void addPort(IpAddress ovsdbAddress, String bridgeName, String portName)
+ throws OvsdbDeviceException, BridgeNotFoundException {
+
+ OvsdbNode ovsdbNode;
+ log.debug("Adding port {} to bridge {} at {}", portName, bridgeName, ovsdbAddress);
+
+ try {
+ // gets the target ovsdb node
+ ovsdbNode = ovsdbNodes.stream().filter(node -> node.ovsdbIp().equals(ovsdbAddress)).findFirst().get();
+ } catch (NoSuchElementException nsee) {
+ log.warn(nsee.getMessage());
+ throw new OvsdbDeviceException(nsee.getMessage());
+ }
+
+ try {
+ Device device = deviceService.getDevice(ovsdbNode.ovsdbId());
+ log.debug("OvsdbNode.ovsdbId = " + ovsdbNode.ovsdbId());
+ if (device == null) {
+ log.warn("Ovsdb device not found, aborting.");
+ throw new OvsdbDeviceException("Ovsdb device not found");
+ }
+ if (device.is(BridgeConfig.class)) {
+ // add port to bridge through ovsdb
+ BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
+ bridgeConfig.addPort(BridgeName.bridgeName(bridgeName), portName);
+ log.info("Correctly added port {} to bridge {} at {}", portName, bridgeName, ovsdbAddress);
+ } else {
+ log.warn("The bridging behaviour is not supported in device {}", device.id());
+ throw new OvsdbDeviceException(
+ "The bridging behaviour is not supported in device " + device.id()
+ );
+ }
+ } catch (ItemNotFoundException e) {
+ log.warn("Failed to delete bridge on {}", ovsdbNode.ovsdbIp());
+ throw new OvsdbDeviceException("Error with ovsdb device: item not found");
+ }
+ }
+
+ @Override
+ public void removePort(IpAddress ovsdbAddress, String bridgeName, String portName)
+ throws OvsdbDeviceException, BridgeNotFoundException {
+
+ OvsdbNode ovsdbNode;
+ log.debug("Deleting port {} to bridge {} at {}", portName, bridgeName, ovsdbAddress);
+
+ try {
+ // gets the target ovsdb node
+ ovsdbNode = ovsdbNodes.stream().filter(node -> node.ovsdbIp().equals(ovsdbAddress)).findFirst().get();
+
+ } catch (NoSuchElementException nsee) {
+ log.warn(nsee.getMessage());
+ throw new OvsdbDeviceException(nsee.getMessage());
+ }
+
+ try {
+ Device device = deviceService.getDevice(ovsdbNode.ovsdbId());
+ if (device == null) {
+ log.warn("Ovsdb device not found, aborting.");
+ throw new OvsdbDeviceException("Ovsdb device not found");
+ }
+ if (device.is(BridgeConfig.class)) {
+
+ // delete port from bridge through ovsdb
+ BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
+ bridgeConfig.deletePort(BridgeName.bridgeName(bridgeName), portName);
+
+ log.info("Correctly deleted port {} from bridge {} at {}", portName, bridgeName, ovsdbAddress);
+
+ } else {
+ log.warn("The bridging behaviour is not supported in device {}", device.id());
+ throw new OvsdbDeviceException(
+ "The bridging behaviour is not supported in device " + device.id()
+ );
+ }
+ } catch (ItemNotFoundException e) {
+ log.warn("Failed to delete bridge on {}", ovsdbNode.ovsdbIp());
+ throw new OvsdbDeviceException("Error with ovsdb device: item not found");
+ }
+ }
+
+ @Override
+ public void createPatchPeerPort(IpAddress ovsdbAddress, String bridgeName, String portName, String patchPeer)
+ throws OvsdbDeviceException {
+
+ OvsdbNode ovsdbNode;
+ log.debug("Setting port {} as peer of port {}", portName, patchPeer);
+
+ try {
+ // gets the target ovsdb node
+ ovsdbNode = ovsdbNodes.stream().filter(node -> node.ovsdbIp().equals(ovsdbAddress)).findFirst().get();
+ } catch (NoSuchElementException nsee) {
+ log.warn(nsee.getMessage());
+ throw new OvsdbDeviceException(nsee.getMessage());
+ }
+
+ Device device = deviceService.getDevice(ovsdbNode.ovsdbId());
+ log.debug("OvsdbNode.ovsdbId = " + ovsdbNode.ovsdbId());
+ if (device == null) {
+ log.warn("Ovsdb device not found, aborting.");
+ throw new OvsdbDeviceException("Ovsdb device not found");
+ }
+
+ if (device.is(InterfaceConfig.class)) {
+ InterfaceConfig interfaceConfig = device.as(InterfaceConfig.class);
+
+ // prepare patch
+ PatchDescription.Builder builder = DefaultPatchDescription.builder();
+ PatchDescription patchDescription = builder
+ .deviceId(bridgeName)
+ .ifaceName(portName)
+ .peer(patchPeer)
+ .build();
+ // add patch to port through ovsdb
+ interfaceConfig.addPatchMode(portName, patchDescription);
+ log.info("Correctly created port {} on device {} as peer of port {}", portName, bridgeName, patchPeer);
+ } else {
+ log.warn("The interface behaviour is not supported in device {}", device.id());
+ throw new OvsdbDeviceException(
+ "The interface behaviour is not supported in device " + device.id()
+ );
+ }
+ }
+
+ @Override
+ public void createGreTunnel(IpAddress ovsdbAddress, String bridgeName, String portName, IpAddress localIp,
+ IpAddress remoteIp, String key)
+ throws OvsdbDeviceException, BridgeNotFoundException {
+
+ OvsdbNode ovsdbNode;
+ log.debug("Setting up tunnel GRE from {} to {} with key {}",
+ localIp, remoteIp, key);
+
+ try {
+ // gets the target ovsdb node
+ ovsdbNode = ovsdbNodes.stream().filter(node -> node.ovsdbIp().equals(ovsdbAddress)).findFirst().get();
+ } catch (NoSuchElementException nsee) {
+ log.warn(nsee.getMessage());
+ throw new OvsdbDeviceException(nsee.getMessage());
+ }
+
+ try {
+ Device device = deviceService.getDevice(ovsdbNode.ovsdbId());
+ log.debug("OvsdbNode.ovsdbId = " + ovsdbNode.ovsdbId());
+ if (device == null) {
+ log.warn("Ovsdb device not found, aborting.");
+ throw new OvsdbDeviceException("Ovsdb device not found");
+ }
+
+ if (device.is(InterfaceConfig.class)) {
+ InterfaceConfig interfaceConfig = device.as(InterfaceConfig.class);
+
+ // prepare tunnel
+ TunnelDescription tunnelDescription = DefaultTunnelDescription.builder()
+ .deviceId(bridgeName)
+ .ifaceName(portName)
+ .type(TunnelDescription.Type.GRE)
+ .local(TunnelEndPoints.ipTunnelEndpoint(localIp))
+ .remote(TunnelEndPoints.ipTunnelEndpoint(remoteIp))
+ .key(new TunnelKey<>(key))
+ .build();
+ // create tunnel to port through ovsdb
+ interfaceConfig.addTunnelMode(portName, tunnelDescription);
+ log.info("Correctly added tunnel GRE from {} to {} with key {}",
+ localIp, remoteIp, key);
+ } else {
+ log.warn("The interface behaviour is not supported in device {}", device.id());
+ throw new OvsdbDeviceException(
+ "The interface behaviour is not supported in device " + device.id()
+ );
+ }
+ } catch (ItemNotFoundException e) {
+ log.warn("Failed to delete bridge on {}", ovsdbNode.ovsdbIp());
+ throw new OvsdbDeviceException("Error with ovsdb device: item not found");
+ }
+ }
+
+ @Override
+ public void deleteGreTunnel(IpAddress ovsdbAddress, String bridgeName, String portName)
+ throws OvsdbDeviceException {
+
+ OvsdbNode ovsdbNode;
+ log.debug("Deleting tunnel GRE from interface {}",
+ portName);
+
+ try {
+ // gets the target ovsdb node
+ ovsdbNode = ovsdbNodes.stream().filter(node -> node.ovsdbIp().equals(ovsdbAddress)).findFirst().get();
+ } catch (NoSuchElementException nsee) {
+ log.warn(nsee.getMessage());
+ throw new OvsdbDeviceException(nsee.getMessage());
+ }
+
+ try {
+ Device device = deviceService.getDevice(ovsdbNode.ovsdbId());
+ if (device == null) {
+ log.warn("Ovsdb device not found, aborting.");
+ throw new OvsdbDeviceException("Ovsdb device not found");
+ }
+
+ if (device.is(InterfaceConfig.class)) {
+ InterfaceConfig interfaceConfig = device.as(InterfaceConfig.class);
+ // remove tunnel through ovsdb
+ interfaceConfig.removeTunnelMode(portName);
+ log.info("Correctly deleted tunnel GRE from interface {}", portName);
+ } else {
+ log.warn("The interface behaviour is not supported in device {}", device.id());
+ throw new OvsdbDeviceException(
+ "The interface behaviour is not supported in device " + device.id()
+ );
+ }
+ } catch (ItemNotFoundException e) {
+ log.warn("Failed to delete bridge on {}", ovsdbNode.ovsdbIp());
+ throw new OvsdbDeviceException("Error with ovsdb device: item not found");
+ }
+
+ }
+
+ /**
+ * Performs the connection to ovsdb.
+ *
+ * @param node the ovsdb node, with IP address and port
+ */
+ private void connectOvsdb(OvsdbNode node) {
+ if (!isOvsdbConnected(node)) {
+ log.info("connecting ovsdb at {}:{}", node.ovsdbIp(), node.ovsdbPort());
+ controller.connect(node.ovsdbIp(), node.ovsdbPort());
+ }
+ }
+
+ /**
+ * Gets an available datapath id for the new bridge.
+ *
+ * @param datapathId the integer used to generate ids
+ * @return the datapath id
+ */
+ private DeviceId getNextUniqueDatapathId(AtomicLong datapathId) {
+ DeviceId dpid;
+ do {
+ String stringId = String.format("%16X", datapathId.getAndIncrement()).replace(' ', '0');
+ log.info("String id is: " + stringId);
+ dpid = DeviceId.deviceId(stringId);
+ } while (deviceService.getDevice(dpid) != null);
+ return dpid;
+ }
+
+ /**
+ * Checks if the bridge exists and is available.
+ *
+ * @return true if the bridge is available, false otherwise
+ */
+ private boolean isBridgeCreated(String bridgeName) {
+ DeviceId deviceId = bridgeIds.get(bridgeName);
+ return (deviceId != null
+ && deviceService.getDevice(deviceId) != null
+ && deviceService.isAvailable(deviceId));
+ }
+
+ /**
+ * Returns connection state of OVSDB server for a given node.
+ *
+ * @return true if it is connected, false otherwise
+ */
+ private boolean isOvsdbConnected(OvsdbNode node) {
+
+ OvsdbClientService ovsdbClient = getOvsdbClient(node);
+ return deviceService.isAvailable(node.ovsdbId()) &&
+ ovsdbClient != null && ovsdbClient.isConnected();
+ }
+
+ /**
+ * Returns OVSDB client for a given node.
+ *
+ * @return OVSDB client, or null if it fails to get OVSDB client
+ */
+ private OvsdbClientService getOvsdbClient(OvsdbNode node) {
+
+ OvsdbClientService ovsdbClient = controller.getOvsdbClient(
+ new OvsdbNodeId(node.ovsdbIp(), node.ovsdbPort().toInt()));
+ if (ovsdbClient == null) {
+ log.trace("Couldn't find OVSDB client for {}", node.ovsdbId().toString());
+ }
+ return ovsdbClient;
+ }
+
+ /**
+ * Returns an ovsdb node associated with a given OVSDB device.
+ *
+ * @param ovsdbId OVSDB device id
+ * @return cordvtn node, null if it fails to find the node
+ */
+ private OvsdbNode nodeByOvsdbId(DeviceId ovsdbId) {
+ return ovsdbNodes.stream()
+ .filter(node -> node.ovsdbId().equals(ovsdbId))
+ .findFirst().orElse(null);
+ }
+
+ /**
+ * Returns ovsdb node associated with a given integration bridge.
+ *
+ * @param bridgeId device id of the bridge
+ * @return ovsdb node, null if it fails to find the node
+ */
+ private OvsdbNode nodeByBridgeId(DeviceId bridgeId) {
+ final Set<OvsdbNode> nodes = new HashSet<>();
+ ovsdbNodeDevIdsSetMap.forEach((node, set) -> {
+ if (set.contains(bridgeId)) {
+ nodes.add(node);
+ }
+ });
+ Optional<OvsdbNode> opt = nodes.stream().findAny();
+ if (opt.isPresent()) {
+ return opt.get();
+ } else {
+ return null;
+ }
+ }
+
+ private void readConfiguration() {
+ OvsdbNodeConfig config = configRegistry.getConfig(appId, OvsdbNodeConfig.class);
+ if (config == null) {
+ log.debug("No configuration found");
+ return;
+ }
+ ovsdbNodes = config.getNodes();
+ ovsdbNodes.forEach(this::connectOvsdb);
+ }
+
+ private class InternalConfigListener implements NetworkConfigListener {
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+ if (!event.configClass().equals(OvsdbNodeConfig.class)) {
+ return;
+ }
+ switch (event.type()) {
+ case CONFIG_ADDED:
+ case CONFIG_UPDATED:
+ eventExecutor.execute(OvsdbBridgeManager.this::readConfiguration);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbBridgeService.java b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbBridgeService.java
new file mode 100644
index 0000000..6f69f69
--- /dev/null
+++ b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbBridgeService.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed 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 org.onosproject.ovsdbrest;
+
+import org.onlab.packet.IpAddress;
+
+/**
+ * APIs for ovsdb driver access.
+ */
+public interface OvsdbBridgeService {
+
+ /**
+ * Creates a new bridge.
+ * @param ovsdbAddress the ovsdb IP address
+ * @param bridgeName the bridge identifier
+ */
+ void createBridge(IpAddress ovsdbAddress, String bridgeName) throws OvsdbRestException.OvsdbDeviceException,
+ OvsdbRestException.BridgeAlreadyExistsException;
+
+ /**
+ * Deletes a bridge.
+ * @param ovsdbAddress the ovsdb IP address
+ * @param bridgeName the bridge identifier
+ */
+ void deleteBridge(IpAddress ovsdbAddress, String bridgeName) throws OvsdbRestException.OvsdbDeviceException,
+ OvsdbRestException.BridgeNotFoundException;
+
+ /**
+ * Adds a port to a bridge.
+ * @param ovsdbAddress the ovsdb IP address
+ * @param bridgeName the bridge identifier
+ * @param portName the name of the port to attach to the bridge
+ */
+ void addPort(IpAddress ovsdbAddress, String bridgeName, String portName)
+ throws OvsdbRestException.OvsdbDeviceException, OvsdbRestException.BridgeNotFoundException;
+
+ /**
+ * Removes a port from a bridge.
+ * @param ovsdbAddress the ovsdb IP address
+ * @param bridgeName the bridge identifier
+ * @param portName the name of the port to remove from the bridge
+ */
+ void removePort(IpAddress ovsdbAddress, String bridgeName, String portName)
+ throws OvsdbRestException.OvsdbDeviceException, OvsdbRestException.BridgeNotFoundException;
+
+ /**
+ * Adds a patch port to a bridge setting it as peer of an other port.
+ * @param ovsdbAddress the ovsdb IP address
+ * @param bridgeName the bridge identifier
+ * @param portName the port name
+ * @param patchPeer the name of the peer port
+ */
+ void createPatchPeerPort(IpAddress ovsdbAddress, String bridgeName, String portName, String patchPeer)
+ throws OvsdbRestException.OvsdbDeviceException;
+
+ /**
+ * Creates a GRE tunnel from a bridge to a remote destination.
+ * @param ovsdbAddress the ovsdb IP address
+ * @param bridgeName the bridge identifier
+ * @param portName the name of the new GRE port
+ * @param localIp local end point of the GRE tunnel
+ * @param remoteIp remote end point of GRE tunnel
+ * @param key the tunnel key, should represent a 32 bit hexadecimal number
+ */
+ void createGreTunnel(IpAddress ovsdbAddress, String bridgeName, String portName, IpAddress localIp,
+ IpAddress remoteIp, String key)
+ throws OvsdbRestException.OvsdbDeviceException, OvsdbRestException.BridgeNotFoundException;
+
+ /**
+ * Deletes a GRE tunnel given the port name.
+ * @param ovsdbAddress the ovsdb IP address
+ * @param bridgeName the bridge identifier
+ * @param portName the name of the GRE
+ */
+ void deleteGreTunnel(IpAddress ovsdbAddress, String bridgeName, String portName)
+ throws OvsdbRestException.OvsdbDeviceException;
+}
diff --git a/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbNodeConfig.java b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbNodeConfig.java
new file mode 100644
index 0000000..5caa9d3
--- /dev/null
+++ b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbNodeConfig.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed 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 org.onosproject.ovsdbrest;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.Sets;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.Config;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Set;
+
+/**
+ * Configuration info to reach the OVSDB server.
+ */
+public class OvsdbNodeConfig extends Config<ApplicationId> {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private static final String NODES = "nodes";
+ private static final String OVSDB_PORT = "ovsdbPort";
+ private static final String OVSDB_IP = "ovsdbIp";
+
+ public Set<OvsdbNode> getNodes() {
+ Set<OvsdbNode> nodes = Sets.newConcurrentHashSet();
+
+ JsonNode jsnoNodes = object.path(NODES);
+ jsnoNodes.forEach(node -> {
+ IpAddress ovsdbIp = IpAddress.valueOf(node.path(OVSDB_IP).textValue());
+ TpPort port = TpPort.tpPort(Integer.parseInt(node.path(OVSDB_PORT).asText()));
+ log.info("Ovsdb port: " + port.toString());
+ nodes.add(new OvsdbNode(ovsdbIp, port));
+ });
+ return nodes;
+ }
+
+ public static class OvsdbNode {
+ private final IpAddress ovsdbIp;
+ private final TpPort ovsdbPort;
+
+ public OvsdbNode(IpAddress ovsdbIp, TpPort ovsdbPort) {
+ this.ovsdbIp = ovsdbIp;
+ this.ovsdbPort = ovsdbPort;
+ }
+
+ public IpAddress ovsdbIp() {
+ return ovsdbIp;
+ }
+
+ public TpPort ovsdbPort() {
+ return ovsdbPort;
+ }
+
+ public DeviceId ovsdbId() {
+ return DeviceId.deviceId("ovsdb:" + ovsdbIp.toString());
+ }
+ }
+}
diff --git a/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbRestException.java b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbRestException.java
new file mode 100644
index 0000000..c6aa621
--- /dev/null
+++ b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/OvsdbRestException.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed 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 org.onosproject.ovsdbrest;
+
+/**
+ * Custom exception class for OVSDB device.
+ */
+public class OvsdbRestException {
+
+ /**
+ * Thrown for problems related to a device entity representing an ovsdb node.
+ */
+ public static class OvsdbDeviceException extends Exception {
+ public OvsdbDeviceException(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Thrown when the an ovs bridge already exists with a given name.
+ */
+ public static class BridgeAlreadyExistsException extends Exception { }
+
+ /**
+ * Thrown when an ovs bridge is not found.
+ */
+ public static class BridgeNotFoundException extends Exception { }
+}
diff --git a/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/package-info.java b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/package-info.java
new file mode 100644
index 0000000..a15b6a3
--- /dev/null
+++ b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed 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.
+ */
+
+/**
+ * Ovsdb interaction implementation.
+ */
+package org.onosproject.ovsdbrest;
\ No newline at end of file
diff --git a/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/rest/OvsdbBridgeWebResource.java b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/rest/OvsdbBridgeWebResource.java
new file mode 100644
index 0000000..f00bd0d
--- /dev/null
+++ b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/rest/OvsdbBridgeWebResource.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed 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 org.onosproject.ovsdbrest.rest;
+
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onosproject.ovsdbrest.OvsdbRestException;
+import org.onosproject.ovsdbrest.OvsdbBridgeService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.io.InputStream;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * REST APIs for create/delete a bridge and create a port.
+ */
+
+@Path("/")
+public class OvsdbBridgeWebResource extends AbstractWebResource {
+ private final Logger log = getLogger(getClass());
+
+ @GET
+ @Path("/test")
+ public Response getTest() {
+ ObjectNode responseBody = new ObjectNode(JsonNodeFactory.instance);
+ responseBody.put("message", "it works!");
+ return Response.status(200).entity(responseBody).build();
+ }
+
+ @POST
+ @Path("/{ovsdb-ip}/bridge/{bridge-name}")
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response addBridge(InputStream stream,
+ @PathParam("ovsdb-ip") String ovsdbIp,
+ @PathParam("bridge-name") String bridgeName) {
+ try {
+ IpAddress ovsdbAddress = IpAddress.valueOf(ovsdbIp);
+ OvsdbBridgeService ovsdbBridgeService = get(OvsdbBridgeService.class);
+ ovsdbBridgeService.createBridge(ovsdbAddress, bridgeName);
+ return Response.status(200).build();
+ } catch (OvsdbRestException.BridgeAlreadyExistsException ex) {
+ return Response.status(Response.Status.CONFLICT).entity("A bridge with this name already exists").build();
+ } catch (OvsdbRestException.OvsdbDeviceException ex) {
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
+ }
+ }
+
+ @DELETE
+ @Path("/{ovsdb-ip}/bridge/{bridge-name}")
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response deleteBridge(InputStream stream,
+ @PathParam("ovsdb-ip") String ovsdbIp,
+ @PathParam("bridge-name") String bridgeName) {
+ try {
+
+ IpAddress ovsdbAddress = IpAddress.valueOf(ovsdbIp);
+ OvsdbBridgeService ovsdbBridgeService = get(OvsdbBridgeService.class);
+ ovsdbBridgeService.deleteBridge(ovsdbAddress, bridgeName);
+ return Response.status(200).build();
+ } catch (OvsdbRestException.BridgeNotFoundException ex) {
+ return Response.status(Response.Status.NOT_FOUND).entity("No bridge found with the specified name").build();
+ } catch (OvsdbRestException.OvsdbDeviceException ex) {
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
+ }
+ }
+
+ @POST
+ @Path("/{ovsdb-ip}/bridge/{bridge-name}/port/{port-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response addPort(InputStream stream,
+ @PathParam("ovsdb-ip") String ovsdbIp,
+ @PathParam("bridge-name") String bridgeName,
+ @PathParam("port-name") String portName) {
+ try {
+ IpAddress ovsdbAddress = IpAddress.valueOf(ovsdbIp);
+ OvsdbBridgeService ovsdbBridgeService = get(OvsdbBridgeService.class);
+ ovsdbBridgeService.addPort(ovsdbAddress, bridgeName, portName);
+ return Response.status(200).build();
+ } catch (OvsdbRestException.BridgeNotFoundException ex) {
+ return Response.status(Response.Status.NOT_FOUND).entity("No bridge found with the specified name").build();
+ } catch (OvsdbRestException.OvsdbDeviceException ex) {
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
+ }
+ }
+
+ @DELETE
+ @Path("/{ovsdb-ip}/bridge/{bridge-name}/port/{port-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response deletePort(InputStream stream,
+ @PathParam("ovsdb-ip") String ovsdbIp,
+ @PathParam("bridge-name") String bridgeName,
+ @PathParam("port-name") String portName) {
+ try {
+ IpAddress ovsdbAddress = IpAddress.valueOf(ovsdbIp);
+ OvsdbBridgeService ovsdbBridgeService = get(OvsdbBridgeService.class);
+ ovsdbBridgeService.removePort(ovsdbAddress, bridgeName, portName);
+ return Response.status(200).build();
+ } catch (OvsdbRestException.BridgeNotFoundException ex) {
+ return Response.status(Response.Status.NOT_FOUND).entity("No bridge found with the specified name").build();
+ } catch (OvsdbRestException.OvsdbDeviceException ex) {
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
+ }
+ }
+
+ @POST
+ @Path("/{ovsdb-ip}/bridge/{bridge-name}/port/{port-name}/patch_peer/{patch-peer}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response createPatchPeerPort(InputStream stream,
+ @PathParam("ovsdb-ip") String ovsdbIp,
+ @PathParam("bridge-name") String bridgeName,
+ @PathParam("port-name") String portName,
+ @PathParam("patch-peer") String patchPeer) {
+ try {
+ IpAddress ovsdbAddress = IpAddress.valueOf(ovsdbIp);
+ OvsdbBridgeService ovsdbBridgeService = get(OvsdbBridgeService.class);
+ ovsdbBridgeService.createPatchPeerPort(ovsdbAddress, bridgeName, portName, patchPeer);
+ return Response.status(200).build();
+ } catch (OvsdbRestException.OvsdbDeviceException ex) {
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
+ }
+ }
+
+ @POST
+ @Path("/{ovsdb-ip}/bridge/{bridge-name}/port/{port-name}/gre/{local-ip}/{remote-ip}/{key}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response addGreTunnel(InputStream stream,
+ @PathParam("ovsdb-ip") String ovsdbIp,
+ @PathParam("bridge-name") String bridgeName,
+ @PathParam("port-name") String portName,
+ @PathParam("local-ip") String localIp,
+ @PathParam("remote-ip") String remoteIp,
+ @PathParam("key") String key) {
+ try {
+ IpAddress ovsdbAddress = IpAddress.valueOf(ovsdbIp);
+ IpAddress tunnelLocalIp = IpAddress.valueOf(localIp);
+ IpAddress tunnelRemoteIp = IpAddress.valueOf(remoteIp);
+ OvsdbBridgeService ovsdbBridgeService = get(OvsdbBridgeService.class);
+ ovsdbBridgeService.createGreTunnel(ovsdbAddress, bridgeName, portName, tunnelLocalIp, tunnelRemoteIp, key);
+ return Response.status(200).build();
+ } catch (OvsdbRestException.BridgeNotFoundException ex) {
+ return Response.status(Response.Status.NOT_FOUND).entity("No bridge found with the specified name").build();
+ } catch (OvsdbRestException.OvsdbDeviceException ex) {
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
+ }
+ }
+
+ @DELETE
+ @Path("/{ovsdb-ip}/bridge/{bridge-name}/port/{port-name}/gre")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response deleteGreTunnel(InputStream stream,
+ @PathParam("ovsdb-ip") String ovsdbIp,
+ @PathParam("bridge-name") String bridgeName,
+ @PathParam("port-name") String portName) {
+ try {
+ IpAddress ovsdbAddress = IpAddress.valueOf(ovsdbIp);
+ OvsdbBridgeService ovsdbBridgeService = get(OvsdbBridgeService.class);
+ ovsdbBridgeService.deleteGreTunnel(ovsdbAddress, bridgeName, portName);
+ return Response.status(200).build();
+ } catch (OvsdbRestException.OvsdbDeviceException ex) {
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
+ }
+ }
+}
diff --git a/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/rest/OvsdbRestApp.java b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/rest/OvsdbRestApp.java
new file mode 100644
index 0000000..a308409
--- /dev/null
+++ b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/rest/OvsdbRestApp.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed 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 org.onosproject.ovsdbrest.rest;
+
+import org.onlab.rest.AbstractWebApplication;
+
+import java.util.Set;
+
+/**
+ * Loaders of web resource classes.
+ */
+public class OvsdbRestApp extends AbstractWebApplication {
+
+ @Override
+ public Set<Class<?>> getClasses() {
+ return getClasses(OvsdbBridgeWebResource.class);
+ }
+}
diff --git a/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/rest/package-info.java b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/rest/package-info.java
new file mode 100644
index 0000000..32a6dc2
--- /dev/null
+++ b/ovsdb-rest/src/main/java/org/onosproject/ovsdbrest/rest/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed 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.
+ */
+
+/**
+ * REST interfaces implementation.
+ */
+package org.onosproject.ovsdbrest.rest;
\ No newline at end of file
diff --git a/ovsdb-rest/src/main/webapp/WEB-INF/web.xml b/ovsdb-rest/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..8725ab5
--- /dev/null
+++ b/ovsdb-rest/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2016-present Open Networking Laboratory
+ ~
+ ~ Licensed 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.
+ -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ id="ONOS" version="2.5">
+ <display-name>ONOS REST API v1.0</display-name>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Secured</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>admin</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <security-role>
+ <role-name>admin</role-name>
+ </security-role>
+
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ <realm-name>karaf</realm-name>
+ </login-config>
+
+ <servlet>
+ <servlet-name>JAX-RS Service</servlet-name>
+ <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value>org.onosproject.ovsdbrest.rest.OvsdbRestApp</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>JAX-RS Service</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+</web-app>
diff --git a/ovsdb-rest/tools/addBridge.json b/ovsdb-rest/tools/addBridge.json
new file mode 100644
index 0000000..60ac33d
--- /dev/null
+++ b/ovsdb-rest/tools/addBridge.json
@@ -0,0 +1 @@
+{"ovsdbIp" : "127.0.0.1", "bridgeName" : "br-test"}
diff --git a/ovsdb-rest/tools/ovsdbrest.json b/ovsdb-rest/tools/ovsdbrest.json
new file mode 100644
index 0000000..da79f40
--- /dev/null
+++ b/ovsdb-rest/tools/ovsdbrest.json
@@ -0,0 +1,15 @@
+{
+ "apps": {
+ "org.onosproject.ovsdbrest": {
+ "ovsdbrest": {
+ "nodes": [
+ {
+ "ovsdbIp": "127.0.0.1",
+ "ovsdbPort": "6632"
+ }
+ ]
+ }
+ }
+ }
+}
+
diff --git a/pom.xml b/pom.xml
index aae10b6..accaeaf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -47,6 +47,7 @@
<module>mef-sca-api</module>
<module>icona</module>
<module>patchpanel</module>
+ <module>ovsdb-rest</module>
</modules>
</project>