PIM Neighbors refactored to PIMInterfaces and now used
the NetworkConfiguration service
Change-Id: Ieb0a6faee3f3399f1bba5d9614fce6b0050e8510
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
index 0ef7e38..6bd563b 100644
--- a/apps/pim/src/main/java/org/onosproject/pim/cli/PIMShowCommand.java
+++ b/apps/pim/src/main/java/org/onosproject/pim/cli/PIMShowCommand.java
@@ -18,30 +18,30 @@
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.pim.impl.PIMNeighbors;
-import org.onosproject.pim.impl.PIMNeighborsCodec;
+import org.onosproject.pim.impl.PIMInterface;
+import org.onosproject.pim.impl.PIMInterfaces;
+import org.onosproject.pim.impl.PIMInterfacesCodec;
-import java.util.HashMap;
+import java.util.Collection;
-@Command(scope = "onos", name = "pim-neighbors", description = "Displays the pim neighbors")
+@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 PIMNeighbors class.
+ // neighbors from the PIMInterfaces class.
@Override
protected void execute() {
// grab connect point neighbors hash map to send in to json encoder.
- HashMap<ConnectPoint, PIMNeighbors> pimNbrs = PIMNeighbors.getConnectPointNeighbors();
+ Collection<PIMInterface> pimIntfs = PIMInterfaces.getInstance().getInterfaces();
if (outputJson()) {
- print("%s", json(pimNbrs));
+ print("%s", json(pimIntfs));
} else {
- print(PIMNeighbors.printPimNeighbors());
+ print(PIMInterfaces.getInstance().printInterfaces());
}
}
- private JsonNode json(HashMap<ConnectPoint, PIMNeighbors> pimNbrs) {
- return new PIMNeighborsCodec().encode(pimNbrs, this);
+ 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/PIMComponent.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMComponent.java
index bd5e148..1a2d6f5 100644
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMComponent.java
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMComponent.java
@@ -22,132 +22,61 @@
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.onlab.packet.Ip4Address;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.PIM;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.packet.InboundPacket;
-import org.onosproject.net.packet.PacketContext;
-import org.onosproject.net.packet.PacketPriority;
-import org.onosproject.net.packet.PacketProcessor;
+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 Emulation.
+ * 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;
- private PIMPacketProcessor processor = new PIMPacketProcessor();
+ // 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");
- packetService.addProcessor(processor, PacketProcessor.director(1));
+ // Initialize the Packet Handler class
+ pimPacketHandler = PIMPacketHandler.getInstance();
+ pimPacketHandler.initialize(packetService, appId);
- // 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);
+ // Initialize the Interface class
+ pimInterfaces = PIMInterfaces.getInstance();
+ pimInterfaces.initialize(configService, interfaceService);
log.info("Started");
}
@Deactivate
public void deactivate() {
- packetService.removeProcessor(processor);
- processor = null;
+ PIMPacketHandler.getInstance().stop();
log.info("Stopped");
}
-
- /**
- * Packet processor responsible for handling IGMP packets.
- */
- private class PIMPacketProcessor implements PacketProcessor {
-
- @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:
- PIMNeighbors.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;
- }
- }
- }
}
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
new file mode 100644
index 0000000..28d1e8b
--- /dev/null
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterface.java
@@ -0,0 +1,339 @@
+/*
+ * 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.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 static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * The PIM Interface is a wrapper around a ConnectPoint and used to provide
+ * hello options values when "talking" with PIM other PIM routers.
+ */
+public class PIMInterface {
+ private static Logger log = LoggerFactory.getLogger("PIMInterfaces");
+
+ // Interface from the interface subsystem
+ private Interface theInterface;
+
+ // The list of PIM neighbors adjacent to this interface
+ private Map<IpAddress, PIMNeighbor> neighbors = new HashMap<>();
+
+ // The designatedRouter for this LAN
+ private PIMNeighbor designatedRouter;
+
+ // The priority we use on this ConnectPoint.
+ private int priority = PIMHelloOption.DEFAULT_PRIORITY;
+
+ // The holdtime we are sending out.
+ private int holdtime = PIMHelloOption.DEFAULT_HOLDTIME;
+
+ // 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;
+
+ /**
+ * Create a PIMInterface.
+ */
+ 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();
+ }
+
+ /**
+ * Get the PIM Interface.
+ *
+ * @return the PIM Interface
+ */
+ public Interface getInterface() {
+ return theInterface;
+ }
+
+ /**
+ * Getter for our IP address.
+ *
+ * @return our IP address.
+ */
+ public IpAddress getIpAddress() {
+ if (theInterface.ipAddresses().isEmpty()) {
+ return null;
+ }
+
+ // We will just assume the first interface on the list
+ IpAddress ipaddr = null;
+ for (InterfaceIpAddress ifipaddr : theInterface.ipAddresses()) {
+ ipaddr = ifipaddr.ipAddress();
+ break;
+ }
+ return ipaddr;
+ }
+
+ /**
+ * Get our priority.
+ *
+ * @return our priority.
+ */
+ public int getPriority() {
+ return this.priority;
+ }
+
+ /**
+ * Get the designated router on this connection.
+ *
+ * @return the PIMNeighbor representing the DR
+ */
+ public PIMNeighbor getDesignatedRouter() {
+ return designatedRouter;
+ }
+
+ /**
+ * Are we the DR on this CP?
+ *
+ * @return true if we are, false if not
+ */
+ public boolean areWeDr() {
+ return (designatedRouter != null &&
+ designatedRouter.getPrimaryAddr().equals(this.getIpAddress()));
+ }
+
+ /**
+ * Return a collection of PIM Neighbors.
+ *
+ * @return the collection of PIM Neighbors
+ */
+ public Collection<PIMNeighbor> getNeighbors() {
+ return this.neighbors.values();
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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());
+ 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;
+ }
+ nbr.refresh(hello);
+ }
+
+ /**
+ * 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.
+ *
+ * @return string of neighbors.
+ */
+ public String printNeighbors() {
+ String out = "PIM Neighbors Table: \n";
+ for (PIMNeighbor nbr : this.neighbors.values()) {
+ out += "\t" + nbr.toString();
+ }
+ return out;
+ }
+
+ @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/PIMInterfaces.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaces.java
new file mode 100644
index 0000000..e33d5aa
--- /dev/null
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfaces.java
@@ -0,0 +1,260 @@
+/*
+ * 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) {
+ 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/PIMNeighborsCodec.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfacesCodec.java
similarity index 86%
rename from apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighborsCodec.java
rename to apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfacesCodec.java
index ee62eb7..ddd7a59 100644
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighborsCodec.java
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMInterfacesCodec.java
@@ -19,16 +19,15 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
-import org.onosproject.net.ConnectPoint;
-import java.util.HashMap;
+import java.util.Collection;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* PIM neighbors Codec.
*/
-public class PIMNeighborsCodec extends JsonCodec<HashMap<ConnectPoint, PIMNeighbors>> {
+public class PIMInterfacesCodec extends JsonCodec<Collection<PIMInterface>> {
// JSON field names
//Return Name
private static final String CPNBRLIST = "connect_point_list";
@@ -53,22 +52,22 @@
* @return Encoded neighbors used by CLI and REST
*/
@Override
- public ObjectNode encode(HashMap<ConnectPoint, PIMNeighbors> cpn, CodecContext context) {
+ 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 (PIMNeighbors pn: cpn.values()) {
+ 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.getOurIpAddress().toString());
- cp.put(PRIORITY, String.valueOf(pn.getOurPriority()));
+ 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.getOurNeighborsList().values()) {
+ for (PIMNeighbor nbr : pn.getNeighbors()) {
nbrsList.add(neighbor(nbr, context));
}
// adds pim neighbor to list
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
index 1a96138..73d1598 100644
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbor.java
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbor.java
@@ -60,22 +60,20 @@
// Timeout for this neighbor
private volatile Timeout timeout;
- private boolean reelect = false;
-
// A back pointer the neighbors list this neighbor belongs to.
- private PIMNeighbors neighbors;
+ 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 cp The ConnectPoint of this neighbor
+ * @param pimInterface The PIMInterface of this neighbor
*/
- public PIMNeighbor(IpAddress ipaddr, MacAddress macaddr, ConnectPoint cp) {
+ public PIMNeighbor(IpAddress ipaddr, MacAddress macaddr, PIMInterface pimInterface) {
this.macAddress = macaddr;
this.primaryAddr = ipaddr;
- this.connectPoint = cp;
+ this.pimInterface = pimInterface;
this.resetTimeout();
}
@@ -174,30 +172,12 @@
*
* @return the ConnectPoint
*/
- public ConnectPoint getConnectPoint() {
- return connectPoint;
+ public PIMInterface getPimInterface() {
+ return pimInterface;
}
/**
- * Set the ConnectPoint this router is connected to.
- *
- * @param connectPoint the ConnectPoint this router is connected to.
- */
- public void setConnectPoint(ConnectPoint connectPoint) {
- this.connectPoint = connectPoint;
- }
-
- /**
- * Set a back pointer to the neighbors list this neighbor is a member of.
- *
- * @param neighbors the neighbor list this neighbor belongs to
- */
- public void setNeighbors(PIMNeighbors neighbors) {
- this.neighbors = neighbors;
- }
-
- /**
- * We have received a fresh hello from a neighbor, now we need to process it.
+ * 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.
*
@@ -208,17 +188,19 @@
public void refresh(PIMHello hello) {
checkNotNull(hello);
+ boolean reelect = false;
for (PIMHelloOption opt : hello.getOptions().values()) {
int len = opt.getOptLength();
- byte [] value = new byte[len];
- ByteBuffer bb = ByteBuffer.wrap(value);
+ ByteBuffer bb = ByteBuffer.wrap(opt.getValue());
switch (opt.getOptType()) {
case PIMHelloOption.OPT_GENID:
int newid = bb.getInt();
if (this.genId != newid) {
- // TODO: we have a newly rebooted neighbor. Send them our joins.
+
+ // We have a newly rebooted neighbor, this is where we would
+ // send them our joins.
this.genId = newid;
}
break;
@@ -228,7 +210,7 @@
if (this.priority != newpri) {
// The priorities have changed. We may need to re-elect a new DR?
- if (this.isDr || this.neighbors.getDesignatedRouter().getPriority() < priority) {
+ if (this.isDr || pimInterface.getDesignatedRouter().getPriority() < priority) {
reelect = true;
}
this.priority = newpri;
@@ -242,7 +224,6 @@
if (holdtime == 0) {
// We have a neighbor going down. We can remove all joins
// we have learned from them.
- // TODO: What else do we need to do when a neighbor goes down?
log.debug("PIM Neighbor has timed out: {}", this.primaryAddr.toString());
return;
@@ -261,7 +242,7 @@
}
if (reelect) {
- this.neighbors.electDR(this);
+ pimInterface.electDR(this);
}
// Reset the next timeout timer
@@ -307,9 +288,8 @@
@Override
public void run(Timeout timeout) throws Exception {
- // TODO: log.debug;
- PIMNeighbors neighbors = nbr.neighbors;
- neighbors.removeNeighbor(nbr.getPrimaryAddr());
+ log.debug("PIM Neighbor {} has timed out: ", nbr.toString());
+ nbr.pimInterface.removeNeighbor(nbr);
}
}
diff --git a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java
deleted file mode 100644
index cad9076..0000000
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java
+++ /dev/null
@@ -1,395 +0,0 @@
-
-package org.onosproject.pim.impl;
-
-import org.jboss.netty.util.Timeout;
-import org.jboss.netty.util.TimerTask;
-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.onosproject.net.ConnectPoint;
-import java.util.HashMap;
-import java.util.concurrent.TimeUnit;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * PIMNeighbors 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 PIMNeighbors {
-
- private static Logger log = LoggerFactory.getLogger("PIMNeighbors");
-
- /**
- * This is the global container for all PIM neighbors indexed by ConnectPoints.
- *
- * NOTE: We'll have a problem if the same neighbor can show up on two interfaces
- * but that should never happen.
- */
- private static HashMap<ConnectPoint, PIMNeighbors> connectPointNeighbors = new HashMap<>();
-
- // The connect point these neighbors are connected to.
- private ConnectPoint connectPoint;
-
- // Pointer to the current designated router on this ConnectPoint.
- private PIMNeighbor designatedRouter;
-
- // The list of neighbors we have learned on this ConnectPoint.
- private HashMap<IpAddress, PIMNeighbor> neighbors = new HashMap<>();
-
- /*
- * TODO: turn ourIpAddress, ourPriority and OurHoldTime into config options.
- */
- // The IP address we are using to source our PIM hello messages on this connect Point.
- private IpAddress ourIpAddress;
-
- // The priority we use on this ConnectPoint.
- private int ourPriority = 1;
-
- // The holdtime we are sending out.
- private int ourHoldtime = 105;
-
- // Then generation ID we are sending out. 0 means we need to generate a new random ID
- private int ourGenid = 0;
-
- // Hello Timer for sending hello messages per ConnectPoint with neighbors.
- private volatile Timeout helloTimer;
-
- // The period of which we will be sending out PIM hello messages.
- private final int defaultPimHelloInterval = 30; // seconds
-
- /**
- * Create PIMNeighbors object per ConnectPoint.
- *
- * @param cp the ConnectPoint.
- * @return PIMNeighbors structure
- */
- public static PIMNeighbors getConnectPointNeighbors(ConnectPoint cp) {
- return connectPointNeighbors.get(cp);
- }
-
- /**
- * 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
- */
- public static void processHello(Ethernet ethPkt, ConnectPoint receivedFrom) {
- checkNotNull(ethPkt);
- checkNotNull(ethPkt);
-
- 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 = PIMNeighbors.findOrCreate(srcip, srcmac, receivedFrom);
- if (nbr == null) {
- log.error("Could not create a neighbor for: {1}", srcip.toString());
- return;
- }
-
- nbr.setConnectPoint(receivedFrom);
- nbr.refresh(hello);
- }
-
- /**
- * Create a PIM Neighbor.
- *
- * @param cp The ConnectPoint this neighbor was found on
- */
- public PIMNeighbors(ConnectPoint cp) {
- this.connectPoint = cp;
-
- // TODO: use network config to assign address.
- this.ourIpAddress = IpAddress.valueOf("10.2.2.2");
- this.addIpAddress(this.ourIpAddress);
- }
-
- /**
- * Create a PIM neighbor.
- *
- * @param cp the ConnectPoint this neighbor was found on
- * @param ourIp the IP address of this neighbor
- */
- public PIMNeighbors(ConnectPoint cp, IpAddress ourIp) {
- this.connectPoint = cp;
- this.addIpAddress(ourIp);
- }
-
- /**
- * Start the hello timer when we have been given an IP address.
- *
- * @param ourIp our IP address.
- */
- public void addIpAddress(IpAddress ourIp) {
- this.startHelloTimer();
-
- // Kick off the first pim hello packet
- this.sendHelloPacket();
- }
-
- /**
- * Getter for our IP address.
- *
- * @return our IP address.
- */
- public IpAddress getOurIpAddress() {
- return this.ourIpAddress;
- }
-
- /**
- * Get our priority.
- *
- * @return our priority.
- */
- public int getOurPriority() {
- return this.ourPriority;
- }
-
- /**
- * Get the neighbor list for this specific connectPoint.
- *
- * @return PIM neighbors on this ConnectPoint
- */
- public HashMap<IpAddress, PIMNeighbor> getOurNeighborsList() {
- return this.neighbors;
- }
-
- /**
- * Get the designated router on this connection.
- *
- * @return the PIMNeighbor representing the DR
- */
- public PIMNeighbor getDesignatedRouter() {
- return designatedRouter;
- }
-
- /**
- * Are we the DR on this CP?
- *
- * @return true if we are, false if not
- */
- public boolean weAreTheDr() {
- return (designatedRouter != null &&
- designatedRouter.getPrimaryAddr().equals(ourIpAddress));
- }
-
- /**
- * 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;
- }
-
- /**
- * 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())) {
-
- // TODO: Hmmm, how should this be handled?
- log.debug("We are adding a neighbor that already exists: {}", nbr.toString());
- neighbors.remove(nbr.getPrimaryAddr(), nbr);
- }
- nbr.setNeighbors(this);
- 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) {
-
- boolean reelect = (designatedRouter == null || designatedRouter.getPrimaryAddr().equals(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) {
-
- boolean reelect = (designatedRouter == null || nbr.isDr());
- 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
- * @param cp the connect point the neighbor was learned from
- * @return an existing or new PIM neighbor
- */
- public static PIMNeighbor findOrCreate(IpAddress ipaddr, MacAddress mac, ConnectPoint cp) {
- PIMNeighbors neighbors = connectPointNeighbors.get(cp);
- if (neighbors == null) {
- neighbors = new PIMNeighbors(cp);
- connectPointNeighbors.put(cp, neighbors);
- }
-
- PIMNeighbor nbr = neighbors.findNeighbor(ipaddr);
- if (nbr == null) {
- nbr = new PIMNeighbor(ipaddr, mac, cp);
- neighbors.addNeighbor(nbr);
- neighbors.electDR(nbr);
- }
- return nbr;
- }
-
- // Returns the connect point neighbors hash map
- public static HashMap<ConnectPoint, PIMNeighbors> getConnectPointNeighbors() {
- return connectPointNeighbors;
- }
-
- /* ---------------------------------- PIM Hello Timer ----------------------------------- */
-
- /**
- * Start a new hello timer for this ConnectPoint.
- */
- private void startHelloTimer() {
- this.helloTimer = PIMTimer.getTimer().newTimeout(
- new HelloTimer(this),
- this.defaultPimHelloInterval,
- TimeUnit.SECONDS);
-
- log.trace("Started Hello Timer: " + this.ourIpAddress.toString());
- }
-
- /**
- * This inner class handles transmitting a PIM hello message on this ConnectPoint.
- */
- private final class HelloTimer implements TimerTask {
- PIMNeighbors neighbors;
-
- HelloTimer(PIMNeighbors neighbors) {
- this.neighbors = neighbors;
- }
-
- @Override
- public void run(Timeout timeout) throws Exception {
-
- // Send off a hello packet
- sendHelloPacket();
-
- // restart the hello timer
- neighbors.startHelloTimer();
- }
- }
-
- private void sendHelloPacket() {
- PIMHello hello = new PIMHello();
-
- // TODO: we will need to implement the network config service to assign ip addresses & options
- /*
- hello.createDefaultOptions();
-
- Ethernet eth = hello.createPIMHello(this.ourIpAddress);
- hello.sendPacket(this.connectPoint);
- */
- }
-
- /**
- * prints the connectPointNeighbors list with each neighbor list.
- *
- * @return string of neighbors.
- */
- public static String printPimNeighbors() {
- String out = "PIM Neighbors Table: \n";
-
- for (PIMNeighbors pn: connectPointNeighbors.values()) {
-
- out += "CP:\n " + pn.toString();
- for (PIMNeighbor nbr : pn.neighbors.values()) {
- out += "\t" + nbr.toString();
- }
- }
- return out;
- }
-
- @Override
- public String toString() {
- String out = "PIM Neighbors: ";
- if (this.ourIpAddress != null) {
- out += "IP: " + this.ourIpAddress.toString();
- } else {
- out += "IP: *Null*";
- }
- out += "\tPR: " + String.valueOf(this.ourPriority) + "\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
new file mode 100644
index 0000000..c1ad2cf
--- /dev/null
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMPacketHandler.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.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.
+ */
+public final 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;
+ }
+
+ /**
+ * Initialize the packet handling service.
+ *
+ * @param ps the packetService
+ * @param appId our application ID
+ */
+ public void initialize(PacketService ps, ApplicationId appId) {
+ packetService = ps;
+
+ // 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;
+ }
+ }
+
+ /**
+ * 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());
+ }
+
+ // 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);
+
+ // Now set pim
+ ip.setPayload(pim);
+ pim.setParent(ip);
+
+ ConnectPoint cp = theInterface.connectPoint();
+ checkNotNull(cp);
+
+ TrafficTreatment treat = DefaultTrafficTreatment.builder().setOutput(cp.port()).build();
+ ByteBuffer bb = ByteBuffer.wrap(eth.serialize());
+ OutboundPacket packet = new DefaultOutboundPacket(cp.deviceId(), treat, bb);
+ checkNotNull(packet);
+
+ packetService.emit(packet);
+ }
+}
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
index c131a53..c2a3303 100644
--- a/apps/pim/src/main/java/org/onosproject/pim/impl/PIMTimer.java
+++ b/apps/pim/src/main/java/org/onosproject/pim/impl/PIMTimer.java
@@ -17,6 +17,8 @@
import org.jboss.netty.util.HashedWheelTimer;
+import static com.google.common.base.Preconditions.checkNotNull;
+
/**
* PIM Timer used for PIM Neighbors.
*/
@@ -50,4 +52,21 @@
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();
+ }
}