Committed by
Gerrit Code Review
ONOS- 2946 Adding ability to view packet processor statistics.
Change-Id: Ic55ec670b197b1ee08f2d11f97658fd614da1614
Showing
5 changed files
with
167 additions
and
43 deletions
... | @@ -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 | } | ... | ... |
-
Please register or login to post a comment