Consolidating null providers and making them fully configurable and integrated with the ConfigProvider to allow arbitrary topologies.

Change-Id: I899e27a9771af4013a3ce6da7f683a4927ffb438
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/NullPacketProvider.java b/providers/null/src/main/java/org/onosproject/provider/nil/NullPacketProvider.java
new file mode 100644
index 0000000..a1baec9
--- /dev/null
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/NullPacketProvider.java
@@ -0,0 +1,169 @@
+/*
+ * 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;
+
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timeout;
+import org.jboss.netty.util.TimerTask;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP;
+import org.onlab.util.Timer;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceAdminService;
+import org.onosproject.net.host.HostService;
+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.PacketProvider;
+import org.onosproject.net.packet.PacketProviderService;
+import org.slf4j.Logger;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import static com.google.common.collect.ImmutableList.copyOf;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.onosproject.net.MastershipRole.MASTER;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provider which generates simulated packets and acts as a sink for outbound
+ * packets. To be used for benchmarking only.
+ */
+class NullPacketProvider extends NullProviders.AbstractNullProvider
+        implements PacketProvider {
+
+    private static final int INITIAL_DELAY = 5;
+    private final Logger log = getLogger(getClass());
+
+    // Arbitrary host src/dst
+    private static final int SRC_HOST = 2;
+    private static final int DST_HOST = 5;
+
+    // Time between event firing, in milliseconds
+    private int delay;
+
+    // TODO: use host service to pick legitimate hosts connected to devices
+    private HostService hostService;
+    private PacketProviderService providerService;
+
+    private List<Device> devices;
+    private int currentDevice = 0;
+
+    private HashedWheelTimer timer = Timer.getTimer();
+    private Timeout timeout;
+
+    /**
+     * Starts the packet generation process.
+     *
+     * @param packetRate      packets per second
+     * @param hostService     host service
+     * @param deviceService   device service
+     * @param providerService packet provider service
+     */
+    void start(int packetRate, HostService hostService,
+               DeviceAdminService deviceService,
+               PacketProviderService providerService) {
+        this.hostService = hostService;
+        this.providerService = providerService;
+
+        this.devices = copyOf(deviceService.getDevices()).stream()
+                .filter(d -> deviceService.getRole(d.id()) == MASTER)
+                .collect(Collectors.toList());
+
+        adjustRate(packetRate);
+        timeout = timer.newTimeout(new PacketDriverTask(), INITIAL_DELAY, SECONDS);
+    }
+
+    /**
+     * Adjusts packet rate.
+     *
+     * @param packetRate new packet rate
+     */
+    void adjustRate(int packetRate) {
+        delay = 1000 / packetRate;
+        log.info("Settings: packetRate={}, delay={}", packetRate, delay);
+    }
+
+    /**
+     * Stops the packet generation process.
+     */
+    void stop() {
+        if (timeout != null) {
+            timeout.cancel();
+        }
+    }
+
+    @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 PacketDriverTask implements TimerTask {
+
+        // Filler echo request
+        ICMP icmp;
+        Ethernet eth;
+
+        public PacketDriverTask() {
+            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(Timeout to) {
+            if (!devices.isEmpty()) {
+                sendEvent(devices.get(currentDevice));
+                currentDevice = (currentDevice + 1) % devices.size();
+                timeout = timer.newTimeout(to.getTask(), delay, TimeUnit.MILLISECONDS);
+            }
+        }
+
+        private void sendEvent(Device device) {
+            // Make it look like things came from ports attached to hosts
+            eth.setSourceMACAddress("00:00:10:00:00:0" + SRC_HOST)
+                    .setDestinationMACAddress("00:00:10:00:00:0" + DST_HOST);
+            InboundPacket inPkt = new DefaultInboundPacket(
+                    new ConnectPoint(device.id(), PortNumber.portNumber(SRC_HOST)),
+                    eth, ByteBuffer.wrap(eth.serialize()));
+            providerService.processPacket(new NullPacketContext(inPkt, null));
+        }
+    }
+
+     // Minimal PacketContext to make core and applications happy.
+    private final class NullPacketContext extends DefaultPacketContext {
+        private NullPacketContext(InboundPacket inPkt, OutboundPacket outPkt) {
+            super(System.currentTimeMillis(), inPkt, outPkt, false);
+        }
+
+        @Override
+        public void send() {
+            // We don't send anything out.
+        }
+    }
+
+}