blob: e2c12c95ce06e3fe58b7652390df9d338e69cfc0 [file] [log] [blame]
Diego Garcia09ab5e22018-12-18 11:47:01 +01001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * This work was partially supported by EC H2020 project METRO-HAUL (761727).
17 */
18package org.onosproject.drivers.odtn.tapi;
19
20import com.fasterxml.jackson.databind.JsonNode;
21import com.fasterxml.jackson.databind.ObjectMapper;
22import com.google.common.collect.ImmutableList;
23import com.google.common.collect.Lists;
24import org.onlab.packet.ChassisId;
25import org.onosproject.net.Device;
26import org.onosproject.net.PortNumber;
27import org.onosproject.net.DeviceId;
28import org.onosproject.net.device.PortDescription;
29import org.onosproject.net.device.DefaultDeviceDescription;
30import org.onosproject.net.device.DeviceDescription;
31import org.onosproject.net.device.DeviceDescriptionDiscovery;
32import org.onosproject.net.device.DeviceService;
33import org.onosproject.net.driver.AbstractHandlerBehaviour;
34import org.onosproject.net.OchSignal;
35import org.onosproject.net.OduSignalType;
36import org.onosproject.net.GridType;
37import org.onosproject.net.ChannelSpacing;
38import org.onosproject.net.DefaultAnnotations;
39import org.onosproject.protocol.rest.RestSBController;
40import org.slf4j.Logger;
41
42import javax.ws.rs.core.MediaType;
43import java.io.IOException;
44import java.io.InputStream;
45import java.util.Iterator;
46import java.util.List;
47
48import static com.google.common.base.Preconditions.checkNotNull;
49import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
50import static org.slf4j.LoggerFactory.getLogger;
51
52/**
53 * Driver Implementation of the DeviceDescrption discovery for ONF Transport-API (TAPI) v2.1 based
54 * open line systems (OLS).
55 */
56
57public class TapiDeviceDescriptionDiscovery
58 extends AbstractHandlerBehaviour
59 implements DeviceDescriptionDiscovery {
60
61 private static final Logger log = getLogger(TapiDeviceDescriptionDiscovery.class);
62 private static final String SIP_REQUEST_DATA_API = "/data/context/";
63 public static final String SERVICE_INTERFACE_POINT = "service-interface-point";
64 public static final String UUID = "uuid";
65 public static final String MEDIA_CHANNEL_SERVICE_INTERFACE_POINT_SPEC =
66 "media-channel-service-interface-point-spec";
67 public static final String MC_POOL = "mc-pool";
68 public static final String LAYER_PROTOCOL_NAME = "layer-protocol-name";
69 public static final String PHOTONIC_MEDIA = "PHOTONIC_MEDIA";
70 public static final String SUPPORTED_LAYER_PROTOCOL_QUALIFIER = "supported-layer-protocol-qualifier";
71 public static final String PHOTONIC_LAYER_QUALIFIER_NMC = "PHOTONIC_LAYER_QUALIFIER_NMC";
72 public static final String FREQUENCY_CONSTRAINT = "frequency-constraint";
73 public static final String GRID_TYPE = "grid-type";
74 public static final String ADJUSTMENT_GRANULARITY = "adjustment-granularity";
75 public static final String UPPER_FREQUENCY = "upper-frequency";
76 public static final String LOWER_FREQUENCY = "lower-frequency";
77 public static final String AVAILABLE_SPECTRUM = "available-spectrum";
78 private static PortNumber nPort = PortNumber.portNumber(1);
79 private static final long BASE_FREQUENCY = 193100000; //Working in Mhz
80
81 /**
82 * Get the deviceId for which the methods apply.
83 *
84 * @return The deviceId as contained in the handler data
85 */
86 private DeviceId did() {
87 return handler().data().deviceId();
88 }
89
90 @Override
91 public DeviceDescription discoverDeviceDetails() {
92 log.debug("Getting device description");
93 DeviceService deviceService = checkNotNull(handler().get(DeviceService.class));
94 DeviceId deviceId = handler().data().deviceId();
95 Device device = deviceService.getDevice(deviceId);
96
97 if (device == null) {
98 return new DefaultDeviceDescription(deviceId.uri(),
99 Device.Type.OLS,
100 "tapi-swagger",
101 "0",
102 "2.1",
103 "Unknown",
104 new ChassisId());
105 } else {
106 return new DefaultDeviceDescription(device.id().uri(),
107 Device.Type.OLS,
108 device.manufacturer(),
109 device.hwVersion(),
110 device.swVersion(),
111 device.serialNumber(),
112 device.chassisId());
113 }
114 }
115
116 @Override
117 public List<PortDescription> discoverPortDetails() {
118 log.debug("Discovering port details.");
119 RestSBController controller = checkNotNull(handler().get(RestSBController.class));
120 DeviceId deviceId = handler().data().deviceId();
121
122 try {
123 InputStream inputStream = controller.get(deviceId, SIP_REQUEST_DATA_API, MediaType.APPLICATION_JSON_TYPE);
124 JsonNode jsonNode = new ObjectMapper().readTree(inputStream);
125 return parseTapiPorts(jsonNode);
126 } catch (IOException e) {
127 log.error("Exception discoverPortDetails() {}", did(), e);
128 return ImmutableList.of();
129 }
130 }
131
132 protected List<PortDescription> parseTapiPorts(JsonNode tapiContext) {
133 List<PortDescription> ports = Lists.newArrayList();
134 int counter = 0;
135
136 /**
137 This annotations are used to store persistent mapping information between TAPI SIP's uuid
138 and ONOS device portNumbers. This is needed to be publicly available at least within ODTN app
139 when connectivity services will be sent to OLS Controller.
140 **/
141 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder();
142
143 JsonNode sips = tapiContext.get(SERVICE_INTERFACE_POINT);
144 Iterator<JsonNode> iter = sips.iterator();
145 while (iter.hasNext()) {
146 JsonNode sipAttributes = iter.next();
147 if (checkValidEndpoint(sipAttributes)) {
148 String uuid = sipAttributes.get(UUID).textValue();
149 JsonNode mcPool = sipAttributes.get(MEDIA_CHANNEL_SERVICE_INTERFACE_POINT_SPEC).get(MC_POOL);
150
151 OchSignal ochSignal = getOchSignal(mcPool);
152 //annotations(portNumber-uuid)
153 annotations.set(nPort.toString(), uuid);
154
155 //add och port
156 ports.add(ochPortDescription(nPort, true, OduSignalType.ODU4,
157 false, ochSignal, annotations.build()));
158
159 nPort = PortNumber.portNumber(counter++);
160 } else {
161 log.error("SIP {} is not valid", sipAttributes);
162 }
163 }
164 log.debug("PortList: {}", ports);
165 return ImmutableList.copyOf(ports);
166 }
167
168 /**
169 * Create a filter method to identify just valid OLS SIPs.This method must check the
170 * tapi object: "layer-protocol-name" and matching only if equals to "PHOTONIC-MEDIA" SIPs.
171 * Moreover,the filtering could be enhanced by reading also:
172 * "supported-layer-protocol-qualifier", to identify valid protocol-qualifier values such:
173 * [PHOTONIC_LAYER_QUALIFIER_NMC, PHOTONIC_LAYER_QUALIFIER_NMCA, PHOTONIC_LAYER_QUALIFIER_OTSI...]
174 **/
175 private boolean checkValidEndpoint(JsonNode sipAttributes) {
176 return (sipAttributes.get(LAYER_PROTOCOL_NAME).toString().contains(PHOTONIC_MEDIA) &&
177 sipAttributes.get(SUPPORTED_LAYER_PROTOCOL_QUALIFIER).toString()
178 .contains(PHOTONIC_LAYER_QUALIFIER_NMC));
179 }
180
181 /**
182 * If SIP info match our criteria, SIP component shall includes mc-pool information which must be obtained in order
183 * to complete the OchSignal info. with the TAPI SIP information included in spectrum-supported, spectrum-available
184 * and spectrum-occupied tapi objects.
185 **/
186 private OchSignal getOchSignal(JsonNode mcPool) {
187 long availableUpperFrec = 0, availableLowerFrec = 0;
188 String availableAdjustmentGranularity = "", availableGridType = "";
189 JsonNode availableSpectrum = mcPool.get(AVAILABLE_SPECTRUM);
190
191 /**At this time only the latest availableSpectrum is used**/
192 Iterator<JsonNode> iterAvailable = availableSpectrum.iterator();
193 while (iterAvailable.hasNext()) {
194 JsonNode availableSpec = iterAvailable.next();
195 availableUpperFrec = availableSpec.get(UPPER_FREQUENCY).asLong();
196 availableLowerFrec = availableSpec.get(LOWER_FREQUENCY).asLong();
197 availableAdjustmentGranularity = availableSpec.get(FREQUENCY_CONSTRAINT)
198 .get(ADJUSTMENT_GRANULARITY).textValue();
199 availableGridType = availableSpec.get(FREQUENCY_CONSTRAINT).get(GRID_TYPE).textValue();
200 }
201
202 int spacingMult = 0, slotGranularity = 1;
203 ChannelSpacing chSpacing = getChannelSpacing(availableAdjustmentGranularity);
204 long spacingFrequency = chSpacing.frequency().asHz();
205 long centralFrequency = (availableUpperFrec - (availableUpperFrec - availableLowerFrec) / 2);
206
207 GridType gridType = getGridType(availableGridType);
208 if (gridType == GridType.DWDM) {
209 spacingMult = (int) ((centralFrequency - BASE_FREQUENCY) / toMbpsFromHz(spacingFrequency));
210 } else if (gridType == GridType.CWDM) {
211 log.warn("GridType CWDM. Not implemented");
212 } else if (gridType == GridType.FLEX) {
213 log.warn("GridType FLEX. Not implemented");
214 slotGranularity = getSlotGranularity(chSpacing);
215 } else {
216 log.warn("Unknown GridType");
217 }
218 return new OchSignal(gridType, chSpacing, spacingMult, slotGranularity);
219 }
220
221 private int getSlotGranularity(ChannelSpacing chSpacing) {
222 if (chSpacing.equals(ChannelSpacing.CHL_100GHZ)) {
223 return 8;
224 } else if (chSpacing.equals(ChannelSpacing.CHL_50GHZ)) {
225 return 4;
226 } else if (chSpacing.equals(ChannelSpacing.CHL_25GHZ)) {
227 return 2;
228 } else if (chSpacing.equals(ChannelSpacing.CHL_12P5GHZ)) {
229 return 1;
230 } else {
231 return 0;
232 }
233 }
234
235 private GridType getGridType(String gridType) {
236 switch (gridType) {
237 case "DWDM":
238 return GridType.DWDM;
239 case "CWDM":
240 return GridType.CWDM;
241 case "FLEX":
242 return GridType.FLEX;
243 default:
244 return GridType.UNKNOWN;
245 }
246 }
247
248 private ChannelSpacing getChannelSpacing(String adjustmentGranularity) {
249 switch (adjustmentGranularity) {
250 case "G_100GHZ ":
251 return ChannelSpacing.CHL_100GHZ;
252 case "G_50GHZ":
253 return ChannelSpacing.CHL_50GHZ;
254 case "G_25GHZ":
255 return ChannelSpacing.CHL_25GHZ;
256 case "G_12_5GHZ ":
257 return ChannelSpacing.CHL_12P5GHZ;
258 case "G_6_25GHZ ":
259 return ChannelSpacing.CHL_6P25GHZ;
260 default:
261 return ChannelSpacing.CHL_0GHZ;
262 }
263 }
264
265 private static long toMbpsFromHz(long speed) {
266 return speed / 1000000;
267 }
268
269}