[ONOS-7826] Adding a TAPI 2.1 Flow Rule programmable behaviour
Change-Id: I0b0070c4ca2a8c175b1fc6a4107566bb503e5b04
diff --git a/apps/odtn/api/src/test/resources/tapi-ols.json b/apps/odtn/api/src/test/resources/tapi-ols.json
new file mode 100644
index 0000000..a49ca8c
--- /dev/null
+++ b/apps/odtn/api/src/test/resources/tapi-ols.json
@@ -0,0 +1,18 @@
+{
+ "devices": {
+ "rest:127.0.0.1:1234": {
+ "rest": {
+ "ip": "127.0.0.1",
+ "port": 1234,
+ "protocol": "http",
+ "testUrl":"/data/context/",
+ "manufacturer": "tapi-swagger",
+ "hwVersion": "0",
+ "swVersion": "2.1"
+ },
+ "basic": {
+ "driver": "ols"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/drivers/odtn-driver/BUILD b/drivers/odtn-driver/BUILD
index fb1dbfc..5c65159 100644
--- a/drivers/odtn-driver/BUILD
+++ b/drivers/odtn-driver/BUILD
@@ -1,12 +1,12 @@
-COMPILE_DEPS = CORE_DEPS + [
+COMPILE_DEPS = CORE_DEPS + JACKSON + [
"@commons_jxpath//jar",
+ "@javax_ws_rs_api//jar",
+ "@httpcore_osgi//jar",
"//core/store/serializers:onos-core-serializers",
"//drivers/utilities:onos-drivers-utilities",
"//protocols/netconf/api:onos-protocols-netconf-api",
"//protocols/rest/api:onos-protocols-rest-api",
"//apps/odtn/api:onos-apps-odtn-api",
- "@jackson_databind//jar",
- "@javax_ws_rs_api//jar",
"//apps/optical-model:onos-apps-optical-model",
"//drivers/optical:onos-drivers-optical",
]
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/impl/DeviceConnectionCache.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/impl/DeviceConnectionCache.java
index ba0ea76..827ebd4 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/impl/DeviceConnectionCache.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/impl/DeviceConnectionCache.java
@@ -101,16 +101,15 @@
* @param flowId flow id
* @return the flow rule
*/
- public FlowRule get(DeviceId did, FlowId flowId) {
+ public DeviceConnection get(DeviceId did, FlowId flowId) {
if (!flowCache.containsKey(did)) {
return null;
}
Set<DeviceConnection> set = flowCache.get(did);
- DeviceConnection connection = set.stream()
+ return set.stream()
.filter(c -> c.getFlowRule().id() == flowId)
.findFirst()
.orElse(null);
- return connection != null ? connection.getFlowRule() : null;
}
/**
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceDescriptionDiscovery.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceDescriptionDiscovery.java
index 4bc7e69..c106202 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceDescriptionDiscovery.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceDescriptionDiscovery.java
@@ -46,7 +46,24 @@
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.*;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.LAYER_PROTOCOL_NAME;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.MEDIA_CHANNEL_SERVICE_INTERFACE_POINT_SPEC;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.AVAILABLE_SPECTRUM;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.ADJUSTMENT_GRANULARITY;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.BASE_FREQUENCY;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.FREQUENCY_CONSTRAINT;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.GRID_TYPE;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.LOWER_FREQUENCY;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.MC_POOL;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.PHOTONIC_LAYER_QUALIFIER_NMC;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.PHOTONIC_MEDIA;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.SERVICE_INTERFACE_POINT;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.SUPPORTED_LAYER_PROTOCOL_QUALIFIER;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.UPPER_FREQUENCY;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.UUID;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.toMbpsFromHz;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.getChannelSpacing;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.getSlotGranularity;
import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
import static org.slf4j.LoggerFactory.getLogger;
@@ -142,7 +159,7 @@
OchSignal ochSignal = getOchSignal(mcPool);
synchronized (N_PORT_LOCK) {
//annotations(portNumber-uuid)
- annotations.set(nPort.toString(), uuid);
+ annotations.set(UUID, uuid);
//add och port
ports.add(ochPortDescription(nPort, true, OduSignalType.ODU4,
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceHelper.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceHelper.java
index 11bf38c..d4e9c06 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceHelper.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceHelper.java
@@ -40,6 +40,16 @@
public static final String LOWER_FREQUENCY = "lower-frequency";
public static final String AVAILABLE_SPECTRUM = "available-spectrum";
public static final long BASE_FREQUENCY = 193100000; //Working in Mhz
+ public static final String TAPI_CONNECTIVITY_CONNECTIVITY_SERVICE = "tapi-connectivity:connectivity-service";
+ public static final String END_POINT = "end-point";
+ public static final String SERVICE_LAYER = "service-layer";
+ public static final String SERVICE_TYPE = "service-type";
+ public static final String POINT_TO_POINT_CONNECTIVITY = "POINT_TO_POINT_CONNECTIVITY";
+ public static final String LOCAL_ID = "local-id";
+ public static final String LAYER_PROTOCOL_QUALIFIER = "layer-protocol-qualifier";
+ public static final String TAPI_PHOTONIC_MEDIA_PHOTONIC_LAYER_QUALIFIER_NMC =
+ "tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC";
+ public static final String SERVICE_INTERFACE_POINT_UUID = "service-interface-point-uuid";
private TapiDeviceHelper(){}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceLambdaQuery.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceLambdaQuery.java
index 0127f43..fa46b87 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceLambdaQuery.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceLambdaQuery.java
@@ -48,6 +48,7 @@
import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.LOWER_FREQUENCY;
import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.MC_POOL;
import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.UPPER_FREQUENCY;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.UUID;
import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.toMbpsFromHz;
import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.getChannelSpacing;
import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.getSlotGranularity;
@@ -92,7 +93,7 @@
log.error("Port {} does not exist", port);
return ImmutableSet.of();
}
- String uuid = p.annotations().value(port.toString());
+ String uuid = p.annotations().value(UUID);
try {
InputStream inputStream = controller.get(deviceId, SIP_REQUEST_DATA_API + uuid,
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiFlowRuleProgrammable.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiFlowRuleProgrammable.java
new file mode 100644
index 0000000..c0bea12
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiFlowRuleProgrammable.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ *
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.tapi;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
+import com.google.common.collect.ImmutableList;
+import org.apache.http.HttpStatus;
+import org.onosproject.drivers.odtn.impl.DeviceConnection;
+import org.onosproject.drivers.odtn.impl.DeviceConnectionCache;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleProgrammable;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.protocol.rest.RestSBController;
+import org.slf4j.Logger;
+
+import javax.ws.rs.core.MediaType;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.END_POINT;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.LAYER_PROTOCOL_NAME;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.LAYER_PROTOCOL_QUALIFIER;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.LOCAL_ID;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.PHOTONIC_MEDIA;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.POINT_TO_POINT_CONNECTIVITY;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.SERVICE_INTERFACE_POINT;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.SERVICE_INTERFACE_POINT_UUID;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.SERVICE_LAYER;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.SERVICE_TYPE;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.TAPI_CONNECTIVITY_CONNECTIVITY_SERVICE;
+import static org.onosproject.drivers.odtn.tapi.TapiDeviceHelper.TAPI_PHOTONIC_MEDIA_PHOTONIC_LAYER_QUALIFIER_NMC;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Driver Implementation of the DeviceDescrption discovery for ONF Transport-API (TAPI) v2.1 based
+ * open line systems (OLS).
+ */
+
+public class TapiFlowRuleProgrammable extends AbstractHandlerBehaviour
+ implements FlowRuleProgrammable {
+
+ private static final Logger log = getLogger(TapiFlowRuleProgrammable.class);
+ private static final String CONN_REQ_POST_API = "/restconf/data/tapi-common:context/" +
+ "tapi-connectivity:connectivity-context/";
+ private static final String CONN_REQ_REMOVE_DATA_API = "/restconf/data/tapi-common:context/" +
+ "tapi-connectivity:connectivity-context/connectivity-service=";
+ private static final String CONN_REQ_GET_API = "/restconf/data/tapi-common:context/" +
+ "tapi-connectivity:connectivity-context/";
+
+
+ @Override
+ public Collection<FlowEntry> getFlowEntries() {
+ DeviceId deviceId = did();
+ RestSBController controller = checkNotNull(handler().get(RestSBController.class));
+ ObjectMapper om = new ObjectMapper();
+ final ObjectReader reader = om.reader();
+ // all waveserver responses contain data node, which contains the requested data
+ InputStream response = controller.get(deviceId, CONN_REQ_GET_API, MediaType.APPLICATION_JSON_TYPE);
+ JsonNode jsonNode = null;
+ try {
+ jsonNode = reader.readTree(response);
+ if (jsonNode == null) {
+ log.error("JsonNode is null for response {}", response);
+ return ImmutableList.of();
+ }
+ Set<String> uuids = parseTapiGetConnectivityRequest(jsonNode);
+ DeviceConnectionCache cache = getConnectionCache();
+ if (cache.get(deviceId) == null) {
+ return ImmutableList.of();
+ }
+ List<FlowEntry> entries = new ArrayList<>();
+ uuids.forEach(uuid -> {
+ FlowRule rule = cache.get(deviceId, uuid);
+ if (rule != null) {
+ entries.add(new DefaultFlowEntry(rule, FlowEntry.FlowEntryState.ADDED, 0, 0, 0));
+ } else {
+ log.info("Non existing rule for uuid {}", uuid);
+ }
+ });
+ return entries;
+ } catch (IOException e) {
+ return ImmutableList.of();
+ }
+ }
+
+ @Override
+ public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
+ DeviceId deviceId = handler().data().deviceId();
+ RestSBController controller = checkNotNull(handler().get(RestSBController.class));
+ ImmutableList.Builder<FlowRule> added = ImmutableList.builder();
+ rules.forEach(flowRule -> {
+ String uuid = createUuid();
+ ByteArrayOutputStream applyConnectivityRequest = createConnectivityRequest(uuid, flowRule);
+ if (applyConnectivityRequest.size() != 0) {
+ int result = controller.post(deviceId, CONN_REQ_POST_API,
+ new ByteArrayInputStream(applyConnectivityRequest.toByteArray()),
+ MediaType.APPLICATION_JSON_TYPE);
+ // TODO retrieve the UUID from the location and store with that identifier
+ // at the moment is implied that the sent one is the same used by the TAPI server.
+ if (result == HttpStatus.SC_CREATED) {
+ getConnectionCache().add(deviceId, uuid, flowRule);
+ added.add(flowRule);
+ }
+ }
+ });
+ return added.build();
+ }
+
+ @Override
+ public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {
+ DeviceId deviceId = handler().data().deviceId();
+ RestSBController controller = checkNotNull(handler().get(RestSBController.class));
+ ImmutableList.Builder<FlowRule> removed = ImmutableList.builder();
+ rules.forEach(flowRule -> {
+ DeviceConnection conn = getConnectionCache().get(deviceId, flowRule.id());
+ if (conn == null || conn.getId() == null) {
+ log.warn("Can't find associate device connection for flow {} and device {}",
+ flowRule.id(), deviceId);
+ return;
+ }
+ int result = controller.delete(deviceId, CONN_REQ_REMOVE_DATA_API + conn.getId(),
+ null, MediaType.APPLICATION_JSON_TYPE);
+ if (result == HttpStatus.SC_NO_CONTENT) {
+ getConnectionCache().remove(deviceId, flowRule);
+ removed.add(flowRule);
+ }
+ });
+ return removed.build();
+ }
+
+ /**
+ * Get the deviceId for which the methods apply.
+ *
+ * @return The deviceId as contained in the handler data
+ */
+ private DeviceId did() {
+ return handler().data().deviceId();
+ }
+
+ private DeviceConnectionCache getConnectionCache() {
+ return DeviceConnectionCache.init();
+ }
+
+ protected Set<String> parseTapiGetConnectivityRequest(JsonNode tapiConnectivityReply) {
+ /*
+ {
+ "tapi-connectivity:connectivity-service":[
+ {
+ "uuid":"ffb006d4-349e-4d2f-817e-0906c88458d0",
+ <other fields>
+ }
+ ]
+ }
+ */
+ Set<String> uuids = new HashSet<>();
+ if (tapiConnectivityReply.has(TAPI_CONNECTIVITY_CONNECTIVITY_SERVICE)) {
+ tapiConnectivityReply.get(TAPI_CONNECTIVITY_CONNECTIVITY_SERVICE).elements()
+ .forEachRemaining(node -> uuids.add(node.get(TapiDeviceHelper.UUID).asText()));
+ } else {
+ log.warn("Cant retrieve connectivity UUID from {}", tapiConnectivityReply);
+ }
+ //This is only one uuid or empty in case of failures
+ return uuids;
+ }
+
+ ByteArrayOutputStream createConnectivityRequest(String uuid, FlowRule rule) {
+ /*
+ {
+ "tapi-connectivity:connectivity-service":[
+ {
+ "uuid":"ffb006d4-349e-4d2f-817e-0906c88458d0",
+ "service-layer":"PHOTONIC_MEDIA",
+ "service-type":"POINT_TO_POINT_CONNECTIVITY",
+ "end-point":[
+ {
+ "local-id":"1",
+ "layer-protocol-name":"PHOTONIC_MEDIA",
+ "layer-protocol-qualifier":"tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC",
+ "service-interface-point":{
+ "service-interface-point-uuid":"0923962e-b83f-4702-9b16-a1a0db0dc1f9"
+ }
+ },
+ {
+ "local-id":"2",
+ "layer-protocol-name":"PHOTONIC_MEDIA",
+ "layer-protocol-qualifier":"tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC",
+ "service-interface-point":{
+ "service-interface-point-uuid":"76be95de-5769-4e5d-b65e-62cb6c39cf6b "
+ }
+ }
+ ]
+ }
+ ]
+ }
+ */
+ DeviceService deviceService = handler().get(DeviceService.class);
+ PortCriterion inputPortCriterion = (PortCriterion) checkNotNull(rule.selector()
+ .getCriterion(Criterion.Type.IN_PORT));
+ String inputPortUuid = deviceService.getPort(rule.deviceId(),
+ inputPortCriterion.port()).annotations().value(TapiDeviceHelper.UUID);
+
+ Instructions.OutputInstruction outInstruction = (Instructions.OutputInstruction) checkNotNull(rule.treatment()
+ .allInstructions().stream().filter(instr -> instr.type().equals(Instruction.Type.OUTPUT))
+ .findFirst().orElse(null));
+ String outputPortUuid = deviceService.getPort(rule.deviceId(),
+ outInstruction.port()).annotations().value(TapiDeviceHelper.UUID);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ try {
+ JsonGenerator generator = getJsonGenerator(stream);
+ generator.writeStartObject();
+ generator.writeArrayFieldStart(TAPI_CONNECTIVITY_CONNECTIVITY_SERVICE);
+ generator.writeStartObject();
+ generator.writeStringField(TapiDeviceHelper.UUID, uuid);
+ generator.writeStringField(SERVICE_LAYER, PHOTONIC_MEDIA);
+ generator.writeStringField(SERVICE_TYPE, POINT_TO_POINT_CONNECTIVITY);
+ generator.writeArrayFieldStart(END_POINT);
+ addEndPoint(generator, inputPortUuid);
+ addEndPoint(generator, outputPortUuid);
+ generator.writeEndArray();
+ generator.writeEndObject();
+ generator.writeEndArray();
+ generator.writeEndObject();
+ generator.close();
+ return stream;
+ } catch (IOException e) {
+ log.error("Cant' create json", e);
+ }
+ return stream;
+ }
+
+ private JsonGenerator getJsonGenerator(ByteArrayOutputStream stream) throws IOException {
+ JsonFactory factory = new JsonFactory();
+ return factory.createGenerator(stream, JsonEncoding.UTF8);
+ }
+ /*
+ {
+ "local-id":"1",
+ "layer-protocol-name":"PHOTONIC_MEDIA",
+ "layer-protocol-qualifier":"tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC",
+ "service-interface-point":{
+ "service-interface-point-uuid":"0923962e-b83f-4702-9b16-a1a0db0dc1f9"
+ }
+ }
+ */
+ private void addEndPoint(JsonGenerator generator, String sipUuid) throws IOException {
+ generator.writeStartObject();
+ generator.writeStringField(LOCAL_ID, sipUuid);
+ generator.writeStringField(LAYER_PROTOCOL_NAME, PHOTONIC_MEDIA);
+ generator.writeStringField(LAYER_PROTOCOL_QUALIFIER,
+ TAPI_PHOTONIC_MEDIA_PHOTONIC_LAYER_QUALIFIER_NMC);
+ generator.writeObjectFieldStart(SERVICE_INTERFACE_POINT);
+ generator.writeStringField(SERVICE_INTERFACE_POINT_UUID, sipUuid);
+ generator.writeEndObject();
+ generator.writeEndObject();
+ }
+
+ private String createUuid() {
+ return UUID.randomUUID().toString();
+ }
+}
diff --git a/drivers/odtn-driver/src/main/resources/odtn-drivers.xml b/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
index 2472385..510abb7 100644
--- a/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
+++ b/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
@@ -20,8 +20,8 @@
impl="org.onosproject.drivers.odtn.tapi.TapiDeviceDescriptionDiscovery"/>
<behaviour api ="org.onosproject.net.behaviour.LambdaQuery"
impl="org.onosproject.drivers.odtn.tapi.TapiDeviceLambdaQuery"/>
- <!--<behaviour api="org.onosproject.net.flow.FlowRuleProgrammable"
- impl="org.onosproject.drivers.odtn.TapiFlowRuleProgrammable-->
+ <behaviour api="org.onosproject.net.flow.FlowRuleProgrammable"
+ impl="org.onosproject.drivers.odtn.tapi.TapiFlowRuleProgrammable"/>
</driver>
<driver name="odtn" manufacturer="" hwVersion="" swVersion="">
<behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"
diff --git a/drivers/odtn-driver/src/test/java/org/onosproject/drivers/odtn/tapi/TapiFlowRuleProgrammableTest.java b/drivers/odtn-driver/src/test/java/org/onosproject/drivers/odtn/tapi/TapiFlowRuleProgrammableTest.java
new file mode 100644
index 0000000..a3128af
--- /dev/null
+++ b/drivers/odtn-driver/src/test/java/org/onosproject/drivers/odtn/tapi/TapiFlowRuleProgrammableTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * 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.
+ *
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+package org.onosproject.drivers.odtn.tapi;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableSet;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.DefaultPort;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.GridType;
+import org.onosproject.net.Lambda;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OchSignalType;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.driver.Behaviour;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverData;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.provider.ProviderId;
+
+import java.io.IOException;
+import java.util.Set;
+
+import static junit.framework.TestCase.assertEquals;
+
+/**
+ * Tests for the TAPI Flow Rule Programmable.
+ */
+public class TapiFlowRuleProgrammableTest {
+
+ private static final DeviceId DEVICE_ID = DeviceId.deviceId("rest:127.0.0.1:8080");
+ private static final ApplicationId APP_ID = new DefaultApplicationId(1, "test_app_id");
+
+ private static final ProviderId PID = new ProviderId("rest", "foo");
+ private static final DefaultAnnotations DEVICE_ANNOTATIONS =
+ DefaultAnnotations.builder().set(AnnotationKeys.DRIVER, "foo").build();
+ private static final Device DEV =
+ new DefaultDevice(PID, DEVICE_ID, Device.Type.OLS, "", "", "", "", null, DEVICE_ANNOTATIONS);
+
+ private static final DefaultAnnotations PORT_ANNOTATIONS = DefaultAnnotations.builder()
+ .set(TapiDeviceHelper.UUID, "76be95de-5769-4e5d-b65e-62cb6c39cf6b").build();
+
+ private static final DefaultAnnotations PORT_ANNOTATIONS_2 = DefaultAnnotations.builder()
+ .set(TapiDeviceHelper.UUID, "0923962e-b83f-4702-9b16-a1a0db0dc1f9").build();
+
+ private static final PortNumber ONE = PortNumber.portNumber(1);
+ private static final PortNumber TWO = PortNumber.portNumber(2);
+
+ private static final Port PORT_IN = new DefaultPort(DEV, ONE, true, PORT_ANNOTATIONS);
+ private static final Port PORT_OUT = new DefaultPort(DEV, TWO, true, PORT_ANNOTATIONS_2);
+
+
+ private static final Lambda LAMBDA = new OchSignal(GridType.DWDM, ChannelSpacing.CHL_0GHZ, 1, 1);
+
+ private static final TrafficSelector SELECTOR = DefaultTrafficSelector.builder()
+ .matchInPort(ONE)
+ .add(Criteria.matchLambda(LAMBDA))
+ .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID))
+ .build();
+
+ private static final TrafficTreatment TREATMENT = DefaultTrafficTreatment.builder()
+ .add(Instructions.modL0Lambda(LAMBDA))
+ .setOutput(TWO)
+ .build();
+
+ private static final FlowRule FLOW_RULE = DefaultFlowRule.builder()
+ .forDevice(DEVICE_ID)
+ .withSelector(SELECTOR)
+ .withTreatment(TREATMENT)
+ .withPriority(1)
+ .fromApp(APP_ID)
+ .makePermanent()
+ .build();
+
+ private static final String CONNECTION_UUID = "30c3e74c-0e3c-40b3-9e26-221c56e995c2";
+ private static final String END_POINT_1_UUID = "76be95de-5769-4e5d-b65e-62cb6c39cf6b";
+ private static final String END_POINT_2_UUID = "0923962e-b83f-4702-9b16-a1a0db0dc1f9";
+
+ private static final String CONNECTIVITY_REQUEST = "{\"tapi-connectivity:connectivity-service\":" +
+ "[{\"uuid\":\"" + CONNECTION_UUID + "\",\"service-layer\":\"PHOTONIC_MEDIA\",\"service-type\"" +
+ ":\"POINT_TO_POINT_CONNECTIVITY\",\"end-point\":[{\"local-id\":\"" + END_POINT_1_UUID + "\"," +
+ "\"layer-protocol-name\":" + "\"PHOTONIC_MEDIA\",\"layer-protocol-qualifier\":" +
+ "\"tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC\"," + "\"service-interface-point\":" +
+ "{\"service-interface-point-uuid\":\"" + END_POINT_1_UUID + "\"}}," +
+ "{\"local-id\":\"" + END_POINT_2_UUID + "\",\"layer-protocol-name\":\"PHOTONIC_MEDIA\"," +
+ "\"layer-protocol-qualifier\":" + "\"tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC\"," +
+ "\"service-interface-point\":{" + "\"service-interface-point-uuid\":\"" + END_POINT_2_UUID + "\"}}]}]}";
+
+ private static final String GET_CONNECTIVITY_REQUEST_REPLY = "{\"tapi-connectivity:connectivity-service\" : " +
+ "[{\"uuid\" : \"" + CONNECTION_UUID + "\"}]}";
+
+ private static final Set<String> CONNECTION_UUIDS = ImmutableSet.of(CONNECTION_UUID);
+
+ private TapiFlowRuleProgrammable tapiFrp;
+
+ @Before
+ public void setUp() throws Exception {
+ tapiFrp = new TapiFlowRuleProgrammable();
+ DriverHandler mockHandler = new InternalDriverHandler();
+ tapiFrp.setHandler(mockHandler);
+ }
+
+ @Test
+ public void createConnRequest() {
+ String output = tapiFrp.createConnectivityRequest(CONNECTION_UUID, FLOW_RULE).toString();
+ System.out.println(output);
+ assertEquals("Json to create network connectivity is wrong", CONNECTIVITY_REQUEST, output);
+ }
+
+ @Test
+ public void parseConnReply() throws IOException {
+ TapiFlowRuleProgrammable tapiFrp = new TapiFlowRuleProgrammable();
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode jsonReply = mapper.readTree(GET_CONNECTIVITY_REQUEST_REPLY);
+ Set<String> output = tapiFrp.parseTapiGetConnectivityRequest(jsonReply);
+ assertEquals("Wrong Tapi UUIDS", CONNECTION_UUIDS, output);
+ }
+
+ private class InternalDriverHandler implements DriverHandler {
+
+ @Override
+ public Driver driver() {
+ return null;
+ }
+
+ @Override
+ public DriverData data() {
+ return null;
+ }
+
+ @Override
+ public <T extends Behaviour> T behaviour(Class<T> behaviourClass) {
+ return null;
+ }
+
+ @Override
+ public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
+ return false;
+ }
+
+ @Override
+ public <T> T get(Class<T> serviceClass) {
+ if (serviceClass.equals(DeviceService.class)) {
+ return (T) new InternalDeviceService();
+ }
+ return null;
+ }
+ }
+
+ private class InternalDeviceService extends DeviceServiceAdapter {
+ @Override
+ public Port getPort(DeviceId deviceId, PortNumber portNumber) {
+ if (portNumber.equals(ONE)) {
+ return PORT_IN;
+ } else {
+ return PORT_OUT;
+ }
+ }
+ }
+}
\ No newline at end of file