Thomas Vachuska
Committed by Gerrit Code Review

ONOS- 2946 Adding ability to view packet processor statistics.

Change-Id: Ic55ec670b197b1ee08f2d11f97658fd614da1614
...@@ -17,7 +17,7 @@ package org.onosproject.cli.net; ...@@ -17,7 +17,7 @@ package org.onosproject.cli.net;
17 17
18 import org.apache.karaf.shell.commands.Command; 18 import org.apache.karaf.shell.commands.Command;
19 import org.onosproject.cli.AbstractShellCommand; 19 import org.onosproject.cli.AbstractShellCommand;
20 -import org.onosproject.net.packet.PacketProcessor; 20 +import org.onosproject.net.packet.PacketProcessorEntry;
21 import org.onosproject.net.packet.PacketService; 21 import org.onosproject.net.packet.PacketService;
22 22
23 import static org.onosproject.net.packet.PacketProcessor.ADVISOR_MAX; 23 import static org.onosproject.net.packet.PacketProcessor.ADVISOR_MAX;
...@@ -30,7 +30,7 @@ import static org.onosproject.net.packet.PacketProcessor.DIRECTOR_MAX; ...@@ -30,7 +30,7 @@ import static org.onosproject.net.packet.PacketProcessor.DIRECTOR_MAX;
30 description = "Lists packet processors") 30 description = "Lists packet processors")
31 public class PacketProcessorsListCommand extends AbstractShellCommand { 31 public class PacketProcessorsListCommand extends AbstractShellCommand {
32 32
33 - private static final String FMT = "priority=%s, class=%s"; 33 + private static final String FMT = "priority=%s, class=%s, packets=%d, avgNanos=%d";
34 34
35 @Override 35 @Override
36 protected void execute() { 36 protected void execute() {
...@@ -43,8 +43,10 @@ public class PacketProcessorsListCommand extends AbstractShellCommand { ...@@ -43,8 +43,10 @@ public class PacketProcessorsListCommand extends AbstractShellCommand {
43 } 43 }
44 } 44 }
45 45
46 - private void print(int priority, PacketProcessor processor) { 46 + private void print(PacketProcessorEntry entry) {
47 - print(FMT, priorityFormat(priority), processor.getClass().getName()); 47 + print(FMT, priorityFormat(entry.priority()),
48 + entry.processor().getClass().getName(),
49 + entry.invocations(), entry.averageNanos());
48 } 50 }
49 51
50 private String priorityFormat(int priority) { 52 private String priorityFormat(int priority) {
......
1 +/*
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 + */
16 +package org.onosproject.net.packet;
17 +
18 +/**
19 + * Packet processor entry tracking the processor, its priority and
20 + * time consumption.
21 + */
22 +public interface PacketProcessorEntry {
23 +
24 + /**
25 + * Returns the packet processor.
26 + *
27 + * @return packet processor
28 + */
29 + PacketProcessor processor();
30 +
31 + /**
32 + * Returns the packet processor priority.
33 + *
34 + * @return processor priority
35 + */
36 + int priority();
37 +
38 + /**
39 + * Returns the number of invocations.
40 + *
41 + * @return number of invocations
42 + */
43 + long invocations();
44 +
45 + /**
46 + * Returns the total time, in nanoseconds, spent processing packets.
47 + *
48 + * @return total time in nanos
49 + */
50 + long totalNanos();
51 +
52 + /**
53 + * Returns the average time, in nanoseconds, spent processing packets.
54 + *
55 + * @return average time in nanos
56 + */
57 + long averageNanos();
58 +}
...@@ -20,7 +20,6 @@ import org.onosproject.core.ApplicationId; ...@@ -20,7 +20,6 @@ import org.onosproject.core.ApplicationId;
20 import org.onosproject.net.flow.TrafficSelector; 20 import org.onosproject.net.flow.TrafficSelector;
21 21
22 import java.util.List; 22 import java.util.List;
23 -import java.util.Map;
24 23
25 /** 24 /**
26 * Service for intercepting data plane packets and for emitting synthetic 25 * Service for intercepting data plane packets and for emitting synthetic
...@@ -52,13 +51,12 @@ public interface PacketService { ...@@ -52,13 +51,12 @@ public interface PacketService {
52 void removeProcessor(PacketProcessor processor); 51 void removeProcessor(PacketProcessor processor);
53 52
54 /** 53 /**
55 - * Returns priority bindings of all registered packet processors. 54 + * Returns priority bindings of all registered packet processor entries.
56 * 55 *
57 - * @return list of existing packet processors 56 + * @return list of existing packet processor entries
58 */ 57 */
59 @Beta 58 @Beta
60 - // TODO: Consider returning list of PacketProcessorEntry with processor, priority and stats 59 + List<PacketProcessorEntry> getProcessors();
61 - Map<Integer, PacketProcessor> getProcessors();
62 60
63 /** 61 /**
64 * Requests that packets matching the given selector are punted from the 62 * Requests that packets matching the given selector are punted from the
......
...@@ -19,7 +19,6 @@ import org.onosproject.core.ApplicationId; ...@@ -19,7 +19,6 @@ import org.onosproject.core.ApplicationId;
19 import org.onosproject.net.flow.TrafficSelector; 19 import org.onosproject.net.flow.TrafficSelector;
20 20
21 import java.util.List; 21 import java.util.List;
22 -import java.util.Map;
23 22
24 /** 23 /**
25 * Test adapter for packet service. 24 * Test adapter for packet service.
...@@ -34,7 +33,7 @@ public class PacketServiceAdapter implements PacketService { ...@@ -34,7 +33,7 @@ public class PacketServiceAdapter implements PacketService {
34 } 33 }
35 34
36 @Override 35 @Override
37 - public Map<Integer, PacketProcessor> getProcessors() { 36 + public List<PacketProcessorEntry> getProcessors() {
38 return null; 37 return null;
39 } 38 }
40 39
......
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
15 */ 15 */
16 package org.onosproject.net.packet.impl; 16 package org.onosproject.net.packet.impl;
17 17
18 -import com.google.common.collect.ImmutableMap; 18 +import com.google.common.collect.ImmutableList;
19 +import com.google.common.collect.Lists;
19 import org.apache.felix.scr.annotations.Activate; 20 import org.apache.felix.scr.annotations.Activate;
20 import org.apache.felix.scr.annotations.Component; 21 import org.apache.felix.scr.annotations.Component;
21 import org.apache.felix.scr.annotations.Deactivate; 22 import org.apache.felix.scr.annotations.Deactivate;
...@@ -43,6 +44,7 @@ import org.onosproject.net.packet.PacketContext; ...@@ -43,6 +44,7 @@ import org.onosproject.net.packet.PacketContext;
43 import org.onosproject.net.packet.PacketEvent; 44 import org.onosproject.net.packet.PacketEvent;
44 import org.onosproject.net.packet.PacketPriority; 45 import org.onosproject.net.packet.PacketPriority;
45 import org.onosproject.net.packet.PacketProcessor; 46 import org.onosproject.net.packet.PacketProcessor;
47 +import org.onosproject.net.packet.PacketProcessorEntry;
46 import org.onosproject.net.packet.PacketProvider; 48 import org.onosproject.net.packet.PacketProvider;
47 import org.onosproject.net.packet.PacketProviderRegistry; 49 import org.onosproject.net.packet.PacketProviderRegistry;
48 import org.onosproject.net.packet.PacketProviderService; 50 import org.onosproject.net.packet.PacketProviderService;
...@@ -55,8 +57,6 @@ import org.onosproject.net.provider.AbstractProviderService; ...@@ -55,8 +57,6 @@ import org.onosproject.net.provider.AbstractProviderService;
55 import org.slf4j.Logger; 57 import org.slf4j.Logger;
56 58
57 import java.util.List; 59 import java.util.List;
58 -import java.util.Map;
59 -import java.util.concurrent.ConcurrentHashMap;
60 import java.util.concurrent.ExecutorService; 60 import java.util.concurrent.ExecutorService;
61 import java.util.concurrent.Executors; 61 import java.util.concurrent.Executors;
62 62
...@@ -102,18 +102,18 @@ public class PacketManager ...@@ -102,18 +102,18 @@ public class PacketManager
102 102
103 private final DeviceListener deviceListener = new InternalDeviceListener(); 103 private final DeviceListener deviceListener = new InternalDeviceListener();
104 104
105 - private final Map<Integer, PacketProcessor> processors = new ConcurrentHashMap<>(); 105 + private final List<ProcessorEntry> processors = Lists.newCopyOnWriteArrayList();
106 106
107 private ApplicationId appId; 107 private ApplicationId appId;
108 108
109 @Activate 109 @Activate
110 public void activate() { 110 public void activate() {
111 eventHandlingExecutor = Executors.newSingleThreadExecutor( 111 eventHandlingExecutor = Executors.newSingleThreadExecutor(
112 - groupedThreads("onos/net/packet", "event-handler")); 112 + groupedThreads("onos/net/packet", "event-handler"));
113 appId = coreService.getAppId(CoreService.CORE_APP_NAME); 113 appId = coreService.getAppId(CoreService.CORE_APP_NAME);
114 store.setDelegate(delegate); 114 store.setDelegate(delegate);
115 deviceService.addListener(deviceListener); 115 deviceService.addListener(deviceListener);
116 - // TODO: Should we request packets for all existing devices? I believe we should. 116 + store.existingRequests().forEach(this::pushToAllDevices);
117 log.info("Started"); 117 log.info("Started");
118 } 118 }
119 119
...@@ -121,6 +121,7 @@ public class PacketManager ...@@ -121,6 +121,7 @@ public class PacketManager
121 public void deactivate() { 121 public void deactivate() {
122 store.unsetDelegate(delegate); 122 store.unsetDelegate(delegate);
123 deviceService.removeListener(deviceListener); 123 deviceService.removeListener(deviceListener);
124 + store.existingRequests().forEach(this::removeFromAllDevices);
124 eventHandlingExecutor.shutdown(); 125 eventHandlingExecutor.shutdown();
125 log.info("Stopped"); 126 log.info("Stopped");
126 } 127 }
...@@ -129,19 +130,35 @@ public class PacketManager ...@@ -129,19 +130,35 @@ public class PacketManager
129 public void addProcessor(PacketProcessor processor, int priority) { 130 public void addProcessor(PacketProcessor processor, int priority) {
130 checkPermission(PACKET_EVENT); 131 checkPermission(PACKET_EVENT);
131 checkNotNull(processor, "Processor cannot be null"); 132 checkNotNull(processor, "Processor cannot be null");
132 - processors.put(priority, processor); 133 + ProcessorEntry entry = new ProcessorEntry(processor, priority);
134 +
135 + // Insert the new processor according to its priority.
136 + int i = 0;
137 + for (; i < processors.size(); i++) {
138 + if (priority < processors.get(i).priority()) {
139 + break;
140 + }
141 + }
142 + processors.add(i, entry);
133 } 143 }
134 144
135 @Override 145 @Override
136 public void removeProcessor(PacketProcessor processor) { 146 public void removeProcessor(PacketProcessor processor) {
137 checkPermission(PACKET_EVENT); 147 checkPermission(PACKET_EVENT);
138 checkNotNull(processor, "Processor cannot be null"); 148 checkNotNull(processor, "Processor cannot be null");
139 - processors.values().remove(processor); 149 +
150 + // Remove the processor entry.
151 + for (int i = 0; i < processors.size(); i++) {
152 + if (processors.get(i).processor() == processor) {
153 + processors.remove(i);
154 + break;
155 + }
156 + }
140 } 157 }
141 158
142 @Override 159 @Override
143 - public Map<Integer, PacketProcessor> getProcessors() { 160 + public List<PacketProcessorEntry> getProcessors() {
144 - return ImmutableMap.copyOf(processors); 161 + return ImmutableList.copyOf(processors);
145 } 162 }
146 163
147 @Override 164 @Override
...@@ -176,6 +193,18 @@ public class PacketManager ...@@ -176,6 +193,18 @@ public class PacketManager
176 } 193 }
177 194
178 /** 195 /**
196 + * Pushes all rules to the specified device.
197 + *
198 + * @param device device on which to install packet request flows
199 + */
200 + private void pushRulesToDevice(Device device) {
201 + log.debug("Pushing packet requests to device {}", device.id());
202 + for (PacketRequest request : store.existingRequests()) {
203 + pushRule(device, request);
204 + }
205 + }
206 +
207 + /**
179 * Pushes a packet request flow rule to all devices. 208 * Pushes a packet request flow rule to all devices.
180 * 209 *
181 * @param request the packet request 210 * @param request the packet request
...@@ -187,16 +216,13 @@ public class PacketManager ...@@ -187,16 +216,13 @@ public class PacketManager
187 } 216 }
188 } 217 }
189 218
190 -
191 /** 219 /**
192 * Removes packet request flow rule from all devices. 220 * Removes packet request flow rule from all devices.
193 * 221 *
194 * @param request the packet request 222 * @param request the packet request
195 */ 223 */
196 private void removeFromAllDevices(PacketRequest request) { 224 private void removeFromAllDevices(PacketRequest request) {
197 - for (Device device : deviceService.getDevices()) { 225 + deviceService.getAvailableDevices().forEach(d -> removeRule(d, request));
198 - removeRule(device, request);
199 - }
200 } 226 }
201 227
202 /** 228 /**
...@@ -232,7 +258,6 @@ public class PacketManager ...@@ -232,7 +258,6 @@ public class PacketManager
232 if (!device.type().equals(Device.Type.SWITCH)) { 258 if (!device.type().equals(Device.Type.SWITCH)) {
233 return; 259 return;
234 } 260 }
235 -
236 ForwardingObjective forwarding = createBuilder(request) 261 ForwardingObjective forwarding = createBuilder(request)
237 .remove(new ObjectiveContext() { 262 .remove(new ObjectiveContext() {
238 @Override 263 @Override
...@@ -241,7 +266,6 @@ public class PacketManager ...@@ -241,7 +266,6 @@ public class PacketManager
241 request, device.id(), error); 266 request, device.id(), error);
242 } 267 }
243 }); 268 });
244 -
245 objectiveService.forward(device.id(), forwarding); 269 objectiveService.forward(device.id(), forwarding);
246 } 270 }
247 271
...@@ -263,12 +287,10 @@ public class PacketManager ...@@ -263,12 +287,10 @@ public class PacketManager
263 } 287 }
264 288
265 private void localEmit(OutboundPacket packet) { 289 private void localEmit(OutboundPacket packet) {
266 - final Device device = deviceService.getDevice(packet.sendThrough()); 290 + Device device = deviceService.getDevice(packet.sendThrough());
267 -
268 if (device == null) { 291 if (device == null) {
269 return; 292 return;
270 } 293 }
271 -
272 PacketProvider packetProvider = getProvider(device.providerId()); 294 PacketProvider packetProvider = getProvider(device.providerId());
273 if (packetProvider != null) { 295 if (packetProvider != null) {
274 packetProvider.emit(packet); 296 packetProvider.emit(packet);
...@@ -280,7 +302,9 @@ public class PacketManager ...@@ -280,7 +302,9 @@ public class PacketManager
280 return new InternalPacketProviderService(provider); 302 return new InternalPacketProviderService(provider);
281 } 303 }
282 304
283 - // Personalized packet provider service issued to the supplied provider. 305 + /**
306 + * Personalized packet provider service issued to the supplied provider.
307 + */
284 private class InternalPacketProviderService 308 private class InternalPacketProviderService
285 extends AbstractProviderService<PacketProvider> 309 extends AbstractProviderService<PacketProvider>
286 implements PacketProviderService { 310 implements PacketProviderService {
...@@ -292,8 +316,10 @@ public class PacketManager ...@@ -292,8 +316,10 @@ public class PacketManager
292 @Override 316 @Override
293 public void processPacket(PacketContext context) { 317 public void processPacket(PacketContext context) {
294 // TODO filter packets sent to processors based on registrations 318 // TODO filter packets sent to processors based on registrations
295 - for (PacketProcessor processor : processors.values()) { 319 + for (ProcessorEntry entry : processors) {
296 - processor.process(context); 320 + long start = System.nanoTime();
321 + entry.processor().process(context);
322 + entry.addNanos(System.nanoTime() - start);
297 } 323 }
298 } 324 }
299 325
...@@ -319,17 +345,14 @@ public class PacketManager ...@@ -319,17 +345,14 @@ public class PacketManager
319 try { 345 try {
320 Device device = event.subject(); 346 Device device = event.subject();
321 switch (event.type()) { 347 switch (event.type()) {
322 - case DEVICE_ADDED: 348 + case DEVICE_ADDED:
323 - case DEVICE_AVAILABILITY_CHANGED: 349 + case DEVICE_AVAILABILITY_CHANGED:
324 - if (deviceService.isAvailable(event.subject().id())) { 350 + if (deviceService.isAvailable(event.subject().id())) {
325 - log.debug("Pushing packet requests to device {}", event.subject().id()); 351 + pushRulesToDevice(device);
326 - for (PacketRequest request : store.existingRequests()) {
327 - pushRule(device, request);
328 } 352 }
329 - } 353 + break;
330 - break; 354 + default:
331 - default: 355 + break;
332 - break;
333 } 356 }
334 } catch (Exception e) { 357 } catch (Exception e) {
335 log.warn("Failed to process {}", event, e); 358 log.warn("Failed to process {}", event, e);
...@@ -338,4 +361,48 @@ public class PacketManager ...@@ -338,4 +361,48 @@ public class PacketManager
338 } 361 }
339 } 362 }
340 363
364 + /**
365 + * Entity for tracking stats for a packet processor.
366 + */
367 + private class ProcessorEntry implements PacketProcessorEntry {
368 + private final PacketProcessor processor;
369 + private final int priority;
370 + private long invocations = 0;
371 + private long nanos = 0;
372 +
373 + public ProcessorEntry(PacketProcessor processor, int priority) {
374 + this.processor = processor;
375 + this.priority = priority;
376 + }
377 +
378 + @Override
379 + public PacketProcessor processor() {
380 + return processor;
381 + }
382 +
383 + @Override
384 + public int priority() {
385 + return priority;
386 + }
387 +
388 + @Override
389 + public long invocations() {
390 + return invocations;
391 + }
392 +
393 + @Override
394 + public long totalNanos() {
395 + return nanos;
396 + }
397 +
398 + @Override
399 + public long averageNanos() {
400 + return invocations > 0 ? nanos / invocations : 0;
401 + }
402 +
403 + void addNanos(long nanos) {
404 + this.nanos += nanos;
405 + this.invocations++;
406 + }
407 + }
341 } 408 }
......