blob: e70076fe7310283420a176bc50b8f26913b4d9d8 [file] [log] [blame]
Ayaka Koshibe7dc1d042015-01-21 15:28:03 -08001/*
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 */
16package org.onosproject.provider.nil.packet.impl;
17
18import static com.google.common.base.Strings.isNullOrEmpty;
19import static org.onlab.util.Tools.delay;
20import static org.onlab.util.Tools.namedThreads;
21import static org.slf4j.LoggerFactory.getLogger;
22
23import java.nio.ByteBuffer;
24import java.util.Dictionary;
25import java.util.concurrent.ExecutorService;
26import java.util.concurrent.Executors;
27import java.util.concurrent.TimeUnit;
28
29import org.apache.felix.scr.annotations.Activate;
30import org.apache.felix.scr.annotations.Component;
31import org.apache.felix.scr.annotations.Deactivate;
32import org.apache.felix.scr.annotations.Modified;
33import org.apache.felix.scr.annotations.Property;
34import org.apache.felix.scr.annotations.Reference;
35import org.apache.felix.scr.annotations.ReferenceCardinality;
36import org.onlab.packet.Ethernet;
37import org.onlab.packet.ICMP;
38import org.onosproject.net.ConnectPoint;
39import org.onosproject.net.Device;
40import org.onosproject.net.PortNumber;
41import org.onosproject.net.device.DeviceService;
42import org.onosproject.net.packet.DefaultInboundPacket;
43import org.onosproject.net.packet.DefaultPacketContext;
44import org.onosproject.net.packet.InboundPacket;
45import org.onosproject.net.packet.OutboundPacket;
46import org.onosproject.net.packet.PacketContext;
47import org.onosproject.net.packet.PacketProvider;
48import org.onosproject.net.packet.PacketProviderRegistry;
49import org.onosproject.net.packet.PacketProviderService;
50import org.onosproject.net.provider.AbstractProvider;
51import org.onosproject.net.provider.ProviderId;
52import org.osgi.service.component.ComponentContext;
53import org.slf4j.Logger;
54
55/**
56 * Provider which 1) intercepts network-bound messages from the core, and 2)
57 * generates PacketEvents at some tunable rate. To be used for benchmarking
58 * only.
59 */
60@Component(immediate = true)
61public class NullPacketProvider extends AbstractProvider implements
62 PacketProvider {
63
64 private final Logger log = getLogger(getClass());
65
66 // Default packetEvent generation rate (in packets/sec)
67 // If 0, we are just a sink for network-bound packets
68 private static final int DEFAULT_RATE = 5;
69 // arbitrary host "destination"
70 private static final int DESTHOST = 5;
71
72 private PacketProviderService providerService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected PacketProviderRegistry providerRegistry;
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected DeviceService deviceService;
79
80 // Rate to generate PacketEvents, per second
81 @Property(name = "pktRate", intValue = DEFAULT_RATE,
82 label = "Rate of PacketEvent generation")
83 private int pktRate = DEFAULT_RATE;
84
85 private ExecutorService packetDriver = Executors.newFixedThreadPool(1,
86 namedThreads("null-packet-driver"));
87
88 public NullPacketProvider() {
89 super(new ProviderId("null", "org.onosproject.provider.nil"));
90 }
91
92 @Activate
93 public void activate(ComponentContext context) {
94 providerService = providerRegistry.register(this);
95 if (!modified(context)) {
96 packetDriver.submit(new PacketDriver());
97 }
98 log.info("started");
99 }
100
101 @Deactivate
102 public void deactivate(ComponentContext context) {
103 try {
104 packetDriver.awaitTermination(1000, TimeUnit.MILLISECONDS);
105 } catch (InterruptedException e) {
106 log.error("PacketDriver did not terminate");
107 }
108 packetDriver.shutdownNow();
109 providerRegistry.unregister(this);
110 log.info("stopped");
111 }
112
113 @Modified
114 public boolean modified(ComponentContext context) {
115 if (context == null) {
116 log.info("No configuration change, using defaults: pktRate={}",
117 DEFAULT_RATE);
118 return false;
119 }
120 Dictionary<?, ?> properties = context.getProperties();
121
122 int newRate;
123 try {
124 String s = String.valueOf(properties.get("pktRate"));
125 newRate = isNullOrEmpty(s) ? pktRate : Integer.valueOf(s);
126 } catch (Exception e) {
127 log.warn(e.getMessage());
128 newRate = pktRate;
129 }
130
131 if (newRate != pktRate) {
132 pktRate = newRate;
133 packetDriver.submit(new PacketDriver());
134 log.info("Using new settings: pktRate={}", pktRate);
135 return true;
136 }
137 return false;
138 }
139
140 @Override
141 public void emit(OutboundPacket packet) {
142 // We don't have a network to emit to. Keep a counter here, maybe?
143 }
144
145 /**
146 * Generates packet events at a given rate.
147 */
148 private class PacketDriver implements Runnable {
149
150 // time between event firing, in milliseconds
151 int pktInterval;
152 // filler echo request
153 ICMP icmp;
154 Ethernet eth;
155
156 public PacketDriver() {
157 pktInterval = 1000 / pktRate;
158 icmp = new ICMP();
159 icmp.setIcmpType((byte) 8).setIcmpCode((byte) 0)
160 .setChecksum((short) 0);
161 eth = new Ethernet();
162 eth.setEtherType(Ethernet.TYPE_IPV4);
163 eth.setPayload(icmp);
164 }
165
166 @Override
167 public void run() {
168 log.info("PacketDriver started");
169 while (!packetDriver.isShutdown()) {
170 for (Device dev : deviceService.getDevices()) {
171 sendEvents(dev);
172 }
173 }
174 }
175
176 private void sendEvents(Device dev) {
177 // make it look like things came from ports attached to hosts
178 for (int i = 0; i < 4; i++) {
179 eth.setSourceMACAddress("00:00:10:00:00:0" + i)
180 .setDestinationMACAddress("00:00:10:00:00:0" + DESTHOST);
181 InboundPacket inPkt = new DefaultInboundPacket(
182 new ConnectPoint(dev.id(), PortNumber.portNumber(i)),
183 eth, ByteBuffer.wrap(eth.serialize()));
184 PacketContext pctx = new NullPacketContext(
185 System.currentTimeMillis(), inPkt, null, false);
186 providerService.processPacket(pctx);
187 delay(pktInterval);
188 }
189 }
190
191 }
192
193 /**
194 * Minimal PacketContext to make core + applications happy.
195 */
196 private class NullPacketContext extends DefaultPacketContext {
197
198 public NullPacketContext(long time, InboundPacket inPkt,
199 OutboundPacket outPkt, boolean block) {
200 super(time, inPkt, outPkt, block);
201 }
202
203 @Override
204 public void send() {
205 // We don't send anything out.
206 }
207
208 }
209
210}