blob: 15bd6714ca24a4442f8134bd34e1e45cecc99ccd [file] [log] [blame]
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.provider.nil.packet.impl;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.packet.DefaultInboundPacket;
import org.onosproject.net.packet.DefaultPacketContext;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProvider;
import org.onosproject.net.packet.PacketProviderRegistry;
import org.onosproject.net.packet.PacketProviderService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import java.nio.ByteBuffer;
import java.util.Dictionary;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Strings.isNullOrEmpty;
import static org.onlab.util.Tools.delay;
import static org.onlab.util.Tools.groupedThreads;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Provider which 1) intercepts network-bound messages from the core, and 2)
* generates PacketEvents at some tunable rate. To be used for benchmarking
* only.
*/
@Component(immediate = true)
public class NullPacketProvider extends AbstractProvider implements
PacketProvider {
private final Logger log = getLogger(getClass());
// Default packetEvent generation rate (in packets/sec)
// If 0, we are just a sink for network-bound packets
private static final int DEFAULT_RATE = 5;
// arbitrary host "destination"
private static final int DESTHOST = 5;
private PacketProviderService providerService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketProviderRegistry providerRegistry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ComponentConfigService cfgService;
// Rate to generate PacketEvents, per second
@Property(name = "pktRate", intValue = DEFAULT_RATE,
label = "Rate of PacketEvent generation")
private int pktRate = DEFAULT_RATE;
private ExecutorService packetDriver =
Executors.newFixedThreadPool(1, groupedThreads("onos/null", "packet-driver"));
public NullPacketProvider() {
super(new ProviderId("null", "org.onosproject.provider.nil"));
}
@Activate
public void activate(ComponentContext context) {
cfgService.registerProperties(getClass());
providerService = providerRegistry.register(this);
if (!modified(context)) {
packetDriver.submit(new PacketDriver());
}
log.info("started");
}
@Deactivate
public void deactivate(ComponentContext context) {
cfgService.unregisterProperties(getClass(), false);
try {
packetDriver.awaitTermination(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
log.error("PacketDriver did not terminate");
}
packetDriver.shutdownNow();
providerRegistry.unregister(this);
log.info("stopped");
}
@Modified
public boolean modified(ComponentContext context) {
if (context == null) {
log.info("No configuration change, using defaults: pktRate={}",
DEFAULT_RATE);
return false;
}
Dictionary<?, ?> properties = context.getProperties();
int newRate;
try {
String s = String.valueOf(properties.get("pktRate"));
newRate = isNullOrEmpty(s) ? pktRate : Integer.parseInt(s.trim());
} catch (NumberFormatException | ClassCastException e) {
log.warn(e.getMessage());
newRate = pktRate;
}
if (newRate != pktRate) {
pktRate = newRate;
packetDriver.submit(new PacketDriver());
log.info("Using new settings: pktRate={}", pktRate);
return true;
}
return false;
}
@Override
public void emit(OutboundPacket packet) {
// We don't have a network to emit to. Keep a counter here, maybe?
}
/**
* Generates packet events at a given rate.
*/
private class PacketDriver implements Runnable {
// time between event firing, in milliseconds
int pktInterval;
// filler echo request
ICMP icmp;
Ethernet eth;
public PacketDriver() {
pktInterval = 1000 / pktRate;
icmp = new ICMP();
icmp.setIcmpType((byte) 8).setIcmpCode((byte) 0)
.setChecksum((short) 0);
eth = new Ethernet();
eth.setEtherType(Ethernet.TYPE_IPV4);
eth.setPayload(icmp);
}
@Override
public void run() {
log.info("PacketDriver started");
while (!packetDriver.isShutdown()) {
for (Device dev : deviceService.getDevices()) {
sendEvents(dev);
}
}
}
private void sendEvents(Device dev) {
// make it look like things came from ports attached to hosts
for (int i = 0; i < 4; i++) {
eth.setSourceMACAddress("00:00:10:00:00:0" + i)
.setDestinationMACAddress("00:00:10:00:00:0" + DESTHOST);
InboundPacket inPkt = new DefaultInboundPacket(
new ConnectPoint(dev.id(), PortNumber.portNumber(i)),
eth, ByteBuffer.wrap(eth.serialize()));
PacketContext pctx = new NullPacketContext(
System.currentTimeMillis(), inPkt, null, false);
providerService.processPacket(pctx);
delay(pktInterval);
}
}
}
/**
* Minimal PacketContext to make core + applications happy.
*/
private class NullPacketContext extends DefaultPacketContext {
public NullPacketContext(long time, InboundPacket inPkt,
OutboundPacket outPkt, boolean block) {
super(time, inPkt, outPkt, block);
}
@Override
public void send() {
// We don't send anything out.
}
}
}