Rusty Eddy
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
...@@ -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();
......