| /* |
| * 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; |
| } |
| } |