blob: fe767140b4edd78c123420d9e5ff1accc6994f23 [file] [log] [blame]
Toshio Koide4f308732014-02-18 15:19:48 -08001package net.onrc.onos.intent.runtime;
2
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 Koide4f308732014-02-18 15:19:48 -08008import java.util.Map;
Toshio Koide066506e2014-02-20 19:52:09 -08009import java.util.Map.Entry;
Toshio Koide93be5d62014-02-23 19:30:57 -080010import java.util.concurrent.locks.ReentrantLock;
Toshio Koide4f308732014-02-18 15:19:48 -080011
Toshio Koidea94060f2014-02-21 22:58:32 -080012import org.slf4j.Logger;
13import org.slf4j.LoggerFactory;
14
Toshio Koide4f308732014-02-18 15:19:48 -080015import net.floodlightcontroller.core.module.FloodlightModuleContext;
16import net.floodlightcontroller.core.module.FloodlightModuleException;
17import net.floodlightcontroller.core.module.IFloodlightModule;
18import net.floodlightcontroller.core.module.IFloodlightService;
19import net.onrc.onos.datagrid.IDatagridService;
20import net.onrc.onos.datagrid.IEventChannel;
Toshio Koide066506e2014-02-20 19:52:09 -080021import net.onrc.onos.datagrid.IEventChannelListener;
22import net.onrc.onos.intent.Intent;
Toshio Koidedf2eab92014-02-20 11:24:59 -080023import net.onrc.onos.intent.Intent.IntentState;
Toshio Koide4f308732014-02-18 15:19:48 -080024import net.onrc.onos.intent.IntentMap;
Toshio Koidedf2eab92014-02-20 11:24:59 -080025import net.onrc.onos.intent.IntentOperation;
Toshio Koide0c9106d2014-02-19 15:26:38 -080026import net.onrc.onos.intent.IntentOperation.Operator;
Toshio Koide4f308732014-02-18 15:19:48 -080027import net.onrc.onos.intent.IntentOperationList;
Toshio Koide0c9106d2014-02-19 15:26:38 -080028import net.onrc.onos.intent.PathIntent;
Toshio Koide4f308732014-02-18 15:19:48 -080029import net.onrc.onos.intent.PathIntentMap;
Toshio Koide066506e2014-02-20 19:52:09 -080030import net.onrc.onos.intent.ShortestPathIntent;
Toshio Koidedf2eab92014-02-20 11:24:59 -080031import net.onrc.onos.intent.persist.PersistIntent;
Toshio Koide0c9106d2014-02-19 15:26:38 -080032import net.onrc.onos.ofcontroller.networkgraph.DeviceEvent;
33import net.onrc.onos.ofcontroller.networkgraph.INetworkGraphListener;
Toshio Koide27ffd412014-02-18 19:15:27 -080034import net.onrc.onos.ofcontroller.networkgraph.INetworkGraphService;
Toshio Koide0c9106d2014-02-19 15:26:38 -080035import net.onrc.onos.ofcontroller.networkgraph.LinkEvent;
36import net.onrc.onos.ofcontroller.networkgraph.PortEvent;
37import net.onrc.onos.ofcontroller.networkgraph.SwitchEvent;
Nick Karanatsios8abe7172014-02-19 20:31:48 -080038import net.onrc.onos.registry.controller.IControllerRegistryService;
Toshio Koide4f308732014-02-18 15:19:48 -080039
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> {
Toshio Koide4f308732014-02-18 15:19:48 -080044 private PathCalcRuntime runtime;
45 private IDatagridService datagridService;
Toshio Koide27ffd412014-02-18 19:15:27 -080046 private INetworkGraphService networkGraphService;
Toshio Koide4f308732014-02-18 15:19:48 -080047 private IntentMap highLevelIntents;
Toshio Koide27ffd412014-02-18 19:15:27 -080048 private PathIntentMap pathIntents;
Toshio Koide798bc1b2014-02-20 14:02:40 -080049 private IControllerRegistryService controllerRegistry;
50 private PersistIntent persistIntent;
Toshio Koide27ffd412014-02-18 19:15:27 -080051
Toshio Koide066506e2014-02-20 19:52:09 -080052 private IEventChannel<Long, IntentOperationList> opEventChannel;
Toshio Koide93be5d62014-02-23 19:30:57 -080053 private final ReentrantLock lock = new ReentrantLock();
Toshio Koide066506e2014-02-20 19:52:09 -080054 private static final String INTENT_OP_EVENT_CHANNEL_NAME = "onos.pathintent";
55 private static final String INTENT_STATE_EVENT_CHANNEL_NAME = "onos.pathintent_state";
Toshio Koidea94060f2014-02-21 22:58:32 -080056 private static final Logger log = LoggerFactory.getLogger(PathCalcRuntimeModule.class);
Toshio Koide4f308732014-02-18 15:19:48 -080057
Toshio Koide798bc1b2014-02-20 14:02:40 -080058 // ================================================================================
59 // private methods
60 // ================================================================================
61
Toshio Koidea94060f2014-02-21 22:58:32 -080062 private void reroutePaths(Collection<Intent> oldPaths) {
Toshio Koidea9078af2014-02-21 16:57:04 -080063 if (oldPaths == null || oldPaths.isEmpty())
Toshio Koide798bc1b2014-02-20 14:02:40 -080064 return;
Toshio Koidea10c0372014-02-20 17:28:10 -080065
Toshio Koide0c9106d2014-02-19 15:26:38 -080066 IntentOperationList reroutingOperation = new IntentOperationList();
Toshio Koide982c81f2014-02-23 16:53:10 -080067 for (Intent intent : oldPaths) {
68 PathIntent pathIntent = (PathIntent) intent;
69 if (pathIntent.getState().equals(IntentState.INST_ACK) &&
70 !reroutingOperation.contains(pathIntent)) {
71 reroutingOperation.add(Operator.ADD, pathIntent.getParentIntent());
72 }
Toshio Koide0c9106d2014-02-19 15:26:38 -080073 }
Toshio Koide8315d7d2014-02-21 22:58:32 -080074 executeIntentOperations(reroutingOperation);
Toshio Koidea94060f2014-02-21 22:58:32 -080075 }
76
77 private void log(String step) {
78 log.error("Step:{}, Time:{}", step, System.nanoTime());
Toshio Koide0c9106d2014-02-19 15:26:38 -080079 }
Toshio Koide27ffd412014-02-18 19:15:27 -080080
Toshio Koide798bc1b2014-02-20 14:02:40 -080081 // ================================================================================
82 // IFloodlightModule implementations
83 // ================================================================================
84
Toshio Koide4f308732014-02-18 15:19:48 -080085 @Override
86 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
87 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>(1);
Toshio Koideeb90d912014-02-18 21:30:22 -080088 l.add(IPathCalcRuntimeService.class);
Toshio Koide4f308732014-02-18 15:19:48 -080089 return l;
90 }
91
92 @Override
93 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Toshio Koidea9078af2014-02-21 16:57:04 -080094 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
Toshio Koide27ffd412014-02-18 19:15:27 -080095 m.put(IPathCalcRuntimeService.class, this);
Toshio Koide4f308732014-02-18 15:19:48 -080096 return m;
97 }
98
99 @Override
100 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Toshio Koidea9078af2014-02-21 16:57:04 -0800101 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>(2);
Toshio Koide4f308732014-02-18 15:19:48 -0800102 l.add(IDatagridService.class);
Toshio Koide27ffd412014-02-18 19:15:27 -0800103 l.add(INetworkGraphService.class);
Toshio Koide4f308732014-02-18 15:19:48 -0800104 return l;
105 }
106
107 @Override
108 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
109 datagridService = context.getServiceImpl(IDatagridService.class);
Toshio Koided9fa2a82014-02-19 17:35:18 -0800110 networkGraphService = context.getServiceImpl(INetworkGraphService.class);
Toshio Koide798bc1b2014-02-20 14:02:40 -0800111 controllerRegistry = context.getServiceImpl(IControllerRegistryService.class);
Toshio Koide4f308732014-02-18 15:19:48 -0800112 }
113
114 @Override
115 public void startUp(FloodlightModuleContext context) {
Toshio Koideeb90d912014-02-18 21:30:22 -0800116 highLevelIntents = new IntentMap();
117 runtime = new PathCalcRuntime(networkGraphService.getNetworkGraph());
Toshio Koide0c9106d2014-02-19 15:26:38 -0800118 pathIntents = new PathIntentMap();
Toshio Koide066506e2014-02-20 19:52:09 -0800119 opEventChannel = datagridService.createChannel(INTENT_OP_EVENT_CHANNEL_NAME, Long.class, IntentOperationList.class);
120 datagridService.addListener(INTENT_STATE_EVENT_CHANNEL_NAME, this, Long.class, IntentStateList.class);
Toshio Koide0c9106d2014-02-19 15:26:38 -0800121 networkGraphService.registerNetworkGraphListener(this);
Toshio Koide798bc1b2014-02-20 14:02:40 -0800122 persistIntent = new PersistIntent(controllerRegistry, networkGraphService);
Toshio Koide4f308732014-02-18 15:19:48 -0800123 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800124
Toshio Koide798bc1b2014-02-20 14:02:40 -0800125 // ================================================================================
126 // IPathCalcRuntimeService implementations
127 // ================================================================================
128
Toshio Koide27ffd412014-02-18 19:15:27 -0800129 @Override
130 public IntentOperationList executeIntentOperations(IntentOperationList list) {
Toshio Koide93be5d62014-02-23 19:30:57 -0800131 lock.lock(); // TODO optimize locking using smaller steps
132 try {
133 // update the map of high-level intents
134 log("begin_updateInMemoryIntents");
135 highLevelIntents.executeOperations(list);
Toshio Koidedf2eab92014-02-20 11:24:59 -0800136
Toshio Koide93be5d62014-02-23 19:30:57 -0800137 // change states of high-level intents
138 IntentStateList states = new IntentStateList();
139 for (IntentOperation op : list) {
140 if (op.intent.getState().equals(IntentState.INST_ACK))
141 states.put(op.intent.getId(), IntentState.REROUTE_REQ);
Toshio Koidedf2eab92014-02-20 11:24:59 -0800142 }
Toshio Koide93be5d62014-02-23 19:30:57 -0800143 highLevelIntents.changeStates(states);
144 log("end_updateInMemoryIntents");
Toshio Koidedf2eab92014-02-20 11:24:59 -0800145
Toshio Koide93be5d62014-02-23 19:30:57 -0800146 // calculate path-intents (low-level operations)
147 log("begin_calcPathIntents");
148 IntentOperationList pathIntentOperations = runtime.calcPathIntents(list, highLevelIntents, pathIntents);
149 log("end_calcPathIntents");
Toshio Koide600ae5f2014-02-20 18:42:00 -0800150
Toshio Koide93be5d62014-02-23 19:30:57 -0800151 // persist calculated low-level operations into data store
152 log("begin_persistPathIntents");
153 long key = persistIntent.getKey();
154 persistIntent.persistIfLeader(key, pathIntentOperations);
155 log("end_persistPathIntents");
156
157 // remove error-intents and reflect them to high-level intents
158 log("begin_removeErrorIntents");
159 states.clear();
160 Iterator<IntentOperation> i = pathIntentOperations.iterator();
161 while (i.hasNext()) {
162 IntentOperation op = i.next();
163 if (op.operator.equals(Operator.ERROR)) {
164 states.put(op.intent.getId(), IntentState.INST_NACK);
165 i.remove();
166 }
Toshio Koide600ae5f2014-02-20 18:42:00 -0800167 }
Toshio Koide93be5d62014-02-23 19:30:57 -0800168 highLevelIntents.changeStates(states);
169 log("end_removeErrorIntents");
Toshio Koidea94060f2014-02-21 22:58:32 -0800170
Toshio Koide93be5d62014-02-23 19:30:57 -0800171 // update the map of path intents and publish the path operations
172 log("begin_updateInMemoryPathIntents");
173 pathIntents.executeOperations(pathIntentOperations);
174 log("end_updateInMemoryPathIntents");
175
176 // Demo special: add a complete path to remove operation
177 log("begin_addPathToRemoveOperation");
178 for (IntentOperation op: pathIntentOperations) {
179 if(op.operator.equals(Operator.REMOVE)) {
180 op.intent = pathIntents.getIntent(op.intent.getId());
181 }
182 if (op.intent instanceof PathIntent) {
183 log.debug("operation: {}, intent:{}", op.operator, op.intent);
184 }
185 }
186 log("end_addPathToRemoveOperation");
187
188 // send notification
189 log("begin_sendNotification");
190 opEventChannel.addEntry(key, pathIntentOperations);
191 log("end_sendNotification");
192 return pathIntentOperations;
193 }
194 finally {
195 lock.unlock();
196 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800197 }
198
199 @Override
200 public IntentMap getHighLevelIntents() {
Toshio Koide4f308732014-02-18 15:19:48 -0800201 return highLevelIntents;
202 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800203
204 @Override
205 public IntentMap getPathIntents() {
206 return pathIntents;
207 }
208
209 @Override
Toshio Koide4f308732014-02-18 15:19:48 -0800210 public void purgeIntents() {
211 highLevelIntents.purge();
Toshio Koide27ffd412014-02-18 19:15:27 -0800212 pathIntents.purge();
Toshio Koide4f308732014-02-18 15:19:48 -0800213 }
Toshio Koide0c9106d2014-02-19 15:26:38 -0800214
Toshio Koide798bc1b2014-02-20 14:02:40 -0800215 // ================================================================================
216 // INetworkGraphListener implementations
217 // ================================================================================
218
Toshio Koide0c9106d2014-02-19 15:26:38 -0800219 @Override
Toshio Koide798bc1b2014-02-20 14:02:40 -0800220 public void networkGraphEvents(Collection<SwitchEvent> addedSwitchEvents,
221 Collection<SwitchEvent> removedSwitchEvents,
222 Collection<PortEvent> addedPortEvents,
223 Collection<PortEvent> removedPortEvents,
224 Collection<LinkEvent> addedLinkEvents,
225 Collection<LinkEvent> removedLinkEvents,
226 Collection<DeviceEvent> addedDeviceEvents,
227 Collection<DeviceEvent> removedDeviceEvents) {
Toshio Koidea9078af2014-02-21 16:57:04 -0800228
Toshio Koidea94060f2014-02-21 22:58:32 -0800229 log("called_networkGraphEvents");
230 HashSet<Intent> affectedPaths = new HashSet<>();
Toshio Koidea9078af2014-02-21 16:57:04 -0800231
Toshio Koidea94060f2014-02-21 22:58:32 -0800232 if (addedLinkEvents.size() > 0 ||
233 addedPortEvents.size() > 0 ||
234 addedSwitchEvents.size() > 0) {
235 log("begin_getAllIntents");
236 affectedPaths.addAll(getPathIntents().getAllIntents());
237 log("end_getAllIntents");
238 }
239 else {
240 log("begin_getIntentsByLink");
241 for (LinkEvent linkEvent: removedLinkEvents)
242 affectedPaths.addAll(pathIntents.getIntentsByLink(linkEvent));
243 log("end_getIntentsByLink");
Toshio Koidea9078af2014-02-21 16:57:04 -0800244
Toshio Koidea94060f2014-02-21 22:58:32 -0800245 log("begin_getIntentsByPort");
246 for (PortEvent portEvent: removedPortEvents)
247 affectedPaths.addAll(pathIntents.getIntentsByPort(portEvent.getDpid(), portEvent.getNumber()));
248 log("end_getIntentsByPort");
Toshio Koidea9078af2014-02-21 16:57:04 -0800249
Toshio Koidea94060f2014-02-21 22:58:32 -0800250 log("begin_getIntentsByDpid");
251 for (SwitchEvent switchEvent: removedSwitchEvents)
252 affectedPaths.addAll(pathIntents.getIntentsByDpid(switchEvent.getDpid()));
253 log("end_getIntentsByDpid");
254 }
Toshio Koidea9078af2014-02-21 16:57:04 -0800255 reroutePaths(affectedPaths);
Toshio Koidea94060f2014-02-21 22:58:32 -0800256 log("finished_networkGraphEvents");
Toshio Koide0c9106d2014-02-19 15:26:38 -0800257 }
Toshio Koide066506e2014-02-20 19:52:09 -0800258
259 // ================================================================================
260 // IEventChannelListener implementations
261 // ================================================================================
262
263 @Override
264 public void entryAdded(IntentStateList value) {
Toshio Koidea94060f2014-02-21 22:58:32 -0800265 log("called_EntryAdded");
Toshio Koide066506e2014-02-20 19:52:09 -0800266 entryUpdated(value);
267 }
268
269 @Override
270 public void entryRemoved(IntentStateList value) {
271 // do nothing
272 }
273
274 @Override
275 public void entryUpdated(IntentStateList value) {
Toshio Koide8315d7d2014-02-21 22:58:32 -0800276 // TODO draw state transition diagram in multiple ONOS instances and update this method
Toshio Koide93be5d62014-02-23 19:30:57 -0800277 lock.lock(); // TODO optimize locking using smaller steps
278 try {
279 log("called_EntryUpdated");
280 // reflect state changes of path-level intent into application-level intents
281 log("begin_changeStateByNotification");
282 IntentStateList parentStates = new IntentStateList();
283 for (Entry<String, IntentState> entry: value.entrySet()) {
284 PathIntent pathIntent = (PathIntent) pathIntents.getIntent(entry.getKey());
285 if (pathIntent == null) continue;
Toshio Koide8315d7d2014-02-21 22:58:32 -0800286
Toshio Koide93be5d62014-02-23 19:30:57 -0800287 Intent parentIntent = pathIntent.getParentIntent();
288 if (parentIntent == null ||
289 !(parentIntent instanceof ShortestPathIntent) ||
290 !((ShortestPathIntent) parentIntent).getPathIntentId().equals(pathIntent.getId()))
291 continue;
Toshio Koide066506e2014-02-20 19:52:09 -0800292
Toshio Koide93be5d62014-02-23 19:30:57 -0800293 IntentState state = entry.getValue();
294 switch (state) {
295 case INST_REQ:
296 case INST_ACK:
297 case INST_NACK:
298 case DEL_REQ:
299 case DEL_ACK:
300 case DEL_PENDING:
301 parentStates.put(parentIntent.getId(), state);
302 break;
303 default:
304 break;
305 }
Toshio Koide066506e2014-02-20 19:52:09 -0800306 }
Toshio Koide93be5d62014-02-23 19:30:57 -0800307 highLevelIntents.changeStates(parentStates);
308 pathIntents.changeStates(value);
309 log("end_changeStateByNotification");
Toshio Koide066506e2014-02-20 19:52:09 -0800310 }
Toshio Koide93be5d62014-02-23 19:30:57 -0800311 finally {
312 lock.unlock();
313 }
Toshio Koide066506e2014-02-20 19:52:09 -0800314 }
Toshio Koidea9078af2014-02-21 16:57:04 -0800315}