diff options
Diffstat (limited to 'framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java')
-rw-r--r-- | framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java new file mode 100644 index 00000000..cad90768 --- /dev/null +++ b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java @@ -0,0 +1,395 @@ + +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 |