blob: c5ec5605df35f9e900daad4184d2d64f5e332ce2 [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
Brian O'Connor772852a2014-11-17 15:51:19 -080018import com.google.common.collect.Lists;
weibitf32383b2014-10-22 10:17:31 -070019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
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;
Brian O'Connorabafb502014-12-02 22:26:20 -080028import org.onosproject.net.ConnectPoint;
29import org.onosproject.net.Host;
30import org.onosproject.net.Link;
31import org.onosproject.net.Path;
32import org.onosproject.net.host.HostService;
33import org.onosproject.net.intent.HostToHostIntent;
34import org.onosproject.net.intent.Intent;
35import org.onosproject.net.intent.IntentEvent;
36import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.intent.IntentService;
38import org.onosproject.net.intent.IntentState;
39import org.onosproject.net.intent.OpticalConnectivityIntent;
40import org.onosproject.net.intent.PointToPointIntent;
41import org.onosproject.net.topology.LinkWeight;
42import org.onosproject.net.topology.PathService;
43import org.onosproject.net.topology.TopologyEdge;
weibitf32383b2014-10-22 10:17:31 -070044import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
46
Brian O'Connor772852a2014-11-17 15:51:19 -080047import java.util.Iterator;
48import java.util.List;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080049import java.util.Map;
Brian O'Connor772852a2014-11-17 15:51:19 -080050import java.util.Set;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080051import java.util.concurrent.ConcurrentHashMap;
52
53import static org.onosproject.net.intent.IntentState.INSTALLED;
Praseed Balakrishnanc0029652014-11-14 13:38:49 -080054
weibitf32383b2014-10-22 10:17:31 -070055/**
56 * OpticalPathProvisioner listens event notifications from the Intent F/W.
57 * It generates one or more opticalConnectivityIntent(s) and submits (or withdraws) to Intent F/W
58 * for adding/releasing capacity at the packet layer.
59 *
60 */
61
62@Component(immediate = true)
63public class OpticalPathProvisioner {
64
65 protected static final Logger log = LoggerFactory
66 .getLogger(OpticalPathProvisioner.class);
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 private IntentService intentService;
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Brian O'Connor772852a2014-11-17 15:51:19 -080072 protected PathService pathService;
weibitf32383b2014-10-22 10:17:31 -070073
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected CoreService coreService;
76
weibit7e583462014-10-23 10:14:05 -070077 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Praseed Balakrishnanc0029652014-11-14 13:38:49 -080078 protected HostService hostService;
79
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -080080 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected MastershipService mastershipService;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected ClusterService clusterService;
85
weibitf32383b2014-10-22 10:17:31 -070086 private ApplicationId appId;
weibitf32383b2014-10-22 10:17:31 -070087
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080088 // TODO use a shared map for distributed operation
89 protected final Map<ConnectPoint, OpticalConnectivityIntent> inStatusTportMap =
90 new ConcurrentHashMap<>();
91 protected final Map<ConnectPoint, OpticalConnectivityIntent> outStatusTportMap =
92 new ConcurrentHashMap<>();
93
94 protected final Map<ConnectPoint, Map<ConnectPoint, Intent>> intentMap =
95 new ConcurrentHashMap<>();
weibitf32383b2014-10-22 10:17:31 -070096
97 private final InternalOpticalPathProvisioner pathProvisioner = new InternalOpticalPathProvisioner();
98
99 @Activate
100 protected void activate() {
101 intentService.addListener(pathProvisioner);
Brian O'Connorabafb502014-12-02 22:26:20 -0800102 appId = coreService.registerApplication("org.onosproject.optical");
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800103 initTport();
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800104 log.info("Starting optical path provisioning...");
weibitf32383b2014-10-22 10:17:31 -0700105 }
106
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800107 protected void initTport() {
108 inStatusTportMap.clear();
109 outStatusTportMap.clear();
110 for (Intent intent : intentService.getIntents()) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800111 if (intentService.getIntentState(intent.key()) == INSTALLED) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800112 if (intent instanceof OpticalConnectivityIntent) {
113 inStatusTportMap.put(((OpticalConnectivityIntent) intent).getSrc(),
114 (OpticalConnectivityIntent) intent);
115 outStatusTportMap.put(((OpticalConnectivityIntent) intent).getDst(),
116 (OpticalConnectivityIntent) intent);
117 }
118 }
119 }
120 }
121
weibitf32383b2014-10-22 10:17:31 -0700122 protected void deactivate() {
123 intentService.removeListener(pathProvisioner);
124 }
125
126 public class InternalOpticalPathProvisioner implements IntentListener {
127 @Override
128 public void event(IntentEvent event) {
129 switch (event.type()) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800130 case INSTALL_REQ:
weibitf32383b2014-10-22 10:17:31 -0700131 break;
132 case INSTALLED:
133 break;
134 case FAILED:
weibit50eb95b2014-10-25 21:47:54 -0700135 log.info("packet intent {} failed, calling optical path provisioning APP.", event.subject());
Brian O'Connor772852a2014-11-17 15:51:19 -0800136 setupLightpath(event.subject());
weibitf32383b2014-10-22 10:17:31 -0700137 break;
138 case WITHDRAWN:
139 log.info("intent {} withdrawn.", event.subject());
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800140 //FIXME
141 //teardownLightpath(event.subject());
weibitf32383b2014-10-22 10:17:31 -0700142 break;
143 default:
144 break;
145 }
146 }
147
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800148 private void reserveTport(Intent intent) {
149 // TODO move to resourceManager
150 if (intent instanceof OpticalConnectivityIntent) {
151 OpticalConnectivityIntent opticalIntent =
152 (OpticalConnectivityIntent) intent;
153 if (inStatusTportMap.containsKey(opticalIntent.getSrc()) ||
154 outStatusTportMap.containsKey(opticalIntent.getDst())) {
155 //TODO throw an exception, perhaps
156 log.warn("Overlapping reservation: {}", opticalIntent);
157 }
158 inStatusTportMap.put(opticalIntent.getSrc(), opticalIntent);
159 outStatusTportMap.put(opticalIntent.getDst(), opticalIntent);
160 }
161 }
162
163 /**
164 * Registers an intent from src to dst.
165 * @param src source point
166 * @param dst destination point
167 * @param intent intent to be registered
168 * @return true if intent has not been previously added, false otherwise
169 */
170 private boolean addIntent(ConnectPoint src, ConnectPoint dst, Intent intent) {
171 Map<ConnectPoint, Intent> srcMap = intentMap.get(src);
172 if (srcMap == null) {
173 srcMap = new ConcurrentHashMap<>();
174 intentMap.put(src, srcMap);
175 }
176 if (srcMap.containsKey(dst)) {
177 return false;
178 } else {
179 srcMap.put(dst, intent);
180 return true;
181 }
182 }
183
Brian O'Connor772852a2014-11-17 15:51:19 -0800184 private void setupLightpath(Intent intent) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800185 // TODO change the coordination approach between packet intents and optical intents
186 // Low speed LLDP may cause multiple calls which are not expected
187
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800188 if (!IntentState.FAILED.equals(intentService.getIntentState(intent.key()))) {
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800189 return;
Marc De Leenheerb473b9d2015-02-06 15:21:03 -0800190 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800191
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800192 NodeId localNode = clusterService.getLocalNode().id();
193
Brian O'Connor772852a2014-11-17 15:51:19 -0800194 List<Intent> intents = Lists.newArrayList();
195 if (intent instanceof HostToHostIntent) {
196 HostToHostIntent hostToHostIntent = (HostToHostIntent) intent;
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800197
Brian O'Connor772852a2014-11-17 15:51:19 -0800198 Host one = hostService.getHost(hostToHostIntent.one());
199 Host two = hostService.getHost(hostToHostIntent.two());
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800200 if (one == null || two == null) {
201 return; //FIXME
202 }
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800203
204 // Ignore if we're not the master for the intent's origin device
205 NodeId sourceMaster = mastershipService.getMasterFor(one.location().deviceId());
206 if (!localNode.equals(sourceMaster)) {
207 return;
208 }
209
Brian O'Connor772852a2014-11-17 15:51:19 -0800210 // provision both directions
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800211 intents.addAll(getOpticalPath(one.location(), two.location()));
Brian O'Connor025fb442014-12-08 20:02:15 -0800212 // note: bi-directional intent is set up
213 // HostToHost Intent requires symmetric path!
214 //intents.addAll(getOpticalPath(two.location(), one.location()));
Brian O'Connor772852a2014-11-17 15:51:19 -0800215 } else if (intent instanceof PointToPointIntent) {
216 PointToPointIntent p2pIntent = (PointToPointIntent) intent;
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800217
218 // Ignore if we're not the master for the intent's origin device
219 NodeId sourceMaster = mastershipService.getMasterFor(p2pIntent.ingressPoint().deviceId());
220 if (!localNode.equals(sourceMaster)) {
221 return;
222 }
223
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800224 intents.addAll(getOpticalPath(p2pIntent.ingressPoint(), p2pIntent.egressPoint()));
Brian O'Connor772852a2014-11-17 15:51:19 -0800225 } else {
226 log.info("Unsupported intent type: {}", intent.getClass());
227 }
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800228
Brian O'Connor03406a42015-02-03 17:28:57 -0800229 // Create the intents
Brian O'Connor772852a2014-11-17 15:51:19 -0800230 for (Intent i : intents) {
231 // TODO: don't allow duplicate intents between the same points for now
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800232 // we may want to allow this carefully in future to increase capacity
233 if (i instanceof OpticalConnectivityIntent) {
234 OpticalConnectivityIntent oi = (OpticalConnectivityIntent) i;
235 if (addIntent(oi.getSrc(), oi.getDst(), oi)) {
Brian O'Connor03406a42015-02-03 17:28:57 -0800236 intentService.submit(i);
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800237 reserveTport(i);
238 }
239 } else {
240 log.warn("Invalid intent type: {} for {}", i.getClass(), i);
Brian O'Connor772852a2014-11-17 15:51:19 -0800241 }
242 }
weibit7e583462014-10-23 10:14:05 -0700243 }
244
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800245 private List<Intent> getOpticalPath(ConnectPoint ingress, ConnectPoint egress) {
Brian O'Connor772852a2014-11-17 15:51:19 -0800246 Set<Path> paths = pathService.getPaths(ingress.deviceId(),
247 egress.deviceId(),
248 new OpticalLinkWeight());
249
250 if (paths.isEmpty()) {
251 return Lists.newArrayList();
weibit7e583462014-10-23 10:14:05 -0700252 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800253
Brian O'Connor772852a2014-11-17 15:51:19 -0800254 List<Intent> connectionList = Lists.newArrayList();
255
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800256 Iterator<Path> itrPath = paths.iterator();
257 while (itrPath.hasNext()) {
258 boolean usedTportFound = false;
259 Path nextPath = itrPath.next();
260 log.info(nextPath.links().toString()); // TODO drop log level
Brian O'Connor772852a2014-11-17 15:51:19 -0800261
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800262 Iterator<Link> itrLink = nextPath.links().iterator();
263 while (itrLink.hasNext()) {
264 ConnectPoint srcWdmPoint, dstWdmPoint;
265 Link link1 = itrLink.next();
266 if (!isOpticalLink(link1)) {
267 continue;
Brian O'Connor772852a2014-11-17 15:51:19 -0800268 } else {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800269 srcWdmPoint = link1.dst();
270 dstWdmPoint = srcWdmPoint;
271 }
272
273 while (itrLink.hasNext()) {
274 Link link2 = itrLink.next();
275 if (isOpticalLink(link2)) {
276 dstWdmPoint = link2.src();
277 } else {
278 break;
279 }
280 }
281
282 if (inStatusTportMap.get(srcWdmPoint) != null ||
283 outStatusTportMap.get(dstWdmPoint) != null) {
284 usedTportFound = true;
285 // log.info("used ConnectPoint {} to {} were found", srcWdmPoint, dstWdmPoint);
Brian O'Connor772852a2014-11-17 15:51:19 -0800286 break;
287 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800288
Ray Milkeye076c792015-03-24 09:38:30 -0700289 Intent opticalIntent = OpticalConnectivityIntent.builder()
290 .appId(appId)
291 .src(srcWdmPoint)
292 .dst(dstWdmPoint)
293 .build();
294 Intent opticalIntent2 = OpticalConnectivityIntent.builder()
295 .appId(appId)
296 .src(dstWdmPoint)
297 .dst(srcWdmPoint)
298 .build();
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800299 log.info("Creating optical intent from {} to {}", srcWdmPoint, dstWdmPoint);
Brian O'Connor025fb442014-12-08 20:02:15 -0800300 log.info("Creating optical intent from {} to {}", dstWdmPoint, srcWdmPoint);
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800301 connectionList.add(opticalIntent);
Brian O'Connor025fb442014-12-08 20:02:15 -0800302 connectionList.add(opticalIntent2);
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800303
304 break;
Brian O'Connor772852a2014-11-17 15:51:19 -0800305 }
306
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800307 if (!usedTportFound) {
308 break;
309 } else {
310 // reset the connection list
311 connectionList = Lists.newArrayList();
312 }
313
Brian O'Connor772852a2014-11-17 15:51:19 -0800314 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800315
Brian O'Connor772852a2014-11-17 15:51:19 -0800316 return connectionList;
317 }
318
weibitf32383b2014-10-22 10:17:31 -0700319 private void teardownLightpath(Intent intent) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800320 /* FIXME this command doesn't make much sense. we need to define the semantics
321 // TODO move to resourceManager
322 if (intent instanceof OpticalConnectivityIntent) {
323 inStatusTportMap.remove(((OpticalConnectivityIntent) intent).getSrc());
324 outStatusTportMap.remove(((OpticalConnectivityIntent) intent).getDst());
325 // TODO tear down the idle lightpath if the utilization is zero.
326
327 }
328 */ //end-FIXME
weibitf32383b2014-10-22 10:17:31 -0700329 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800330
Brian O'Connor772852a2014-11-17 15:51:19 -0800331 }
weibitf32383b2014-10-22 10:17:31 -0700332
Brian O'Connor772852a2014-11-17 15:51:19 -0800333 private static boolean isOpticalLink(Link link) {
334 boolean isOptical = false;
335 Link.Type lt = link.type();
336 if (lt == Link.Type.OPTICAL) {
337 isOptical = true;
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800338 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800339 return isOptical;
340 }
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800341
Brian O'Connor772852a2014-11-17 15:51:19 -0800342 private static class OpticalLinkWeight implements LinkWeight {
343 @Override
344 public double weight(TopologyEdge edge) {
Praseed Balakrishnan00dd1f92014-11-19 17:12:36 -0800345 if (edge.link().state() == Link.State.INACTIVE) {
346 return -1; // ignore inactive links
347 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800348 if (isOpticalLink(edge.link())) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800349 return 1000; // optical links
Brian O'Connor772852a2014-11-17 15:51:19 -0800350 } else {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800351 return 1; // packet links
Brian O'Connor772852a2014-11-17 15:51:19 -0800352 }
353 }
weibitf32383b2014-10-22 10:17:31 -0700354 }
355
356}