blob: d6cd25a59e43ff4c9f6061b5ae10a9a0df63810b [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;
Toshio Koide4f308732014-02-18 15:19:48 -08009import java.util.Map;
Toshio Koide066506e2014-02-20 19:52:09 -080010import java.util.Map.Entry;
Toshio Koide93be5d62014-02-23 19:30:57 -080011import java.util.concurrent.locks.ReentrantLock;
Toshio Koide4f308732014-02-18 15:19:48 -080012
13import net.floodlightcontroller.core.module.FloodlightModuleContext;
14import net.floodlightcontroller.core.module.FloodlightModuleException;
15import net.floodlightcontroller.core.module.IFloodlightModule;
16import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart6df90172014-04-03 10:13:11 -070017import net.onrc.onos.core.datagrid.IDatagridService;
18import net.onrc.onos.core.datagrid.IEventChannel;
19import net.onrc.onos.core.datagrid.IEventChannelListener;
Jonathan Hartaa380972014-04-03 10:24:46 -070020import net.onrc.onos.core.intent.Intent;
Jonathan Harta99ec672014-04-03 11:30:34 -070021import net.onrc.onos.core.intent.Intent.IntentState;
Jonathan Hartaa380972014-04-03 10:24:46 -070022import net.onrc.onos.core.intent.IntentMap;
23import net.onrc.onos.core.intent.IntentOperation;
Jonathan Harta99ec672014-04-03 11:30:34 -070024import net.onrc.onos.core.intent.IntentOperation.Operator;
Jonathan Hartaa380972014-04-03 10:24:46 -070025import net.onrc.onos.core.intent.IntentOperationList;
26import net.onrc.onos.core.intent.PathIntent;
27import net.onrc.onos.core.intent.PathIntentMap;
28import net.onrc.onos.core.intent.ShortestPathIntent;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070029import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart472062d2014-04-03 10:56:48 -070030import net.onrc.onos.core.topology.DeviceEvent;
31import net.onrc.onos.core.topology.INetworkGraphListener;
32import net.onrc.onos.core.topology.INetworkGraphService;
33import net.onrc.onos.core.topology.LinkEvent;
34import net.onrc.onos.core.topology.PortEvent;
35import net.onrc.onos.core.topology.SwitchEvent;
Toshio Koide4f308732014-02-18 15:19:48 -080036
Jonathan Harta99ec672014-04-03 11:30:34 -070037import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
Toshio Koide0c9106d2014-02-19 15:26:38 -080040/**
41 * @author Toshio Koide (t-koide@onlab.us)
42 */
Toshio Koide066506e2014-02-20 19:52:09 -080043public class PathCalcRuntimeModule implements IFloodlightModule, IPathCalcRuntimeService, INetworkGraphListener, IEventChannelListener<Long, IntentStateList> {
Ray Milkey269ffb92014-04-03 14:43:30 -070044 class PerfLog {
45 private String step;
46 private long time;
Toshio Koidebf875662014-02-24 12:19:15 -080047
Ray Milkey269ffb92014-04-03 14:43:30 -070048 public PerfLog(String step) {
49 this.step = step;
50 this.time = System.nanoTime();
51 }
Toshio Koidebf875662014-02-24 12:19:15 -080052
Ray Milkey269ffb92014-04-03 14:43:30 -070053 public void logThis() {
54 log.error("Time:{}, Step:{}", time, step);
55 }
56 }
Toshio Koidebf875662014-02-24 12:19:15 -080057
Ray Milkey269ffb92014-04-03 14:43:30 -070058 class PerfLogger {
59 private LinkedList<PerfLog> logData = new LinkedList<>();
Toshio Koidebf875662014-02-24 12:19:15 -080060
Ray Milkey269ffb92014-04-03 14:43:30 -070061 public PerfLogger(String logPhase) {
62 log("start_" + logPhase);
63 }
Toshio Koidebf875662014-02-24 12:19:15 -080064
Ray Milkey269ffb92014-04-03 14:43:30 -070065 public void log(String step) {
66 logData.add(new PerfLog(step));
67 }
Toshio Koide27ffd412014-02-18 19:15:27 -080068
Ray Milkey269ffb92014-04-03 14:43:30 -070069 public void flushLog() {
70 log("finish");
71 for (PerfLog log : logData) {
72 log.logThis();
73 }
74 logData.clear();
75 }
76 }
Toshio Koide4f308732014-02-18 15:19:48 -080077
Ray Milkey269ffb92014-04-03 14:43:30 -070078 private PathCalcRuntime runtime;
79 private IDatagridService datagridService;
80 private INetworkGraphService networkGraphService;
81 private IntentMap highLevelIntents;
82 private PathIntentMap pathIntents;
83 private IControllerRegistryService controllerRegistry;
84 private PersistIntent persistIntent;
Toshio Koide798bc1b2014-02-20 14:02:40 -080085
Ray Milkey269ffb92014-04-03 14:43:30 -070086 private IEventChannel<Long, IntentOperationList> opEventChannel;
87 private final ReentrantLock lock = new ReentrantLock();
88 private HashSet<LinkEvent> unmatchedLinkEvents = new HashSet<>();
89 private static final String INTENT_OP_EVENT_CHANNEL_NAME = "onos.pathintent";
90 private static final String INTENT_STATE_EVENT_CHANNEL_NAME = "onos.pathintent_state";
91 private static final Logger log = LoggerFactory.getLogger(PathCalcRuntimeModule.class);
Toshio Koidea10c0372014-02-20 17:28:10 -080092
Ray Milkey269ffb92014-04-03 14:43:30 -070093 // ================================================================================
94 // private methods
95 // ================================================================================
96
97 private void reroutePaths(Collection<Intent> oldPaths) {
98 if (oldPaths == null || oldPaths.isEmpty())
99 return;
100
101 IntentOperationList reroutingOperation = new IntentOperationList();
102 for (Intent intent : oldPaths) {
103 PathIntent pathIntent = (PathIntent) intent;
104 if (pathIntent.isPathFrozen())
105 continue;
106 if (pathIntent.getState().equals(IntentState.INST_ACK) && // XXX: path intents in flight
107 !reroutingOperation.contains(pathIntent.getParentIntent())) {
108 reroutingOperation.add(Operator.ADD, pathIntent.getParentIntent());
109 }
110 }
111 executeIntentOperations(reroutingOperation);
112 }
Toshio Koidea94060f2014-02-21 22:58:32 -0800113
Toshio Koide27ffd412014-02-18 19:15:27 -0800114
Ray Milkey269ffb92014-04-03 14:43:30 -0700115 // ================================================================================
116 // IFloodlightModule implementations
117 // ================================================================================
Toshio Koide798bc1b2014-02-20 14:02:40 -0800118
Ray Milkey269ffb92014-04-03 14:43:30 -0700119 @Override
120 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
121 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>(1);
122 l.add(IPathCalcRuntimeService.class);
123 return l;
124 }
Toshio Koide4f308732014-02-18 15:19:48 -0800125
Ray Milkey269ffb92014-04-03 14:43:30 -0700126 @Override
127 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
128 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
129 m.put(IPathCalcRuntimeService.class, this);
130 return m;
131 }
Toshio Koide4f308732014-02-18 15:19:48 -0800132
Ray Milkey269ffb92014-04-03 14:43:30 -0700133 @Override
134 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
135 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>(2);
136 l.add(IDatagridService.class);
137 l.add(INetworkGraphService.class);
138 return l;
139 }
Toshio Koide4f308732014-02-18 15:19:48 -0800140
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 @Override
142 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
143 datagridService = context.getServiceImpl(IDatagridService.class);
144 networkGraphService = context.getServiceImpl(INetworkGraphService.class);
145 controllerRegistry = context.getServiceImpl(IControllerRegistryService.class);
146 }
Toshio Koide4f308732014-02-18 15:19:48 -0800147
Ray Milkey269ffb92014-04-03 14:43:30 -0700148 @Override
149 public void startUp(FloodlightModuleContext context) {
150 highLevelIntents = new IntentMap();
151 runtime = new PathCalcRuntime(networkGraphService.getNetworkGraph());
152 pathIntents = new PathIntentMap();
153 opEventChannel = datagridService.createChannel(INTENT_OP_EVENT_CHANNEL_NAME, Long.class, IntentOperationList.class);
154 datagridService.addListener(INTENT_STATE_EVENT_CHANNEL_NAME, this, Long.class, IntentStateList.class);
155 networkGraphService.registerNetworkGraphListener(this);
156 persistIntent = new PersistIntent(controllerRegistry, networkGraphService);
157 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800158
Ray Milkey269ffb92014-04-03 14:43:30 -0700159 // ================================================================================
160 // IPathCalcRuntimeService implementations
161 // ================================================================================
Toshio Koide798bc1b2014-02-20 14:02:40 -0800162
Ray Milkey269ffb92014-04-03 14:43:30 -0700163 @Override
164 public IntentOperationList executeIntentOperations(IntentOperationList list) {
165 if (list == null || list.size() == 0)
166 return null;
167 PerfLogger p = new PerfLogger("executeIntentOperations_" + list.get(0).operator);
Toshio Koide275d8142014-02-24 16:41:52 -0800168
Ray Milkey269ffb92014-04-03 14:43:30 -0700169 lock.lock(); // TODO optimize locking using smaller steps
170 try {
171 // update the map of high-level intents
172 p.log("begin_updateInMemoryIntents");
173 highLevelIntents.executeOperations(list);
Toshio Koidedf2eab92014-02-20 11:24:59 -0800174
Ray Milkey269ffb92014-04-03 14:43:30 -0700175 // change states of high-level intents
176 IntentStateList states = new IntentStateList();
177 for (IntentOperation op : list) {
178 switch (op.operator) {
179 case ADD:
180 switch (op.intent.getState()) {
181 case CREATED:
182 states.put(op.intent.getId(), IntentState.INST_REQ);
183 break;
184 case INST_ACK:
185 states.put(op.intent.getId(), IntentState.REROUTE_REQ);
186 break;
187 default:
188 break;
189 }
190 break;
191 case REMOVE:
192 switch (op.intent.getState()) {
193 case CREATED:
194 states.put(op.intent.getId(), IntentState.DEL_REQ);
195 break;
196 default:
197 break;
198 }
199 break;
200 default:
201 break;
202 }
203 }
204 highLevelIntents.changeStates(states);
205 p.log("end_updateInMemoryIntents");
Toshio Koidedf2eab92014-02-20 11:24:59 -0800206
Ray Milkey269ffb92014-04-03 14:43:30 -0700207 // calculate path-intents (low-level operations)
208 p.log("begin_calcPathIntents");
209 IntentOperationList pathIntentOperations = runtime.calcPathIntents(list, highLevelIntents, pathIntents);
210 p.log("end_calcPathIntents");
Toshio Koide600ae5f2014-02-20 18:42:00 -0800211
Ray Milkey269ffb92014-04-03 14:43:30 -0700212 // persist calculated low-level operations into data store
213 p.log("begin_persistPathIntents");
214 long key = persistIntent.getKey();
215 persistIntent.persistIfLeader(key, pathIntentOperations);
216 p.log("end_persistPathIntents");
Toshio Koide93be5d62014-02-23 19:30:57 -0800217
Ray Milkey269ffb92014-04-03 14:43:30 -0700218 // remove error-intents and reflect them to high-level intents
219 p.log("begin_removeErrorIntents");
220 states.clear();
221 Iterator<IntentOperation> i = pathIntentOperations.iterator();
222 while (i.hasNext()) {
223 IntentOperation op = i.next();
224 if (op.operator.equals(Operator.ERROR)) {
225 states.put(op.intent.getId(), IntentState.INST_NACK);
226 i.remove();
227 }
228 }
229 highLevelIntents.changeStates(states);
230 p.log("end_removeErrorIntents");
Toshio Koidea94060f2014-02-21 22:58:32 -0800231
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 // update the map of path intents and publish the path operations
233 p.log("begin_updateInMemoryPathIntents");
234 pathIntents.executeOperations(pathIntentOperations);
235 p.log("end_updateInMemoryPathIntents");
Toshio Koide93be5d62014-02-23 19:30:57 -0800236
Ray Milkey269ffb92014-04-03 14:43:30 -0700237 // XXX Demo special: add a complete path to remove operation
238 p.log("begin_addPathToRemoveOperation");
239 for (IntentOperation op : pathIntentOperations) {
240 if (op.operator.equals(Operator.REMOVE)) {
241 op.intent = pathIntents.getIntent(op.intent.getId());
242 }
243 if (op.intent instanceof PathIntent) {
244 log.debug("operation: {}, intent:{}", op.operator, op.intent);
245 }
246 }
247 p.log("end_addPathToRemoveOperation");
Toshio Koide93be5d62014-02-23 19:30:57 -0800248
Ray Milkey269ffb92014-04-03 14:43:30 -0700249 // send notification
250 p.log("begin_sendNotification");
251 // XXX: Send notifications using the same key every time
252 // and receive them by entryAdded() and entryUpdated()
253 opEventChannel.addEntry(0L, pathIntentOperations);
254 p.log("end_sendNotification");
255 //opEventChannel.removeEntry(key);
256 return pathIntentOperations;
257 } finally {
258 p.flushLog();
259 lock.unlock();
260 }
261 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800262
Ray Milkey269ffb92014-04-03 14:43:30 -0700263 @Override
264 public IntentMap getHighLevelIntents() {
265 return highLevelIntents;
266 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800267
Ray Milkey269ffb92014-04-03 14:43:30 -0700268 @Override
269 public IntentMap getPathIntents() {
270 return pathIntents;
271 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800272
Ray Milkey269ffb92014-04-03 14:43:30 -0700273 @Override
274 public void purgeIntents() {
275 highLevelIntents.purge();
276 pathIntents.purge();
277 }
Toshio Koide0c9106d2014-02-19 15:26:38 -0800278
Ray Milkey269ffb92014-04-03 14:43:30 -0700279 // ================================================================================
280 // INetworkGraphListener implementations
281 // ================================================================================
Toshio Koide798bc1b2014-02-20 14:02:40 -0800282
Ray Milkey269ffb92014-04-03 14:43:30 -0700283 @Override
284 public void networkGraphEvents(Collection<SwitchEvent> addedSwitchEvents,
285 Collection<SwitchEvent> removedSwitchEvents,
286 Collection<PortEvent> addedPortEvents,
287 Collection<PortEvent> removedPortEvents,
288 Collection<LinkEvent> addedLinkEvents,
289 Collection<LinkEvent> removedLinkEvents,
290 Collection<DeviceEvent> addedDeviceEvents,
291 Collection<DeviceEvent> removedDeviceEvents) {
Toshio Koidea9078af2014-02-21 16:57:04 -0800292
Ray Milkey269ffb92014-04-03 14:43:30 -0700293 PerfLogger p = new PerfLogger("networkGraphEvents");
294 HashSet<Intent> affectedPaths = new HashSet<>();
Toshio Koide93797dc2014-02-27 23:54:26 -0800295
Ray Milkey269ffb92014-04-03 14:43:30 -0700296 boolean rerouteAll = false;
297 for (LinkEvent le : addedLinkEvents) {
298 LinkEvent rev = new LinkEvent(le.getDst().getDpid(), le.getDst().getNumber(), le.getSrc().getDpid(), le.getSrc().getNumber());
299 if (unmatchedLinkEvents.contains(rev)) {
300 rerouteAll = true;
301 unmatchedLinkEvents.remove(rev);
302 log.debug("Found matched LinkEvent: {} {}", rev, le);
303 } else {
304 unmatchedLinkEvents.add(le);
305 log.debug("Adding unmatched LinkEvent: {}", le);
306 }
307 }
308 for (LinkEvent le : removedLinkEvents) {
309 if (unmatchedLinkEvents.contains(le)) {
310 unmatchedLinkEvents.remove(le);
311 log.debug("Removing LinkEvent: {}", le);
312 }
313 }
314 if (unmatchedLinkEvents.size() > 0) {
315 log.debug("Unmatched link events: {} events", unmatchedLinkEvents.size());
316 }
Toshio Koidea9078af2014-02-21 16:57:04 -0800317
Ray Milkey7f1567c2014-04-08 13:53:32 -0700318 if (rerouteAll) { //addedLinkEvents.size() > 0) { // ||
Ray Milkey269ffb92014-04-03 14:43:30 -0700319// addedPortEvents.size() > 0 ||
320// addedSwitchEvents.size() > 0) {
321 p.log("begin_getAllIntents");
322 affectedPaths.addAll(getPathIntents().getAllIntents());
323 p.log("end_getAllIntents");
324 } else if (removedSwitchEvents.size() > 0 ||
325 removedLinkEvents.size() > 0 ||
326 removedPortEvents.size() > 0) {
327 p.log("begin_getIntentsByLink");
328 for (LinkEvent linkEvent : removedLinkEvents)
329 affectedPaths.addAll(pathIntents.getIntentsByLink(linkEvent));
330 p.log("end_getIntentsByLink");
Toshio Koidea9078af2014-02-21 16:57:04 -0800331
Ray Milkey269ffb92014-04-03 14:43:30 -0700332 p.log("begin_getIntentsByPort");
333 for (PortEvent portEvent : removedPortEvents)
334 affectedPaths.addAll(pathIntents.getIntentsByPort(portEvent.getDpid(), portEvent.getNumber()));
335 p.log("end_getIntentsByPort");
Toshio Koidea9078af2014-02-21 16:57:04 -0800336
Ray Milkey269ffb92014-04-03 14:43:30 -0700337 p.log("begin_getIntentsByDpid");
338 for (SwitchEvent switchEvent : removedSwitchEvents)
339 affectedPaths.addAll(pathIntents.getIntentsByDpid(switchEvent.getDpid()));
340 p.log("end_getIntentsByDpid");
341 }
342 p.log("begin_reroutePaths");
343 reroutePaths(affectedPaths);
344 p.log("end_reroutePaths");
345 p.flushLog();
346 }
Toshio Koide066506e2014-02-20 19:52:09 -0800347
Ray Milkey269ffb92014-04-03 14:43:30 -0700348 // ================================================================================
349 // IEventChannelListener implementations
350 // ================================================================================
Toshio Koide066506e2014-02-20 19:52:09 -0800351
Ray Milkey269ffb92014-04-03 14:43:30 -0700352 @Override
353 public void entryAdded(IntentStateList value) {
354 entryUpdated(value);
355 }
Toshio Koide066506e2014-02-20 19:52:09 -0800356
Ray Milkey269ffb92014-04-03 14:43:30 -0700357 @Override
358 public void entryRemoved(IntentStateList value) {
359 // do nothing
360 }
Toshio Koide066506e2014-02-20 19:52:09 -0800361
Ray Milkey269ffb92014-04-03 14:43:30 -0700362 @Override
363 public void entryUpdated(IntentStateList value) {
364 // TODO draw state transition diagram in multiple ONOS instances and update this method
365 PerfLogger p = new PerfLogger("entryUpdated");
366 lock.lock(); // TODO optimize locking using smaller steps
367 try {
368 // reflect state changes of path-level intent into application-level intents
369 p.log("begin_changeStateByNotification");
370 IntentStateList highLevelIntentStates = new IntentStateList();
371 IntentStateList pathIntentStates = new IntentStateList();
372 for (Entry<String, IntentState> entry : value.entrySet()) {
373 PathIntent pathIntent = (PathIntent) pathIntents.getIntent(entry.getKey());
374 if (pathIntent == null) continue;
Toshio Koide8315d7d2014-02-21 22:58:32 -0800375
Ray Milkey269ffb92014-04-03 14:43:30 -0700376 Intent parentIntent = pathIntent.getParentIntent();
377 if (parentIntent == null ||
378 !(parentIntent instanceof ShortestPathIntent) ||
379 !((ShortestPathIntent) parentIntent).getPathIntentId().equals(pathIntent.getId()))
380 continue;
Toshio Koide066506e2014-02-20 19:52:09 -0800381
Ray Milkey269ffb92014-04-03 14:43:30 -0700382 IntentState state = entry.getValue();
383 switch (state) {
384 //case INST_REQ:
385 case INST_ACK:
386 case INST_NACK:
387 //case DEL_REQ:
388 case DEL_ACK:
389 case DEL_PENDING:
390 highLevelIntentStates.put(parentIntent.getId(), state);
391 pathIntentStates.put(entry.getKey(), entry.getValue());
392 break;
393 default:
394 break;
395 }
396 }
397 highLevelIntents.changeStates(highLevelIntentStates);
398 pathIntents.changeStates(pathIntentStates);
399 p.log("end_changeStateByNotification");
400 } finally {
401 p.flushLog();
402 lock.unlock();
403 }
404 }
Toshio Koidea9078af2014-02-21 16:57:04 -0800405}