mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-16 18:02:05 +02:00
Added packet handling functions for PIM, Specifically
PIM Hello and PIM Join/Prune messages along with respective PIM encoded address types Change-Id: Iaef2e3581e27fa910ad355043bcb3e175238706a
This commit is contained in:
parent
fef9b2ef7c
commit
80f12527dc
@ -35,6 +35,7 @@ public class IPv4 extends BasePacket {
|
||||
public static final byte PROTOCOL_IGMP = 0x2;
|
||||
public static final byte PROTOCOL_TCP = 0x6;
|
||||
public static final byte PROTOCOL_UDP = 0x11;
|
||||
public static final byte PROTOCOL_PIM = 0x67;
|
||||
public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP =
|
||||
new HashMap<>();
|
||||
|
||||
@ -43,6 +44,7 @@ public class IPv4 extends BasePacket {
|
||||
IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_IGMP, IGMP.deserializer());
|
||||
IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_TCP, TCP.deserializer());
|
||||
IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_UDP, UDP.deserializer());
|
||||
IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_PIM, PIM.deserializer());
|
||||
}
|
||||
|
||||
private static final byte DSCP_MASK = 0x3f;
|
||||
|
296
utils/misc/src/main/java/org/onlab/packet/PIM.java
Executable file
296
utils/misc/src/main/java/org/onlab/packet/PIM.java
Executable file
@ -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_REQUEST_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
|
||||
*/
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
256
utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java
Normal file
256
utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.pim;
|
||||
|
||||
import org.onlab.packet.DeserializationException;
|
||||
import org.onlab.packet.Ip4Address;
|
||||
import org.onlab.packet.IpAddress;
|
||||
import org.onlab.packet.IpPrefix;
|
||||
import org.onlab.packet.Ip6Address;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.onlab.packet.PacketUtils.checkInput;
|
||||
|
||||
public class PIMAddrGroup {
|
||||
private byte family;
|
||||
private byte encType;
|
||||
private byte reserved;
|
||||
private boolean bBit;
|
||||
private boolean zBit;
|
||||
private byte masklen;
|
||||
IpAddress addr;
|
||||
|
||||
public static final int ENC_GROUP_IPV4_BYTE_LENGTH = 4 + Ip4Address.BYTE_LENGTH;
|
||||
public static final int ENC_GROUP_IPV6_BYTE_LENGTH = 4 + Ip6Address.BYTE_LENGTH;
|
||||
|
||||
/**
|
||||
* PIM Encoded Group Address.
|
||||
*/
|
||||
public PIMAddrGroup() {
|
||||
this.family = 4;
|
||||
this.encType = 0;
|
||||
this.reserved = 0;
|
||||
this.bBit = false;
|
||||
this.zBit = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* PIM Encoded Source Address.
|
||||
*
|
||||
* @param addr IPv4 or IPv6
|
||||
*/
|
||||
public PIMAddrGroup(String addr) {
|
||||
this.setAddr(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* PIM Encoded Group Address.
|
||||
*
|
||||
* @param gpfx PIM encoded group address.
|
||||
*/
|
||||
public PIMAddrGroup(IpPrefix gpfx) {
|
||||
this.setAddr(gpfx);
|
||||
}
|
||||
|
||||
/**
|
||||
* PIM encoded source address.
|
||||
*
|
||||
* @param addr IPv4 or IPv6
|
||||
*/
|
||||
public void setAddr(String addr) {
|
||||
setAddr(IpPrefix.valueOf(addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the encoded source address.
|
||||
*
|
||||
* @param pfx
|
||||
*/
|
||||
public void setAddr(IpPrefix pfx) {
|
||||
this.addr = pfx.address();
|
||||
this.masklen = (byte) pfx.prefixLength();
|
||||
this.family = (byte) ((this.addr.isIp4()) ? 4 : 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IP family of this address: 4 or 6.
|
||||
*
|
||||
* @return the IP address family
|
||||
*/
|
||||
public int getFamily() {
|
||||
return this.family;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address of this encoded address.
|
||||
*
|
||||
* @return source address
|
||||
*/
|
||||
public IpAddress getAddr() {
|
||||
return this.addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the masklen of the group address.
|
||||
*
|
||||
* @return the masklen
|
||||
*/
|
||||
public int getMasklen() {
|
||||
return this.masklen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the z bit for admin scoping. Only used for the Bootstrap router.
|
||||
*
|
||||
* @return true or false
|
||||
*/
|
||||
public boolean getZBit() {
|
||||
return this.zBit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bBit. Used to indicate this is a bidir
|
||||
*
|
||||
* @return return true or false.
|
||||
*/
|
||||
public boolean getBBit() {
|
||||
return this.bBit;
|
||||
}
|
||||
|
||||
/**
|
||||
* The size in bytes of a serialized address.
|
||||
*
|
||||
* @return the number of bytes when serialized
|
||||
*/
|
||||
public int getByteSize() {
|
||||
int size = 4;
|
||||
size += addr.isIp4() ? 4 : 16;
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize this group address.
|
||||
*
|
||||
* @return the serialized address in a buffer.
|
||||
*/
|
||||
public byte[] serialize() {
|
||||
int len = getByteSize();
|
||||
|
||||
final byte[] data = new byte[len];
|
||||
final ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
|
||||
bb.put(this.family);
|
||||
bb.put(this.encType);
|
||||
|
||||
// Todo: technically we should be setting the B and Z bits, but we'll never use them.
|
||||
bb.put(reserved);
|
||||
|
||||
bb.put(this.masklen);
|
||||
bb.put(this.addr.toOctets());
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialze from a ByteBuffer.
|
||||
*
|
||||
* @param bb the ByteBuffer
|
||||
* @return an encoded PIM group address.
|
||||
*/
|
||||
public PIMAddrGroup deserialize(ByteBuffer bb) throws DeserializationException {
|
||||
|
||||
/*
|
||||
* We need to verify that we have enough buffer space. First we'll assume that
|
||||
* we are decoding an IPv4 address. After we read the first by (address family),
|
||||
* we'll determine if we actually need more buffer space for an IPv6 address.
|
||||
*/
|
||||
checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_GROUP_IPV4_BYTE_LENGTH);
|
||||
|
||||
this.family = bb.get();
|
||||
if (family != 4 && family != 6) {
|
||||
throw new DeserializationException("Illegal IP version number: " + family + "\n");
|
||||
} else if (family == 6) {
|
||||
|
||||
// Check for one less by since we have already read the first byte of the packet.
|
||||
checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_GROUP_IPV6_BYTE_LENGTH - 1);
|
||||
}
|
||||
|
||||
this.encType = bb.get();
|
||||
this.reserved = bb.get();
|
||||
if ((this.reserved & 0x80) != 0) {
|
||||
this.bBit = true;
|
||||
}
|
||||
if ((this.reserved & 0x01) != 0) {
|
||||
this.zBit = true;
|
||||
}
|
||||
// Remove the z and b bits from reserved
|
||||
this.reserved |= 0x7d;
|
||||
|
||||
this.masklen = bb.get();
|
||||
if (this.family == 4) {
|
||||
this.addr = IpAddress.valueOf(bb.getInt());
|
||||
} else if (this.family == 6) {
|
||||
this.addr = Ip6Address.valueOf(bb.array(), 2);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 2521;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + this.family;
|
||||
result = prime * result + this.encType;
|
||||
result = prime * result + this.reserved;
|
||||
result = prime * result + this.masklen;
|
||||
result = prime * result + this.addr.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals()
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof PIMAddrGroup)) {
|
||||
return false;
|
||||
}
|
||||
final PIMAddrGroup other = (PIMAddrGroup) obj;
|
||||
if (this.family != this.family) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.encType != other.encType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.addr.equals(other.addr)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
281
utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java
Normal file
281
utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* 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.pim;
|
||||
|
||||
import org.onlab.packet.DeserializationException;
|
||||
import org.onlab.packet.Ip4Address;
|
||||
import org.onlab.packet.IpAddress;
|
||||
import org.onlab.packet.IpPrefix;
|
||||
import org.onlab.packet.Ip6Address;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.onlab.packet.PacketUtils.checkInput;
|
||||
|
||||
public class PIMAddrSource {
|
||||
private byte family;
|
||||
private byte encType;
|
||||
private byte reserved;
|
||||
private boolean sBit;
|
||||
private boolean wBit;
|
||||
private boolean rBit;
|
||||
private byte masklen;
|
||||
IpAddress addr;
|
||||
|
||||
public static final int ENC_SOURCE_IPV4_BYTE_LENGTH = 4 + Ip4Address.BYTE_LENGTH;
|
||||
public static final int ENC_SOURCE_IPV6_BYTE_LENGTH = 4 + Ip6Address.BYTE_LENGTH;
|
||||
|
||||
/**
|
||||
* PIM Encoded Source Address.
|
||||
*
|
||||
* @param addr IPv4 or IPv6
|
||||
*/
|
||||
public PIMAddrSource(String addr) {
|
||||
this.init();
|
||||
this.setAddr(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* PIM Encoded Source Address.
|
||||
*
|
||||
* @param spfx IPv4 or IPv6
|
||||
*/
|
||||
public PIMAddrSource(IpPrefix spfx) {
|
||||
this.init();
|
||||
this.setAddr(spfx);
|
||||
}
|
||||
|
||||
/**
|
||||
* PIM Encoded Group Address.
|
||||
*/
|
||||
public PIMAddrSource() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
this.family = 4;
|
||||
this.encType = 0;
|
||||
this.reserved = 0;
|
||||
this.sBit = true;
|
||||
this.wBit = false;
|
||||
this.rBit = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* PIM Encoded Source Address.
|
||||
*
|
||||
* @param addr IPv4 or IPv6
|
||||
*/
|
||||
public void setAddr(String addr) {
|
||||
IpPrefix spfx = IpPrefix.valueOf(addr);
|
||||
setAddr(spfx);
|
||||
}
|
||||
|
||||
/**
|
||||
* PIM Encoded Source Address.
|
||||
*
|
||||
* @param spfx IPv4 or IPv6 address prefix
|
||||
*/
|
||||
public void setAddr(IpPrefix spfx) {
|
||||
this.addr = spfx.address();
|
||||
this.masklen = (byte) spfx.prefixLength();
|
||||
this.family = (byte) ((this.addr.isIp4()) ? 4 : 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IP family of this address: 4 or 6.
|
||||
*
|
||||
* @return the IP address family
|
||||
*/
|
||||
public byte getFamily() {
|
||||
return this.family;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address of this encoded address.
|
||||
*
|
||||
* @return source address
|
||||
*/
|
||||
public IpAddress getAddr() {
|
||||
return this.addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the masklen of the group address.
|
||||
*
|
||||
* @return the masklen
|
||||
*/
|
||||
public int getMasklen() {
|
||||
return this.masklen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sparse bit.
|
||||
*
|
||||
* @return true or false
|
||||
*/
|
||||
public boolean getSBit() {
|
||||
return this.sBit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the wBit, used in Join/Prune messages.
|
||||
*
|
||||
* @return return true or false.
|
||||
*/
|
||||
public boolean getWBit() {
|
||||
return this.wBit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rBit. Used by Rendezvous Point.
|
||||
*
|
||||
* @return the rBit.
|
||||
*/
|
||||
public boolean getRBit() {
|
||||
return this.rBit;
|
||||
}
|
||||
|
||||
/**
|
||||
* The size in bytes of a serialized address.
|
||||
*
|
||||
* @return the number of bytes when serialized
|
||||
*/
|
||||
public int getByteSize() {
|
||||
int size = 4;
|
||||
size += addr.isIp4() ? 4 : 16;
|
||||
return size;
|
||||
}
|
||||
|
||||
public byte[] serialize() {
|
||||
int len = addr.isIp4() ? ENC_SOURCE_IPV4_BYTE_LENGTH : ENC_SOURCE_IPV6_BYTE_LENGTH;
|
||||
|
||||
final byte[] data = new byte[len];
|
||||
final ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
|
||||
bb.put(this.family);
|
||||
bb.put(this.encType);
|
||||
|
||||
// Todo: technically we should be setting the B and Z bits, but we'll never use them.
|
||||
byte mask = 0x0;
|
||||
if (this.sBit) {
|
||||
this.reserved |= 0x4;
|
||||
}
|
||||
if (this.wBit) {
|
||||
this.reserved |= 0x2;
|
||||
}
|
||||
if (this.rBit) {
|
||||
this.reserved |= 0x1;
|
||||
}
|
||||
bb.put(reserved);
|
||||
|
||||
bb.put(this.masklen);
|
||||
bb.put(this.addr.toOctets());
|
||||
return data;
|
||||
}
|
||||
|
||||
public PIMAddrSource deserialize(byte[] data, int offset, int length) throws DeserializationException {
|
||||
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
|
||||
return deserialize(bb);
|
||||
}
|
||||
|
||||
public PIMAddrSource deserialize(ByteBuffer bb) throws DeserializationException {
|
||||
|
||||
/*
|
||||
* We need to verify that we have enough buffer space. First we'll assume that
|
||||
* we are decoding an IPv4 address. After we read the first by (address family),
|
||||
* we'll determine if we actually need more buffer space for an IPv6 address.
|
||||
*/
|
||||
checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_SOURCE_IPV4_BYTE_LENGTH);
|
||||
|
||||
this.family = bb.get();
|
||||
if (family != 4 && family != 6) {
|
||||
throw new DeserializationException("Illegal IP version number: " + family + "\n");
|
||||
} else if (family == 6) {
|
||||
|
||||
// Check for one less by since we have already read the first byte of the packet.
|
||||
checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_SOURCE_IPV6_BYTE_LENGTH - 1);
|
||||
}
|
||||
|
||||
this.encType = bb.get();
|
||||
this.reserved = bb.get();
|
||||
if ((this.reserved & 0x01) != 0) {
|
||||
this.rBit = true;
|
||||
}
|
||||
if ((this.reserved & 0x02) != 0) {
|
||||
this.wBit = true;
|
||||
}
|
||||
if ((this.reserved & 0x4) != 0) {
|
||||
this.sBit = true;
|
||||
}
|
||||
|
||||
// Remove the s, reserved
|
||||
this.reserved &= 0xf8;
|
||||
|
||||
this.masklen = bb.get();
|
||||
if (this.family == 4) {
|
||||
this.addr = IpAddress.valueOf(bb.getInt());
|
||||
} else if (this.family == 6) {
|
||||
this.addr = Ip6Address.valueOf(bb.array(), 2);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 2521;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + this.family;
|
||||
result = prime * result + this.encType;
|
||||
result = prime * result + this.reserved;
|
||||
result = prime * result + this.masklen;
|
||||
result = prime * result + this.addr.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof PIMAddrSource)) {
|
||||
return false;
|
||||
}
|
||||
final PIMAddrSource other = (PIMAddrSource) obj;
|
||||
if (this.family != this.family) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.encType != other.encType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.addr.equals(other.addr)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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.pim;
|
||||
|
||||
import org.onlab.packet.DeserializationException;
|
||||
import org.onlab.packet.Ip4Address;
|
||||
import org.onlab.packet.IpAddress;
|
||||
import org.onlab.packet.Ip6Address;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.onlab.packet.PacketUtils.checkInput;
|
||||
|
||||
public class PIMAddrUnicast {
|
||||
private byte family;
|
||||
private byte encType;
|
||||
IpAddress addr;
|
||||
|
||||
public static final int ENC_UNICAST_IPV4_BYTE_LENGTH = 2 + Ip4Address.BYTE_LENGTH;
|
||||
public static final int ENC_UNICAST_IPV6_BYTE_LENGTH = 2 + Ip6Address.BYTE_LENGTH;
|
||||
|
||||
/**
|
||||
* PIM Encoded Source Address.
|
||||
*/
|
||||
public PIMAddrUnicast() {
|
||||
this.family = 4;
|
||||
this.encType = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* PIM Encoded Source Address.
|
||||
*
|
||||
* @param addr IPv4 or IPv6
|
||||
*/
|
||||
public PIMAddrUnicast(String addr) {
|
||||
this.addr = IpAddress.valueOf(addr);
|
||||
if (this.addr.isIp4()) {
|
||||
this.family = 4;
|
||||
} else {
|
||||
this.family = 6;
|
||||
}
|
||||
this.encType = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* PIM Encoded Source Address.
|
||||
*
|
||||
* @param addr IPv4 or IPv6
|
||||
*/
|
||||
public void setAddr(IpAddress addr) {
|
||||
this.addr = addr;
|
||||
if (this.addr.isIp4()) {
|
||||
this.family = 4;
|
||||
} else {
|
||||
this.family = 6;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address of this encoded address.
|
||||
*
|
||||
* @return source address
|
||||
*/
|
||||
public IpAddress getAddr() {
|
||||
return this.addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IP family of this address: 4 or 6.
|
||||
*
|
||||
* @return the IP address family
|
||||
*/
|
||||
public int getFamily() {
|
||||
return this.family;
|
||||
}
|
||||
|
||||
/**
|
||||
* The size in bytes of a serialized address.
|
||||
*
|
||||
* @return the number of bytes when serialized
|
||||
*/
|
||||
public int getByteSize() {
|
||||
int size = 2;
|
||||
if (addr != null) {
|
||||
size += addr.isIp4() ? 4 : 16;
|
||||
} else {
|
||||
size += 4;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public byte[] serialize() {
|
||||
int len = getByteSize();
|
||||
|
||||
final byte[] data = new byte[len];
|
||||
final ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
|
||||
bb.put(family);
|
||||
bb.put(encType);
|
||||
bb.put(addr.toOctets());
|
||||
return data;
|
||||
}
|
||||
|
||||
public PIMAddrUnicast deserialize(ByteBuffer bb) throws DeserializationException {
|
||||
|
||||
// Assume IPv4 for check length until we read the encoded family.
|
||||
checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_UNICAST_IPV4_BYTE_LENGTH);
|
||||
this.family = bb.get();
|
||||
|
||||
// If we have IPv6 we need to ensure we have adequate buffer space.
|
||||
if (this.family != 4 && this.family != 6) {
|
||||
throw new DeserializationException("Invalid address family: " + this.family);
|
||||
} else if (this.family == 6) {
|
||||
// Subtract -1 from ENC_UNICAST_IPv6 BYTE_LENGTH because we read one byte for family previously.
|
||||
checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_UNICAST_IPV6_BYTE_LENGTH - 1);
|
||||
}
|
||||
|
||||
this.encType = bb.get();
|
||||
if (this.family == 4) {
|
||||
this.addr = IpAddress.valueOf(bb.getInt());
|
||||
} else if (this.family == 6) {
|
||||
this.addr = Ip6Address.valueOf(bb.array(), 2);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 2521;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + this.family;
|
||||
result = prime * result + this.encType;
|
||||
result = prime * result + this.addr.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof PIMAddrUnicast)) {
|
||||
return false;
|
||||
}
|
||||
final PIMAddrUnicast other = (PIMAddrUnicast) obj;
|
||||
if (this.family != this.family) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.encType != other.encType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.addr.equals(other.addr)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
179
utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java
Normal file
179
utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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.pim;
|
||||
|
||||
import org.onlab.packet.BasePacket;
|
||||
import org.onlab.packet.Deserializer;
|
||||
import org.onlab.packet.IPacket;
|
||||
import org.onlab.packet.IpAddress;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.onlab.packet.PacketUtils.checkInput;
|
||||
|
||||
public class PIMHello extends BasePacket {
|
||||
|
||||
private IpAddress nbrIpAddress;
|
||||
|
||||
private int holdtime = 105;
|
||||
private int genid = 0;
|
||||
private int priority = 1;
|
||||
private boolean priorityPresent = false;
|
||||
|
||||
public static final int MINIMUM_OPTION_LEN_BYTES = 4;
|
||||
|
||||
/**
|
||||
* PIM Option types.
|
||||
*/
|
||||
public enum Option {
|
||||
HOLDTIME (1, 2),
|
||||
PRUNEDELAY(2, 4),
|
||||
PRIORITY (19, 4),
|
||||
GENID (20, 4),
|
||||
ADDRLIST (24, 0);
|
||||
|
||||
private final int optType;
|
||||
private final int optLen;
|
||||
|
||||
Option(int ot, int ol) {
|
||||
this.optType = ot;
|
||||
this.optLen = ol;
|
||||
}
|
||||
|
||||
public int optType() {
|
||||
return this.optType;
|
||||
}
|
||||
|
||||
public int optLen() {
|
||||
return this.optLen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the holdtime to the packet.
|
||||
*
|
||||
* @param holdtime the holdtime in seconds
|
||||
*/
|
||||
public void addHoldtime(int holdtime) {
|
||||
this.holdtime = holdtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the hello priority.
|
||||
*
|
||||
* @param priority default is 1, the higher the better
|
||||
*/
|
||||
public void addPriority(int priority) {
|
||||
this.priority = priority;
|
||||
this.priorityPresent = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Gen ID.
|
||||
*
|
||||
* @param genid a random generated number, changes only after reset.
|
||||
*/
|
||||
public void addGenId(int genid) {
|
||||
if (genid == 0) {
|
||||
this.addGenId();
|
||||
} else {
|
||||
this.genid = genid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the genid. Let this function figure out the number.
|
||||
*/
|
||||
public void addGenId() {
|
||||
Random rand = new Random();
|
||||
this.genid = rand.nextInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all payloads parent packet if applicable, then serializes this
|
||||
* packet and all payloads.
|
||||
*
|
||||
* @return a byte[] containing this packet and payloads
|
||||
*/
|
||||
@Override
|
||||
public byte[] serialize() {
|
||||
|
||||
// TODO: Figure out a better way to calculate buffer size
|
||||
int size = Option.PRIORITY.optLen() + 4 +
|
||||
Option.GENID.optLen() + 4 +
|
||||
Option.HOLDTIME.optLen() + 4;
|
||||
|
||||
byte[] data = new byte[size]; // Come up with something better
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
|
||||
// Add the priority
|
||||
bb.putShort((short) Option.PRIORITY.optType);
|
||||
bb.putShort((short) Option.PRIORITY.optLen);
|
||||
bb.putInt(this.priority);
|
||||
|
||||
// Add the genid
|
||||
bb.putShort((short) Option.GENID.optType);
|
||||
bb.putShort((short) Option.GENID.optLen);
|
||||
bb.putInt(this.genid);
|
||||
|
||||
// Add the holdtime
|
||||
bb.putShort((short) Option.HOLDTIME.optType);
|
||||
bb.putShort((short) Option.HOLDTIME.optLen);
|
||||
bb.putShort((short) this.holdtime);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* XXX: This is deprecated, DO NOT USE, use the deserializer() function instead.
|
||||
*/
|
||||
// @Override
|
||||
public IPacket deserialize(final byte[] data, final int offset,
|
||||
final int length) {
|
||||
//
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize this hello message.
|
||||
*
|
||||
* @return a deserialized hello message.
|
||||
*/
|
||||
public static Deserializer<PIMHello> deserializer() {
|
||||
return (data, offset, length) -> {
|
||||
checkInput(data, offset, length, MINIMUM_OPTION_LEN_BYTES);
|
||||
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
|
||||
|
||||
PIMHello hello = new PIMHello();
|
||||
while (bb.hasRemaining()) {
|
||||
int optType = bb.getShort();
|
||||
int optLen = bb.getShort();
|
||||
|
||||
// Check that we have enough buffer for the next option.
|
||||
checkInput(data, bb.position(), bb.limit() - bb.position(), optLen);
|
||||
if (optType == Option.GENID.optType) {
|
||||
hello.addGenId(bb.getInt());
|
||||
} else if (optType == Option.PRIORITY.optType) {
|
||||
hello.addPriority(bb.getInt());
|
||||
} else if (optType == Option.HOLDTIME.optType) {
|
||||
hello.addHoldtime((int) bb.getShort());
|
||||
}
|
||||
}
|
||||
|
||||
return hello;
|
||||
};
|
||||
}
|
||||
}
|
271
utils/misc/src/main/java/org/onlab/packet/pim/PIMJoinPrune.java
Normal file
271
utils/misc/src/main/java/org/onlab/packet/pim/PIMJoinPrune.java
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
* 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.pim;
|
||||
|
||||
import org.onlab.packet.BasePacket;
|
||||
import org.onlab.packet.Deserializer;
|
||||
import org.onlab.packet.IPacket;
|
||||
import org.onlab.packet.IpPrefix;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.onlab.packet.PacketUtils.checkInput;
|
||||
|
||||
public class PIMJoinPrune extends BasePacket {
|
||||
|
||||
private PIMAddrUnicast upstreamAddr = new PIMAddrUnicast();
|
||||
private short holdTime = (short) 0xffff;
|
||||
|
||||
private class JoinPruneGroup {
|
||||
protected IpPrefix group;
|
||||
protected HashMap<IpPrefix, IpPrefix> joins = new HashMap<>();
|
||||
protected HashMap<IpPrefix, IpPrefix> prunes = new HashMap<>();
|
||||
|
||||
public JoinPruneGroup(IpPrefix grp) {
|
||||
group = grp;
|
||||
}
|
||||
}
|
||||
private HashMap<IpPrefix, JoinPruneGroup> joinPrunes = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Get the J/P hold time.
|
||||
*
|
||||
* @return specified in seconds.
|
||||
*/
|
||||
public short getHoldTime() {
|
||||
return holdTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the J/P holdtime in seconds.
|
||||
*
|
||||
* @param holdTime return the holdtime.
|
||||
*/
|
||||
public void setHoldTime(short holdTime) {
|
||||
this.holdTime = holdTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the upstreamAddr for this J/P request.
|
||||
*
|
||||
* @return the upstream address.
|
||||
*/
|
||||
public PIMAddrUnicast getUpstreamAddr() {
|
||||
return upstreamAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the upstream address of this PIM J/P request.
|
||||
*
|
||||
* @param upstr the PIM Upstream unicast address
|
||||
*/
|
||||
public void setUpstreamAddr(PIMAddrUnicast upstr) {
|
||||
this.upstreamAddr = upstr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified s,g to join field.
|
||||
*
|
||||
* @param saddr the source address of the route
|
||||
* @param gaddr the group address of the route
|
||||
* @param join true for a join, false for a prune.
|
||||
*/
|
||||
public void addJoinPrune(String saddr, String gaddr, boolean join) {
|
||||
IpPrefix gpfx = IpPrefix.valueOf(gaddr);
|
||||
IpPrefix spfx = IpPrefix.valueOf(saddr);
|
||||
addJoinPrune(spfx, gpfx, join);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified S, G to the join field.
|
||||
*
|
||||
* @param spfx the source prefix of the route
|
||||
* @param gpfx the group prefix of the route
|
||||
* @param join true for join, false for prune
|
||||
*/
|
||||
public void addJoinPrune(IpPrefix spfx, IpPrefix gpfx, boolean join) {
|
||||
JoinPruneGroup jpg = joinPrunes.get(gpfx);
|
||||
if (jpg == null) {
|
||||
jpg = new JoinPruneGroup(gpfx);
|
||||
joinPrunes.put(gpfx, jpg);
|
||||
}
|
||||
|
||||
HashMap<IpPrefix, IpPrefix> members = (join) ? jpg.joins : jpg.prunes;
|
||||
if (members.get(spfx) == null) {
|
||||
members.put(spfx, spfx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a join given strings represending the source and group addresses.
|
||||
*
|
||||
* @param saddr source address
|
||||
* @param gaddr group address
|
||||
*/
|
||||
public void addJoin(String saddr, String gaddr) {
|
||||
this.addJoinPrune(saddr, gaddr, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a prune given strings represending the source and group addresses.
|
||||
*
|
||||
* @param saddr source address
|
||||
* @param gaddr group address
|
||||
*/
|
||||
public void addPrune(String saddr, String gaddr) {
|
||||
this.addJoinPrune(saddr, gaddr, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all payloads parent packet if applicable, then serializes this
|
||||
* packet and all payloads.
|
||||
*
|
||||
* @return a byte[] containing this packet and payloads
|
||||
*/
|
||||
@Override
|
||||
public byte[] serialize() {
|
||||
|
||||
byte[] data = new byte[8096]; // Come up with something better
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
|
||||
bb.put(upstreamAddr.serialize());
|
||||
bb.put((byte) 0); // reserved
|
||||
|
||||
int ngrps = joinPrunes.size();
|
||||
bb.put((byte) ngrps);
|
||||
bb.putShort(this.holdTime);
|
||||
|
||||
// Walk the group list and input all groups
|
||||
for (JoinPruneGroup jpg : joinPrunes.values()) {
|
||||
PIMAddrGroup grp = new PIMAddrGroup(jpg.group);
|
||||
bb.put(grp.serialize());
|
||||
|
||||
// put the number of joins and prunes
|
||||
bb.putShort((short) jpg.joins.size());
|
||||
bb.putShort((short) jpg.prunes.size());
|
||||
|
||||
// Set all of the joins
|
||||
for (IpPrefix spfx : jpg.joins.values()) {
|
||||
PIMAddrSource src = new PIMAddrSource(spfx);
|
||||
bb.put(src.serialize());
|
||||
}
|
||||
|
||||
// Set all of the prunes
|
||||
for (IpPrefix spfx : jpg.prunes.values()) {
|
||||
PIMAddrSource src = new PIMAddrSource(spfx);
|
||||
bb.put(src.serialize());
|
||||
}
|
||||
}
|
||||
|
||||
int len = bb.position();
|
||||
byte[] data2 = new byte[len];
|
||||
bb = ByteBuffer.wrap(data2, 0, len);
|
||||
bb.put(data, 0, len);
|
||||
return data2;
|
||||
}
|
||||
|
||||
// TODO: I suppose I really need to implement this?
|
||||
@Override
|
||||
public IPacket deserialize(final byte[] data, final int offset,
|
||||
final int length) {
|
||||
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the J/P deserializer function.
|
||||
*
|
||||
* @return a function that will deserialize a J/P message.
|
||||
*/
|
||||
public static Deserializer<PIMJoinPrune> deserializer() {
|
||||
return (data, offset, length) -> {
|
||||
|
||||
/*
|
||||
* Delay buffer checks until we read enough of the packet to know how
|
||||
* much data we will require. Each encoded address deserializer function
|
||||
* will ensure there is enough data for that address.
|
||||
*/
|
||||
PIMJoinPrune jp = new PIMJoinPrune();
|
||||
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
|
||||
|
||||
// We must get a PIM encoded unicast address
|
||||
PIMAddrUnicast upstream = new PIMAddrUnicast();
|
||||
upstream.deserialize(bb);
|
||||
jp.setUpstreamAddr(upstream);
|
||||
|
||||
// Use this boolean to determine the buffer space we need according to address sizes
|
||||
boolean ipv4 = upstream.getAddr().isIp4();
|
||||
|
||||
// We need at minimum 4 bytes for reserved(1), ngroups(1) & holdtime(2)
|
||||
checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), 4);
|
||||
|
||||
// get and skip the reserved byte
|
||||
bb.get();
|
||||
|
||||
// Get the number of groups.
|
||||
int ngroups = bb.get();
|
||||
|
||||
// Save the holdtime.
|
||||
jp.setHoldTime(bb.getShort());
|
||||
|
||||
|
||||
for (int i = 0; i < ngroups; i++) {
|
||||
PIMAddrGroup grp = new PIMAddrGroup();
|
||||
|
||||
/*
|
||||
* grp.deserialize will ensure the buffer has enough data to read the group address.
|
||||
*/
|
||||
grp.deserialize(bb);
|
||||
|
||||
checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), 4);
|
||||
int njoins = bb.getShort();
|
||||
int nprunes = bb.getShort();
|
||||
|
||||
/*
|
||||
* Now we'll verify we have enough buffer to read the next
|
||||
* group of join and prune addresses for this group.
|
||||
*/
|
||||
int required = (njoins + nprunes) *
|
||||
(ipv4 ? PIMAddrSource.ENC_SOURCE_IPV4_BYTE_LENGTH : PIMAddrSource.ENC_SOURCE_IPV6_BYTE_LENGTH);
|
||||
checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), required);
|
||||
|
||||
// Now iterate through the joins for this group
|
||||
for (; njoins > 0; njoins--) {
|
||||
|
||||
PIMAddrSource src = new PIMAddrSource();
|
||||
src.deserialize(bb);
|
||||
|
||||
jp.addJoinPrune(
|
||||
src.getAddr().toIpPrefix(),
|
||||
grp.getAddr().toIpPrefix(), true);
|
||||
}
|
||||
|
||||
// Now iterate through the prunes for this group
|
||||
for (; nprunes > 0; nprunes--) {
|
||||
|
||||
PIMAddrSource src = new PIMAddrSource();
|
||||
src.deserialize(bb);
|
||||
jp.addJoinPrune(
|
||||
src.getAddr().toIpPrefix(),
|
||||
grp.getAddr().toIpPrefix(), false);
|
||||
}
|
||||
}
|
||||
|
||||
return jp;
|
||||
};
|
||||
}
|
||||
}
|
21
utils/misc/src/main/java/org/onlab/packet/pim/package-info.java
Executable file
21
utils/misc/src/main/java/org/onlab/packet/pim/package-info.java
Executable file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Utilities for managing PIM packets.
|
||||
*/
|
||||
package org.onlab.packet.pim;
|
||||
|
112
utils/misc/src/test/java/org/onlab/packet/PIMTest.java
Normal file
112
utils/misc/src/test/java/org/onlab/packet/PIMTest.java
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.onlab.packet.pim.PIMAddrUnicast;
|
||||
import org.onlab.packet.pim.PIMHello;
|
||||
import org.onlab.packet.pim.PIMJoinPrune;
|
||||
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
public final class PIMTest {
|
||||
|
||||
public static final String SADDR = "10.2.1.2";
|
||||
public static final String PIMADDR = "224.0.0.13";
|
||||
public static final String PIMUADDR = "10.23.3.5";
|
||||
|
||||
public static final String SADDR1 = "10.1.1.1/32";
|
||||
public static final String SADDR2 = "10.1.2.1/32";
|
||||
public static final String GADDR1 = "232.1.1.1/32";
|
||||
public static final String GADDR2 = "232.1.2.1/32";
|
||||
|
||||
public static final String CPSTR1 = "of:deadbeefball/8";
|
||||
public static final String CPSTR2 = "of:deadbeefcafe/3";
|
||||
public static final String CPSTR3 = "of:2badcafef00d/3";
|
||||
|
||||
private Deserializer<PIM> deserializer;
|
||||
|
||||
private PIM pimHello;
|
||||
private PIMHello hello;
|
||||
|
||||
private PIM pimJoinPrune;
|
||||
private PIMJoinPrune joinPrune;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
// Create a PIM Hello
|
||||
pimHello = new PIM();
|
||||
pimHello.setVersion((byte) 2);
|
||||
pimHello.setPIMType((byte) PIM.TYPE_HELLO);
|
||||
pimHello.setChecksum((short) 0);
|
||||
|
||||
hello = new PIMHello();
|
||||
hello.addHoldtime(0xd2);
|
||||
hello.addPriority(44);
|
||||
hello.addGenId(0xf00d);
|
||||
pimHello.setPayload(hello);
|
||||
hello.setParent(pimHello);
|
||||
|
||||
// Create PIM Join Prune
|
||||
pimJoinPrune = new PIM();
|
||||
pimJoinPrune.setVersion((byte) 2);
|
||||
pimJoinPrune.setPIMType((byte) PIM.TYPE_JOIN_PRUNE_REQUEST);
|
||||
pimJoinPrune.setChecksum((short) 0);
|
||||
|
||||
joinPrune = new PIMJoinPrune();
|
||||
joinPrune.setUpstreamAddr(new PIMAddrUnicast(SADDR));
|
||||
joinPrune.addJoin(GADDR1, SADDR1);
|
||||
joinPrune.addJoin(GADDR2, SADDR2);
|
||||
joinPrune.addPrune(GADDR1, SADDR2);
|
||||
joinPrune.addPrune(GADDR2, SADDR1);
|
||||
|
||||
pimJoinPrune.setPayload(joinPrune);
|
||||
joinPrune.setParent(pimJoinPrune);
|
||||
|
||||
deserializer = PIM.deserializer();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDerserializeBadInput() throws Exception {
|
||||
PacketTestUtils.testDeserializeBadInput(deserializer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeserializeTruncated() throws Exception {
|
||||
//byte [] bits = pimHello.serialize();
|
||||
//PacketTestUtils.testDeserializeTruncated(deserializer, bits);
|
||||
|
||||
byte [] bits = pimJoinPrune.serialize();
|
||||
PacketTestUtils.testDeserializeTruncated(deserializer, bits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeserializeHello() throws Exception {
|
||||
byte [] data = pimHello.serialize();
|
||||
PIM pim = deserializer.deserialize(data, 0, data.length);
|
||||
assertTrue(pim.equals(pimHello));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeserializeJoinPrune() throws Exception {
|
||||
byte [] data = pimJoinPrune.serialize();
|
||||
PIM pim = deserializer.deserialize(data, 0, data.length);
|
||||
assertTrue(pim.equals(pimJoinPrune));
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user