Blew away old version of PIM to restructure.  And:

1) Added packetService to register for PIM packets.
2) Added PIMPacketHandler to process PIM packets.
3) Added NetworkConfig Listener
4) Added PIMInterfaceService / PIMInterfaceManager
5) Added Process incoming hello packets to PIMInterfaceManager
6) Code Review inspired changes

Change-Id: I753880c954b9a6a91544903b613305ff9aa78cd0
diff --git a/apps/pim/src/main/java/org/onosproject/pim/cli/PIMShowCommand.java b/apps/pim/src/main/java/org/onosproject/pim/cli/PIMShowCommand.java
deleted file mode 100644
index 6bd563b..0000000
--- a/apps/pim/src/main/java/org/onosproject/pim/cli/PIMShowCommand.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2014-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.cli;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import org.apache.karaf.shell.commands.Command;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.pim.impl.PIMInterface;
-import org.onosproject.pim.impl.PIMInterfaces;
-import org.onosproject.pim.impl.PIMInterfacesCodec;
-
-import java.util.Collection;
-
-@Command(scope = "onos", name = "pim-interfaces", description = "Displays the pim interfaces")
-public class PIMShowCommand extends AbstractShellCommand {
-
-    // prints either the json or cli version of the hash map connect point
-    // neighbors from the PIMInterfaces class.
-    @Override
-    protected  void execute() {
-        // grab connect point neighbors hash map to send in to json encoder.
-        Collection<PIMInterface> pimIntfs = PIMInterfaces.getInstance().getInterfaces();
-        if (outputJson()) {
-            print("%s", json(pimIntfs));
-        } else {
-            print(PIMInterfaces.getInstance().printInterfaces());
-        }
-    }
-
-    private JsonNode json(Collection<PIMInterface> pimIntfs) {
-        return new PIMInterfacesCodec().encode(pimIntfs, this);
-    }
-
-}
\ No newline at end of file
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMApplication.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMApplication.java
new file mode 100644
index 0000000..a286726
--- /dev/null
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMApplication.java
@@ -0,0 +1,229 @@
+/*
+ * 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.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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.config.basics.ConfigException;
+import org.onosproject.incubator.net.config.basics.InterfaceConfig;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.mcast.MulticastRouteService;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
+import org.slf4j.Logger;
+
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * The main PIM controller class.
+ */
+@Component(immediate = true)
+public class PIMApplication {
+    private final Logger log = getLogger(getClass());
+
+    // Used to get the appId
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    // Our application ID
+    private static ApplicationId appId;
+
+    // Register to receive PIM packets, used to send packets as well
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PacketService packetService;
+
+    // Use the MulticastRouteService to manage incoming PIM Join/Prune state as well as
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MulticastRouteService ms;
+
+    // Create an instance of the PIM packet handler
+    protected PIMPacketHandler pimPacketHandler;
+
+    // Get the network configuration updates
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService configService;
+
+    // Access defined network (IP) interfaces
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected InterfaceService interfaceService;
+
+    // Internal class used to listen for network configuration changes
+    private InternalConfigListener configListener = new InternalConfigListener();
+
+    // Provide interfaces to the pimInterface manager as a result of Netconfig updates.
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PIMInterfaceService pimInterfaceManager;
+
+    /**
+     * Activate the PIM component.
+     */
+    @Activate
+    public void activate() {
+
+        // Get our application ID
+        appId = coreService.registerApplication("org.onosproject.pim");
+
+        // Build the traffic selector for PIM packets
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        selector.matchEthType(Ethernet.TYPE_IPV4);
+        selector.matchIPProtocol(IPv4.PROTOCOL_PIM);
+
+        // Use the traffic selector to tell the packet service which packets we want.
+        // PIMPacketService is an inner class defined below
+        PIMPacketProcessor processor = new PIMPacketProcessor();
+        packetService.addProcessor(processor, PacketProcessor.director(5));
+
+        // Register for notifications from the Network config & Interface services.
+        // We'll use these services to represent "PIMInterfaces"
+
+        // Get a copy of the PIM Packet Handler
+        pimPacketHandler = new PIMPacketHandler();
+
+        // Listen for network configuration changes
+        configService.addListener(configListener);
+
+        log.info("Started");
+    }
+
+    /**
+     * Deactivate the PIM component.
+     */
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+    /**
+     * The class that will receive PIM packets, sanitize them, determine the PIMInterface
+     * they arrived on, then forward them on to be processed by the appropriate entity.
+     */
+    public class PIMPacketProcessor implements PacketProcessor {
+        private final Logger log = getLogger(getClass());
+
+        @Override
+        public void process(PacketContext context) {
+
+            // return if this packet has already been handled
+            if (context.isHandled()) {
+                return;
+            }
+
+            // get the inbound packet
+            InboundPacket pkt = context.inPacket();
+            if (pkt == null) {
+                // problem getting the inbound pkt.  Log it debug to avoid spamming log file
+                log.debug("Could not retrieve packet from context");
+                return;
+            }
+
+            // Get the ethernet header
+            Ethernet eth = pkt.parsed();
+            if (eth == null) {
+                // problem getting the ethernet pkt.  Log it debug to avoid spamming log file
+                log.debug("Could not retrieve ethnernet packet from the parsed packet");
+                return;
+            }
+
+            // Get the PIM Interface the packet was received on.
+            PIMInterface pimi = pimInterfaceManager.getPIMInterface(pkt.receivedFrom());
+            if (pimi == null) {
+                log.debug("We received PIM packet from a non PIM interface: " + pkt.receivedFrom().toString());
+                return;
+            }
+
+            /*
+             * Pass the packet processing off to the PIMInterface for processing.
+             *
+             * TODO: Is it possible that PIM interface processing should move to the
+             * PIMInterfaceManager directly?
+             */
+            PIMPacketHandler ph = new PIMPacketHandler();
+            ph.processPacket(eth, pimi);
+        }
+    }
+
+    /*
+     * This class receives all events from the network config services, then hands the
+     * event off to the PIMInterfaceManager for proper handling.
+     *
+     * TODO: should this move to PIMInterfaceManager?
+     */
+    private class InternalConfigListener implements NetworkConfigListener {
+
+        @Override
+        public void event(NetworkConfigEvent event) {
+
+            log.debug(event.toString());
+            switch (event.type()) {
+                case CONFIG_ADDED:
+                case CONFIG_UPDATED:
+
+                    if (event.configClass() == InterfaceConfig.class) {
+                        InterfaceConfig config = configService.getConfig(
+                                (ConnectPoint) event.subject(),
+                                InterfaceConfig.class);
+
+                        log.debug("Got a network configuration event");
+
+                        // Walk the interfaces and feed them to the PIMInterfaceManager
+                        Set<Interface> intfs;
+                        try {
+                            intfs = config.getInterfaces();
+                            for (Interface intf : intfs) {
+                                pimInterfaceManager.updateInterface(intf);
+                            }
+                        } catch (ConfigException e) {
+                            log.error(e.toString());
+                            return;
+                        }
+                    }
+                    break;
+
+                case CONFIG_REMOVED:
+                    if (event.configClass() == InterfaceConfig.class) {
+                        ConnectPoint cp = (ConnectPoint) event.subject();
+                        //assertNotNull(cp);
+                        pimInterfaceManager.deleteInterface(cp);
+                    }
+                    break;
+
+                case CONFIG_REGISTERED:
+                case CONFIG_UNREGISTERED:
+                default:
+                    log.debug("\tWe are not handling this event type");
+                    break;
+            }
+        }
+    }
+}
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMComponent.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMComponent.java
deleted file mode 100644
index 1a2d6f5..0000000
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMComponent.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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 static org.slf4j.LoggerFactory.getLogger;
-
-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.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.incubator.net.intf.InterfaceService;
-import org.onosproject.net.config.NetworkConfigService;
-import org.onosproject.net.packet.PacketService;
-import org.slf4j.Logger;
-
-/**
- * Protocol Independent Multicast (PIM) Emulation.  This component is responsible
- * for reference the services this PIM module is going to need, then initializing
- * the corresponding utility classes.
- */
-@Component(immediate = true)
-public class PIMComponent {
-    private final Logger log = getLogger(getClass());
-
-    // Register to receive PIM packets, used to send packets as well
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected PacketService packetService;
-
-    // Get the appId
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected CoreService coreService;
-
-    // Get the network configuration updates
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected NetworkConfigService configService;
-
-    // Access defined network (IP) interfaces
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected InterfaceService interfaceService;
-
-    private static ApplicationId appId;
-
-    private PIMInterfaces pimInterfaces;
-    private PIMPacketHandler pimPacketHandler;
-
-    @Activate
-    public void activate() {
-        appId = coreService.registerApplication("org.onosproject.pim");
-
-        // Initialize the Packet Handler class
-        pimPacketHandler = PIMPacketHandler.getInstance();
-        pimPacketHandler.initialize(packetService, appId);
-
-        // Initialize the Interface class
-        pimInterfaces = PIMInterfaces.getInstance();
-        pimInterfaces.initialize(configService, interfaceService);
-
-        log.info("Started");
-    }
-
-    @Deactivate
-    public void deactivate() {
-        PIMPacketHandler.getInstance().stop();
-        log.info("Stopped");
-    }
-}
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 5da5c2b..4d8d05e 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,88 +17,90 @@
 
 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;
 import org.onlab.packet.pim.PIMHello;
 import org.onlab.packet.pim.PIMHelloOption;
 import org.onosproject.incubator.net.intf.Interface;
