blob: e0ac8571bf0b2e49b8ab4123fa166b33d92b6528 [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 Luigi23934ce2018-03-05 11:09:42 +010018import com.google.common.collect.ImmutableSet;
Harshada Chaundkar0acb3262019-07-03 16:27:45 +000019import com.google.common.collect.ImmutableList;
Saurav Das73a6cc12017-12-05 15:00:23 -080020import com.google.common.collect.Lists;
alshabib77b88482015-04-07 15:47:50 -070021import com.google.common.collect.Maps;
Thomas Vachuskad27097c2016-06-14 19:10:41 -070022import com.google.common.collect.Sets;
Harshada Chaundkar0acb3262019-07-03 16:27:45 +000023import org.apache.commons.lang3.tuple.Pair;
alshabib77b88482015-04-07 15:47:50 -070024import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
Yi Tseng374c5f32017-03-05 22:51:35 -080027import org.apache.felix.scr.annotations.Modified;
28import org.apache.felix.scr.annotations.Property;
alshabib77b88482015-04-07 15:47:50 -070029import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
31import org.apache.felix.scr.annotations.Service;
32import org.onlab.osgi.DefaultServiceDirectory;
33import org.onlab.osgi.ServiceDirectory;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070034import org.onlab.util.ItemNotFoundException;
Yi Tseng374c5f32017-03-05 22:51:35 -080035import org.onlab.util.Tools;
36import org.onosproject.cfg.ComponentConfigService;
alshabib77b88482015-04-07 15:47:50 -070037import org.onosproject.cluster.ClusterService;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070038import org.onosproject.net.Device;
alshabib77b88482015-04-07 15:47:50 -070039import org.onosproject.net.DeviceId;
Saurav Das24431192016-03-07 19:13:00 -080040import org.onosproject.net.behaviour.NextGroup;
alshabib77b88482015-04-07 15:47:50 -070041import org.onosproject.net.behaviour.Pipeliner;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070042import org.onosproject.net.behaviour.PipelinerContext;
alshabibaebe7752015-04-07 17:45:42 -070043import org.onosproject.net.device.DeviceEvent;
44import org.onosproject.net.device.DeviceListener;
alshabib77b88482015-04-07 15:47:50 -070045import org.onosproject.net.device.DeviceService;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070046import org.onosproject.net.driver.DriverEvent;
alshabib77b88482015-04-07 15:47:50 -070047import org.onosproject.net.driver.DriverHandler;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070048import org.onosproject.net.driver.DriverListener;
alshabib77b88482015-04-07 15:47:50 -070049import org.onosproject.net.driver.DriverService;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070050import org.onosproject.net.flow.FlowRuleService;
alshabib77b88482015-04-07 15:47:50 -070051import org.onosproject.net.flowobjective.FilteringObjective;
52import org.onosproject.net.flowobjective.FlowObjectiveService;
alshabib2a441c62015-04-13 18:39:38 -070053import org.onosproject.net.flowobjective.FlowObjectiveStore;
54import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate;
alshabib77b88482015-04-07 15:47:50 -070055import org.onosproject.net.flowobjective.ForwardingObjective;
56import org.onosproject.net.flowobjective.NextObjective;
alshabib910aff12015-04-09 16:55:57 -070057import org.onosproject.net.flowobjective.Objective;
Saurav Das1547b3f2017-05-05 17:01:08 -070058import org.onosproject.net.flowobjective.Objective.Operation;
Jonathan Hart17d00452015-04-21 17:10:00 -070059import org.onosproject.net.flowobjective.ObjectiveError;
alshabib2a441c62015-04-13 18:39:38 -070060import org.onosproject.net.flowobjective.ObjectiveEvent;
Saurav Das423fe2b2015-12-04 10:52:59 -080061import org.onosproject.net.flowobjective.ObjectiveEvent.Type;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070062import org.onosproject.net.group.GroupService;
Yi Tseng374c5f32017-03-05 22:51:35 -080063import org.osgi.service.component.ComponentContext;
alshabib77b88482015-04-07 15:47:50 -070064import org.slf4j.Logger;
65import org.slf4j.LoggerFactory;
66
Saurav Das24431192016-03-07 19:13:00 -080067import java.util.ArrayList;
Saurav Das24431192016-03-07 19:13:00 -080068import java.util.List;
alshabib77b88482015-04-07 15:47:50 -070069import java.util.Map;
Saurav Das8a0732e2015-11-20 15:27:53 -080070import java.util.Objects;
alshabib2a441c62015-04-13 18:39:38 -070071import java.util.Set;
Harshada Chaundkar0acb3262019-07-03 16:27:45 +000072import java.util.HashMap;
Jonathan Hart17d00452015-04-21 17:10:00 -070073import java.util.concurrent.ExecutorService;
alshabib77b88482015-04-07 15:47:50 -070074
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -070075import static com.google.common.base.Preconditions.checkNotNull;
Yi Tseng374c5f32017-03-05 22:51:35 -080076import static com.google.common.base.Strings.isNullOrEmpty;
Thomas Vachuska866b46a2015-04-30 00:26:55 -070077import static java.util.concurrent.Executors.newFixedThreadPool;
Ruchi Sahota196a9ca2019-03-01 16:56:07 +000078import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Jonathan Hart17d00452015-04-21 17:10:00 -070079import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070080import static org.onosproject.net.AnnotationKeys.DRIVER;
Changhoon Yoon541ef712015-05-23 17:18:34 +090081import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuskad27097c2016-06-14 19:10:41 -070082import static org.onosproject.security.AppPermission.Type.FLOWRULE_WRITE;
alshabib77b88482015-04-07 15:47:50 -070083
84/**
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070085 * Provides implementation of the flow objective programming service.
alshabib77b88482015-04-07 15:47:50 -070086 */
Charles Chancb1db5a2018-03-15 20:14:16 -070087@Component(enabled = false)
alshabib77b88482015-04-07 15:47:50 -070088@Service
89public class FlowObjectiveManager implements FlowObjectiveService {
90
Charles Chancb1db5a2018-03-15 20:14:16 -070091 private static final int INSTALL_RETRY_ATTEMPTS = 5;
92 private static final long INSTALL_RETRY_INTERVAL = 1000; // ms
alshabib77b88482015-04-07 15:47:50 -070093
pier2107d0c2020-01-27 17:45:03 +010094 private static final String INSTALLER_PATTERN = "installer-%d";
95 private static final String VERIFIER_PATTERN = "verifier-%d";
96 private static final String GROUP_THREAD_NAME = "onos/objective";
Yi Tseng374c5f32017-03-05 22:51:35 -080097 private static final String NUM_THREAD = "numThreads";
98
Jonathan Hart17d00452015-04-21 17:10:00 -070099 private final Logger log = LoggerFactory.getLogger(getClass());
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700100
pier5b9b9e32019-03-11 15:14:02 -0700101 // Parameters for the accumulator, each pipeline can implement
102 // its own accumulation logic. The following parameters are used
103 // to control the accumulator.
104 private static final String ACCUMULATOR_MAX_OBJECTIVES = "accumulatorMaxObjectives";
105 // Maximum number of objectives to accumulate before processing is triggered
106 private static final int DEFAULT_ACCUMULATOR_MAX_OBJECTIVES = 1000;
107 @Property(name = ACCUMULATOR_MAX_OBJECTIVES,
108 intValue = DEFAULT_ACCUMULATOR_MAX_OBJECTIVES,
109 label = "Maximum number of objectives to accumulate")
110 private int accumulatorMaxObjectives = DEFAULT_ACCUMULATOR_MAX_OBJECTIVES;
111
112 private static final String ACCUMULATOR_MAX_IDLE_MILLIS = "accumulatorMaxIdleMillis";
113 // Maximum number of millis between objectives before processing is triggered
114 private static final int DEFAULT_ACCUMULATOR_MAX_IDLE_MILLIS = 10;
115 @Property(name = ACCUMULATOR_MAX_IDLE_MILLIS,
116 intValue = DEFAULT_ACCUMULATOR_MAX_IDLE_MILLIS,
117 label = "Maximum number of millis between objectives")
118 private int accumulatorMaxIdleMillis = DEFAULT_ACCUMULATOR_MAX_IDLE_MILLIS;
119
120 private static final String ACCUMULATOR_MAX_BATCH_MILLIS = "accumulatorMaxBatchMillis";
121 // Maximum number of millis allowed since the first objective before processing is triggered
122 private static final int DEFAULT_ACCUMULATOR_MAX_BATCH_MILLIS = 500;
123 @Property(name = ACCUMULATOR_MAX_BATCH_MILLIS,
124 intValue = DEFAULT_ACCUMULATOR_MAX_BATCH_MILLIS,
125 label = "Maximum number of millis allowed since the first objective")
126 private int accumulatorMaxBatchMillis = DEFAULT_ACCUMULATOR_MAX_BATCH_MILLIS;
127
Yi Tseng9753fc12017-03-10 18:42:46 -0800128 private static final int DEFAULT_NUM_THREADS = 4;
Yi Tseng374c5f32017-03-05 22:51:35 -0800129 @Property(name = NUM_THREAD,
130 intValue = DEFAULT_NUM_THREADS,
131 label = "Number of worker threads")
132 private int numThreads = DEFAULT_NUM_THREADS;
133
alshabib77b88482015-04-07 15:47:50 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected DriverService driverService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 protected DeviceService deviceService;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib77b88482015-04-07 15:47:50 -0700141 protected ClusterService clusterService;
142
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700143 // Note: The following dependencies are added on behalf of the pipeline
144 // driver behaviours to assure these services are available for their
145 // initialization.
Charles Chancb1db5a2018-03-15 20:14:16 -0700146 @SuppressWarnings("unused")
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
148 protected FlowRuleService flowRuleService;
149
Charles Chancb1db5a2018-03-15 20:14:16 -0700150 @SuppressWarnings("unused")
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
152 protected GroupService groupService;
153
alshabib2a441c62015-04-13 18:39:38 -0700154 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
155 protected FlowObjectiveStore flowObjectiveStore;
156
Yi Tseng374c5f32017-03-05 22:51:35 -0800157 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
158 protected ComponentConfigService cfgService;
159
Charles Chancb1db5a2018-03-15 20:14:16 -0700160 final FlowObjectiveStoreDelegate delegate = new InternalStoreDelegate();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700161
162 private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap();
Charles Chancb1db5a2018-03-15 20:14:16 -0700163 protected final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700164
165 private final PipelinerContext context = new InnerPipelineContext();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700166 private final DeviceListener deviceListener = new InnerDeviceListener();
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700167 private final DriverListener driverListener = new InnerDriverListener();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700168
Charles Chancb1db5a2018-03-15 20:14:16 -0700169 private ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
alshabib910aff12015-04-09 16:55:57 -0700170
Saurav Das1547b3f2017-05-05 17:01:08 -0700171 // local stores for queuing fwd and next objectives that are waiting for an
172 // associated next objective execution to complete. The signal for completed
173 // execution comes from a pipeline driver, in this or another controller
174 // instance, via the DistributedFlowObjectiveStore.
Charles Chancb1db5a2018-03-15 20:14:16 -0700175 // TODO Making these cache and timeout the entries
176 final Map<Integer, Set<PendingFlowObjective>> pendingForwards = Maps.newConcurrentMap();
177 final Map<Integer, List<PendingFlowObjective>> pendingNexts = Maps.newConcurrentMap();
alshabib2a441c62015-04-13 18:39:38 -0700178
Saurav Das24431192016-03-07 19:13:00 -0800179 // local store to track which nextObjectives were sent to which device
180 // for debugging purposes
181 private Map<Integer, DeviceId> nextToDevice = Maps.newConcurrentMap();
182
pier2107d0c2020-01-27 17:45:03 +0100183 ExecutorService installerExecutor;
184 ExecutorService verifierExecutor;
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000185 protected ExecutorService devEventExecutor;
alshabib2a441c62015-04-13 18:39:38 -0700186
alshabib77b88482015-04-07 15:47:50 -0700187 @Activate
pier5b9b9e32019-03-11 15:14:02 -0700188 protected void activate(ComponentContext context) {
Yi Tseng374c5f32017-03-05 22:51:35 -0800189 cfgService.registerProperties(getClass());
pier2107d0c2020-01-27 17:45:03 +0100190 installerExecutor = newFixedThreadPool(numThreads,
191 groupedThreads(GROUP_THREAD_NAME, INSTALLER_PATTERN, log));
192 verifierExecutor = newFixedThreadPool(numThreads,
193 groupedThreads(GROUP_THREAD_NAME, VERIFIER_PATTERN, log));
194
pier5b9b9e32019-03-11 15:14:02 -0700195 modified(context);
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000196 devEventExecutor = newSingleThreadScheduledExecutor(
197 groupedThreads("onos/flowobj-dev-events", "events-%d", log));
alshabib2a441c62015-04-13 18:39:38 -0700198 flowObjectiveStore.setDelegate(delegate);
alshabibaebe7752015-04-07 17:45:42 -0700199 deviceService.addListener(deviceListener);
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700200 driverService.addListener(driverListener);
alshabib77b88482015-04-07 15:47:50 -0700201 log.info("Started");
202 }
203
204 @Deactivate
205 protected void deactivate() {
Yi Tseng374c5f32017-03-05 22:51:35 -0800206 cfgService.unregisterProperties(getClass(), false);
alshabib2a441c62015-04-13 18:39:38 -0700207 flowObjectiveStore.unsetDelegate(delegate);
alshabibaebe7752015-04-07 17:45:42 -0700208 deviceService.removeListener(deviceListener);
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700209 driverService.removeListener(driverListener);
pier2107d0c2020-01-27 17:45:03 +0100210 installerExecutor.shutdown();
211 verifierExecutor.shutdown();
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000212 devEventExecutor.shutdownNow();
213 devEventExecutor = null;
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700214 pipeliners.clear();
215 driverHandlers.clear();
Saurav Das24431192016-03-07 19:13:00 -0800216 nextToDevice.clear();
alshabib77b88482015-04-07 15:47:50 -0700217 log.info("Stopped");
218 }
219
Yi Tseng374c5f32017-03-05 22:51:35 -0800220 @Modified
221 protected void modified(ComponentContext context) {
pier5b9b9e32019-03-11 15:14:02 -0700222 if (context != null) {
223 readComponentConfiguration(context);
224 }
225 }
226
227 /**
228 * Extracts properties from the component configuration context.
229 *
230 * @param context the component context
231 */
232 private void readComponentConfiguration(ComponentContext context) {
233 String propertyValue = Tools.get(context.getProperties(), NUM_THREAD);
Yi Tseng374c5f32017-03-05 22:51:35 -0800234 int newNumThreads = isNullOrEmpty(propertyValue) ? numThreads : Integer.parseInt(propertyValue);
235
236 if (newNumThreads != numThreads && newNumThreads > 0) {
237 numThreads = newNumThreads;
pier2107d0c2020-01-27 17:45:03 +0100238 ExecutorService oldWorkerExecutor = installerExecutor;
239 installerExecutor = newFixedThreadPool(numThreads,
240 groupedThreads(GROUP_THREAD_NAME, INSTALLER_PATTERN, log));
241 if (oldWorkerExecutor != null) {
242 oldWorkerExecutor.shutdown();
243 }
244 oldWorkerExecutor = verifierExecutor;
245 verifierExecutor = newFixedThreadPool(numThreads,
246 groupedThreads(GROUP_THREAD_NAME, VERIFIER_PATTERN, log));
Yi Tseng374c5f32017-03-05 22:51:35 -0800247 if (oldWorkerExecutor != null) {
248 oldWorkerExecutor.shutdown();
249 }
250 log.info("Reconfigured number of worker threads to {}", numThreads);
251 }
pier5b9b9e32019-03-11 15:14:02 -0700252
253 // Reconfiguration of the accumulator parameters is allowed
254 // Note: it will affect only pipelines going through init method
255 propertyValue = Tools.get(context.getProperties(), ACCUMULATOR_MAX_OBJECTIVES);
256 int newMaxObjs = isNullOrEmpty(propertyValue) ?
257 accumulatorMaxObjectives : Integer.parseInt(propertyValue);
258 if (newMaxObjs != accumulatorMaxObjectives && newMaxObjs > 0) {
259 accumulatorMaxObjectives = newMaxObjs;
260 log.info("Reconfigured maximum number of objectives to accumulate to {}",
261 accumulatorMaxObjectives);
262 }
263
264 propertyValue = Tools.get(context.getProperties(), ACCUMULATOR_MAX_IDLE_MILLIS);
265 int newMaxIdleMS = isNullOrEmpty(propertyValue) ?
266 accumulatorMaxIdleMillis : Integer.parseInt(propertyValue);
267 if (newMaxIdleMS != accumulatorMaxIdleMillis && newMaxIdleMS > 0) {
268 accumulatorMaxIdleMillis = newMaxIdleMS;
269 log.info("Reconfigured maximum number of millis between objectives to {}",
270 accumulatorMaxIdleMillis);
271 }
272
273 propertyValue = Tools.get(context.getProperties(), ACCUMULATOR_MAX_BATCH_MILLIS);
274 int newMaxBatchMS = isNullOrEmpty(propertyValue) ?
275 accumulatorMaxBatchMillis : Integer.parseInt(propertyValue);
276 if (newMaxBatchMS != accumulatorMaxBatchMillis && newMaxBatchMS > 0) {
277 accumulatorMaxBatchMillis = newMaxBatchMS;
278 log.info("Reconfigured maximum number of millis allowed since the first objective to {}",
279 accumulatorMaxBatchMillis);
280 }
281
Yi Tseng374c5f32017-03-05 22:51:35 -0800282 }
283
Jonathan Hart17d00452015-04-21 17:10:00 -0700284 /**
285 * Task that passes the flow objective down to the driver. The task will
286 * make a few attempts to find the appropriate driver, then eventually give
287 * up and report an error if no suitable driver could be found.
288 */
pier2107d0c2020-01-27 17:45:03 +0100289 class ObjectiveProcessor implements Runnable {
Charles Chancb1db5a2018-03-15 20:14:16 -0700290 final DeviceId deviceId;
291 final Objective objective;
pier2107d0c2020-01-27 17:45:03 +0100292 final ExecutorService executor;
Jonathan Hart17d00452015-04-21 17:10:00 -0700293
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700294 private final int numAttempts;
Jonathan Hart17d00452015-04-21 17:10:00 -0700295
pier2107d0c2020-01-27 17:45:03 +0100296 ObjectiveProcessor(DeviceId deviceId, Objective objective,
297 ExecutorService executorService) {
298 this(deviceId, objective, 1, executorService);
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700299 }
300
pier2107d0c2020-01-27 17:45:03 +0100301 ObjectiveProcessor(DeviceId deviceId, Objective objective, int attempts,
302 ExecutorService executorService) {
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700303 this.deviceId = checkNotNull(deviceId);
304 this.objective = checkNotNull(objective);
pier2107d0c2020-01-27 17:45:03 +0100305 this.executor = checkNotNull(executorService);
306 this.numAttempts = attempts;
alshabib910aff12015-04-09 16:55:57 -0700307 }
alshabib77b88482015-04-07 15:47:50 -0700308
Jonathan Hart17d00452015-04-21 17:10:00 -0700309 @Override
310 public void run() {
311 try {
Jonathan Hart17d00452015-04-21 17:10:00 -0700312 Pipeliner pipeliner = getDevicePipeliner(deviceId);
313
pier20511962020-05-11 13:49:37 +0200314 if (pipeliner != null) {
Jonathan Hart17d00452015-04-21 17:10:00 -0700315 if (objective instanceof NextObjective) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700316 nextToDevice.put(objective.id(), deviceId);
Jonathan Hart17d00452015-04-21 17:10:00 -0700317 pipeliner.next((NextObjective) objective);
318 } else if (objective instanceof ForwardingObjective) {
319 pipeliner.forward((ForwardingObjective) objective);
320 } else {
321 pipeliner.filter((FilteringObjective) objective);
322 }
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800323 //Attempts to check if pipeliner is null for retry attempts
Jonathan Hart17d00452015-04-21 17:10:00 -0700324 } else if (numAttempts < INSTALL_RETRY_ATTEMPTS) {
Saurav Das3d038262015-04-23 12:36:58 -0700325 Thread.sleep(INSTALL_RETRY_INTERVAL);
pier2107d0c2020-01-27 17:45:03 +0100326 executor.execute(new ObjectiveProcessor(deviceId, objective,
327 numAttempts + 1, executor));
Jonathan Hart17d00452015-04-21 17:10:00 -0700328 } else {
329 // Otherwise we've tried a few times and failed, report an
330 // error back to the user.
331 objective.context().ifPresent(
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800332 c -> c.onError(objective, ObjectiveError.NOPIPELINER));
Jonathan Hart17d00452015-04-21 17:10:00 -0700333 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700334 //Exception thrown
Jonathan Hart17d00452015-04-21 17:10:00 -0700335 } catch (Exception e) {
pier2107d0c2020-01-27 17:45:03 +0100336 log.warn("Exception while processing flow objective", e);
Jonathan Hart17d00452015-04-21 17:10:00 -0700337 }
338 }
339 }
340
341 @Override
342 public void filter(DeviceId deviceId, FilteringObjective filteringObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900343 checkPermission(FLOWRULE_WRITE);
pier2107d0c2020-01-27 17:45:03 +0100344 installerExecutor.execute(new ObjectiveProcessor(deviceId, filteringObjective, installerExecutor));
alshabib77b88482015-04-07 15:47:50 -0700345 }
346
347 @Override
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700348 public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900349 checkPermission(FLOWRULE_WRITE);
Yi Tseng1666b502017-05-17 11:05:18 -0700350 if (forwardingObjective.nextId() == null ||
Yi Tseng1666b502017-05-17 11:05:18 -0700351 flowObjectiveStore.getNextGroup(forwardingObjective.nextId()) != null ||
352 !queueFwdObjective(deviceId, forwardingObjective)) {
353 // fast path
pier2107d0c2020-01-27 17:45:03 +0100354 installerExecutor.execute(new ObjectiveProcessor(deviceId, forwardingObjective, installerExecutor));
alshabib910aff12015-04-09 16:55:57 -0700355 }
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700356 }
357
alshabib2a441c62015-04-13 18:39:38 -0700358 @Override
Jonathan Hart17d00452015-04-21 17:10:00 -0700359 public void next(DeviceId deviceId, NextObjective nextObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900360 checkPermission(FLOWRULE_WRITE);
pier2107d0c2020-01-27 17:45:03 +0100361 if (nextObjective.op() == Operation.VERIFY) {
362 // Verify does not need to wait
363 verifierExecutor.execute(new ObjectiveProcessor(deviceId, nextObjective, verifierExecutor));
364 } else if (nextObjective.op() == Operation.ADD ||
Yi Tseng1666b502017-05-17 11:05:18 -0700365 flowObjectiveStore.getNextGroup(nextObjective.id()) != null ||
366 !queueNextObjective(deviceId, nextObjective)) {
367 // either group exists or we are trying to create it - let it through
pier2107d0c2020-01-27 17:45:03 +0100368 installerExecutor.execute(new ObjectiveProcessor(deviceId, nextObjective, installerExecutor));
Saurav Das1547b3f2017-05-05 17:01:08 -0700369 }
alshabib2a441c62015-04-13 18:39:38 -0700370 }
371
alshabibf6ea9e62015-04-21 17:08:26 -0700372 @Override
373 public int allocateNextId() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900374 checkPermission(FLOWRULE_WRITE);
alshabibf6ea9e62015-04-21 17:08:26 -0700375 return flowObjectiveStore.allocateNextId();
376 }
377
Xin Jin313708b2015-07-09 13:43:04 -0700378 @Override
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700379 public void initPolicy(String policy) {
380 }
Xin Jin313708b2015-07-09 13:43:04 -0700381
Charles Chancb1db5a2018-03-15 20:14:16 -0700382 boolean queueFwdObjective(DeviceId deviceId, ForwardingObjective fwd) {
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700383 boolean queued = false;
384 synchronized (pendingForwards) {
385 // double check the flow objective store, because this block could run
386 // after a notification arrives
387 if (flowObjectiveStore.getNextGroup(fwd.nextId()) == null) {
388 pendingForwards.compute(fwd.nextId(), (id, pending) -> {
Saurav Das1547b3f2017-05-05 17:01:08 -0700389 PendingFlowObjective pendfo = new PendingFlowObjective(deviceId, fwd);
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700390 if (pending == null) {
Pier Luigi23934ce2018-03-05 11:09:42 +0100391 return Sets.newLinkedHashSet(ImmutableSet.of(pendfo));
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700392 } else {
Saurav Das1547b3f2017-05-05 17:01:08 -0700393 pending.add(pendfo);
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700394 return pending;
395 }
396 });
397 queued = true;
398 }
399 }
400 if (queued) {
Saurav Dasf3f75942018-01-25 09:49:01 -0800401 log.debug("Queued forwarding objective {} for nextId {} meant for device {}",
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700402 fwd.id(), fwd.nextId(), deviceId);
403 }
404 return queued;
alshabib2a441c62015-04-13 18:39:38 -0700405 }
406
Charles Chancb1db5a2018-03-15 20:14:16 -0700407 boolean queueNextObjective(DeviceId deviceId, NextObjective next) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700408 // we need to hold off on other operations till we get notified that the
409 // initial group creation has succeeded
410 boolean queued = false;
411 synchronized (pendingNexts) {
412 // double check the flow objective store, because this block could run
413 // after a notification arrives
414 if (flowObjectiveStore.getNextGroup(next.id()) == null) {
415 pendingNexts.compute(next.id(), (id, pending) -> {
416 PendingFlowObjective pendfo = new PendingFlowObjective(deviceId, next);
417 if (pending == null) {
Saurav Das73a6cc12017-12-05 15:00:23 -0800418 return Lists.newArrayList(pendfo);
Saurav Das1547b3f2017-05-05 17:01:08 -0700419 } else {
420 pending.add(pendfo);
421 return pending;
422 }
423 });
424 queued = true;
425 }
426 }
427 if (queued) {
Saurav Dasf3f75942018-01-25 09:49:01 -0800428 log.debug("Queued next objective {} with operation {} meant for device {}",
Saurav Das1547b3f2017-05-05 17:01:08 -0700429 next.id(), next.op(), deviceId);
430 }
431 return queued;
432 }
433
Pier Ventre57a61cd2016-09-07 10:55:41 -0700434 /**
435 * Retrieves (if it exists) the device pipeline behaviour from the cache.
436 * Otherwise it warms the caches and triggers the init method of the Pipeline.
437 *
438 * @param deviceId the id of the device associated to the pipeline
439 * @return the implementation of the Pipeliner behaviour
440 */
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700441 private Pipeliner getDevicePipeliner(DeviceId deviceId) {
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700442 return pipeliners.computeIfAbsent(deviceId, this::initPipelineHandler);
alshabib77b88482015-04-07 15:47:50 -0700443 }
444
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700445 /**
Pier Ventre57a61cd2016-09-07 10:55:41 -0700446 * Retrieves (if it exists) the device pipeline behaviour from the cache and
447 * and triggers the init method of the pipeline. Otherwise (DEVICE_ADDED) it warms
448 * the caches and triggers the init method of the Pipeline. The rationale of this
449 * method is for managing the scenario of a switch that goes down for a failure
450 * and goes up after a while.
451 *
452 * @param deviceId the id of the device associated to the pipeline
453 * @return the implementation of the Pipeliner behaviour
454 */
455 private Pipeliner getAndInitDevicePipeliner(DeviceId deviceId) {
456 return pipeliners.compute(deviceId, (deviceIdValue, pipelinerValue) -> {
457 if (pipelinerValue != null) {
458 pipelinerValue.init(deviceId, context);
459 return pipelinerValue;
460 }
461 return this.initPipelineHandler(deviceId);
462 });
463 }
464
465 /**
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700466 * Creates and initialize {@link Pipeliner}.
467 * <p>
468 * Note: Expected to be called under per-Device lock.
469 * e.g., {@code pipeliners}' Map#compute family methods
470 *
471 * @param deviceId Device to initialize pipeliner
472 * @return {@link Pipeliner} instance or null
473 */
474 private Pipeliner initPipelineHandler(DeviceId deviceId) {
475 start = now();
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700476
Jonathan Hart17d00452015-04-21 17:10:00 -0700477 // Attempt to lookup the handler in the cache
478 DriverHandler handler = driverHandlers.get(deviceId);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700479 cTime = now();
480
Jonathan Hart17d00452015-04-21 17:10:00 -0700481 if (handler == null) {
482 try {
483 // Otherwise create it and if it has pipeline behaviour, cache it
484 handler = driverService.createHandler(deviceId);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700485 dTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700486 if (!handler.driver().hasBehaviour(Pipeliner.class)) {
Yuta HIGUCHIa2a4f342017-03-17 11:38:57 -0700487 log.debug("Pipeline behaviour not supported for device {}",
Jonathan Hart17d00452015-04-21 17:10:00 -0700488 deviceId);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700489 return null;
alshabib2a441c62015-04-13 18:39:38 -0700490 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700491 } catch (ItemNotFoundException e) {
492 log.warn("No applicable driver for device {}", deviceId);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700493 return null;
alshabib2a441c62015-04-13 18:39:38 -0700494 }
495
Jonathan Hart17d00452015-04-21 17:10:00 -0700496 driverHandlers.put(deviceId, handler);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700497 eTime = now();
alshabib2a441c62015-04-13 18:39:38 -0700498 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700499
500 // Always (re)initialize the pipeline behaviour
501 log.info("Driver {} bound to device {} ... initializing driver",
502 handler.driver().name(), deviceId);
Thomas Vachuska0121a612015-07-21 11:18:09 -0700503 hTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700504 Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
Thomas Vachuska94c3cf42015-07-20 13:01:12 -0700505 hbTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700506 pipeliner.init(deviceId, context);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700507 stopWatch();
508 return pipeliner;
alshabibaebe7752015-04-07 17:45:42 -0700509 }
alshabib77b88482015-04-07 15:47:50 -0700510
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700511 private void invalidatePipelinerIfNecessary(Device device) {
512 DriverHandler handler = driverHandlers.get(device.id());
513 if (handler != null &&
514 !Objects.equals(handler.driver().name(),
515 device.annotations().value(DRIVER))) {
516 invalidatePipeliner(device.id());
517 }
518 }
519
520 private void invalidatePipeliner(DeviceId id) {
521 log.info("Invalidating cached pipeline behaviour for {}", id);
522 driverHandlers.remove(id);
pier20511962020-05-11 13:49:37 +0200523 pipeliners.remove(id);
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700524 if (deviceService.isAvailable(id)) {
525 getAndInitDevicePipeliner(id);
526 }
527 }
528
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700529 // Triggers driver setup when a device is (re)detected.
alshabibaebe7752015-04-07 17:45:42 -0700530 private class InnerDeviceListener implements DeviceListener {
531 @Override
532 public void event(DeviceEvent event) {
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000533 if (devEventExecutor != null) {
alshabibaebe7752015-04-07 17:45:42 -0700534 switch (event.type()) {
535 case DEVICE_ADDED:
536 case DEVICE_AVAILABILITY_CHANGED:
Madan Jampani0174f452015-05-29 11:52:05 -0700537 log.debug("Device either added or availability changed {}",
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700538 event.subject().id());
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000539 devEventExecutor.execute(() -> {
540 if (deviceService.isAvailable(event.subject().id())) {
Madan Jampani0174f452015-05-29 11:52:05 -0700541 log.debug("Device is now available {}", event.subject().id());
Pier Ventre57a61cd2016-09-07 10:55:41 -0700542 getAndInitDevicePipeliner(event.subject().id());
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000543 } else {
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700544 log.debug("Device is no longer available {}", event.subject().id());
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000545 }
546 });
alshabib4313d102015-04-08 18:55:08 -0700547 break;
548 case DEVICE_UPDATED:
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700549 // Invalidate pipeliner and handler caches if the driver name
550 // device annotation changed.
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000551 devEventExecutor.execute(() -> invalidatePipelinerIfNecessary(event.subject()));
alshabib4313d102015-04-08 18:55:08 -0700552 break;
553 case DEVICE_REMOVED:
Yuta HIGUCHIad0c9902016-08-23 10:37:32 -0700554 // evict Pipeliner and Handler cache, when
555 // the Device was administratively removed.
556 //
557 // System expect the user to clear all existing flows,
558 // before removing device, especially if they intend to
559 // replace driver/pipeliner assigned to the device.
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000560 devEventExecutor.execute(() -> {
pier95e62512020-03-20 11:00:38 +0100561 driverHandlers.remove(event.subject().id());
pier20511962020-05-11 13:49:37 +0200562 pipeliners.remove(event.subject().id());
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000563 });
alshabib4313d102015-04-08 18:55:08 -0700564 break;
Yuta HIGUCHIad0c9902016-08-23 10:37:32 -0700565 case DEVICE_SUSPENDED:
566 break;
alshabib4313d102015-04-08 18:55:08 -0700567 case PORT_ADDED:
568 break;
569 case PORT_UPDATED:
570 break;
571 case PORT_REMOVED:
alshabibaebe7752015-04-07 17:45:42 -0700572 break;
573 default:
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700574 break;
alshabibaebe7752015-04-07 17:45:42 -0700575 }
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000576 }
alshabib77b88482015-04-07 15:47:50 -0700577 }
578 }
alshabibaebe7752015-04-07 17:45:42 -0700579
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700580 // Monitors driver configuration changes and invalidates the pipeliner cache entries.
581 // Note that this may leave stale entries on the device if the driver changes
582 // in manner where the new driver does not produce backward compatible flow objectives.
583 // In such cases, it is the operator's responsibility to force device re-connect.
584 private class InnerDriverListener implements DriverListener {
585 @Override
586 public void event(DriverEvent event) {
587 String driverName = event.subject().name();
588 driverHandlers.entrySet().stream()
589 .filter(e -> driverName.equals(e.getValue().driver().name()))
590 .map(Map.Entry::getKey)
591 .distinct()
592 .forEach(FlowObjectiveManager.this::invalidatePipeliner);
593 }
594 }
595
Thomas Vachuska174bb912015-07-16 21:27:14 -0700596 // Temporary mechanism to monitor pipeliner setup time-cost; there are
597 // intermittent time where this takes in excess of 2 seconds. Why?
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700598 private long start = 0, totals = 0, count = 0;
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700599 private long cTime, dTime, eTime, hTime, hbTime;
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700600 private static final long LIMIT = 500;
Thomas Vachuska174bb912015-07-16 21:27:14 -0700601
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700602 private long now() {
Thomas Vachuska174bb912015-07-16 21:27:14 -0700603 return System.currentTimeMillis();
604 }
605
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700606 private void stopWatch() {
Thomas Vachuska174bb912015-07-16 21:27:14 -0700607 long duration = System.currentTimeMillis() - start;
608 totals += duration;
609 count += 1;
610 if (duration > LIMIT) {
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700611 log.info("Pipeline setup took {} ms; avg {} ms; cTime={}, dTime={}, eTime={}, hTime={}, hbTime={}",
612 duration, totals / count, diff(cTime), diff(dTime), diff(eTime), diff(hTime), diff(hbTime));
Thomas Vachuska174bb912015-07-16 21:27:14 -0700613 }
614 }
615
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700616 private long diff(long bTime) {
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700617 long diff = bTime - start;
618 return diff < 0 ? 0 : diff;
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700619 }
620
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700621 // Processing context for initializing pipeline driver behaviours.
622 private class InnerPipelineContext implements PipelinerContext {
pier5b9b9e32019-03-11 15:14:02 -0700623
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700624 @Override
625 public ServiceDirectory directory() {
626 return serviceDirectory;
alshabibaebe7752015-04-07 17:45:42 -0700627 }
alshabib2a441c62015-04-13 18:39:38 -0700628
629 @Override
630 public FlowObjectiveStore store() {
631 return flowObjectiveStore;
632 }
pier5b9b9e32019-03-11 15:14:02 -0700633
634 @Override
635 public int accumulatorMaxObjectives() {
636 return accumulatorMaxObjectives;
637 }
638
639 @Override
640 public int accumulatorMaxIdleMillis() {
641 return accumulatorMaxIdleMillis;
642 }
643
644 @Override
645 public int accumulatorMaxBatchMillis() {
646 return accumulatorMaxBatchMillis;
647 }
alshabib2a441c62015-04-13 18:39:38 -0700648 }
649
650 private class InternalStoreDelegate implements FlowObjectiveStoreDelegate {
651 @Override
652 public void notify(ObjectiveEvent event) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800653 if (event.type() == Type.ADD) {
654 log.debug("Received notification of obj event {}", event);
Saurav Das1547b3f2017-05-05 17:01:08 -0700655 Set<PendingFlowObjective> pending;
656
657 // first send all pending flows
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700658 synchronized (pendingForwards) {
659 // needs to be synchronized for queueObjective lookup
660 pending = pendingForwards.remove(event.subject());
661 }
Saurav Das423fe2b2015-12-04 10:52:59 -0800662 if (pending == null) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700663 log.debug("No forwarding objectives pending for this "
664 + "obj event {}", event);
665 } else {
666 log.debug("Processing {} pending forwarding objectives for nextId {}",
667 pending.size(), event.subject());
668 pending.forEach(p -> getDevicePipeliner(p.deviceId())
669 .forward((ForwardingObjective) p.flowObjective()));
Saurav Das423fe2b2015-12-04 10:52:59 -0800670 }
671
Saurav Das1547b3f2017-05-05 17:01:08 -0700672 // now check for pending next-objectives
Saurav Das73a6cc12017-12-05 15:00:23 -0800673 List<PendingFlowObjective> pendNexts;
Saurav Das1547b3f2017-05-05 17:01:08 -0700674 synchronized (pendingNexts) {
675 // needs to be synchronized for queueObjective lookup
Saurav Das73a6cc12017-12-05 15:00:23 -0800676 pendNexts = pendingNexts.remove(event.subject());
Saurav Das1547b3f2017-05-05 17:01:08 -0700677 }
Saurav Das73a6cc12017-12-05 15:00:23 -0800678 if (pendNexts == null) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700679 log.debug("No next objectives pending for this "
680 + "obj event {}", event);
681 } else {
682 log.debug("Processing {} pending next objectives for nextId {}",
Saurav Das73a6cc12017-12-05 15:00:23 -0800683 pendNexts.size(), event.subject());
684 pendNexts.forEach(p -> getDevicePipeliner(p.deviceId())
Saurav Das1547b3f2017-05-05 17:01:08 -0700685 .next((NextObjective) p.flowObjective()));
686 }
alshabib2a441c62015-04-13 18:39:38 -0700687 }
alshabib2a441c62015-04-13 18:39:38 -0700688 }
689 }
690
691 /**
Saurav Das1547b3f2017-05-05 17:01:08 -0700692 * Data class used to hold a pending flow objective that could not
alshabib2a441c62015-04-13 18:39:38 -0700693 * be processed because the associated next object was not present.
Saurav Das1547b3f2017-05-05 17:01:08 -0700694 * Note that this pending flow objective could be a forwarding objective
695 * waiting for a next objective to complete execution. Or it could a
696 * next objective (with a different operation - remove, addToExisting, or
697 * removeFromExisting) waiting for a next objective with the same id to
698 * complete execution.
alshabib2a441c62015-04-13 18:39:38 -0700699 */
Charles Chancb1db5a2018-03-15 20:14:16 -0700700 protected class PendingFlowObjective {
alshabib2a441c62015-04-13 18:39:38 -0700701 private final DeviceId deviceId;
Saurav Das1547b3f2017-05-05 17:01:08 -0700702 private final Objective flowObj;
alshabib2a441c62015-04-13 18:39:38 -0700703
Charles Chancb1db5a2018-03-15 20:14:16 -0700704 PendingFlowObjective(DeviceId deviceId, Objective flowObj) {
alshabib2a441c62015-04-13 18:39:38 -0700705 this.deviceId = deviceId;
Saurav Das1547b3f2017-05-05 17:01:08 -0700706 this.flowObj = flowObj;
alshabib2a441c62015-04-13 18:39:38 -0700707 }
708
709 public DeviceId deviceId() {
710 return deviceId;
711 }
712
Saurav Das1547b3f2017-05-05 17:01:08 -0700713 public Objective flowObjective() {
714 return flowObj;
alshabib2a441c62015-04-13 18:39:38 -0700715 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800716
717 @Override
718 public int hashCode() {
Saurav Das1547b3f2017-05-05 17:01:08 -0700719 return Objects.hash(deviceId, flowObj);
Saurav Das8a0732e2015-11-20 15:27:53 -0800720 }
721
722 @Override
723 public boolean equals(final Object obj) {
724 if (this == obj) {
725 return true;
726 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700727 if (!(obj instanceof PendingFlowObjective)) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800728 return false;
729 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700730 final PendingFlowObjective other = (PendingFlowObjective) obj;
Charles Chancb1db5a2018-03-15 20:14:16 -0700731
732 return this.deviceId.equals(other.deviceId) &&
733 this.flowObj.equals(other.flowObj);
Saurav Das8a0732e2015-11-20 15:27:53 -0800734 }
alshabibaebe7752015-04-07 17:45:42 -0700735 }
Saurav Das24431192016-03-07 19:13:00 -0800736
737 @Override
738 public List<String> getNextMappings() {
739 List<String> mappings = new ArrayList<>();
740 Map<Integer, NextGroup> allnexts = flowObjectiveStore.getAllGroups();
Saurav Das25190812016-05-27 13:54:07 -0700741 // XXX if the NextGroup after de-serialization actually stored info of the deviceId
Saurav Das24431192016-03-07 19:13:00 -0800742 // then info on any nextObj could be retrieved from one controller instance.
743 // Right now the drivers on one instance can only fetch for next-ids that came
744 // to them.
745 // Also, we still need to send the right next-id to the right driver as potentially
746 // there can be different drivers for different devices. But on that account,
747 // no instance should be decoding for another instance's nextIds.
748
749 for (Map.Entry<Integer, NextGroup> e : allnexts.entrySet()) {
750 // get the device this next Objective was sent to
751 DeviceId deviceId = nextToDevice.get(e.getKey());
752 mappings.add("NextId " + e.getKey() + ": " +
753 ((deviceId != null) ? deviceId : "nextId not in this onos instance"));
754 if (deviceId != null) {
755 // this instance of the controller sent the nextObj to a driver
756 Pipeliner pipeliner = getDevicePipeliner(deviceId);
757 List<String> nextMappings = pipeliner.getNextMappings(e.getValue());
758 if (nextMappings != null) {
759 mappings.addAll(nextMappings);
760 }
761 }
762 }
763 return mappings;
764 }
Saurav Dasb5c236e2016-06-07 10:08:06 -0700765
766 @Override
Harshada Chaundkar0acb3262019-07-03 16:27:45 +0000767 public Map<Pair<Integer, DeviceId>, List<String>> getNextMappingsChain() {
768 Map<Pair<Integer, DeviceId>, List<String>> nextObjGroupMap = new HashMap<>();
769 Map<Integer, NextGroup> allnexts = flowObjectiveStore.getAllGroups();
770
771 // XXX if the NextGroup after de-serialization actually stored info of the deviceId
772 // then info on any nextObj could be retrieved from one controller instance.
773 // Right now the drivers on one instance can only fetch for next-ids that came
774 // to them.
775 // Also, we still need to send the right next-id to the right driver as potentially
776 // there can be different drivers for different devices. But on that account,
777 // no instance should be decoding for another instance's nextIds.
778
779 for (Map.Entry<Integer, NextGroup> e : allnexts.entrySet()) {
780 // get the device this next Objective was sent to
781 DeviceId deviceId = nextToDevice.get(e.getKey());
782 if (deviceId != null) {
783 // this instance of the controller sent the nextObj to a driver
784 Pipeliner pipeliner = getDevicePipeliner(deviceId);
785 List<String> nextMappings = pipeliner.getNextMappings(e.getValue());
786 if (nextMappings != null) {
787 //mappings.addAll(nextMappings);
788 nextObjGroupMap.put(Pair.of(e.getKey(), deviceId), nextMappings);
789 }
790 } else {
791 nextObjGroupMap.put(Pair.of(e.getKey(), deviceId), ImmutableList.of("nextId not in this onos instance"));
792 }
793 }
794 return nextObjGroupMap;
795 }
796
797
798 @Override
Saurav Das1547b3f2017-05-05 17:01:08 -0700799 public List<String> getPendingFlowObjectives() {
800 List<String> pendingFlowObjectives = new ArrayList<>();
Charles Chan54734712017-03-29 11:07:55 -0700801
Saurav Das1547b3f2017-05-05 17:01:08 -0700802 for (Integer nextId : pendingForwards.keySet()) {
803 Set<PendingFlowObjective> pfwd = pendingForwards.get(nextId);
Sho SHIMIZU81470a52016-08-12 17:24:55 -0700804 StringBuilder pend = new StringBuilder();
Charles Chan54734712017-03-29 11:07:55 -0700805 pend.append("NextId: ")
806 .append(nextId);
Saurav Das1547b3f2017-05-05 17:01:08 -0700807 for (PendingFlowObjective pf : pfwd) {
Charles Chan54734712017-03-29 11:07:55 -0700808 pend.append("\n FwdId: ")
Saurav Das1547b3f2017-05-05 17:01:08 -0700809 .append(String.format("%11s", pf.flowObjective().id()))
810 .append(", DeviceId: ")
811 .append(pf.deviceId())
812 .append(", Selector: ")
813 .append(((ForwardingObjective) pf.flowObjective())
814 .selector().criteria());
815 }
816 pendingFlowObjectives.add(pend.toString());
817 }
818
819 for (Integer nextId : pendingNexts.keySet()) {
Saurav Das73a6cc12017-12-05 15:00:23 -0800820 List<PendingFlowObjective> pnext = pendingNexts.get(nextId);
Saurav Das1547b3f2017-05-05 17:01:08 -0700821 StringBuilder pend = new StringBuilder();
822 pend.append("NextId: ")
823 .append(nextId);
824 for (PendingFlowObjective pn : pnext) {
825 pend.append("\n NextOp: ")
826 .append(pn.flowObjective().op())
Charles Chan54734712017-03-29 11:07:55 -0700827 .append(", DeviceId: ")
828 .append(pn.deviceId())
Saurav Das1547b3f2017-05-05 17:01:08 -0700829 .append(", Treatments: ")
830 .append(((NextObjective) pn.flowObjective())
831 .next());
Saurav Dasb5c236e2016-06-07 10:08:06 -0700832 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700833 pendingFlowObjectives.add(pend.toString());
Saurav Dasb5c236e2016-06-07 10:08:06 -0700834 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700835
836 return pendingFlowObjectives;
837 }
alshabib77b88482015-04-07 15:47:50 -0700838}