blob: 75239fdd2b4108d7f1c9c5312153d86f331e6462 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.packet.impl;
alshabib7674db42014-09-12 23:40:46 -070017
alshabib7674db42014-09-12 23:40:46 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.apache.felix.scr.annotations.Service;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080024import org.onosproject.core.ApplicationId;
Thomas Vachuska6cba4952015-04-22 12:38:22 -070025import org.onosproject.core.CoreService;
Brian O'Connorabafb502014-12-02 22:26:20 -080026import org.onosproject.net.Device;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080027import org.onosproject.net.device.DeviceEvent;
28import org.onosproject.net.device.DeviceListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.net.device.DeviceService;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080030import org.onosproject.net.flow.DefaultTrafficTreatment;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080031import org.onosproject.net.flow.FlowRuleService;
32import org.onosproject.net.flow.TrafficSelector;
Jonathan Hart17d00452015-04-21 17:10:00 -070033import org.onosproject.net.flowobjective.DefaultForwardingObjective;
34import org.onosproject.net.flowobjective.FlowObjectiveService;
35import org.onosproject.net.flowobjective.ForwardingObjective;
36import org.onosproject.net.flowobjective.Objective;
37import org.onosproject.net.flowobjective.ObjectiveContext;
38import org.onosproject.net.flowobjective.ObjectiveError;
alshabib42947782015-03-31 14:59:06 -070039import org.onosproject.net.packet.DefaultPacketRequest;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.packet.OutboundPacket;
41import org.onosproject.net.packet.PacketContext;
42import org.onosproject.net.packet.PacketEvent;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080043import org.onosproject.net.packet.PacketPriority;
Brian O'Connorabafb502014-12-02 22:26:20 -080044import org.onosproject.net.packet.PacketProcessor;
45import org.onosproject.net.packet.PacketProvider;
46import org.onosproject.net.packet.PacketProviderRegistry;
47import org.onosproject.net.packet.PacketProviderService;
alshabib42947782015-03-31 14:59:06 -070048import org.onosproject.net.packet.PacketRequest;
Brian O'Connorabafb502014-12-02 22:26:20 -080049import org.onosproject.net.packet.PacketService;
50import org.onosproject.net.packet.PacketStore;
51import org.onosproject.net.packet.PacketStoreDelegate;
52import org.onosproject.net.provider.AbstractProviderRegistry;
53import org.onosproject.net.provider.AbstractProviderService;
alshabib7674db42014-09-12 23:40:46 -070054import org.slf4j.Logger;
55
alshabib089bb772015-03-03 18:26:26 -080056import java.util.Map;
alshabib089bb772015-03-03 18:26:26 -080057import java.util.concurrent.ConcurrentHashMap;
Madan Jampanic626f1e2015-05-29 13:53:38 -070058import java.util.concurrent.ExecutorService;
59import java.util.concurrent.Executors;
alshabib089bb772015-03-03 18:26:26 -080060
61import static com.google.common.base.Preconditions.checkNotNull;
Madan Jampanic626f1e2015-05-29 13:53:38 -070062import static org.onlab.util.Tools.groupedThreads;
Changhoon Yoon541ef712015-05-23 17:18:34 +090063import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuska27bee092015-06-23 19:03:10 -070064import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090065import static org.onosproject.security.AppPermission.Type.*;
alshabib089bb772015-03-03 18:26:26 -080066
alshabib7674db42014-09-12 23:40:46 -070067/**
68 * Provides a basic implementation of the packet SB & NB APIs.
alshabib7674db42014-09-12 23:40:46 -070069 */
70@Component(immediate = true)
71@Service
tom202175a2014-09-19 19:00:11 -070072public class PacketManager
Thomas Vachuska6cba4952015-04-22 12:38:22 -070073 extends AbstractProviderRegistry<PacketProvider, PacketProviderService>
74 implements PacketService, PacketProviderRegistry {
alshabib7674db42014-09-12 23:40:46 -070075
76 private final Logger log = getLogger(getClass());
77
Thomas Vachuska27bee092015-06-23 19:03:10 -070078 private static final String TABLE_TYPE_MSG =
79 "Table Type cannot be null. For requesting packets without " +
80 "table hints, use other methods in the packetService API";
81
Jonathan Hart4f60f982014-10-27 08:11:17 -070082 private final PacketStoreDelegate delegate = new InternalStoreDelegate();
83
alshabib7674db42014-09-12 23:40:46 -070084 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Thomas Vachuska6cba4952015-04-22 12:38:22 -070085 private CoreService coreService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib7674db42014-09-12 23:40:46 -070088 private DeviceService deviceService;
89
Jonathan Hart4f60f982014-10-27 08:11:17 -070090 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080091 private FlowRuleService flowService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hart4f60f982014-10-27 08:11:17 -070094 private PacketStore store;
95
Thomas Vachuska866b46a2015-04-30 00:26:55 -070096 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 private FlowObjectiveService objectiveService;
98
Madan Jampanic626f1e2015-05-29 13:53:38 -070099 private ExecutorService eventHandlingExecutor;
100
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800101 private final DeviceListener deviceListener = new InternalDeviceListener();
102
Jonathan Hart4f60f982014-10-27 08:11:17 -0700103 private final Map<Integer, PacketProcessor> processors = new ConcurrentHashMap<>();
alshabib7674db42014-09-12 23:40:46 -0700104
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700105 private ApplicationId appId;
106
alshabib7674db42014-09-12 23:40:46 -0700107 @Activate
108 public void activate() {
Madan Jampanic626f1e2015-05-29 13:53:38 -0700109 eventHandlingExecutor = Executors.newSingleThreadExecutor(
110 groupedThreads("onos/net/packet", "event-handler"));
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700111 appId = coreService.getAppId(CoreService.CORE_APP_NAME);
Jonathan Hart4f60f982014-10-27 08:11:17 -0700112 store.setDelegate(delegate);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800113 deviceService.addListener(deviceListener);
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700114 // TODO: Should we request packets for all existing devices? I believe we should.
alshabib7674db42014-09-12 23:40:46 -0700115 log.info("Started");
116 }
117
118 @Deactivate
119 public void deactivate() {
Jonathan Hart4f60f982014-10-27 08:11:17 -0700120 store.unsetDelegate(delegate);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800121 deviceService.removeListener(deviceListener);
Madan Jampanic626f1e2015-05-29 13:53:38 -0700122 eventHandlingExecutor.shutdown();
alshabib7674db42014-09-12 23:40:46 -0700123 log.info("Stopped");
124 }
125
126 @Override
127 public void addProcessor(PacketProcessor processor, int priority) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900128 checkPermission(PACKET_EVENT);
alshabib030111e2014-09-15 15:56:42 -0700129 checkNotNull(processor, "Processor cannot be null");
alshabibd58d3522014-09-13 17:14:53 -0700130 processors.put(priority, processor);
alshabib7674db42014-09-12 23:40:46 -0700131 }
132
133 @Override
134 public void removeProcessor(PacketProcessor processor) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900135 checkPermission(PACKET_EVENT);
tomc370ebd2014-09-16 01:25:21 -0700136 checkNotNull(processor, "Processor cannot be null");
alshabibd58d3522014-09-13 17:14:53 -0700137 processors.values().remove(processor);
alshabib7674db42014-09-12 23:40:46 -0700138 }
139
140 @Override
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800141 public void requestPackets(TrafficSelector selector, PacketPriority priority,
142 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900143 checkPermission(PACKET_READ);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800144 checkNotNull(selector, "Selector cannot be null");
145 checkNotNull(appId, "Application ID cannot be null");
146
Thomas Vachuska27bee092015-06-23 19:03:10 -0700147 PacketRequest request = new DefaultPacketRequest(selector, priority, appId);
alshabib42947782015-03-31 14:59:06 -0700148 if (store.requestPackets(request)) {
149 pushToAllDevices(request);
150 }
Saurav Dasc313c402015-02-27 10:09:47 -0800151 }
152
153 @Override
Thomas Vachuska27bee092015-06-23 19:03:10 -0700154 public void cancelPackets(TrafficSelector selector, PacketPriority priority,
155 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900156 checkPermission(PACKET_READ);
Saurav Dasc313c402015-02-27 10:09:47 -0800157 checkNotNull(selector, "Selector cannot be null");
158 checkNotNull(appId, "Application ID cannot be null");
Saurav Dasc313c402015-02-27 10:09:47 -0800159
Thomas Vachuska27bee092015-06-23 19:03:10 -0700160 PacketRequest request = new DefaultPacketRequest(selector, priority, appId);
161 if (store.cancelPackets(request)) {
162 removeFromAllDevices(request);
alshabib089bb772015-03-03 18:26:26 -0800163 }
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800164 }
165
166 /**
167 * Pushes a packet request flow rule to all devices.
168 *
169 * @param request the packet request
170 */
171 private void pushToAllDevices(PacketRequest request) {
Thomas Vachuska88fd6902015-08-04 10:08:34 -0700172 log.debug("Pushing packet request {} to all devices", request);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800173 for (Device device : deviceService.getDevices()) {
alshabib42947782015-03-31 14:59:06 -0700174 pushRule(device, request);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800175 }
176 }
177
Thomas Vachuska27bee092015-06-23 19:03:10 -0700178
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800179 /**
Thomas Vachuska27bee092015-06-23 19:03:10 -0700180 * Removes packet request flow rule from all devices.
181 *
182 * @param request the packet request
183 */
184 private void removeFromAllDevices(PacketRequest request) {
185 for (Device device : deviceService.getDevices()) {
186 removeRule(device, request);
187 }
188 }
189
190 /**
191 * Pushes packet intercept flow rules to the device.
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800192 *
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700193 * @param device the device to push the rules to
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800194 * @param request the packet request
195 */
196 private void pushRule(Device device, PacketRequest request) {
Marc De Leenheerb9311372015-07-09 11:36:49 -0700197 if (!device.type().equals(Device.Type.SWITCH)) {
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800198 return;
199 }
200
Thomas Vachuska27bee092015-06-23 19:03:10 -0700201 ForwardingObjective forwarding = createBuilder(request)
Jonathan Hart17d00452015-04-21 17:10:00 -0700202 .add(new ObjectiveContext() {
203 @Override
Jonathan Hart17d00452015-04-21 17:10:00 -0700204 public void onError(Objective objective, ObjectiveError error) {
Thomas Vachuska88fd6902015-08-04 10:08:34 -0700205 log.warn("Failed to install packet request {} to {}: {}",
206 request, device.id(), error);
Jonathan Hart17d00452015-04-21 17:10:00 -0700207 }
208 });
209
210 objectiveService.forward(device.id(), forwarding);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800211 }
212
Thomas Vachuska27bee092015-06-23 19:03:10 -0700213 /**
214 * Removes packet intercept flow rules from the device.
215 *
216 * @param device the device to remove the rules deom
217 * @param request the packet request
218 */
219 private void removeRule(Device device, PacketRequest request) {
Marc De Leenheerb9311372015-07-09 11:36:49 -0700220 if (!device.type().equals(Device.Type.SWITCH)) {
Thomas Vachuska27bee092015-06-23 19:03:10 -0700221 return;
222 }
223
224 ForwardingObjective forwarding = createBuilder(request)
225 .remove(new ObjectiveContext() {
226 @Override
227 public void onError(Objective objective, ObjectiveError error) {
Thomas Vachuska88fd6902015-08-04 10:08:34 -0700228 log.warn("Failed to withdraw packet request {} from {}: {}",
229 request, device.id(), error);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700230 }
231 });
232
233 objectiveService.forward(device.id(), forwarding);
234 }
235
236 private DefaultForwardingObjective.Builder createBuilder(PacketRequest request) {
237 return DefaultForwardingObjective.builder()
238 .withPriority(request.priority().priorityValue())
239 .withSelector(request.selector())
240 .fromApp(appId)
241 .withFlag(ForwardingObjective.Flag.VERSATILE)
242 .withTreatment(DefaultTrafficTreatment.builder().punt().build())
243 .makePermanent();
244 }
245
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800246 @Override
alshabib7674db42014-09-12 23:40:46 -0700247 public void emit(OutboundPacket packet) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900248 checkPermission(PACKET_WRITE);
tomc370ebd2014-09-16 01:25:21 -0700249 checkNotNull(packet, "Packet cannot be null");
Jonathan Hart4f60f982014-10-27 08:11:17 -0700250 store.emit(packet);
251 }
252
253 private void localEmit(OutboundPacket packet) {
alshabib7674db42014-09-12 23:40:46 -0700254 final Device device = deviceService.getDevice(packet.sendThrough());
Jonathan Hart7466d612014-11-24 17:09:53 -0800255
256 if (device == null) {
257 return;
258 }
259
Thomas Vachuska27bee092015-06-23 19:03:10 -0700260 PacketProvider packetProvider = getProvider(device.providerId());
alshabib3d643ec2014-10-22 18:33:00 -0700261 if (packetProvider != null) {
262 packetProvider.emit(packet);
263 }
alshabib7674db42014-09-12 23:40:46 -0700264 }
265
266 @Override
tomc370ebd2014-09-16 01:25:21 -0700267 protected PacketProviderService createProviderService(PacketProvider provider) {
alshabib7674db42014-09-12 23:40:46 -0700268 return new InternalPacketProviderService(provider);
269 }
270
Thomas Vachuska27bee092015-06-23 19:03:10 -0700271 // Personalized packet provider service issued to the supplied provider.
alshabib7674db42014-09-12 23:40:46 -0700272 private class InternalPacketProviderService
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700273 extends AbstractProviderService<PacketProvider>
274 implements PacketProviderService {
alshabib7674db42014-09-12 23:40:46 -0700275
276 protected InternalPacketProviderService(PacketProvider provider) {
277 super(provider);
278 }
279
280 @Override
281 public void processPacket(PacketContext context) {
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800282 // TODO filter packets sent to processors based on registrations
alshabibd58d3522014-09-13 17:14:53 -0700283 for (PacketProcessor processor : processors.values()) {
alshabib7674db42014-09-12 23:40:46 -0700284 processor.process(context);
285 }
286 }
287
288 }
Jonathan Hart4f60f982014-10-27 08:11:17 -0700289
290 /**
291 * Internal callback from the packet store.
292 */
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700293 private class InternalStoreDelegate implements PacketStoreDelegate {
Jonathan Hart4f60f982014-10-27 08:11:17 -0700294 @Override
295 public void notify(PacketEvent event) {
296 localEmit(event.subject());
297 }
298 }
299
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800300 /**
301 * Internal listener for device service events.
302 */
303 private class InternalDeviceListener implements DeviceListener {
304 @Override
305 public void event(DeviceEvent event) {
Madan Jampanic626f1e2015-05-29 13:53:38 -0700306 eventHandlingExecutor.execute(() -> {
307 try {
308 Device device = event.subject();
309 switch (event.type()) {
310 case DEVICE_ADDED:
311 case DEVICE_AVAILABILITY_CHANGED:
312 if (deviceService.isAvailable(event.subject().id())) {
Thomas Vachuska88fd6902015-08-04 10:08:34 -0700313 log.debug("Pushing packet requests to device {}", event.subject().id());
Madan Jampanic626f1e2015-05-29 13:53:38 -0700314 for (PacketRequest request : store.existingRequests()) {
315 pushRule(device, request);
316 }
sangho864a9db22015-04-28 12:06:31 -0700317 }
Madan Jampanic626f1e2015-05-29 13:53:38 -0700318 break;
319 default:
320 break;
sangho864a9db22015-04-28 12:06:31 -0700321 }
Madan Jampanic626f1e2015-05-29 13:53:38 -0700322 } catch (Exception e) {
323 log.warn("Failed to process {}", event, e);
324 }
325 });
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800326 }
327 }
328
alshabibae857582014-09-12 23:53:10 -0700329}