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