blob: 7f6b0ee261632cb070d7c81372bd778640d5fa7b [file] [log] [blame]
alshabib77b88482015-04-07 15:47:50 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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
alshabib910aff12015-04-09 16:55:57 -070018import com.google.common.collect.Lists;
alshabib77b88482015-04-07 15:47:50 -070019import com.google.common.collect.Maps;
alshabib2a441c62015-04-13 18:39:38 -070020import com.google.common.collect.Sets;
alshabib77b88482015-04-07 15:47:50 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
27import org.onlab.osgi.DefaultServiceDirectory;
28import org.onlab.osgi.ServiceDirectory;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070029import org.onlab.util.ItemNotFoundException;
alshabib77b88482015-04-07 15:47:50 -070030import org.onosproject.cluster.ClusterService;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070031import org.onosproject.cluster.NodeId;
alshabib77b88482015-04-07 15:47:50 -070032import org.onosproject.mastership.MastershipEvent;
33import org.onosproject.mastership.MastershipListener;
34import org.onosproject.mastership.MastershipService;
alshabib77b88482015-04-07 15:47:50 -070035import org.onosproject.net.DeviceId;
36import org.onosproject.net.behaviour.Pipeliner;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070037import org.onosproject.net.behaviour.PipelinerContext;
alshabibaebe7752015-04-07 17:45:42 -070038import org.onosproject.net.device.DeviceEvent;
39import org.onosproject.net.device.DeviceListener;
alshabib77b88482015-04-07 15:47:50 -070040import org.onosproject.net.device.DeviceService;
alshabib77b88482015-04-07 15:47:50 -070041import org.onosproject.net.driver.DriverHandler;
42import org.onosproject.net.driver.DriverService;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070043import org.onosproject.net.flow.FlowRuleService;
alshabib77b88482015-04-07 15:47:50 -070044import org.onosproject.net.flowobjective.FilteringObjective;
45import org.onosproject.net.flowobjective.FlowObjectiveService;
alshabib2a441c62015-04-13 18:39:38 -070046import org.onosproject.net.flowobjective.FlowObjectiveStore;
47import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate;
alshabib77b88482015-04-07 15:47:50 -070048import org.onosproject.net.flowobjective.ForwardingObjective;
49import org.onosproject.net.flowobjective.NextObjective;
alshabib910aff12015-04-09 16:55:57 -070050import org.onosproject.net.flowobjective.Objective;
alshabib2a441c62015-04-13 18:39:38 -070051import org.onosproject.net.flowobjective.ObjectiveEvent;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070052import org.onosproject.net.group.GroupService;
alshabib77b88482015-04-07 15:47:50 -070053import org.slf4j.Logger;
54import org.slf4j.LoggerFactory;
55
56import java.util.Collection;
alshabib910aff12015-04-09 16:55:57 -070057import java.util.Collections;
alshabib77b88482015-04-07 15:47:50 -070058import java.util.Map;
alshabib2a441c62015-04-13 18:39:38 -070059import java.util.Set;
alshabib77b88482015-04-07 15:47:50 -070060
61import static com.google.common.base.Preconditions.checkState;
62
63/**
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070064 * Provides implementation of the flow objective programming service.
alshabib77b88482015-04-07 15:47:50 -070065 */
alshabib2a441c62015-04-13 18:39:38 -070066@Component(immediate = true)
alshabib77b88482015-04-07 15:47:50 -070067@Service
68public class FlowObjectiveManager implements FlowObjectiveService {
69
70 private final Logger log = LoggerFactory.getLogger(getClass());
71
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070072 public static final String NOT_INITIALIZED = "Driver not initialized";
73
alshabib77b88482015-04-07 15:47:50 -070074 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected DriverService driverService;
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected DeviceService deviceService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected MastershipService mastershipService;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected ClusterService clusterService;
85
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070086 // Note: The following dependencies are added on behalf of the pipeline
87 // driver behaviours to assure these services are available for their
88 // initialization.
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected FlowRuleService flowRuleService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected GroupService groupService;
94
alshabib2a441c62015-04-13 18:39:38 -070095 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected FlowObjectiveStore flowObjectiveStore;
97
98 private final FlowObjectiveStoreDelegate delegate = new InternalStoreDelegate();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070099
100 private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap();
alshabib910aff12015-04-09 16:55:57 -0700101 private final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700102
103 private final PipelinerContext context = new InnerPipelineContext();
104 private final MastershipListener mastershipListener = new InnerMastershipListener();
105 private final DeviceListener deviceListener = new InnerDeviceListener();
106
alshabib77b88482015-04-07 15:47:50 -0700107 protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
alshabib910aff12015-04-09 16:55:57 -0700108
109 private final Map<DeviceId, Collection<Objective>> pendingObjectives =
110 Maps.newConcurrentMap();
alshabib2a441c62015-04-13 18:39:38 -0700111
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700112 private NodeId localNode;
alshabib77b88482015-04-07 15:47:50 -0700113
alshabib2a441c62015-04-13 18:39:38 -0700114 private Map<Integer, Set<PendingNext>> pendingForwards =
115 Maps.newConcurrentMap();
116
117
alshabib77b88482015-04-07 15:47:50 -0700118 @Activate
119 protected void activate() {
alshabib2a441c62015-04-13 18:39:38 -0700120 flowObjectiveStore.setDelegate(delegate);
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700121 localNode = clusterService.getLocalNode().id();
alshabib77b88482015-04-07 15:47:50 -0700122 mastershipService.addListener(mastershipListener);
alshabibaebe7752015-04-07 17:45:42 -0700123 deviceService.addListener(deviceListener);
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700124 deviceService.getDevices().forEach(device -> setupPipelineHandler(device.id()));
alshabib77b88482015-04-07 15:47:50 -0700125 log.info("Started");
126 }
127
128 @Deactivate
129 protected void deactivate() {
alshabib2a441c62015-04-13 18:39:38 -0700130 flowObjectiveStore.unsetDelegate(delegate);
alshabib77b88482015-04-07 15:47:50 -0700131 mastershipService.removeListener(mastershipListener);
alshabibaebe7752015-04-07 17:45:42 -0700132 deviceService.removeListener(deviceListener);
alshabib77b88482015-04-07 15:47:50 -0700133 log.info("Stopped");
134 }
135
136 @Override
alshabib2a441c62015-04-13 18:39:38 -0700137 public void filter(DeviceId deviceId,
138 FilteringObjective filteringObjective) {
alshabib910aff12015-04-09 16:55:57 -0700139 if (deviceService.isAvailable(deviceId)) {
alshabib2a441c62015-04-13 18:39:38 -0700140 getDevicePipeliner(deviceId).filter(filteringObjective);
alshabib910aff12015-04-09 16:55:57 -0700141 } else {
alshabib2a441c62015-04-13 18:39:38 -0700142 updatePendingMap(deviceId, filteringObjective);
alshabib910aff12015-04-09 16:55:57 -0700143 }
alshabib77b88482015-04-07 15:47:50 -0700144
alshabib77b88482015-04-07 15:47:50 -0700145 }
146
147 @Override
alshabib2a441c62015-04-13 18:39:38 -0700148 public void forward(DeviceId deviceId,
149 ForwardingObjective forwardingObjective) {
150
151 if (queueObjective(deviceId, forwardingObjective)) {
152 return;
alshabib910aff12015-04-09 16:55:57 -0700153 }
alshabib2a441c62015-04-13 18:39:38 -0700154
155 if (deviceService.isAvailable(deviceId)) {
156 getDevicePipeliner(deviceId).forward(forwardingObjective);
157 } else {
158 updatePendingMap(deviceId, forwardingObjective);
159 }
160
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700161 }
162
alshabib2a441c62015-04-13 18:39:38 -0700163 @Override
164 public void next(DeviceId deviceId,
165 NextObjective nextObjective) {
166 if (deviceService.isAvailable(deviceId)) {
167 getDevicePipeliner(deviceId).next(nextObjective);
168 } else {
169 updatePendingMap(deviceId, nextObjective);
170 }
171 }
172
alshabibf6ea9e62015-04-21 17:08:26 -0700173 @Override
174 public int allocateNextId() {
175 return flowObjectiveStore.allocateNextId();
176 }
177
alshabib2a441c62015-04-13 18:39:38 -0700178 private boolean queueObjective(DeviceId deviceId, ForwardingObjective fwd) {
179 if (fwd.nextId() != null &&
180 flowObjectiveStore.getNextGroup(fwd.nextId()) == null) {
Saurav Das3ea46622015-04-22 14:01:34 -0700181 log.trace("Queuing forwarding objective for nextId {}", fwd.nextId());
alshabib2a441c62015-04-13 18:39:38 -0700182 if (pendingForwards.putIfAbsent(fwd.nextId(),
183 Sets.newHashSet(new PendingNext(deviceId, fwd))) != null) {
184 Set<PendingNext> pending = pendingForwards.get(fwd.nextId());
185 pending.add(new PendingNext(deviceId, fwd));
186 }
187 return true;
188 }
189 return false;
190 }
191
192
alshabib910aff12015-04-09 16:55:57 -0700193 private void updatePendingMap(DeviceId deviceId, Objective pending) {
194 if (pendingObjectives.putIfAbsent(deviceId, Lists.newArrayList(pending)) != null) {
195 Collection<Objective> objectives = pendingObjectives.get(deviceId);
196 objectives.add(pending);
197 }
198
199 }
200
201 // Retrieves the device pipeline behaviour from the cache.
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700202 private Pipeliner getDevicePipeliner(DeviceId deviceId) {
alshabib910aff12015-04-09 16:55:57 -0700203 Pipeliner pipeliner = pipeliners.get(deviceId);
204 checkState(pipeliner != null, NOT_INITIALIZED);
205 return pipeliner;
alshabib77b88482015-04-07 15:47:50 -0700206 }
207
alshabib2a441c62015-04-13 18:39:38 -0700208 private void setupPipelineHandler(DeviceId deviceId) {
209 if (localNode.equals(mastershipService.getMasterFor(deviceId))) {
210 // Attempt to lookup the handler in the cache
211 DriverHandler handler = driverHandlers.get(deviceId);
212 if (handler == null) {
213 try {
214 // Otherwise create it and if it has pipeline behaviour, cache it
215 handler = driverService.createHandler(deviceId);
216 if (!handler.driver().hasBehaviour(Pipeliner.class)) {
217 log.warn("Pipeline behaviour not supported for device {}",
218 deviceId);
219 return;
220 }
221 } catch (ItemNotFoundException e) {
222 log.warn("No applicable driver for device {}", deviceId);
223 return;
224 }
225 driverHandlers.put(deviceId, handler);
226 }
227
228 // Always (re)initialize the pipeline behaviour
Saurav Das3ea46622015-04-22 14:01:34 -0700229 log.info("Driver {} bound to device {} ... initializing driver",
230 handler.driver().name(), deviceId);
alshabib2a441c62015-04-13 18:39:38 -0700231 Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
232 pipeliner.init(deviceId, context);
233 pipeliners.putIfAbsent(deviceId, pipeliner);
alshabib2a441c62015-04-13 18:39:38 -0700234 }
235 }
alshabibaebe7752015-04-07 17:45:42 -0700236
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700237 // Triggers driver setup when the local node becomes a device master.
alshabib77b88482015-04-07 15:47:50 -0700238 private class InnerMastershipListener implements MastershipListener {
239 @Override
240 public void event(MastershipEvent event) {
241 switch (event.type()) {
alshabib77b88482015-04-07 15:47:50 -0700242 case MASTER_CHANGED:
alshabib4313d102015-04-08 18:55:08 -0700243 if (event.roleInfo().master() != null) {
244 setupPipelineHandler(event.subject());
Saurav Das3ea46622015-04-22 14:01:34 -0700245 log.info("mastership changed on device {}", event.subject());
alshabib4313d102015-04-08 18:55:08 -0700246 }
247 break;
248 case BACKUPS_CHANGED:
alshabib77b88482015-04-07 15:47:50 -0700249 break;
250 default:
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700251 break;
alshabib77b88482015-04-07 15:47:50 -0700252 }
253 }
alshabibaebe7752015-04-07 17:45:42 -0700254 }
alshabib77b88482015-04-07 15:47:50 -0700255
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700256 // Triggers driver setup when a device is (re)detected.
alshabibaebe7752015-04-07 17:45:42 -0700257 private class InnerDeviceListener implements DeviceListener {
258 @Override
259 public void event(DeviceEvent event) {
260 switch (event.type()) {
261 case DEVICE_ADDED:
262 case DEVICE_AVAILABILITY_CHANGED:
Saurav Das3ea46622015-04-22 14:01:34 -0700263 log.info("Device either added or availability changed {}",
264 event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700265 if (deviceService.isAvailable(event.subject().id())) {
Saurav Das3ea46622015-04-22 14:01:34 -0700266 log.info("Device is now available {}", event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700267 setupPipelineHandler(event.subject().id());
alshabib910aff12015-04-09 16:55:57 -0700268 processPendingObjectives(event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700269 }
270 break;
271 case DEVICE_UPDATED:
272 break;
273 case DEVICE_REMOVED:
274 break;
275 case DEVICE_SUSPENDED:
276 break;
277 case PORT_ADDED:
278 break;
279 case PORT_UPDATED:
280 break;
281 case PORT_REMOVED:
alshabibaebe7752015-04-07 17:45:42 -0700282 break;
283 default:
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700284 break;
alshabibaebe7752015-04-07 17:45:42 -0700285 }
alshabib77b88482015-04-07 15:47:50 -0700286 }
alshabib910aff12015-04-09 16:55:57 -0700287
288 private void processPendingObjectives(DeviceId deviceId) {
Saurav Das3ea46622015-04-22 14:01:34 -0700289 log.debug("Processing pending objectives for device {}", deviceId);
290
alshabib1097c972015-04-10 14:41:32 -0700291 pendingObjectives.getOrDefault(deviceId,
292 Collections.emptySet()).forEach(obj -> {
alshabib910aff12015-04-09 16:55:57 -0700293 if (obj instanceof NextObjective) {
alshabib2a441c62015-04-13 18:39:38 -0700294 next(deviceId, (NextObjective) obj);
alshabib910aff12015-04-09 16:55:57 -0700295 } else if (obj instanceof ForwardingObjective) {
alshabib2a441c62015-04-13 18:39:38 -0700296 forward(deviceId, (ForwardingObjective) obj);
alshabib910aff12015-04-09 16:55:57 -0700297 } else {
298 getDevicePipeliner(deviceId)
alshabib2a441c62015-04-13 18:39:38 -0700299 .filter((FilteringObjective) obj);
alshabib910aff12015-04-09 16:55:57 -0700300 }
301 });
302 }
alshabib77b88482015-04-07 15:47:50 -0700303 }
alshabibaebe7752015-04-07 17:45:42 -0700304
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700305 // Processing context for initializing pipeline driver behaviours.
306 private class InnerPipelineContext implements PipelinerContext {
307 @Override
308 public ServiceDirectory directory() {
309 return serviceDirectory;
alshabibaebe7752015-04-07 17:45:42 -0700310 }
alshabib2a441c62015-04-13 18:39:38 -0700311
312 @Override
313 public FlowObjectiveStore store() {
314 return flowObjectiveStore;
315 }
316
317
318 }
319
320 private class InternalStoreDelegate implements FlowObjectiveStoreDelegate {
321 @Override
322 public void notify(ObjectiveEvent event) {
Saurav Das3ea46622015-04-22 14:01:34 -0700323 log.debug("Received notification of obj event {}", event);
alshabib2a441c62015-04-13 18:39:38 -0700324 Set<PendingNext> pending = pendingForwards.remove(event.subject());
325
326 if (pending == null) {
Saurav Das3ea46622015-04-22 14:01:34 -0700327 log.debug("Nothing pending for this obj event");
alshabib2a441c62015-04-13 18:39:38 -0700328 return;
329 }
330
Saurav Das3ea46622015-04-22 14:01:34 -0700331 log.debug("Processing pending forwarding objectives {}", pending.size());
alshabib2a441c62015-04-13 18:39:38 -0700332
333 pending.forEach(p -> getDevicePipeliner(p.deviceId())
334 .forward(p.forwardingObjective()));
335
336 }
337 }
338
339 /**
340 * Data class used to hold a pending forwarding objective that could not
341 * be processed because the associated next object was not present.
342 */
343 private class PendingNext {
344 private final DeviceId deviceId;
345 private final ForwardingObjective fwd;
346
347 public PendingNext(DeviceId deviceId, ForwardingObjective fwd) {
348 this.deviceId = deviceId;
349 this.fwd = fwd;
350 }
351
352 public DeviceId deviceId() {
353 return deviceId;
354 }
355
356 public ForwardingObjective forwardingObjective() {
357 return fwd;
358 }
359
360
alshabibaebe7752015-04-07 17:45:42 -0700361 }
alshabib77b88482015-04-07 15:47:50 -0700362}