blob: f84c24fde62f3bafe215d450344ba1a033081ab6 [file] [log] [blame]
alshabib77b88482015-04-07 15:47:50 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.net.flowobjective.impl;
17
18import com.google.common.collect.Maps;
alshabib2a441c62015-04-13 18:39:38 -070019import com.google.common.collect.Sets;
alshabib77b88482015-04-07 15:47:50 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
26import org.onlab.osgi.DefaultServiceDirectory;
27import org.onlab.osgi.ServiceDirectory;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070028import org.onlab.util.ItemNotFoundException;
alshabib77b88482015-04-07 15:47:50 -070029import org.onosproject.cluster.ClusterService;
30import org.onosproject.mastership.MastershipEvent;
31import org.onosproject.mastership.MastershipListener;
32import org.onosproject.mastership.MastershipService;
alshabib77b88482015-04-07 15:47:50 -070033import org.onosproject.net.DeviceId;
34import org.onosproject.net.behaviour.Pipeliner;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070035import org.onosproject.net.behaviour.PipelinerContext;
alshabibaebe7752015-04-07 17:45:42 -070036import org.onosproject.net.device.DeviceEvent;
37import org.onosproject.net.device.DeviceListener;
alshabib77b88482015-04-07 15:47:50 -070038import org.onosproject.net.device.DeviceService;
Thomas Vachuska866b46a2015-04-30 00:26:55 -070039import org.onosproject.net.driver.DefaultDriverProviderService;
alshabib77b88482015-04-07 15:47:50 -070040import org.onosproject.net.driver.DriverHandler;
41import org.onosproject.net.driver.DriverService;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070042import org.onosproject.net.flow.FlowRuleService;
alshabib77b88482015-04-07 15:47:50 -070043import org.onosproject.net.flowobjective.FilteringObjective;
44import org.onosproject.net.flowobjective.FlowObjectiveService;
alshabib2a441c62015-04-13 18:39:38 -070045import org.onosproject.net.flowobjective.FlowObjectiveStore;
46import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate;
alshabib77b88482015-04-07 15:47:50 -070047import org.onosproject.net.flowobjective.ForwardingObjective;
48import org.onosproject.net.flowobjective.NextObjective;
alshabib910aff12015-04-09 16:55:57 -070049import org.onosproject.net.flowobjective.Objective;
Jonathan Hart17d00452015-04-21 17:10:00 -070050import org.onosproject.net.flowobjective.ObjectiveError;
alshabib2a441c62015-04-13 18:39:38 -070051import org.onosproject.net.flowobjective.ObjectiveEvent;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070052import org.onosproject.net.group.GroupService;
alshabib77b88482015-04-07 15:47:50 -070053import org.slf4j.Logger;
54import org.slf4j.LoggerFactory;
55
alshabib77b88482015-04-07 15:47:50 -070056import java.util.Map;
alshabib2a441c62015-04-13 18:39:38 -070057import java.util.Set;
Jonathan Hart17d00452015-04-21 17:10:00 -070058import java.util.concurrent.ExecutorService;
alshabib77b88482015-04-07 15:47:50 -070059
Thomas Vachuska866b46a2015-04-30 00:26:55 -070060import static java.util.concurrent.Executors.newFixedThreadPool;
Jonathan Hart17d00452015-04-21 17:10:00 -070061import static org.onlab.util.Tools.groupedThreads;
alshabib77b88482015-04-07 15:47:50 -070062
63/**
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070064 * Provides implementation of the flow objective programming service.
alshabib77b88482015-04-07 15:47:50 -070065 */
alshabib2a441c62015-04-13 18:39:38 -070066@Component(immediate = true)
alshabib77b88482015-04-07 15:47:50 -070067@Service
68public class FlowObjectiveManager implements FlowObjectiveService {
69
Saurav Dasbd7f7422015-04-23 16:31:47 -070070 public static final int INSTALL_RETRY_ATTEMPTS = 5;
Jonathan Hart17d00452015-04-21 17:10:00 -070071 public static final long INSTALL_RETRY_INTERVAL = 1000; // ms
alshabib77b88482015-04-07 15:47:50 -070072
Jonathan Hart17d00452015-04-21 17:10:00 -070073 private final Logger log = LoggerFactory.getLogger(getClass());
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070074
alshabib77b88482015-04-07 15:47:50 -070075 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected DriverService driverService;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected DeviceService deviceService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected MastershipService mastershipService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected ClusterService clusterService;
86
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070087 // Note: The following dependencies are added on behalf of the pipeline
88 // driver behaviours to assure these services are available for their
89 // initialization.
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected FlowRuleService flowRuleService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected GroupService groupService;
95
alshabib2a441c62015-04-13 18:39:38 -070096 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected FlowObjectiveStore flowObjectiveStore;
98
Thomas Vachuska866b46a2015-04-30 00:26:55 -070099 // Note: This must remain an optional dependency to allow re-install of default drivers.
100 // Note: For now disabled until we can move to OPTIONAL_UNARY dependency
101 // @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC)
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected DefaultDriverProviderService defaultDriverService;
104
alshabib2a441c62015-04-13 18:39:38 -0700105 private final FlowObjectiveStoreDelegate delegate = new InternalStoreDelegate();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700106
107 private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap();
alshabib910aff12015-04-09 16:55:57 -0700108 private final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700109
110 private final PipelinerContext context = new InnerPipelineContext();
111 private final MastershipListener mastershipListener = new InnerMastershipListener();
112 private final DeviceListener deviceListener = new InnerDeviceListener();
113
alshabib77b88482015-04-07 15:47:50 -0700114 protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
alshabib910aff12015-04-09 16:55:57 -0700115
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700116 private Map<Integer, Set<PendingNext>> pendingForwards = Maps.newConcurrentMap();
alshabib2a441c62015-04-13 18:39:38 -0700117
Jonathan Hart17d00452015-04-21 17:10:00 -0700118 private ExecutorService executorService;
alshabib2a441c62015-04-13 18:39:38 -0700119
alshabib77b88482015-04-07 15:47:50 -0700120 @Activate
121 protected void activate() {
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700122 executorService = newFixedThreadPool(4, groupedThreads("onos/objective-installer", "%d"));
alshabib2a441c62015-04-13 18:39:38 -0700123 flowObjectiveStore.setDelegate(delegate);
alshabib77b88482015-04-07 15:47:50 -0700124 mastershipService.addListener(mastershipListener);
alshabibaebe7752015-04-07 17:45:42 -0700125 deviceService.addListener(deviceListener);
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700126 deviceService.getDevices().forEach(device -> setupPipelineHandler(device.id()));
alshabib77b88482015-04-07 15:47:50 -0700127 log.info("Started");
128 }
129
130 @Deactivate
131 protected void deactivate() {
alshabib2a441c62015-04-13 18:39:38 -0700132 flowObjectiveStore.unsetDelegate(delegate);
alshabib77b88482015-04-07 15:47:50 -0700133 mastershipService.removeListener(mastershipListener);
alshabibaebe7752015-04-07 17:45:42 -0700134 deviceService.removeListener(deviceListener);
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700135 executorService.shutdown();
136 pipeliners.clear();
137 driverHandlers.clear();
alshabib77b88482015-04-07 15:47:50 -0700138 log.info("Stopped");
139 }
140
Jonathan Hart17d00452015-04-21 17:10:00 -0700141 /**
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700142 * Hook for binding the optional default driver providers.
143 *
144 * @param service arriving default driver provider service
145 */
146 // Note: For now disabled until we can move to OPTIONAL_UNARY dependency
147 protected void xbindDefaultDriverService(DefaultDriverProviderService service) {
148 log.info("Detected default drivers... going active");
149 defaultDriverService = service;
150 deviceService.getDevices().forEach(device -> setupPipelineHandler(device.id()));
151 }
152
153 /**
154 * Hook for unbinding the optional default driver providers.
155 *
156 * @param service departing default driver provider service
157 */
158 // Note: For now disabled until we can move to OPTIONAL_UNARY dependency
159 protected void xunbindDefaultDriverService(DefaultDriverProviderService service) {
160 log.info("Lost default drivers... going dormant");
161 defaultDriverService = null;
162 pipeliners.clear();
163 driverHandlers.clear();
164 }
165
166
167 /**
Jonathan Hart17d00452015-04-21 17:10:00 -0700168 * Task that passes the flow objective down to the driver. The task will
169 * make a few attempts to find the appropriate driver, then eventually give
170 * up and report an error if no suitable driver could be found.
171 */
172 private class ObjectiveInstaller implements Runnable {
173 private final DeviceId deviceId;
174 private final Objective objective;
175
176 private int numAttempts = 0;
177
178 public ObjectiveInstaller(DeviceId deviceId, Objective objective) {
179 this.deviceId = deviceId;
180 this.objective = objective;
alshabib910aff12015-04-09 16:55:57 -0700181 }
alshabib77b88482015-04-07 15:47:50 -0700182
Jonathan Hart17d00452015-04-21 17:10:00 -0700183 @Override
184 public void run() {
185 try {
186 numAttempts++;
187
188 Pipeliner pipeliner = getDevicePipeliner(deviceId);
189
190 if (pipeliner != null) {
191 if (objective instanceof NextObjective) {
192 pipeliner.next((NextObjective) objective);
193 } else if (objective instanceof ForwardingObjective) {
194 pipeliner.forward((ForwardingObjective) objective);
195 } else {
196 pipeliner.filter((FilteringObjective) objective);
197 }
198 } else if (numAttempts < INSTALL_RETRY_ATTEMPTS) {
Saurav Das3d038262015-04-23 12:36:58 -0700199 Thread.sleep(INSTALL_RETRY_INTERVAL);
Jonathan Hart17d00452015-04-21 17:10:00 -0700200 executorService.submit(this);
201 } else {
202 // Otherwise we've tried a few times and failed, report an
203 // error back to the user.
204 objective.context().ifPresent(
205 c -> c.onError(objective, ObjectiveError.DEVICEMISSING));
206 }
207 } catch (Exception e) {
208 log.warn("Exception while installing flow objective", e);
209 }
210 }
211 }
212
213 @Override
214 public void filter(DeviceId deviceId, FilteringObjective filteringObjective) {
215 executorService.submit(new ObjectiveInstaller(deviceId, filteringObjective));
alshabib77b88482015-04-07 15:47:50 -0700216 }
217
218 @Override
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700219 public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
alshabib2a441c62015-04-13 18:39:38 -0700220 if (queueObjective(deviceId, forwardingObjective)) {
221 return;
alshabib910aff12015-04-09 16:55:57 -0700222 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700223 executorService.submit(new ObjectiveInstaller(deviceId, forwardingObjective));
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700224 }
225
alshabib2a441c62015-04-13 18:39:38 -0700226 @Override
Jonathan Hart17d00452015-04-21 17:10:00 -0700227 public void next(DeviceId deviceId, NextObjective nextObjective) {
228 executorService.submit(new ObjectiveInstaller(deviceId, nextObjective));
alshabib2a441c62015-04-13 18:39:38 -0700229 }
230
alshabibf6ea9e62015-04-21 17:08:26 -0700231 @Override
232 public int allocateNextId() {
233 return flowObjectiveStore.allocateNextId();
234 }
235
alshabib2a441c62015-04-13 18:39:38 -0700236 private boolean queueObjective(DeviceId deviceId, ForwardingObjective fwd) {
237 if (fwd.nextId() != null &&
238 flowObjectiveStore.getNextGroup(fwd.nextId()) == null) {
Saurav Das3ea46622015-04-22 14:01:34 -0700239 log.trace("Queuing forwarding objective for nextId {}", fwd.nextId());
alshabib2a441c62015-04-13 18:39:38 -0700240 if (pendingForwards.putIfAbsent(fwd.nextId(),
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700241 Sets.newHashSet(new PendingNext(deviceId, fwd))) != null) {
alshabib2a441c62015-04-13 18:39:38 -0700242 Set<PendingNext> pending = pendingForwards.get(fwd.nextId());
243 pending.add(new PendingNext(deviceId, fwd));
244 }
245 return true;
246 }
247 return false;
248 }
249
alshabib910aff12015-04-09 16:55:57 -0700250 // Retrieves the device pipeline behaviour from the cache.
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700251 private Pipeliner getDevicePipeliner(DeviceId deviceId) {
alshabib910aff12015-04-09 16:55:57 -0700252 Pipeliner pipeliner = pipeliners.get(deviceId);
alshabib910aff12015-04-09 16:55:57 -0700253 return pipeliner;
alshabib77b88482015-04-07 15:47:50 -0700254 }
255
alshabib2a441c62015-04-13 18:39:38 -0700256 private void setupPipelineHandler(DeviceId deviceId) {
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700257 if (defaultDriverService == null) {
258 // We're not ready to go to work yet.
259 return;
260 }
261
Jonathan Hart17d00452015-04-21 17:10:00 -0700262 // Attempt to lookup the handler in the cache
263 DriverHandler handler = driverHandlers.get(deviceId);
264 if (handler == null) {
265 try {
266 // Otherwise create it and if it has pipeline behaviour, cache it
267 handler = driverService.createHandler(deviceId);
268 if (!handler.driver().hasBehaviour(Pipeliner.class)) {
269 log.warn("Pipeline behaviour not supported for device {}",
270 deviceId);
alshabib2a441c62015-04-13 18:39:38 -0700271 return;
272 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700273 } catch (ItemNotFoundException e) {
274 log.warn("No applicable driver for device {}", deviceId);
275 return;
alshabib2a441c62015-04-13 18:39:38 -0700276 }
277
Jonathan Hart17d00452015-04-21 17:10:00 -0700278 driverHandlers.put(deviceId, handler);
alshabib2a441c62015-04-13 18:39:38 -0700279 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700280
281 // Always (re)initialize the pipeline behaviour
282 log.info("Driver {} bound to device {} ... initializing driver",
283 handler.driver().name(), deviceId);
284 Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
285 pipeliner.init(deviceId, context);
286 pipeliners.putIfAbsent(deviceId, pipeliner);
alshabib2a441c62015-04-13 18:39:38 -0700287 }
alshabibaebe7752015-04-07 17:45:42 -0700288
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700289 // Triggers driver setup when the local node becomes a device master.
alshabib77b88482015-04-07 15:47:50 -0700290 private class InnerMastershipListener implements MastershipListener {
291 @Override
292 public void event(MastershipEvent event) {
293 switch (event.type()) {
alshabib77b88482015-04-07 15:47:50 -0700294 case MASTER_CHANGED:
Jonathan Hart17d00452015-04-21 17:10:00 -0700295 log.info("mastership changed on device {}", event.subject());
Saurav Das3d038262015-04-23 12:36:58 -0700296 if (deviceService.isAvailable(event.subject())) {
297 setupPipelineHandler(event.subject());
298 }
alshabib4313d102015-04-08 18:55:08 -0700299 break;
300 case BACKUPS_CHANGED:
alshabib77b88482015-04-07 15:47:50 -0700301 break;
302 default:
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700303 break;
alshabib77b88482015-04-07 15:47:50 -0700304 }
305 }
alshabibaebe7752015-04-07 17:45:42 -0700306 }
alshabib77b88482015-04-07 15:47:50 -0700307
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700308 // Triggers driver setup when a device is (re)detected.
alshabibaebe7752015-04-07 17:45:42 -0700309 private class InnerDeviceListener implements DeviceListener {
310 @Override
311 public void event(DeviceEvent event) {
312 switch (event.type()) {
313 case DEVICE_ADDED:
314 case DEVICE_AVAILABILITY_CHANGED:
Saurav Das3ea46622015-04-22 14:01:34 -0700315 log.info("Device either added or availability changed {}",
316 event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700317 if (deviceService.isAvailable(event.subject().id())) {
Saurav Das3ea46622015-04-22 14:01:34 -0700318 log.info("Device is now available {}", event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700319 setupPipelineHandler(event.subject().id());
320 }
321 break;
322 case DEVICE_UPDATED:
323 break;
324 case DEVICE_REMOVED:
325 break;
326 case DEVICE_SUSPENDED:
327 break;
328 case PORT_ADDED:
329 break;
330 case PORT_UPDATED:
331 break;
332 case PORT_REMOVED:
alshabibaebe7752015-04-07 17:45:42 -0700333 break;
334 default:
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700335 break;
alshabibaebe7752015-04-07 17:45:42 -0700336 }
alshabib77b88482015-04-07 15:47:50 -0700337 }
338 }
alshabibaebe7752015-04-07 17:45:42 -0700339
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700340 // Processing context for initializing pipeline driver behaviours.
341 private class InnerPipelineContext implements PipelinerContext {
342 @Override
343 public ServiceDirectory directory() {
344 return serviceDirectory;
alshabibaebe7752015-04-07 17:45:42 -0700345 }
alshabib2a441c62015-04-13 18:39:38 -0700346
347 @Override
348 public FlowObjectiveStore store() {
349 return flowObjectiveStore;
350 }
alshabib2a441c62015-04-13 18:39:38 -0700351 }
352
353 private class InternalStoreDelegate implements FlowObjectiveStoreDelegate {
354 @Override
355 public void notify(ObjectiveEvent event) {
Saurav Das3ea46622015-04-22 14:01:34 -0700356 log.debug("Received notification of obj event {}", event);
alshabib2a441c62015-04-13 18:39:38 -0700357 Set<PendingNext> pending = pendingForwards.remove(event.subject());
358
359 if (pending == null) {
Saurav Das3ea46622015-04-22 14:01:34 -0700360 log.debug("Nothing pending for this obj event");
alshabib2a441c62015-04-13 18:39:38 -0700361 return;
362 }
363
Saurav Das3ea46622015-04-22 14:01:34 -0700364 log.debug("Processing pending forwarding objectives {}", pending.size());
alshabib2a441c62015-04-13 18:39:38 -0700365
366 pending.forEach(p -> getDevicePipeliner(p.deviceId())
367 .forward(p.forwardingObjective()));
368
369 }
370 }
371
372 /**
373 * Data class used to hold a pending forwarding objective that could not
374 * be processed because the associated next object was not present.
375 */
376 private class PendingNext {
377 private final DeviceId deviceId;
378 private final ForwardingObjective fwd;
379
380 public PendingNext(DeviceId deviceId, ForwardingObjective fwd) {
381 this.deviceId = deviceId;
382 this.fwd = fwd;
383 }
384
385 public DeviceId deviceId() {
386 return deviceId;
387 }
388
389 public ForwardingObjective forwardingObjective() {
390 return fwd;
391 }
alshabibaebe7752015-04-07 17:45:42 -0700392 }
alshabib77b88482015-04-07 15:47:50 -0700393}