blob: 597e91e5f301ae9dde3d7867670b3830aae5db08 [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;
Harshada Chaundkar5a198b02019-07-03 16:27:45 +000019import com.google.common.collect.ImmutableList;
Saurav Dasf14d9ef2017-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 Chaundkar5a198b02019-07-03 16:27:45 +000023import org.apache.commons.lang3.tuple.Pair;
alshabib77b88482015-04-07 15:47:50 -070024import org.onlab.osgi.DefaultServiceDirectory;
25import org.onlab.osgi.ServiceDirectory;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070026import org.onlab.util.ItemNotFoundException;
Yi Tseng374c5f32017-03-05 22:51:35 -080027import org.onlab.util.Tools;
28import org.onosproject.cfg.ComponentConfigService;
alshabib77b88482015-04-07 15:47:50 -070029import org.onosproject.cluster.ClusterService;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070030import org.onosproject.net.Device;
alshabib77b88482015-04-07 15:47:50 -070031import org.onosproject.net.DeviceId;
Saurav Das24431192016-03-07 19:13:00 -080032import org.onosproject.net.behaviour.NextGroup;
alshabib77b88482015-04-07 15:47:50 -070033import org.onosproject.net.behaviour.Pipeliner;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070034import org.onosproject.net.behaviour.PipelinerContext;
alshabibaebe7752015-04-07 17:45:42 -070035import org.onosproject.net.device.DeviceEvent;
36import org.onosproject.net.device.DeviceListener;
alshabib77b88482015-04-07 15:47:50 -070037import org.onosproject.net.device.DeviceService;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070038import org.onosproject.net.driver.DriverEvent;
alshabib77b88482015-04-07 15:47:50 -070039import org.onosproject.net.driver.DriverHandler;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070040import org.onosproject.net.driver.DriverListener;
alshabib77b88482015-04-07 15:47:50 -070041import org.onosproject.net.driver.DriverService;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070042import org.onosproject.net.flow.FlowRuleService;
alshabib77b88482015-04-07 15:47:50 -070043import org.onosproject.net.flowobjective.FilteringObjective;
44import org.onosproject.net.flowobjective.FlowObjectiveService;
alshabib2a441c62015-04-13 18:39:38 -070045import org.onosproject.net.flowobjective.FlowObjectiveStore;
46import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate;
alshabib77b88482015-04-07 15:47:50 -070047import org.onosproject.net.flowobjective.ForwardingObjective;
48import org.onosproject.net.flowobjective.NextObjective;
alshabib910aff12015-04-09 16:55:57 -070049import org.onosproject.net.flowobjective.Objective;
Saurav Das1547b3f2017-05-05 17:01:08 -070050import org.onosproject.net.flowobjective.Objective.Operation;
Jonathan Hart17d00452015-04-21 17:10:00 -070051import org.onosproject.net.flowobjective.ObjectiveError;
alshabib2a441c62015-04-13 18:39:38 -070052import org.onosproject.net.flowobjective.ObjectiveEvent;
Saurav Das423fe2b2015-12-04 10:52:59 -080053import org.onosproject.net.flowobjective.ObjectiveEvent.Type;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070054import org.onosproject.net.group.GroupService;
Yi Tseng374c5f32017-03-05 22:51:35 -080055import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070056import org.osgi.service.component.annotations.Activate;
57import org.osgi.service.component.annotations.Component;
58import org.osgi.service.component.annotations.Deactivate;
59import org.osgi.service.component.annotations.Modified;
60import org.osgi.service.component.annotations.Reference;
61import org.osgi.service.component.annotations.ReferenceCardinality;
alshabib77b88482015-04-07 15:47:50 -070062import org.slf4j.Logger;
63import org.slf4j.LoggerFactory;
64
Saurav Das24431192016-03-07 19:13:00 -080065import java.util.ArrayList;
Saurav Das24431192016-03-07 19:13:00 -080066import java.util.List;
alshabib77b88482015-04-07 15:47:50 -070067import java.util.Map;
Saurav Das8a0732e2015-11-20 15:27:53 -080068import java.util.Objects;
alshabib2a441c62015-04-13 18:39:38 -070069import java.util.Set;
Harshada Chaundkar5a198b02019-07-03 16:27:45 +000070import java.util.HashMap;
Jonathan Hart17d00452015-04-21 17:10:00 -070071import java.util.concurrent.ExecutorService;
alshabib77b88482015-04-07 15:47:50 -070072
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -070073import static com.google.common.base.Preconditions.checkNotNull;
Yi Tseng374c5f32017-03-05 22:51:35 -080074import static com.google.common.base.Strings.isNullOrEmpty;
Thomas Vachuska866b46a2015-04-30 00:26:55 -070075import static java.util.concurrent.Executors.newFixedThreadPool;
Ruchi Sahotae4934e12019-03-01 16:56:07 +000076import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Jonathan Hart17d00452015-04-21 17:10:00 -070077import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuskacfeff192017-08-23 15:29:34 -070078import static org.onosproject.net.AnnotationKeys.DRIVER;
Ray Milkeyd04e2272018-10-16 18:20:18 -070079import static org.onosproject.net.OsgiPropertyConstants.FOM_NUM_THREADS;
80import static org.onosproject.net.OsgiPropertyConstants.FOM_NUM_THREADS_DEFAULT;
pier8b3aef42019-03-11 15:14:02 -070081import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_OBJECTIVES;
82import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_OBJECTIVES_DEFAULT;
83import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_IDLE_MILLIS;
84import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_IDLE_MILLIS_DEFAULT;
85import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_BATCH_MILLIS;
86import static org.onosproject.net.OsgiPropertyConstants.FOM_ACCUMULATOR_MAX_BATCH_MILLIS_DEFAULT;
Changhoon Yoon541ef712015-05-23 17:18:34 +090087import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuskad27097c2016-06-14 19:10:41 -070088import static org.onosproject.security.AppPermission.Type.FLOWRULE_WRITE;
alshabib77b88482015-04-07 15:47:50 -070089
90/**
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070091 * Provides implementation of the flow objective programming service.
alshabib77b88482015-04-07 15:47:50 -070092 */
Ray Milkeyd04e2272018-10-16 18:20:18 -070093@Component(
94 enabled = false,
95 service = FlowObjectiveService.class,
96 property = {
pier8b3aef42019-03-11 15:14:02 -070097 FOM_NUM_THREADS + ":Integer=" + FOM_NUM_THREADS_DEFAULT,
98 FOM_ACCUMULATOR_MAX_OBJECTIVES + ":Integer=" + FOM_ACCUMULATOR_MAX_OBJECTIVES_DEFAULT,
99 FOM_ACCUMULATOR_MAX_IDLE_MILLIS + ":Integer=" + FOM_ACCUMULATOR_MAX_IDLE_MILLIS_DEFAULT,
100 FOM_ACCUMULATOR_MAX_BATCH_MILLIS + ":Integer=" + FOM_ACCUMULATOR_MAX_BATCH_MILLIS_DEFAULT,
Ray Milkeyd04e2272018-10-16 18:20:18 -0700101 }
102)
alshabib77b88482015-04-07 15:47:50 -0700103public class FlowObjectiveManager implements FlowObjectiveService {
104
Charles Chana7903c82018-03-15 20:14:16 -0700105 private static final int INSTALL_RETRY_ATTEMPTS = 5;
106 private static final long INSTALL_RETRY_INTERVAL = 1000; // ms
alshabib77b88482015-04-07 15:47:50 -0700107
piera6b11992020-01-27 17:45:03 +0100108 private static final String INSTALLER_PATTERN = "installer-%d";
109 private static final String VERIFIER_PATTERN = "verifier-%d";
110 private static final String GROUP_THREAD_NAME = "onos/objective";
Yi Tseng374c5f32017-03-05 22:51:35 -0800111
Jonathan Hart17d00452015-04-21 17:10:00 -0700112 private final Logger log = LoggerFactory.getLogger(getClass());
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700113
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700114 /** Number of worker threads. */
Ray Milkeyd04e2272018-10-16 18:20:18 -0700115 private int numThreads = FOM_NUM_THREADS_DEFAULT;
Yi Tseng374c5f32017-03-05 22:51:35 -0800116
pier8b3aef42019-03-11 15:14:02 -0700117 // Parameters for the accumulator, each pipeline can implement
118 // its own accumulation logic. The following parameters are used
119 // to control the accumulator.
120
pierventre13a72352020-10-27 16:08:48 +0100121 /** Max number of objs to accumulate before processing is triggered. */
pier8b3aef42019-03-11 15:14:02 -0700122 private int accumulatorMaxObjectives = FOM_ACCUMULATOR_MAX_OBJECTIVES_DEFAULT;
pierventre13a72352020-10-27 16:08:48 +0100123 /** Max of ms between objs before processing is triggered. */
pier8b3aef42019-03-11 15:14:02 -0700124 private int accumulatorMaxIdleMillis = FOM_ACCUMULATOR_MAX_IDLE_MILLIS_DEFAULT;
pierventre13a72352020-10-27 16:08:48 +0100125 /** Max number of ms allowed since the first obj before processing is triggered. */
pier8b3aef42019-03-11 15:14:02 -0700126 private int accumulatorMaxBatchMillis = FOM_ACCUMULATOR_MAX_BATCH_MILLIS_DEFAULT;
127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib77b88482015-04-07 15:47:50 -0700129 protected DriverService driverService;
130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib77b88482015-04-07 15:47:50 -0700132 protected DeviceService deviceService;
133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib77b88482015-04-07 15:47:50 -0700135 protected ClusterService clusterService;
136
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700137 // Note: The following dependencies are added on behalf of the pipeline
138 // driver behaviours to assure these services are available for their
139 // initialization.
Charles Chana7903c82018-03-15 20:14:16 -0700140 @SuppressWarnings("unused")
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700142 protected FlowRuleService flowRuleService;
143
Charles Chana7903c82018-03-15 20:14:16 -0700144 @SuppressWarnings("unused")
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700146 protected GroupService groupService;
147
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib2a441c62015-04-13 18:39:38 -0700149 protected FlowObjectiveStore flowObjectiveStore;
150
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700151 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng374c5f32017-03-05 22:51:35 -0800152 protected ComponentConfigService cfgService;
153
Charles Chana7903c82018-03-15 20:14:16 -0700154 final FlowObjectiveStoreDelegate delegate = new InternalStoreDelegate();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700155
156 private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap();
Charles Chana7903c82018-03-15 20:14:16 -0700157 protected final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700158
159 private final PipelinerContext context = new InnerPipelineContext();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700160 private final DeviceListener deviceListener = new InnerDeviceListener();
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700161 private final DriverListener driverListener = new InnerDriverListener();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700162
Charles Chana7903c82018-03-15 20:14:16 -0700163 private ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
alshabib910aff12015-04-09 16:55:57 -0700164
Saurav Das1547b3f2017-05-05 17:01:08 -0700165 // local stores for queuing fwd and next objectives that are waiting for an
166 // associated next objective execution to complete. The signal for completed
167 // execution comes from a pipeline driver, in this or another controller
168 // instance, via the DistributedFlowObjectiveStore.
Charles Chana7903c82018-03-15 20:14:16 -0700169 // TODO Making these cache and timeout the entries
170 final Map<Integer, Set<PendingFlowObjective>> pendingForwards = Maps.newConcurrentMap();
171 final Map<Integer, List<PendingFlowObjective>> pendingNexts = Maps.newConcurrentMap();
alshabib2a441c62015-04-13 18:39:38 -0700172
Saurav Das24431192016-03-07 19:13:00 -0800173 // local store to track which nextObjectives were sent to which device
174 // for debugging purposes
175 private Map<Integer, DeviceId> nextToDevice = Maps.newConcurrentMap();
176
piera6b11992020-01-27 17:45:03 +0100177 ExecutorService installerExecutor;
178 ExecutorService verifierExecutor;
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000179 protected ExecutorService devEventExecutor;
alshabib2a441c62015-04-13 18:39:38 -0700180
alshabib77b88482015-04-07 15:47:50 -0700181 @Activate
pier8b3aef42019-03-11 15:14:02 -0700182 protected void activate(ComponentContext context) {
Ray Milkey1f0764a2019-03-01 08:40:37 -0800183 cfgService.registerProperties(FlowObjectiveManager.class);
piera6b11992020-01-27 17:45:03 +0100184 installerExecutor = newFixedThreadPool(numThreads,
185 groupedThreads(GROUP_THREAD_NAME, INSTALLER_PATTERN, log));
186 verifierExecutor = newFixedThreadPool(numThreads,
187 groupedThreads(GROUP_THREAD_NAME, VERIFIER_PATTERN, log));
188
pier8b3aef42019-03-11 15:14:02 -0700189 modified(context);
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000190 devEventExecutor = newSingleThreadScheduledExecutor(
191 groupedThreads("onos/flowobj-dev-events", "events-%d", log));
alshabib2a441c62015-04-13 18:39:38 -0700192 flowObjectiveStore.setDelegate(delegate);
alshabibaebe7752015-04-07 17:45:42 -0700193 deviceService.addListener(deviceListener);
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700194 driverService.addListener(driverListener);
alshabib77b88482015-04-07 15:47:50 -0700195 log.info("Started");
196 }
197
198 @Deactivate
199 protected void deactivate() {
Yi Tseng374c5f32017-03-05 22:51:35 -0800200 cfgService.unregisterProperties(getClass(), false);
alshabib2a441c62015-04-13 18:39:38 -0700201 flowObjectiveStore.unsetDelegate(delegate);
alshabibaebe7752015-04-07 17:45:42 -0700202 deviceService.removeListener(deviceListener);
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700203 driverService.removeListener(driverListener);
piera6b11992020-01-27 17:45:03 +0100204 installerExecutor.shutdown();
205 verifierExecutor.shutdown();
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000206 devEventExecutor.shutdownNow();
207 devEventExecutor = null;
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700208 pipeliners.clear();
209 driverHandlers.clear();
Saurav Das24431192016-03-07 19:13:00 -0800210 nextToDevice.clear();
alshabib77b88482015-04-07 15:47:50 -0700211 log.info("Stopped");
212 }
213
Yi Tseng374c5f32017-03-05 22:51:35 -0800214 @Modified
215 protected void modified(ComponentContext context) {
pier8b3aef42019-03-11 15:14:02 -0700216 if (context != null) {
217 readComponentConfiguration(context);
218 }
219 }
220
221 /**
222 * Extracts properties from the component configuration context.
223 *
224 * @param context the component context
225 */
pierventre13a72352020-10-27 16:08:48 +0100226 protected void readComponentConfiguration(ComponentContext context) {
pier8b3aef42019-03-11 15:14:02 -0700227 String propertyValue = Tools.get(context.getProperties(), FOM_NUM_THREADS);
Yi Tseng374c5f32017-03-05 22:51:35 -0800228 int newNumThreads = isNullOrEmpty(propertyValue) ? numThreads : Integer.parseInt(propertyValue);
229
230 if (newNumThreads != numThreads && newNumThreads > 0) {
231 numThreads = newNumThreads;
piera6b11992020-01-27 17:45:03 +0100232 ExecutorService oldWorkerExecutor = installerExecutor;
233 installerExecutor = newFixedThreadPool(numThreads,
234 groupedThreads(GROUP_THREAD_NAME, INSTALLER_PATTERN, log));
235 if (oldWorkerExecutor != null) {
236 oldWorkerExecutor.shutdown();
237 }
238 oldWorkerExecutor = verifierExecutor;
239 verifierExecutor = newFixedThreadPool(numThreads,
240 groupedThreads(GROUP_THREAD_NAME, VERIFIER_PATTERN, log));
Yi Tseng374c5f32017-03-05 22:51:35 -0800241 if (oldWorkerExecutor != null) {
242 oldWorkerExecutor.shutdown();
243 }
244 log.info("Reconfigured number of worker threads to {}", numThreads);
245 }
pier8b3aef42019-03-11 15:14:02 -0700246
247 // Reconfiguration of the accumulator parameters is allowed
248 // Note: it will affect only pipelines going through init method
249 propertyValue = Tools.get(context.getProperties(), FOM_ACCUMULATOR_MAX_OBJECTIVES);
250 int newMaxObjs = isNullOrEmpty(propertyValue) ?
251 accumulatorMaxObjectives : Integer.parseInt(propertyValue);
252 if (newMaxObjs != accumulatorMaxObjectives && newMaxObjs > 0) {
253 accumulatorMaxObjectives = newMaxObjs;
254 log.info("Reconfigured maximum number of objectives to accumulate to {}",
255 accumulatorMaxObjectives);
256 }
257
258 propertyValue = Tools.get(context.getProperties(), FOM_ACCUMULATOR_MAX_IDLE_MILLIS);
259 int newMaxIdleMS = isNullOrEmpty(propertyValue) ?
260 accumulatorMaxIdleMillis : Integer.parseInt(propertyValue);
261 if (newMaxIdleMS != accumulatorMaxIdleMillis && newMaxIdleMS > 0) {
262 accumulatorMaxIdleMillis = newMaxIdleMS;
263 log.info("Reconfigured maximum number of millis between objectives to {}",
264 accumulatorMaxIdleMillis);
265 }
266
267 propertyValue = Tools.get(context.getProperties(), FOM_ACCUMULATOR_MAX_BATCH_MILLIS);
268 int newMaxBatchMS = isNullOrEmpty(propertyValue) ?
269 accumulatorMaxBatchMillis : Integer.parseInt(propertyValue);
270 if (newMaxBatchMS != accumulatorMaxBatchMillis && newMaxBatchMS > 0) {
271 accumulatorMaxBatchMillis = newMaxBatchMS;
272 log.info("Reconfigured maximum number of millis allowed since the first objective to {}",
273 accumulatorMaxBatchMillis);
274 }
275
Yi Tseng374c5f32017-03-05 22:51:35 -0800276 }
277
Jonathan Hart17d00452015-04-21 17:10:00 -0700278 /**
279 * Task that passes the flow objective down to the driver. The task will
280 * make a few attempts to find the appropriate driver, then eventually give
281 * up and report an error if no suitable driver could be found.
282 */
piera6b11992020-01-27 17:45:03 +0100283 class ObjectiveProcessor implements Runnable {
Charles Chana7903c82018-03-15 20:14:16 -0700284 final DeviceId deviceId;
285 final Objective objective;
piera6b11992020-01-27 17:45:03 +0100286 final ExecutorService executor;
Jonathan Hart17d00452015-04-21 17:10:00 -0700287
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700288 private final int numAttempts;
Jonathan Hart17d00452015-04-21 17:10:00 -0700289
piera6b11992020-01-27 17:45:03 +0100290 ObjectiveProcessor(DeviceId deviceId, Objective objective,
291 ExecutorService executorService) {
292 this(deviceId, objective, 1, executorService);
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700293 }
294
piera6b11992020-01-27 17:45:03 +0100295 ObjectiveProcessor(DeviceId deviceId, Objective objective, int attempts,
296 ExecutorService executorService) {
Sho SHIMIZUf45d85d2015-07-01 14:39:11 -0700297 this.deviceId = checkNotNull(deviceId);
298 this.objective = checkNotNull(objective);
piera6b11992020-01-27 17:45:03 +0100299 this.executor = checkNotNull(executorService);
300 this.numAttempts = attempts;
alshabib910aff12015-04-09 16:55:57 -0700301 }
alshabib77b88482015-04-07 15:47:50 -0700302
Jonathan Hart17d00452015-04-21 17:10:00 -0700303 @Override
304 public void run() {
305 try {
Jonathan Hart17d00452015-04-21 17:10:00 -0700306 Pipeliner pipeliner = getDevicePipeliner(deviceId);
307
pier561c8812020-05-20 22:50:30 +0200308 if (pipeliner != null) {
Jonathan Hart17d00452015-04-21 17:10:00 -0700309 if (objective instanceof NextObjective) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700310 nextToDevice.put(objective.id(), deviceId);
Jonathan Hart17d00452015-04-21 17:10:00 -0700311 pipeliner.next((NextObjective) objective);
312 } else if (objective instanceof ForwardingObjective) {
313 pipeliner.forward((ForwardingObjective) objective);
314 } else {
315 pipeliner.filter((FilteringObjective) objective);
316 }
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800317 //Attempts to check if pipeliner is null for retry attempts
Jonathan Hart17d00452015-04-21 17:10:00 -0700318 } else if (numAttempts < INSTALL_RETRY_ATTEMPTS) {
Saurav Das3d038262015-04-23 12:36:58 -0700319 Thread.sleep(INSTALL_RETRY_INTERVAL);
piera6b11992020-01-27 17:45:03 +0100320 executor.execute(new ObjectiveProcessor(deviceId, objective,
321 numAttempts + 1, executor));
Jonathan Hart17d00452015-04-21 17:10:00 -0700322 } else {
323 // Otherwise we've tried a few times and failed, report an
324 // error back to the user.
325 objective.context().ifPresent(
Andrea Campanella1f8188d2016-02-29 13:24:54 -0800326 c -> c.onError(objective, ObjectiveError.NOPIPELINER));
Jonathan Hart17d00452015-04-21 17:10:00 -0700327 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700328 //Exception thrown
Jonathan Hart17d00452015-04-21 17:10:00 -0700329 } catch (Exception e) {
piera6b11992020-01-27 17:45:03 +0100330 log.warn("Exception while processing flow objective", e);
Jonathan Hart17d00452015-04-21 17:10:00 -0700331 }
332 }
333 }
334
335 @Override
336 public void filter(DeviceId deviceId, FilteringObjective filteringObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900337 checkPermission(FLOWRULE_WRITE);
piera6b11992020-01-27 17:45:03 +0100338 installerExecutor.execute(new ObjectiveProcessor(deviceId, filteringObjective, installerExecutor));
alshabib77b88482015-04-07 15:47:50 -0700339 }
340
341 @Override
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700342 public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900343 checkPermission(FLOWRULE_WRITE);
Yi Tseng1666b502017-05-17 11:05:18 -0700344 if (forwardingObjective.nextId() == null ||
Yi Tseng1666b502017-05-17 11:05:18 -0700345 flowObjectiveStore.getNextGroup(forwardingObjective.nextId()) != null ||
346 !queueFwdObjective(deviceId, forwardingObjective)) {
347 // fast path
piera6b11992020-01-27 17:45:03 +0100348 installerExecutor.execute(new ObjectiveProcessor(deviceId, forwardingObjective, installerExecutor));
alshabib910aff12015-04-09 16:55:57 -0700349 }
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700350 }
351
alshabib2a441c62015-04-13 18:39:38 -0700352 @Override
Jonathan Hart17d00452015-04-21 17:10:00 -0700353 public void next(DeviceId deviceId, NextObjective nextObjective) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900354 checkPermission(FLOWRULE_WRITE);
piera6b11992020-01-27 17:45:03 +0100355 if (nextObjective.op() == Operation.VERIFY) {
356 // Verify does not need to wait
357 verifierExecutor.execute(new ObjectiveProcessor(deviceId, nextObjective, verifierExecutor));
358 } else if (nextObjective.op() == Operation.ADD ||
Yi Tseng1666b502017-05-17 11:05:18 -0700359 flowObjectiveStore.getNextGroup(nextObjective.id()) != null ||
360 !queueNextObjective(deviceId, nextObjective)) {
361 // either group exists or we are trying to create it - let it through
piera6b11992020-01-27 17:45:03 +0100362 installerExecutor.execute(new ObjectiveProcessor(deviceId, nextObjective, installerExecutor));
Saurav Das1547b3f2017-05-05 17:01:08 -0700363 }
alshabib2a441c62015-04-13 18:39:38 -0700364 }
365
alshabibf6ea9e62015-04-21 17:08:26 -0700366 @Override
367 public int allocateNextId() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900368 checkPermission(FLOWRULE_WRITE);
alshabibf6ea9e62015-04-21 17:08:26 -0700369 return flowObjectiveStore.allocateNextId();
370 }
371
Xin Jin313708b2015-07-09 13:43:04 -0700372 @Override
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700373 public void initPolicy(String policy) {
374 }
Xin Jin313708b2015-07-09 13:43:04 -0700375
Charles Chana7903c82018-03-15 20:14:16 -0700376 boolean queueFwdObjective(DeviceId deviceId, ForwardingObjective fwd) {
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700377 boolean queued = false;
378 synchronized (pendingForwards) {
379 // double check the flow objective store, because this block could run
380 // after a notification arrives
381 if (flowObjectiveStore.getNextGroup(fwd.nextId()) == null) {
382 pendingForwards.compute(fwd.nextId(), (id, pending) -> {
Saurav Das1547b3f2017-05-05 17:01:08 -0700383 PendingFlowObjective pendfo = new PendingFlowObjective(deviceId, fwd);
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700384 if (pending == null) {
Pier Luigi97893112018-03-05 11:09:42 +0100385 return Sets.newLinkedHashSet(ImmutableSet.of(pendfo));
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700386 } else {
Saurav Das1547b3f2017-05-05 17:01:08 -0700387 pending.add(pendfo);
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700388 return pending;
389 }
390 });
391 queued = true;
392 }
393 }
394 if (queued) {
Saurav Dasc568c342018-01-25 09:49:01 -0800395 log.debug("Queued forwarding objective {} for nextId {} meant for device {}",
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700396 fwd.id(), fwd.nextId(), deviceId);
397 }
398 return queued;
alshabib2a441c62015-04-13 18:39:38 -0700399 }
400
Charles Chana7903c82018-03-15 20:14:16 -0700401 boolean queueNextObjective(DeviceId deviceId, NextObjective next) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700402 // we need to hold off on other operations till we get notified that the
403 // initial group creation has succeeded
404 boolean queued = false;
405 synchronized (pendingNexts) {
406 // double check the flow objective store, because this block could run
407 // after a notification arrives
408 if (flowObjectiveStore.getNextGroup(next.id()) == null) {
409 pendingNexts.compute(next.id(), (id, pending) -> {
410 PendingFlowObjective pendfo = new PendingFlowObjective(deviceId, next);
411 if (pending == null) {
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800412 return Lists.newArrayList(pendfo);
Saurav Das1547b3f2017-05-05 17:01:08 -0700413 } else {
414 pending.add(pendfo);
415 return pending;
416 }
417 });
418 queued = true;
419 }
420 }
421 if (queued) {
Saurav Dasc568c342018-01-25 09:49:01 -0800422 log.debug("Queued next objective {} with operation {} meant for device {}",
Saurav Das1547b3f2017-05-05 17:01:08 -0700423 next.id(), next.op(), deviceId);
424 }
425 return queued;
426 }
427
Pier Ventre57a61cd2016-09-07 10:55:41 -0700428 /**
429 * Retrieves (if it exists) the device pipeline behaviour from the cache.
430 * Otherwise it warms the caches and triggers the init method of the Pipeline.
431 *
432 * @param deviceId the id of the device associated to the pipeline
433 * @return the implementation of the Pipeliner behaviour
434 */
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700435 private Pipeliner getDevicePipeliner(DeviceId deviceId) {
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700436 return pipeliners.computeIfAbsent(deviceId, this::initPipelineHandler);
alshabib77b88482015-04-07 15:47:50 -0700437 }
438
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700439 /**
Pier Ventre57a61cd2016-09-07 10:55:41 -0700440 * Retrieves (if it exists) the device pipeline behaviour from the cache and
441 * and triggers the init method of the pipeline. Otherwise (DEVICE_ADDED) it warms
442 * the caches and triggers the init method of the Pipeline. The rationale of this
443 * method is for managing the scenario of a switch that goes down for a failure
444 * and goes up after a while.
445 *
446 * @param deviceId the id of the device associated to the pipeline
447 * @return the implementation of the Pipeliner behaviour
448 */
449 private Pipeliner getAndInitDevicePipeliner(DeviceId deviceId) {
450 return pipeliners.compute(deviceId, (deviceIdValue, pipelinerValue) -> {
451 if (pipelinerValue != null) {
452 pipelinerValue.init(deviceId, context);
453 return pipelinerValue;
454 }
455 return this.initPipelineHandler(deviceId);
456 });
457 }
458
459 /**
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700460 * Creates and initialize {@link Pipeliner}.
461 * <p>
462 * Note: Expected to be called under per-Device lock.
463 * e.g., {@code pipeliners}' Map#compute family methods
464 *
465 * @param deviceId Device to initialize pipeliner
466 * @return {@link Pipeliner} instance or null
467 */
468 private Pipeliner initPipelineHandler(DeviceId deviceId) {
469 start = now();
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700470
Jonathan Hart17d00452015-04-21 17:10:00 -0700471 // Attempt to lookup the handler in the cache
472 DriverHandler handler = driverHandlers.get(deviceId);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700473 cTime = now();
474
Jonathan Hart17d00452015-04-21 17:10:00 -0700475 if (handler == null) {
476 try {
477 // Otherwise create it and if it has pipeline behaviour, cache it
478 handler = driverService.createHandler(deviceId);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700479 dTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700480 if (!handler.driver().hasBehaviour(Pipeliner.class)) {
Yuta HIGUCHIa2a4f342017-03-17 11:38:57 -0700481 log.debug("Pipeline behaviour not supported for device {}",
Jonathan Hart17d00452015-04-21 17:10:00 -0700482 deviceId);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700483 return null;
alshabib2a441c62015-04-13 18:39:38 -0700484 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700485 } catch (ItemNotFoundException e) {
486 log.warn("No applicable driver for device {}", deviceId);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700487 return null;
alshabib2a441c62015-04-13 18:39:38 -0700488 }
489
Jonathan Hart17d00452015-04-21 17:10:00 -0700490 driverHandlers.put(deviceId, handler);
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700491 eTime = now();
alshabib2a441c62015-04-13 18:39:38 -0700492 }
Jonathan Hart17d00452015-04-21 17:10:00 -0700493
494 // Always (re)initialize the pipeline behaviour
495 log.info("Driver {} bound to device {} ... initializing driver",
496 handler.driver().name(), deviceId);
Thomas Vachuska0121a612015-07-21 11:18:09 -0700497 hTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700498 Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
Thomas Vachuska94c3cf42015-07-20 13:01:12 -0700499 hbTime = now();
Jonathan Hart17d00452015-04-21 17:10:00 -0700500 pipeliner.init(deviceId, context);
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700501 stopWatch();
502 return pipeliner;
alshabibaebe7752015-04-07 17:45:42 -0700503 }
alshabib77b88482015-04-07 15:47:50 -0700504
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700505 private void invalidatePipelinerIfNecessary(Device device) {
506 DriverHandler handler = driverHandlers.get(device.id());
507 if (handler != null &&
508 !Objects.equals(handler.driver().name(),
509 device.annotations().value(DRIVER))) {
510 invalidatePipeliner(device.id());
511 }
512 }
513
514 private void invalidatePipeliner(DeviceId id) {
515 log.info("Invalidating cached pipeline behaviour for {}", id);
516 driverHandlers.remove(id);
pier561c8812020-05-20 22:50:30 +0200517 pipeliners.remove(id);
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700518 if (deviceService.isAvailable(id)) {
519 getAndInitDevicePipeliner(id);
520 }
521 }
522
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700523 // Triggers driver setup when a device is (re)detected.
alshabibaebe7752015-04-07 17:45:42 -0700524 private class InnerDeviceListener implements DeviceListener {
525 @Override
526 public void event(DeviceEvent event) {
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000527 if (devEventExecutor != null) {
alshabibaebe7752015-04-07 17:45:42 -0700528 switch (event.type()) {
529 case DEVICE_ADDED:
530 case DEVICE_AVAILABILITY_CHANGED:
Madan Jampani0174f452015-05-29 11:52:05 -0700531 log.debug("Device either added or availability changed {}",
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700532 event.subject().id());
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000533 devEventExecutor.execute(() -> {
534 if (deviceService.isAvailable(event.subject().id())) {
Madan Jampani0174f452015-05-29 11:52:05 -0700535 log.debug("Device is now available {}", event.subject().id());
Pier Ventre57a61cd2016-09-07 10:55:41 -0700536 getAndInitDevicePipeliner(event.subject().id());
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000537 } else {
Yuta HIGUCHI1fb0a8c2016-08-12 10:59:24 -0700538 log.debug("Device is no longer available {}", event.subject().id());
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000539 }
540 });
alshabib4313d102015-04-08 18:55:08 -0700541 break;
542 case DEVICE_UPDATED:
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700543 // Invalidate pipeliner and handler caches if the driver name
544 // device annotation changed.
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000545 devEventExecutor.execute(() -> invalidatePipelinerIfNecessary(event.subject()));
alshabib4313d102015-04-08 18:55:08 -0700546 break;
547 case DEVICE_REMOVED:
Yuta HIGUCHIad0c9902016-08-23 10:37:32 -0700548 // evict Pipeliner and Handler cache, when
549 // the Device was administratively removed.
550 //
551 // System expect the user to clear all existing flows,
552 // before removing device, especially if they intend to
553 // replace driver/pipeliner assigned to the device.
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000554 devEventExecutor.execute(() -> {
pier9ada4192020-03-20 11:00:38 +0100555 driverHandlers.remove(event.subject().id());
pier561c8812020-05-20 22:50:30 +0200556 pipeliners.remove(event.subject().id());
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000557 });
alshabib4313d102015-04-08 18:55:08 -0700558 break;
Yuta HIGUCHIad0c9902016-08-23 10:37:32 -0700559 case DEVICE_SUSPENDED:
560 break;
alshabib4313d102015-04-08 18:55:08 -0700561 case PORT_ADDED:
562 break;
563 case PORT_UPDATED:
564 break;
565 case PORT_REMOVED:
alshabibaebe7752015-04-07 17:45:42 -0700566 break;
567 default:
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700568 break;
alshabibaebe7752015-04-07 17:45:42 -0700569 }
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000570 }
alshabib77b88482015-04-07 15:47:50 -0700571 }
572 }
alshabibaebe7752015-04-07 17:45:42 -0700573
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700574 // Monitors driver configuration changes and invalidates the pipeliner cache entries.
575 // Note that this may leave stale entries on the device if the driver changes
576 // in manner where the new driver does not produce backward compatible flow objectives.
577 // In such cases, it is the operator's responsibility to force device re-connect.
578 private class InnerDriverListener implements DriverListener {
579 @Override
580 public void event(DriverEvent event) {
581 String driverName = event.subject().name();
Andrea Campanellad0561022021-03-26 10:34:30 +0100582 //we invalidate the pipeliner if the event is for the same driver or
583 // if we have the device in the cache but the driver for it changed.
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700584 driverHandlers.entrySet().stream()
Andrea Campanellad0561022021-03-26 10:34:30 +0100585 .filter(e -> driverName.equals(e.getValue().driver().name())
586 || !e.getValue().driver().name()
587 .equals(driverService.getDriver(e.getKey()).name()))
Thomas Vachuskacfeff192017-08-23 15:29:34 -0700588 .map(Map.Entry::getKey)
589 .distinct()
590 .forEach(FlowObjectiveManager.this::invalidatePipeliner);
591 }
592 }
593
Thomas Vachuska174bb912015-07-16 21:27:14 -0700594 // Temporary mechanism to monitor pipeliner setup time-cost; there are
595 // intermittent time where this takes in excess of 2 seconds. Why?
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700596 private long start = 0, totals = 0, count = 0;
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700597 private long cTime, dTime, eTime, hTime, hbTime;
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700598 private static final long LIMIT = 500;
Thomas Vachuska174bb912015-07-16 21:27:14 -0700599
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700600 private long now() {
Thomas Vachuska174bb912015-07-16 21:27:14 -0700601 return System.currentTimeMillis();
602 }
603
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700604 private void stopWatch() {
Thomas Vachuska174bb912015-07-16 21:27:14 -0700605 long duration = System.currentTimeMillis() - start;
606 totals += duration;
607 count += 1;
608 if (duration > LIMIT) {
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700609 log.info("Pipeline setup took {} ms; avg {} ms; cTime={}, dTime={}, eTime={}, hTime={}, hbTime={}",
610 duration, totals / count, diff(cTime), diff(dTime), diff(eTime), diff(hTime), diff(hbTime));
Thomas Vachuska174bb912015-07-16 21:27:14 -0700611 }
612 }
613
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700614 private long diff(long bTime) {
Thomas Vachuskab19bffb2015-07-22 10:56:16 -0700615 long diff = bTime - start;
616 return diff < 0 ? 0 : diff;
Thomas Vachuska9c9ff7c2015-07-20 10:38:59 -0700617 }
618
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700619 // Processing context for initializing pipeline driver behaviours.
620 private class InnerPipelineContext implements PipelinerContext {
pier8b3aef42019-03-11 15:14:02 -0700621
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700622 @Override
623 public ServiceDirectory directory() {
624 return serviceDirectory;
alshabibaebe7752015-04-07 17:45:42 -0700625 }
alshabib2a441c62015-04-13 18:39:38 -0700626
627 @Override
628 public FlowObjectiveStore store() {
629 return flowObjectiveStore;
630 }
pier8b3aef42019-03-11 15:14:02 -0700631
632 @Override
633 public int accumulatorMaxObjectives() {
634 return accumulatorMaxObjectives;
635 }
636
637 @Override
638 public int accumulatorMaxIdleMillis() {
639 return accumulatorMaxIdleMillis;
640 }
641
642 @Override
643 public int accumulatorMaxBatchMillis() {
644 return accumulatorMaxBatchMillis;
645 }
646
alshabib2a441c62015-04-13 18:39:38 -0700647 }
648
649 private class InternalStoreDelegate implements FlowObjectiveStoreDelegate {
650 @Override
651 public void notify(ObjectiveEvent event) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800652 if (event.type() == Type.ADD) {
653 log.debug("Received notification of obj event {}", event);
Saurav Das1547b3f2017-05-05 17:01:08 -0700654 Set<PendingFlowObjective> pending;
655
656 // first send all pending flows
Thomas Vachuskad27097c2016-06-14 19:10:41 -0700657 synchronized (pendingForwards) {
658 // needs to be synchronized for queueObjective lookup
659 pending = pendingForwards.remove(event.subject());
660 }
Saurav Das423fe2b2015-12-04 10:52:59 -0800661 if (pending == null) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700662 log.debug("No forwarding objectives pending for this "
663 + "obj event {}", event);
664 } else {
665 log.debug("Processing {} pending forwarding objectives for nextId {}",
666 pending.size(), event.subject());
667 pending.forEach(p -> getDevicePipeliner(p.deviceId())
668 .forward((ForwardingObjective) p.flowObjective()));
Saurav Das423fe2b2015-12-04 10:52:59 -0800669 }
670
Saurav Das1547b3f2017-05-05 17:01:08 -0700671 // now check for pending next-objectives
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800672 List<PendingFlowObjective> pendNexts;
Saurav Das1547b3f2017-05-05 17:01:08 -0700673 synchronized (pendingNexts) {
674 // needs to be synchronized for queueObjective lookup
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800675 pendNexts = pendingNexts.remove(event.subject());
Saurav Das1547b3f2017-05-05 17:01:08 -0700676 }
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800677 if (pendNexts == null) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700678 log.debug("No next objectives pending for this "
679 + "obj event {}", event);
680 } else {
681 log.debug("Processing {} pending next objectives for nextId {}",
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800682 pendNexts.size(), event.subject());
683 pendNexts.forEach(p -> getDevicePipeliner(p.deviceId())
Saurav Das1547b3f2017-05-05 17:01:08 -0700684 .next((NextObjective) p.flowObjective()));
685 }
alshabib2a441c62015-04-13 18:39:38 -0700686 }
alshabib2a441c62015-04-13 18:39:38 -0700687 }
688 }
689
690 /**
Saurav Das1547b3f2017-05-05 17:01:08 -0700691 * Data class used to hold a pending flow objective that could not
alshabib2a441c62015-04-13 18:39:38 -0700692 * be processed because the associated next object was not present.
Saurav Das1547b3f2017-05-05 17:01:08 -0700693 * Note that this pending flow objective could be a forwarding objective
694 * waiting for a next objective to complete execution. Or it could a
695 * next objective (with a different operation - remove, addToExisting, or
696 * removeFromExisting) waiting for a next objective with the same id to
697 * complete execution.
alshabib2a441c62015-04-13 18:39:38 -0700698 */
Charles Chana7903c82018-03-15 20:14:16 -0700699 protected class PendingFlowObjective {
alshabib2a441c62015-04-13 18:39:38 -0700700 private final DeviceId deviceId;
Saurav Das1547b3f2017-05-05 17:01:08 -0700701 private final Objective flowObj;
alshabib2a441c62015-04-13 18:39:38 -0700702
Charles Chana7903c82018-03-15 20:14:16 -0700703 PendingFlowObjective(DeviceId deviceId, Objective flowObj) {
alshabib2a441c62015-04-13 18:39:38 -0700704 this.deviceId = deviceId;
Saurav Das1547b3f2017-05-05 17:01:08 -0700705 this.flowObj = flowObj;
alshabib2a441c62015-04-13 18:39:38 -0700706 }
707
708 public DeviceId deviceId() {
709 return deviceId;
710 }
711
Saurav Das1547b3f2017-05-05 17:01:08 -0700712 public Objective flowObjective() {
713 return flowObj;
alshabib2a441c62015-04-13 18:39:38 -0700714 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800715
716 @Override
717 public int hashCode() {
Saurav Das1547b3f2017-05-05 17:01:08 -0700718 return Objects.hash(deviceId, flowObj);
Saurav Das8a0732e2015-11-20 15:27:53 -0800719 }
720
721 @Override
722 public boolean equals(final Object obj) {
723 if (this == obj) {
724 return true;
725 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700726 if (!(obj instanceof PendingFlowObjective)) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800727 return false;
728 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700729 final PendingFlowObjective other = (PendingFlowObjective) obj;
Charles Chana7903c82018-03-15 20:14:16 -0700730
731 return this.deviceId.equals(other.deviceId) &&
732 this.flowObj.equals(other.flowObj);
Saurav Das8a0732e2015-11-20 15:27:53 -0800733 }
alshabibaebe7752015-04-07 17:45:42 -0700734 }
Saurav Das24431192016-03-07 19:13:00 -0800735
736 @Override
737 public List<String> getNextMappings() {
738 List<String> mappings = new ArrayList<>();
739 Map<Integer, NextGroup> allnexts = flowObjectiveStore.getAllGroups();
Saurav Das25190812016-05-27 13:54:07 -0700740 // XXX if the NextGroup after de-serialization actually stored info of the deviceId
Saurav Das24431192016-03-07 19:13:00 -0800741 // then info on any nextObj could be retrieved from one controller instance.
742 // Right now the drivers on one instance can only fetch for next-ids that came
743 // to them.
744 // Also, we still need to send the right next-id to the right driver as potentially
745 // there can be different drivers for different devices. But on that account,
746 // no instance should be decoding for another instance's nextIds.
747
748 for (Map.Entry<Integer, NextGroup> e : allnexts.entrySet()) {
749 // get the device this next Objective was sent to
750 DeviceId deviceId = nextToDevice.get(e.getKey());
751 mappings.add("NextId " + e.getKey() + ": " +
752 ((deviceId != null) ? deviceId : "nextId not in this onos instance"));
753 if (deviceId != null) {
754 // this instance of the controller sent the nextObj to a driver
755 Pipeliner pipeliner = getDevicePipeliner(deviceId);
756 List<String> nextMappings = pipeliner.getNextMappings(e.getValue());
757 if (nextMappings != null) {
758 mappings.addAll(nextMappings);
759 }
760 }
761 }
762 return mappings;
763 }
Saurav Dasb5c236e2016-06-07 10:08:06 -0700764
765 @Override
Harshada Chaundkar5a198b02019-07-03 16:27:45 +0000766 public Map<Pair<Integer, DeviceId>, List<String>> getNextMappingsChain() {
767 Map<Pair<Integer, DeviceId>, List<String>> nextObjGroupMap = new HashMap<>();
768 Map<Integer, NextGroup> allnexts = flowObjectiveStore.getAllGroups();
769
770 // XXX if the NextGroup after de-serialization actually stored info of the deviceId
771 // then info on any nextObj could be retrieved from one controller instance.
772 // Right now the drivers on one instance can only fetch for next-ids that came
773 // to them.
774 // Also, we still need to send the right next-id to the right driver as potentially
775 // there can be different drivers for different devices. But on that account,
776 // no instance should be decoding for another instance's nextIds.
777
778 for (Map.Entry<Integer, NextGroup> e : allnexts.entrySet()) {
779 // get the device this next Objective was sent to
780 DeviceId deviceId = nextToDevice.get(e.getKey());
781 if (deviceId != null) {
782 // this instance of the controller sent the nextObj to a driver
783 Pipeliner pipeliner = getDevicePipeliner(deviceId);
784 List<String> nextMappings = pipeliner.getNextMappings(e.getValue());
785 if (nextMappings != null) {
786 //mappings.addAll(nextMappings);
787 nextObjGroupMap.put(Pair.of(e.getKey(), deviceId), nextMappings);
788 }
789 } else {
790 nextObjGroupMap.put(Pair.of(e.getKey(), deviceId), ImmutableList.of("nextId not in this onos instance"));
791 }
792 }
793 return nextObjGroupMap;
794 }
795
796
797 @Override
Saurav Das1547b3f2017-05-05 17:01:08 -0700798 public List<String> getPendingFlowObjectives() {
799 List<String> pendingFlowObjectives = new ArrayList<>();
Charles Chan54734712017-03-29 11:07:55 -0700800
Saurav Das1547b3f2017-05-05 17:01:08 -0700801 for (Integer nextId : pendingForwards.keySet()) {
802 Set<PendingFlowObjective> pfwd = pendingForwards.get(nextId);
Sho SHIMIZU81470a52016-08-12 17:24:55 -0700803 StringBuilder pend = new StringBuilder();
Charles Chan54734712017-03-29 11:07:55 -0700804 pend.append("NextId: ")
805 .append(nextId);
Saurav Das1547b3f2017-05-05 17:01:08 -0700806 for (PendingFlowObjective pf : pfwd) {
Charles Chan54734712017-03-29 11:07:55 -0700807 pend.append("\n FwdId: ")
Saurav Das1547b3f2017-05-05 17:01:08 -0700808 .append(String.format("%11s", pf.flowObjective().id()))
809 .append(", DeviceId: ")
810 .append(pf.deviceId())
811 .append(", Selector: ")
812 .append(((ForwardingObjective) pf.flowObjective())
813 .selector().criteria());
814 }
815 pendingFlowObjectives.add(pend.toString());
816 }
817
818 for (Integer nextId : pendingNexts.keySet()) {
Saurav Dasf14d9ef2017-12-05 15:00:23 -0800819 List<PendingFlowObjective> pnext = pendingNexts.get(nextId);
Saurav Das1547b3f2017-05-05 17:01:08 -0700820 StringBuilder pend = new StringBuilder();
821 pend.append("NextId: ")
822 .append(nextId);
823 for (PendingFlowObjective pn : pnext) {
824 pend.append("\n NextOp: ")
825 .append(pn.flowObjective().op())
Charles Chan54734712017-03-29 11:07:55 -0700826 .append(", DeviceId: ")
827 .append(pn.deviceId())
Saurav Das1547b3f2017-05-05 17:01:08 -0700828 .append(", Treatments: ")
829 .append(((NextObjective) pn.flowObjective())
830 .next());
Saurav Dasb5c236e2016-06-07 10:08:06 -0700831 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700832 pendingFlowObjectives.add(pend.toString());
Saurav Dasb5c236e2016-06-07 10:08:06 -0700833 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700834
835 return pendingFlowObjectives;
836 }
alshabib77b88482015-04-07 15:47:50 -0700837}