-import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.host.InterfaceIpAddress;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Set;
 
-import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
- * The PIM Interface is a wrapper around a ConnectPoint and used to provide
- * hello options values when "talking" with PIM other PIM routers.
+ * PIM Interface represents an ONOS Interface with IP & MAC addresses for
+ * a given ConnectPoint.
  */
 public class PIMInterface {
-    private static Logger log = LoggerFactory.getLogger("PIMInterfaces");
 
-    // Interface from the interface subsystem
-    private Interface theInterface;
+    private final Logger log = getLogger(getClass());
 
-    // The list of PIM neighbors adjacent to this interface
-    private Map<IpAddress, PIMNeighbor> neighbors = new HashMap<>();
+    private Interface onosInterface;
 
-    // The designatedRouter for this LAN
-    private PIMNeighbor designatedRouter;
+    // Our hello opt holdtime
+    private short holdtime = PIMHelloOption.DEFAULT_HOLDTIME;
 
-    // The priority we use on this ConnectPoint.
-    private int priority = PIMHelloOption.DEFAULT_PRIORITY;
+    // Our hello opt prune delay
+    private int pruneDelay = PIMHelloOption.DEFAULT_PRUNEDELAY;
 
-    // The holdtime we are sending out.
-    private int holdtime = PIMHelloOption.DEFAULT_HOLDTIME;
+    // Neighbor priority
+    private int priority   = PIMHelloOption.DEFAULT_PRIORITY;
 
-    // Then generation ID we are sending out. 0 means we need to generate a new random ID
-    private int genid = PIMHelloOption.DEFAULT_GENID;
-
-    // Our default prune delay
-    private int prunedelay = PIMHelloOption.DEFAULT_PRUNEDELAY;
+    // Our current genid
+    private int genid      = PIMHelloOption.DEFAULT_GENID;   // Needs to be assigned.
 
     /**
-     * Create a PIMInterface.
+     * Create a PIMInterface from an ONOS Interface.
      *
-     * @param intf the network interface configuration
+     * @param intf the ONOS Interface.
      */
     public PIMInterface(Interface intf) {
-
-        log.debug("Adding an interface: " + intf.toString() + "\n");
-        this.theInterface = intf;
-
-        // Send a hello to let our neighbors know we are alive
-        sendHello();
+        onosInterface = intf;
     }
 
     /**
-     * Get the PIM Interface.
+     * Return the ONOS Interface.
      *
-     * @return the PIM Interface
+     * @return ONOS Interface.
      */
     public Interface getInterface() {
-        return theInterface;
+        return this.onosInterface;
     }
 
     /**
-     * Getter for our IP address.
+     * Set the ONOS Interface, it will override a previous value.
      *
-     * @return our IP address.
+     * @param intf ONOS Interface.
+     */
+    public PIMInterface setInterface(Interface intf) {
+        this.onosInterface = intf;
+        return this;
+    }
+
+    /**
+     * Get the set of IP Addresses associated with this interface.
+     *
+     * @return a set of Ip Addresses on this interface
+     */
+    public Set<InterfaceIpAddress> getIpAddresses() {
+        return this.onosInterface.ipAddresses();
+    }
+
+    /**
+     * Return a single "best" IP address.
+     *
+     * @return the choosen IP address or null if none
      */
     public IpAddress getIpAddress() {
-        if (theInterface.ipAddresses().isEmpty()) {
+        if (onosInterface.ipAddresses().isEmpty()) {
             return null;
         }
 
-        // We will just assume the first interface on the list
         IpAddress ipaddr = null;
-        for (InterfaceIpAddress ifipaddr : theInterface.ipAddresses()) {
+        for (InterfaceIpAddress ifipaddr : onosInterface.ipAddresses()) {
             ipaddr = ifipaddr.ipAddress();
             break;
         }
@@ -106,236 +108,87 @@
     }
 
     /**
-     * Get our priority.
+     * Get the holdtime.
      *
-     * @return our priority.
+     * @return the holdtime
+     */
+    public short getHoldtime() {
+        return this.holdtime;
+    }
+
+    /**
+     * Get the prune delay.
+     *
+     * @return The prune delay
+     */
+    public int getPruneDelay() {
+        return this.pruneDelay;
+    }
+
+    /**
+     * Get our hello priority.
+     *
+     * @return our priority
      */
     public int getPriority() {
         return this.priority;
     }
 
     /**
-     * Get the designated router on this connection.
+     * Get our generation ID.
      *
-     * @return the PIMNeighbor representing the DR
+     * @return our generation ID
      */
-    public PIMNeighbor getDesignatedRouter() {
-        return designatedRouter;
+    public int getGenid() {
+        return this.genid;
     }
 
     /**
-     * Are we the DR on this CP?
+     * Process an incoming PIM Hello message.
      *
-     * @return true if we are, false if not
+     * @param ethPkt the Ethernet packet header
      */
-    public boolean areWeDr() {
-        return (designatedRouter != null &&
-                designatedRouter.getPrimaryAddr().equals(this.getIpAddress()));
-    }
+    public void processHello(Ethernet ethPkt) {
 
-    /**
-     * Return a collection of PIM Neighbors.
-     *
-     * @return the collection of PIM Neighbors
-     */
-    public Collection<PIMNeighbor> getNeighbors() {
-        return this.neighbors.values();
-    }
+        // We'll need to save our neighbors MAC address
+        MacAddress nbrmac = ethPkt.getSourceMAC();
 
-    /**
-     * Find the neighbor with the given IP address on this CP.
-     *
-     * @param ipaddr the IP address of the neighbor we are interested in
-     * @return the pim neighbor if it exists
-     */
-    public PIMNeighbor findNeighbor(IpAddress ipaddr) {
-        PIMNeighbor nbr = neighbors.get(ipaddr);
-        return nbr;
-    }
+        // And we'll need to save neighbors IP Address.
+        IPv4 iphdr = (IPv4) ethPkt.getPayload();
+        IpAddress srcip = IpAddress.valueOf(iphdr.getSourceAddress());
 
-    /**
-     * Add a new PIM neighbor to this list.
-     *
-     * @param nbr the neighbor to be added.
-     */
-    public void addNeighbor(PIMNeighbor nbr) {
-        if (neighbors.containsKey(nbr.getPrimaryAddr())) {
-
-            log.debug("We are adding a neighbor that already exists: {}", nbr.toString());
-            neighbors.remove(nbr.getPrimaryAddr());
-        }
-        neighbors.put(nbr.getPrimaryAddr(), nbr);
-    }
-
-    /**
-     * Remove the neighbor from our neighbor list.
-     *
-     * @param ipaddr the IP address of the neighbor to remove
-     */
-    public void removeNeighbor(IpAddress ipaddr) {
-
-        if (neighbors.containsKey(ipaddr)) {
-            neighbors.remove(ipaddr);
-        }
-        this.electDR();
-    }
-
-    /**
-     * Remove the given neighbor from the neighbor list.
-     *
-     * @param nbr the nbr to be removed.
-     */
-    public void removeNeighbor(PIMNeighbor nbr) {
-
-        neighbors.remove(nbr.getPrimaryAddr(), nbr);
-        this.electDR();
-    }
-
-    /**
-     * Elect a new DR on this ConnectPoint.
-     *
-     * @return the PIM Neighbor that wins
-     */
-    public PIMNeighbor electDR() {
-
-        for (PIMNeighbor nbr : this.neighbors.values()) {
-            if (this.designatedRouter == null) {
-                this.designatedRouter = nbr;
-                continue;
-            }
-
-            if (nbr.getPriority() > this.designatedRouter.getPriority()) {
-                this.designatedRouter = nbr;
-                continue;
-            }
-
-            // We could sort in ascending order
-            if (this.designatedRouter.getPrimaryAddr().compareTo(nbr.getPrimaryAddr()) > 0) {
-                this.designatedRouter = nbr;
-                continue;
-            }
-        }
-
-        return this.designatedRouter;
-    }
-
-    /**
-     * Elect a new DR given the new neighbor.
-     *
-     * @param nbr the new neighbor to use in DR election.
-     * @return the PIM Neighbor that wins DR election
-     */
-    public PIMNeighbor electDR(PIMNeighbor nbr) {
-
-        // Make sure I have
-        if (this.designatedRouter == null ||
-                this.designatedRouter.getPriority() < nbr.getPriority() ||
-                this.designatedRouter.getPrimaryAddr().compareTo(nbr.getPrimaryAddr()) > 0) {
-            this.designatedRouter = nbr;
-        }
-        return this.designatedRouter;
-    }
-
-    /**
-     * Find or create a pim neighbor with a given ip address and connect point.
-     *
-     * @param ipaddr of the pim neighbor
-     * @param mac The mac address of our sending neighbor
-     * @return an existing or new PIM neighbor
-     */
-    public PIMNeighbor findOrCreate(IpAddress ipaddr, MacAddress mac) {
-        PIMNeighbor nbr = this.findNeighbor(ipaddr);
-        if (nbr == null) {
-            nbr = new PIMNeighbor(ipaddr, mac, this);
-            this.addNeighbor(nbr);
-            this.electDR(nbr);
-        }
-        return nbr;
-    }
-
-    /**
-     * Process a hello packet received on this Interface.
-     *
-     * @param ethPkt the ethernet packet containing the hello message
-     * @param cp the ConnectPoint of this interface
-     */
-    public void processHello(Ethernet ethPkt, ConnectPoint cp) {
-        checkNotNull(ethPkt);
-        checkNotNull(cp);
-
-        MacAddress srcmac = ethPkt.getSourceMAC();
-        IPv4 ip = (IPv4) ethPkt.getPayload();
-        Ip4Address srcip = Ip4Address.valueOf(ip.getSourceAddress());
-
-        PIM pim = (PIM) ip.getPayload();
-        checkNotNull(pim);
-
-        PIMHello hello = (PIMHello) pim.getPayload();
-        checkNotNull(hello);
-
-        PIMNeighbor nbr = this.findOrCreate(srcip, srcmac);
-        if (nbr == null) {
-            log.error("Could not create a neighbor for: {1}", srcip.toString());
+        PIM pimhdr = (PIM) iphdr.getPayload();
+        if (pimhdr.getPimMsgType() != PIM.TYPE_HELLO) {
+            log.error("process Hello has received a non hello packet type: " + pimhdr.getPimMsgType());
             return;
         }
 
-        ConnectPoint icp = theInterface.connectPoint();
-        checkNotNull(icp);
-        if (!cp.equals(icp)) {
-            log.error("PIM Hello message received from {} on incorrect interface {}",
-                    nbr.getPrimaryAddr(), this.toString());
-            return;
+        // TODO: Maybe a good idea to check the checksum.  Let's jump into the hello options.
+        PIMHello hello = (PIMHello) pimhdr.getPayload();
+
+        // TODO: this is about where we find or create our PIMNeighbor
+
+        boolean reElectDr = false;
+
+        // Start walking through all the hello options to handle accordingly.
+        for (PIMHelloOption opt : hello.getOptions().values()) {
+
+            // TODO: This is where we handle the options and modify the neighbor accordingly.
+            // We'll need to create the PIMNeighbor class next.  Depending on what happens
+            // we may need to re-elect a DR
         }
-        nbr.refresh(hello);
+
+        if (reElectDr) {
+            // TODO: create an election() method and call it here with a PIMNeighbor
+        }
     }
 
     /**
-     * Send a hello packet from this interface.
-     */
-    public void sendHello() {
-        PIM pim = new PIM();
-        PIMHello hello = new PIMHello();
-
-        // Create a PIM Hello
-        pim = new PIM();
-        pim.setVersion((byte) 2);
-        pim.setPIMType((byte) PIM.TYPE_HELLO);
-        pim.setChecksum((short) 0);
-
-        hello = new PIMHello();
-        hello.createDefaultOptions();
-        pim.setPayload(hello);
-        hello.setParent(pim);
-
-        log.debug("Sending hello: \n");
-        PIMPacketHandler.getInstance().sendPacket(pim, this);
-    }
-
-    /**
-     * prints the connectPointNeighbors list with each neighbor list.
+     * Process an incoming PIM JoinPrune message.
      *
-     * @return string of neighbors.
+     * @param ethPkt the Ethernet packet header.
      */
-    public String printNeighbors() {
-        String out = "PIM Neighbors Table: \n";
-        for (PIMNeighbor nbr : this.neighbors.values()) {
-            out += "\t" + nbr.toString();
-        }
-        return out;
-    }
+    public void processJoinPrune(Ethernet ethPkt) {
 
-    @Override
-    public String toString() {
-        IpAddress ipaddr = this.getIpAddress();
-        String out = "PIM Neighbors: ";
-        if (ipaddr != null) {
-            out += "IP: " + ipaddr.toString();
-        } else {
-            out += "IP: *Null*";
-        }
-        out += "\tPR: " + String.valueOf(this.priority) + "\n";
-        return out;
     }
-
 }
-
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
new file mode 100644
index 0000000..8b8e2e6
--- /dev/null
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaceManager.java
@@ -0,0 +1,115 @@
+/*
+ * 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 com.google.common.collect.Maps;
+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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.provider.ProviderId;
+import org.slf4j.Logger;
+import java.util.Map;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Manages PIMInterfaces.
+ *
+ * TODO: Do we need to add a ServiceListener?
+ */
+@Component(immediate = true)
+@Service
+public class PIMInterfaceManager implements PIMInterfaceService {
+
+    private final Logger log = getLogger(getClass());
+
+    // Create ourselves a provider ID
+    private static final ProviderId PID = new ProviderId("pim", "org.onosproject.pim");
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected InterfaceService interfaceService;
+
+    // Store PIM Interfaces in a map key'd by ConnectPoint
+    private final Map<ConnectPoint, PIMInterface> pimInterfaces = Maps.newConcurrentMap();
+
+    @Activate
+    public void activate() {
+        // Query the Interface service to see if Interfaces already exist.
+        log.info("Started");
+
+        // Create PIM Interfaces for each of the existing ONOS Interfaces.
+        for (Interface intf : interfaceService.getInterfaces()) {
+            pimInterfaces.put(intf.connectPoint(), new PIMInterface(intf));
+        }
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+    /**
+     * Update the ONOS Interface with the new Interface.  If the PIMInterface does
+     * not exist we'll create a new one and store it.
+     *
+     * @param intf ONOS Interface.
+     */
+    @Override
+    public void updateInterface(Interface intf) {
+        ConnectPoint cp = intf.connectPoint();
+
+        log.debug("Updating Interface for " + intf.connectPoint().toString());
+        pimInterfaces.compute(cp, (k, v) -> (v == null) ?
+                new PIMInterface(intf) :
+                v.setInterface(intf));
+    }
+
+    /**
+     * Delete the PIM Interface to the corresponding ConnectPoint.
+     *
+     * @param cp The connect point associated with this interface we want to delete
+     */
+    @Override
+    public void deleteInterface(ConnectPoint cp) {
+
+        PIMInterface pi = pimInterfaces.remove(cp);
+        if (pi == null) {
+            log.warn("We've been asked to remove an interface we3 don't have: " + cp.toString());
+            return;
+        }
+    }
+
+    /**
+     * Return the PIMInterface that corresponds to the given ConnectPoint.
+     *
+     * @param cp The ConnectPoint we want to get the PIMInterface for
+     * @return The PIMInterface if it exists, NULL if it does not exist.
+     */
+    @Override
+    public PIMInterface getPIMInterface(ConnectPoint cp) {
+        PIMInterface pi = pimInterfaces.getOrDefault(cp, null);
+        if (pi == null) {
+            log.warn("We have been asked for an Interface we don't have: " + cp.toString());
+        }
+        return pi;
+    }
+}
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaceService.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaceService.java
new file mode 100644
index 0000000..528c51d
--- /dev/null
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaceService.java
@@ -0,0 +1,52 @@
+/*
+ * 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.onosproject.incubator.net.intf.Interface;
+import org.onosproject.net.ConnectPoint;
+
+/**
+ * Define the PIMInterfaceService.  PIM will use ONOS Interfaces to
+ * define PIM Interfaces.  The PIM Application signed up as a Netconfig
+ * listener.
+ *
+ * TODO: Do we need a PIMInterfaceListenerService?  Who sould listen to Interfaces changes?
+ */
+public interface PIMInterfaceService {
+
+    /**
+     * Update the corresponding PIMInterface.  If the PIMInterface
+     * does not exist it will be created.
+     *
+     * @param intf ONOS Interface.
+     */
+    public void updateInterface(Interface intf);
+
+    /**
+     * Delete the PIMInterface that corresponds to the given ConnectPoint.
+     *
+     * @param cp The connect point associated with this interface.
+     */
+    public void deleteInterface(ConnectPoint cp);
+
+    /**
+     * Return the PIMInterface associated with the given ConnectPoint.
+     *
+     * @param cp The ConnectPoint we want to get the PIMInterface for.
+     * @return the PIMInterface if it exists, NULL if it does not exist.
+     */
+    public PIMInterface getPIMInterface(ConnectPoint cp);
+}
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaces.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaces.java
deleted file mode 100644
index 70ade23..0000000
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaces.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * 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.jboss.netty.util.Timeout;
-import org.jboss.netty.util.TimerTask;
-import org.onosproject.incubator.net.config.basics.ConfigException;
-import org.onosproject.incubator.net.config.basics.InterfaceConfig;
-import org.onosproject.incubator.net.intf.Interface;
-import org.onosproject.incubator.net.intf.InterfaceService;
-import org.onosproject.net.ConnectPoint;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.config.NetworkConfigListener;
-import org.onosproject.net.config.NetworkConfigService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * PIMInterfaces is a collection of all neighbors we have received
- * PIM hello messages from.  The main structure is a HashMap indexed
- * by ConnectPoint with another HashMap indexed on the PIM neighbors
- * IPAddress, it contains all PIM neighbors attached on that ConnectPoint.
- */
-public final class PIMInterfaces {
-
-    private Logger log = LoggerFactory.getLogger("PIMInterfaces");
-
-    private static PIMInterfaces instance = null;
-
-    // Used to listen to network configuration changes
-    private NetworkConfigService configService;
-
-    // Used to access IP Interface definitions for our segment
-    private InterfaceService interfaceService;
-
-    // Internal class used to listen for network configuration changes
-    private InternalConfigListener configListener = new InternalConfigListener();
-
-    // This is the global container for all PIM Interfaces indexed by ConnectPoints.
-    private Map<ConnectPoint, PIMInterface> interfaces = new HashMap<>();
-
-    // Default hello message interval
-    private int helloMessageInterval = 60;
-
-    // Timer used to send hello messages on this interface
-    private Timeout helloTimer;
-
-    // Required by a utility class
-    private PIMInterfaces() {}
-
-    /**
-     * Get the instance of PIMInterfaces.  Create the instance if needed.
-     *
-     * @return PIMInterface instance
-     */
-    public static PIMInterfaces getInstance() {
-        if (null == instance) {
-            instance = new PIMInterfaces();
-        }
-        return instance;
-    }
-
-    // Initialize the services
-    public void initialize(NetworkConfigService cs, InterfaceService is) {
-        configService = cs;
-        interfaceService = is;
-
-        // Initialize interfaces if they already exist
-        initInterfaces();
-
-        // Listen for network config changes
-        configService.addListener(configListener);
-    }
-
-    /**
-     * Listener for network config events.
-     */
-    private class InternalConfigListener implements NetworkConfigListener {
-
-        private void updateInterfaces(InterfaceConfig config) {
-            Set<Interface> intfs;
-            try {
-                intfs = config.getInterfaces();
-            } catch (ConfigException e) {
-                log.error(e.toString());
-                return;
-            }
-            for (Interface intf : intfs) {
-                addInterface(intf);
-            }
-        }
-
-        /**
-         * Remove the PIMInterface represented by the ConnectPoint. If the
-         * PIMInterface does not exist this function is a no-op.
-         *
-         * @param cp The connectPoint representing the PIMInterface to be removed.
-         */
-        private void removeInterface(ConnectPoint cp) {
-            PIMInterfaces.this.removeInterface(cp);
-        }
-
-        @Override
-        public void event(NetworkConfigEvent event) {
-            switch (event.type()) {
-                case CONFIG_ADDED:
-                case CONFIG_UPDATED:
-                    log.debug("Config updated: " + event.toString() + "\n");
-                    if (event.configClass() == InterfaceConfig.class) {
-                        InterfaceConfig config =
-                                configService.getConfig((ConnectPoint) event.subject(), InterfaceConfig.class);
-                        updateInterfaces(config);
-                    }
-                    break;
-                case CONFIG_REMOVED:
-                    if (event.configClass() == InterfaceConfig.class) {
-                        removeInterface((ConnectPoint) event.subject());
-                    }
-                    break;
-                case CONFIG_REGISTERED:
-                case CONFIG_UNREGISTERED:
-                default:
-                    break;
-            }
-        }
-    }
-
-    // Configure interfaces if they already exist.
-    private void initInterfaces() {
-        Set<Interface> intfs = interfaceService.getInterfaces();
-        for (Interface intf : intfs) {
-            log.debug("Adding interface: " + intf.toString() + "\n");
-            addInterface(intf);
-        }
-    }
-
-    /**
-     * Create a PIM Interface and add to our interfaces list.
-     *
-     * @param intf the interface to add
-     * @return the PIMInterface
-     */
-    public PIMInterface addInterface(Interface intf) {
-        PIMInterface pif = new PIMInterface(intf);
-        interfaces.put(intf.connectPoint(), pif);
-
-        // If we have added our first interface start the hello timer.
-        if (interfaces.size() == 1) {
-            startHelloTimer();
-        }
-
-        // Return this interface
-        return pif;
-    }
-
-    /**
-     * Remove the PIMInterface from the given ConnectPoint.
-     *
-     * @param cp the ConnectPoint indexing the PIMInterface to be removed.
-     */
-    public void removeInterface(ConnectPoint cp) {
-        if (interfaces.containsKey(cp)) {
-            interfaces.remove(cp);
-        }
-
-        if (interfaces.size() == 0) {
-            PIMTimer.stop();
-        }
-    }
-
-    /**
-     * Return a collection of PIMInterfaces for use by the PIM Interface codec.
-     *
-     * @return the collection of PIMInterfaces
-     */
-    public Collection<PIMInterface> getInterfaces() {
-        return interfaces.values();
-    }
-
-    /**
-     * Get the PIM Interface indexed by the given ConnectPoint.
-     *
-     * @param cp the connect point
-     * @return the PIMInterface if it exists, NULL if not
-     */
-    public PIMInterface getInterface(ConnectPoint cp) {
-        return interfaces.get(cp);
-    }
-
-    /**
-     * Return a string of PIMInterfaces for the cli command.
-     *
-     * @return a string representing PIM interfaces
-     */
-    public String printInterfaces() {
-        String str = "";
-        for (PIMInterface pi : interfaces.values()) {
-            str += pi.toString();
-        }
-        return str;
-    }
-
-    /* ---------------------------------- PIM Hello Timer ----------------------------------- */
-
-    /**
-     * Start a new hello timer for this interface.
-     */
-    private void startHelloTimer() {
-        helloTimer = PIMTimer.getTimer().newTimeout(
-                new HelloTimer(),
-                helloMessageInterval,
-                TimeUnit.SECONDS);
-
-        log.debug("Started Hello Timer");
-    }
-
-    /**
-     * This inner class handles transmitting a PIM hello message on this ConnectPoint.
-     */
-    private final class HelloTimer implements TimerTask {
-
-        HelloTimer() {
-        }
-
-        @Override
-        public void run(Timeout timeout) throws Exception {
-
-            log.debug("Running Hello Timer\n");
-            // Technically we should not send all hello's in synch..
-            for (PIMInterface pi : interfaces.values()) {
-                pi.sendHello();
-            }
-
-            // restart the hello timer
-            if (interfaces.size() > 0) {
-                startHelloTimer();
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfacesCodec.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfacesCodec.java
deleted file mode 100644
index ddd7a59..0000000
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfacesCodec.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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 com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.onosproject.codec.CodecContext;
-import org.onosproject.codec.JsonCodec;
-
-import java.util.Collection;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * PIM neighbors Codec.
- */
-public class PIMInterfacesCodec extends JsonCodec<Collection<PIMInterface>> {
-    // JSON field names
-    //Return Name
-    private static final String CPNBRLIST = "connect_point_list";
-
-    // PIM Neightbors Fields
-    private static final String IP = "ip";
-    private static final String PRIORITY = "priority";
-    private static final String NBRLIST = "neighbor_list";
-
-    // PIM neighbor Files
-    private static final String DR = "designated";
-    private static final String NBR_IP = "ip";
-    private static final String PR = "priority";
-    private static final String HOLDTIME = "hold_time";
-
-    /**
-     * Encode the PIM Neighbors.
-     *
-     * @param cpn ConnectPoint neighbors
-     * @param context encoding context
-     *
-     * @return Encoded neighbors used by CLI and REST
-     */
-    @Override
-    public ObjectNode encode(Collection<PIMInterface> cpn, CodecContext context) {
-        checkNotNull(cpn, "Pim Neighbors cannot be null");
-
-        ObjectNode pimNbrJsonCodec = context.mapper().createObjectNode();
-        ArrayNode cpnList = context.mapper().createArrayNode();
-
-        for (PIMInterface pn: cpn) {
-            // get the PimNeighbors Obj, contains Neighbors list
-            // create the json object for a single Entry in the Neighbors list
-            ObjectNode cp = context.mapper().createObjectNode();
-            cp.put(IP, pn.getIpAddress().toString());
-            cp.put(PRIORITY, String.valueOf(pn.getPriority()));
-
-            // create the array for the neighbors list
-            ArrayNode nbrsList = context.mapper().createArrayNode();
-            for (PIMNeighbor nbr : pn.getNeighbors()) {
-                nbrsList.add(neighbor(nbr, context));
-            }
-            // adds pim neighbor to list
-            cp.set(NBRLIST, nbrsList);
-            // adds to arraynode which will represent the connect point neighbors hash map.
-            cpnList.add(cp);
-        }
-        pimNbrJsonCodec.set(CPNBRLIST, cpnList);
-        return pimNbrJsonCodec;
-    }
-
-    /**
-     * Encode a single PIM Neighbor.
-     *
-     * @param nbr the neighbor to be encoded
-     * @param context encoding context
-     * @return the encoded neighbor
-     */
-    private ObjectNode neighbor(PIMNeighbor nbr, CodecContext context) {
-        return context.mapper().createObjectNode()
-                .put(DR, Boolean.toString(nbr.isDr()))
-                .put(NBR_IP, nbr.getPrimaryAddr().toString())
-                .put(PR, String.valueOf(nbr.getPriority()))
-                .put(HOLDTIME, String.valueOf(nbr.getHoldtime()));
-    }
-}
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbor.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbor.java
deleted file mode 100644
index 73d1598..0000000
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbor.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright 2014-2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in reliance 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.jboss.netty.util.Timeout;
-import org.jboss.netty.util.TimerTask;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.pim.PIMHello;
-import org.onlab.packet.pim.PIMHelloOption;
-import org.onosproject.net.ConnectPoint;
-import org.slf4j.Logger;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.TimeUnit;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * PIMNeighbor represents all the PIM routers that have sent us
- * hello messages, or that possibly have been statically configured.
- */
-public class PIMNeighbor {
-    private final Logger log = getLogger(getClass());
-
-    // The primary address of this PIM neighbor
-    private IpAddress primaryAddr;
-
-    // The MacAddress of this neighbor
-    private MacAddress macAddress;
-
-    // The ConnectPoint this PIM neighbor is connected to.
-    private ConnectPoint connectPoint;
-
-    // Is this neighbor us?
-    private boolean isThisUs = false;
-
-    // The option values this neighbor has sent us.
-    private int priority = 0;
-    private int genId = 0;
-    private short holdtime = 0;
-
-    // Is this pim neighbor the DR?
-    private boolean isDr = false;
-
-    // Timeout for this neighbor
-    private volatile Timeout timeout;
-
-    // A back pointer the neighbors list this neighbor belongs to.
-    private PIMInterface pimInterface;
-
-    /**
-     * Construct this neighbor from the address and connect point.
-     *
-     * @param ipaddr IP Address of neighbor
-     * @param macaddr MAC Address of the neighbor
-     * @param pimInterface The PIMInterface of this neighbor
-     */
-    public PIMNeighbor(IpAddress ipaddr, MacAddress macaddr, PIMInterface pimInterface) {
-        this.macAddress = macaddr;
-        this.primaryAddr = ipaddr;
-        this.pimInterface = pimInterface;
-        this.resetTimeout();
-    }
-
-    /**
-     * Get the primary address of this neighbor.
-     *
-     * @return the primary IP address.
-     */
-    public IpAddress getPrimaryAddr() {
-        return primaryAddr;
-    }
-
-    /**
-     * Set the primary address of this neighbor.
-     *
-     * @param primaryAddr the address we'll use when sending hello messages
-     */
-    public void setPrimaryAddr(IpAddress primaryAddr) {
-        this.primaryAddr = primaryAddr;
-    }
-
-    /**
-     * Get the priority this neighbor has advertised to us.
-     *
-     * @return the priority
-     */
-    public int getPriority() {
-        return priority;
-    }
-
-    /**
-     * Set the priority for this neighbor.
-     *
-     * @param priority This neighbors priority.
-     */
-    public void setPriority(int priority) {
-        this.priority = priority;
-    }
-
-    /**
-     * Get the generation ID.
-     *
-     * @return the generation ID.
-     */
-    public int getGenId() {
-        return genId;
-    }
-
-    /**
-     * Set the generation ID.
-     *
-     * @param genId the generation ID.
-     */
-    public void setGenId(int genId) {
-        this.genId = genId;
-    }
-
-    /**
-     * Get the holdtime for this neighbor.
-     *
-     * @return the holdtime
-     */
-    public short getHoldtime() {
-        return holdtime;
-    }
-
-    /**
-     * Set the holdtime for this neighbor.
-     *
-     * @param holdtime the holdtime.
-     */
-    public void setholdtime(short holdtime) {
-        this.holdtime = holdtime;
-    }
-
-    /**
-     * Is this neighbor the designated router on this connect point?
-     *
-     * @return true if so, false if not.
-     */
-    public boolean isDr() {
-        return isDr;
-    }
-
-    /**
-     * Set this router as the designated router on this connect point.
-     *
-     * @param isDr True is this neighbor is the DR false otherwise
-     */
-    public void setIsDr(boolean isDr) {
-        this.isDr = isDr;
-    }
-
-    /**
-     * The ConnectPoint this neighbor is connected to.
-     *
-     * @return the ConnectPoint
-     */
-    public PIMInterface getPimInterface() {
-        return pimInterface;
-    }
-
-    /**
-     * We have received a fresh hello from this neighbor, now we need to process it.
-     * Depending on the values received in the the hello options may force a
-     * re-election process.
-     *
-     * We will also refresh the timeout for this neighbor.
-     *
-     * @param hello copy of the hello we'll be able to extract options from.
-     */
-    public void refresh(PIMHello hello) {
-        checkNotNull(hello);
-
-        boolean reelect = false;
-        for (PIMHelloOption opt : hello.getOptions().values()) {
-
-            int len = opt.getOptLength();
-            ByteBuffer bb = ByteBuffer.wrap(opt.getValue());
-
-            switch (opt.getOptType()) {
-                case PIMHelloOption.OPT_GENID:
-                    int newid = bb.getInt();
-                    if (this.genId != newid) {
-
-                        // We have a newly rebooted neighbor, this is where we would
-                        // send them our joins.
-                        this.genId = newid;
-                    }
-                    break;
-
-                case PIMHelloOption.OPT_PRIORITY:
-                    int newpri = bb.getInt();
-                    if (this.priority != newpri) {
-
-                        // The priorities have changed.  We may need to re-elect a new DR?
-                        if (this.isDr || pimInterface.getDesignatedRouter().getPriority() < priority) {
-                            reelect = true;
-                        }
-                        this.priority = newpri;
-                    }
-                    break;
-
-                case PIMHelloOption.OPT_HOLDTIME:
-                    short holdtime = bb.getShort();
-                    if (this.holdtime != holdtime) {
-                        this.holdtime = holdtime;
-                        if (holdtime == 0) {
-                            // We have a neighbor going down.  We can remove all joins
-                            // we have learned from them.
-
-                            log.debug("PIM Neighbor has timed out: {}", this.primaryAddr.toString());
-                            return;
-                        }
-                    }
-                    break;
-
-                case PIMHelloOption.OPT_PRUNEDELAY:
-                case PIMHelloOption.OPT_ADDRLIST:
-                    // TODO: implement prune delay and addr list.  Fall through for now.
-
-                default:
-                    log.debug("PIM Hello option type: {} not yet supported or unknown.", opt.getOptType());
-                    break;
-            }
-        }
-
-        if (reelect) {
-            pimInterface.electDR(this);
-        }
-
-        // Reset the next timeout timer
-        this.resetTimeout();
-    }
-
-    /* --------------------------------------- Timer functions -------------------------- */
-
-    /**
-     * Restart the timeout task for this neighbor.
-     */
-    private void resetTimeout() {
-
-        if (this.holdtime == 0) {
-
-            // Prepare to die.
-            log.debug("shutting down timer for nbr {}", this.primaryAddr.toString());
-            if (this.timeout != null) {
-                this.timeout.cancel();
-                this.timeout = null;
-            }
-            return;
-        }
-
-        // Cancel the existing timeout and start a fresh new one.
-        if (this.timeout != null) {
-            this.timeout.cancel();
-        }
-
-        this.timeout = PIMTimer.getTimer().newTimeout(new NeighborTimeoutTask(this), holdtime, TimeUnit.SECONDS);
-    }
-
-    /**
-     * The task to run when a neighbor timeout expires.
-     */
-    private final class NeighborTimeoutTask implements TimerTask {
-        PIMNeighbor nbr;
-
-        NeighborTimeoutTask(PIMNeighbor nbr) {
-            this.nbr = nbr;
-        }
-
-        @Override
-        public void run(Timeout timeout) throws Exception {
-
-            log.debug("PIM Neighbor {} has timed out: ", nbr.toString());
-            nbr.pimInterface.removeNeighbor(nbr);
-        }
-    }
-
-    /**
-     * Stop the timeout timer.
-     *
-     * This happens when we remove the neighbor.
-     */
-    private final void stopTimeout() {
-        this.timeout.cancel();
-        this.timeout = null;
-    }
-
-    @Override
-    public String toString() {
-        String out = "";
-        if (this.isDr) {
-            out += "*NBR:";
-        } else {
-            out += "NBR:";
-        }
-        out += "\tIP: " + this.primaryAddr.toString();
-        out += "\tPr: " + String.valueOf(this.priority);
-        out += "\tHoldTime: " + String.valueOf(this.holdtime);
-        out += "\tGenID: " + String.valueOf(this.genId) + "\n";
-        return out;
-    }
-}
\ No newline at end of file
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMPacketHandler.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMPacketHandler.java
index c1ad2cf..afc57fd 100644
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMPacketHandler.java
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMPacketHandler.java
@@ -17,213 +17,74 @@
 
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
-import org.onlab.packet.Ip4Address;
 import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
 import org.onlab.packet.PIM;
-import org.onlab.packet.VlanId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.incubator.net.intf.Interface;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.packet.DefaultOutboundPacket;
-import org.onosproject.net.packet.InboundPacket;
-import org.onosproject.net.packet.OutboundPacket;
-import org.onosproject.net.packet.PacketContext;
-import org.onosproject.net.packet.PacketPriority;
-import org.onosproject.net.packet.PacketProcessor;
-import org.onosproject.net.packet.PacketService;
 import org.slf4j.Logger;
 
-import java.nio.ByteBuffer;
-
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
- * Handing Incoming and outgoing PIM packets.
+ * This class will process PIM packets.
  */
-public final class PIMPacketHandler {
+public class PIMPacketHandler {
+
     private final Logger log = getLogger(getClass());
 
-    private static PIMPacketHandler instance = null;
-
-    private PacketService packetService;
-    private PIMPacketProcessor processor = new PIMPacketProcessor();
-    private MacAddress pimDestinationMac = MacAddress.valueOf("01:00:5E:00:00:0d");
-
-    // Utility class
-    private PIMPacketHandler() {}
-
-    public static PIMPacketHandler getInstance() {
-        if (null == instance) {
-            instance = new PIMPacketHandler();
-        }
-        return instance;
+    /**
+     * Constructor for this class.
+     */
+    public PIMPacketHandler() {
     }
 
     /**
-     * Initialize the packet handling service.
+     * Sanitize and process the packet.
+     * TODO: replace ConnectPoint with PIMInterface when PIMInterface has been added.
      *
-     * @param ps the packetService
-     * @param appId our application ID
+     * @param ethPkt the packet starting with the Ethernet header.
+     * @param pimi the PIM Interface the packet arrived on.
      */
-    public void initialize(PacketService ps, ApplicationId appId) {
-        packetService = ps;
+    public void processPacket(Ethernet ethPkt, PIMInterface pimi) {
+        checkNotNull(ethPkt);
+        checkNotNull(pimi);
 
-        // Build a traffic selector for all multicast traffic
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-        selector.matchEthType(Ethernet.TYPE_IPV4);
-        selector.matchIPProtocol(IPv4.PROTOCOL_PIM);
-        packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);
-
-        packetService.addProcessor(processor, PacketProcessor.director(1));
-    }
-
-    /**
-     * Shutdown the packet handling service.
-     */
-    public void stop() {
-        packetService.removeProcessor(processor);
-        processor = null;
-    }
-
-    /**
-     * Packet processor responsible for handling IGMP packets.
-     */
-    public class PIMPacketProcessor implements PacketProcessor {
-        private final Logger log = getLogger(getClass());
-
-        @Override
-        public void process(PacketContext context) {
-            // Stop processing if the packet has been handled, since we
-            // can't do any more to it.
-            if (context.isHandled()) {
-                return;
-            }
-
-            InboundPacket pkt = context.inPacket();
-            if (pkt == null) {
-                return;
-            }
-
-            Ethernet ethPkt = pkt.parsed();
-            if (ethPkt == null) {
-                return;
-            }
-
-            /*
-             * IPv6 MLD packets are handled by ICMP6. We'll only deal
-             * with IPv4.
-             */
-            if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) {
-                return;
-            }
-
-            IPv4 ip = (IPv4) ethPkt.getPayload();
-            IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
-            IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
-            log.debug("Packet (" + saddr.toString() + ", " + gaddr.toString() +
-                    "\tingress port: " + context.inPacket().receivedFrom().toString());
-
-            if (ip.getProtocol() != IPv4.PROTOCOL_PIM) {
-                log.debug("PIM Picked up a non PIM packet: IP protocol: " + ip.getProtocol());
-                return;
-            }
-
-            // TODO: check incoming to be PIM.PIM_ADDRESS or "Our" address.
-            IpPrefix spfx = IpPrefix.valueOf(saddr, 32);
-            IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32);
-
-            PIM pim = (PIM) ip.getPayload();
-            switch (pim.getPimMsgType()) {
-
-                case PIM.TYPE_HELLO:
-                    processHello(ethPkt, context.inPacket().receivedFrom());
-                    break;
-
-                case PIM.TYPE_JOIN_PRUNE_REQUEST:
-                    // Create the function
-                    break;
-
-                case PIM.TYPE_ASSERT:
-                case PIM.TYPE_BOOTSTRAP:
-                case PIM.TYPE_CANDIDATE_RP_ADV:
-                case PIM.TYPE_GRAFT:
-                case PIM.TYPE_GRAFT_ACK:
-                case PIM.TYPE_REGISTER:
-                case PIM.TYPE_REGISTER_STOP:
-                    log.debug("Unsupported PIM message type: " + pim.getPimMsgType());
-                    break;
-
-                default:
-                    log.debug("Unkown PIM message type: " + pim.getPimMsgType());
-                    break;
-            }
+        // Sanitize the ethernet header to ensure it is IPv4.  IPv6 we'll deal with later
+        if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) {
+            log.debug("Recieved a non IPv4 packet");
+            return;
         }
 
-        /**
-         * Process incoming hello message, we will need the Macaddress and IP address of the sender.
-         *
-         * @param ethPkt the ethernet header
-         * @param receivedFrom the connect point we recieved this message from
-         */
-        private void processHello(Ethernet ethPkt, ConnectPoint receivedFrom) {
-            checkNotNull(ethPkt);
-            checkNotNull(receivedFrom);
-
-            // It is a problem if we don't have the
-            PIMInterfaces pintfs = PIMInterfaces.getInstance();
-            PIMInterface intf = pintfs.getInterface(receivedFrom);
-            if (intf == null) {
-                log.error("We received a PIM message on an interface we were not supposed to");
-                return;
-            }
-            intf.processHello(ethPkt, receivedFrom);
-        }
-    }
-
-    // Create an ethernet header and serialize then send
-    public void sendPacket(PIM pim, PIMInterface pimIntf) {
-
-        Interface theInterface = pimIntf.getInterface();
-
-        // Create the ethernet packet
-        Ethernet eth = new Ethernet();
-        eth.setDestinationMACAddress(pimDestinationMac);
-        eth.setSourceMACAddress(theInterface.mac());
-        eth.setEtherType(Ethernet.TYPE_IPV4);
-        if (theInterface.vlan() != VlanId.NONE) {
-            eth.setVlanID(theInterface.vlan().toShort());
+        // Get the IP header
+        IPv4 ip = (IPv4) ethPkt.getPayload();
+        if (ip.getProtocol() != IPv4.PROTOCOL_PIM) {
+            log.debug("Received a non PIM IP packet");
+            return;
         }
 
-        // Create the IP Packet
-        IPv4 ip = new IPv4();
-        ip.setVersion((byte) 4);
-        ip.setTtl((byte) 20);
-        ip.setProtocol(IPv4.PROTOCOL_PIM);
-        ip.setChecksum((short) 0);
-        ip.setSourceAddress(checkNotNull(pimIntf.getIpAddress()).getIp4Address().toInt());
-        ip.setDestinationAddress(PIM.PIM_ADDRESS.getIp4Address().toInt());
-        eth.setPayload(ip);
-        ip.setParent(eth);
+        // Get the address of our the neighbor that sent this packet to us.
+        IpAddress nbraddr = IpAddress.valueOf(ip.getDestinationAddress());
+        log.debug("Packet " + nbraddr.toString() + " received on port " + pimi.toString());
 
-        // Now set pim
-        ip.setPayload(pim);
-        pim.setParent(ip);
+        // Get the PIM header
+        PIM pim = (PIM) ip.getPayload();
+        checkNotNull(pim);
 
-        ConnectPoint cp = theInterface.connectPoint();
-        checkNotNull(cp);
+        // Process the pim packet
+        switch (pim.getPimMsgType()) {
 
-        TrafficTreatment treat = DefaultTrafficTreatment.builder().setOutput(cp.port()).build();
-        ByteBuffer bb = ByteBuffer.wrap(eth.serialize());
-        OutboundPacket packet = new DefaultOutboundPacket(cp.deviceId(), treat, bb);
-        checkNotNull(packet);
+            case PIM.TYPE_HELLO:
+                pimi.processHello(ethPkt);
+                log.debug("Received a PIM hello packet");
+                break;
 
-        packetService.emit(packet);
+            case PIM.TYPE_JOIN_PRUNE_REQUEST:
+                pimi.processJoinPrune(ethPkt);
+                log.debug("Received a PIM Join/Prune message");
+                break;
+
+            default:
+                log.debug("Recieved unsupported PIM type: " + pim.getPimMsgType());
+                break;
+        }
     }
 }
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMTimer.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMTimer.java
deleted file mode 100644
index c2a3303..0000000
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMTimer.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.jboss.netty.util.HashedWheelTimer;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * PIM Timer used for PIM Neighbors.
- */
-public final class PIMTimer {
-
-    private static volatile HashedWheelTimer timer;
-
-    // Ban public construction
-    private PIMTimer() {
-    }
-
-    /**
-     * Returns the singleton hashed-wheel timer.
-     *
-     * @return hashed-wheel timer
-     */
-    public static HashedWheelTimer getTimer() {
-        if (PIMTimer.timer == null) {
-            initTimer();
-        }
-        return PIMTimer.timer;
-    }
-
-    // Start the PIM timer.
-    private static synchronized  void initTimer() {
-        if (PIMTimer.timer == null) {
-
-            // Create and start a new hashed wheel timer, if it does not exist.
-            HashedWheelTimer hwTimer = new HashedWheelTimer();
-            hwTimer.start();
-            PIMTimer.timer = hwTimer;
-        }
-    }
-
-    public static void start() {
-        if (PIMTimer.timer == null) {
-            getTimer();
-        }
-        checkNotNull(timer);
-        timer.start();
-    }
-
-    public static void stop() {
-        if (PIMTimer.timer == null) {
-            // No need to stop
-            return;
-        }
-        checkNotNull(timer);
-        timer.stop();
-    }
-}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java
index 793b636..fa92204 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java
@@ -53,7 +53,6 @@
 
 import static org.slf4j.LoggerFactory.getLogger;
 
-
 /**
  * Provides implementation of the meter service APIs.
  */