blob: d73daeb98089fbac4270bcb9d0e6f18fefe24f91 [file] [log] [blame]
Diego Garciaaab99472019-01-10 13:53:31 +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
Andrea Campanellab9e491b2019-02-18 17:45:01 +010020import com.fasterxml.jackson.databind.JsonNode;
Andrea Campanellae4b2c682019-08-23 15:42:55 +020021import com.fasterxml.jackson.databind.ObjectMapper;
22import com.fasterxml.jackson.databind.ObjectReader;
23import com.google.common.collect.ImmutableSet;
24import org.apache.http.HttpStatus;
25import org.onosproject.drivers.odtn.impl.DeviceConnectionCache;
Diego Garciaaab99472019-01-10 13:53:31 +010026import org.onosproject.net.ChannelSpacing;
Andrea Campanellae4b2c682019-08-23 15:42:55 +020027import org.onosproject.net.DeviceId;
Andrea Campanellab9e491b2019-02-18 17:45:01 +010028import org.onosproject.net.GridType;
29import org.onosproject.net.OchSignal;
Andrea Campanellae4b2c682019-08-23 15:42:55 +020030import org.onosproject.net.driver.DriverHandler;
31import org.onosproject.protocol.rest.RestSBController;
Andrea Campanellab9e491b2019-02-18 17:45:01 +010032import org.slf4j.Logger;
33
Andrea Campanellae4b2c682019-08-23 15:42:55 +020034import javax.ws.rs.core.MediaType;
35import java.io.IOException;
36import java.io.InputStream;
37import java.util.HashSet;
Andrea Campanellab9e491b2019-02-18 17:45:01 +010038import java.util.Iterator;
39import java.util.LinkedHashSet;
40import java.util.Set;
Andrea Campanellae4b2c682019-08-23 15:42:55 +020041import java.util.concurrent.CompletableFuture;
Andrea Campanellab9e491b2019-02-18 17:45:01 +010042import java.util.stream.IntStream;
43
Andrea Campanellae4b2c682019-08-23 15:42:55 +020044import static com.google.common.base.Preconditions.checkNotNull;
Andrea Campanellab9e491b2019-02-18 17:45:01 +010045import static org.slf4j.LoggerFactory.getLogger;
Diego Garciaaab99472019-01-10 13:53:31 +010046
47/**
48 * Tapi 2.1 OLS device related helpers.
49 */
50public final class TapiDeviceHelper {
51
Andrea Campanellab9e491b2019-02-18 17:45:01 +010052 private static final Logger log = getLogger(TapiDeviceHelper.class);
53
Diego Garciaaab99472019-01-10 13:53:31 +010054 public static final String SERVICE_INTERFACE_POINT = "service-interface-point";
Andrea Campanella3d2ba462019-08-22 16:29:21 +020055 public static final String TAPI_COMMON = "tapi-common";
Andrea Campanellab9e491b2019-02-18 17:45:01 +010056 public static final String CONTEXT = "tapi-common:context";
Diego Garciaaab99472019-01-10 13:53:31 +010057 public static final String UUID = "uuid";
58 public static final String MEDIA_CHANNEL_SERVICE_INTERFACE_POINT_SPEC =
Andrea Campanellab9e491b2019-02-18 17:45:01 +010059 "tapi-photonic-media:media-channel-service-interface-point-spec";
Diego Garciaaab99472019-01-10 13:53:31 +010060 public static final String MC_POOL = "mc-pool";
61 public static final String LAYER_PROTOCOL_NAME = "layer-protocol-name";
62 public static final String PHOTONIC_MEDIA = "PHOTONIC_MEDIA";
63 public static final String SUPPORTED_LAYER_PROTOCOL_QUALIFIER = "supported-layer-protocol-qualifier";
64 public static final String PHOTONIC_LAYER_QUALIFIER_NMC = "PHOTONIC_LAYER_QUALIFIER_NMC";
65 public static final String FREQUENCY_CONSTRAINT = "frequency-constraint";
66 public static final String GRID_TYPE = "grid-type";
67 public static final String ADJUSTMENT_GRANULARITY = "adjustment-granularity";
68 public static final String UPPER_FREQUENCY = "upper-frequency";
69 public static final String LOWER_FREQUENCY = "lower-frequency";
Diego Garciaaab99472019-01-10 13:53:31 +010070 public static final long BASE_FREQUENCY = 193100000; //Working in Mhz
Andrea Campanella2bdf2042019-01-28 13:47:11 +010071 public static final String TAPI_CONNECTIVITY_CONNECTIVITY_SERVICE = "tapi-connectivity:connectivity-service";
Andrea Campanellae4b2c682019-08-23 15:42:55 +020072 public static final String TAPI_CONNECTIVITY_CONNECTIVITY_CONTEXT = "tapi-connectivity:connectivity-context";
73 public static final String CONNECTIVITY_SERVICE = "connectivity-service";
Andrea Campanella2bdf2042019-01-28 13:47:11 +010074 public static final String END_POINT = "end-point";
75 public static final String SERVICE_LAYER = "service-layer";
76 public static final String SERVICE_TYPE = "service-type";
77 public static final String POINT_TO_POINT_CONNECTIVITY = "POINT_TO_POINT_CONNECTIVITY";
78 public static final String LOCAL_ID = "local-id";
79 public static final String LAYER_PROTOCOL_QUALIFIER = "layer-protocol-qualifier";
80 public static final String TAPI_PHOTONIC_MEDIA_PHOTONIC_LAYER_QUALIFIER_NMC =
81 "tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC";
82 public static final String SERVICE_INTERFACE_POINT_UUID = "service-interface-point-uuid";
Andrea Campanellab9e491b2019-02-18 17:45:01 +010083 public static final String AVAILABLE_SPECTRUM = "available-spectrum";
84 protected static final String SUPPORTABLE_SPECTRUM = "supportable-spectrum";
Diego Garciaaab99472019-01-10 13:53:31 +010085
Andrea Campanellae4b2c682019-08-23 15:42:55 +020086 protected static final String CONN_REQ_POST_API = "/restconf/data/tapi-common:context/" +
87 "tapi-connectivity:connectivity-context/";
88 protected static final String CONN_REQ_REMOVE_DATA_API = "/restconf/data/tapi-common:context/" +
89 "tapi-connectivity:connectivity-context/connectivity-service=";
90 protected static final String CONN_REQ_GET_API = "/restconf/data/tapi-common:context/" +
91 "tapi-connectivity:connectivity-context/";
92
93 private TapiDeviceHelper() {
94 }
Diego Garciaaab99472019-01-10 13:53:31 +010095
96 /**
97 * Returns the slot granularity corresponding to a channelSpacing.
98 *
Andrea Campanellae4b2c682019-08-23 15:42:55 +020099 * @param chSpacing OchSingal channel spacing {@link ChannelSpacing}
Diego Garciaaab99472019-01-10 13:53:31 +0100100 * @return OchSignal slot width granularity
101 */
102 public static int getSlotGranularity(ChannelSpacing chSpacing) {
103 if (chSpacing.equals(ChannelSpacing.CHL_100GHZ)) {
104 return 8;
105 } else if (chSpacing.equals(ChannelSpacing.CHL_50GHZ)) {
106 return 4;
107 } else if (chSpacing.equals(ChannelSpacing.CHL_25GHZ)) {
108 return 2;
109 } else if (chSpacing.equals(ChannelSpacing.CHL_12P5GHZ)) {
110 return 1;
111 } else {
112 return 0;
113 }
114 }
115
116 /**
117 * Returns the ChannelSpacing corresponding to an adjustmentGranularity.
118 *
119 * @param adjustmentGranularity {@link String}
120 * @return OchSingnal ChannelSpacing {@link ChannelSpacing}
121 */
122 public static ChannelSpacing getChannelSpacing(String adjustmentGranularity) {
123 switch (adjustmentGranularity) {
124 case "G_100GHZ ":
125 return ChannelSpacing.CHL_100GHZ;
126 case "G_50GHZ":
127 return ChannelSpacing.CHL_50GHZ;
128 case "G_25GHZ":
129 return ChannelSpacing.CHL_25GHZ;
130 case "G_12_5GHZ ":
131 return ChannelSpacing.CHL_12P5GHZ;
132 case "G_6_25GHZ ":
133 return ChannelSpacing.CHL_6P25GHZ;
134 default:
135 return ChannelSpacing.CHL_0GHZ;
136 }
137 }
138
139 /**
Andrea Campanellae4b2c682019-08-23 15:42:55 +0200140 * To Mbps conversion from Hz.
Diego Garciaaab99472019-01-10 13:53:31 +0100141 *
Andrea Campanellae4b2c682019-08-23 15:42:55 +0200142 * @param speed the speed in Hz
143 * @return the speed in Mbps
Diego Garciaaab99472019-01-10 13:53:31 +0100144 */
145 public static long toMbpsFromHz(long speed) {
146 return speed / 1000000;
147 }
Andrea Campanellab9e491b2019-02-18 17:45:01 +0100148
149 /**
150 * If SIP info match our criteria, SIP component shall includes mc-pool information which must be obtained in order
151 * to complete the OchSignal info. with the TAPI SIP information included in spectrum-supported, spectrum-available
152 * and spectrum-occupied tapi objects.
153 *
154 * @param mcPool the MC_POOL json node
155 * @return the set of OCH signals given the port's information
156 **/
157 protected static Set<OchSignal> getOchSignal(JsonNode mcPool) {
158
159 Set<OchSignal> lambdas = new LinkedHashSet<>();
160 long availableUpperFrec = 0;
161 long availableLowerFrec = 0;
162 String availableAdjustmentGranularity = "";
163 String availableGridType = "";
164 JsonNode availableSpectrum = mcPool.get(AVAILABLE_SPECTRUM);
165
166 if (availableSpectrum == null) {
167 availableSpectrum = mcPool.get(SUPPORTABLE_SPECTRUM);
168 }
169
170 Iterator<JsonNode> iterAvailable = availableSpectrum.iterator();
171 while (iterAvailable.hasNext()) {
172 JsonNode availableSpec = iterAvailable.next();
173 availableUpperFrec = availableSpec.get(UPPER_FREQUENCY).asLong();
174 availableLowerFrec = availableSpec.get(LOWER_FREQUENCY).asLong();
Andrea Campanellae4b2c682019-08-23 15:42:55 +0200175 log.debug("availableUpperFrec {}, availableLowerFrec {}", availableUpperFrec,
Andrea Campanellab9e491b2019-02-18 17:45:01 +0100176 availableLowerFrec);
177 availableAdjustmentGranularity = availableSpec.get(FREQUENCY_CONSTRAINT)
178 .get(ADJUSTMENT_GRANULARITY).textValue();
179 availableGridType = availableSpec.get(FREQUENCY_CONSTRAINT).get(GRID_TYPE).textValue();
Andrea Campanellae4b2c682019-08-23 15:42:55 +0200180 log.debug("adjustment {}, availableLowerFrec {}", availableUpperFrec,
181 availableLowerFrec);
Andrea Campanellab9e491b2019-02-18 17:45:01 +0100182 int slotGranularity;
183 ChannelSpacing chSpacing = getChannelSpacing(availableAdjustmentGranularity);
Andrea Campanellae4b2c682019-08-23 15:42:55 +0200184 double spacingFrequency = chSpacing.frequency().asMHz();
Andrea Campanellab9e491b2019-02-18 17:45:01 +0100185 int lambdaCount = (int) ((availableUpperFrec - availableLowerFrec) / spacingFrequency);
186 GridType gridType = GridType.valueOf(availableGridType);
187 if (gridType == GridType.DWDM) {
188 slotGranularity = getSlotGranularity(chSpacing);
189 int finalSlotGranularity = slotGranularity;
Andrea Campanellae4b2c682019-08-23 15:42:55 +0200190 long finalAvailableUpperFrec = availableUpperFrec;
191 long finalAvailableLowerFrec = availableLowerFrec;
192 IntStream.range(0, lambdaCount).forEach(x -> {
193 int spacingMultiplier = 0;
194 if (finalAvailableUpperFrec > BASE_FREQUENCY) {
195 spacingMultiplier = (int) (((finalAvailableUpperFrec -
196 (chSpacing.frequency().asMHz() * lambdaCount * x) - slotGranularity / 2)
197 - BASE_FREQUENCY) / (chSpacing.frequency().asMHz()));
198 } else {
199 spacingMultiplier = (int) ((BASE_FREQUENCY - (finalAvailableLowerFrec +
200 (chSpacing.frequency().asMHz() * lambdaCount * x) + slotGranularity / 2))
201 / (chSpacing.frequency().asMHz()));
202 }
203 OchSignal ochSignal = new OchSignal(GridType.DWDM, chSpacing,
204 spacingMultiplier, finalSlotGranularity);
205 log.debug("Spacing Freq {}, LambdaCount {}, FinalSlotGran {}, Spacing mult {}, CentralFreq {}",
206 spacingFrequency, lambdaCount, finalSlotGranularity, spacingMultiplier,
207 ochSignal.centralFrequency());
208 lambdas.add(ochSignal);
209 });
Andrea Campanellab9e491b2019-02-18 17:45:01 +0100210 } 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 } else {
215 log.warn("Unknown GridType");
216 }
217 }
218 return lambdas;
219 }
Andrea Campanellae4b2c682019-08-23 15:42:55 +0200220
221 static DeviceConnectionCache getConnectionCache() {
222 return DeviceConnectionCache.init();
223 }
224
225 protected static Set<String> getUuids(DeviceId deviceId, DriverHandler handler) {
226 RestSBController controller = checkNotNull(handler.get(RestSBController.class));
227 ObjectMapper om = new ObjectMapper();
228 final ObjectReader reader = om.reader();
229 InputStream response = controller.get(deviceId, CONN_REQ_GET_API, MediaType.APPLICATION_JSON_TYPE);
230 JsonNode jsonNode;
231 try {
232 jsonNode = reader.readTree(response);
233 if (jsonNode == null) {
234 log.error("JsonNode is null for response {}", response);
235 return ImmutableSet.of();
236 }
237 return parseTapiGetConnectivityRequest(jsonNode);
238 } catch (IOException e) {
239 log.error("Exception while reading response {}", response, e);
240 return ImmutableSet.of();
241 }
242 }
243
244 protected static Set<String> parseTapiGetConnectivityRequest(JsonNode tapiConnectivityReply) {
245 /*
246 {
247 "tapi-connectivity:connectivity-context": {
248 "connectivity-service": [
249 {
250 "uuid": "f4088e82-e8bd-4d00-a96c-40d9fcfa1d4d",
251 ......
252 ]
253 }
254 }
255 */
256 Set<String> uuids = new HashSet<>();
257 if (tapiConnectivityReply.has(TAPI_CONNECTIVITY_CONNECTIVITY_CONTEXT)
258 && tapiConnectivityReply.get(TAPI_CONNECTIVITY_CONNECTIVITY_CONTEXT).has(CONNECTIVITY_SERVICE)) {
259 tapiConnectivityReply.get(TAPI_CONNECTIVITY_CONNECTIVITY_CONTEXT).get(CONNECTIVITY_SERVICE).elements()
260 .forEachRemaining(node -> uuids.add(node.get(TapiDeviceHelper.UUID).asText()));
261 } else {
262 log.warn("Can't retrieve connectivity UUID from {}", tapiConnectivityReply);
263 }
264 //This is only one uuid or empty in case of failures
265 return uuids;
266 }
267
268 protected static void removeInitalConnectivityServices(DeviceId deviceId, DriverHandler handler) {
269 RestSBController controller = checkNotNull(handler.get(RestSBController.class));
270 //If no connections are there removing all previous (if any) connections during first installation
271 if (getConnectionCache().size(deviceId) == 0) {
272 Set<String> uuids = getUuids(deviceId, handler);
273 uuids.forEach(uuid -> {
274 CompletableFuture<Integer> flowRemoval =
275 CompletableFuture.supplyAsync(() -> controller.delete(deviceId,
276 CONN_REQ_REMOVE_DATA_API + uuid,
277 null, MediaType.APPLICATION_JSON_TYPE));
278 flowRemoval.thenApply(result -> {
279 if (result == HttpStatus.SC_NO_CONTENT || result == HttpStatus.SC_OK) {
280 log.info("Removed connectivity service {} from {}, result {}", uuid, deviceId, result);
281 } else {
282 log.error("Can't remove connectivity service {}, result {}", uuid, result);
283 }
284 return result;
285 });
286 });
287 }
288 }
Diego Garciaaab99472019-01-10 13:53:31 +0100289}