blob: 59a5ef83493d09f8083a8dcc97c99841f6130c5a [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);
Ray Milkeyf48a2742019-01-03 10:35:53 -080079 private static final Object N_PORT_LOCK = new Object();
Diego Garcia09ab5e22018-12-18 11:47:01 +010080 private static final long BASE_FREQUENCY = 193100000; //Working in Mhz
81
82 /**
83 * Get the deviceId for which the methods apply.
84 *
85 * @return The deviceId as contained in the handler data
86 */
87 private DeviceId did() {
88 return handler().data().deviceId();
89 }
90
91 @Override
92 public DeviceDescription discoverDeviceDetails() {
93 log.debug("Getting device description");
94 DeviceService deviceService = checkNotNull(handler().get(DeviceService.class));
95 DeviceId deviceId = handler().data().deviceId();
96 Device device = deviceService.getDevice(deviceId);
97
98 if (device == null) {
99 return new DefaultDeviceDescription(deviceId.uri(),
100 Device.Type.OLS,
101 "tapi-swagger",
102 "0",
103 "2.1",
104 "Unknown",
105 new ChassisId());
106 } else {
107 return new DefaultDeviceDescription(device.id().uri(),
108 Device.Type.OLS,
109 device.manufacturer(),
110 device.hwVersion(),
111 device.swVersion(),
112 device.serialNumber(),
113 device.chassisId());
114 }
115 }
116
117 @Override
118 public List<PortDescription> discoverPortDetails() {
119 log.debug("Discovering port details.");
120 RestSBController controller = checkNotNull(handler().get(RestSBController.class));
121 DeviceId deviceId = handler().data().deviceId();
122
123 try {
124 InputStream inputStream = controller.get(deviceId, SIP_REQUEST_DATA_API, MediaType.APPLICATION_JSON_TYPE);
125 JsonNode jsonNode = new ObjectMapper().readTree(inputStream);
126 return parseTapiPorts(jsonNode);
127 } catch (IOException e) {
128 log.error("Exception discoverPortDetails() {}", did(), e);
129 return ImmutableList.of();
130 }
131 }
132
133 protected List<PortDescription> parseTapiPorts(JsonNode tapiContext) {
134 List<PortDescription> ports = Lists.newArrayList();
135 int counter = 0;
136
137 /**
138 This annotations are used to store persistent mapping information between TAPI SIP's uuid
139 and ONOS device portNumbers. This is needed to be publicly available at least within ODTN app
140 when connectivity services will be sent to OLS Controller.
141 **/
142 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder();
143
144 JsonNode sips = tapiContext.get(SERVICE_INTERFACE_POINT);
145 Iterator<JsonNode> iter = sips.iterator();
146 while (iter.hasNext()) {
147 JsonNode sipAttributes = iter.next();
148 if (checkValidEndpoint(sipAttributes)) {
149 String uuid = sipAttributes.get(UUID).textValue();
150 JsonNode mcPool = sipAttributes.get(MEDIA_CHANNEL_SERVICE_INTERFACE_POINT_SPEC).get(MC_POOL);
151
152 OchSignal ochSignal = getOchSignal(mcPool);
Ray Milkeyf48a2742019-01-03 10:35:53 -0800153 synchronized (N_PORT_LOCK) {
154 //annotations(portNumber-uuid)
155 annotations.set(nPort.toString(), uuid);
Diego Garcia09ab5e22018-12-18 11:47:01 +0100156
Ray Milkeyf48a2742019-01-03 10:35:53 -0800157 //add och port
158 ports.add(ochPortDescription(nPort, true, OduSignalType.ODU4,
159 false, ochSignal, annotations.build()));
Diego Garcia09ab5e22018-12-18 11:47:01 +0100160
Ray Milkeyf48a2742019-01-03 10:35:53 -0800161 nPort = PortNumber.portNumber(counter++);
162 }
Diego Garcia09ab5e22018-12-18 11:47:01 +0100163 } else {
164 log.error("SIP {} is not valid", sipAttributes);
165 }
166 }
167 log.debug("PortList: {}", ports);
168 return ImmutableList.copyOf(ports);
169 }
170
171 /**
172 * Create a filter method to identify just valid OLS SIPs.This method must check the
173 * tapi object: "layer-protocol-name" and matching only if equals to "PHOTONIC-MEDIA" SIPs.
174 * Moreover,the filtering could be enhanced by reading also:
175 * "supported-layer-protocol-qualifier", to identify valid protocol-qualifier values such:
176 * [PHOTONIC_LAYER_QUALIFIER_NMC, PHOTONIC_LAYER_QUALIFIER_NMCA, PHOTONIC_LAYER_QUALIFIER_OTSI...]
177 **/
178 private boolean checkValidEndpoint(JsonNode sipAttributes) {
179 return (sipAttributes.get(LAYER_PROTOCOL_NAME).toString().contains(PHOTONIC_MEDIA) &&
180 sipAttributes.get(SUPPORTED_LAYER_PROTOCOL_QUALIFIER).toString()
181 .contains(PHOTONIC_LAYER_QUALIFIER_NMC));
182 }
183
184 /**
185 * If SIP info match our criteria, SIP component shall includes mc-pool information which must be obtained in order
186 * to complete the OchSignal info. with the TAPI SIP information included in spectrum-supported, spectrum-available
187 * and spectrum-occupied tapi objects.
188 **/
189 private OchSignal getOchSignal(JsonNode mcPool) {
190 long availableUpperFrec = 0, availableLowerFrec = 0;
191 String availableAdjustmentGranularity = "", availableGridType = "";
192 JsonNode availableSpectrum = mcPool.get(AVAILABLE_SPECTRUM);
193
194 /**At this time only the latest availableSpectrum is used**/
195 Iterator<JsonNode> iterAvailable = availableSpectrum.iterator();
196 while (iterAvailable.hasNext()) {
197 JsonNode availableSpec = iterAvailable.next();
198 availableUpperFrec = availableSpec.get(UPPER_FREQUENCY).asLong();
199 availableLowerFrec = availableSpec.get(LOWER_FREQUENCY).asLong();
200 availableAdjustmentGranularity = availableSpec.get(FREQUENCY_CONSTRAINT)
201 .get(ADJUSTMENT_GRANULARITY).textValue();
202 availableGridType = availableSpec.get(FREQUENCY_CONSTRAINT).get(GRID_TYPE).textValue();
203 }
204
205 int spacingMult = 0, slotGranularity = 1;
206 ChannelSpacing chSpacing = getChannelSpacing(availableAdjustmentGranularity);
207 long spacingFrequency = chSpacing.frequency().asHz();
208 long centralFrequency = (availableUpperFrec - (availableUpperFrec - availableLowerFrec) / 2);
209
210 GridType gridType = getGridType(availableGridType);
211 if (gridType == GridType.DWDM) {
212 spacingMult = (int) ((centralFrequency - BASE_FREQUENCY) / toMbpsFromHz(spacingFrequency));
213 } else if (gridType == GridType.CWDM) {
214 log.warn("GridType CWDM. Not implemented");
215 } else if (gridType == GridType.FLEX) {
216 log.warn("GridType FLEX. Not implemented");
217 slotGranularity = getSlotGranularity(chSpacing);
218 } else {
219 log.warn("Unknown GridType");
220 }
221 return new OchSignal(gridType, chSpacing, spacingMult, slotGranularity);
222 }
223
224 private int getSlotGranularity(ChannelSpacing chSpacing) {
225 if (chSpacing.equals(ChannelSpacing.CHL_100GHZ)) {
226 return 8;
227 } else if (chSpacing.equals(ChannelSpacing.CHL_50GHZ)) {
228 return 4;
229 } else if (chSpacing.equals(ChannelSpacing.CHL_25GHZ)) {
230 return 2;
231 } else if (chSpacing.equals(ChannelSpacing.CHL_12P5GHZ)) {
232 return 1;
233 } else {
234 return 0;
235 }
236 }
237
238 private GridType getGridType(String gridType) {
239 switch (gridType) {
240 case "DWDM":
241 return GridType.DWDM;
242 case "CWDM":
243 return GridType.CWDM;
244 case "FLEX":
245 return GridType.FLEX;
246 default:
247 return GridType.UNKNOWN;
248 }
249 }
250
251 private ChannelSpacing getChannelSpacing(String adjustmentGranularity) {
252 switch (adjustmentGranularity) {
253 case "G_100GHZ ":
254 return ChannelSpacing.CHL_100GHZ;
255 case "G_50GHZ":
256 return ChannelSpacing.CHL_50GHZ;
257 case "G_25GHZ":
258 return ChannelSpacing.CHL_25GHZ;
259 case "G_12_5GHZ ":
260 return ChannelSpacing.CHL_12P5GHZ;
261 case "G_6_25GHZ ":
262 return ChannelSpacing.CHL_6P25GHZ;
263 default:
264 return ChannelSpacing.CHL_0GHZ;
265 }
266 }
267
268 private static long toMbpsFromHz(long speed) {
269 return speed / 1000000;
270 }
271
272}