blob: ebcb7898e2d082243d991c8c2a64180ca9012c6f [file] [log] [blame]
Brian O'Connor66630c82014-10-02 21:08:19 -07001package org.onlab.onos.net.intent.impl;
2
tom95329eb2014-10-06 08:40:06 -07003import com.google.common.collect.ImmutableMap;
Brian O'Connor66630c82014-10-02 21:08:19 -07004import org.apache.felix.scr.annotations.Activate;
5import org.apache.felix.scr.annotations.Component;
6import org.apache.felix.scr.annotations.Deactivate;
7import org.apache.felix.scr.annotations.Reference;
8import org.apache.felix.scr.annotations.ReferenceCardinality;
9import org.apache.felix.scr.annotations.Service;
10import org.onlab.onos.event.AbstractListenerRegistry;
11import org.onlab.onos.event.EventDeliveryService;
12import org.onlab.onos.net.intent.InstallableIntent;
13import org.onlab.onos.net.intent.Intent;
14import org.onlab.onos.net.intent.IntentCompiler;
15import org.onlab.onos.net.intent.IntentEvent;
16import org.onlab.onos.net.intent.IntentException;
17import org.onlab.onos.net.intent.IntentExtensionService;
18import org.onlab.onos.net.intent.IntentId;
19import org.onlab.onos.net.intent.IntentInstaller;
20import org.onlab.onos.net.intent.IntentListener;
21import org.onlab.onos.net.intent.IntentOperations;
22import org.onlab.onos.net.intent.IntentService;
23import org.onlab.onos.net.intent.IntentState;
24import org.onlab.onos.net.intent.IntentStore;
25import org.onlab.onos.net.intent.IntentStoreDelegate;
26import org.slf4j.Logger;
27
tom95329eb2014-10-06 08:40:06 -070028import java.util.ArrayList;
29import java.util.List;
30import java.util.Map;
31import java.util.concurrent.ConcurrentHashMap;
32import java.util.concurrent.ConcurrentMap;
33
34import static com.google.common.base.Preconditions.checkNotNull;
35import static org.onlab.onos.net.intent.IntentState.*;
36import static org.slf4j.LoggerFactory.getLogger;
Brian O'Connor66630c82014-10-02 21:08:19 -070037
38/**
39 * An implementation of Intent Manager.
40 */
41@Component(immediate = true)
42@Service
43public class IntentManager
44 implements IntentService, IntentExtensionService {
45 private final Logger log = getLogger(getClass());
46
47 public static final String INTENT_NULL = "Intent cannot be null";
48 public static final String INTENT_ID_NULL = "Intent ID cannot be null";
49
50 // Collections for compiler, installer, and listener are ONOS instance local
51 private final ConcurrentMap<Class<? extends Intent>,
52 IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
53 private final ConcurrentMap<Class<? extends InstallableIntent>,
54 IntentInstaller<? extends InstallableIntent>> installers = new ConcurrentHashMap<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070055
56 private final AbstractListenerRegistry<IntentEvent, IntentListener>
tom95329eb2014-10-06 08:40:06 -070057 listenerRegistry = new AbstractListenerRegistry<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070058
59 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
tom95329eb2014-10-06 08:40:06 -070060 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
Brian O'Connor66630c82014-10-02 21:08:19 -070061
62 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 protected IntentStore store;
64
65 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom95329eb2014-10-06 08:40:06 -070066 protected FlowTrackerService trackerService;
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Brian O'Connor66630c82014-10-02 21:08:19 -070069 protected EventDeliveryService eventDispatcher;
70
71 @Activate
72 public void activate() {
73 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -070074 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -070075 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connor66630c82014-10-02 21:08:19 -070076 log.info("Started");
77 }
78
79 @Deactivate
80 public void deactivate() {
81 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -070082 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -070083 eventDispatcher.removeSink(IntentEvent.class);
84 log.info("Stopped");
85 }
86
87 @Override
88 public void submit(Intent intent) {
89 checkNotNull(intent, INTENT_NULL);
90 registerSubclassCompilerIfNeeded(intent);
91 IntentEvent event = store.createIntent(intent);
Brian O'Connor66630c82014-10-02 21:08:19 -070092 processStoreEvent(event);
93 }
94
95 @Override
96 public void withdraw(Intent intent) {
97 checkNotNull(intent, INTENT_NULL);
98 IntentEvent event = store.setState(intent, WITHDRAWING);
tom95329eb2014-10-06 08:40:06 -070099 List<InstallableIntent> installables = store.getInstallableIntents(intent.getId());
100 if (installables != null) {
101 for (InstallableIntent installable : installables) {
102 trackerService.removeTrackedResources(intent.getId(),
103 installable.requiredLinks());
104 }
105 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700106 processStoreEvent(event);
107 }
108
109 // FIXME: implement this method
110 @Override
111 public void execute(IntentOperations operations) {
112 throw new UnsupportedOperationException("execute() is not implemented yet");
113 }
114
115 @Override
116 public Iterable<Intent> getIntents() {
117 return store.getIntents();
118 }
119
120 @Override
121 public long getIntentCount() {
122 return store.getIntentCount();
123 }
124
125 @Override
126 public Intent getIntent(IntentId id) {
127 checkNotNull(id, INTENT_ID_NULL);
128 return store.getIntent(id);
129 }
130
131 @Override
132 public IntentState getIntentState(IntentId id) {
133 checkNotNull(id, INTENT_ID_NULL);
134 return store.getIntentState(id);
135 }
136
137 @Override
138 public void addListener(IntentListener listener) {
139 listenerRegistry.addListener(listener);
140 }
141
142 @Override
143 public void removeListener(IntentListener listener) {
144 listenerRegistry.removeListener(listener);
145 }
146
147 @Override
148 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
149 compilers.put(cls, compiler);
150 }
151
152 @Override
153 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
154 compilers.remove(cls);
155 }
156
157 @Override
158 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
159 return ImmutableMap.copyOf(compilers);
160 }
161
162 @Override
163 public <T extends InstallableIntent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
164 installers.put(cls, installer);
165 }
166
167 @Override
168 public <T extends InstallableIntent> void unregisterInstaller(Class<T> cls) {
169 installers.remove(cls);
170 }
171
172 @Override
173 public Map<Class<? extends InstallableIntent>, IntentInstaller<? extends InstallableIntent>> getInstallers() {
174 return ImmutableMap.copyOf(installers);
175 }
176
177 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700178 * Returns the corresponding intent compiler to the specified intent.
179 *
180 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700181 * @param <T> the type of intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700182 * @return intent compiler corresponding to the specified intent
183 */
184 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
185 @SuppressWarnings("unchecked")
186 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
187 if (compiler == null) {
188 throw new IntentException("no compiler for class " + intent.getClass());
189 }
190 return compiler;
191 }
192
193 /**
194 * Returns the corresponding intent installer to the specified installable intent.
tom95329eb2014-10-06 08:40:06 -0700195 *
Brian O'Connor66630c82014-10-02 21:08:19 -0700196 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700197 * @param <T> the type of installable intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700198 * @return intent installer corresponding to the specified installable intent
199 */
200 private <T extends InstallableIntent> IntentInstaller<T> getInstaller(T intent) {
201 @SuppressWarnings("unchecked")
202 IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
203 if (installer == null) {
204 throw new IntentException("no installer for class " + intent.getClass());
205 }
206 return installer;
207 }
208
209 /**
210 * Compiles an intent.
211 *
212 * @param intent intent
213 */
214 private void compileIntent(Intent intent) {
215 // FIXME: To make SDN-IP workable ASAP, only single level compilation is implemented
216 // TODO: implement compilation traversing tree structure
217 List<InstallableIntent> installable = new ArrayList<>();
218 for (Intent compiled : getCompiler(intent).compile(intent)) {
tom95329eb2014-10-06 08:40:06 -0700219 InstallableIntent installableIntent = (InstallableIntent) compiled;
220 installable.add(installableIntent);
221 trackerService.addTrackedResources(intent.getId(),
222 installableIntent.requiredLinks());
Brian O'Connor66630c82014-10-02 21:08:19 -0700223 }
224 IntentEvent event = store.addInstallableIntents(intent.getId(), installable);
Brian O'Connor66630c82014-10-02 21:08:19 -0700225 processStoreEvent(event);
226 }
227
228 /**
229 * Installs an intent.
230 *
231 * @param intent intent
232 */
233 private void installIntent(Intent intent) {
tom95329eb2014-10-06 08:40:06 -0700234 List<InstallableIntent> installables = store.getInstallableIntents(intent.getId());
235 if (installables != null) {
236 for (InstallableIntent installable : installables) {
237 registerSubclassInstallerIfNeeded(installable);
238 getInstaller(installable).install(installable);
239 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700240 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700241 IntentEvent event = store.setState(intent, INSTALLED);
Brian O'Connor66630c82014-10-02 21:08:19 -0700242 processStoreEvent(event);
243
244 }
245
246 /**
247 * Uninstalls an intent.
248 *
249 * @param intent intent
250 */
251 private void uninstallIntent(Intent intent) {
tom95329eb2014-10-06 08:40:06 -0700252 List<InstallableIntent> installables = store.getInstallableIntents(intent.getId());
253 if (installables != null) {
254 for (InstallableIntent installable : installables) {
255 getInstaller(installable).uninstall(installable);
256 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700257 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700258 store.removeInstalledIntents(intent.getId());
259 store.setState(intent, WITHDRAWN);
260 }
261
262 /**
263 * Registers an intent compiler of the specified intent if an intent compiler
264 * for the intent is not registered. This method traverses the class hierarchy of
265 * the intent. Once an intent compiler for a parent type is found, this method
266 * registers the found intent compiler.
267 *
268 * @param intent intent
269 */
270 private void registerSubclassCompilerIfNeeded(Intent intent) {
271 if (!compilers.containsKey(intent.getClass())) {
272 Class<?> cls = intent.getClass();
273 while (cls != Object.class) {
274 // As long as we're within the Intent class descendants
275 if (Intent.class.isAssignableFrom(cls)) {
276 IntentCompiler<?> compiler = compilers.get(cls);
277 if (compiler != null) {
278 compilers.put(intent.getClass(), compiler);
279 return;
280 }
281 }
282 cls = cls.getSuperclass();
283 }
284 }
285 }
286
287 /**
288 * Registers an intent installer of the specified intent if an intent installer
289 * for the intent is not registered. This method traverses the class hierarchy of
290 * the intent. Once an intent installer for a parent type is found, this method
291 * registers the found intent installer.
292 *
293 * @param intent intent
294 */
295 private void registerSubclassInstallerIfNeeded(InstallableIntent intent) {
296 if (!installers.containsKey(intent.getClass())) {
297 Class<?> cls = intent.getClass();
298 while (cls != Object.class) {
299 // As long as we're within the InstallableIntent class descendants
300 if (InstallableIntent.class.isAssignableFrom(cls)) {
301 IntentInstaller<?> installer = installers.get(cls);
302 if (installer != null) {
303 installers.put(intent.getClass(), installer);
304 return;
305 }
306 }
307 cls = cls.getSuperclass();
308 }
309 }
310 }
311
312 /**
313 * Handles state transition of submitted intents.
314 */
315 private void processStoreEvent(IntentEvent event) {
tom95329eb2014-10-06 08:40:06 -0700316 eventDispatcher.post(event);
317 Intent intent = event.getIntent();
318 try {
319 switch (event.getState()) {
320 case SUBMITTED:
321 compileIntent(intent);
322 break;
323 case COMPILED:
324 installIntent(intent);
325 break;
326 case INSTALLED:
327 break;
328 case WITHDRAWING:
329 uninstallIntent(intent);
330 break;
331 case WITHDRAWN:
332 break;
333 case FAILED:
334 break;
335 default:
336 throw new IllegalStateException("the state of IntentEvent is illegal: " +
337 event.getState());
Brian O'Connor66630c82014-10-02 21:08:19 -0700338 }
tom95329eb2014-10-06 08:40:06 -0700339 } catch (IntentException e) {
340 store.setState(intent, FAILED);
341 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700342
343 }
344
345 // Store delegate to re-post events emitted from the store.
346 private class InternalStoreDelegate implements IntentStoreDelegate {
347 @Override
348 public void notify(IntentEvent event) {
tomf5c9d922014-10-03 15:22:03 -0700349 processStoreEvent(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700350 }
351 }
352
tom95329eb2014-10-06 08:40:06 -0700353 // Topology change delegate
354 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
355 @Override
356 public void bumpIntents(Iterable<IntentId> intentIds) {
357 for (IntentId intentId : intentIds) {
358 compileIntent(getIntent(intentId));
359 }
360 }
361
362 @Override
363 public void failIntents(Iterable<IntentId> intentIds) {
364 for (IntentId intentId : intentIds) {
365 Intent intent = getIntent(intentId);
366 uninstallIntent(intent);
367 compileIntent(intent);
368 }
369 }
370 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700371}