blob: c9ec460c09dbf175fc4d3eaa0cf5b92d411913ca [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;
34import org.onosproject.net.intent.IntentOperations;
35import org.onosproject.net.intent.IntentService;
36import org.onosproject.net.intent.IntentState;
37import org.onosproject.net.intent.OpticalConnectivityIntent;
38import org.onosproject.net.intent.PointToPointIntent;
39import org.onosproject.net.topology.LinkWeight;
40import org.onosproject.net.topology.PathService;
41import org.onosproject.net.topology.TopologyEdge;
weibitf32383b2014-10-22 10:17:31 -070042import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44
Brian O'Connor772852a2014-11-17 15:51:19 -080045import java.util.Iterator;
46import java.util.List;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080047import java.util.Map;
Brian O'Connor772852a2014-11-17 15:51:19 -080048import java.util.Set;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080049import java.util.concurrent.ConcurrentHashMap;
50
51import static org.onosproject.net.intent.IntentState.INSTALLED;
Praseed Balakrishnanc0029652014-11-14 13:38:49 -080052
weibitf32383b2014-10-22 10:17:31 -070053/**
54 * OpticalPathProvisioner listens event notifications from the Intent F/W.
55 * It generates one or more opticalConnectivityIntent(s) and submits (or withdraws) to Intent F/W
56 * for adding/releasing capacity at the packet layer.
57 *
58 */
59
60@Component(immediate = true)
61public class OpticalPathProvisioner {
62
63 protected static final Logger log = LoggerFactory
64 .getLogger(OpticalPathProvisioner.class);
65
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 private IntentService intentService;
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Brian O'Connor772852a2014-11-17 15:51:19 -080070 protected PathService pathService;
weibitf32383b2014-10-22 10:17:31 -070071
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected CoreService coreService;
74
weibit7e583462014-10-23 10:14:05 -070075 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Praseed Balakrishnanc0029652014-11-14 13:38:49 -080076 protected HostService hostService;
77
weibitf32383b2014-10-22 10:17:31 -070078 private ApplicationId appId;
weibitf32383b2014-10-22 10:17:31 -070079
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080080 // TODO use a shared map for distributed operation
81 protected final Map<ConnectPoint, OpticalConnectivityIntent> inStatusTportMap =
82 new ConcurrentHashMap<>();
83 protected final Map<ConnectPoint, OpticalConnectivityIntent> outStatusTportMap =
84 new ConcurrentHashMap<>();
85
86 protected final Map<ConnectPoint, Map<ConnectPoint, Intent>> intentMap =
87 new ConcurrentHashMap<>();
weibitf32383b2014-10-22 10:17:31 -070088
89 private final InternalOpticalPathProvisioner pathProvisioner = new InternalOpticalPathProvisioner();
90
91 @Activate
92 protected void activate() {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080093 // TODO elect a leader and have one instance do the provisioning
weibitf32383b2014-10-22 10:17:31 -070094 intentService.addListener(pathProvisioner);
Brian O'Connorabafb502014-12-02 22:26:20 -080095 appId = coreService.registerApplication("org.onosproject.optical");
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -080096 initTport();
weibitf32383b2014-10-22 10:17:31 -070097 log.info("Starting optical path provisoning...");
98 }
99
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800100 protected void initTport() {
101 inStatusTportMap.clear();
102 outStatusTportMap.clear();
103 for (Intent intent : intentService.getIntents()) {
104 if (intentService.getIntentState(intent.id()) == INSTALLED) {
105 if (intent instanceof OpticalConnectivityIntent) {
106 inStatusTportMap.put(((OpticalConnectivityIntent) intent).getSrc(),
107 (OpticalConnectivityIntent) intent);
108 outStatusTportMap.put(((OpticalConnectivityIntent) intent).getDst(),
109 (OpticalConnectivityIntent) intent);
110 }
111 }
112 }
113 }
114
weibitf32383b2014-10-22 10:17:31 -0700115 protected void deactivate() {
116 intentService.removeListener(pathProvisioner);
117 }
118
119 public class InternalOpticalPathProvisioner implements IntentListener {
120 @Override
121 public void event(IntentEvent event) {
122 switch (event.type()) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800123 case INSTALL_REQ:
weibitf32383b2014-10-22 10:17:31 -0700124 break;
125 case INSTALLED:
126 break;
127 case FAILED:
weibit50eb95b2014-10-25 21:47:54 -0700128 log.info("packet intent {} failed, calling optical path provisioning APP.", event.subject());
Brian O'Connor772852a2014-11-17 15:51:19 -0800129 setupLightpath(event.subject());
weibitf32383b2014-10-22 10:17:31 -0700130 break;
131 case WITHDRAWN:
132 log.info("intent {} withdrawn.", event.subject());
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800133 //FIXME
134 //teardownLightpath(event.subject());
weibitf32383b2014-10-22 10:17:31 -0700135 break;
136 default:
137 break;
138 }
139 }
140
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800141 private void reserveTport(Intent intent) {
142 // TODO move to resourceManager
143 if (intent instanceof OpticalConnectivityIntent) {
144 OpticalConnectivityIntent opticalIntent =
145 (OpticalConnectivityIntent) intent;
146 if (inStatusTportMap.containsKey(opticalIntent.getSrc()) ||
147 outStatusTportMap.containsKey(opticalIntent.getDst())) {
148 //TODO throw an exception, perhaps
149 log.warn("Overlapping reservation: {}", opticalIntent);
150 }
151 inStatusTportMap.put(opticalIntent.getSrc(), opticalIntent);
152 outStatusTportMap.put(opticalIntent.getDst(), opticalIntent);
153 }
154 }
155
156 /**
157 * Registers an intent from src to dst.
158 * @param src source point
159 * @param dst destination point
160 * @param intent intent to be registered
161 * @return true if intent has not been previously added, false otherwise
162 */
163 private boolean addIntent(ConnectPoint src, ConnectPoint dst, Intent intent) {
164 Map<ConnectPoint, Intent> srcMap = intentMap.get(src);
165 if (srcMap == null) {
166 srcMap = new ConcurrentHashMap<>();
167 intentMap.put(src, srcMap);
168 }
169 if (srcMap.containsKey(dst)) {
170 return false;
171 } else {
172 srcMap.put(dst, intent);
173 return true;
174 }
175 }
176
Brian O'Connor772852a2014-11-17 15:51:19 -0800177 private void setupLightpath(Intent intent) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800178 // TODO change the coordination approach between packet intents and optical intents
179 // Low speed LLDP may cause multiple calls which are not expected
180
181 if (!IntentState.FAILED.equals(intentService.getIntentState(intent.id()))) {
182 return;
183 }
184
Brian O'Connor772852a2014-11-17 15:51:19 -0800185 List<Intent> intents = Lists.newArrayList();
186 if (intent instanceof HostToHostIntent) {
187 HostToHostIntent hostToHostIntent = (HostToHostIntent) intent;
188 Host one = hostService.getHost(hostToHostIntent.one());
189 Host two = hostService.getHost(hostToHostIntent.two());
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800190 if (one == null || two == null) {
191 return; //FIXME
192 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800193 // provision both directions
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800194 intents.addAll(getOpticalPath(one.location(), two.location()));
195 intents.addAll(getOpticalPath(two.location(), one.location()));
Brian O'Connor772852a2014-11-17 15:51:19 -0800196 } else if (intent instanceof PointToPointIntent) {
197 PointToPointIntent p2pIntent = (PointToPointIntent) intent;
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800198 intents.addAll(getOpticalPath(p2pIntent.ingressPoint(), p2pIntent.egressPoint()));
Brian O'Connor772852a2014-11-17 15:51:19 -0800199 } else {
200 log.info("Unsupported intent type: {}", intent.getClass());
201 }
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800202
Brian O'Connor772852a2014-11-17 15:51:19 -0800203 // Build the intent batch
Brian O'Connor72a034c2014-11-26 18:24:23 -0800204 IntentOperations.Builder ops = IntentOperations.builder(appId);
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)) {
211 ops.addSubmitOperation(i);
212 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 }
218 intentService.execute(ops.build());
weibit7e583462014-10-23 10:14:05 -0700219 }
220
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800221 private List<Intent> getOpticalPath(ConnectPoint ingress, ConnectPoint egress) {
Brian O'Connor772852a2014-11-17 15:51:19 -0800222 Set<Path> paths = pathService.getPaths(ingress.deviceId(),
223 egress.deviceId(),
224 new OpticalLinkWeight());
225
226 if (paths.isEmpty()) {
227 return Lists.newArrayList();
weibit7e583462014-10-23 10:14:05 -0700228 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800229
Brian O'Connor772852a2014-11-17 15:51:19 -0800230 List<Intent> connectionList = Lists.newArrayList();
231
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800232 Iterator<Path> itrPath = paths.iterator();
233 while (itrPath.hasNext()) {
234 boolean usedTportFound = false;
235 Path nextPath = itrPath.next();
236 log.info(nextPath.links().toString()); // TODO drop log level
Brian O'Connor772852a2014-11-17 15:51:19 -0800237
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800238 Iterator<Link> itrLink = nextPath.links().iterator();
239 while (itrLink.hasNext()) {
240 ConnectPoint srcWdmPoint, dstWdmPoint;
241 Link link1 = itrLink.next();
242 if (!isOpticalLink(link1)) {
243 continue;
Brian O'Connor772852a2014-11-17 15:51:19 -0800244 } else {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800245 srcWdmPoint = link1.dst();
246 dstWdmPoint = srcWdmPoint;
247 }
248
249 while (itrLink.hasNext()) {
250 Link link2 = itrLink.next();
251 if (isOpticalLink(link2)) {
252 dstWdmPoint = link2.src();
253 } else {
254 break;
255 }
256 }
257
258 if (inStatusTportMap.get(srcWdmPoint) != null ||
259 outStatusTportMap.get(dstWdmPoint) != null) {
260 usedTportFound = true;
261 // log.info("used ConnectPoint {} to {} were found", srcWdmPoint, dstWdmPoint);
Brian O'Connor772852a2014-11-17 15:51:19 -0800262 break;
263 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800264
265 Intent opticalIntent = new OpticalConnectivityIntent(appId,
266 srcWdmPoint,
267 dstWdmPoint);
268 log.info("Creating optical intent from {} to {}", srcWdmPoint, dstWdmPoint);
269 connectionList.add(opticalIntent);
270
271 break;
Brian O'Connor772852a2014-11-17 15:51:19 -0800272 }
273
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800274 if (!usedTportFound) {
275 break;
276 } else {
277 // reset the connection list
278 connectionList = Lists.newArrayList();
279 }
280
Brian O'Connor772852a2014-11-17 15:51:19 -0800281 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800282
Brian O'Connor772852a2014-11-17 15:51:19 -0800283 return connectionList;
284 }
285
weibitf32383b2014-10-22 10:17:31 -0700286 private void teardownLightpath(Intent intent) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800287 /* FIXME this command doesn't make much sense. we need to define the semantics
288 // TODO move to resourceManager
289 if (intent instanceof OpticalConnectivityIntent) {
290 inStatusTportMap.remove(((OpticalConnectivityIntent) intent).getSrc());
291 outStatusTportMap.remove(((OpticalConnectivityIntent) intent).getDst());
292 // TODO tear down the idle lightpath if the utilization is zero.
293
294 }
295 */ //end-FIXME
weibitf32383b2014-10-22 10:17:31 -0700296 }
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800297
Brian O'Connor772852a2014-11-17 15:51:19 -0800298 }
weibitf32383b2014-10-22 10:17:31 -0700299
Brian O'Connor772852a2014-11-17 15:51:19 -0800300 private static boolean isOpticalLink(Link link) {
301 boolean isOptical = false;
302 Link.Type lt = link.type();
303 if (lt == Link.Type.OPTICAL) {
304 isOptical = true;
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800305 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800306 return isOptical;
307 }
Praseed Balakrishnanc0029652014-11-14 13:38:49 -0800308
Brian O'Connor772852a2014-11-17 15:51:19 -0800309 private static class OpticalLinkWeight implements LinkWeight {
310 @Override
311 public double weight(TopologyEdge edge) {
Praseed Balakrishnan00dd1f92014-11-19 17:12:36 -0800312 if (edge.link().state() == Link.State.INACTIVE) {
313 return -1; // ignore inactive links
314 }
Brian O'Connor772852a2014-11-17 15:51:19 -0800315 if (isOpticalLink(edge.link())) {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800316 return 1000; // optical links
Brian O'Connor772852a2014-11-17 15:51:19 -0800317 } else {
Brian O'Connorc7bdd8c2014-12-08 01:29:53 -0800318 return 1; // packet links
Brian O'Connor772852a2014-11-17 15:51:19 -0800319 }
320 }
weibitf32383b2014-10-22 10:17:31 -0700321 }
322
323}