blob: d0bd1c502d4c039597f75b46e6cf97862e9a526c [file] [log] [blame]
alshabib77b88482015-04-07 15:47:50 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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
Pier Luigi97893112018-03-05 11:09:42 +010018import com.google.common.collect.ImmutableSet;
Saurav Dasf14d9ef2017-12-05 15:00:23 -080019import com.google.common.collect.Lists;
alshabib77b88482015-04-07 15:47:50 -070020import com.google.common.collect.Maps;
Thomas Vachuskad27097c2016-06-14 19:10:41 -070021import com.google.common.collect.Sets;
alshabib77b88482015-04-07 15:47:50 -070022import org.onlab.osgi.DefaultServiceDirectory;
23import org.onlab.osgi.ServiceDirectory;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070024import org.onlab.util.ItemNotFoundException;
Yi Tseng374c5f32017-03-05 22:51:35 -080025import org.onlab.util.Tools;
26import org.onosproject.cfg.ComponentConfigService;
alshabib77b88482015-04-07 15:47:50 -070027import org.onosproject.cluster.ClusterService;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070028import org.onosproject.net.Device;
alshabib77b88482015-04-07 15:47:50 -070029import org.onosproject.net.DeviceId;
Saurav Das24431192016-03-07 19:13:00 -080030import org.onosproject.net.behaviour.NextGroup;
alshabib77b88482015-04-07 15:47:50 -070031import org.onosproject.net.behaviour.Pipeliner;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070032import org.onosproject.net.behaviour.PipelinerContext;
alshabibaebe7752015-04-07 17:45:42 -070033import org.onosproject.net.device.DeviceEvent;
34import org.onosproject.net.device.DeviceListener;
alshabib77b88482015-04-07 15:47:50 -070035import org.onosproject.net.device.DeviceService;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070036import org.onosproject.net.driver.DriverEvent;
alshabib77b88482015-04-07 15:47:50 -070037import org.onosproject.net.driver.DriverHandler;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070038import org.onosproject.net.driver.DriverListener;
alshabib77b88482015-04-07 15:47:50 -070039import 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;
Saurav Das1547b3f2017-05-05 17:01:08 -070048import org.onosproject.net.flowobjective.Objective.Operation;
Jonathan Hart17d00452015-04-21 17:10:00 -070049import org.onosproject.net.flowobjective.ObjectiveError;
alshabib2a441c62015-04-13 18:39:38 -070050import org.onosproject.net.flowobjective.ObjectiveEvent;
Saurav Das423fe2b2015-12-04 10:52:59 -080051import org.onosproject.net.flowobjective.ObjectiveEvent.Type;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070052import org.onosproject.net.group.GroupService;
Yi Tseng374c5f32017-03-05 22:51:35 -080053import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070054import org.osgi.service.component.annotations.Activate;
55import org.osgi.service.component.annotations.Component;
56import org.osgi.service.component.annotations.Deactivate;
57import org.osgi.service.component.annotations.Modified;
58import org.osgi.service.component.annotations.Reference;
59import org.osgi.service.component.annotations.ReferenceCardinality;
alshabib77b88482015-04-07 15:47:50 -070060import org.slf4j.Logger;
61import org.slf4j.LoggerFactory;
62
Saurav Das24431192016-03-07 19:13:00 -080063import java.util.ArrayList;
Saurav Das24431192016-03-07 19:13:00 -080064import java.util.List;
alshabib77b88482015-04-07 15:47:50 -070065import java.util.Map;
Saurav Das8a0732e2015-11-20 15:27:53 -080066import java.util.Objects;
alshabib2a441c62015-04-13 18:39:38 -070067import java.util.Set;
Jonathan Hart17d00452015-04-21 17:10:00 -070068import java.util.concurrent.ExecutorService;
alshabib77b88482015-04-07 15:47:50 -070069
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -070070import static com.google.common.base.Preconditions.checkNotNull;
Yi Tseng374c5f32017-03-05 22:51:35 -080071import static com.google.common.base.Strings.isNullOrEmpty;
Thomas Vachuska866b46a2015-04-30 00:26:55 -070072import static java.util.concurrent.Executors.newFixedThreadPool;
Ruchi Sahotae4934e12019-03-01 16:56:07 +000073import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Jonathan Hart17d00452015-04-21 17:10:00 -070074import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070075import static org.onosproject.net.AnnotationKeys.DRIVER;
Ray Milkeyd04e2272018-10-16 18:20:18 -070076import static org.onosproject.net.OsgiPropertyConstants.FOM_NUM_THREADS;
77import static org.onosproject.net.OsgiPropertyConstants.FOM_NUM_THREADS_DEFAULT;
pier8b3aef42019-03-11 15:14:02 -070078import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_OBJECTIVES;
79import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_OBJECTIVES_DEFAULT;
80import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_IDLE_MILLIS;
81import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_IDLE_MILLIS_DEFAULT;
82import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_BATCH_MILLIS;
83import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_BATCH_MILLIS_DEFAULT;
Changhoon Yoon541ef712015-05-23 17:18:34 +090084import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuskad27097c2016-06-14 19:10:41 -070085import static org.onosproject.security.AppPermission.Type.FLOWRULE_WRITE;
alshabib77b88482015-04-07 15:47:50 -070086
87/**
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070088 * Provides implementation of the flow objective programming service.
alshabib77b88482015-04-07 15:47:50 -070089 */
Ray Milkeyd04e2272018-10-16 18:20:18 -070090@Component(
91 enabled = false,
92 service = FlowObjectiveService.class,
93 property = {
pier8b3aef42019-03-11 15:14:02 -070094 FOM_NUM_THREADS + ":Integer=" + FOM_NUM_THREADS_DEFAULT,
95 FOM_ACCUMULATOR_MAX_OBJECTIVES + ":Integer=" + FOM_ACCUMULATOR_MAX_OBJECTIVES_DEFAULT,
96 FOM_ACCUMULATOR_MAX_IDLE_MILLIS + ":Integer=" + FOM_ACCUMULATOR_MAX_IDLE_MILLIS_DEFAULT,
97 FOM_ACCUMULATOR_MAX_BATCH_MILLIS + ":Integer=" + FOM_ACCUMULATOR_MAX_BATCH_MILLIS_DEFAULT,
Ray Milkeyd04e2272018-10-16 18:20:18 -070098 }
99)
alshabib77b88482015-04-07 15:47:50 -0700100public class FlowObjectiveManager implements FlowObjectiveService {
101
Charles Chana7903c82018-03-15 20:14:16 -0700102 private static final int INSTALL_RETRY_ATTEMPTS = 5;
103 private static final long INSTALL_RETRY_INTERVAL = 1000; // ms
alshabib77b88482015-04-07 15:47:50 -0700104
Yi Tseng374c5f32017-03-05 22:51:35 -0800105 private static final String WORKER_PATTERN = "objective-installer-%d";
106 private static final String GROUP_THREAD_NAME = "onos/objective-installer";
Yi Tseng374c5f32017-03-05 22:51:35 -0800107
Jonathan Hart17d00452015-04-21 17:10:00 -0700108 private final Logger log = LoggerFactory.getLogger(getClass());
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700109
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700110 /** Number of worker threads. */
Ray Milkeyd04e2272018-10-16 18:20:18 -0700111 private int numThreads = FOM_NUM_THREADS_DEFAULT;
Yi Tseng374c5f32017-03-05 22:51:35 -0800112
pier8b3aef42019-03-11 15:14:02 -0700113 // Parameters for the accumulator, each pipeline can implement
114 // its own accumulation logic. The following parameters are used
115 // to control the accumulator.
116
117 // Maximum number of objectives to accumulate before processing is triggered
118 private int accumulatorMaxObjectives = FOM_ACCUMULATOR_MAX_OBJECTIVES_DEFAULT;
119 // Maximum number of millis between objectives before processing is triggered
120 private int accumulatorMaxIdleMillis = FOM_ACCUMULATOR_MAX_IDLE_MILLIS_DEFAULT;
121 // Maximum number of millis allowed since the first objective before processing is triggered
122 private int accumulatorMaxBatchMillis = FOM_ACCUMULATOR_MAX_BATCH_MILLIS_DEFAULT;
123
124
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700125 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib77b88482015-04-07 15:47:50 -0700126 protected DriverService driverService;
127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib77b88482015-04-07 15:47:50 -0700129 protected DeviceService deviceService;
130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib77b88482015-04-07 15:47:50 -0700132 protected ClusterService clusterService;
133
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700134 // Note: The following dependencies are added on behalf of the pipeline
135 // driver behaviours to assure these services are available for their
136 // initialization.
Charles Chana7903c82018-03-15 20:14:16 -0700137 @SuppressWarnings("unused")
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700139 protected FlowRuleService flowRuleService;
140
Charles Chana7903c82018-03-15 20:14:16 -0700141 @SuppressWarnings("unused")
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700143 protected GroupService groupService;
144
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib2a441c62015-04-13 18:39:38 -0700146 protected FlowObjectiveStore flowObjectiveStore;
147
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng374c5f32017-03-05 22:51:35 -0800149 protected ComponentConfigService cfgService;
150
Charles Chana7903c82018-03-15 20:14:16 -0700151 final FlowObjectiveStoreDelegate delegate = new InternalStoreDelegate();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700152
153 private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap();
Charles Chana7903c82018-03-15 20:14:16 -0700154 protected final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700155
156 private final PipelinerContext context = new InnerPipelineContext();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700157 private final DeviceListener deviceListener = new InnerDeviceListener();
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700158 private final DriverListener driverListener = new InnerDriverListener();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700159
Charles Chana7903c82018-03-15 20:14:16 -0700160 private ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
alshabib910aff12015-04-09 16:55:57 -0700161
Saurav Das1547b3f2017-05-05 17:01:08 -0700162 // local stores for queuing fwd and next objectives that are waiting for an
163 // associated next objective execution to complete. The signal for completed
164 // execution comes from a pipeline driver, in this or another controller
165 // instance, via the DistributedFlowObjectiveStore.
Charles Chana7903c82018-03-15 20:14:16 -0700166 // TODO Making these cache and timeout the entries
167 final Map<Integer, Set<PendingFlowObjective>> pendingForwards = Maps.newConcurrentMap();
168 final Map<Integer, List<PendingFlowObjective>> pendingNexts = Maps.newConcurrentMap();
alshabib2a441c62015-04-13 18:39:38 -0700169
Saurav Das24431192016-03-07 19:13:00 -0800170 // local store to track which nextObjectives were sent to which device
171 // for debugging purposes
172 private Map<Integer, DeviceId> nextToDevice = Maps.newConcurrentMap();
173
Charles Chana7903c82018-03-15 20:14:16 -0700174 ExecutorService executorService;
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000175 protected ExecutorService devEventExecutor;
alshabib2a441c62015-04-13 18:39:38 -0700176
alshabib77b88482015-04-07 15:47:50 -0700177 @Activate
pier8b3aef42019-03-11 15:14:02 -0700178 protected void activate(ComponentContext context) {
Ray Milkey1f0764a2019-03-01 08:40:37 -0800179 cfgService.registerProperties(FlowObjectiveManager.class);
Yi Tseng374c5f32017-03-05 22:51:35 -0800180 executorService = newFixedThreadPool(numThreads,
181 groupedThreads(GROUP_THREAD_NAME, WORKER_PATTERN, log));
pier8b3aef42019-03-11 15:14:02 -0700182 modified(context);
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000183 devEventExecutor = newSingleThreadScheduledExecutor(
184 groupedThreads("onos/flowobj-dev-events", "events-%d", log));
alshabib2a441c62015-04-13 18:39:38 -0700185 flowObjectiveStore.setDelegate(delegate);
alshabibaebe7752015-04-07 17:45:42 -0700186 deviceService.addListener(deviceListener);
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700187 driverService.addListener(driverListener);
alshabib77b88482015-04-07 15:47:50 -0700188 log.info("Started");
189 }
190
191 @Deactivate
192 protected void deactivate() {
Yi Tseng374c5f32017-03-05 22:51:35 -0800193 cfgService.unregisterProperties(getClass(), false);
alshabib2a441c62015-04-13 18:39:38 -0700194 flowObjectiveStore.unsetDelegate(delegate);
alshabibaebe7752015-04-07 17:45:42 -0700195 deviceService.removeListener(deviceListener);
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700196 driverService.removeListener(driverListener);
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700197 executorService.shutdown();
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000198 devEventExecutor.shutdownNow();
199 devEventExecutor = null;
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700200 pipeliners.clear();
201 driverHandlers.clear();
Saurav Das24431192016-03-07 19:13:00 -0800202 nextToDevice.clear();
alshabib77b88482015-04-07 15:47:50 -0700203 log.info("Stopped");
204 }
205
Yi Tseng374c5f32017-03-05 22:51:35 -0800206 @Modified
207 protected void modified(ComponentContext context) {
pier8b3aef42019-03-11 15:14:02 -0700208 if (context != null) {
209 readComponentConfiguration(context);
210 }
211 }
212
213 /**
214 * Extracts properties from the component configuration context.
215 *
216 * @param context the component context
217 */
218 private void readComponentConfiguration(ComponentContext context) {
219 String propertyValue = Tools.get(context.getProperties(), FOM_NUM_THREADS);
Yi Tseng374c5f32017-03-05 22:51:35 -0800220 int newNumThreads = isNullOrEmpty(propertyValue) ? numThreads : Integer.parseInt(propertyValue);
221
222 if (newNumThreads != numThreads && newNumThreads > 0) {
223 numThreads = newNumThreads;
224 ExecutorService oldWorkerExecutor = executorService;
225 executorService = newFixedThreadPool(numThreads,
226 groupedThreads(GROUP_THREAD_NAME, WORKER_PATTERN, log));
227 if (oldWorkerExecutor != null) {
228 oldWorkerExecutor.shutdown();
229 }
230 log.info("Reconfigured number of worker threads to {}", numThreads);
231 }
pier8b3aef42019-03-11 15:14:02 -0700232
233 // Reconfiguration of the accumulator parameters is allowed
234 // Note: it will affect only pipelines going through init method
235 propertyValue = Tools.get(context.getProperties(), FOM_ACCUMULATOR_MAX_OBJECTIVES);
236 int newMaxObjs = isNullOrEmpty(propertyValue) ?
237 accumulatorMaxObjectives : Integer.parseInt(propertyValue);
238 if (newMaxObjs != accumulatorMaxObjectives && newMaxObjs > 0) {
239 accumulatorMaxObjectives = newMaxObjs;
240 log.info("Reconfigured maximum number of objectives to accumulate to {}",
241 accumulatorMaxObjectives);
242 }
243
244 propertyValue = Tools.get(context.getProperties(), FOM_ACCUMULATOR_MAX_IDLE_MILLIS);
245 int newMaxIdleMS = isNullOrEmpty(propertyValue) ?
246 accumulatorMaxIdleMillis : Integer.parseInt(propertyValue);
247 if (newMaxIdleMS != accumulatorMaxIdleMillis && newMaxIdleMS > 0) {
248 accumulatorMaxIdleMillis = newMaxIdleMS;
249 log.info("Reconfigured maximum number of millis between objectives to {}",
250 accumulatorMaxIdleMillis);
251 }
252
253 propertyValue = Tools.get(context.getProperties(), FOM_ACCUMULATOR_MAX_BATCH_MILLIS);
254 int newMaxBatchMS = isNullOrEmpty(propertyValue) ?
255 accumulatorMaxBatchMillis : Integer.parseInt(propertyValue);
256 if (newMaxBatchMS != accumulatorMaxBatchMillis && newMaxBatchMS > 0) {
257 accumulatorMaxBatchMillis = newMaxBatchMS;
258 log.info("Reconfigured maximum number of millis allowed since the first objective to {}",
259 accumulatorMaxBatchMillis);
260 }
261
Yi Tseng374c5f32017-03-05 22:51:35 -0800262 }
263
Jonathan Hart17d00452015-04-21 17:10:00 -0700264 /**
265 * Task that passes the flow objective down to the driver. The task will
266 * make a few attempts to find the appropriate driver, then eventually give
267 * up and report an error if no suitable driver could be found.
268 */
Charles Chana7903c82018-03-15 20:14:16 -0700269 class ObjectiveInstaller implements Runnable {
270 final DeviceId deviceId;
271 final Objective objective;
Jonathan Hart17d00452015-04-21 17:10:00 -0700272
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700273 private final int numAttempts;
Jonathan Hart17d00452015-04-21 17:10:00 -0700274
Charles Chana7903c82018-03-15 20:14:16 -0700275 ObjectiveInstaller(DeviceId deviceId, Objective objective) {
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700276 this(deviceId, objective, 1);
277 }
278
Charles Chana7903c82018-03-15 20:14:16 -0700279 ObjectiveInstaller(DeviceId deviceId, Objective objective, int attemps) {
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700280 this.deviceId = checkNotNull(deviceId);
281 this.objective = checkNotNull(objective);
Yuta HIGUCHIfbd9ae92018-01-24 23:39:06 -0800282 this.numAttempts = attemps;
alshabib910aff12015-04-09 16:55:57 -0700283 }
alshabib77b88482015-04-07 15:47:50 -0700284
Jonathan Hart17d00452015-04-21 17:10:00 -0700285 @Override
286 public void run() {
287 try {
Jonathan Hart17d00452015-04-21 17:10:00 -0700288 Pipeliner pipeliner = getDevicePipeliner(deviceId);
289
290 if (pipeliner != null) {
291 if (objective instanceof NextObjective) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700292 nextToDevice.put(objective.id(), deviceId);
Jonathan Hart17d00452015-04-21 17:10:00 -0700293 pipeliner.next((NextObjective) objective);
294 } else if (objective instanceof ForwardingObjective) {
295 pipeliner.forward((ForwardingObjective) objective);
296 } else {
297 pipeliner.filter((FilteringObjective) objective);
298 }
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800299 //Attempts to check if pipeliner is null for retry attempts
Jonathan Hart17d00452015-04-21 17:10:00 -0700300 } else if (numAttempts < INSTALL_RETRY_ATTEMPTS) {
Saurav Das3d038262015-04-23 12:36:58 -0700301 Thread.sleep(INSTALL_RETRY_INTERVAL);
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700302 executorService.execute(new ObjectiveInstaller(deviceId, objective, numAttempts + 1));
Jonathan Hart17d00452015-04-21 17:10:00 -0700303 } else {
304 // Otherwise we've tried a few times and failed, report an
305 // error back to the user.
306 objective.context().ifPresent(
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800307 c -> c.onError(objective, ObjectiveError.NOPIPELINER));
Jonathan Hart17d00452015-04-21 17:10:00 -0700308 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700309 //Exception thrown
Jonathan Hart17d00452015-04-21 17:10:00 -0700310 } catch (Exception e) {
311 log.warn("Exception while installing flow objective", e);
312 }
313 }
314 }
315
316 @Override
317 public void filter(DeviceId deviceId, FilteringObjective filteringObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900318 checkPermission(FLOWRULE_WRITE);
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700319 executorService.execute(new ObjectiveInstaller(deviceId, filteringObjective));
alshabib77b88482015-04-07 15:47:50 -0700320 }
321
322 @Override
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700323 public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900324 checkPermission(FLOWRULE_WRITE);
Yi Tseng1666b502017-05-17 11:05:18 -0700325 if (forwardingObjective.nextId() == null ||
Yi Tseng1666b502017-05-17 11:05:18 -0700326 flowObjectiveStore.getNextGroup(forwardingObjective.nextId()) != null ||
327 !queueFwdObjective(deviceId, forwardingObjective)) {
328 // fast path
329 executorService.execute(new ObjectiveInstaller(deviceId, forwardingObjective));
alshabib910aff12015-04-09 16:55:57 -0700330 }
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700331 }
332
alshabib2a441c62015-04-13 18:39:38 -0700333 @Override
Jonathan Hart17d00452015-04-21 17:10:00 -0700334 public void next(DeviceId deviceId, NextObjective nextObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900335 checkPermission(FLOWRULE_WRITE);
Yi Tseng1666b502017-05-17 11:05:18 -0700336 if (nextObjective.op() == Operation.ADD ||
Charles Chanb71e1ba2018-08-16 21:02:34 -0700337 nextObjective.op() == Operation.VERIFY ||
Yi Tseng1666b502017-05-17 11:05:18 -0700338 flowObjectiveStore.getNextGroup(nextObjective.id()) != null ||
339 !queueNextObjective(deviceId, nextObjective)) {
340 // either group exists or we are trying to create it - let it through
341 executorService.execute(new ObjectiveInstaller(deviceId, nextObjective));
Saurav Das1547b3f2017-05-05 17:01:08 -0700342 }
alshabib2a441c62015-04-13 18:39:38 -0700343 }
344
alshabibf6ea9e62015-04-21 17:08:26 -0700345 @Override
346 public int allocateNextId() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900347 checkPermission(FLOWRULE_WRITE);
alshabibf6ea9e62015-04-21 17:08:26 -0700348 return flowObjectiveStore.allocateNextId();
349 }
350
Xin Jin313708b2015-07-09 13:43:04 -0700351 @Override
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700352 public void initPolicy(String policy) {
353 }
Xin Jin313708b2015-07-09 13:43:04 -0700354
Charles Chana7903c82018-03-15 20:14:16 -0700355 boolean queueFwdObjective(DeviceId deviceId, ForwardingObjective fwd) {
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700356 boolean queued = false;
357 synchronized (pendingForwards) {
358 // double check the flow objective store, because this block could run
359 // after a notification arrives
360 if (flowObjectiveStore.getNextGroup(fwd.nextId()) == null) {
361 pendingForwards.compute(fwd.nextId(), (id, pending) -> {
Saurav Das1547b3f2017-05-05 17:01:08 -0700362 PendingFlowObjective pendfo = new PendingFlowObjective(deviceId, fwd);
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700363 if (pending == null) {
Pier Luigi97893112018-03-05 11:09:42 +0100364 return Sets.newLinkedHashSet(ImmutableSet.of(pendfo));
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700365 } else {
Saurav Das1547b3f2017-05-05 17:01:08 -0700366 pending.add(pendfo);
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700367 return pending;
368 }
369 });
370 queued = true;
371 }
372 }
373 if (queued) {
Saurav Dasc568c342018-01-25 09:49:01 -0800374 log.debug("Queued forwarding objective {} for nextId {} meant for device {}",
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700375 fwd.id(), fwd.nextId(), deviceId);
376 }
377 return queued;
alshabib2a441c62015-04-13 18:39:38 -0700378 }
379
Charles Chana7903c82018-03-15 20:14:16 -0700380 boolean queueNextObjective(DeviceId deviceId, NextObjective next) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700381 // we need to hold off on other operations till we get notified that the
382 // initial group creation has succeeded
383 boolean queued = false;
384 synchronized (pendingNexts) {
385 // double check the flow objective store, because this block could run
386 // after a notification arrives
387 if (flowObjectiveStore.getNextGroup(next.id()) == null) {
388 pendingNexts.compute(next.id(), (id, pending) -> {
389 PendingFlowObjective pendfo = new PendingFlowObjective(deviceId, next);
390 if (pending == null) {
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800391 return Lists.newArrayList(pendfo);
Saurav Das1547b3f2017-05-05 17:01:08 -0700392 } else {
393 pending.add(pendfo);
394 return pending;
395 }
396 });
397 queued = true;
398 }
399 }
400 if (queued) {
Saurav Dasc568c342018-01-25 09:49:01 -0800401 log.debug("Queued next objective {} with operation {} meant for device {}",
Saurav Das1547b3f2017-05-05 17:01:08 -0700402 next.id(), next.op(), deviceId);
403 }
404 return queued;
405 }
406
Pier Ventre57a61cd2016-09-07 10:55:41 -0700407 /**
408 * Retrieves (if it exists) the device pipeline behaviour from the cache.
409 * Otherwise it warms the caches and triggers the init method of the Pipeline.
410 *
411 * @param deviceId the id of the device associated to the pipeline
412 * @return the implementation of the Pipeliner behaviour
413 */
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700414 private Pipeliner getDevicePipeliner(DeviceId deviceId) {
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700415 return pipeliners.computeIfAbsent(deviceId, this::initPipelineHandler);
alshabib77b88482015-04-07 15:47:50 -0700416 }
417
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700418 /**
Pier Ventre57a61cd2016-09-07 10:55:41 -0700419 * Retrieves (if it exists) the device pipeline behaviour from the cache and
420 * and triggers the init method of the pipeline. Otherwise (DEVICE_ADDED) it warms
421 * the caches and triggers the init method of the Pipeline. The rationale of this
422 * method is for managing the scenario of a switch that goes down for a failure
423 * and goes up after a while.
424 *
425 * @param deviceId the id of the device associated to the pipeline
426 * @return the implementation of the Pipeliner behaviour
427 */
428 private Pipeliner getAndInitDevicePipeliner(DeviceId deviceId) {
429 return pipeliners.compute(deviceId, (deviceIdValue, pipelinerValue) -> {
430 if (pipelinerValue != null) {
431 pipelinerValue.init(deviceId, context);
432 return pipelinerValue;
433 }
434 return this.initPipelineHandler(deviceId);
435 });
436 }
437
438 /**
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700439 * Creates and initialize {@link Pipeliner}.
440 * <p>
441 * Note: Expected to be called under per-Device lock.
442 * e.g., {@code pipeliners}' Map#compute family methods
443 *
444 * @param deviceId Device to initialize pipeliner
445 * @return {@link Pipeliner} instance or null
446 */
447 private Pipeliner initPipelineHandler(DeviceId deviceId) {
448 start = now();
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700449
Jonathan Hart17d00452015-04-21 17:10:00 -0700450 // Attempt to lookup the handler in the cache
451 DriverHandler handler = driverHandlers.get(deviceId);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700452 cTime = now();
453
Jonathan Hart17d00452015-04-21 17:10:00 -0700454 if (handler == null) {
455 try {
456 // Otherwise create it and if it has pipeline behaviour, cache it
457 handler = driverService.createHandler(deviceId);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700458 dTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700459 if (!handler.driver().hasBehaviour(Pipeliner.class)) {
Yuta HIGUCHIa2a4f342017-03-17 11:38:57 -0700460 log.debug("Pipeline behaviour not supported for device {}",
Jonathan Hart17d00452015-04-21 17:10:00 -0700461 deviceId);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700462 return null;
alshabib2a441c62015-04-13 18:39:38 -0700463 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700464 } catch (ItemNotFoundException e) {
465 log.warn("No applicable driver for device {}", deviceId);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700466 return null;
alshabib2a441c62015-04-13 18:39:38 -0700467 }
468
Jonathan Hart17d00452015-04-21 17:10:00 -0700469 driverHandlers.put(deviceId, handler);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700470 eTime = now();
alshabib2a441c62015-04-13 18:39:38 -0700471 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700472
473 // Always (re)initialize the pipeline behaviour
474 log.info("Driver {} bound to device {} ... initializing driver",
475 handler.driver().name(), deviceId);
Thomas Vachuska0121a612015-07-21 11:18:09 -0700476 hTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700477 Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
Thomas Vachuska94c3cf42015-07-20 13:01:12 -0700478 hbTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700479 pipeliner.init(deviceId, context);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700480 stopWatch();
481 return pipeliner;
alshabibaebe7752015-04-07 17:45:42 -0700482 }
alshabib77b88482015-04-07 15:47:50 -0700483
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700484 private void invalidatePipelinerIfNecessary(Device device) {
485 DriverHandler handler = driverHandlers.get(device.id());
486 if (handler != null &&
487 !Objects.equals(handler.driver().name(),
488 device.annotations().value(DRIVER))) {
489 invalidatePipeliner(device.id());
490 }
491 }
492
493 private void invalidatePipeliner(DeviceId id) {
494 log.info("Invalidating cached pipeline behaviour for {}", id);
495 driverHandlers.remove(id);
496 pipeliners.remove(id);
497 if (deviceService.isAvailable(id)) {
498 getAndInitDevicePipeliner(id);
499 }
500 }
501
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700502 // Triggers driver setup when a device is (re)detected.
alshabibaebe7752015-04-07 17:45:42 -0700503 private class InnerDeviceListener implements DeviceListener {
504 @Override
505 public void event(DeviceEvent event) {
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000506 if (devEventExecutor != null) {
alshabibaebe7752015-04-07 17:45:42 -0700507 switch (event.type()) {
508 case DEVICE_ADDED:
509 case DEVICE_AVAILABILITY_CHANGED:
Madan Jampani0174f452015-05-29 11:52:05 -0700510 log.debug("Device either added or availability changed {}",
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700511 event.subject().id());
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000512 devEventExecutor.execute(() -> {
513 if (deviceService.isAvailable(event.subject().id())) {
Madan Jampani0174f452015-05-29 11:52:05 -0700514 log.debug("Device is now available {}", event.subject().id());
Pier Ventre57a61cd2016-09-07 10:55:41 -0700515 getAndInitDevicePipeliner(event.subject().id());
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000516 } else {
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700517 log.debug("Device is no longer available {}", event.subject().id());
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000518 }
519 });
alshabib4313d102015-04-08 18:55:08 -0700520 break;
521 case DEVICE_UPDATED:
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700522 // Invalidate pipeliner and handler caches if the driver name
523 // device annotation changed.
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000524 devEventExecutor.execute(() -> invalidatePipelinerIfNecessary(event.subject()));
alshabib4313d102015-04-08 18:55:08 -0700525 break;
526 case DEVICE_REMOVED:
Yuta HIGUCHIad0c9902016-08-23 10:37:32 -0700527 // evict Pipeliner and Handler cache, when
528 // the Device was administratively removed.
529 //
530 // System expect the user to clear all existing flows,
531 // before removing device, especially if they intend to
532 // replace driver/pipeliner assigned to the device.
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000533 devEventExecutor.execute(() -> {
534 driverHandlers.remove(event.subject().id());
535 pipeliners.remove(event.subject().id());
536 });
alshabib4313d102015-04-08 18:55:08 -0700537 break;
Yuta HIGUCHIad0c9902016-08-23 10:37:32 -0700538 case DEVICE_SUSPENDED:
539 break;
alshabib4313d102015-04-08 18:55:08 -0700540 case PORT_ADDED:
541 break;
542 case PORT_UPDATED:
543 break;
544 case PORT_REMOVED:
alshabibaebe7752015-04-07 17:45:42 -0700545 break;
546 default:
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700547 break;
alshabibaebe7752015-04-07 17:45:42 -0700548 }
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000549 }
alshabib77b88482015-04-07 15:47:50 -0700550 }
551 }
alshabibaebe7752015-04-07 17:45:42 -0700552
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700553 // Monitors driver configuration changes and invalidates the pipeliner cache entries.
554 // Note that this may leave stale entries on the device if the driver changes
555 // in manner where the new driver does not produce backward compatible flow objectives.
556 // In such cases, it is the operator's responsibility to force device re-connect.
557 private class InnerDriverListener implements DriverListener {
558 @Override
559 public void event(DriverEvent event) {
560 String driverName = event.subject().name();
561 driverHandlers.entrySet().stream()
562 .filter(e -> driverName.equals(e.getValue().driver().name()))
563 .map(Map.Entry::getKey)
564 .distinct()
565 .forEach(FlowObjectiveManager.this::invalidatePipeliner);
566 }
567 }
568
Thomas Vachuska174bb912015-07-16 21:27:14 -0700569 // Temporary mechanism to monitor pipeliner setup time-cost; there are
570 // intermittent time where this takes in excess of 2 seconds. Why?
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700571 private long start = 0, totals = 0, count = 0;
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700572 private long cTime, dTime, eTime, hTime, hbTime;
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700573 private static final long LIMIT = 500;
Thomas Vachuska174bb912015-07-16 21:27:14 -0700574
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700575 private long now() {
Thomas Vachuska174bb912015-07-16 21:27:14 -0700576 return System.currentTimeMillis();
577 }
578
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700579 private void stopWatch() {
Thomas Vachuska174bb912015-07-16 21:27:14 -0700580 long duration = System.currentTimeMillis() - start;
581 totals += duration;
582 count += 1;
583 if (duration > LIMIT) {
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700584 log.info("Pipeline setup took {} ms; avg {} ms; cTime={}, dTime={}, eTime={}, hTime={}, hbTime={}",
585 duration, totals / count, diff(cTime), diff(dTime), diff(eTime), diff(hTime), diff(hbTime));
Thomas Vachuska174bb912015-07-16 21:27:14 -0700586 }
587 }
588
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700589 private long diff(long bTime) {
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700590 long diff = bTime - start;
591 return diff < 0 ? 0 : diff;
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700592 }
593
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700594 // Processing context for initializing pipeline driver behaviours.
595 private class InnerPipelineContext implements PipelinerContext {
pier8b3aef42019-03-11 15:14:02 -0700596
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700597 @Override
598 public ServiceDirectory directory() {
599 return serviceDirectory;
alshabibaebe7752015-04-07 17:45:42 -0700600 }
alshabib2a441c62015-04-13 18:39:38 -0700601
602 @Override
603 public FlowObjectiveStore store() {
604 return flowObjectiveStore;
605 }
pier8b3aef42019-03-11 15:14:02 -0700606
607 @Override
608 public int accumulatorMaxObjectives() {
609 return accumulatorMaxObjectives;
610 }
611
612 @Override
613 public int accumulatorMaxIdleMillis() {
614 return accumulatorMaxIdleMillis;
615 }
616
617 @Override
618 public int accumulatorMaxBatchMillis() {
619 return accumulatorMaxBatchMillis;
620 }
621
alshabib2a441c62015-04-13 18:39:38 -0700622 }
623
624 private class InternalStoreDelegate implements FlowObjectiveStoreDelegate {
625 @Override
626 public void notify(ObjectiveEvent event) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800627 if (event.type() == Type.ADD) {
628 log.debug("Received notification of obj event {}", event);
Saurav Das1547b3f2017-05-05 17:01:08 -0700629 Set<PendingFlowObjective> pending;
630
631 // first send all pending flows
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700632 synchronized (pendingForwards) {
633 // needs to be synchronized for queueObjective lookup
634 pending = pendingForwards.remove(event.subject());
635 }
Saurav Das423fe2b2015-12-04 10:52:59 -0800636 if (pending == null) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700637 log.debug("No forwarding objectives pending for this "
638 + "obj event {}", event);
639 } else {
640 log.debug("Processing {} pending forwarding objectives for nextId {}",
641 pending.size(), event.subject());
642 pending.forEach(p -> getDevicePipeliner(p.deviceId())
643 .forward((ForwardingObjective) p.flowObjective()));
Saurav Das423fe2b2015-12-04 10:52:59 -0800644 }
645
Saurav Das1547b3f2017-05-05 17:01:08 -0700646 // now check for pending next-objectives
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800647 List<PendingFlowObjective> pendNexts;
Saurav Das1547b3f2017-05-05 17:01:08 -0700648 synchronized (pendingNexts) {
649 // needs to be synchronized for queueObjective lookup
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800650 pendNexts = pendingNexts.remove(event.subject());
Saurav Das1547b3f2017-05-05 17:01:08 -0700651 }
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800652 if (pendNexts == null) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700653 log.debug("No next objectives pending for this "
654 + "obj event {}", event);
655 } else {
656 log.debug("Processing {} pending next objectives for nextId {}",
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800657 pendNexts.size(), event.subject());
658 pendNexts.forEach(p -> getDevicePipeliner(p.deviceId())
Saurav Das1547b3f2017-05-05 17:01:08 -0700659 .next((NextObjective) p.flowObjective()));
660 }
alshabib2a441c62015-04-13 18:39:38 -0700661 }
alshabib2a441c62015-04-13 18:39:38 -0700662 }
663 }
664
665 /**
Saurav Das1547b3f2017-05-05 17:01:08 -0700666 * Data class used to hold a pending flow objective that could not
alshabib2a441c62015-04-13 18:39:38 -0700667 * be processed because the associated next object was not present.
Saurav Das1547b3f2017-05-05 17:01:08 -0700668 * Note that this pending flow objective could be a forwarding objective
669 * waiting for a next objective to complete execution. Or it could a
670 * next objective (with a different operation - remove, addToExisting, or
671 * removeFromExisting) waiting for a next objective with the same id to
672 * complete execution.
alshabib2a441c62015-04-13 18:39:38 -0700673 */
Charles Chana7903c82018-03-15 20:14:16 -0700674 protected class PendingFlowObjective {
alshabib2a441c62015-04-13 18:39:38 -0700675 private final DeviceId deviceId;
Saurav Das1547b3f2017-05-05 17:01:08 -0700676 private final Objective flowObj;
alshabib2a441c62015-04-13 18:39:38 -0700677
Charles Chana7903c82018-03-15 20:14:16 -0700678 PendingFlowObjective(DeviceId deviceId, Objective flowObj) {
alshabib2a441c62015-04-13 18:39:38 -0700679 this.deviceId = deviceId;
Saurav Das1547b3f2017-05-05 17:01:08 -0700680 this.flowObj = flowObj;
alshabib2a441c62015-04-13 18:39:38 -0700681 }
682
683 public DeviceId deviceId() {
684 return deviceId;
685 }
686
Saurav Das1547b3f2017-05-05 17:01:08 -0700687 public Objective flowObjective() {
688 return flowObj;
alshabib2a441c62015-04-13 18:39:38 -0700689 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800690
691 @Override
692 public int hashCode() {
Saurav Das1547b3f2017-05-05 17:01:08 -0700693 return Objects.hash(deviceId, flowObj);
Saurav Das8a0732e2015-11-20 15:27:53 -0800694 }
695
696 @Override
697 public boolean equals(final Object obj) {
698 if (this == obj) {
699 return true;
700 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700701 if (!(obj instanceof PendingFlowObjective)) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800702 return false;
703 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700704 final PendingFlowObjective other = (PendingFlowObjective) obj;
Charles Chana7903c82018-03-15 20:14:16 -0700705
706 return this.deviceId.equals(other.deviceId) &&
707 this.flowObj.equals(other.flowObj);
Saurav Das8a0732e2015-11-20 15:27:53 -0800708 }
alshabibaebe7752015-04-07 17:45:42 -0700709 }
Saurav Das24431192016-03-07 19:13:00 -0800710
711 @Override
712 public List<String> getNextMappings() {
713 List<String> mappings = new ArrayList<>();
714 Map<Integer, NextGroup> allnexts = flowObjectiveStore.getAllGroups();
Saurav Das25190812016-05-27 13:54:07 -0700715 // XXX if the NextGroup after de-serialization actually stored info of the deviceId
Saurav Das24431192016-03-07 19:13:00 -0800716 // then info on any nextObj could be retrieved from one controller instance.
717 // Right now the drivers on one instance can only fetch for next-ids that came
718 // to them.
719 // Also, we still need to send the right next-id to the right driver as potentially
720 // there can be different drivers for different devices. But on that account,
721 // no instance should be decoding for another instance's nextIds.
722
723 for (Map.Entry<Integer, NextGroup> e : allnexts.entrySet()) {
724 // get the device this next Objective was sent to
725 DeviceId deviceId = nextToDevice.get(e.getKey());
726 mappings.add("NextId " + e.getKey() + ": " +
727 ((deviceId != null) ? deviceId : "nextId not in this onos instance"));
728 if (deviceId != null) {
729 // this instance of the controller sent the nextObj to a driver
730 Pipeliner pipeliner = getDevicePipeliner(deviceId);
731 List<String> nextMappings = pipeliner.getNextMappings(e.getValue());
732 if (nextMappings != null) {
733 mappings.addAll(nextMappings);
734 }
735 }
736 }
737 return mappings;
738 }
Saurav Dasb5c236e2016-06-07 10:08:06 -0700739
740 @Override
Saurav Das1547b3f2017-05-05 17:01:08 -0700741 public List<String> getPendingFlowObjectives() {
742 List<String> pendingFlowObjectives = new ArrayList<>();
Charles Chan54734712017-03-29 11:07:55 -0700743
Saurav Das1547b3f2017-05-05 17:01:08 -0700744 for (Integer nextId : pendingForwards.keySet()) {
745 Set<PendingFlowObjective> pfwd = pendingForwards.get(nextId);
Sho SHIMIZU81470a52016-08-12 17:24:55 -0700746 StringBuilder pend = new StringBuilder();
Charles Chan54734712017-03-29 11:07:55 -0700747 pend.append("NextId: ")
748 .append(nextId);
Saurav Das1547b3f2017-05-05 17:01:08 -0700749 for (PendingFlowObjective pf : pfwd) {
Charles Chan54734712017-03-29 11:07:55 -0700750 pend.append("\n FwdId: ")
Saurav Das1547b3f2017-05-05 17:01:08 -0700751 .append(String.format("%11s", pf.flowObjective().id()))
752 .append(", DeviceId: ")
753 .append(pf.deviceId())
754 .append(", Selector: ")
755 .append(((ForwardingObjective) pf.flowObjective())
756 .selector().criteria());
757 }
758 pendingFlowObjectives.add(pend.toString());
759 }
760
761 for (Integer nextId : pendingNexts.keySet()) {
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800762 List<PendingFlowObjective> pnext = pendingNexts.get(nextId);
Saurav Das1547b3f2017-05-05 17:01:08 -0700763 StringBuilder pend = new StringBuilder();
764 pend.append("NextId: ")
765 .append(nextId);
766 for (PendingFlowObjective pn : pnext) {
767 pend.append("\n NextOp: ")
768 .append(pn.flowObjective().op())
Charles Chan54734712017-03-29 11:07:55 -0700769 .append(", DeviceId: ")
770 .append(pn.deviceId())
Saurav Das1547b3f2017-05-05 17:01:08 -0700771 .append(", Treatments: ")
772 .append(((NextObjective) pn.flowObjective())
773 .next());
Saurav Dasb5c236e2016-06-07 10:08:06 -0700774 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700775 pendingFlowObjectives.add(pend.toString());
Saurav Dasb5c236e2016-06-07 10:08:06 -0700776 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700777
778 return pendingFlowObjectives;
779 }
alshabib77b88482015-04-07 15:47:50 -0700780}