blob: 13796f941394227c8b538706cdb7d079b71423f1 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 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;
Brian O'Connorabafb502014-12-02 22:26:20 -080023import org.onosproject.core.ApplicationId;
24import org.onosproject.core.CoreService;
25import org.onosproject.net.ConnectPoint;
26import org.onosproject.net.Host;
27import org.onosproject.net.Link;
28import org.onosproject.net.Path;
29import org.onosproject.net.host.HostService;
30import org.onosproject.net.intent.HostToHostIntent;
31import org.onosproject.net.intent.Intent;
32import org.onosproject.net.intent.IntentEvent;
33import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.intent.IntentService;
35import org.onosproject.net.intent.IntentState;
36import org.onosproject.net.intent.OpticalConnectivityIntent;
37import org.onosproject.net.intent.PointToPointIntent;
38import org.onosproject.net.topology.LinkWeight;
39import org.onosproject.net.topology.PathService;
40import org.onosproject.net.topology.TopologyEdge;
weibitf32383b2014-10-22 10:17:31 -070041import org.slf4j.Logger;
42import org.slf4j.LoggerFactory;
43
Brian O'Connor772852a2014-11-17 15:51:19 -080044import java.util.Iterator;
45import java.util.List;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080046import java.util.Map;
Brian O'Connor772852a2014-11-17 15:51:19 -080047import java.util.Set;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080048import java.util.concurrent.ConcurrentHashMap;
49
50import static org.onosproject.net.intent.IntentState.INSTALLED;
Praseed Balakrishnanc0029652014-11-14 13:38:49 -080051
weibitf32383b2014-10-22 10:17:31 -070052/**
53 * OpticalPathProvisioner listens event notifications from the Intent F/W.
54 * It generates one or more opticalConnectivityIntent(s) and submits (or withdraws) to Intent F/W
55 * for adding/releasing capacity at the packet layer.
56 *
57 */
58
59@Component(immediate = true)
60public class OpticalPathProvisioner {
61
62 protected static final Logger log = LoggerFactory
63 .getLogger(OpticalPathProvisioner.class);
64
65 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 private IntentService intentService;
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Brian O'Connor772852a2014-11-17 15:51:19 -080069 protected PathService pathService;
weibitf32383b2014-10-22 10:17:31 -070070
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected CoreService coreService;
73
weibit7e583462014-10-23 10:14:05 -070074 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Praseed Balakrishnanc0029652014-11-14 13:38:49 -080075 protected HostService hostService;
76
weibitf32383b2014-10-22 10:17:31 -070077 private ApplicationId appId;
weibitf32383b2014-10-22 10:17:31 -070078
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080079 // TODO use a shared map for distributed operation
80 protected final Map<ConnectPoint, OpticalConnectivityIntent> inStatusTportMap =
81 new ConcurrentHashMap<>();
82 protected final Map<ConnectPoint, OpticalConnectivityIntent> outStatusTportMap =
83 new ConcurrentHashMap<>();
84
85 protected final Map<ConnectPoint, Map<ConnectPoint, Intent>> intentMap =
86 new ConcurrentHashMap<>();
weibitf32383b2014-10-22 10:17:31 -070087
88 private final InternalOpticalPathProvisioner pathProvisioner = new InternalOpticalPathProvisioner();
89
90 @Activate
91 protected void activate() {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080092 // TODO elect a leader and have one instance do the provisioning
weibitf32383b2014-10-22 10:17:31 -070093 intentService.addListener(pathProvisioner);
Brian O'Connorabafb502014-12-02 22:26:20 -080094 appId = coreService.registerApplication("org.onosproject.optical");
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080095 initTport();
weibitf32383b2014-10-22 10:17:31 -070096 log.info("Starting optical path provisoning...");
97 }
98
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080099 protected void initTport() {
100 inStatusTportMap.clear();
101 outStatusTportMap.clear();
102 for (Intent intent : intentService.getIntents()) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800103 if (intentService.getIntentState(intent.key()) == INSTALLED) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800104 if (intent instanceof OpticalConnectivityIntent) {
105 inStatusTportMap.put(((OpticalConnectivityIntent) intent).getSrc(),
106 (OpticalConnectivityIntent) intent);
107 outStatusTportMap.put(((OpticalConnectivityIntent) intent).getDst(),
108 (OpticalConnectivityIntent) intent);
109 }
110 }
111 }
112 }
113
weibitf32383b2014-10-22 10:17:31 -0700114 protected void deactivate() {
115 intentService.removeListener(pathProvisioner);
116 }
117
118 public class InternalOpticalPathProvisioner implements IntentListener {
119 @Override
120 public void event(IntentEvent event) {
121 switch (event.type()) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800122 case INSTALL_REQ:
weibitf32383b2014-10-22 10:17:31 -0700123 break;
124 case INSTALLED:
125 break;
126 case FAILED:
weibit50eb95b2014-10-25 21:47:54 -0700127 log.info("packet intent {} failed, calling optical path provisioning APP.", event.subject());
Brian O'Connor772852a2014-11-17 15:51:19 -0800128 setupLightpath(event.subject());
weibitf32383b2014-10-22 10:17:31 -0700129 break;
130 case WITHDRAWN:
131 log.info("intent {} withdrawn.", event.subject());
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800132 //FIXME
133 //teardownLightpath(event.subject());
weibitf32383b2014-10-22 10:17:31 -0700134 break;
135 default:
136 break;
137 }
138 }
139
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800140 private void reserveTport(Intent intent) {
141 // TODO move to resourceManager
142 if (intent instanceof OpticalConnectivityIntent) {
143 OpticalConnectivityIntent opticalIntent =
144 (OpticalConnectivityIntent) intent;
145 if (inStatusTportMap.containsKey(opticalIntent.getSrc()) ||
146 outStatusTportMap.containsKey(opticalIntent.getDst())) {
147 //TODO throw an exception, perhaps
148 log.warn("Overlapping reservation: {}", opticalIntent);
149 }
150 inStatusTportMap.put(opticalIntent.getSrc(), opticalIntent);
151 outStatusTportMap.put(opticalIntent.getDst(), opticalIntent);
152 }
153 }
154
155 /**
156 * Registers an intent from src to dst.
157 * @param src source point
158 * @param dst destination point
159 * @param intent intent to be registered
160 * @return true if intent has not been previously added, false otherwise
161 */
162 private boolean addIntent(ConnectPoint src, ConnectPoint dst, Intent intent) {
163 Map<ConnectPoint, Intent> srcMap = intentMap.get(src);
164 if (srcMap == null) {
165 srcMap = new ConcurrentHashMap<>();
166 intentMap.put(src, srcMap);
167 }
168 if (srcMap.containsKey(dst)) {
169 return false;
170 } else {
171 srcMap.put(dst, intent);
172 return true;
173 }
174 }
175
Brian O'Connor772852a2014-11-17 15:51:19 -0800176 private void setupLightpath(Intent intent) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800177 // TODO change the coordination approach between packet intents and optical intents
178 // Low speed LLDP may cause multiple calls which are not expected
179
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800180 if (!IntentState.FAILED.equals(intentService.getIntentState(intent.key()))) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800181 return;
Marc De Leenheerb473b9d2015-02-06 15:21:03 -0800182 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800183
Brian O'Connor772852a2014-11-17 15:51:19 -0800184 List<Intent> intents = Lists.newArrayList();
185 if (intent instanceof HostToHostIntent) {
186 HostToHostIntent hostToHostIntent = (HostToHostIntent) intent;
187 Host one = hostService.getHost(hostToHostIntent.one());
188 Host two = hostService.getHost(hostToHostIntent.two());
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800189 if (one == null || two == null) {
190 return; //FIXME
191 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800192 // provision both directions
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800193 intents.addAll(getOpticalPath(one.location(), two.location()));
Brian O'Connor025fb442014-12-08 20:02:15 -0800194 // note: bi-directional intent is set up
195 // HostToHost Intent requires symmetric path!
196 //intents.addAll(getOpticalPath(two.location(), one.location()));
Brian O'Connor772852a2014-11-17 15:51:19 -0800197 } else if (intent instanceof PointToPointIntent) {
198 PointToPointIntent p2pIntent = (PointToPointIntent) intent;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800199 intents.addAll(getOpticalPath(p2pIntent.ingressPoint(), p2pIntent.egressPoint()));
Brian O'Connor772852a2014-11-17 15:51:19 -0800200 } else {
201 log.info("Unsupported intent type: {}", intent.getClass());
202 }
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800203
Brian O'Connor03406a42015-02-03 17:28:57 -0800204 // Create the intents
Brian O'Connor772852a2014-11-17 15:51:19 -0800205 for (Intent i : intents) {
206 // TODO: don't allow duplicate intents between the same points for now
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800207 // we may want to allow this carefully in future to increase capacity
208 if (i instanceof OpticalConnectivityIntent) {
209 OpticalConnectivityIntent oi = (OpticalConnectivityIntent) i;
210 if (addIntent(oi.getSrc(), oi.getDst(), oi)) {
Brian O'Connor03406a42015-02-03 17:28:57 -0800211 intentService.submit(i);
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800212 reserveTport(i);
213 }
214 } else {
215 log.warn("Invalid intent type: {} for {}", i.getClass(), i);
Brian O'Connor772852a2014-11-17 15:51:19 -0800216 }
217 }
weibit7e583462014-10-23 10:14:05 -0700218 }
219
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800220 private List<Intent> getOpticalPath(ConnectPoint ingress, ConnectPoint egress) {
Brian O'Connor772852a2014-11-17 15:51:19 -0800221 Set<Path> paths = pathService.getPaths(ingress.deviceId(),
222 egress.deviceId(),
223 new OpticalLinkWeight());
224
225 if (paths.isEmpty()) {
226 return Lists.newArrayList();
weibit7e583462014-10-23 10:14:05 -0700227 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800228
Brian O'Connor772852a2014-11-17 15:51:19 -0800229 List<Intent> connectionList = Lists.newArrayList();
230
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800231 Iterator<Path> itrPath = paths.iterator();
232 while (itrPath.hasNext()) {
233 boolean usedTportFound = false;
234 Path nextPath = itrPath.next();
235 log.info(nextPath.links().toString()); // TODO drop log level
Brian O'Connor772852a2014-11-17 15:51:19 -0800236
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800237 Iterator<Link> itrLink = nextPath.links().iterator();
238 while (itrLink.hasNext()) {
239 ConnectPoint srcWdmPoint, dstWdmPoint;
240 Link link1 = itrLink.next();
241 if (!isOpticalLink(link1)) {
242 continue;
Brian O'Connor772852a2014-11-17 15:51:19 -0800243 } else {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800244 srcWdmPoint = link1.dst();
245 dstWdmPoint = srcWdmPoint;
246 }
247
248 while (itrLink.hasNext()) {
249 Link link2 = itrLink.next();
250 if (isOpticalLink(link2)) {
251 dstWdmPoint = link2.src();
252 } else {
253 break;
254 }
255 }
256
257 if (inStatusTportMap.get(srcWdmPoint) != null ||
258 outStatusTportMap.get(dstWdmPoint) != null) {
259 usedTportFound = true;
260 // log.info("used ConnectPoint {} to {} were found", srcWdmPoint, dstWdmPoint);
Brian O'Connor772852a2014-11-17 15:51:19 -0800261 break;
262 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800263
264 Intent opticalIntent = new OpticalConnectivityIntent(appId,
265 srcWdmPoint,
266 dstWdmPoint);
Brian O'Connor025fb442014-12-08 20:02:15 -0800267 Intent opticalIntent2 = new OpticalConnectivityIntent(appId,
268 dstWdmPoint,
269 srcWdmPoint);
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800270 log.info("Creating optical intent from {} to {}", srcWdmPoint, dstWdmPoint);
Brian O'Connor025fb442014-12-08 20:02:15 -0800271 log.info("Creating optical intent from {} to {}", dstWdmPoint, srcWdmPoint);
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800272 connectionList.add(opticalIntent);
Brian O'Connor025fb442014-12-08 20:02:15 -0800273 connectionList.add(opticalIntent2);
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800274
275 break;
Brian O'Connor772852a2014-11-17 15:51:19 -0800276 }
277
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800278 if (!usedTportFound) {
279 break;
280 } else {
281 // reset the connection list
282 connectionList = Lists.newArrayList();
283 }
284
Brian O'Connor772852a2014-11-17 15:51:19 -0800285 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800286
Brian O'Connor772852a2014-11-17 15:51:19 -0800287 return connectionList;
288 }
289
weibitf32383b2014-10-22 10:17:31 -0700290 private void teardownLightpath(Intent intent) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800291 /* FIXME this command doesn't make much sense. we need to define the semantics
292 // TODO move to resourceManager
293 if (intent instanceof OpticalConnectivityIntent) {
294 inStatusTportMap.remove(((OpticalConnectivityIntent) intent).getSrc());
295 outStatusTportMap.remove(((OpticalConnectivityIntent) intent).getDst());
296 // TODO tear down the idle lightpath if the utilization is zero.
297
298 }
299 */ //end-FIXME
weibitf32383b2014-10-22 10:17:31 -0700300 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800301
Brian O'Connor772852a2014-11-17 15:51:19 -0800302 }
weibitf32383b2014-10-22 10:17:31 -0700303
Brian O'Connor772852a2014-11-17 15:51:19 -0800304 private static boolean isOpticalLink(Link link) {
305 boolean isOptical = false;
306 Link.Type lt = link.type();
307 if (lt == Link.Type.OPTICAL) {
308 isOptical = true;
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800309 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800310 return isOptical;
311 }
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800312
Brian O'Connor772852a2014-11-17 15:51:19 -0800313 private static class OpticalLinkWeight implements LinkWeight {
314 @Override
315 public double weight(TopologyEdge edge) {
Praseed Balakrishnan00dd1f92014-11-19 17:12:36 -0800316 if (edge.link().state() == Link.State.INACTIVE) {
317 return -1; // ignore inactive links
318 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800319 if (isOpticalLink(edge.link())) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800320 return 1000; // optical links
Brian O'Connor772852a2014-11-17 15:51:19 -0800321 } else {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800322 return 1; // packet links
Brian O'Connor772852a2014-11-17 15:51:19 -0800323 }
324 }
weibitf32383b2014-10-22 10:17:31 -0700325 }
326
327}