blob: 47b63ed35706450f7caa0f57368065aa2e9f7f53 [file] [log] [blame]
alshabib77b88482015-04-07 15:47:50 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
alshabib77b88482015-04-07 15:47:50 -07003 *
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;
Thomas Vachuskad27097c2016-06-14 19:10:41 -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;
Yi Tseng374c5f32017-03-05 22:51:35 -080023import org.apache.felix.scr.annotations.Modified;
24import org.apache.felix.scr.annotations.Property;
alshabib77b88482015-04-07 15:47:50 -070025import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.apache.felix.scr.annotations.Service;
28import org.onlab.osgi.DefaultServiceDirectory;
29import org.onlab.osgi.ServiceDirectory;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070030import org.onlab.util.ItemNotFoundException;
Yi Tseng374c5f32017-03-05 22:51:35 -080031import org.onlab.util.Tools;
32import org.onosproject.cfg.ComponentConfigService;
alshabib77b88482015-04-07 15:47:50 -070033import org.onosproject.cluster.ClusterService;
alshabib77b88482015-04-07 15:47:50 -070034import org.onosproject.net.DeviceId;
Saurav Das24431192016-03-07 19:13:00 -080035import org.onosproject.net.behaviour.NextGroup;
alshabib77b88482015-04-07 15:47:50 -070036import org.onosproject.net.behaviour.Pipeliner;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070037import org.onosproject.net.behaviour.PipelinerContext;
alshabibaebe7752015-04-07 17:45:42 -070038import org.onosproject.net.device.DeviceEvent;
39import org.onosproject.net.device.DeviceListener;
alshabib77b88482015-04-07 15:47:50 -070040import org.onosproject.net.device.DeviceService;
alshabib77b88482015-04-07 15:47:50 -070041import org.onosproject.net.driver.DriverHandler;
42import org.onosproject.net.driver.DriverService;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070043import org.onosproject.net.flow.FlowRuleService;
alshabib77b88482015-04-07 15:47:50 -070044import org.onosproject.net.flowobjective.FilteringObjective;
45import org.onosproject.net.flowobjective.FlowObjectiveService;
alshabib2a441c62015-04-13 18:39:38 -070046import org.onosproject.net.flowobjective.FlowObjectiveStore;
47import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate;
alshabib77b88482015-04-07 15:47:50 -070048import org.onosproject.net.flowobjective.ForwardingObjective;
49import org.onosproject.net.flowobjective.NextObjective;
alshabib910aff12015-04-09 16:55:57 -070050import org.onosproject.net.flowobjective.Objective;
Jonathan Hart17d00452015-04-21 17:10:00 -070051import org.onosproject.net.flowobjective.ObjectiveError;
alshabib2a441c62015-04-13 18:39:38 -070052import org.onosproject.net.flowobjective.ObjectiveEvent;
Saurav Das423fe2b2015-12-04 10:52:59 -080053import org.onosproject.net.flowobjective.ObjectiveEvent.Type;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070054import org.onosproject.net.group.GroupService;
Yi Tseng374c5f32017-03-05 22:51:35 -080055import org.osgi.service.component.ComponentContext;
alshabib77b88482015-04-07 15:47:50 -070056import org.slf4j.Logger;
57import org.slf4j.LoggerFactory;
58
Saurav Das24431192016-03-07 19:13:00 -080059import java.util.ArrayList;
Saurav Das24431192016-03-07 19:13:00 -080060import java.util.List;
alshabib77b88482015-04-07 15:47:50 -070061import java.util.Map;
Saurav Das8a0732e2015-11-20 15:27:53 -080062import java.util.Objects;
alshabib2a441c62015-04-13 18:39:38 -070063import java.util.Set;
Jonathan Hart17d00452015-04-21 17:10:00 -070064import java.util.concurrent.ExecutorService;
alshabib77b88482015-04-07 15:47:50 -070065
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -070066import static com.google.common.base.Preconditions.checkNotNull;
Yi Tseng374c5f32017-03-05 22:51:35 -080067import static com.google.common.base.Strings.isNullOrEmpty;
Thomas Vachuska866b46a2015-04-30 00:26:55 -070068import static java.util.concurrent.Executors.newFixedThreadPool;
Jonathan Hart17d00452015-04-21 17:10:00 -070069import static org.onlab.util.Tools.groupedThreads;
Changhoon Yoon541ef712015-05-23 17:18:34 +090070import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuskad27097c2016-06-14 19:10:41 -070071import static org.onosproject.security.AppPermission.Type.FLOWRULE_WRITE;
alshabib77b88482015-04-07 15:47:50 -070072
73/**
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070074 * Provides implementation of the flow objective programming service.
alshabib77b88482015-04-07 15:47:50 -070075 */
alshabib2a441c62015-04-13 18:39:38 -070076@Component(immediate = true)
alshabib77b88482015-04-07 15:47:50 -070077@Service
78public class FlowObjectiveManager implements FlowObjectiveService {
79
Saurav Dasbd7f7422015-04-23 16:31:47 -070080 public static final int INSTALL_RETRY_ATTEMPTS = 5;
Jonathan Hart17d00452015-04-21 17:10:00 -070081 public static final long INSTALL_RETRY_INTERVAL = 1000; // ms
alshabib77b88482015-04-07 15:47:50 -070082
Yi Tseng374c5f32017-03-05 22:51:35 -080083 private static final String WORKER_PATTERN = "objective-installer-%d";
84 private static final String GROUP_THREAD_NAME = "onos/objective-installer";
85 private static final String NUM_THREAD = "numThreads";
86
Jonathan Hart17d00452015-04-21 17:10:00 -070087 private final Logger log = LoggerFactory.getLogger(getClass());
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070088
Yi Tseng9753fc12017-03-10 18:42:46 -080089 private static final int DEFAULT_NUM_THREADS = 4;
Yi Tseng374c5f32017-03-05 22:51:35 -080090 @Property(name = NUM_THREAD,
91 intValue = DEFAULT_NUM_THREADS,
92 label = "Number of worker threads")
93 private int numThreads = DEFAULT_NUM_THREADS;
94
alshabib77b88482015-04-07 15:47:50 -070095 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected DriverService driverService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected DeviceService deviceService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib77b88482015-04-07 15:47:50 -0700102 protected ClusterService clusterService;
103
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700104 // Note: The following dependencies are added on behalf of the pipeline
105 // driver behaviours to assure these services are available for their
106 // initialization.
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected FlowRuleService flowRuleService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected GroupService groupService;
112
alshabib2a441c62015-04-13 18:39:38 -0700113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected FlowObjectiveStore flowObjectiveStore;
115
Yi Tseng374c5f32017-03-05 22:51:35 -0800116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected ComponentConfigService cfgService;
118
alshabib2a441c62015-04-13 18:39:38 -0700119 private final FlowObjectiveStoreDelegate delegate = new InternalStoreDelegate();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700120
121 private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap();
alshabib910aff12015-04-09 16:55:57 -0700122 private final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700123
124 private final PipelinerContext context = new InnerPipelineContext();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700125 private final DeviceListener deviceListener = new InnerDeviceListener();
126
alshabib77b88482015-04-07 15:47:50 -0700127 protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
alshabib910aff12015-04-09 16:55:57 -0700128
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700129 private final Map<Integer, Set<PendingNext>> pendingForwards = Maps.newConcurrentMap();
alshabib2a441c62015-04-13 18:39:38 -0700130
Saurav Das24431192016-03-07 19:13:00 -0800131 // local store to track which nextObjectives were sent to which device
132 // for debugging purposes
133 private Map<Integer, DeviceId> nextToDevice = Maps.newConcurrentMap();
134
Jonathan Hart17d00452015-04-21 17:10:00 -0700135 private ExecutorService executorService;
alshabib2a441c62015-04-13 18:39:38 -0700136
alshabib77b88482015-04-07 15:47:50 -0700137 @Activate
138 protected void activate() {
Yi Tseng374c5f32017-03-05 22:51:35 -0800139 cfgService.registerProperties(getClass());
140 executorService = newFixedThreadPool(numThreads,
141 groupedThreads(GROUP_THREAD_NAME, WORKER_PATTERN, log));
alshabib2a441c62015-04-13 18:39:38 -0700142 flowObjectiveStore.setDelegate(delegate);
alshabibaebe7752015-04-07 17:45:42 -0700143 deviceService.addListener(deviceListener);
alshabib77b88482015-04-07 15:47:50 -0700144 log.info("Started");
145 }
146
147 @Deactivate
148 protected void deactivate() {
Yi Tseng374c5f32017-03-05 22:51:35 -0800149 cfgService.unregisterProperties(getClass(), false);
alshabib2a441c62015-04-13 18:39:38 -0700150 flowObjectiveStore.unsetDelegate(delegate);
alshabibaebe7752015-04-07 17:45:42 -0700151 deviceService.removeListener(deviceListener);
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700152 executorService.shutdown();
153 pipeliners.clear();
154 driverHandlers.clear();
Saurav Das24431192016-03-07 19:13:00 -0800155 nextToDevice.clear();
alshabib77b88482015-04-07 15:47:50 -0700156 log.info("Stopped");
157 }
158
Yi Tseng374c5f32017-03-05 22:51:35 -0800159 @Modified
160 protected void modified(ComponentContext context) {
161 String propertyValue =
162 Tools.get(context.getProperties(), NUM_THREAD);
163 int newNumThreads = isNullOrEmpty(propertyValue) ? numThreads : Integer.parseInt(propertyValue);
164
165 if (newNumThreads != numThreads && newNumThreads > 0) {
166 numThreads = newNumThreads;
167 ExecutorService oldWorkerExecutor = executorService;
168 executorService = newFixedThreadPool(numThreads,
169 groupedThreads(GROUP_THREAD_NAME, WORKER_PATTERN, log));
170 if (oldWorkerExecutor != null) {
171 oldWorkerExecutor.shutdown();
172 }
173 log.info("Reconfigured number of worker threads to {}", numThreads);
174 }
175 }
176
Jonathan Hart17d00452015-04-21 17:10:00 -0700177 /**
178 * Task that passes the flow objective down to the driver. The task will
179 * make a few attempts to find the appropriate driver, then eventually give
180 * up and report an error if no suitable driver could be found.
181 */
182 private class ObjectiveInstaller implements Runnable {
183 private final DeviceId deviceId;
184 private final Objective objective;
185
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700186 private final int numAttempts;
Jonathan Hart17d00452015-04-21 17:10:00 -0700187
188 public ObjectiveInstaller(DeviceId deviceId, Objective objective) {
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700189 this(deviceId, objective, 1);
190 }
191
192 public ObjectiveInstaller(DeviceId deviceId, Objective objective, int attemps) {
193 this.deviceId = checkNotNull(deviceId);
194 this.objective = checkNotNull(objective);
195 this.numAttempts = checkNotNull(attemps);
alshabib910aff12015-04-09 16:55:57 -0700196 }
alshabib77b88482015-04-07 15:47:50 -0700197
Jonathan Hart17d00452015-04-21 17:10:00 -0700198 @Override
199 public void run() {
200 try {
Jonathan Hart17d00452015-04-21 17:10:00 -0700201 Pipeliner pipeliner = getDevicePipeliner(deviceId);
202
203 if (pipeliner != null) {
204 if (objective instanceof NextObjective) {
205 pipeliner.next((NextObjective) objective);
206 } else if (objective instanceof ForwardingObjective) {
207 pipeliner.forward((ForwardingObjective) objective);
208 } else {
209 pipeliner.filter((FilteringObjective) objective);
210 }
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800211 //Attempts to check if pipeliner is null for retry attempts
Jonathan Hart17d00452015-04-21 17:10:00 -0700212 } else if (numAttempts < INSTALL_RETRY_ATTEMPTS) {
Saurav Das3d038262015-04-23 12:36:58 -0700213 Thread.sleep(INSTALL_RETRY_INTERVAL);
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700214 executorService.execute(new ObjectiveInstaller(deviceId, objective, numAttempts + 1));
Jonathan Hart17d00452015-04-21 17:10:00 -0700215 } else {
216 // Otherwise we've tried a few times and failed, report an
217 // error back to the user.
218 objective.context().ifPresent(
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800219 c -> c.onError(objective, ObjectiveError.NOPIPELINER));
Jonathan Hart17d00452015-04-21 17:10:00 -0700220 }
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800221 //Excpetion thrown
Jonathan Hart17d00452015-04-21 17:10:00 -0700222 } catch (Exception e) {
223 log.warn("Exception while installing flow objective", e);
224 }
225 }
226 }
227
228 @Override
229 public void filter(DeviceId deviceId, FilteringObjective filteringObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900230 checkPermission(FLOWRULE_WRITE);
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700231 executorService.execute(new ObjectiveInstaller(deviceId, filteringObjective));
alshabib77b88482015-04-07 15:47:50 -0700232 }
233
234 @Override
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700235 public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900236 checkPermission(FLOWRULE_WRITE);
alshabib2a441c62015-04-13 18:39:38 -0700237 if (queueObjective(deviceId, forwardingObjective)) {
238 return;
alshabib910aff12015-04-09 16:55:57 -0700239 }
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700240 executorService.execute(new ObjectiveInstaller(deviceId, forwardingObjective));
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700241 }
242
alshabib2a441c62015-04-13 18:39:38 -0700243 @Override
Jonathan Hart17d00452015-04-21 17:10:00 -0700244 public void next(DeviceId deviceId, NextObjective nextObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900245 checkPermission(FLOWRULE_WRITE);
Saurav Das24431192016-03-07 19:13:00 -0800246 nextToDevice.put(nextObjective.id(), deviceId);
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700247 executorService.execute(new ObjectiveInstaller(deviceId, nextObjective));
alshabib2a441c62015-04-13 18:39:38 -0700248 }
249
alshabibf6ea9e62015-04-21 17:08:26 -0700250 @Override
251 public int allocateNextId() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900252 checkPermission(FLOWRULE_WRITE);
alshabibf6ea9e62015-04-21 17:08:26 -0700253 return flowObjectiveStore.allocateNextId();
254 }
255
Xin Jin313708b2015-07-09 13:43:04 -0700256 @Override
257 public void initPolicy(String policy) {}
258
alshabib2a441c62015-04-13 18:39:38 -0700259 private boolean queueObjective(DeviceId deviceId, ForwardingObjective fwd) {
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700260 if (fwd.nextId() == null ||
Yi Tseng38fc71e2017-02-03 14:50:47 -0800261 flowObjectiveStore.getNextGroup(fwd.nextId()) != null ||
262 fwd.op() == Objective.Operation.REMOVE) {
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700263 // fast path
264 return false;
alshabib2a441c62015-04-13 18:39:38 -0700265 }
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700266 boolean queued = false;
267 synchronized (pendingForwards) {
268 // double check the flow objective store, because this block could run
269 // after a notification arrives
270 if (flowObjectiveStore.getNextGroup(fwd.nextId()) == null) {
271 pendingForwards.compute(fwd.nextId(), (id, pending) -> {
272 PendingNext next = new PendingNext(deviceId, fwd);
273 if (pending == null) {
274 return Sets.newHashSet(next);
275 } else {
276 pending.add(next);
277 return pending;
278 }
279 });
280 queued = true;
281 }
282 }
283 if (queued) {
284 log.debug("Queued forwarding objective {} for nextId {} meant for device {}",
285 fwd.id(), fwd.nextId(), deviceId);
286 }
287 return queued;
alshabib2a441c62015-04-13 18:39:38 -0700288 }
289
Pier Ventre57a61cd2016-09-07 10:55:41 -0700290 /**
291 * Retrieves (if it exists) the device pipeline behaviour from the cache.
292 * Otherwise it warms the caches and triggers the init method of the Pipeline.
293 *
294 * @param deviceId the id of the device associated to the pipeline
295 * @return the implementation of the Pipeliner behaviour
296 */
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700297 private Pipeliner getDevicePipeliner(DeviceId deviceId) {
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700298 return pipeliners.computeIfAbsent(deviceId, this::initPipelineHandler);
alshabib77b88482015-04-07 15:47:50 -0700299 }
300
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700301 /**
Pier Ventre57a61cd2016-09-07 10:55:41 -0700302 * Retrieves (if it exists) the device pipeline behaviour from the cache and
303 * and triggers the init method of the pipeline. Otherwise (DEVICE_ADDED) it warms
304 * the caches and triggers the init method of the Pipeline. The rationale of this
305 * method is for managing the scenario of a switch that goes down for a failure
306 * and goes up after a while.
307 *
308 * @param deviceId the id of the device associated to the pipeline
309 * @return the implementation of the Pipeliner behaviour
310 */
311 private Pipeliner getAndInitDevicePipeliner(DeviceId deviceId) {
312 return pipeliners.compute(deviceId, (deviceIdValue, pipelinerValue) -> {
313 if (pipelinerValue != null) {
314 pipelinerValue.init(deviceId, context);
315 return pipelinerValue;
316 }
317 return this.initPipelineHandler(deviceId);
318 });
319 }
320
321 /**
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700322 * Creates and initialize {@link Pipeliner}.
323 * <p>
324 * Note: Expected to be called under per-Device lock.
325 * e.g., {@code pipeliners}' Map#compute family methods
326 *
327 * @param deviceId Device to initialize pipeliner
328 * @return {@link Pipeliner} instance or null
329 */
330 private Pipeliner initPipelineHandler(DeviceId deviceId) {
331 start = now();
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700332
Jonathan Hart17d00452015-04-21 17:10:00 -0700333 // Attempt to lookup the handler in the cache
334 DriverHandler handler = driverHandlers.get(deviceId);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700335 cTime = now();
336
Jonathan Hart17d00452015-04-21 17:10:00 -0700337 if (handler == null) {
338 try {
339 // Otherwise create it and if it has pipeline behaviour, cache it
340 handler = driverService.createHandler(deviceId);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700341 dTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700342 if (!handler.driver().hasBehaviour(Pipeliner.class)) {
Yuta HIGUCHIa2a4f342017-03-17 11:38:57 -0700343 log.debug("Pipeline behaviour not supported for device {}",
Jonathan Hart17d00452015-04-21 17:10:00 -0700344 deviceId);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700345 return null;
alshabib2a441c62015-04-13 18:39:38 -0700346 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700347 } catch (ItemNotFoundException e) {
348 log.warn("No applicable driver for device {}", deviceId);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700349 return null;
alshabib2a441c62015-04-13 18:39:38 -0700350 }
351
Jonathan Hart17d00452015-04-21 17:10:00 -0700352 driverHandlers.put(deviceId, handler);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700353 eTime = now();
alshabib2a441c62015-04-13 18:39:38 -0700354 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700355
356 // Always (re)initialize the pipeline behaviour
357 log.info("Driver {} bound to device {} ... initializing driver",
358 handler.driver().name(), deviceId);
Thomas Vachuska0121a612015-07-21 11:18:09 -0700359 hTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700360 Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
Thomas Vachuska94c3cf42015-07-20 13:01:12 -0700361 hbTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700362 pipeliner.init(deviceId, context);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700363 stopWatch();
364 return pipeliner;
alshabibaebe7752015-04-07 17:45:42 -0700365 }
alshabib77b88482015-04-07 15:47:50 -0700366
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700367 // Triggers driver setup when a device is (re)detected.
alshabibaebe7752015-04-07 17:45:42 -0700368 private class InnerDeviceListener implements DeviceListener {
369 @Override
370 public void event(DeviceEvent event) {
371 switch (event.type()) {
372 case DEVICE_ADDED:
373 case DEVICE_AVAILABILITY_CHANGED:
Madan Jampani0174f452015-05-29 11:52:05 -0700374 log.debug("Device either added or availability changed {}",
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700375 event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700376 if (deviceService.isAvailable(event.subject().id())) {
Madan Jampani0174f452015-05-29 11:52:05 -0700377 log.debug("Device is now available {}", event.subject().id());
Pier Ventre57a61cd2016-09-07 10:55:41 -0700378 getAndInitDevicePipeliner(event.subject().id());
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700379 } else {
380 log.debug("Device is no longer available {}", event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700381 }
382 break;
383 case DEVICE_UPDATED:
384 break;
385 case DEVICE_REMOVED:
Yuta HIGUCHIad0c9902016-08-23 10:37:32 -0700386 // evict Pipeliner and Handler cache, when
387 // the Device was administratively removed.
388 //
389 // System expect the user to clear all existing flows,
390 // before removing device, especially if they intend to
391 // replace driver/pipeliner assigned to the device.
392 driverHandlers.remove(event.subject().id());
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700393 pipeliners.remove(event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700394 break;
Yuta HIGUCHIad0c9902016-08-23 10:37:32 -0700395 case DEVICE_SUSPENDED:
396 break;
alshabib4313d102015-04-08 18:55:08 -0700397 case PORT_ADDED:
398 break;
399 case PORT_UPDATED:
400 break;
401 case PORT_REMOVED:
alshabibaebe7752015-04-07 17:45:42 -0700402 break;
403 default:
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700404 break;
alshabibaebe7752015-04-07 17:45:42 -0700405 }
alshabib77b88482015-04-07 15:47:50 -0700406 }
407 }
alshabibaebe7752015-04-07 17:45:42 -0700408
Thomas Vachuska174bb912015-07-16 21:27:14 -0700409 // Temporary mechanism to monitor pipeliner setup time-cost; there are
410 // intermittent time where this takes in excess of 2 seconds. Why?
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700411 private long start = 0, totals = 0, count = 0;
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700412 private long cTime, dTime, eTime, hTime, hbTime;
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700413 private static final long LIMIT = 500;
Thomas Vachuska174bb912015-07-16 21:27:14 -0700414
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700415 private long now() {
Thomas Vachuska174bb912015-07-16 21:27:14 -0700416 return System.currentTimeMillis();
417 }
418
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700419 private void stopWatch() {
Thomas Vachuska174bb912015-07-16 21:27:14 -0700420 long duration = System.currentTimeMillis() - start;
421 totals += duration;
422 count += 1;
423 if (duration > LIMIT) {
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700424 log.info("Pipeline setup took {} ms; avg {} ms; cTime={}, dTime={}, eTime={}, hTime={}, hbTime={}",
425 duration, totals / count, diff(cTime), diff(dTime), diff(eTime), diff(hTime), diff(hbTime));
Thomas Vachuska174bb912015-07-16 21:27:14 -0700426 }
427 }
428
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700429 private long diff(long bTime) {
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700430 long diff = bTime - start;
431 return diff < 0 ? 0 : diff;
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700432 }
433
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700434 // Processing context for initializing pipeline driver behaviours.
435 private class InnerPipelineContext implements PipelinerContext {
436 @Override
437 public ServiceDirectory directory() {
438 return serviceDirectory;
alshabibaebe7752015-04-07 17:45:42 -0700439 }
alshabib2a441c62015-04-13 18:39:38 -0700440
441 @Override
442 public FlowObjectiveStore store() {
443 return flowObjectiveStore;
444 }
alshabib2a441c62015-04-13 18:39:38 -0700445 }
446
447 private class InternalStoreDelegate implements FlowObjectiveStoreDelegate {
448 @Override
449 public void notify(ObjectiveEvent event) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800450 if (event.type() == Type.ADD) {
451 log.debug("Received notification of obj event {}", event);
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700452 Set<PendingNext> pending;
453 synchronized (pendingForwards) {
454 // needs to be synchronized for queueObjective lookup
455 pending = pendingForwards.remove(event.subject());
456 }
alshabib2a441c62015-04-13 18:39:38 -0700457
Saurav Das423fe2b2015-12-04 10:52:59 -0800458 if (pending == null) {
Saurav Das25190812016-05-27 13:54:07 -0700459 log.debug("Nothing pending for this obj event {}", event);
Saurav Das423fe2b2015-12-04 10:52:59 -0800460 return;
461 }
462
Saurav Das49cb5a12016-01-16 22:54:07 -0800463 log.debug("Processing {} pending forwarding objectives for nextId {}",
464 pending.size(), event.subject());
Saurav Das423fe2b2015-12-04 10:52:59 -0800465 pending.forEach(p -> getDevicePipeliner(p.deviceId())
466 .forward(p.forwardingObjective()));
alshabib2a441c62015-04-13 18:39:38 -0700467 }
alshabib2a441c62015-04-13 18:39:38 -0700468 }
469 }
470
471 /**
472 * Data class used to hold a pending forwarding objective that could not
473 * be processed because the associated next object was not present.
474 */
475 private class PendingNext {
476 private final DeviceId deviceId;
477 private final ForwardingObjective fwd;
478
479 public PendingNext(DeviceId deviceId, ForwardingObjective fwd) {
480 this.deviceId = deviceId;
481 this.fwd = fwd;
482 }
483
484 public DeviceId deviceId() {
485 return deviceId;
486 }
487
488 public ForwardingObjective forwardingObjective() {
489 return fwd;
490 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800491
492 @Override
493 public int hashCode() {
494 return Objects.hash(deviceId, fwd);
495 }
496
497 @Override
498 public boolean equals(final Object obj) {
499 if (this == obj) {
500 return true;
501 }
502 if (!(obj instanceof PendingNext)) {
503 return false;
504 }
505 final PendingNext other = (PendingNext) obj;
506 if (this.deviceId.equals(other.deviceId) &&
507 this.fwd.equals(other.fwd)) {
508 return true;
509 }
510 return false;
511 }
alshabibaebe7752015-04-07 17:45:42 -0700512 }
Saurav Das24431192016-03-07 19:13:00 -0800513
514 @Override
515 public List<String> getNextMappings() {
516 List<String> mappings = new ArrayList<>();
517 Map<Integer, NextGroup> allnexts = flowObjectiveStore.getAllGroups();
Saurav Das25190812016-05-27 13:54:07 -0700518 // XXX if the NextGroup after de-serialization actually stored info of the deviceId
Saurav Das24431192016-03-07 19:13:00 -0800519 // then info on any nextObj could be retrieved from one controller instance.
520 // Right now the drivers on one instance can only fetch for next-ids that came
521 // to them.
522 // Also, we still need to send the right next-id to the right driver as potentially
523 // there can be different drivers for different devices. But on that account,
524 // no instance should be decoding for another instance's nextIds.
525
526 for (Map.Entry<Integer, NextGroup> e : allnexts.entrySet()) {
527 // get the device this next Objective was sent to
528 DeviceId deviceId = nextToDevice.get(e.getKey());
529 mappings.add("NextId " + e.getKey() + ": " +
530 ((deviceId != null) ? deviceId : "nextId not in this onos instance"));
531 if (deviceId != null) {
532 // this instance of the controller sent the nextObj to a driver
533 Pipeliner pipeliner = getDevicePipeliner(deviceId);
534 List<String> nextMappings = pipeliner.getNextMappings(e.getValue());
535 if (nextMappings != null) {
536 mappings.addAll(nextMappings);
537 }
538 }
539 }
540 return mappings;
541 }
Saurav Dasb5c236e2016-06-07 10:08:06 -0700542
543 @Override
544 public List<String> getPendingNexts() {
545 List<String> pendingNexts = new ArrayList<>();
546 for (Integer nextId : pendingForwards.keySet()) {
547 Set<PendingNext> pnext = pendingForwards.get(nextId);
Charles Chan54734712017-03-29 11:07:55 -0700548
Sho SHIMIZU81470a52016-08-12 17:24:55 -0700549 StringBuilder pend = new StringBuilder();
Charles Chan54734712017-03-29 11:07:55 -0700550 pend.append("NextId: ")
551 .append(nextId);
Saurav Dasb5c236e2016-06-07 10:08:06 -0700552 for (PendingNext pn : pnext) {
Charles Chan54734712017-03-29 11:07:55 -0700553 pend.append("\n FwdId: ")
554 .append(String.format("%11s", pn.forwardingObjective().id()))
555 .append(", DeviceId: ")
556 .append(pn.deviceId())
557 .append(", Selector: ")
558 .append(pn.forwardingObjective().selector().criteria());
Saurav Dasb5c236e2016-06-07 10:08:06 -0700559 }
560 pendingNexts.add(pend.toString());
561 }
562 return pendingNexts;
563 }
alshabib77b88482015-04-07 15:47:50 -0700564}