Added a Scheduled Executor, PIM packet maker to generate hello packets

Change-Id: I27b91a9eb2906e9345223382238fd4fcfd1397f4
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterface.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterface.java
index c4d35fc..b6ba703 100644
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterface.java
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterface.java
@@ -17,6 +17,7 @@
 
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.PIM;
@@ -166,6 +167,30 @@
     }
 
     /**
+     * Multicast a hello message out our interface.  This hello message is sent
+     * periodically during the normal PIM Neighbor refresh time, as well as a
+     * result of a newly created interface.
+     */
+    public void sendHello() {
+
+        // Create the base PIM Packet and mark it a hello packet
+        PIMPacket pimPacket = new PIMPacket(PIM.TYPE_HELLO);
+
+        // We need to set the source MAC and IPv4 addresses
+        pimPacket.setSrcMacAddr(onosInterface.mac());
+        pimPacket.setSrcIpAddress(Ip4Address.valueOf(getIpAddress().toOctets()));
+
+        // Create the hello message with options
+        PIMHello hello = new PIMHello();
+        hello.createDefaultOptions();
+
+        // Now set the hello option payload
+        pimPacket.setPIMPayload(hello);
+
+        // TODO: How to send the packet.?.
+    }
+
+    /**
      * Process an incoming PIM Hello message.  There are a few things going on in
      * this method:
      * <ul>
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaceManager.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaceManager.java
index 8b8e2e6..9ff39fb 100644
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaceManager.java
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaceManager.java
@@ -28,6 +28,9 @@
 import org.onosproject.net.provider.ProviderId;
 import org.slf4j.Logger;
 import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -45,6 +48,17 @@
     // Create ourselves a provider ID
     private static final ProviderId PID = new ProviderId("pim", "org.onosproject.pim");
 
+    // Create a Scheduled Executor service to send PIM hellos
+    private final ScheduledExecutorService helloScheduler =
+            Executors.newScheduledThreadPool(1);
+
+    // Wait for a bout 3 seconds before sending the initial hello messages.
+    // TODO: make this tunnable.
+    private final long initialHelloDelay = (long) 3;
+
+    // Send PIM hello packets: 30 seconds.
+    private final long pimHelloPeriod = (long) 30;
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected InterfaceService interfaceService;
 
@@ -60,10 +74,24 @@
         for (Interface intf : interfaceService.getInterfaces()) {
             pimInterfaces.put(intf.connectPoint(), new PIMInterface(intf));
         }
+
+        // Schedule the periodic hello sender.
+        helloScheduler.scheduleAtFixedRate(new Runnable() {
+            @Override
+            public void run() {
+                for (PIMInterface pif : pimInterfaces.values()) {
+                    pif.sendHello();
+                }
+            }
+        }, initialHelloDelay, pimHelloPeriod, TimeUnit.SECONDS);
     }
 
     @Deactivate
     public void deactivate() {
+
+        // Shutdown the periodic hello task.
+        helloScheduler.shutdown();
+
         log.info("Stopped");
     }
 
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMPacket.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMPacket.java
new file mode 100644
index 0000000..7949a15
--- /dev/null
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMPacket.java
@@ -0,0 +1,130 @@
+/*
+ * 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.pim.impl;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPacket;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.PIM;
+
+public class PIMPacket {
+
+    // Ethernet header
+    private Ethernet ethHeader = new Ethernet();
+
+    // IP header
+    private IPv4 ipHeader = new IPv4();
+
+    // PIM Header
+    private PIM pimHeader = new PIM();
+
+    // The pim type
+    private byte pimType;
+
+    // PIM MAC address
+    private MacAddress pimDestinationMac = MacAddress.valueOf("01:00:5E:00:00:0d");
+
+    /**
+     * Create a PIM packet for a given PIM type.
+     *
+     * The resulting packet will have Ethernet and IPv4 headers with all defaults filled in.
+     * The final packet will require a PIM header that corresponds to the PIM type set as
+     * a payload.
+     *
+     * Additionally the source MAC and IPv4 address will need to be filled in for the
+     * packet to be ready to serialize in most cases.
+     *
+     * @param type PIM.TYPE_XXXX where XXX is the PIM message type
+     */
+    public PIMPacket(byte type) {
+        pimType = type;
+        initDefaults();
+    }
+
+    /**
+     * Fill in defaults for the Ethernet, IPv4 and PIM headers, then associate each
+     * of these headers as payload and parent accordingly.
+     */
+    public void initDefaults() {
+        // Prepopulate dst MACAddress and Ethernet Types. The Source MAC needs to be filled in.
+        ethHeader.setDestinationMACAddress(pimDestinationMac);
+        ethHeader.setEtherType(Ethernet.TYPE_IPV4);
+
+        // Prepopulate the IP Type and Dest address. The Source IP address needs to be filled in.
+        ipHeader.setDestinationAddress(PIM.PIM_ADDRESS.getIp4Address().toInt());
+        ipHeader.setTtl((byte) 1);
+        ipHeader.setProtocol(IPv4.PROTOCOL_PIM);
+
+        // Establish the order between Ethernet and IP headers
+        ethHeader.setPayload(ipHeader);
+        ipHeader.setParent(ethHeader);
+
+        // Prepopulate the PIM packet
+        pimHeader.setPIMType(pimType);
+
+        // Establish the order between IP and PIM headers
+        ipHeader.setPayload(pimHeader);
+        pimHeader.setParent(ipHeader);
+    }
+
+    /**
+     * Set the source MAC address.
+     *
+     * @param src source MAC address
+     */
+    public void setSrcMacAddr(MacAddress src) {
+        ethHeader.setSourceMACAddress(src);
+    }
+
+    /**
+     * Set the source IPv4 address.
+     *
+     * @param ipSrcAddress the source IPv4 address
+     */
+    public void setSrcIpAddress(Ip4Address ipSrcAddress) {
+        ipHeader.setSourceAddress(ipSrcAddress.toInt());
+    }
+
+    /**
+     * Set the PIM payload.
+     *
+     * @param payload the PIM payload
+     */
+    public void setPIMPayload(IPacket payload) {
+        pimHeader.setPayload(payload);
+        payload.setParent(pimHeader);
+    }
+
+    /**
+     * Get the ethernet header.
+     *
+     * @return the Ethernet header
+     */
+    public Ethernet getEthernet() {
+        return ethHeader;
+    }
+
+    /**
+     * Get the IPv4 header.
+     *
+     * @return the IPv4 header
+     */
+    public IPv4 getIpv4() {
+        return ipHeader;
+    }
+}