diff --git a/core/api/src/main/java/org/onosproject/net/ChannelSpacing.java b/core/api/src/main/java/org/onosproject/net/ChannelSpacing.java index bae78e9277..2b21f9191e 100644 --- a/core/api/src/main/java/org/onosproject/net/ChannelSpacing.java +++ b/core/api/src/main/java/org/onosproject/net/ChannelSpacing.java @@ -25,7 +25,8 @@ public enum ChannelSpacing { CHL_50GHZ(50_000), // 50 GHz CHL_25GHZ(25_000), // 25 GHz CHL_12P5GHZ(12_500), // 12.5 GHz - CHL_6P25GHZ(6_250); // 6.25 GHz + CHL_6P25GHZ(6_250), // 6.25 GHz + CHL_0GHZ(0); // 0 GHz (Unknown) private final Frequency frequency; diff --git a/drivers/odtn-driver/BUILD b/drivers/odtn-driver/BUILD index 657d568812..bb48507280 100644 --- a/drivers/odtn-driver/BUILD +++ b/drivers/odtn-driver/BUILD @@ -2,7 +2,10 @@ COMPILE_DEPS = CORE_DEPS + [ "@commons_jxpath//jar", "//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", ] @@ -30,6 +33,7 @@ onos_app( description = "Drivers related to ODTN", included_bundles = BUNDLES, required_apps = [ + "org.onosproject.restsb", "org.onosproject.netconf", "org.onosproject.config", "org.onosproject.odtn-api", 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 new file mode 100644 index 0000000000..e2c12c95ce --- /dev/null +++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/TapiDeviceDescriptionDiscovery.java @@ -0,0 +1,269 @@ +/* + * 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.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import org.onlab.packet.ChassisId; +import org.onosproject.net.Device; +import org.onosproject.net.PortNumber; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.PortDescription; +import org.onosproject.net.device.DefaultDeviceDescription; +import org.onosproject.net.device.DeviceDescription; +import org.onosproject.net.device.DeviceDescriptionDiscovery; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.driver.AbstractHandlerBehaviour; +import org.onosproject.net.OchSignal; +import org.onosproject.net.OduSignalType; +import org.onosproject.net.GridType; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.protocol.rest.RestSBController; +import org.slf4j.Logger; + +import javax.ws.rs.core.MediaType; +import java.io.IOException; +import java.io.InputStream; +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription; +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 TapiDeviceDescriptionDiscovery + extends AbstractHandlerBehaviour + implements DeviceDescriptionDiscovery { + + private static final Logger log = getLogger(TapiDeviceDescriptionDiscovery.class); + private static final String SIP_REQUEST_DATA_API = "/data/context/"; + public static final String SERVICE_INTERFACE_POINT = "service-interface-point"; + public static final String UUID = "uuid"; + public static final String MEDIA_CHANNEL_SERVICE_INTERFACE_POINT_SPEC = + "media-channel-service-interface-point-spec"; + public static final String MC_POOL = "mc-pool"; + public static final String LAYER_PROTOCOL_NAME = "layer-protocol-name"; + public static final String PHOTONIC_MEDIA = "PHOTONIC_MEDIA"; + public static final String SUPPORTED_LAYER_PROTOCOL_QUALIFIER = "supported-layer-protocol-qualifier"; + public static final String PHOTONIC_LAYER_QUALIFIER_NMC = "PHOTONIC_LAYER_QUALIFIER_NMC"; + public static final String FREQUENCY_CONSTRAINT = "frequency-constraint"; + public static final String GRID_TYPE = "grid-type"; + public static final String ADJUSTMENT_GRANULARITY = "adjustment-granularity"; + public static final String UPPER_FREQUENCY = "upper-frequency"; + public static final String LOWER_FREQUENCY = "lower-frequency"; + public static final String AVAILABLE_SPECTRUM = "available-spectrum"; + private static PortNumber nPort = PortNumber.portNumber(1); + private static final long BASE_FREQUENCY = 193100000; //Working in Mhz + + /** + * Get the deviceId for which the methods apply. + * + * @return The deviceId as contained in the handler data + */ + private DeviceId did() { + return handler().data().deviceId(); + } + + @Override + public DeviceDescription discoverDeviceDetails() { + log.debug("Getting device description"); + DeviceService deviceService = checkNotNull(handler().get(DeviceService.class)); + DeviceId deviceId = handler().data().deviceId(); + Device device = deviceService.getDevice(deviceId); + + if (device == null) { + return new DefaultDeviceDescription(deviceId.uri(), + Device.Type.OLS, + "tapi-swagger", + "0", + "2.1", + "Unknown", + new ChassisId()); + } else { + return new DefaultDeviceDescription(device.id().uri(), + Device.Type.OLS, + device.manufacturer(), + device.hwVersion(), + device.swVersion(), + device.serialNumber(), + device.chassisId()); + } + } + + @Override + public List discoverPortDetails() { + log.debug("Discovering port details."); + RestSBController controller = checkNotNull(handler().get(RestSBController.class)); + DeviceId deviceId = handler().data().deviceId(); + + try { + InputStream inputStream = controller.get(deviceId, SIP_REQUEST_DATA_API, MediaType.APPLICATION_JSON_TYPE); + JsonNode jsonNode = new ObjectMapper().readTree(inputStream); + return parseTapiPorts(jsonNode); + } catch (IOException e) { + log.error("Exception discoverPortDetails() {}", did(), e); + return ImmutableList.of(); + } + } + + protected List parseTapiPorts(JsonNode tapiContext) { + List ports = Lists.newArrayList(); + int counter = 0; + + /** + This annotations are used to store persistent mapping information between TAPI SIP's uuid + and ONOS device portNumbers. This is needed to be publicly available at least within ODTN app + when connectivity services will be sent to OLS Controller. + **/ + DefaultAnnotations.Builder annotations = DefaultAnnotations.builder(); + + JsonNode sips = tapiContext.get(SERVICE_INTERFACE_POINT); + Iterator iter = sips.iterator(); + while (iter.hasNext()) { + JsonNode sipAttributes = iter.next(); + if (checkValidEndpoint(sipAttributes)) { + String uuid = sipAttributes.get(UUID).textValue(); + JsonNode mcPool = sipAttributes.get(MEDIA_CHANNEL_SERVICE_INTERFACE_POINT_SPEC).get(MC_POOL); + + OchSignal ochSignal = getOchSignal(mcPool); + //annotations(portNumber-uuid) + annotations.set(nPort.toString(), uuid); + + //add och port + ports.add(ochPortDescription(nPort, true, OduSignalType.ODU4, + false, ochSignal, annotations.build())); + + nPort = PortNumber.portNumber(counter++); + } else { + log.error("SIP {} is not valid", sipAttributes); + } + } + log.debug("PortList: {}", ports); + return ImmutableList.copyOf(ports); + } + + /** + * Create a filter method to identify just valid OLS SIPs.This method must check the + * tapi object: "layer-protocol-name" and matching only if equals to "PHOTONIC-MEDIA" SIPs. + * Moreover,the filtering could be enhanced by reading also: + * "supported-layer-protocol-qualifier", to identify valid protocol-qualifier values such: + * [PHOTONIC_LAYER_QUALIFIER_NMC, PHOTONIC_LAYER_QUALIFIER_NMCA, PHOTONIC_LAYER_QUALIFIER_OTSI...] + **/ + private boolean checkValidEndpoint(JsonNode sipAttributes) { + return (sipAttributes.get(LAYER_PROTOCOL_NAME).toString().contains(PHOTONIC_MEDIA) && + sipAttributes.get(SUPPORTED_LAYER_PROTOCOL_QUALIFIER).toString() + .contains(PHOTONIC_LAYER_QUALIFIER_NMC)); + } + + /** + * If SIP info match our criteria, SIP component shall includes mc-pool information which must be obtained in order + * to complete the OchSignal info. with the TAPI SIP information included in spectrum-supported, spectrum-available + * and spectrum-occupied tapi objects. + **/ + private OchSignal getOchSignal(JsonNode mcPool) { + long availableUpperFrec = 0, availableLowerFrec = 0; + String availableAdjustmentGranularity = "", availableGridType = ""; + JsonNode availableSpectrum = mcPool.get(AVAILABLE_SPECTRUM); + + /**At this time only the latest availableSpectrum is used**/ + Iterator iterAvailable = availableSpectrum.iterator(); + while (iterAvailable.hasNext()) { + JsonNode availableSpec = iterAvailable.next(); + availableUpperFrec = availableSpec.get(UPPER_FREQUENCY).asLong(); + availableLowerFrec = availableSpec.get(LOWER_FREQUENCY).asLong(); + availableAdjustmentGranularity = availableSpec.get(FREQUENCY_CONSTRAINT) + .get(ADJUSTMENT_GRANULARITY).textValue(); + availableGridType = availableSpec.get(FREQUENCY_CONSTRAINT).get(GRID_TYPE).textValue(); + } + + int spacingMult = 0, slotGranularity = 1; + ChannelSpacing chSpacing = getChannelSpacing(availableAdjustmentGranularity); + long spacingFrequency = chSpacing.frequency().asHz(); + long centralFrequency = (availableUpperFrec - (availableUpperFrec - availableLowerFrec) / 2); + + GridType gridType = getGridType(availableGridType); + if (gridType == GridType.DWDM) { + spacingMult = (int) ((centralFrequency - BASE_FREQUENCY) / toMbpsFromHz(spacingFrequency)); + } else if (gridType == GridType.CWDM) { + log.warn("GridType CWDM. Not implemented"); + } else if (gridType == GridType.FLEX) { + log.warn("GridType FLEX. Not implemented"); + slotGranularity = getSlotGranularity(chSpacing); + } else { + log.warn("Unknown GridType"); + } + return new OchSignal(gridType, chSpacing, spacingMult, slotGranularity); + } + + private int getSlotGranularity(ChannelSpacing chSpacing) { + if (chSpacing.equals(ChannelSpacing.CHL_100GHZ)) { + return 8; + } else if (chSpacing.equals(ChannelSpacing.CHL_50GHZ)) { + return 4; + } else if (chSpacing.equals(ChannelSpacing.CHL_25GHZ)) { + return 2; + } else if (chSpacing.equals(ChannelSpacing.CHL_12P5GHZ)) { + return 1; + } else { + return 0; + } + } + + private GridType getGridType(String gridType) { + switch (gridType) { + case "DWDM": + return GridType.DWDM; + case "CWDM": + return GridType.CWDM; + case "FLEX": + return GridType.FLEX; + default: + return GridType.UNKNOWN; + } + } + + private ChannelSpacing getChannelSpacing(String adjustmentGranularity) { + switch (adjustmentGranularity) { + case "G_100GHZ ": + return ChannelSpacing.CHL_100GHZ; + case "G_50GHZ": + return ChannelSpacing.CHL_50GHZ; + case "G_25GHZ": + return ChannelSpacing.CHL_25GHZ; + case "G_12_5GHZ ": + return ChannelSpacing.CHL_12P5GHZ; + case "G_6_25GHZ ": + return ChannelSpacing.CHL_6P25GHZ; + default: + return ChannelSpacing.CHL_0GHZ; + } + } + + private static long toMbpsFromHz(long speed) { + return speed / 1000000; + } + +} diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/package-info.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/package-info.java new file mode 100644 index 0000000000..25dc05c326 --- /dev/null +++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/tapi/package-info.java @@ -0,0 +1,19 @@ +/* + * 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. + */ +/** + * ODTN Driver. + */ +package org.onosproject.drivers.odtn.tapi; diff --git a/drivers/odtn-driver/src/main/resources/odtn-drivers.xml b/drivers/odtn-driver/src/main/resources/odtn-drivers.xml index e4e6890cdd..bd3dff4630 100644 --- a/drivers/odtn-driver/src/main/resources/odtn-drivers.xml +++ b/drivers/odtn-driver/src/main/resources/odtn-drivers.xml @@ -15,6 +15,12 @@ ~ limitations under the License. --> + + + +