blob: 12d85d69b8a11337b9d776d7ea999c3b99df1f17 [file] [log] [blame]
Jonathan Hartaa380972014-04-03 10:24:46 -07001package net.onrc.onos.core.intent.runtime;
Toshio Koide4f308732014-02-18 15:19:48 -08002
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.HashMap;
Toshio Koide798bc1b2014-02-20 14:02:40 -08006import java.util.HashSet;
Toshio Koidedf2eab92014-02-20 11:24:59 -08007import java.util.Iterator;
Toshio Koidebf875662014-02-24 12:19:15 -08008import java.util.LinkedList;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -07009import java.util.List;
Toshio Koide4f308732014-02-18 15:19:48 -080010import java.util.Map;
Toshio Koide066506e2014-02-20 19:52:09 -080011import java.util.Map.Entry;
TeruUf9111652014-05-14 23:10:35 -070012import java.util.Set;
13import java.util.concurrent.ConcurrentHashMap;
Toshio Koide353a9e12014-06-09 21:03:40 -070014import java.util.concurrent.ConcurrentMap;
Toshio Koide93be5d62014-02-23 19:30:57 -080015import java.util.concurrent.locks.ReentrantLock;
Toshio Koide4f308732014-02-18 15:19:48 -080016
17import net.floodlightcontroller.core.module.FloodlightModuleContext;
18import net.floodlightcontroller.core.module.FloodlightModuleException;
19import net.floodlightcontroller.core.module.IFloodlightModule;
20import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov13669052014-05-13 10:33:39 -070021import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -070022import net.floodlightcontroller.util.MACAddress;
23import net.onrc.onos.api.intent.ApplicationIntent;
Jonathan Hart6df90172014-04-03 10:13:11 -070024import net.onrc.onos.core.datagrid.IDatagridService;
25import net.onrc.onos.core.datagrid.IEventChannel;
26import net.onrc.onos.core.datagrid.IEventChannelListener;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -070027import net.onrc.onos.core.intent.ConstrainedShortestPathIntent;
Jonathan Hartaa380972014-04-03 10:24:46 -070028import net.onrc.onos.core.intent.Intent;
Jonathan Harta99ec672014-04-03 11:30:34 -070029import net.onrc.onos.core.intent.Intent.IntentState;
Jonathan Hartaa380972014-04-03 10:24:46 -070030import net.onrc.onos.core.intent.IntentMap;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -070031import net.onrc.onos.core.intent.IntentMap.ChangedEvent;
32import net.onrc.onos.core.intent.IntentMap.ChangedListener;
Jonathan Hartaa380972014-04-03 10:24:46 -070033import net.onrc.onos.core.intent.IntentOperation;
Jonathan Harta99ec672014-04-03 11:30:34 -070034import net.onrc.onos.core.intent.IntentOperation.Operator;
Jonathan Hartaa380972014-04-03 10:24:46 -070035import net.onrc.onos.core.intent.IntentOperationList;
36import net.onrc.onos.core.intent.PathIntent;
37import net.onrc.onos.core.intent.PathIntentMap;
38import net.onrc.onos.core.intent.ShortestPathIntent;
Pavlin Radoslavov13669052014-05-13 10:33:39 -070039import net.onrc.onos.core.intent.runtime.web.IntentWebRoutable;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070040import net.onrc.onos.core.metrics.OnosMetrics;
41import net.onrc.onos.core.metrics.OnosMetrics.MetricsComponent;
42import net.onrc.onos.core.metrics.OnosMetrics.MetricsFeature;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070043import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070044import net.onrc.onos.core.topology.ITopologyListener;
45import net.onrc.onos.core.topology.ITopologyService;
Jonathan Hart472062d2014-04-03 10:56:48 -070046import net.onrc.onos.core.topology.LinkEvent;
47import net.onrc.onos.core.topology.PortEvent;
48import net.onrc.onos.core.topology.SwitchEvent;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070049import net.onrc.onos.core.topology.TopologyEvents;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -070050import net.onrc.onos.core.util.Dpid;
Yuta HIGUCHIb8093642014-07-16 13:17:07 -070051import net.onrc.onos.core.util.LinkTuple;
Toshio Koide4f308732014-02-18 15:19:48 -080052
Jonathan Harta99ec672014-04-03 11:30:34 -070053import org.slf4j.Logger;
54import org.slf4j.LoggerFactory;
55
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070056import com.codahale.metrics.Gauge;
57import com.codahale.metrics.Meter;
58
Toshio Koide0c9106d2014-02-19 15:26:38 -080059/**
Toshio Koidefdb75932014-06-16 17:59:24 -070060 * The PathCalcRuntimeModule contains the PathCalcRuntime and PersistIntent.
61 * <p>
62 * It is responsible for converting operations for application level intents
63 * into operations for path level intents and send the converted operations
64 * to PlanCalcRuntimeModule in order to calculate flow entries and install them.
Toshio Koide0c9106d2014-02-19 15:26:38 -080065 */
Jonathan Hartc00f5c22014-06-10 15:14:40 -070066public class PathCalcRuntimeModule implements IFloodlightModule,
67 IPathCalcRuntimeService,
68 ITopologyListener,
69 IEventChannelListener<Long, IntentStateList> {
Toshio Koidefdb75932014-06-16 17:59:24 -070070
71 /**
72 * Logging object for performance measurement.
73 * TODO: merge this into measurement framework
74 */
Pavlin Radoslavovfee80982014-04-10 12:12:04 -070075 static class PerfLog {
Ray Milkey269ffb92014-04-03 14:43:30 -070076 private String step;
77 private long time;
Toshio Koidebf875662014-02-24 12:19:15 -080078
Ray Milkey269ffb92014-04-03 14:43:30 -070079 public PerfLog(String step) {
80 this.step = step;
81 this.time = System.nanoTime();
82 }
Toshio Koidebf875662014-02-24 12:19:15 -080083
Ray Milkey269ffb92014-04-03 14:43:30 -070084 public void logThis() {
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -070085 log.debug("Time:{}, Step:{}", time, step);
Ray Milkey269ffb92014-04-03 14:43:30 -070086 }
87 }
Toshio Koidebf875662014-02-24 12:19:15 -080088
Toshio Koidefdb75932014-06-16 17:59:24 -070089 /**
90 * Formatted logger for performance measurement.
91 * TODO: merge this into measurement framework
92 */
Pavlin Radoslavov53ad5e32014-04-10 14:24:26 -070093 static class PerfLogger {
Ray Milkey269ffb92014-04-03 14:43:30 -070094 private LinkedList<PerfLog> logData = new LinkedList<>();
Toshio Koidebf875662014-02-24 12:19:15 -080095
Ray Milkey269ffb92014-04-03 14:43:30 -070096 public PerfLogger(String logPhase) {
97 log("start_" + logPhase);
98 }
Toshio Koidebf875662014-02-24 12:19:15 -080099
Ray Milkey269ffb92014-04-03 14:43:30 -0700100 public void log(String step) {
101 logData.add(new PerfLog(step));
102 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800103
Ray Milkey269ffb92014-04-03 14:43:30 -0700104 public void flushLog() {
105 log("finish");
Ray Milkey5df613b2014-04-15 10:50:56 -0700106 for (PerfLog perfLog : logData) {
107 perfLog.logThis();
Ray Milkey269ffb92014-04-03 14:43:30 -0700108 }
109 logData.clear();
110 }
111 }
Toshio Koide4f308732014-02-18 15:19:48 -0800112
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700113 /**
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700114 * A class to track the status of high-level intents.
115 * Currently, it is used for monitoring and measurement purposes.
116 */
117 private class HighLevelIntentsTracker implements ChangedListener {
118 @Override
119 public void intentsChange(LinkedList<ChangedEvent> events) {
120 //
121 // Process the events one-by-one and collect measurements.
122 //
123 for (ChangedEvent event : events) {
124 log.debug("HighLevelIntentsTracker: Intent ID {}, eventType {}, intentState {}",
125 event.intent.getId(), event.eventType,
126 event.intent.getState());
127
128 //
129 // Update the metrics
130 //
131 switch (event.eventType) {
132 case ADDED:
133 break;
134 case REMOVED:
135 break;
136 case STATE_CHANGED:
137 IntentState state = event.intent.getState();
138 switch (state) {
139 case INST_REQ:
140 break;
141 case INST_ACK:
142 intentAddProcessingRate.mark(1);
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700143 intentAddEndTimestampEpochMs = System.currentTimeMillis();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700144 break;
145 case INST_NACK:
146 break;
147 case DEL_REQ:
148 break;
149 case DEL_ACK:
150 intentRemoveProcessingRate.mark(1);
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700151 intentRemoveEndTimestampEpochMs = System.currentTimeMillis();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700152 break;
153 case DEL_PENDING:
154 break;
155 case REROUTE_REQ:
156 break;
157 default:
158 break;
159 }
160 break;
161 default:
162 break;
163 }
164 }
165 }
166 }
167
168 /**
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700169 * A class to track the deletion of intents and purge them as appropriate.
170 */
171 private class DeleteIntentsTracker implements ChangedListener {
172 @Override
173 public void intentsChange(LinkedList<ChangedEvent> events) {
174 List<String> removeIntentIds = new LinkedList<String>();
175 List<String> removePathIds = new LinkedList<String>();
176
177 //
178 // Process the events one-by-one and collect the Intent IDs of
179 // those intents that should be purged.
180 //
181 for (ChangedEvent event : events) {
182 log.debug("DeleteIntentsTracker: Intent ID {}, eventType {}",
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700183 event.intent.getId(), event.eventType);
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700184 PathIntent pathIntent = (PathIntent) pathIntents.getIntent(event.intent.getId());
185 if (pathIntent == null) {
186 continue;
187 }
188
189 //
190 // Test whether the new Intent state allows the Intent
191 // to be purged.
192 //
193 boolean shouldPurge = false;
194 switch (event.eventType) {
195 case ADDED:
196 break;
197 case REMOVED:
198 break;
199 case STATE_CHANGED:
200 IntentState state = pathIntent.getState();
201 switch (state) {
202 case INST_REQ:
203 break;
204 case INST_ACK:
205 break;
206 case INST_NACK:
207 shouldPurge = true;
208 break;
209 case DEL_REQ:
210 break;
211 case DEL_ACK:
212 shouldPurge = true;
213 break;
214 case DEL_PENDING:
215 break;
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700216 case REROUTE_REQ:
217 break;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700218 default:
219 break;
220 }
221 break;
222 default:
223 break;
224 }
225
226 if (shouldPurge) {
227 removePathIds.add(pathIntent.getId());
228 Intent parentIntent = pathIntent.getParentIntent();
229 if (parentIntent != null) {
230 //
231 // Remove the High-level Intent only if it was
232 // explicitly deleted by the user via the API.
233 //
234 String intentId = parentIntent.getId();
235 if (removedApplicationIntentIds.contains(intentId)) {
236 removeIntentIds.add(intentId);
237 removedApplicationIntentIds.remove(intentId);
238 }
239 }
240 }
241 }
242
243 // Purge the intents
244 if (!removeIntentIds.isEmpty()) {
245 highLevelIntents.purge(removeIntentIds);
246 }
247 if (!removePathIds.isEmpty()) {
248 pathIntents.purge(removePathIds);
249 }
250 }
251 }
252
Ray Milkey269ffb92014-04-03 14:43:30 -0700253 private PathCalcRuntime runtime;
254 private IDatagridService datagridService;
Jonathan Harte37e4e22014-05-13 19:12:02 -0700255 private ITopologyService topologyService;
Ray Milkey269ffb92014-04-03 14:43:30 -0700256 private IntentMap highLevelIntents;
257 private PathIntentMap pathIntents;
258 private IControllerRegistryService controllerRegistry;
259 private PersistIntent persistIntent;
Pavlin Radoslavov13669052014-05-13 10:33:39 -0700260 private IRestApiService restApi;
Toshio Koide798bc1b2014-02-20 14:02:40 -0800261
Ray Milkey269ffb92014-04-03 14:43:30 -0700262 private IEventChannel<Long, IntentOperationList> opEventChannel;
TeruU9e530662014-05-18 11:49:37 -0700263 private final ReentrantLock lock = new ReentrantLock(true);
Ray Milkey269ffb92014-04-03 14:43:30 -0700264 private static final String INTENT_OP_EVENT_CHANNEL_NAME = "onos.pathintent";
265 private static final String INTENT_STATE_EVENT_CHANNEL_NAME = "onos.pathintent_state";
266 private static final Logger log = LoggerFactory.getLogger(PathCalcRuntimeModule.class);
Toshio Koidea10c0372014-02-20 17:28:10 -0800267
Yuta HIGUCHIb8093642014-07-16 13:17:07 -0700268 private HashSet<LinkTuple> unmatchedLinkEvents = new HashSet<>();
Toshio Koide353a9e12014-06-09 21:03:40 -0700269 private ConcurrentMap<String, Set<Long>> intentInstalledMap = new ConcurrentHashMap<String, Set<Long>>();
270 private ConcurrentMap<String, Intent> staleIntents = new ConcurrentHashMap<String, Intent>();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700271 private DeleteIntentsTracker deleteIntentsTracker = new DeleteIntentsTracker();
272 private Set<String> removedApplicationIntentIds = new HashSet<String>();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700273 private HighLevelIntentsTracker highLevelIntentsTracker = new HighLevelIntentsTracker();
274
275 //
276 // Metrics
277 //
278 private static final MetricsComponent METRICS_COMPONENT =
279 OnosMetrics.registerComponent("Intents");
280 private static final MetricsFeature METRICS_FEATURE_ADD_OPERATION =
281 METRICS_COMPONENT.registerFeature("AddOperation");
282 private static final MetricsFeature METRICS_FEATURE_REMOVE_OPERATION =
283 METRICS_COMPONENT.registerFeature("RemoveOperation");
284 //
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700285 // Timestamp of the incoming Add Intent API operation (ms from the Epoch)
286 private volatile long intentAddBeginTimestampEpochMs = 0;
287 private final Gauge<Long> gaugeIntentAddBeginTimestampEpochMs =
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700288 OnosMetrics.registerMetric(METRICS_COMPONENT,
289 METRICS_FEATURE_ADD_OPERATION,
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700290 "BeginOperationTimestamp.EpochMs",
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700291 new Gauge<Long>() {
292 @Override
293 public Long getValue() {
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700294 return intentAddBeginTimestampEpochMs;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700295 }
296 });
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700297 // Timestamp of the Add Intent operation completion (ms from the Epoch)
298 private volatile long intentAddEndTimestampEpochMs = 0;
299 private final Gauge<Long> gaugeIntentAddEndTimestampEpochMs =
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700300 OnosMetrics.registerMetric(METRICS_COMPONENT,
301 METRICS_FEATURE_ADD_OPERATION,
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700302 "EndOperationTimestamp.EpochMs",
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700303 new Gauge<Long>() {
304 @Override
305 public Long getValue() {
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700306 return intentAddEndTimestampEpochMs;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700307 }
308 });
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700309 // Timestamp of the incoming Remove Intent API operation (ms from the Epoch)
310 private volatile long intentRemoveBeginTimestampEpochMs = 0;
311 private final Gauge<Long> gaugeIntentRemoveBeginTimestampEpochMs =
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700312 OnosMetrics.registerMetric(METRICS_COMPONENT,
313 METRICS_FEATURE_REMOVE_OPERATION,
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700314 "BeginOperationTimestamp.EpochMs",
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700315 new Gauge<Long>() {
316 @Override
317 public Long getValue() {
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700318 return intentRemoveBeginTimestampEpochMs;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700319 }
320 });
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700321 // Timestamp of the Remove Intent operation completion (ms from the Epoch)
322 private volatile long intentRemoveEndTimestampEpochMs = 0;
323 private final Gauge<Long> gaugeIntentRemoveEndTimestampEpochMs =
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700324 OnosMetrics.registerMetric(METRICS_COMPONENT,
325 METRICS_FEATURE_REMOVE_OPERATION,
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700326 "EndOperationTimestamp.EpochMs",
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700327 new Gauge<Long>() {
328 @Override
329 public Long getValue() {
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700330 return intentRemoveEndTimestampEpochMs;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700331 }
332 });
333 //
334 // Rate of the incoming Add Intent API operations
335 private final Meter intentAddIncomingRate =
336 OnosMetrics.createMeter(METRICS_COMPONENT,
337 METRICS_FEATURE_ADD_OPERATION,
338 "IncomingRate");
339 // Rate of processing the Add Intent operations
340 private final Meter intentAddProcessingRate =
341 OnosMetrics.createMeter(METRICS_COMPONENT,
342 METRICS_FEATURE_ADD_OPERATION,
343 "ProcessingRate");
344 // Rate of the incoming Remove Intent API operations
345 private final Meter intentRemoveIncomingRate =
346 OnosMetrics.createMeter(METRICS_COMPONENT,
347 METRICS_FEATURE_REMOVE_OPERATION,
348 "IncomingRate");
349 // Rate of processing the Remove Intent operations
350 private final Meter intentRemoveProcessingRate =
351 OnosMetrics.createMeter(METRICS_COMPONENT,
352 METRICS_FEATURE_REMOVE_OPERATION,
353 "ProcessingRate");
Toshio Koide353a9e12014-06-09 21:03:40 -0700354
Ray Milkey269ffb92014-04-03 14:43:30 -0700355 // ================================================================================
356 // private methods
357 // ================================================================================
358
Toshio Koidefdb75932014-06-16 17:59:24 -0700359 /**
360 * Creates operations (IntentOperationList) for Application-level
361 * intents that should be rerouted because of topology change,
362 * and execute the created operations.
363 *
364 * @param oldPaths a list of invalid path intents (which should be rerouted)
365 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700366 private void reroutePaths(Collection<Intent> oldPaths) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700367 if (oldPaths == null || oldPaths.isEmpty()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700368 return;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700369 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700370
371 IntentOperationList reroutingOperation = new IntentOperationList();
372 for (Intent intent : oldPaths) {
373 PathIntent pathIntent = (PathIntent) intent;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700374 if (pathIntent.isPathFrozen()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700375 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700376 }
Toshio Koide353a9e12014-06-09 21:03:40 -0700377 Intent parentIntent = pathIntent.getParentIntent();
378 if (parentIntent == null) {
379 continue;
380 }
381 if (pathIntent.getState().equals(IntentState.INST_ACK)) {
382 if (!reroutingOperation.contains(parentIntent)) {
383 // reroute now
384 reroutingOperation.add(Operator.ADD, parentIntent);
385 }
386 } else if (pathIntent.getState().equals(IntentState.INST_REQ)) {
387 // reroute after the completion of the current execution
388 staleIntents.put(parentIntent.getId(), parentIntent);
389 log.debug("pending reroute execution for intent ID:{}", parentIntent.getId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700390 }
391 }
392 executeIntentOperations(reroutingOperation);
393 }
Toshio Koidea94060f2014-02-21 22:58:32 -0800394
Toshio Koidefdb75932014-06-16 17:59:24 -0700395 /**
396 * Checks whether the entire path's flow entries are installed or not.
397 *
398 * @param pathIntent : The pathIntent to be checked
399 * @param installedDpids : The dpids installed on one ONOS instance
400 * @return The result of whether a pathIntent has been installed or not.
401 */
402 private boolean isFlowInstalled(PathIntent pathIntent, Set<Long> installedDpids) {
403 String pathIntentId = pathIntent.getId();
404
405 if (intentInstalledMap.containsKey(pathIntentId)) {
406 if (!installedDpids.isEmpty()) {
407 intentInstalledMap.get(pathIntentId).addAll(installedDpids);
408 }
409 } else {
410 // This is the creation of an entry.
411 intentInstalledMap.put(pathIntentId, installedDpids);
412 }
413
414 Set<Long> allSwitchesForPath = new HashSet<Long>();
415 ShortestPathIntent spfIntent = (ShortestPathIntent) pathIntent.getParentIntent();
416
417 for (LinkEvent linkEvent : pathIntent.getPath()) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700418 long sw = linkEvent.getSrc().getDpid().value();
Toshio Koidefdb75932014-06-16 17:59:24 -0700419 allSwitchesForPath.add(sw);
420 }
421 allSwitchesForPath.add(spfIntent.getDstSwitchDpid());
422
423 if (log.isDebugEnabled()) {
424 log.debug("checking flow installation. ID:{}, dpids:{}, installed:{}",
425 pathIntentId,
426 allSwitchesForPath,
427 intentInstalledMap.get(pathIntentId));
428 }
429
430 if (allSwitchesForPath.equals(intentInstalledMap.get(pathIntentId))) {
431 intentInstalledMap.remove(pathIntentId);
432 return true;
433 }
434
435 return false;
436 }
437
438 /**
439 * Enumerates switch dpids along the specified path and inside the specified domain.
440 *
441 * @param pathIntent the path for enumeration
442 * @param domainSwitchDpids a set of the domain switch dpids
443 * @return a set of switch dpids along the specified path and inside the specified domain
444 */
445 private Set<Long> calcInstalledDpids(PathIntent pathIntent, Set<Long> domainSwitchDpids) {
446 Set<Long> allSwitchesForPath = new HashSet<Long>();
447 ShortestPathIntent spfIntent = (ShortestPathIntent) pathIntent.getParentIntent();
448
449 for (LinkEvent linkEvent : pathIntent.getPath()) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700450 long sw = linkEvent.getSrc().getDpid().value();
Toshio Koidefdb75932014-06-16 17:59:24 -0700451
452 if (domainSwitchDpids.contains(sw)) {
453 allSwitchesForPath.add(sw);
454 }
455 }
456
457 if (domainSwitchDpids.contains(spfIntent.getDstSwitchDpid())) {
458 allSwitchesForPath.add(spfIntent.getDstSwitchDpid());
459 }
460
461 if (log.isTraceEnabled()) {
462 log.trace("All switches for a path {}, domain switch dpids {}", allSwitchesForPath, domainSwitchDpids);
463 }
464
465 return allSwitchesForPath;
466 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800467
Ray Milkey269ffb92014-04-03 14:43:30 -0700468 // ================================================================================
469 // IFloodlightModule implementations
470 // ================================================================================
Toshio Koide798bc1b2014-02-20 14:02:40 -0800471
Toshio Koidefdb75932014-06-16 17:59:24 -0700472 /**
473 * {@inheritDoc}
474 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700475 @Override
476 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
477 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>(1);
478 l.add(IPathCalcRuntimeService.class);
479 return l;
480 }
Toshio Koide4f308732014-02-18 15:19:48 -0800481
Toshio Koidefdb75932014-06-16 17:59:24 -0700482 /**
483 * {@inheritDoc}
484 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700485 @Override
486 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
487 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
488 m.put(IPathCalcRuntimeService.class, this);
489 return m;
490 }
Toshio Koide4f308732014-02-18 15:19:48 -0800491
Toshio Koidefdb75932014-06-16 17:59:24 -0700492 /**
493 * {@inheritDoc}
494 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700495 @Override
496 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
497 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>(2);
498 l.add(IDatagridService.class);
Pavlin Radoslavov13669052014-05-13 10:33:39 -0700499 l.add(IRestApiService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700500 l.add(ITopologyService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700501 return l;
502 }
Toshio Koide4f308732014-02-18 15:19:48 -0800503
Toshio Koidefdb75932014-06-16 17:59:24 -0700504 /**
505 * {@inheritDoc}
506 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700507 @Override
508 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
509 datagridService = context.getServiceImpl(IDatagridService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700510 topologyService = context.getServiceImpl(ITopologyService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700511 controllerRegistry = context.getServiceImpl(IControllerRegistryService.class);
Pavlin Radoslavov13669052014-05-13 10:33:39 -0700512 restApi = context.getServiceImpl(IRestApiService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700513 }
Toshio Koide4f308732014-02-18 15:19:48 -0800514
Toshio Koidefdb75932014-06-16 17:59:24 -0700515 /**
516 * {@inheritDoc}
517 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700518 @Override
519 public void startUp(FloodlightModuleContext context) {
520 highLevelIntents = new IntentMap();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700521 highLevelIntents.addChangeListener(highLevelIntentsTracker);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700522 runtime = new PathCalcRuntime(topologyService.getTopology());
Ray Milkey269ffb92014-04-03 14:43:30 -0700523 pathIntents = new PathIntentMap();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700524 pathIntents.addChangeListener(deleteIntentsTracker);
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700525 opEventChannel = datagridService.createChannel(
526 INTENT_OP_EVENT_CHANNEL_NAME, Long.class, IntentOperationList.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700527 datagridService.addListener(INTENT_STATE_EVENT_CHANNEL_NAME, this, Long.class, IntentStateList.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700528 topologyService.registerTopologyListener(this);
Pavlin Radoslavov0294e052014-04-10 13:36:45 -0700529 persistIntent = new PersistIntent(controllerRegistry);
Pavlin Radoslavov13669052014-05-13 10:33:39 -0700530 restApi.addRestletRoutable(new IntentWebRoutable());
Ray Milkey269ffb92014-04-03 14:43:30 -0700531 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800532
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700533 // ======================================================================
Ray Milkey269ffb92014-04-03 14:43:30 -0700534 // IPathCalcRuntimeService implementations
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700535 // ======================================================================
536
537 /**
Toshio Koidefdb75932014-06-16 17:59:24 -0700538 * {@inheritDoc}
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700539 */
540 @Override
541 public boolean addApplicationIntents(
542 final String appId,
543 Collection<ApplicationIntent> appIntents) {
544 //
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700545 // Update the metrics
546 //
547 if (!appIntents.isEmpty()) {
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700548 this.intentAddBeginTimestampEpochMs = System.currentTimeMillis();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700549 this.intentAddIncomingRate.mark(appIntents.size());
550 }
551
552 //
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700553 // Process all intents one-by-one
554 //
555 // TODO: The Intent Type should be enum instead of a string,
556 // and we should use a switch statement below to process the
557 // different type of intents.
558 //
559 IntentOperationList intentOperations = new IntentOperationList();
560 for (ApplicationIntent appIntent : appIntents) {
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700561 String appIntentId = appId + ":" + appIntent.getIntentId();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700562
563 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700564 Dpid srcSwitchDpid = new Dpid(appIntent.getSrcSwitchDpid());
565 Dpid dstSwitchDpid = new Dpid(appIntent.getDstSwitchDpid());
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700566
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700567 if (appIntent.getIntentType().equals("SHORTEST_PATH")) {
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700568 //
569 // Process Shortest-Path Intent
570 //
571 ShortestPathIntent spi =
572 new ShortestPathIntent(appIntentId,
573 srcSwitchDpid.value(),
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700574 appIntent.getSrcSwitchPort(),
575 MACAddress.valueOf(appIntent.getMatchSrcMac()).toLong(),
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700576 dstSwitchDpid.value(),
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700577 appIntent.getDstSwitchPort(),
578 MACAddress.valueOf(appIntent.getMatchDstMac()).toLong());
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700579 spi.setPathFrozen(appIntent.isStaticPath());
580 intentOperations.add(operator, spi);
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700581 } else if (appIntent.getIntentType().equals("CONSTRAINED_SHORTEST_PATH")) {
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700582 //
583 // Process Constrained Shortest-Path Intent
584 //
585 ConstrainedShortestPathIntent cspi =
586 new ConstrainedShortestPathIntent(appIntentId,
587 srcSwitchDpid.value(),
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700588 appIntent.getSrcSwitchPort(),
589 MACAddress.valueOf(appIntent.getMatchSrcMac()).toLong(),
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700590 dstSwitchDpid.value(),
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700591 appIntent.getDstSwitchPort(),
592 MACAddress.valueOf(appIntent.getMatchDstMac()).toLong(),
593 appIntent.getBandwidth());
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700594 cspi.setPathFrozen(appIntent.isStaticPath());
595 intentOperations.add(operator, cspi);
596 } else {
597 log.error("Unknown Application Intent Type: {}",
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700598 appIntent.getIntentType());
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700599 return false;
600 }
601 removedApplicationIntentIds.remove(appIntentId);
602 }
603 // Apply the Intent Operations
604 executeIntentOperations(intentOperations);
605 return true;
606 }
607
608 /**
Toshio Koidefdb75932014-06-16 17:59:24 -0700609 * {@inheritDoc}
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700610 */
611 @Override
612 public boolean removeApplicationIntents(final String appId,
613 Collection<String> intentIds) {
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700614 //
615 // Prepare the timestamp for metrics
616 //
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700617 long timestampEpochMs = System.currentTimeMillis();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700618
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700619 IntentMap intentMap = getHighLevelIntents();
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700620 List<String> removeIntentIds = new LinkedList<String>();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700621
622 //
623 // Process all intents one-by-one
624 //
625 IntentOperationList operations = new IntentOperationList();
626 for (String intentId : intentIds) {
627 String appIntentId = appId + ":" + intentId;
628 Intent intent = intentMap.getIntent(appIntentId);
629 if (intent != null) {
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700630 if (intent.getState() == IntentState.INST_NACK) {
631 // TODO: A hack to remove intents stuck in INST_NACK state
632 removeIntentIds.add(intent.getId());
633 continue;
634 }
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700635 operations.add(IntentOperation.Operator.REMOVE, intent);
636 removedApplicationIntentIds.add(appIntentId);
637 }
638 }
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700639
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700640 //
641 // Update the metrics
642 //
643 if (!operations.isEmpty()) {
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700644 this.intentRemoveBeginTimestampEpochMs = timestampEpochMs;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700645 this.intentRemoveIncomingRate.mark(operations.size());
646 }
647
648 //
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700649 // Purge intents
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700650 //
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700651 if (!removeIntentIds.isEmpty()) {
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700652
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700653 lock.lock(); // TODO optimize locking using smaller steps
654 try {
655 highLevelIntents.purge(removeIntentIds);
656 } finally {
657 lock.unlock();
658 }
659 }
660
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700661 executeIntentOperations(operations);
662
663 return true;
664 }
665
666 /**
Toshio Koidefdb75932014-06-16 17:59:24 -0700667 * {@inheritDoc}
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700668 */
669 @Override
670 public boolean removeAllApplicationIntents(final String appId) {
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700671 //
672 // Prepare the timestamp for metrics
673 //
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700674 long timestampEpochMs = System.currentTimeMillis();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700675
676 Collection<Intent> allHighLevelIntents =
677 getHighLevelIntents().getAllIntents();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700678
679 //
680 // Remove all intents
681 //
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700682 List<String> removeIntentIds = new LinkedList<String>();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700683 IntentOperationList operations = new IntentOperationList();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700684 for (Intent intent : allHighLevelIntents) {
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700685 if (intent.getState() == IntentState.INST_NACK) {
686 // TODO: A hack to remove intents stuck in INST_NACK state
687 removeIntentIds.add(intent.getId());
688 continue;
689 }
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700690 operations.add(IntentOperation.Operator.REMOVE, intent);
691 removedApplicationIntentIds.add(intent.getId());
692 }
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700693
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700694 //
695 // Update the metrics
696 //
697 if (!operations.isEmpty()) {
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700698 this.intentRemoveBeginTimestampEpochMs = timestampEpochMs;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700699 this.intentRemoveIncomingRate.mark(operations.size());
700 }
701
702 //
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700703 // Purge intents
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700704 //
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700705 if (!removeIntentIds.isEmpty()) {
706 lock.lock(); // TODO optimize locking using smaller steps
707 try {
708 highLevelIntents.purge(removeIntentIds);
709 } finally {
710 lock.unlock();
711 }
712 }
713
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700714 executeIntentOperations(operations);
715
716 return true;
717 }
Toshio Koide798bc1b2014-02-20 14:02:40 -0800718
Toshio Koidefdb75932014-06-16 17:59:24 -0700719 /**
720 * {@inheritDoc}
721 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700722 @Override
723 public IntentOperationList executeIntentOperations(IntentOperationList list) {
TeruU9e530662014-05-18 11:49:37 -0700724
Ray Milkeyb29e6262014-04-09 16:02:14 -0700725 if (list == null || list.size() == 0) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700726 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700727 }
Toshio Koide275d8142014-02-24 16:41:52 -0800728
Ray Milkey269ffb92014-04-03 14:43:30 -0700729 lock.lock(); // TODO optimize locking using smaller steps
730 try {
TeruU9e530662014-05-18 11:49:37 -0700731 log.trace("lock executeIntentOperations, lock obj is already locked? {}", lock.isLocked());
Ray Milkey269ffb92014-04-03 14:43:30 -0700732 // update the map of high-level intents
TeruU9e530662014-05-18 11:49:37 -0700733
Ray Milkey269ffb92014-04-03 14:43:30 -0700734 highLevelIntents.executeOperations(list);
Toshio Koidedf2eab92014-02-20 11:24:59 -0800735
Ray Milkey269ffb92014-04-03 14:43:30 -0700736 // change states of high-level intents
737 IntentStateList states = new IntentStateList();
738 for (IntentOperation op : list) {
739 switch (op.operator) {
740 case ADD:
741 switch (op.intent.getState()) {
742 case CREATED:
743 states.put(op.intent.getId(), IntentState.INST_REQ);
744 break;
745 case INST_ACK:
746 states.put(op.intent.getId(), IntentState.REROUTE_REQ);
747 break;
748 default:
749 break;
750 }
751 break;
752 case REMOVE:
753 switch (op.intent.getState()) {
754 case CREATED:
755 states.put(op.intent.getId(), IntentState.DEL_REQ);
756 break;
757 default:
758 break;
759 }
760 break;
761 default:
762 break;
763 }
764 }
765 highLevelIntents.changeStates(states);
Toshio Koidedf2eab92014-02-20 11:24:59 -0800766
Ray Milkey269ffb92014-04-03 14:43:30 -0700767 // calculate path-intents (low-level operations)
Ray Milkey269ffb92014-04-03 14:43:30 -0700768 IntentOperationList pathIntentOperations = runtime.calcPathIntents(list, highLevelIntents, pathIntents);
Toshio Koide600ae5f2014-02-20 18:42:00 -0800769
Ray Milkey269ffb92014-04-03 14:43:30 -0700770 // persist calculated low-level operations into data store
Ray Milkey269ffb92014-04-03 14:43:30 -0700771 long key = persistIntent.getKey();
772 persistIntent.persistIfLeader(key, pathIntentOperations);
Toshio Koide93be5d62014-02-23 19:30:57 -0800773
Ray Milkey269ffb92014-04-03 14:43:30 -0700774 // remove error-intents and reflect them to high-level intents
Ray Milkey269ffb92014-04-03 14:43:30 -0700775 states.clear();
776 Iterator<IntentOperation> i = pathIntentOperations.iterator();
777 while (i.hasNext()) {
778 IntentOperation op = i.next();
779 if (op.operator.equals(Operator.ERROR)) {
780 states.put(op.intent.getId(), IntentState.INST_NACK);
781 i.remove();
782 }
783 }
784 highLevelIntents.changeStates(states);
Toshio Koidea94060f2014-02-21 22:58:32 -0800785
Ray Milkey269ffb92014-04-03 14:43:30 -0700786 // update the map of path intents and publish the path operations
Ray Milkey269ffb92014-04-03 14:43:30 -0700787 pathIntents.executeOperations(pathIntentOperations);
Toshio Koide93be5d62014-02-23 19:30:57 -0800788
Ray Milkey269ffb92014-04-03 14:43:30 -0700789 // send notification
Ray Milkey269ffb92014-04-03 14:43:30 -0700790 // XXX: Send notifications using the same key every time
791 // and receive them by entryAdded() and entryUpdated()
792 opEventChannel.addEntry(0L, pathIntentOperations);
Ray Milkey269ffb92014-04-03 14:43:30 -0700793 //opEventChannel.removeEntry(key);
794 return pathIntentOperations;
795 } finally {
Ray Milkey269ffb92014-04-03 14:43:30 -0700796 lock.unlock();
TeruU9e530662014-05-18 11:49:37 -0700797 log.trace("unlock executeIntentOperations");
Ray Milkey269ffb92014-04-03 14:43:30 -0700798 }
799 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800800
Toshio Koidefdb75932014-06-16 17:59:24 -0700801 /**
802 * {@inheritDoc}
803 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700804 @Override
805 public IntentMap getHighLevelIntents() {
806 return highLevelIntents;
807 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800808
Toshio Koidefdb75932014-06-16 17:59:24 -0700809 /**
810 * {@inheritDoc}
811 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700812 @Override
813 public IntentMap getPathIntents() {
814 return pathIntents;
815 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800816
Toshio Koidefdb75932014-06-16 17:59:24 -0700817 /**
818 * {@inheritDoc}
819 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700820 @Override
821 public void purgeIntents() {
822 highLevelIntents.purge();
823 pathIntents.purge();
824 }
Toshio Koide0c9106d2014-02-19 15:26:38 -0800825
Ray Milkey269ffb92014-04-03 14:43:30 -0700826 // ================================================================================
Jonathan Harte37e4e22014-05-13 19:12:02 -0700827 // ITopologyListener implementations
Ray Milkey269ffb92014-04-03 14:43:30 -0700828 // ================================================================================
Toshio Koidefdb75932014-06-16 17:59:24 -0700829 /**
830 * {@inheritDoc}
831 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700832 @Override
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700833 public void topologyEvents(TopologyEvents topologyEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700834 PerfLogger p = new PerfLogger("networkGraphEvents");
835 HashSet<Intent> affectedPaths = new HashSet<>();
Toshio Koide93797dc2014-02-27 23:54:26 -0800836
Ray Milkey269ffb92014-04-03 14:43:30 -0700837 boolean rerouteAll = false;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700838 for (LinkEvent le : topologyEvents.getAddedLinkEvents()) {
Yuta HIGUCHIb8093642014-07-16 13:17:07 -0700839 final LinkTuple rev = new LinkTuple(le.getDst(), le.getSrc());
Ray Milkey269ffb92014-04-03 14:43:30 -0700840 if (unmatchedLinkEvents.contains(rev)) {
841 rerouteAll = true;
842 unmatchedLinkEvents.remove(rev);
843 log.debug("Found matched LinkEvent: {} {}", rev, le);
844 } else {
Yuta HIGUCHIb8093642014-07-16 13:17:07 -0700845 unmatchedLinkEvents.add(le.getLinkTuple());
Ray Milkey269ffb92014-04-03 14:43:30 -0700846 log.debug("Adding unmatched LinkEvent: {}", le);
847 }
848 }
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700849 for (LinkEvent le : topologyEvents.getRemovedLinkEvents()) {
Yuta HIGUCHIb8093642014-07-16 13:17:07 -0700850 if (unmatchedLinkEvents.contains(le.getLinkTuple())) {
851 unmatchedLinkEvents.remove(le.getLinkTuple());
Ray Milkey269ffb92014-04-03 14:43:30 -0700852 log.debug("Removing LinkEvent: {}", le);
853 }
854 }
855 if (unmatchedLinkEvents.size() > 0) {
856 log.debug("Unmatched link events: {} events", unmatchedLinkEvents.size());
857 }
Toshio Koidea9078af2014-02-21 16:57:04 -0800858
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700859 if (rerouteAll) {
860 //
861 // (topologyEvents.getAddedLinkEvents().size() > 0) ||
862 // (topologyEvents.getAddedPortEvents().size() > 0) ||
863 // (topologyEvents.getAddedSwitchEvents.size() > 0)
864 //
Ray Milkey269ffb92014-04-03 14:43:30 -0700865 p.log("begin_getAllIntents");
866 affectedPaths.addAll(getPathIntents().getAllIntents());
867 p.log("end_getAllIntents");
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700868 } else if (topologyEvents.getRemovedSwitchEvents().size() > 0 ||
869 topologyEvents.getRemovedLinkEvents().size() > 0 ||
870 topologyEvents.getRemovedPortEvents().size() > 0) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700871 p.log("begin_getIntentsByLink");
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700872 for (LinkEvent linkEvent : topologyEvents.getRemovedLinkEvents()) {
Pavlin Radoslavova5637c02014-07-30 15:55:11 -0700873 affectedPaths.addAll(pathIntents.getIntentsByLink(linkEvent.getLinkTuple()));
Ray Milkeyb29e6262014-04-09 16:02:14 -0700874 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700875 p.log("end_getIntentsByLink");
Toshio Koidea9078af2014-02-21 16:57:04 -0800876
Ray Milkey269ffb92014-04-03 14:43:30 -0700877 p.log("begin_getIntentsByPort");
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700878 for (PortEvent portEvent : topologyEvents.getRemovedPortEvents()) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700879 affectedPaths.addAll(pathIntents.getIntentsByPort(
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -0700880 portEvent.getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700881 portEvent.getPortNumber()));
Ray Milkeyb29e6262014-04-09 16:02:14 -0700882 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700883 p.log("end_getIntentsByPort");
Toshio Koidea9078af2014-02-21 16:57:04 -0800884
Ray Milkey269ffb92014-04-03 14:43:30 -0700885 p.log("begin_getIntentsByDpid");
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700886 for (SwitchEvent switchEvent : topologyEvents.getRemovedSwitchEvents()) {
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -0700887 affectedPaths.addAll(pathIntents.getIntentsByDpid(switchEvent.getDpid()));
Ray Milkeyb29e6262014-04-09 16:02:14 -0700888 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700889 p.log("end_getIntentsByDpid");
890 }
891 p.log("begin_reroutePaths");
892 reroutePaths(affectedPaths);
893 p.log("end_reroutePaths");
894 p.flushLog();
895 }
Toshio Koide066506e2014-02-20 19:52:09 -0800896
Ray Milkey269ffb92014-04-03 14:43:30 -0700897 // ================================================================================
898 // IEventChannelListener implementations
899 // ================================================================================
Toshio Koide066506e2014-02-20 19:52:09 -0800900
Toshio Koidefdb75932014-06-16 17:59:24 -0700901 /**
902 * {@inheritDoc}
903 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700904 @Override
905 public void entryAdded(IntentStateList value) {
906 entryUpdated(value);
907 }
Toshio Koide066506e2014-02-20 19:52:09 -0800908
Toshio Koidefdb75932014-06-16 17:59:24 -0700909 /**
910 * {@inheritDoc}
911 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700912 @Override
913 public void entryRemoved(IntentStateList value) {
914 // do nothing
915 }
Toshio Koide066506e2014-02-20 19:52:09 -0800916
Toshio Koidefdb75932014-06-16 17:59:24 -0700917 /**
918 * {@inheritDoc}
919 */
Ray Milkey149693c2014-05-20 14:58:53 -0700920 @SuppressWarnings("fallthrough")
Ray Milkey269ffb92014-04-03 14:43:30 -0700921 @Override
922 public void entryUpdated(IntentStateList value) {
923 // TODO draw state transition diagram in multiple ONOS instances and update this method
TeruU9e530662014-05-18 11:49:37 -0700924
Toshio Koide353a9e12014-06-09 21:03:40 -0700925 IntentOperationList opList = new IntentOperationList();
Ray Milkey269ffb92014-04-03 14:43:30 -0700926 lock.lock(); // TODO optimize locking using smaller steps
927 try {
TeruU9e530662014-05-18 11:49:37 -0700928 log.trace("lock entryUpdated, lock obj is already locked? {}", lock.isLocked());
Ray Milkey269ffb92014-04-03 14:43:30 -0700929 // reflect state changes of path-level intent into application-level intents
Ray Milkey269ffb92014-04-03 14:43:30 -0700930 IntentStateList highLevelIntentStates = new IntentStateList();
931 IntentStateList pathIntentStates = new IntentStateList();
932 for (Entry<String, IntentState> entry : value.entrySet()) {
Toshio Koide14dba902014-06-05 18:39:21 -0700933 String pathIntentId = entry.getKey();
934 IntentState nextPathIntentState = entry.getValue();
935 PathIntent pathIntent = (PathIntent) pathIntents.getIntent(pathIntentId);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700936 if (pathIntent == null) {
937 continue;
938 }
Toshio Koide8315d7d2014-02-21 22:58:32 -0800939
Ray Milkey269ffb92014-04-03 14:43:30 -0700940 Intent parentIntent = pathIntent.getParentIntent();
941 if (parentIntent == null ||
Toshio Koide14dba902014-06-05 18:39:21 -0700942 !(parentIntent instanceof ShortestPathIntent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700943 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700944 }
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700945 String parentIntentId = parentIntent.getId();
Toshio Koide066506e2014-02-20 19:52:09 -0800946
Toshio Koide14dba902014-06-05 18:39:21 -0700947 boolean isChildIntent = ((ShortestPathIntent) parentIntent).getPathIntentId().equals(pathIntentId);
Toshio Koide353a9e12014-06-09 21:03:40 -0700948
949 // Check necessity for retrying the intent execution.
950 // When the PathIntent(=isChildIntent) transitioned to INST_{ACK/NACK}
951 // but was marked as stale (e.g., has been requested to reroute by Topology event),
952 // then immediately enqueue the re-computation of parent intent.
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700953 if (isChildIntent && staleIntents.containsKey(parentIntentId) && (
Toshio Koide353a9e12014-06-09 21:03:40 -0700954 nextPathIntentState.equals(IntentState.INST_ACK) ||
955 nextPathIntentState.equals(IntentState.INST_NACK))) {
956 opList.add(Operator.ADD, parentIntent);
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700957 staleIntents.remove(parentIntentId);
958 log.debug("retrying intent execution for intent ID:{}", parentIntentId);
Toshio Koide353a9e12014-06-09 21:03:40 -0700959 }
960
Toshio Koide14dba902014-06-05 18:39:21 -0700961 switch (nextPathIntentState) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700962 case INST_ACK:
TeruUf9111652014-05-14 23:10:35 -0700963 Set<Long> installedDpids = calcInstalledDpids(pathIntent, value.domainSwitchDpids);
964 if (!isFlowInstalled(pathIntent, installedDpids)) {
965 break;
966 }
967 // FALLTHROUGH
Ray Milkey269ffb92014-04-03 14:43:30 -0700968 case INST_NACK:
TeruUf9111652014-05-14 23:10:35 -0700969 // FALLTHROUGH
Ray Milkey269ffb92014-04-03 14:43:30 -0700970 case DEL_PENDING:
Toshio Koide14dba902014-06-05 18:39:21 -0700971 if (isChildIntent) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700972 log.debug("put the state highLevelIntentStates ID {}, state {}",
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700973 parentIntentId, nextPathIntentState);
974 highLevelIntentStates.put(parentIntentId, nextPathIntentState);
Toshio Koide14dba902014-06-05 18:39:21 -0700975 }
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700976 log.debug("put the state pathIntentStates ID {}, state {}",
977 pathIntentId, nextPathIntentState);
Toshio Koide14dba902014-06-05 18:39:21 -0700978 pathIntentStates.put(pathIntentId, nextPathIntentState);
TeruU9e530662014-05-18 11:49:37 -0700979 break;
980 case DEL_ACK:
Toshio Koide14dba902014-06-05 18:39:21 -0700981 if (isChildIntent) {
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700982 if (intentInstalledMap.containsKey(pathIntentId)) {
983 intentInstalledMap.remove(pathIntentId);
Toshio Koide14dba902014-06-05 18:39:21 -0700984 }
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700985 log.debug("put the state highLevelIntentStates ID {}, state {}",
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700986 parentIntentId, nextPathIntentState);
987 highLevelIntentStates.put(parentIntentId, nextPathIntentState);
TeruU9e530662014-05-18 11:49:37 -0700988 }
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700989 log.debug("put the state pathIntentStates ID {}, state {}",
990 pathIntentId, nextPathIntentState);
Toshio Koide14dba902014-06-05 18:39:21 -0700991 pathIntentStates.put(pathIntentId, nextPathIntentState);
992 break;
993 case CREATED:
994 break;
995 case DEL_REQ:
996 break;
997 case INST_REQ:
998 break;
999 case REROUTE_REQ:
Ray Milkey269ffb92014-04-03 14:43:30 -07001000 break;
1001 default:
1002 break;
1003 }
1004 }
1005 highLevelIntents.changeStates(highLevelIntentStates);
1006 pathIntents.changeStates(pathIntentStates);
Ray Milkey269ffb92014-04-03 14:43:30 -07001007 } finally {
Ray Milkey269ffb92014-04-03 14:43:30 -07001008 lock.unlock();
TeruU9e530662014-05-18 11:49:37 -07001009 log.trace("unlock entryUpdated");
Ray Milkey269ffb92014-04-03 14:43:30 -07001010 }
Toshio Koide353a9e12014-06-09 21:03:40 -07001011 executeIntentOperations(opList);
Ray Milkey269ffb92014-04-03 14:43:30 -07001012 }
Toshio Koidea9078af2014-02-21 16:57:04 -08001013}