Committed by
Gerrit Code Review
Improvided PIM Hello option handling by creating the
PIMHelloOption class. Also fixed a typo for pim regsiter stop message type. Change-Id: Iff06ce7d2746ebc34811205f4c4a4d4784e2740c
Showing
4 changed files
with
213 additions
and
107 deletions
| ... | @@ -33,7 +33,7 @@ public class PIM extends BasePacket { | ... | @@ -33,7 +33,7 @@ public class PIM extends BasePacket { |
| 33 | 33 | ||
| 34 | public static final byte TYPE_HELLO = 0x00; | 34 | public static final byte TYPE_HELLO = 0x00; |
| 35 | public static final byte TYPE_REGISTER = 0x01; | 35 | public static final byte TYPE_REGISTER = 0x01; |
| 36 | - public static final byte TYPE_REQUEST_STOP = 0x02; | 36 | + public static final byte TYPE_REGISTER_STOP = 0x02; |
| 37 | public static final byte TYPE_JOIN_PRUNE_REQUEST = 0x03; | 37 | public static final byte TYPE_JOIN_PRUNE_REQUEST = 0x03; |
| 38 | public static final byte TYPE_BOOTSTRAP = 0x04; | 38 | public static final byte TYPE_BOOTSTRAP = 0x04; |
| 39 | public static final byte TYPE_ASSERT = 0x05; | 39 | public static final byte TYPE_ASSERT = 0x05; | ... | ... |
| ... | @@ -19,88 +19,41 @@ import org.onlab.packet.BasePacket; | ... | @@ -19,88 +19,41 @@ import org.onlab.packet.BasePacket; |
| 19 | import org.onlab.packet.Deserializer; | 19 | import org.onlab.packet.Deserializer; |
| 20 | import org.onlab.packet.IPacket; | 20 | import org.onlab.packet.IPacket; |
| 21 | import org.onlab.packet.IpAddress; | 21 | import org.onlab.packet.IpAddress; |
| 22 | - | ||
| 23 | import java.nio.ByteBuffer; | 22 | import java.nio.ByteBuffer; |
| 24 | -import java.util.Random; | 23 | +import java.util.HashMap; |
| 24 | +import java.util.Map; | ||
| 25 | 25 | ||
| 26 | import static org.onlab.packet.PacketUtils.checkInput; | 26 | import static org.onlab.packet.PacketUtils.checkInput; |
| 27 | 27 | ||
| 28 | public class PIMHello extends BasePacket { | 28 | public class PIMHello extends BasePacket { |
| 29 | 29 | ||
| 30 | private IpAddress nbrIpAddress; | 30 | private IpAddress nbrIpAddress; |
| 31 | - | ||
| 32 | - private int holdtime = 105; | ||
| 33 | - private int genid = 0; | ||
| 34 | - private int priority = 1; | ||
| 35 | private boolean priorityPresent = false; | 31 | private boolean priorityPresent = false; |
| 36 | 32 | ||
| 37 | - public static final int MINIMUM_OPTION_LEN_BYTES = 4; | 33 | + private Map<Short, PIMHelloOption> options = new HashMap<>(); |
| 38 | - | ||
| 39 | - /** | ||
| 40 | - * PIM Option types. | ||
| 41 | - */ | ||
| 42 | - public enum Option { | ||
| 43 | - HOLDTIME (1, 2), | ||
| 44 | - PRUNEDELAY(2, 4), | ||
| 45 | - PRIORITY (19, 4), | ||
| 46 | - GENID (20, 4), | ||
| 47 | - ADDRLIST (24, 0); | ||
| 48 | - | ||
| 49 | - private final int optType; | ||
| 50 | - private final int optLen; | ||
| 51 | - | ||
| 52 | - Option(int ot, int ol) { | ||
| 53 | - this.optType = ot; | ||
| 54 | - this.optLen = ol; | ||
| 55 | - } | ||
| 56 | - | ||
| 57 | - public int optType() { | ||
| 58 | - return this.optType; | ||
| 59 | - } | ||
| 60 | - | ||
| 61 | - public int optLen() { | ||
| 62 | - return this.optLen; | ||
| 63 | - } | ||
| 64 | - } | ||
| 65 | - | ||
| 66 | - /** | ||
| 67 | - * Add the holdtime to the packet. | ||
| 68 | - * | ||
| 69 | - * @param holdtime the holdtime in seconds | ||
| 70 | - */ | ||
| 71 | - public void addHoldtime(int holdtime) { | ||
| 72 | - this.holdtime = holdtime; | ||
| 73 | - } | ||
| 74 | 34 | ||
| 75 | /** | 35 | /** |
| 76 | - * Add the hello priority. | 36 | + * Create a PIM Hello packet with the most common hello options and default |
| 77 | - * | 37 | + * values. The values of any options can be easily changed by modifying the value of |
| 78 | - * @param priority default is 1, the higher the better | 38 | + * the option with the desired change. |
| 79 | */ | 39 | */ |
| 80 | - public void addPriority(int priority) { | 40 | + public void createDefaultOptions() { |
| 81 | - this.priority = priority; | 41 | + options.put(PIMHelloOption.OPT_HOLDTIME, new PIMHelloOption(PIMHelloOption.OPT_HOLDTIME)); |
| 82 | - this.priorityPresent = true; | 42 | + options.put(PIMHelloOption.OPT_PRIORITY, new PIMHelloOption(PIMHelloOption.OPT_PRIORITY)); |
| 43 | + options.put(PIMHelloOption.OPT_GENID, new PIMHelloOption(PIMHelloOption.OPT_GENID)); | ||
| 83 | } | 44 | } |
| 84 | 45 | ||
| 85 | /** | 46 | /** |
| 86 | - * Add a Gen ID. | 47 | + * Add a PIM Hello option to this hello message. Note |
| 87 | * | 48 | * |
| 88 | - * @param genid a random generated number, changes only after reset. | 49 | + * @param opt the PIM Hello option we are adding |
| 89 | */ | 50 | */ |
| 90 | - public void addGenId(int genid) { | 51 | + public void addOption(PIMHelloOption opt) { |
| 91 | - if (genid == 0) { | 52 | + this.options.put(opt.getOptType(), opt); |
| 92 | - this.addGenId(); | ||
| 93 | - } else { | ||
| 94 | - this.genid = genid; | ||
| 95 | - } | ||
| 96 | } | 53 | } |
| 97 | 54 | ||
| 98 | - /** | 55 | + public Map<Short, PIMHelloOption> getOptions() { |
| 99 | - * Add the genid. Let this function figure out the number. | 56 | + return this.options; |
| 100 | - */ | ||
| 101 | - public void addGenId() { | ||
| 102 | - Random rand = new Random(); | ||
| 103 | - this.genid = rand.nextInt(); | ||
| 104 | } | 57 | } |
| 105 | 58 | ||
| 106 | /** | 59 | /** |
| ... | @@ -111,68 +64,54 @@ public class PIMHello extends BasePacket { | ... | @@ -111,68 +64,54 @@ public class PIMHello extends BasePacket { |
| 111 | */ | 64 | */ |
| 112 | @Override | 65 | @Override |
| 113 | public byte[] serialize() { | 66 | public byte[] serialize() { |
| 67 | + int totalLen = 0; | ||
| 114 | 68 | ||
| 115 | - // TODO: Figure out a better way to calculate buffer size | ||
| 116 | - int size = Option.PRIORITY.optLen() + 4 + | ||
| 117 | - Option.GENID.optLen() + 4 + | ||
| 118 | - Option.HOLDTIME.optLen() + 4; | ||
| 119 | 69 | ||
| 120 | - byte[] data = new byte[size]; // Come up with something better | 70 | + // Since we are likely to only have 3-4 options, go head and walk the |
| 121 | - ByteBuffer bb = ByteBuffer.wrap(data); | 71 | + // hashmap twice, once to calculate the space needed to allocate a |
| 122 | - | 72 | + // buffer, the second time serialize the options into the buffer. This |
| 123 | - // Add the priority | 73 | + // saves us from allocating an over sized buffer the re-allocating and |
| 124 | - bb.putShort((short) Option.PRIORITY.optType); | 74 | + // copying. |
| 125 | - bb.putShort((short) Option.PRIORITY.optLen); | 75 | + for (Short optType : options.keySet()) { |
| 126 | - bb.putInt(this.priority); | 76 | + PIMHelloOption opt = options.get(optType); |
| 77 | + totalLen += PIMHelloOption.MINIMUM_OPTION_LEN_BYTES + opt.getOptLength(); | ||
| 78 | + } | ||
| 127 | 79 | ||
| 128 | - // Add the genid | 80 | + byte[] data = new byte[totalLen]; |
| 129 | - bb.putShort((short) Option.GENID.optType); | 81 | + ByteBuffer bb = ByteBuffer.wrap(data); |
| 130 | - bb.putShort((short) Option.GENID.optLen); | ||
| 131 | - bb.putInt(this.genid); | ||
| 132 | 82 | ||
| 133 | - // Add the holdtime | 83 | + // Now serialize the data. |
| 134 | - bb.putShort((short) Option.HOLDTIME.optType); | 84 | + for (Short optType : options.keySet()) { |
| 135 | - bb.putShort((short) Option.HOLDTIME.optLen); | 85 | + PIMHelloOption opt = options.get(optType); |
| 136 | - bb.putShort((short) this.holdtime); | 86 | + bb.put(opt.serialize()); |
| 87 | + } | ||
| 137 | return data; | 88 | return data; |
| 138 | } | 89 | } |
| 139 | 90 | ||
| 140 | /** | 91 | /** |
| 141 | * XXX: This is deprecated, DO NOT USE, use the deserializer() function instead. | 92 | * XXX: This is deprecated, DO NOT USE, use the deserializer() function instead. |
| 142 | */ | 93 | */ |
| 143 | - // @Override | ||
| 144 | public IPacket deserialize(final byte[] data, final int offset, | 94 | public IPacket deserialize(final byte[] data, final int offset, |
| 145 | final int length) { | 95 | final int length) { |
| 146 | - // | 96 | + // TODO: throw an expection? |
| 147 | return null; | 97 | return null; |
| 148 | } | 98 | } |
| 149 | 99 | ||
| 150 | /** | 100 | /** |
| 151 | * Deserialize this hello message. | 101 | * Deserialize this hello message. |
| 152 | * | 102 | * |
| 153 | - * @return a deserialized hello message. | 103 | + * @return a deserialized hello message |
| 154 | */ | 104 | */ |
| 155 | public static Deserializer<PIMHello> deserializer() { | 105 | public static Deserializer<PIMHello> deserializer() { |
| 156 | return (data, offset, length) -> { | 106 | return (data, offset, length) -> { |
| 157 | - checkInput(data, offset, length, MINIMUM_OPTION_LEN_BYTES); | 107 | + checkInput(data, offset, length, PIMHelloOption.MINIMUM_OPTION_LEN_BYTES); |
| 158 | final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | 108 | final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); |
| 159 | 109 | ||
| 160 | PIMHello hello = new PIMHello(); | 110 | PIMHello hello = new PIMHello(); |
| 161 | while (bb.hasRemaining()) { | 111 | while (bb.hasRemaining()) { |
| 162 | - int optType = bb.getShort(); | 112 | + PIMHelloOption opt = PIMHelloOption.deserialize(bb); |
| 163 | - int optLen = bb.getShort(); | 113 | + hello.addOption(opt); |
| 164 | - | ||
| 165 | - // Check that we have enough buffer for the next option. | ||
| 166 | - checkInput(data, bb.position(), bb.limit() - bb.position(), optLen); | ||
| 167 | - if (optType == Option.GENID.optType) { | ||
| 168 | - hello.addGenId(bb.getInt()); | ||
| 169 | - } else if (optType == Option.PRIORITY.optType) { | ||
| 170 | - hello.addPriority(bb.getInt()); | ||
| 171 | - } else if (optType == Option.HOLDTIME.optType) { | ||
| 172 | - hello.addHoldtime((int) bb.getShort()); | ||
| 173 | - } | ||
| 174 | } | 114 | } |
| 175 | - | ||
| 176 | return hello; | 115 | return hello; |
| 177 | }; | 116 | }; |
| 178 | } | 117 | } | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onlab.packet.pim; | ||
| 17 | + | ||
| 18 | +import org.onlab.packet.DeserializationException; | ||
| 19 | + | ||
| 20 | +import java.nio.ByteBuffer; | ||
| 21 | +import java.text.MessageFormat; | ||
| 22 | + | ||
| 23 | +import static org.onlab.packet.PacketUtils.checkBufferLength; | ||
| 24 | +import static org.onlab.packet.PacketUtils.checkInput; | ||
| 25 | + | ||
| 26 | +public class PIMHelloOption { | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * PIM Option types. | ||
| 30 | + */ | ||
| 31 | + public static final short OPT_HOLDTIME = 1; | ||
| 32 | + public static final short OPT_PRUNEDELAY = 2; | ||
| 33 | + public static final short OPT_PRIORITY = 19; | ||
| 34 | + public static final short OPT_GENID = 20; | ||
| 35 | + public static final short OPT_ADDRLIST = 24; | ||
| 36 | + | ||
| 37 | + public static final short DEFAULT_HOLDTIME = 105; | ||
| 38 | + public static final int DEFAULT_PRUNEDELAY = 2000; // 2,000 ms | ||
| 39 | + public static final int DEFAULT_PRIORITY = 1; | ||
| 40 | + public static final int DEFAULT_GENID = 0; | ||
| 41 | + | ||
| 42 | + public static final int MINIMUM_OPTION_LEN_BYTES = 4; | ||
| 43 | + | ||
| 44 | + // Values for this particular hello option. | ||
| 45 | + private short optType; | ||
| 46 | + private short optLength; | ||
| 47 | + private byte[] optValue; | ||
| 48 | + | ||
| 49 | + public PIMHelloOption() { | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * Set a PIM Hello option by type. The length and default value of the | ||
| 54 | + * type will be auto filled in by default. | ||
| 55 | + * | ||
| 56 | + * @param type hello option type | ||
| 57 | + */ | ||
| 58 | + public PIMHelloOption(short type) { | ||
| 59 | + this.optType = type; | ||
| 60 | + switch (type) { | ||
| 61 | + case OPT_HOLDTIME: | ||
| 62 | + this.optLength = 2; | ||
| 63 | + this.optValue = new byte[optLength]; | ||
| 64 | + ByteBuffer.wrap(this.optValue).putShort(PIMHelloOption.DEFAULT_HOLDTIME); | ||
| 65 | + break; | ||
| 66 | + | ||
| 67 | + case OPT_PRUNEDELAY: | ||
| 68 | + this.optLength = 4; | ||
| 69 | + this.optValue = new byte[this.optLength]; | ||
| 70 | + ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_PRUNEDELAY); | ||
| 71 | + break; | ||
| 72 | + | ||
| 73 | + case OPT_PRIORITY: | ||
| 74 | + this.optLength = 4; | ||
| 75 | + this.optValue = new byte[this.optLength]; | ||
| 76 | + ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_PRIORITY); | ||
| 77 | + break; | ||
| 78 | + | ||
| 79 | + case OPT_GENID: | ||
| 80 | + this.optLength = 4; | ||
| 81 | + this.optValue = new byte[this.optLength]; | ||
| 82 | + ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_GENID); | ||
| 83 | + break; | ||
| 84 | + | ||
| 85 | + case OPT_ADDRLIST: | ||
| 86 | + this.optLength = 0; // We don't know what the length will be yet. | ||
| 87 | + this.optValue = null; | ||
| 88 | + | ||
| 89 | + default: | ||
| 90 | + //log.error("Unkown option type: " + type + "\n" ); | ||
| 91 | + return; | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + public void setOptType(short type) { | ||
| 96 | + this.optType = type; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + public short getOptType() { | ||
| 100 | + return this.optType; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + public void setOptLength(short len) { | ||
| 104 | + this.optLength = len; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + public short getOptLength() { | ||
| 108 | + return this.optLength; | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + public void setValue(ByteBuffer bb) throws DeserializationException { | ||
| 112 | + this.optValue = new byte[this.optLength]; | ||
| 113 | + bb.get(this.optValue, 0, this.optLength); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + public byte[] getValue() { | ||
| 117 | + return this.optValue; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + public static PIMHelloOption deserialize(ByteBuffer bb) throws DeserializationException { | ||
| 121 | + checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), 4); | ||
| 122 | + | ||
| 123 | + PIMHelloOption opt = new PIMHelloOption(); | ||
| 124 | + opt.setOptType(bb.getShort()); | ||
| 125 | + opt.setOptLength(bb.getShort()); | ||
| 126 | + | ||
| 127 | + checkBufferLength(bb.limit(), bb.position(), opt.getOptLength()); | ||
| 128 | + opt.setValue(bb); | ||
| 129 | + | ||
| 130 | + return opt; | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + public byte [] serialize() { | ||
| 134 | + int len = 4 + this.optLength; | ||
| 135 | + ByteBuffer bb = ByteBuffer.allocate(len); | ||
| 136 | + bb.putShort(this.optType); | ||
| 137 | + bb.putShort(this.optLength); | ||
| 138 | + bb.put(this.optValue); | ||
| 139 | + return bb.array(); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + public String toString() { | ||
| 143 | + return MessageFormat.format("Type: {0}, len: {1} value: {2}", this.optType, this.optLength, | ||
| 144 | + (this.optValue == null) ? "null" : this.optValue.toString()); | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | +} |
| ... | @@ -46,6 +46,11 @@ public final class PIMTest { | ... | @@ -46,6 +46,11 @@ public final class PIMTest { |
| 46 | private PIM pimJoinPrune; | 46 | private PIM pimJoinPrune; |
| 47 | private PIMJoinPrune joinPrune; | 47 | private PIMJoinPrune joinPrune; |
| 48 | 48 | ||
| 49 | + /** | ||
| 50 | + * Create PIM Hello and Join/Prune packets to be used in testing. | ||
| 51 | + * | ||
| 52 | + * @throws Exception if packet creation fails | ||
| 53 | + */ | ||
| 49 | @Before | 54 | @Before |
| 50 | public void setUp() throws Exception { | 55 | public void setUp() throws Exception { |
| 51 | 56 | ||
| ... | @@ -56,9 +61,7 @@ public final class PIMTest { | ... | @@ -56,9 +61,7 @@ public final class PIMTest { |
| 56 | pimHello.setChecksum((short) 0); | 61 | pimHello.setChecksum((short) 0); |
| 57 | 62 | ||
| 58 | hello = new PIMHello(); | 63 | hello = new PIMHello(); |
| 59 | - hello.addHoldtime(0xd2); | 64 | + hello.createDefaultOptions(); |
| 60 | - hello.addPriority(44); | ||
| 61 | - hello.addGenId(0xf00d); | ||
| 62 | pimHello.setPayload(hello); | 65 | pimHello.setPayload(hello); |
| 63 | hello.setParent(pimHello); | 66 | hello.setParent(pimHello); |
| 64 | 67 | ||
| ... | @@ -81,20 +84,32 @@ public final class PIMTest { | ... | @@ -81,20 +84,32 @@ public final class PIMTest { |
| 81 | deserializer = PIM.deserializer(); | 84 | deserializer = PIM.deserializer(); |
| 82 | } | 85 | } |
| 83 | 86 | ||
| 87 | + /** | ||
| 88 | + * Make sure our deserializer throws an exception if we recieve bad input. | ||
| 89 | + * | ||
| 90 | + * @throws Exception if we are given bad input. | ||
| 91 | + */ | ||
| 84 | @Test | 92 | @Test |
| 85 | - public void testDerserializeBadInput() throws Exception { | 93 | + public void testDeserializeBadInput() throws Exception { |
| 86 | PacketTestUtils.testDeserializeBadInput(deserializer); | 94 | PacketTestUtils.testDeserializeBadInput(deserializer); |
| 87 | } | 95 | } |
| 88 | 96 | ||
| 97 | + /** | ||
| 98 | + * Verify we throw an exception if we receive a truncated Join/Prune message. | ||
| 99 | + * | ||
| 100 | + * @throws Exception if we receive a truncated Join/Prune message. | ||
| 101 | + */ | ||
| 89 | @Test | 102 | @Test |
| 90 | public void testDeserializeTruncated() throws Exception { | 103 | public void testDeserializeTruncated() throws Exception { |
| 91 | - //byte [] bits = pimHello.serialize(); | ||
| 92 | - //PacketTestUtils.testDeserializeTruncated(deserializer, bits); | ||
| 93 | - | ||
| 94 | byte [] bits = pimJoinPrune.serialize(); | 104 | byte [] bits = pimJoinPrune.serialize(); |
| 95 | PacketTestUtils.testDeserializeTruncated(deserializer, bits); | 105 | PacketTestUtils.testDeserializeTruncated(deserializer, bits); |
| 96 | } | 106 | } |
| 97 | 107 | ||
| 108 | + /** | ||
| 109 | + * Verify that we correctly deserialize hello messages. | ||
| 110 | + * | ||
| 111 | + * @throws Exception if our input is bad or truncated. | ||
| 112 | + */ | ||
| 98 | @Test | 113 | @Test |
| 99 | public void testDeserializeHello() throws Exception { | 114 | public void testDeserializeHello() throws Exception { |
| 100 | byte [] data = pimHello.serialize(); | 115 | byte [] data = pimHello.serialize(); |
| ... | @@ -102,6 +117,11 @@ public final class PIMTest { | ... | @@ -102,6 +117,11 @@ public final class PIMTest { |
| 102 | assertTrue(pim.equals(pimHello)); | 117 | assertTrue(pim.equals(pimHello)); |
| 103 | } | 118 | } |
| 104 | 119 | ||
| 120 | + /** | ||
| 121 | + * Verify that we correctly deserialize Join/Prune messages. | ||
| 122 | + * | ||
| 123 | + * @throws Exception if our input is bad or truncated. | ||
| 124 | + */ | ||
| 105 | @Test | 125 | @Test |
| 106 | public void testDeserializeJoinPrune() throws Exception { | 126 | public void testDeserializeJoinPrune() throws Exception { |
| 107 | byte [] data = pimJoinPrune.serialize(); | 127 | byte [] data = pimJoinPrune.serialize(); | ... | ... |
-
Please register or login to post a comment