blob: f373e4edb750a75d79ca0cdd181e8891a01817a0 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.optical;
weibitf32383b2014-10-22 10:17:31 -070017
weibitf32383b2014-10-22 10:17:31 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
Marc De Leenheer16f857b2015-05-05 20:50:24 -070020import org.apache.felix.scr.annotations.Deactivate;
weibitf32383b2014-10-22 10:17:31 -070021import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -080023import org.onosproject.cluster.ClusterService;
24import org.onosproject.cluster.NodeId;
Brian O'Connorabafb502014-12-02 22:26:20 -080025import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -080027import org.onosproject.mastership.MastershipService;
Toru Furusawa72ee30c2016-01-08 13:29:04 -080028import org.onosproject.net.CltSignalType;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.net.ConnectPoint;
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070030import org.onosproject.net.Device;
Brian O'Connorabafb502014-12-02 22:26:20 -080031import org.onosproject.net.Host;
32import org.onosproject.net.Link;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070033import org.onosproject.net.OchPort;
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070034import org.onosproject.net.OduCltPort;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070035import org.onosproject.net.OduSignalType;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.net.Path;
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070037import org.onosproject.net.Port;
38import org.onosproject.net.device.DeviceService;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.host.HostService;
40import org.onosproject.net.intent.HostToHostIntent;
41import org.onosproject.net.intent.Intent;
42import org.onosproject.net.intent.IntentEvent;
43import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080044import org.onosproject.net.intent.IntentService;
45import org.onosproject.net.intent.IntentState;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070046import org.onosproject.net.intent.OpticalCircuitIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080047import org.onosproject.net.intent.OpticalConnectivityIntent;
48import org.onosproject.net.intent.PointToPointIntent;
49import org.onosproject.net.topology.LinkWeight;
50import org.onosproject.net.topology.PathService;
51import org.onosproject.net.topology.TopologyEdge;
weibitf32383b2014-10-22 10:17:31 -070052import org.slf4j.Logger;
53import org.slf4j.LoggerFactory;
54
Marc De Leenheer16f857b2015-05-05 20:50:24 -070055import java.util.Collections;
Brian O'Connor772852a2014-11-17 15:51:19 -080056import java.util.Iterator;
Marc De Leenheer16f857b2015-05-05 20:50:24 -070057import java.util.LinkedList;
Brian O'Connor772852a2014-11-17 15:51:19 -080058import java.util.List;
59import java.util.Set;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080060
Marc De Leenheer16f857b2015-05-05 20:50:24 -070061import static com.google.common.base.Preconditions.checkArgument;
Marc De Leenheer16f857b2015-05-05 20:50:24 -070062import static com.google.common.base.Preconditions.checkNotNull;
63
weibitf32383b2014-10-22 10:17:31 -070064/**
Marc De Leenheer16f857b2015-05-05 20:50:24 -070065 * OpticalPathProvisioner listens for event notifications from the Intent F/W.
weibitf32383b2014-10-22 10:17:31 -070066 * It generates one or more opticalConnectivityIntent(s) and submits (or withdraws) to Intent F/W
67 * for adding/releasing capacity at the packet layer.
weibitf32383b2014-10-22 10:17:31 -070068 */
69
70@Component(immediate = true)
71public class OpticalPathProvisioner {
72
73 protected static final Logger log = LoggerFactory
74 .getLogger(OpticalPathProvisioner.class);
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 private IntentService intentService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Brian O'Connor772852a2014-11-17 15:51:19 -080080 protected PathService pathService;
weibitf32383b2014-10-22 10:17:31 -070081
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected CoreService coreService;
84
weibit7e583462014-10-23 10:14:05 -070085 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Praseed Balakrishnanc0029652014-11-14 13:38:49 -080086 protected HostService hostService;
87
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -080088 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected MastershipService mastershipService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected ClusterService clusterService;
93
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070094 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070095 protected DeviceService deviceService;
96
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070097 private ApplicationId appId;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080098
weibitf32383b2014-10-22 10:17:31 -070099 private final InternalOpticalPathProvisioner pathProvisioner = new InternalOpticalPathProvisioner();
100
101 @Activate
102 protected void activate() {
103 intentService.addListener(pathProvisioner);
Brian O'Connorabafb502014-12-02 22:26:20 -0800104 appId = coreService.registerApplication("org.onosproject.optical");
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700105 initOpticalPorts();
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700106 log.info("Started");
107 }
108
109 @Deactivate
110 protected void deactivate() {
111 intentService.removeListener(pathProvisioner);
112 log.info("Stopped");
weibitf32383b2014-10-22 10:17:31 -0700113 }
114
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700115 /**
116 * Initialize availability of optical ports.
117 */
118 private void initOpticalPorts() {
119 // TODO: check for existing optical intents
120 return;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800121 }
122
weibitf32383b2014-10-22 10:17:31 -0700123 public class InternalOpticalPathProvisioner implements IntentListener {
124 @Override
125 public void event(IntentEvent event) {
126 switch (event.type()) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800127 case INSTALL_REQ:
weibitf32383b2014-10-22 10:17:31 -0700128 break;
129 case INSTALLED:
130 break;
131 case FAILED:
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700132 log.info("Intent {} failed, calling optical path provisioning app.", event.subject());
Brian O'Connor772852a2014-11-17 15:51:19 -0800133 setupLightpath(event.subject());
weibitf32383b2014-10-22 10:17:31 -0700134 break;
weibitf32383b2014-10-22 10:17:31 -0700135 default:
136 break;
137 }
138 }
139
Brian O'Connor772852a2014-11-17 15:51:19 -0800140 private void setupLightpath(Intent intent) {
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700141 checkNotNull(intent);
142
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800143 // TODO change the coordination approach between packet intents and optical intents
144 // Low speed LLDP may cause multiple calls which are not expected
145
Sho SHIMIZU0a9c9c42015-07-01 15:29:16 -0700146 if (intentService.getIntentState(intent.key()) != IntentState.FAILED) {
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800147 return;
Marc De Leenheerb473b9d2015-02-06 15:21:03 -0800148 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800149
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700150 // Get source and destination based on intent type
151 ConnectPoint src;
152 ConnectPoint dst;
Brian O'Connor772852a2014-11-17 15:51:19 -0800153 if (intent instanceof HostToHostIntent) {
154 HostToHostIntent hostToHostIntent = (HostToHostIntent) intent;
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800155
Brian O'Connor772852a2014-11-17 15:51:19 -0800156 Host one = hostService.getHost(hostToHostIntent.one());
157 Host two = hostService.getHost(hostToHostIntent.two());
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800158
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700159 checkNotNull(one);
160 checkNotNull(two);
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800161
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700162 src = one.location();
163 dst = two.location();
Brian O'Connor772852a2014-11-17 15:51:19 -0800164 } else if (intent instanceof PointToPointIntent) {
165 PointToPointIntent p2pIntent = (PointToPointIntent) intent;
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800166
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700167 src = p2pIntent.ingressPoint();
168 dst = p2pIntent.egressPoint();
Brian O'Connor772852a2014-11-17 15:51:19 -0800169 } else {
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700170 return;
Brian O'Connor772852a2014-11-17 15:51:19 -0800171 }
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800172
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700173 if (src == null || dst == null) {
174 return;
175 }
176
177 // Ignore if we're not the master for the intent's origin device
178 NodeId localNode = clusterService.getLocalNode().id();
179 NodeId sourceMaster = mastershipService.getMasterFor(src.deviceId());
180 if (!localNode.equals(sourceMaster)) {
181 return;
182 }
183
184 // Generate optical connectivity intents
Sho SHIMIZUfb446fe2015-05-21 14:45:23 -0700185 List<Intent> intents = getOpticalIntents(src, dst);
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700186
187 // Submit the intents
Brian O'Connor772852a2014-11-17 15:51:19 -0800188 for (Intent i : intents) {
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700189 intentService.submit(i);
Sho SHIMIZUb5d38412015-05-21 11:12:58 -0700190 log.debug("Submitted an intent: {}", i);
Brian O'Connor772852a2014-11-17 15:51:19 -0800191 }
weibit7e583462014-10-23 10:14:05 -0700192 }
193
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700194 /**
195 * Returns list of cross connection points of missing optical path sections.
196 *
197 * Scans the given multi-layer path and looks for sections that use cross connect links.
198 * The ingress and egress points in the optical layer are returned in a list.
199 *
200 * @param path the multi-layer path
201 * @return list of cross connection points on the optical layer
202 */
203 private List<ConnectPoint> getCrossConnectPoints(Path path) {
204 boolean scanning = false;
Sho SHIMIZU819ee292015-07-01 09:36:21 -0700205 List<ConnectPoint> connectPoints = new LinkedList<>();
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700206
207 for (Link link : path.links()) {
208 if (!isCrossConnectLink(link)) {
209 continue;
210 }
211
212 if (scanning) {
213 connectPoints.add(checkNotNull(link.src()));
214 scanning = false;
215 } else {
216 connectPoints.add(checkNotNull(link.dst()));
217 scanning = true;
218 }
219 }
220
221 return connectPoints;
222 }
223
224 /**
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700225 * Checks if cross connect points are of same type.
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700226 *
227 * @param crossConnectPoints list of cross connection points
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700228 * @return true if cross connect point pairs are of same type, false otherwise
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700229 */
230 private boolean checkCrossConnectPoints(List<ConnectPoint> crossConnectPoints) {
231 checkArgument(crossConnectPoints.size() % 2 == 0);
232
233 Iterator<ConnectPoint> itr = crossConnectPoints.iterator();
234
235 while (itr.hasNext()) {
236 // checkArgument at start ensures we'll always have pairs of connect points
237 ConnectPoint src = itr.next();
238 ConnectPoint dst = itr.next();
239
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700240 Device.Type srcType = deviceService.getDevice(src.deviceId()).type();
241 Device.Type dstType = deviceService.getDevice(dst.deviceId()).type();
242
243 // Only support connections between identical port types
244 if (srcType != dstType) {
245 log.warn("Unsupported mix of cross connect points");
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700246 return false;
247 }
248 }
249
250 return true;
251 }
252
253 /**
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700254 * Scans the list of cross connection points and returns a list of optical connectivity intents.
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700255 *
256 * @param crossConnectPoints list of cross connection points
257 * @return list of optical connectivity intents
258 */
259 private List<Intent> getIntents(List<ConnectPoint> crossConnectPoints) {
260 checkArgument(crossConnectPoints.size() % 2 == 0);
261
Sho SHIMIZU79945e82015-05-20 17:20:47 -0700262 List<Intent> intents = new LinkedList<>();
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700263 Iterator<ConnectPoint> itr = crossConnectPoints.iterator();
264
265 while (itr.hasNext()) {
266 // checkArgument at start ensures we'll always have pairs of connect points
267 ConnectPoint src = itr.next();
268 ConnectPoint dst = itr.next();
269
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700270 Port srcPort = deviceService.getPort(src.deviceId(), src.port());
271 Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700272
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700273 if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700274 // Create OTN circuit
275 Intent circuitIntent = OpticalCircuitIntent.builder()
276 .appId(appId)
277 .src(src)
278 .dst(dst)
Toru Furusawa72ee30c2016-01-08 13:29:04 -0800279 .signalType(CltSignalType.CLT_10GBE)
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700280 .bidirectional(true)
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700281 .build();
282 intents.add(circuitIntent);
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700283 } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
284 // Create lightpath
285 // FIXME: hardcoded ODU signal type
286 Intent opticalIntent = OpticalConnectivityIntent.builder()
287 .appId(appId)
288 .src(src)
289 .dst(dst)
290 .signalType(OduSignalType.ODU4)
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700291 .bidirectional(true)
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700292 .build();
293 intents.add(opticalIntent);
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700294 } else {
295 log.warn("Unsupported cross connect point types {} {}", srcPort.type(), dstPort.type());
296 return Collections.emptyList();
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700297 }
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700298 }
299
300 return intents;
301 }
302
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700303 /**
304 * Returns list of optical connectivity intents needed to create connectivity
305 * between ingress and egress.
306 *
307 * @param ingress the ingress connect point
308 * @param egress the egress connect point
309 * @return list of optical connectivity intents, empty list if no path was found
310 */
311 private List<Intent> getOpticalIntents(ConnectPoint ingress, ConnectPoint egress) {
Brian O'Connor772852a2014-11-17 15:51:19 -0800312 Set<Path> paths = pathService.getPaths(ingress.deviceId(),
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700313 egress.deviceId(),
314 new OpticalLinkWeight());
Brian O'Connor772852a2014-11-17 15:51:19 -0800315
316 if (paths.isEmpty()) {
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700317 return Collections.emptyList();
weibit7e583462014-10-23 10:14:05 -0700318 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800319
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700320 // Search path with available cross connect points
321 for (Path path : paths) {
322 List<ConnectPoint> crossConnectPoints = getCrossConnectPoints(path);
Brian O'Connor772852a2014-11-17 15:51:19 -0800323
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700324 // Skip to next path if cross connect points are mismatched
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700325 if (!checkCrossConnectPoints(crossConnectPoints)) {
326 continue;
Brian O'Connor772852a2014-11-17 15:51:19 -0800327 }
328
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700329 return getIntents(crossConnectPoints);
Brian O'Connor772852a2014-11-17 15:51:19 -0800330 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800331
Marc De Leenheer234fa822015-11-18 18:24:57 -0800332 log.warn("Unable to find multi-layer path.");
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700333 return Collections.emptyList();
Brian O'Connor772852a2014-11-17 15:51:19 -0800334 }
335
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700336 /**
337 * Link weight function that emphasizes re-use of packet links.
338 */
339 private class OpticalLinkWeight implements LinkWeight {
340 @Override
341 public double weight(TopologyEdge edge) {
342 // Ignore inactive links
343 if (edge.link().state() == Link.State.INACTIVE) {
344 return -1;
345 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800346
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700347 // TODO: Ignore cross connect links with used ports
348
349 // Transport links have highest weight
350 if (edge.link().type() == Link.Type.OPTICAL) {
351 return 1000;
352 }
353
354 // Packet links
355 return 1;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800356 }
weibitf32383b2014-10-22 10:17:31 -0700357 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800358
Brian O'Connor772852a2014-11-17 15:51:19 -0800359 }
weibitf32383b2014-10-22 10:17:31 -0700360
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700361 /**
Marc De Leenheer234fa822015-11-18 18:24:57 -0800362 * Verifies if given device type is in packet layer, i.e., ROADM, OTN or ROADM_OTN device.
363 *
364 * @param type device type
365 * @return true if in packet layer, false otherwise
366 */
367 private boolean isPacketLayer(Device.Type type) {
Ayaka Koshibe31980ab2016-01-21 00:11:16 -0800368 return type == Device.Type.SWITCH || type == Device.Type.ROUTER || type == Device.Type.VIRTUAL;
Marc De Leenheer234fa822015-11-18 18:24:57 -0800369 }
370
371 /**
372 * Verifies if given device type is in packet layer, i.e., switch or router device.
373 *
374 * @param type device type
375 * @return true if in packet layer, false otherwise
376 */
377 private boolean isTransportLayer(Device.Type type) {
378 return type == Device.Type.ROADM || type == Device.Type.OTN || type == Device.Type.ROADM_OTN;
379 }
380
381 /**
382 * Verifies if given link forms a cross-connection between packet and optical layer.
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700383 *
384 * @param link the link
Marc De Leenheer234fa822015-11-18 18:24:57 -0800385 * @return true if the link is a cross-connect link, false otherwise
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700386 */
Marc De Leenheer234fa822015-11-18 18:24:57 -0800387 private boolean isCrossConnectLink(Link link) {
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700388 if (link.type() != Link.Type.OPTICAL) {
389 return false;
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800390 }
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700391
Marc De Leenheer234fa822015-11-18 18:24:57 -0800392 Device.Type src = deviceService.getDevice(link.src().deviceId()).type();
393 Device.Type dst = deviceService.getDevice(link.dst().deviceId()).type();
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700394
Marc De Leenheer234fa822015-11-18 18:24:57 -0800395 return src != dst &&
396 ((isPacketLayer(src) && isTransportLayer(dst)) || (isPacketLayer(dst) && isTransportLayer(src)));
Brian O'Connor772852a2014-11-17 15:51:19 -0800397 }
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800398
weibitf32383b2014-10-22 10:17:31 -0700399}