blob: 79ac4b07496a2b4ca0b360032ec1430d33b874ec [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;
Madan Jampani6f8b7022015-12-07 16:59:59 -080020
alshabib7674db42014-09-12 23:40:46 -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;
Madan Jampani6f8b7022015-12-07 16:59:59 -080027import org.onosproject.cluster.ClusterService;
28import org.onosproject.cluster.NodeId;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080029import org.onosproject.core.ApplicationId;
Thomas Vachuska6cba4952015-04-22 12:38:22 -070030import org.onosproject.core.CoreService;
Brian O'Connorabafb502014-12-02 22:26:20 -080031import org.onosproject.net.Device;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080032import org.onosproject.net.device.DeviceEvent;
33import org.onosproject.net.device.DeviceListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.device.DeviceService;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080035import org.onosproject.net.flow.DefaultTrafficTreatment;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080036import org.onosproject.net.flow.FlowRuleService;
37import org.onosproject.net.flow.TrafficSelector;
Jonathan Hart17d00452015-04-21 17:10:00 -070038import org.onosproject.net.flowobjective.DefaultForwardingObjective;
39import org.onosproject.net.flowobjective.FlowObjectiveService;
40import org.onosproject.net.flowobjective.ForwardingObjective;
41import org.onosproject.net.flowobjective.Objective;
42import org.onosproject.net.flowobjective.ObjectiveContext;
43import org.onosproject.net.flowobjective.ObjectiveError;
alshabib42947782015-03-31 14:59:06 -070044import org.onosproject.net.packet.DefaultPacketRequest;
Brian O'Connorabafb502014-12-02 22:26:20 -080045import org.onosproject.net.packet.OutboundPacket;
46import org.onosproject.net.packet.PacketContext;
47import org.onosproject.net.packet.PacketEvent;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080048import org.onosproject.net.packet.PacketPriority;
Brian O'Connorabafb502014-12-02 22:26:20 -080049import org.onosproject.net.packet.PacketProcessor;
Thomas Vachuska924cda42015-09-22 12:11:27 -070050import org.onosproject.net.packet.PacketProcessorEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080051import org.onosproject.net.packet.PacketProvider;
52import org.onosproject.net.packet.PacketProviderRegistry;
53import org.onosproject.net.packet.PacketProviderService;
alshabib42947782015-03-31 14:59:06 -070054import org.onosproject.net.packet.PacketRequest;
Brian O'Connorabafb502014-12-02 22:26:20 -080055import org.onosproject.net.packet.PacketService;
56import org.onosproject.net.packet.PacketStore;
57import org.onosproject.net.packet.PacketStoreDelegate;
58import org.onosproject.net.provider.AbstractProviderRegistry;
59import org.onosproject.net.provider.AbstractProviderService;
alshabib7674db42014-09-12 23:40:46 -070060import org.slf4j.Logger;
61
Thomas Vachuska7f171b22015-08-21 12:49:08 -070062import java.util.List;
Madan Jampanic626f1e2015-05-29 13:53:38 -070063import java.util.concurrent.ExecutorService;
64import java.util.concurrent.Executors;
alshabib089bb772015-03-03 18:26:26 -080065
66import static com.google.common.base.Preconditions.checkNotNull;
Madan Jampanic626f1e2015-05-29 13:53:38 -070067import static org.onlab.util.Tools.groupedThreads;
Changhoon Yoon541ef712015-05-23 17:18:34 +090068import static org.onosproject.security.AppGuard.checkPermission;
Changhoon Yoonb856b812015-08-10 03:47:19 +090069import static org.onosproject.security.AppPermission.Type.*;
Thomas Vachuska7f171b22015-08-21 12:49:08 -070070import static org.slf4j.LoggerFactory.getLogger;
alshabib089bb772015-03-03 18:26:26 -080071
alshabib7674db42014-09-12 23:40:46 -070072/**
73 * Provides a basic implementation of the packet SB & NB APIs.
alshabib7674db42014-09-12 23:40:46 -070074 */
75@Component(immediate = true)
76@Service
tom202175a2014-09-19 19:00:11 -070077public class PacketManager
Thomas Vachuska6cba4952015-04-22 12:38:22 -070078 extends AbstractProviderRegistry<PacketProvider, PacketProviderService>
79 implements PacketService, PacketProviderRegistry {
alshabib7674db42014-09-12 23:40:46 -070080
81 private final Logger log = getLogger(getClass());
82
Thomas Vachuska27bee092015-06-23 19:03:10 -070083 private static final String TABLE_TYPE_MSG =
84 "Table Type cannot be null. For requesting packets without " +
85 "table hints, use other methods in the packetService API";
86
Jonathan Hart4f60f982014-10-27 08:11:17 -070087 private final PacketStoreDelegate delegate = new InternalStoreDelegate();
88
alshabib7674db42014-09-12 23:40:46 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Thomas Vachuska6cba4952015-04-22 12:38:22 -070090 private CoreService coreService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Madan Jampani6f8b7022015-12-07 16:59:59 -080093 private ClusterService clusterService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib7674db42014-09-12 23:40:46 -070096 private DeviceService deviceService;
97
Jonathan Hart4f60f982014-10-27 08:11:17 -070098 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080099 private FlowRuleService flowService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hart4f60f982014-10-27 08:11:17 -0700102 private PacketStore store;
103
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 private FlowObjectiveService objectiveService;
106
Madan Jampanic626f1e2015-05-29 13:53:38 -0700107 private ExecutorService eventHandlingExecutor;
108
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800109 private final DeviceListener deviceListener = new InternalDeviceListener();
110
Thomas Vachuska924cda42015-09-22 12:11:27 -0700111 private final List<ProcessorEntry> processors = Lists.newCopyOnWriteArrayList();
alshabib7674db42014-09-12 23:40:46 -0700112
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700113 private ApplicationId appId;
Madan Jampani6f8b7022015-12-07 16:59:59 -0800114 private NodeId localNodeId;
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700115
alshabib7674db42014-09-12 23:40:46 -0700116 @Activate
117 public void activate() {
Madan Jampanic626f1e2015-05-29 13:53:38 -0700118 eventHandlingExecutor = Executors.newSingleThreadExecutor(
Thomas Vachuska924cda42015-09-22 12:11:27 -0700119 groupedThreads("onos/net/packet", "event-handler"));
Madan Jampani6f8b7022015-12-07 16:59:59 -0800120 localNodeId = clusterService.getLocalNode().id();
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700121 appId = coreService.getAppId(CoreService.CORE_APP_NAME);
Jonathan Hart4f60f982014-10-27 08:11:17 -0700122 store.setDelegate(delegate);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800123 deviceService.addListener(deviceListener);
Thomas Vachuska924cda42015-09-22 12:11:27 -0700124 store.existingRequests().forEach(this::pushToAllDevices);
alshabib7674db42014-09-12 23:40:46 -0700125 log.info("Started");
126 }
127
128 @Deactivate
129 public void deactivate() {
Jonathan Hart4f60f982014-10-27 08:11:17 -0700130 store.unsetDelegate(delegate);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800131 deviceService.removeListener(deviceListener);
Madan Jampanic626f1e2015-05-29 13:53:38 -0700132 eventHandlingExecutor.shutdown();
alshabib7674db42014-09-12 23:40:46 -0700133 log.info("Stopped");
134 }
135
136 @Override
137 public void addProcessor(PacketProcessor processor, int priority) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900138 checkPermission(PACKET_EVENT);
alshabib030111e2014-09-15 15:56:42 -0700139 checkNotNull(processor, "Processor cannot be null");
Thomas Vachuska924cda42015-09-22 12:11:27 -0700140 ProcessorEntry entry = new ProcessorEntry(processor, priority);
141
142 // Insert the new processor according to its priority.
143 int i = 0;
144 for (; i < processors.size(); i++) {
145 if (priority < processors.get(i).priority()) {
146 break;
147 }
148 }
149 processors.add(i, entry);
alshabib7674db42014-09-12 23:40:46 -0700150 }
151
152 @Override
153 public void removeProcessor(PacketProcessor processor) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900154 checkPermission(PACKET_EVENT);
tomc370ebd2014-09-16 01:25:21 -0700155 checkNotNull(processor, "Processor cannot be null");
Thomas Vachuska924cda42015-09-22 12:11:27 -0700156
157 // Remove the processor entry.
158 for (int i = 0; i < processors.size(); i++) {
159 if (processors.get(i).processor() == processor) {
160 processors.remove(i);
161 break;
162 }
163 }
alshabib7674db42014-09-12 23:40:46 -0700164 }
165
166 @Override
Thomas Vachuska924cda42015-09-22 12:11:27 -0700167 public List<PacketProcessorEntry> getProcessors() {
168 return ImmutableList.copyOf(processors);
Thomas Vachuska7f171b22015-08-21 12:49:08 -0700169 }
170
171 @Override
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800172 public void requestPackets(TrafficSelector selector, PacketPriority priority,
173 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900174 checkPermission(PACKET_READ);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800175 checkNotNull(selector, "Selector cannot be null");
176 checkNotNull(appId, "Application ID cannot be null");
177
Madan Jampani6f8b7022015-12-07 16:59:59 -0800178 PacketRequest request = new DefaultPacketRequest(selector, priority, appId, localNodeId);
Brian O'Connor21b028e2015-10-08 22:50:02 -0700179 store.requestPackets(request);
Saurav Dasc313c402015-02-27 10:09:47 -0800180 }
181
182 @Override
Thomas Vachuska27bee092015-06-23 19:03:10 -0700183 public void cancelPackets(TrafficSelector selector, PacketPriority priority,
184 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900185 checkPermission(PACKET_READ);
Saurav Dasc313c402015-02-27 10:09:47 -0800186 checkNotNull(selector, "Selector cannot be null");
187 checkNotNull(appId, "Application ID cannot be null");
Saurav Dasc313c402015-02-27 10:09:47 -0800188
Madan Jampani6f8b7022015-12-07 16:59:59 -0800189 PacketRequest request = new DefaultPacketRequest(selector, priority, appId, localNodeId);
Brian O'Connor21b028e2015-10-08 22:50:02 -0700190 store.cancelPackets(request);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800191 }
192
Thomas Vachuska7f171b22015-08-21 12:49:08 -0700193 @Override
194 public List<PacketRequest> getRequests() {
195 return store.existingRequests();
196 }
197
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800198 /**
Thomas Vachuska924cda42015-09-22 12:11:27 -0700199 * Pushes all rules to the specified device.
200 *
201 * @param device device on which to install packet request flows
202 */
203 private void pushRulesToDevice(Device device) {
204 log.debug("Pushing packet requests to device {}", device.id());
205 for (PacketRequest request : store.existingRequests()) {
206 pushRule(device, request);
207 }
208 }
209
210 /**
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800211 * Pushes a packet request flow rule to all devices.
212 *
213 * @param request the packet request
214 */
215 private void pushToAllDevices(PacketRequest request) {
Thomas Vachuska88fd6902015-08-04 10:08:34 -0700216 log.debug("Pushing packet request {} to all devices", request);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800217 for (Device device : deviceService.getDevices()) {
alshabib42947782015-03-31 14:59:06 -0700218 pushRule(device, request);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800219 }
220 }
221
222 /**
Thomas Vachuska27bee092015-06-23 19:03:10 -0700223 * Removes packet request flow rule from all devices.
224 *
225 * @param request the packet request
226 */
227 private void removeFromAllDevices(PacketRequest request) {
Thomas Vachuska924cda42015-09-22 12:11:27 -0700228 deviceService.getAvailableDevices().forEach(d -> removeRule(d, request));
Thomas Vachuska27bee092015-06-23 19:03:10 -0700229 }
230
231 /**
232 * Pushes packet intercept flow rules to the device.
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800233 *
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700234 * @param device the device to push the rules to
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800235 * @param request the packet request
236 */
237 private void pushRule(Device device, PacketRequest request) {
Marc De Leenheerb9311372015-07-09 11:36:49 -0700238 if (!device.type().equals(Device.Type.SWITCH)) {
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800239 return;
240 }
241
Thomas Vachuska27bee092015-06-23 19:03:10 -0700242 ForwardingObjective forwarding = createBuilder(request)
Jonathan Hart17d00452015-04-21 17:10:00 -0700243 .add(new ObjectiveContext() {
244 @Override
Jonathan Hart17d00452015-04-21 17:10:00 -0700245 public void onError(Objective objective, ObjectiveError error) {
Thomas Vachuska88fd6902015-08-04 10:08:34 -0700246 log.warn("Failed to install packet request {} to {}: {}",
247 request, device.id(), error);
Jonathan Hart17d00452015-04-21 17:10:00 -0700248 }
249 });
250
251 objectiveService.forward(device.id(), forwarding);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800252 }
253
Thomas Vachuska27bee092015-06-23 19:03:10 -0700254 /**
255 * Removes packet intercept flow rules from the device.
256 *
257 * @param device the device to remove the rules deom
258 * @param request the packet request
259 */
260 private void removeRule(Device device, PacketRequest request) {
Marc De Leenheerb9311372015-07-09 11:36:49 -0700261 if (!device.type().equals(Device.Type.SWITCH)) {
Thomas Vachuska27bee092015-06-23 19:03:10 -0700262 return;
263 }
Thomas Vachuska27bee092015-06-23 19:03:10 -0700264 ForwardingObjective forwarding = createBuilder(request)
265 .remove(new ObjectiveContext() {
266 @Override
267 public void onError(Objective objective, ObjectiveError error) {
Thomas Vachuska88fd6902015-08-04 10:08:34 -0700268 log.warn("Failed to withdraw packet request {} from {}: {}",
269 request, device.id(), error);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700270 }
271 });
Thomas Vachuska27bee092015-06-23 19:03:10 -0700272 objectiveService.forward(device.id(), forwarding);
273 }
274
275 private DefaultForwardingObjective.Builder createBuilder(PacketRequest request) {
276 return DefaultForwardingObjective.builder()
277 .withPriority(request.priority().priorityValue())
278 .withSelector(request.selector())
279 .fromApp(appId)
280 .withFlag(ForwardingObjective.Flag.VERSATILE)
281 .withTreatment(DefaultTrafficTreatment.builder().punt().build())
282 .makePermanent();
283 }
284
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800285 @Override
alshabib7674db42014-09-12 23:40:46 -0700286 public void emit(OutboundPacket packet) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900287 checkPermission(PACKET_WRITE);
tomc370ebd2014-09-16 01:25:21 -0700288 checkNotNull(packet, "Packet cannot be null");
Jonathan Hart4f60f982014-10-27 08:11:17 -0700289 store.emit(packet);
290 }
291
292 private void localEmit(OutboundPacket packet) {
Thomas Vachuska924cda42015-09-22 12:11:27 -0700293 Device device = deviceService.getDevice(packet.sendThrough());
Jonathan Hart7466d612014-11-24 17:09:53 -0800294 if (device == null) {
295 return;
296 }
Thomas Vachuska27bee092015-06-23 19:03:10 -0700297 PacketProvider packetProvider = getProvider(device.providerId());
alshabib3d643ec2014-10-22 18:33:00 -0700298 if (packetProvider != null) {
299 packetProvider.emit(packet);
300 }
alshabib7674db42014-09-12 23:40:46 -0700301 }
302
303 @Override
tomc370ebd2014-09-16 01:25:21 -0700304 protected PacketProviderService createProviderService(PacketProvider provider) {
alshabib7674db42014-09-12 23:40:46 -0700305 return new InternalPacketProviderService(provider);
306 }
307
Thomas Vachuska924cda42015-09-22 12:11:27 -0700308 /**
309 * Personalized packet provider service issued to the supplied provider.
310 */
alshabib7674db42014-09-12 23:40:46 -0700311 private class InternalPacketProviderService
Thomas Vachuska6cba4952015-04-22 12:38:22 -0700312 extends AbstractProviderService<PacketProvider>
313 implements PacketProviderService {
alshabib7674db42014-09-12 23:40:46 -0700314
315 protected InternalPacketProviderService(PacketProvider provider) {
316 super(provider);
317 }
318
319 @Override
320 public void processPacket(PacketContext context) {
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800321 // TODO filter packets sent to processors based on registrations
Thomas Vachuska924cda42015-09-22 12:11:27 -0700322 for (ProcessorEntry entry : processors) {
Jonathan Hartf5638302015-11-16 10:56:20 -0800323 try {
324 long start = System.nanoTime();
325 entry.processor().process(context);
326 entry.addNanos(System.nanoTime() - start);
327 } catch (Exception e) {
328 log.warn("Packet processor {} threw an exception", entry.processor(), e);
329 }
alshabib7674db42014-09-12 23:40:46 -0700330 }
331 }
332
333 }
Jonathan Hart4f60f982014-10-27 08:11:17 -0700334
335 /**
336 * Internal callback from the packet store.
337 */
Thomas Vachuska866b46a2015-04-30 00:26:55 -0700338 private class InternalStoreDelegate implements PacketStoreDelegate {
Jonathan Hart4f60f982014-10-27 08:11:17 -0700339 @Override
340 public void notify(PacketEvent event) {
341 localEmit(event.subject());
342 }
Brian O'Connor21b028e2015-10-08 22:50:02 -0700343
344 @Override
345 public void requestPackets(PacketRequest request) {
346 pushToAllDevices(request);
347 }
348
349 @Override
350 public void cancelPackets(PacketRequest request) {
351 removeFromAllDevices(request);
352 }
Jonathan Hart4f60f982014-10-27 08:11:17 -0700353 }
354
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800355 /**
356 * Internal listener for device service events.
357 */
358 private class InternalDeviceListener implements DeviceListener {
359 @Override
360 public void event(DeviceEvent event) {
Madan Jampanic626f1e2015-05-29 13:53:38 -0700361 eventHandlingExecutor.execute(() -> {
362 try {
363 Device device = event.subject();
364 switch (event.type()) {
Thomas Vachuska924cda42015-09-22 12:11:27 -0700365 case DEVICE_ADDED:
366 case DEVICE_AVAILABILITY_CHANGED:
367 if (deviceService.isAvailable(event.subject().id())) {
368 pushRulesToDevice(device);
Madan Jampanic626f1e2015-05-29 13:53:38 -0700369 }
Thomas Vachuska924cda42015-09-22 12:11:27 -0700370 break;
371 default:
372 break;
sangho864a9db22015-04-28 12:06:31 -0700373 }
Madan Jampanic626f1e2015-05-29 13:53:38 -0700374 } catch (Exception e) {
375 log.warn("Failed to process {}", event, e);
376 }
377 });
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800378 }
379 }
380
Thomas Vachuska924cda42015-09-22 12:11:27 -0700381 /**
382 * Entity for tracking stats for a packet processor.
383 */
384 private class ProcessorEntry implements PacketProcessorEntry {
385 private final PacketProcessor processor;
386 private final int priority;
387 private long invocations = 0;
388 private long nanos = 0;
389
390 public ProcessorEntry(PacketProcessor processor, int priority) {
391 this.processor = processor;
392 this.priority = priority;
393 }
394
395 @Override
396 public PacketProcessor processor() {
397 return processor;
398 }
399
400 @Override
401 public int priority() {
402 return priority;
403 }
404
405 @Override
406 public long invocations() {
407 return invocations;
408 }
409
410 @Override
411 public long totalNanos() {
412 return nanos;
413 }
414
415 @Override
416 public long averageNanos() {
417 return invocations > 0 ? nanos / invocations : 0;
418 }
419
420 void addNanos(long nanos) {
421 this.nanos += nanos;
422 this.invocations++;
423 }
424 }
alshabibae857582014-09-12 23:53:10 -0700425}