diff options
Diffstat (limited to 'framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java')
-rwxr-xr-x | framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java new file mode 100755 index 00000000..d9a5e83f --- /dev/null +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java @@ -0,0 +1,296 @@ +/* + * 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.onlab.packet; + +import org.onlab.packet.pim.PIMHello; +import org.onlab.packet.pim.PIMJoinPrune; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +import static org.onlab.packet.PacketUtils.checkInput; + +/** + * Implements PIM control packet format. + */ +public class PIM extends BasePacket { + + public static final IpAddress PIM_ADDRESS = IpAddress.valueOf("224.0.0.13"); + + public static final byte TYPE_HELLO = 0x00; + public static final byte TYPE_REGISTER = 0x01; + public static final byte TYPE_REGISTER_STOP = 0x02; + public static final byte TYPE_JOIN_PRUNE_REQUEST = 0x03; + public static final byte TYPE_BOOTSTRAP = 0x04; + public static final byte TYPE_ASSERT = 0x05; + public static final byte TYPE_GRAFT = 0x06; + public static final byte TYPE_GRAFT_ACK = 0x07; + public static final byte TYPE_CANDIDATE_RP_ADV = 0x08; + + public static final int PIM_HEADER_LEN = 4; + + public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP = + new HashMap<>(); + + static { + PIM.PROTOCOL_DESERIALIZER_MAP.put(PIM.TYPE_HELLO, PIMHello.deserializer()); + PIM.PROTOCOL_DESERIALIZER_MAP.put(PIM.TYPE_JOIN_PRUNE_REQUEST, PIMJoinPrune.deserializer()); + } + + /* + * PIM Header fields + */ + protected byte version; + protected byte type; + protected byte reserved; + protected short checksum; + + /** + * Default constructor. + */ + public PIM() { + super(); + this.version = 2; + this.reserved = 0; + } + + /** + * Return the PIM message type. + * + * @return the pimMsgType + */ + public byte getPimMsgType() { + return this.type; + } + + /** + * Set the PIM message type. Currently PIMJoinPrune and PIMHello are + * supported. + * + * @param type PIM message type + * @return PIM Header + */ + public PIM setPIMType(final byte type) { + this.type = type; + return this; + } + + /** + * Get the version of PIM. + * + * @return the PIM version. Must be 2. + */ + public byte getVersion() { + return version; + } + + /** + * Set the PIM version type. Should not change from 2. + * + * @param version PIM version + */ + public void setVersion(byte version) { + this.version = version; + } + + /** + * Get the reserved field. + * + * @return the reserved field. Must be ignored. + */ + public byte getReserved() { + return reserved; + } + + /** + * Set the reserved field. + * + * @param reserved should be 0 + */ + public void setReserved(byte reserved) { + this.reserved = reserved; + } + + /** + * Get the checksum of this packet. + * + * @return the checksum + */ + public short getChecksum() { + return checksum; + } + + /** + * Set the checksum. + * + * @param checksum the checksum + */ + public void setChecksum(short checksum) { + this.checksum = checksum; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 5807; + int result = super.hashCode(); + result = prime * result + this.type; + result = prime * result + this.version; + result = prime * result + this.checksum; + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (!(obj instanceof PIM)) { + return false; + } + final PIM other = (PIM) obj; + if (this.type != other.type) { + return false; + } + if (this.version != other.version) { + return false; + } + if (this.checksum != other.checksum) { + return false; + } + return true; + } + + /** + * Serializes the packet. Will compute and set the following fields if they + * are set to specific values at the time serialize is called: -checksum : 0 + * -length : 0 + * + * @return will return the serialized packet + */ + @Override + public byte[] serialize() { + int length = 4; + byte[] payloadData = null; + if (this.payload != null) { + this.payload.setParent(this); + payloadData = this.payload.serialize(); + length += payloadData.length; + } + + final byte[] data = new byte[length]; + final ByteBuffer bb = ByteBuffer.wrap(data); + + bb.put((byte) ((this.version & 0xf) << 4 | this.type & 0xf)); + bb.put(this.reserved); + bb.putShort(this.checksum); + if (payloadData != null) { + bb.put(payloadData); + } + + if (this.parent != null && this.parent instanceof PIM) { + ((PIM) this.parent).setPIMType(TYPE_JOIN_PRUNE_REQUEST); + } + + // compute checksum if needed + if (this.checksum == 0) { + bb.rewind(); + int accumulation = 0; + + for (int i = 0; i < length / 2; ++i) { + accumulation += 0xffff & bb.getShort(); + } + // pad to an even number of shorts + if (length % 2 > 0) { + accumulation += (bb.get() & 0xff) << 8; + } + + accumulation = (accumulation >> 16 & 0xffff) + + (accumulation & 0xffff); + this.checksum = (short) (~accumulation & 0xffff); + bb.putShort(2, this.checksum); + } + return data; + } + + /** + * Deserialize the PIM packet. + * + * @param data bytes to deserialize. + * @param offset offset to start deserializing from + * @param length length of the data to deserialize + * + * @return the deserialized PIM packet. + */ + @Override + public IPacket deserialize(final byte[] data, final int offset, + final int length) { + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); + this.type = bb.get(); + this.version = bb.get(); + this.checksum = bb.getShort(); + + //this.payload = new Data(); + this.payload = this.payload.deserialize(data, bb.position(), bb.limit() - bb.position()); + this.payload.setParent(this); + return this; + } + /** + * Deserializer function for IPv4 packets. + * + * @return deserializer function + */ + public static Deserializer<PIM> deserializer() { + return (data, offset, length) -> { + checkInput(data, offset, length, PIM_HEADER_LEN); + + PIM pim = new PIM(); + + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); + + byte versionByte = bb.get(); + pim.version = (byte) (versionByte >> 4 & 0xf); + pim.setPIMType((byte) (versionByte & 0xf)); + pim.reserved = bb.get(); + pim.checksum = bb.getShort(); + + Deserializer<? extends IPacket> deserializer; + if (PIM.PROTOCOL_DESERIALIZER_MAP.containsKey(pim.getPimMsgType())) { + deserializer = PIM.PROTOCOL_DESERIALIZER_MAP.get(pim.getPimMsgType()); + } else { + deserializer = Data.deserializer(); + } + + pim.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position()); + pim.payload.setParent(pim); + + return pim; + }; + } +} |