blob: 29e585764e830819633ea65cf3783c5e04b0b7e6 [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;
alshabib910aff12015-04-09 16:55:57 -070020import com.google.common.util.concurrent.Futures;
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;
46import org.onosproject.net.flowobjective.ForwardingObjective;
47import org.onosproject.net.flowobjective.NextObjective;
alshabib910aff12015-04-09 16:55:57 -070048import org.onosproject.net.flowobjective.Objective;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070049import org.onosproject.net.group.GroupService;
alshabib77b88482015-04-07 15:47:50 -070050import org.slf4j.Logger;
51import org.slf4j.LoggerFactory;
52
53import java.util.Collection;
alshabib910aff12015-04-09 16:55:57 -070054import java.util.Collections;
alshabib77b88482015-04-07 15:47:50 -070055import java.util.Map;
56import java.util.concurrent.Future;
57
58import static com.google.common.base.Preconditions.checkState;
59
60/**
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070061 * Provides implementation of the flow objective programming service.
alshabib77b88482015-04-07 15:47:50 -070062 */
63@Component(immediate = true)
64@Service
65public class FlowObjectiveManager implements FlowObjectiveService {
66
67 private final Logger log = LoggerFactory.getLogger(getClass());
68
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070069 public static final String NOT_INITIALIZED = "Driver not initialized";
70
alshabib77b88482015-04-07 15:47:50 -070071 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected DriverService driverService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected DeviceService deviceService;
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected MastershipService mastershipService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected ClusterService clusterService;
82
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070083 // Note: The following dependencies are added on behalf of the pipeline
84 // driver behaviours to assure these services are available for their
85 // initialization.
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected FlowRuleService flowRuleService;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected GroupService groupService;
91
92
93 private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap();
alshabib910aff12015-04-09 16:55:57 -070094 private final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070095
96 private final PipelinerContext context = new InnerPipelineContext();
97 private final MastershipListener mastershipListener = new InnerMastershipListener();
98 private final DeviceListener deviceListener = new InnerDeviceListener();
99
alshabib77b88482015-04-07 15:47:50 -0700100 protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
alshabib910aff12015-04-09 16:55:57 -0700101
102 private final Map<DeviceId, Collection<Objective>> pendingObjectives =
103 Maps.newConcurrentMap();
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700104 private NodeId localNode;
alshabib77b88482015-04-07 15:47:50 -0700105
106 @Activate
107 protected void activate() {
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700108 localNode = clusterService.getLocalNode().id();
alshabib77b88482015-04-07 15:47:50 -0700109 mastershipService.addListener(mastershipListener);
alshabibaebe7752015-04-07 17:45:42 -0700110 deviceService.addListener(deviceListener);
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700111 deviceService.getDevices().forEach(device -> setupPipelineHandler(device.id()));
alshabib77b88482015-04-07 15:47:50 -0700112 log.info("Started");
113 }
114
115 @Deactivate
116 protected void deactivate() {
117 mastershipService.removeListener(mastershipListener);
alshabibaebe7752015-04-07 17:45:42 -0700118 deviceService.removeListener(deviceListener);
alshabib77b88482015-04-07 15:47:50 -0700119 log.info("Stopped");
120 }
121
122 @Override
123 public Future<Boolean> filter(DeviceId deviceId,
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700124 Collection<FilteringObjective> filteringObjectives) {
alshabib910aff12015-04-09 16:55:57 -0700125 if (deviceService.isAvailable(deviceId)) {
126 return getDevicePipeliner(deviceId).filter(filteringObjectives);
127 } else {
128 filteringObjectives.forEach(obj -> updatePendingMap(deviceId, obj));
129 }
130 return Futures.immediateFuture(true);
alshabib77b88482015-04-07 15:47:50 -0700131 }
132
alshabib910aff12015-04-09 16:55:57 -0700133
134
alshabib77b88482015-04-07 15:47:50 -0700135 @Override
136 public Future<Boolean> forward(DeviceId deviceId,
137 Collection<ForwardingObjective> forwardingObjectives) {
alshabib910aff12015-04-09 16:55:57 -0700138 if (deviceService.isAvailable(deviceId)) {
139 return getDevicePipeliner(deviceId).forward(forwardingObjectives);
140 } else {
141 forwardingObjectives.forEach(obj -> updatePendingMap(deviceId, obj));
142 }
143 return Futures.immediateFuture(true);
alshabib77b88482015-04-07 15:47:50 -0700144 }
145
146 @Override
147 public Future<Boolean> next(DeviceId deviceId,
148 Collection<NextObjective> nextObjectives) {
alshabib910aff12015-04-09 16:55:57 -0700149 if (deviceService.isAvailable(deviceId)) {
150 return getDevicePipeliner(deviceId).next(nextObjectives);
151 } else {
152 nextObjectives.forEach(obj -> updatePendingMap(deviceId, obj));
153 }
154 return Futures.immediateFuture(true);
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700155 }
156
alshabib910aff12015-04-09 16:55:57 -0700157 private void updatePendingMap(DeviceId deviceId, Objective pending) {
158 if (pendingObjectives.putIfAbsent(deviceId, Lists.newArrayList(pending)) != null) {
159 Collection<Objective> objectives = pendingObjectives.get(deviceId);
160 objectives.add(pending);
161 }
162
163 }
164
165 // Retrieves the device pipeline behaviour from the cache.
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700166 private Pipeliner getDevicePipeliner(DeviceId deviceId) {
alshabib910aff12015-04-09 16:55:57 -0700167 Pipeliner pipeliner = pipeliners.get(deviceId);
168 checkState(pipeliner != null, NOT_INITIALIZED);
169 return pipeliner;
alshabib77b88482015-04-07 15:47:50 -0700170 }
171
alshabibaebe7752015-04-07 17:45:42 -0700172
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700173 // Triggers driver setup when the local node becomes a device master.
alshabib77b88482015-04-07 15:47:50 -0700174 private class InnerMastershipListener implements MastershipListener {
175 @Override
176 public void event(MastershipEvent event) {
177 switch (event.type()) {
alshabib77b88482015-04-07 15:47:50 -0700178 case MASTER_CHANGED:
alshabib4313d102015-04-08 18:55:08 -0700179 if (event.roleInfo().master() != null) {
180 setupPipelineHandler(event.subject());
181 }
182 break;
183 case BACKUPS_CHANGED:
alshabib77b88482015-04-07 15:47:50 -0700184 break;
185 default:
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700186 break;
alshabib77b88482015-04-07 15:47:50 -0700187 }
188 }
alshabibaebe7752015-04-07 17:45:42 -0700189 }
alshabib77b88482015-04-07 15:47:50 -0700190
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700191 // Triggers driver setup when a device is (re)detected.
alshabibaebe7752015-04-07 17:45:42 -0700192 private class InnerDeviceListener implements DeviceListener {
193 @Override
194 public void event(DeviceEvent event) {
195 switch (event.type()) {
196 case DEVICE_ADDED:
197 case DEVICE_AVAILABILITY_CHANGED:
alshabib4313d102015-04-08 18:55:08 -0700198 if (deviceService.isAvailable(event.subject().id())) {
199 setupPipelineHandler(event.subject().id());
alshabib910aff12015-04-09 16:55:57 -0700200 processPendingObjectives(event.subject().id());
alshabib4313d102015-04-08 18:55:08 -0700201 }
202 break;
203 case DEVICE_UPDATED:
204 break;
205 case DEVICE_REMOVED:
206 break;
207 case DEVICE_SUSPENDED:
208 break;
209 case PORT_ADDED:
210 break;
211 case PORT_UPDATED:
212 break;
213 case PORT_REMOVED:
alshabibaebe7752015-04-07 17:45:42 -0700214 break;
215 default:
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700216 break;
alshabibaebe7752015-04-07 17:45:42 -0700217 }
alshabib77b88482015-04-07 15:47:50 -0700218 }
alshabib910aff12015-04-09 16:55:57 -0700219
220 private void processPendingObjectives(DeviceId deviceId) {
221 pendingObjectives.get(deviceId).forEach(obj -> {
222 if (obj instanceof NextObjective) {
223 getDevicePipeliner(deviceId)
224 .next(Collections.singletonList((NextObjective) obj));
225 } else if (obj instanceof ForwardingObjective) {
226 getDevicePipeliner(deviceId)
227 .forward(Collections.singletonList((ForwardingObjective) obj));
228 } else {
229 getDevicePipeliner(deviceId)
230 .filter(Collections.singletonList((FilteringObjective) obj));
231 }
232 });
233 }
alshabib77b88482015-04-07 15:47:50 -0700234 }
alshabibaebe7752015-04-07 17:45:42 -0700235
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700236 private void setupPipelineHandler(DeviceId deviceId) {
237 if (localNode.equals(mastershipService.getMasterFor(deviceId))) {
238 // Attempt to lookup the handler in the cache
239 DriverHandler handler = driverHandlers.get(deviceId);
240 if (handler == null) {
241 try {
242 // Otherwise create it and if it has pipeline behaviour, cache it
243 handler = driverService.createHandler(deviceId);
244 if (!handler.driver().hasBehaviour(Pipeliner.class)) {
245 log.warn("Pipeline behaviour not supported for device {}",
246 deviceId);
247 return;
248 }
249 } catch (ItemNotFoundException e) {
250 log.warn("No applicable driver for device {}", deviceId);
251 return;
252 }
alshabibaebe7752015-04-07 17:45:42 -0700253 driverHandlers.put(deviceId, handler);
alshabibaebe7752015-04-07 17:45:42 -0700254 }
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700255
256 // Always (re)initialize the pipeline behaviour
alshabib910aff12015-04-09 16:55:57 -0700257 Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
258 pipeliner.init(deviceId, context);
259 pipeliners.putIfAbsent(deviceId, pipeliner);
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700260 log.info("Driver {} bound to device {}", handler.driver().name(), deviceId);
alshabibaebe7752015-04-07 17:45:42 -0700261 }
262 }
263
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700264 // Processing context for initializing pipeline driver behaviours.
265 private class InnerPipelineContext implements PipelinerContext {
266 @Override
267 public ServiceDirectory directory() {
268 return serviceDirectory;
alshabibaebe7752015-04-07 17:45:42 -0700269 }
alshabibaebe7752015-04-07 17:45:42 -0700270 }
alshabib77b88482015-04-07 15:47:50 -0700271}