blob: 8ce67cddf7cf63b25700bd3cbabb3eea06a193f7 [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;
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;
alshabib77b88482015-04-07 15:47:50 -070030import org.onosproject.net.DeviceId;
Saurav Das24431192016-03-07 19:13:00 -080031import org.onosproject.net.behaviour.NextGroup;
alshabib77b88482015-04-07 15:47:50 -070032import org.onosproject.net.behaviour.Pipeliner;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070033import org.onosproject.net.behaviour.PipelinerContext;
alshabibaebe7752015-04-07 17:45:42 -070034import org.onosproject.net.device.DeviceEvent;
35import org.onosproject.net.device.DeviceListener;
alshabib77b88482015-04-07 15:47:50 -070036import org.onosproject.net.device.DeviceService;
Thomas Vachuska866b46a2015-04-30 00:26:55 -070037import org.onosproject.net.driver.DefaultDriverProviderService;
alshabib77b88482015-04-07 15:47:50 -070038import org.onosproject.net.driver.DriverHandler;
39import org.onosproject.net.driver.DriverService;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070040import org.onosproject.net.flow.FlowRuleService;
alshabib77b88482015-04-07 15:47:50 -070041import org.onosproject.net.flowobjective.FilteringObjective;
42import org.onosproject.net.flowobjective.FlowObjectiveService;
alshabib2a441c62015-04-13 18:39:38 -070043import org.onosproject.net.flowobjective.FlowObjectiveStore;
44import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate;
alshabib77b88482015-04-07 15:47:50 -070045import org.onosproject.net.flowobjective.ForwardingObjective;
46import org.onosproject.net.flowobjective.NextObjective;
alshabib910aff12015-04-09 16:55:57 -070047import org.onosproject.net.flowobjective.Objective;
Jonathan Hart17d00452015-04-21 17:10:00 -070048import org.onosproject.net.flowobjective.ObjectiveError;
alshabib2a441c62015-04-13 18:39:38 -070049import org.onosproject.net.flowobjective.ObjectiveEvent;
Saurav Das423fe2b2015-12-04 10:52:59 -080050import org.onosproject.net.flowobjective.ObjectiveEvent.Type;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070051import org.onosproject.net.group.GroupService;
alshabib77b88482015-04-07 15:47:50 -070052import org.slf4j.Logger;
53import org.slf4j.LoggerFactory;
54
Saurav Das24431192016-03-07 19:13:00 -080055import java.util.ArrayList;
Saurav Das24431192016-03-07 19:13:00 -080056import java.util.List;
alshabib77b88482015-04-07 15:47:50 -070057import java.util.Map;
Saurav Das8a0732e2015-11-20 15:27:53 -080058import java.util.Objects;
alshabib2a441c62015-04-13 18:39:38 -070059import java.util.Set;
Jonathan Hart17d00452015-04-21 17:10:00 -070060import java.util.concurrent.ExecutorService;
alshabib77b88482015-04-07 15:47:50 -070061
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -070062import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuska866b46a2015-04-30 00:26:55 -070063import static java.util.concurrent.Executors.newFixedThreadPool;
Jonathan Hart17d00452015-04-21 17:10:00 -070064import static org.onlab.util.Tools.groupedThreads;
Changhoon Yoon541ef712015-05-23 17:18:34 +090065import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuskad27097c2016-06-14 19:10:41 -070066import static org.onosproject.security.AppPermission.Type.FLOWRULE_WRITE;
alshabib77b88482015-04-07 15:47:50 -070067
68/**
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070069 * Provides implementation of the flow objective programming service.
alshabib77b88482015-04-07 15:47:50 -070070 */
alshabib2a441c62015-04-13 18:39:38 -070071@Component(immediate = true)
alshabib77b88482015-04-07 15:47:50 -070072@Service
73public class FlowObjectiveManager implements FlowObjectiveService {
74
Saurav Dasbd7f7422015-04-23 16:31:47 -070075 public static final int INSTALL_RETRY_ATTEMPTS = 5;
Jonathan Hart17d00452015-04-21 17:10:00 -070076 public static final long INSTALL_RETRY_INTERVAL = 1000; // ms
alshabib77b88482015-04-07 15:47:50 -070077
Jonathan Hart17d00452015-04-21 17:10:00 -070078 private final Logger log = LoggerFactory.getLogger(getClass());
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070079
alshabib77b88482015-04-07 15:47:50 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected DriverService driverService;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected DeviceService deviceService;
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib77b88482015-04-07 15:47:50 -070087 protected ClusterService clusterService;
88
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070089 // Note: The following dependencies are added on behalf of the pipeline
90 // driver behaviours to assure these services are available for their
91 // initialization.
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected FlowRuleService flowRuleService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected GroupService groupService;
97
alshabib2a441c62015-04-13 18:39:38 -070098 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected FlowObjectiveStore flowObjectiveStore;
100
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700101 // Note: This must remain an optional dependency to allow re-install of default drivers.
102 // Note: For now disabled until we can move to OPTIONAL_UNARY dependency
103 // @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC)
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected DefaultDriverProviderService defaultDriverService;
106
alshabib2a441c62015-04-13 18:39:38 -0700107 private final FlowObjectiveStoreDelegate delegate = new InternalStoreDelegate();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700108
109 private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap();
alshabib910aff12015-04-09 16:55:57 -0700110 private final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700111
112 private final PipelinerContext context = new InnerPipelineContext();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700113 private final DeviceListener deviceListener = new InnerDeviceListener();
114
alshabib77b88482015-04-07 15:47:50 -0700115 protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
alshabib910aff12015-04-09 16:55:57 -0700116
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700117 private final Map<Integer, Set<PendingNext>> pendingForwards = Maps.newConcurrentMap();
alshabib2a441c62015-04-13 18:39:38 -0700118
Saurav Das24431192016-03-07 19:13:00 -0800119 // local store to track which nextObjectives were sent to which device
120 // for debugging purposes
121 private Map<Integer, DeviceId> nextToDevice = Maps.newConcurrentMap();
122
Jonathan Hart17d00452015-04-21 17:10:00 -0700123 private ExecutorService executorService;
alshabib2a441c62015-04-13 18:39:38 -0700124
alshabib77b88482015-04-07 15:47:50 -0700125 @Activate
126 protected void activate() {
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700127 executorService = newFixedThreadPool(4, groupedThreads("onos/objective-installer", "%d", log));
alshabib2a441c62015-04-13 18:39:38 -0700128 flowObjectiveStore.setDelegate(delegate);
alshabibaebe7752015-04-07 17:45:42 -0700129 deviceService.addListener(deviceListener);
alshabib77b88482015-04-07 15:47:50 -0700130 log.info("Started");
131 }
132
133 @Deactivate
134 protected void deactivate() {
alshabib2a441c62015-04-13 18:39:38 -0700135 flowObjectiveStore.unsetDelegate(delegate);
alshabibaebe7752015-04-07 17:45:42 -0700136 deviceService.removeListener(deviceListener);
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700137 executorService.shutdown();
138 pipeliners.clear();
139 driverHandlers.clear();
Saurav Das24431192016-03-07 19:13:00 -0800140 nextToDevice.clear();
alshabib77b88482015-04-07 15:47:50 -0700141 log.info("Stopped");
142 }
143
Jonathan Hart17d00452015-04-21 17:10:00 -0700144 /**
145 * Task that passes the flow objective down to the driver. The task will
146 * make a few attempts to find the appropriate driver, then eventually give
147 * up and report an error if no suitable driver could be found.
148 */
149 private class ObjectiveInstaller implements Runnable {
150 private final DeviceId deviceId;
151 private final Objective objective;
152
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700153 private final int numAttempts;
Jonathan Hart17d00452015-04-21 17:10:00 -0700154
155 public ObjectiveInstaller(DeviceId deviceId, Objective objective) {
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700156 this(deviceId, objective, 1);
157 }
158
159 public ObjectiveInstaller(DeviceId deviceId, Objective objective, int attemps) {
160 this.deviceId = checkNotNull(deviceId);
161 this.objective = checkNotNull(objective);
162 this.numAttempts = checkNotNull(attemps);
alshabib910aff12015-04-09 16:55:57 -0700163 }
alshabib77b88482015-04-07 15:47:50 -0700164
Jonathan Hart17d00452015-04-21 17:10:00 -0700165 @Override
166 public void run() {
167 try {
Jonathan Hart17d00452015-04-21 17:10:00 -0700168 Pipeliner pipeliner = getDevicePipeliner(deviceId);
169
170 if (pipeliner != null) {
171 if (objective instanceof NextObjective) {
172 pipeliner.next((NextObjective) objective);
173 } else if (objective instanceof ForwardingObjective) {
174 pipeliner.forward((ForwardingObjective) objective);
175 } else {
176 pipeliner.filter((FilteringObjective) objective);
177 }
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800178 //Attempts to check if pipeliner is null for retry attempts
Jonathan Hart17d00452015-04-21 17:10:00 -0700179 } else if (numAttempts < INSTALL_RETRY_ATTEMPTS) {
Saurav Das3d038262015-04-23 12:36:58 -0700180 Thread.sleep(INSTALL_RETRY_INTERVAL);
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700181 executorService.execute(new ObjectiveInstaller(deviceId, objective, numAttempts + 1));
Jonathan Hart17d00452015-04-21 17:10:00 -0700182 } else {
183 // Otherwise we've tried a few times and failed, report an
184 // error back to the user.
185 objective.context().ifPresent(
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800186 c -> c.onError(objective, ObjectiveError.NOPIPELINER));
Jonathan Hart17d00452015-04-21 17:10:00 -0700187 }
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800188 //Excpetion thrown
Jonathan Hart17d00452015-04-21 17:10:00 -0700189 } catch (Exception e) {
190 log.warn("Exception while installing flow objective", e);
191 }
192 }
193 }
194
195 @Override
196 public void filter(DeviceId deviceId, FilteringObjective filteringObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900197 checkPermission(FLOWRULE_WRITE);
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700198 executorService.execute(new ObjectiveInstaller(deviceId, filteringObjective));
alshabib77b88482015-04-07 15:47:50 -0700199 }
200
201 @Override
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700202 public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900203 checkPermission(FLOWRULE_WRITE);
alshabib2a441c62015-04-13 18:39:38 -0700204 if (queueObjective(deviceId, forwardingObjective)) {
205 return;
alshabib910aff12015-04-09 16:55:57 -0700206 }
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700207 executorService.execute(new ObjectiveInstaller(deviceId, forwardingObjective));
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700208 }
209
alshabib2a441c62015-04-13 18:39:38 -0700210 @Override
Jonathan Hart17d00452015-04-21 17:10:00 -0700211 public void next(DeviceId deviceId, NextObjective nextObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900212 checkPermission(FLOWRULE_WRITE);
Saurav Das24431192016-03-07 19:13:00 -0800213 nextToDevice.put(nextObjective.id(), deviceId);
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700214 executorService.execute(new ObjectiveInstaller(deviceId, nextObjective));
alshabib2a441c62015-04-13 18:39:38 -0700215 }
216
alshabibf6ea9e62015-04-21 17:08:26 -0700217 @Override
218 public int allocateNextId() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900219 checkPermission(FLOWRULE_WRITE);
alshabibf6ea9e62015-04-21 17:08:26 -0700220 return flowObjectiveStore.allocateNextId();
221 }
222
Xin Jin313708b2015-07-09 13:43:04 -0700223 @Override
224 public void initPolicy(String policy) {}
225
alshabib2a441c62015-04-13 18:39:38 -0700226 private boolean queueObjective(DeviceId deviceId, ForwardingObjective fwd) {
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700227 if (fwd.nextId() == null ||
228 flowObjectiveStore.getNextGroup(fwd.nextId()) != null) {
229 // fast path
230 return false;
alshabib2a441c62015-04-13 18:39:38 -0700231 }
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700232 boolean queued = false;
233 synchronized (pendingForwards) {
234 // double check the flow objective store, because this block could run
235 // after a notification arrives
236 if (flowObjectiveStore.getNextGroup(fwd.nextId()) == null) {
237 pendingForwards.compute(fwd.nextId(), (id, pending) -> {
238 PendingNext next = new PendingNext(deviceId, fwd);
239 if (pending == null) {
240 return Sets.newHashSet(next);
241 } else {
242 pending.add(next);
243 return pending;
244 }
245 });
246 queued = true;
247 }
248 }
249 if (queued) {
250 log.debug("Queued forwarding objective {} for nextId {} meant for device {}",
251 fwd.id(), fwd.nextId(), deviceId);
252 }
253 return queued;
alshabib2a441c62015-04-13 18:39:38 -0700254 }
255
Pier Ventre57a61cd2016-09-07 10:55:41 -0700256 /**
257 * Retrieves (if it exists) the device pipeline behaviour from the cache.
258 * Otherwise it warms the caches and triggers the init method of the Pipeline.
259 *
260 * @param deviceId the id of the device associated to the pipeline
261 * @return the implementation of the Pipeliner behaviour
262 */
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700263 private Pipeliner getDevicePipeliner(DeviceId deviceId) {
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700264 return pipeliners.computeIfAbsent(deviceId, this::initPipelineHandler);
alshabib77b88482015-04-07 15:47:50 -0700265 }
266
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700267 /**
Pier Ventre57a61cd2016-09-07 10:55:41 -0700268 * Retrieves (if it exists) the device pipeline behaviour from the cache and
269 * and triggers the init method of the pipeline. Otherwise (DEVICE_ADDED) it warms
270 * the caches and triggers the init method of the Pipeline. The rationale of this
271 * method is for managing the scenario of a switch that goes down for a failure
272 * and goes up after a while.
273 *
274 * @param deviceId the id of the device associated to the pipeline
275 * @return the implementation of the Pipeliner behaviour
276 */
277 private Pipeliner getAndInitDevicePipeliner(DeviceId deviceId) {
278 return pipeliners.compute(deviceId, (deviceIdValue, pipelinerValue) -> {
279 if (pipelinerValue != null) {
280 pipelinerValue.init(deviceId, context);
281 return pipelinerValue;
282 }
283 return this.initPipelineHandler(deviceId);
284 });
285 }
286
287 /**
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700288 * Creates and initialize {@link Pipeliner}.
289 * <p>
290 * Note: Expected to be called under per-Device lock.
291 * e.g., {@code pipeliners}' Map#compute family methods
292 *
293 * @param deviceId Device to initialize pipeliner
294 * @return {@link Pipeliner} instance or null
295 */
296 private Pipeliner initPipelineHandler(DeviceId deviceId) {
297 start = now();
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700298
Jonathan Hart17d00452015-04-21 17:10:00 -0700299 // Attempt to lookup the handler in the cache
300 DriverHandler handler = driverHandlers.get(deviceId);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700301 cTime = now();
302
Jonathan Hart17d00452015-04-21 17:10:00 -0700303 if (handler == null) {
304 try {
305 // Otherwise create it and if it has pipeline behaviour, cache it
306 handler = driverService.createHandler(deviceId);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700307 dTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700308 if (!handler.driver().hasBehaviour(Pipeliner.class)) {
309 log.warn("Pipeline behaviour not supported for device {}",
310 deviceId);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700311 return null;
alshabib2a441c62015-04-13 18:39:38 -0700312 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700313 } catch (ItemNotFoundException e) {
314 log.warn("No applicable driver for device {}", deviceId);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700315 return null;
alshabib2a441c62015-04-13 18:39:38 -0700316 }
317
Jonathan Hart17d00452015-04-21 17:10:00 -0700318 driverHandlers.put(deviceId, handler);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700319 eTime = now();
alshabib2a441c62015-04-13 18:39:38 -0700320 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700321
322 // Always (re)initialize the pipeline behaviour
323 log.info("Driver {} bound to device {} ... initializing driver",
324 handler.driver().name(), deviceId);
Thomas Vachuska0121a612015-07-21 11:18:09 -0700325 hTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700326 Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
Thomas Vachuska94c3cf42015-07-20 13:01:12 -0700327 hbTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700328 pipeliner.init(deviceId, context);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700329 stopWatch();
330 return pipeliner;
alshabibaebe7752015-04-07 17:45:42 -0700331 }
alshabib77b88482015-04-07 15:47:50 -0700332
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700333 // Triggers driver setup when a device is (re)detected.
alshabibaebe7752015-04-07 17:45:42 -0700334 private class InnerDeviceListener implements DeviceListener {
335 @Override
336 public void event(DeviceEvent event) {
337 switch (event.type()) {
338 case DEVICE_ADDED:
339 case DEVICE_AVAILABILITY_CHANGED:
Madan Jampani0174f452015-05-29 11:52:05 -0700340 log.debug("Device either added or availability changed {}",
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700341 event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700342 if (deviceService.isAvailable(event.subject().id())) {
Madan Jampani0174f452015-05-29 11:52:05 -0700343 log.debug("Device is now available {}", event.subject().id());
Pier Ventre57a61cd2016-09-07 10:55:41 -0700344 getAndInitDevicePipeliner(event.subject().id());
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700345 } else {
346 log.debug("Device is no longer available {}", event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700347 }
348 break;
349 case DEVICE_UPDATED:
350 break;
351 case DEVICE_REMOVED:
Yuta HIGUCHIad0c9902016-08-23 10:37:32 -0700352 // evict Pipeliner and Handler cache, when
353 // the Device was administratively removed.
354 //
355 // System expect the user to clear all existing flows,
356 // before removing device, especially if they intend to
357 // replace driver/pipeliner assigned to the device.
358 driverHandlers.remove(event.subject().id());
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700359 pipeliners.remove(event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700360 break;
Yuta HIGUCHIad0c9902016-08-23 10:37:32 -0700361 case DEVICE_SUSPENDED:
362 break;
alshabib4313d102015-04-08 18:55:08 -0700363 case PORT_ADDED:
364 break;
365 case PORT_UPDATED:
366 break;
367 case PORT_REMOVED:
alshabibaebe7752015-04-07 17:45:42 -0700368 break;
369 default:
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700370 break;
alshabibaebe7752015-04-07 17:45:42 -0700371 }
alshabib77b88482015-04-07 15:47:50 -0700372 }
373 }
alshabibaebe7752015-04-07 17:45:42 -0700374
Thomas Vachuska174bb912015-07-16 21:27:14 -0700375 // Temporary mechanism to monitor pipeliner setup time-cost; there are
376 // intermittent time where this takes in excess of 2 seconds. Why?
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700377 private long start = 0, totals = 0, count = 0;
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700378 private long cTime, dTime, eTime, hTime, hbTime;
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700379 private static final long LIMIT = 500;
Thomas Vachuska174bb912015-07-16 21:27:14 -0700380
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700381 private long now() {
Thomas Vachuska174bb912015-07-16 21:27:14 -0700382 return System.currentTimeMillis();
383 }
384
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700385 private void stopWatch() {
Thomas Vachuska174bb912015-07-16 21:27:14 -0700386 long duration = System.currentTimeMillis() - start;
387 totals += duration;
388 count += 1;
389 if (duration > LIMIT) {
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700390 log.info("Pipeline setup took {} ms; avg {} ms; cTime={}, dTime={}, eTime={}, hTime={}, hbTime={}",
391 duration, totals / count, diff(cTime), diff(dTime), diff(eTime), diff(hTime), diff(hbTime));
Thomas Vachuska174bb912015-07-16 21:27:14 -0700392 }
393 }
394
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700395 private long diff(long bTime) {
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700396 long diff = bTime - start;
397 return diff < 0 ? 0 : diff;
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700398 }
399
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700400 // Processing context for initializing pipeline driver behaviours.
401 private class InnerPipelineContext implements PipelinerContext {
402 @Override
403 public ServiceDirectory directory() {
404 return serviceDirectory;
alshabibaebe7752015-04-07 17:45:42 -0700405 }
alshabib2a441c62015-04-13 18:39:38 -0700406
407 @Override
408 public FlowObjectiveStore store() {
409 return flowObjectiveStore;
410 }
alshabib2a441c62015-04-13 18:39:38 -0700411 }
412
413 private class InternalStoreDelegate implements FlowObjectiveStoreDelegate {
414 @Override
415 public void notify(ObjectiveEvent event) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800416 if (event.type() == Type.ADD) {
417 log.debug("Received notification of obj event {}", event);
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700418 Set<PendingNext> pending;
419 synchronized (pendingForwards) {
420 // needs to be synchronized for queueObjective lookup
421 pending = pendingForwards.remove(event.subject());
422 }
alshabib2a441c62015-04-13 18:39:38 -0700423
Saurav Das423fe2b2015-12-04 10:52:59 -0800424 if (pending == null) {
Saurav Das25190812016-05-27 13:54:07 -0700425 log.debug("Nothing pending for this obj event {}", event);
Saurav Das423fe2b2015-12-04 10:52:59 -0800426 return;
427 }
428
Saurav Das49cb5a12016-01-16 22:54:07 -0800429 log.debug("Processing {} pending forwarding objectives for nextId {}",
430 pending.size(), event.subject());
Saurav Das423fe2b2015-12-04 10:52:59 -0800431 pending.forEach(p -> getDevicePipeliner(p.deviceId())
432 .forward(p.forwardingObjective()));
alshabib2a441c62015-04-13 18:39:38 -0700433 }
alshabib2a441c62015-04-13 18:39:38 -0700434 }
435 }
436
437 /**
438 * Data class used to hold a pending forwarding objective that could not
439 * be processed because the associated next object was not present.
440 */
441 private class PendingNext {
442 private final DeviceId deviceId;
443 private final ForwardingObjective fwd;
444
445 public PendingNext(DeviceId deviceId, ForwardingObjective fwd) {
446 this.deviceId = deviceId;
447 this.fwd = fwd;
448 }
449
450 public DeviceId deviceId() {
451 return deviceId;
452 }
453
454 public ForwardingObjective forwardingObjective() {
455 return fwd;
456 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800457
458 @Override
459 public int hashCode() {
460 return Objects.hash(deviceId, fwd);
461 }
462
463 @Override
464 public boolean equals(final Object obj) {
465 if (this == obj) {
466 return true;
467 }
468 if (!(obj instanceof PendingNext)) {
469 return false;
470 }
471 final PendingNext other = (PendingNext) obj;
472 if (this.deviceId.equals(other.deviceId) &&
473 this.fwd.equals(other.fwd)) {
474 return true;
475 }
476 return false;
477 }
alshabibaebe7752015-04-07 17:45:42 -0700478 }
Saurav Das24431192016-03-07 19:13:00 -0800479
480 @Override
481 public List<String> getNextMappings() {
482 List<String> mappings = new ArrayList<>();
483 Map<Integer, NextGroup> allnexts = flowObjectiveStore.getAllGroups();
Saurav Das25190812016-05-27 13:54:07 -0700484 // XXX if the NextGroup after de-serialization actually stored info of the deviceId
Saurav Das24431192016-03-07 19:13:00 -0800485 // then info on any nextObj could be retrieved from one controller instance.
486 // Right now the drivers on one instance can only fetch for next-ids that came
487 // to them.
488 // Also, we still need to send the right next-id to the right driver as potentially
489 // there can be different drivers for different devices. But on that account,
490 // no instance should be decoding for another instance's nextIds.
491
492 for (Map.Entry<Integer, NextGroup> e : allnexts.entrySet()) {
493 // get the device this next Objective was sent to
494 DeviceId deviceId = nextToDevice.get(e.getKey());
495 mappings.add("NextId " + e.getKey() + ": " +
496 ((deviceId != null) ? deviceId : "nextId not in this onos instance"));
497 if (deviceId != null) {
498 // this instance of the controller sent the nextObj to a driver
499 Pipeliner pipeliner = getDevicePipeliner(deviceId);
500 List<String> nextMappings = pipeliner.getNextMappings(e.getValue());
501 if (nextMappings != null) {
502 mappings.addAll(nextMappings);
503 }
504 }
505 }
506 return mappings;
507 }
Saurav Dasb5c236e2016-06-07 10:08:06 -0700508
509 @Override
510 public List<String> getPendingNexts() {
511 List<String> pendingNexts = new ArrayList<>();
512 for (Integer nextId : pendingForwards.keySet()) {
513 Set<PendingNext> pnext = pendingForwards.get(nextId);
Sho SHIMIZU81470a52016-08-12 17:24:55 -0700514 StringBuilder pend = new StringBuilder();
Saurav Dasb5c236e2016-06-07 10:08:06 -0700515 pend.append("Next Id: ").append(Integer.toString(nextId))
516 .append(" :: ");
517 for (PendingNext pn : pnext) {
518 pend.append(Integer.toString(pn.forwardingObjective().id()))
519 .append(" ");
520 }
521 pendingNexts.add(pend.toString());
522 }
523 return pendingNexts;
524 }
alshabib77b88482015-04-07 15:47:50 -0700525}