blob: 793030f22df0e19d9c5772ef35a960f6625edffe [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
Thomas Vachuska924cda42015-09-22 12:11:27 -070018import com.google.common.collect.ImmutableList;
19import com.google.common.collect.Lists;
alshabib7674db42014-09-12 23:40:46 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080026import org.onosproject.core.ApplicationId;
Thomas Vachuska6cba4952015-04-22 12:38:22 -070027import org.onosproject.core.CoreService;
Brian O'Connorabafb502014-12-02 22:26:20 -080028import org.onosproject.net.Device;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080029import org.onosproject.net.device.DeviceEvent;
30import org.onosproject.net.device.DeviceListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080031import org.onosproject.net.device.DeviceService;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080032import org.onosproject.net.flow.DefaultTrafficTreatment;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080033import org.onosproject.net.flow.FlowRuleService;
34import org.onosproject.net.flow.TrafficSelector;
Jonathan Hart17d00452015-04-21 17:10:00 -070035import org.onosproject.net.flowobjective.DefaultForwardingObjective;
36import org.onosproject.net.flowobjective.FlowObjectiveService;
37import org.onosproject.net.flowobjective.ForwardingObjective;
38import org.onosproject.net.flowobjective.Objective;
39import org.onosproject.net.flowobjective.ObjectiveContext;
40import org.onosproject.net.flowobjective.ObjectiveError;
alshabib42947782015-03-31 14:59:06 -070041import org.onosproject.net.packet.DefaultPacketRequest;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.packet.OutboundPacket;
43import org.onosproject.net.packet.PacketContext;
44import org.onosproject.net.packet.PacketEvent;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080045import org.onosproject.net.packet.PacketPriority;
Brian O'Connorabafb502014-12-02 22:26:20 -080046import org.onosproject.net.packet.PacketProcessor;
Thomas Vachuska924cda42015-09-22 12:11:27 -070047import org.onosproject.net.packet.PacketProcessorEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080048import org.onosproject.net.packet.PacketProvider;
49import org.onosproject.net.packet.PacketProviderRegistry;
50import org.onosproject.net.packet.PacketProviderService;
alshabib42947782015-03-31 14:59:06 -070051import org.onosproject.net.packet.PacketRequest;
Brian O'Connorabafb502014-12-02 22:26:20 -080052import org.onosproject.net.packet.PacketService;
53import org.onosproject.net.packet.PacketStore;
54import org.onosproject.net.packet.PacketStoreDelegate;
55import org.onosproject.net.provider.AbstractProviderRegistry;
56import org.onosproject.net.provider.AbstractProviderService;
alshabib7674db42014-09-12 23:40:46 -070057import org.slf4j.Logger;
58
Thomas Vachuska7f171b22015-08-21 12:49:08 -070059import java.util.List;
Madan Jampanic626f1e2015-05-29 13:53:38 -070060import java.util.concurrent.ExecutorService;
61import java.util.concurrent.Executors;
alshabib089bb772015-03-03 18:26:26 -080062
63import static com.google.common.base.Preconditions.checkNotNull;
Madan Jampanic626f1e2015-05-29 13:53:38 -070064import static org.onlab.util.Tools.groupedThreads;
Changhoon Yoon541ef712015-05-23 17:18:34 +090065import static org.onosproject.security.AppGuard.checkPermission;
Changhoon Yoonb856b812015-08-10 03:47:19 +090066import static org.onosproject.security.AppPermission.Type.*;
Thomas Vachuska7f171b22015-08-21 12:49:08 -070067import static org.slf4j.LoggerFactory.getLogger;
alshabib089bb772015-03-03 18:26:26 -080068
alshabib7674db42014-09-12 23:40:46 -070069/**
70 * Provides a basic implementation of the packet SB & NB APIs.
alshabib7674db42014-09-12 23:40:46 -070071 */
72@Component(immediate = true)
73@Service
tom202175a2014-09-19 19:00:11 -070074public class PacketManager
Thomas Vachuska6cba4952015-04-22 12:38:22 -070075 extends AbstractProviderRegistry<PacketProvider, PacketProviderService>
76 implements PacketService, PacketProviderRegistry {
alshabib7674db42014-09-12 23:40:46 -070077
78 private final Logger log = getLogger(getClass());
79
Thomas Vachuska27bee092015-06-23 19:03:10 -070080 private static final String TABLE_TYPE_MSG =
81 "Table Type cannot be null. For requesting packets without " +
82 "table hints, use other methods in the packetService API";
83
Jonathan Hart4f60f982014-10-27 08:11:17 -070084 private final PacketStoreDelegate delegate = new InternalStoreDelegate();
85
alshabib7674db42014-09-12 23:40:46 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Thomas Vachuska6cba4952015-04-22 12:38:22 -070087 private CoreService coreService;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib7674db42014-09-12 23:40:46 -070090 private DeviceService deviceService;
91
Jonathan Hart4f60f982014-10-27 08:11:17 -070092 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080093 private FlowRuleService flowService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hart4f60f982014-10-27 08:11:17 -070096 private PacketStore store;
97
Thomas Vachuska866b46a2015-04-30 00:26:55 -070098 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 private FlowObjectiveService objectiveService;
100
Madan Jampanic626f1e2015-05-29 13:53:38 -0700101 private ExecutorService eventHandlingExecutor;
102
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800103 private final DeviceListener deviceListener = new InternalDeviceListener();
104
Thomas Vachuska924cda42015-09-22 12:11:27 -0700105 private final List<ProcessorEntry> processors = Lists.newCopyOnWriteArrayList();
alshabib7674db42014-09-12 23:40:46 -0700106
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700107 private ApplicationId appId;
108
alshabib7674db42014-09-12 23:40:46 -0700109 @Activate
110 public void activate() {
Madan Jampanic626f1e2015-05-29 13:53:38 -0700111 eventHandlingExecutor = Executors.newSingleThreadExecutor(
Thomas Vachuska924cda42015-09-22 12:11:27 -0700112 groupedThreads("onos/net/packet", "event-handler"));
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700113 appId = coreService.getAppId(CoreService.CORE_APP_NAME);
Jonathan Hart4f60f982014-10-27 08:11:17 -0700114 store.setDelegate(delegate);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800115 deviceService.addListener(deviceListener);
Thomas Vachuska924cda42015-09-22 12:11:27 -0700116 store.existingRequests().forEach(this::pushToAllDevices);
alshabib7674db42014-09-12 23:40:46 -0700117 log.info("Started");
118 }
119
120 @Deactivate
121 public void deactivate() {
Jonathan Hart4f60f982014-10-27 08:11:17 -0700122 store.unsetDelegate(delegate);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800123 deviceService.removeListener(deviceListener);
Madan Jampanic626f1e2015-05-29 13:53:38 -0700124 eventHandlingExecutor.shutdown();
alshabib7674db42014-09-12 23:40:46 -0700125 log.info("Stopped");
126 }
127
128 @Override
129 public void addProcessor(PacketProcessor processor, int priority) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900130 checkPermission(PACKET_EVENT);
alshabib030111e2014-09-15 15:56:42 -0700131 checkNotNull(processor, "Processor cannot be null");
Thomas Vachuska924cda42015-09-22 12:11:27 -0700132 ProcessorEntry entry = new ProcessorEntry(processor, priority);
133
134 // Insert the new processor according to its priority.
135 int i = 0;
136 for (; i < processors.size(); i++) {
137 if (priority < processors.get(i).priority()) {
138 break;
139 }
140 }
141 processors.add(i, entry);
alshabib7674db42014-09-12 23:40:46 -0700142 }
143
144 @Override
145 public void removeProcessor(PacketProcessor processor) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900146 checkPermission(PACKET_EVENT);
tomc370ebd2014-09-16 01:25:21 -0700147 checkNotNull(processor, "Processor cannot be null");
Thomas Vachuska924cda42015-09-22 12:11:27 -0700148
149 // Remove the processor entry.
150 for (int i = 0; i < processors.size(); i++) {
151 if (processors.get(i).processor() == processor) {
152 processors.remove(i);
153 break;
154 }
155 }
alshabib7674db42014-09-12 23:40:46 -0700156 }
157
158 @Override
Thomas Vachuska924cda42015-09-22 12:11:27 -0700159 public List<PacketProcessorEntry> getProcessors() {
160 return ImmutableList.copyOf(processors);
Thomas Vachuska7f171b22015-08-21 12:49:08 -0700161 }
162
163 @Override
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800164 public void requestPackets(TrafficSelector selector, PacketPriority priority,
165 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900166 checkPermission(PACKET_READ);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800167 checkNotNull(selector, "Selector cannot be null");
168 checkNotNull(appId, "Application ID cannot be null");
169
Thomas Vachuska27bee092015-06-23 19:03:10 -0700170 PacketRequest request = new DefaultPacketRequest(selector, priority, appId);
Brian O'Connor21b028e2015-10-08 22:50:02 -0700171 store.requestPackets(request);
Saurav Dasc313c402015-02-27 10:09:47 -0800172 }
173
174 @Override
Thomas Vachuska27bee092015-06-23 19:03:10 -0700175 public void cancelPackets(TrafficSelector selector, PacketPriority priority,
176 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900177 checkPermission(PACKET_READ);
Saurav Dasc313c402015-02-27 10:09:47 -0800178 checkNotNull(selector, "Selector cannot be null");
179 checkNotNull(appId, "Application ID cannot be null");
Saurav Dasc313c402015-02-27 10:09:47 -0800180
Thomas Vachuska27bee092015-06-23 19:03:10 -0700181 PacketRequest request = new DefaultPacketRequest(selector, priority, appId);
Brian O'Connor21b028e2015-10-08 22:50:02 -0700182 store.cancelPackets(request);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800183 }
184
Thomas Vachuska7f171b22015-08-21 12:49:08 -0700185 @Override
186 public List<PacketRequest> getRequests() {
187 return store.existingRequests();
188 }
189
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800190 /**
Thomas Vachuska924cda42015-09-22 12:11:27 -0700191 * Pushes all rules to the specified device.
192 *
193 * @param device device on which to install packet request flows
194 */
195 private void pushRulesToDevice(Device device) {
196 log.debug("Pushing packet requests to device {}", device.id());
197 for (PacketRequest request : store.existingRequests()) {
198 pushRule(device, request);
199 }
200 }
201
202 /**
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800203 * Pushes a packet request flow rule to all devices.
204 *
205 * @param request the packet request
206 */
207 private void pushToAllDevices(PacketRequest request) {
Thomas Vachuska88fd6902015-08-04 10:08:34 -0700208 log.debug("Pushing packet request {} to all devices", request);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800209 for (Device device : deviceService.getDevices()) {
alshabib42947782015-03-31 14:59:06 -0700210 pushRule(device, request);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800211 }
212 }
213
214 /**
Thomas Vachuska27bee092015-06-23 19:03:10 -0700215 * Removes packet request flow rule from all devices.
216 *
217 * @param request the packet request
218 */
219 private void removeFromAllDevices(PacketRequest request) {
Thomas Vachuska924cda42015-09-22 12:11:27 -0700220 deviceService.getAvailableDevices().forEach(d -> removeRule(d, request));
Thomas Vachuska27bee092015-06-23 19:03:10 -0700221 }
222
223 /**
224 * Pushes packet intercept flow rules to the device.
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800225 *
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700226 * @param device the device to push the rules to
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800227 * @param request the packet request
228 */
229 private void pushRule(Device device, PacketRequest request) {
Marc De Leenheerb9311372015-07-09 11:36:49 -0700230 if (!device.type().equals(Device.Type.SWITCH)) {
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800231 return;
232 }
233
Thomas Vachuska27bee092015-06-23 19:03:10 -0700234 ForwardingObjective forwarding = createBuilder(request)
Jonathan Hart17d00452015-04-21 17:10:00 -0700235 .add(new ObjectiveContext() {
236 @Override
Jonathan Hart17d00452015-04-21 17:10:00 -0700237 public void onError(Objective objective, ObjectiveError error) {
Thomas Vachuska88fd6902015-08-04 10:08:34 -0700238 log.warn("Failed to install packet request {} to {}: {}",
239 request, device.id(), error);
Jonathan Hart17d00452015-04-21 17:10:00 -0700240 }
241 });
242
243 objectiveService.forward(device.id(), forwarding);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800244 }
245
Thomas Vachuska27bee092015-06-23 19:03:10 -0700246 /**
247 * Removes packet intercept flow rules from the device.
248 *
249 * @param device the device to remove the rules deom
250 * @param request the packet request
251 */
252 private void removeRule(Device device, PacketRequest request) {
Marc De Leenheerb9311372015-07-09 11:36:49 -0700253 if (!device.type().equals(Device.Type.SWITCH)) {
Thomas Vachuska27bee092015-06-23 19:03:10 -0700254 return;
255 }
Thomas Vachuska27bee092015-06-23 19:03:10 -0700256 ForwardingObjective forwarding = createBuilder(request)
257 .remove(new ObjectiveContext() {
258 @Override
259 public void onError(Objective objective, ObjectiveError error) {
Thomas Vachuska88fd6902015-08-04 10:08:34 -0700260 log.warn("Failed to withdraw packet request {} from {}: {}",
261 request, device.id(), error);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700262 }
263 });
Thomas Vachuska27bee092015-06-23 19:03:10 -0700264 objectiveService.forward(device.id(), forwarding);
265 }
266
267 private DefaultForwardingObjective.Builder createBuilder(PacketRequest request) {
268 return DefaultForwardingObjective.builder()
269 .withPriority(request.priority().priorityValue())
270 .withSelector(request.selector())
271 .fromApp(appId)
272 .withFlag(ForwardingObjective.Flag.VERSATILE)
273 .withTreatment(DefaultTrafficTreatment.builder().punt().build())
274 .makePermanent();
275 }
276
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800277 @Override
alshabib7674db42014-09-12 23:40:46 -0700278 public void emit(OutboundPacket packet) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900279 checkPermission(PACKET_WRITE);
tomc370ebd2014-09-16 01:25:21 -0700280 checkNotNull(packet, "Packet cannot be null");
Jonathan Hart4f60f982014-10-27 08:11:17 -0700281 store.emit(packet);
282 }
283
284 private void localEmit(OutboundPacket packet) {
Thomas Vachuska924cda42015-09-22 12:11:27 -0700285 Device device = deviceService.getDevice(packet.sendThrough());
Jonathan Hart7466d612014-11-24 17:09:53 -0800286 if (device == null) {
287 return;
288 }
Thomas Vachuska27bee092015-06-23 19:03:10 -0700289 PacketProvider packetProvider = getProvider(device.providerId());
alshabib3d643ec2014-10-22 18:33:00 -0700290 if (packetProvider != null) {
291 packetProvider.emit(packet);
292 }
alshabib7674db42014-09-12 23:40:46 -0700293 }
294
295 @Override
tomc370ebd2014-09-16 01:25:21 -0700296 protected PacketProviderService createProviderService(PacketProvider provider) {
alshabib7674db42014-09-12 23:40:46 -0700297 return new InternalPacketProviderService(provider);
298 }
299
Thomas Vachuska924cda42015-09-22 12:11:27 -0700300 /**
301 * Personalized packet provider service issued to the supplied provider.
302 */
alshabib7674db42014-09-12 23:40:46 -0700303 private class InternalPacketProviderService
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700304 extends AbstractProviderService<PacketProvider>
305 implements PacketProviderService {
alshabib7674db42014-09-12 23:40:46 -0700306
307 protected InternalPacketProviderService(PacketProvider provider) {
308 super(provider);
309 }
310
311 @Override
312 public void processPacket(PacketContext context) {
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800313 // TODO filter packets sent to processors based on registrations
Thomas Vachuska924cda42015-09-22 12:11:27 -0700314 for (ProcessorEntry entry : processors) {
Jonathan Hartf5638302015-11-16 10:56:20 -0800315 try {
316 long start = System.nanoTime();
317 entry.processor().process(context);
318 entry.addNanos(System.nanoTime() - start);
319 } catch (Exception e) {
320 log.warn("Packet processor {} threw an exception", entry.processor(), e);
321 }
alshabib7674db42014-09-12 23:40:46 -0700322 }
323 }
324
325 }
Jonathan Hart4f60f982014-10-27 08:11:17 -0700326
327 /**
328 * Internal callback from the packet store.
329 */
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700330 private class InternalStoreDelegate implements PacketStoreDelegate {
Jonathan Hart4f60f982014-10-27 08:11:17 -0700331 @Override
332 public void notify(PacketEvent event) {
333 localEmit(event.subject());
334 }
Brian O'Connor21b028e2015-10-08 22:50:02 -0700335
336 @Override
337 public void requestPackets(PacketRequest request) {
338 pushToAllDevices(request);
339 }
340
341 @Override
342 public void cancelPackets(PacketRequest request) {
343 removeFromAllDevices(request);
344 }
Jonathan Hart4f60f982014-10-27 08:11:17 -0700345 }
346
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800347 /**
348 * Internal listener for device service events.
349 */
350 private class InternalDeviceListener implements DeviceListener {
351 @Override
352 public void event(DeviceEvent event) {
Madan Jampanic626f1e2015-05-29 13:53:38 -0700353 eventHandlingExecutor.execute(() -> {
354 try {
355 Device device = event.subject();
356 switch (event.type()) {
Thomas Vachuska924cda42015-09-22 12:11:27 -0700357 case DEVICE_ADDED:
358 case DEVICE_AVAILABILITY_CHANGED:
359 if (deviceService.isAvailable(event.subject().id())) {
360 pushRulesToDevice(device);
Madan Jampanic626f1e2015-05-29 13:53:38 -0700361 }
Thomas Vachuska924cda42015-09-22 12:11:27 -0700362 break;
363 default:
364 break;
sangho864a9db22015-04-28 12:06:31 -0700365 }
Madan Jampanic626f1e2015-05-29 13:53:38 -0700366 } catch (Exception e) {
367 log.warn("Failed to process {}", event, e);
368 }
369 });
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800370 }
371 }
372
Thomas Vachuska924cda42015-09-22 12:11:27 -0700373 /**
374 * Entity for tracking stats for a packet processor.
375 */
376 private class ProcessorEntry implements PacketProcessorEntry {
377 private final PacketProcessor processor;
378 private final int priority;
379 private long invocations = 0;
380 private long nanos = 0;
381
382 public ProcessorEntry(PacketProcessor processor, int priority) {
383 this.processor = processor;
384 this.priority = priority;
385 }
386
387 @Override
388 public PacketProcessor processor() {
389 return processor;
390 }
391
392 @Override
393 public int priority() {
394 return priority;
395 }
396
397 @Override
398 public long invocations() {
399 return invocations;
400 }
401
402 @Override
403 public long totalNanos() {
404 return nanos;
405 }
406
407 @Override
408 public long averageNanos() {
409 return invocations > 0 ? nanos / invocations : 0;
410 }
411
412 void addNanos(long nanos) {
413 this.nanos += nanos;
414 this.invocations++;
415 }
416 }
alshabibae857582014-09-12 23:53:10 -0700417}