Improvided PIM Hello option handling by creating the
PIMHelloOption class. Also fixed a typo for pim regsiter
stop message type.
Change-Id: Iff06ce7d2746ebc34811205f4c4a4d4784e2740c
diff --git a/utils/misc/src/main/java/org/onlab/packet/PIM.java b/utils/misc/src/main/java/org/onlab/packet/PIM.java
index d306263..d9a5e83 100755
--- a/utils/misc/src/main/java/org/onlab/packet/PIM.java
+++ b/utils/misc/src/main/java/org/onlab/packet/PIM.java
@@ -33,7 +33,7 @@
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_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;
diff --git a/utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java b/utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java
index d454f1a..9ad3fdb 100644
--- a/utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java
+++ b/utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java
@@ -19,88 +19,41 @@
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import org.onlab.packet.IpAddress;
-
import java.nio.ByteBuffer;
-import java.util.Random;
+import java.util.HashMap;
+import java.util.Map;
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;
+ private Map<Short, PIMHelloOption> options = new HashMap<>();
/**
- * PIM Option types.
+ * Create a PIM Hello packet with the most common hello options and default
+ * values. The values of any options can be easily changed by modifying the value of
+ * the option with the desired change.
*/
- 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;
- }
+ public void createDefaultOptions() {
+ options.put(PIMHelloOption.OPT_HOLDTIME, new PIMHelloOption(PIMHelloOption.OPT_HOLDTIME));
+ options.put(PIMHelloOption.OPT_PRIORITY, new PIMHelloOption(PIMHelloOption.OPT_PRIORITY));
+ options.put(PIMHelloOption.OPT_GENID, new PIMHelloOption(PIMHelloOption.OPT_GENID));
}
/**
- * Add the holdtime to the packet.
+ * Add a PIM Hello option to this hello message. Note
*
- * @param holdtime the holdtime in seconds
+ * @param opt the PIM Hello option we are adding
*/
- public void addHoldtime(int holdtime) {
- this.holdtime = holdtime;
+ public void addOption(PIMHelloOption opt) {
+ this.options.put(opt.getOptType(), opt);
}
- /**
- * 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();
+ public Map<Short, PIMHelloOption> getOptions() {
+ return this.options;
}
/**
@@ -111,68 +64,54 @@
*/
@Override
public byte[] serialize() {
+ int totalLen = 0;
- // 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
+ // Since we are likely to only have 3-4 options, go head and walk the
+ // hashmap twice, once to calculate the space needed to allocate a
+ // buffer, the second time serialize the options into the buffer. This
+ // saves us from allocating an over sized buffer the re-allocating and
+ // copying.
+ for (Short optType : options.keySet()) {
+ PIMHelloOption opt = options.get(optType);
+ totalLen += PIMHelloOption.MINIMUM_OPTION_LEN_BYTES + opt.getOptLength();
+ }
+
+ byte[] data = new byte[totalLen];
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);
+ // Now serialize the data.
+ for (Short optType : options.keySet()) {
+ PIMHelloOption opt = options.get(optType);
+ bb.put(opt.serialize());
+ }
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) {
- //
+ // TODO: throw an expection?
return null;
}
/**
* Deserialize this hello message.
*
- * @return a deserialized hello message.
+ * @return a deserialized hello message
*/
public static Deserializer<PIMHello> deserializer() {
return (data, offset, length) -> {
- checkInput(data, offset, length, MINIMUM_OPTION_LEN_BYTES);
+ checkInput(data, offset, length, PIMHelloOption.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());
- }
+ PIMHelloOption opt = PIMHelloOption.deserialize(bb);
+ hello.addOption(opt);
}
-
return hello;
};
}
diff --git a/utils/misc/src/main/java/org/onlab/packet/pim/PIMHelloOption.java b/utils/misc/src/main/java/org/onlab/packet/pim/PIMHelloOption.java
new file mode 100644
index 0000000..bf021fb
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/pim/PIMHelloOption.java
@@ -0,0 +1,147 @@
+/*
+ * 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 java.nio.ByteBuffer;
+import java.text.MessageFormat;
+
+import static org.onlab.packet.PacketUtils.checkBufferLength;
+import static org.onlab.packet.PacketUtils.checkInput;
+
+public class PIMHelloOption {
+
+ /**
+ * PIM Option types.
+ */
+ public static final short OPT_HOLDTIME = 1;
+ public static final short OPT_PRUNEDELAY = 2;
+ public static final short OPT_PRIORITY = 19;
+ public static final short OPT_GENID = 20;
+ public static final short OPT_ADDRLIST = 24;
+
+ public static final short DEFAULT_HOLDTIME = 105;
+ public static final int DEFAULT_PRUNEDELAY = 2000; // 2,000 ms
+ public static final int DEFAULT_PRIORITY = 1;
+ public static final int DEFAULT_GENID = 0;
+
+ public static final int MINIMUM_OPTION_LEN_BYTES = 4;
+
+ // Values for this particular hello option.
+ private short optType;
+ private short optLength;
+ private byte[] optValue;
+
+ public PIMHelloOption() {
+ }
+
+ /**
+ * Set a PIM Hello option by type. The length and default value of the
+ * type will be auto filled in by default.
+ *
+ * @param type hello option type
+ */
+ public PIMHelloOption(short type) {
+ this.optType = type;
+ switch (type) {
+ case OPT_HOLDTIME:
+ this.optLength = 2;
+ this.optValue = new byte[optLength];
+ ByteBuffer.wrap(this.optValue).putShort(PIMHelloOption.DEFAULT_HOLDTIME);
+ break;
+
+ case OPT_PRUNEDELAY:
+ this.optLength = 4;
+ this.optValue = new byte[this.optLength];
+ ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_PRUNEDELAY);
+ break;
+
+ case OPT_PRIORITY:
+ this.optLength = 4;
+ this.optValue = new byte[this.optLength];
+ ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_PRIORITY);
+ break;
+
+ case OPT_GENID:
+ this.optLength = 4;
+ this.optValue = new byte[this.optLength];
+ ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_GENID);
+ break;
+
+ case OPT_ADDRLIST:
+ this.optLength = 0; // We don't know what the length will be yet.
+ this.optValue = null;
+
+ default:
+ //log.error("Unkown option type: " + type + "\n" );
+ return;
+ }
+ }
+
+ public void setOptType(short type) {
+ this.optType = type;
+ }
+
+ public short getOptType() {
+ return this.optType;
+ }
+
+ public void setOptLength(short len) {
+ this.optLength = len;
+ }
+
+ public short getOptLength() {
+ return this.optLength;
+ }
+
+ public void setValue(ByteBuffer bb) throws DeserializationException {
+ this.optValue = new byte[this.optLength];
+ bb.get(this.optValue, 0, this.optLength);
+ }
+
+ public byte[] getValue() {
+ return this.optValue;
+ }
+
+ public static PIMHelloOption deserialize(ByteBuffer bb) throws DeserializationException {
+ checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), 4);
+
+ PIMHelloOption opt = new PIMHelloOption();
+ opt.setOptType(bb.getShort());
+ opt.setOptLength(bb.getShort());
+
+ checkBufferLength(bb.limit(), bb.position(), opt.getOptLength());
+ opt.setValue(bb);
+
+ return opt;
+ }
+
+ public byte [] serialize() {
+ int len = 4 + this.optLength;
+ ByteBuffer bb = ByteBuffer.allocate(len);
+ bb.putShort(this.optType);
+ bb.putShort(this.optLength);
+ bb.put(this.optValue);
+ return bb.array();
+ }
+
+ public String toString() {
+ return MessageFormat.format("Type: {0}, len: {1} value: {2}", this.optType, this.optLength,
+ (this.optValue == null) ? "null" : this.optValue.toString());
+ }
+
+}