Committed by
Gerrit Code Review
Added packet handling functions for PIM, Specifically
PIM Hello and PIM Join/Prune messages along with respective PIM encoded address types Change-Id: Iaef2e3581e27fa910ad355043bcb3e175238706a
Showing
9 changed files
with
1600 additions
and
0 deletions
... | @@ -35,6 +35,7 @@ public class IPv4 extends BasePacket { | ... | @@ -35,6 +35,7 @@ public class IPv4 extends BasePacket { |
35 | public static final byte PROTOCOL_IGMP = 0x2; | 35 | public static final byte PROTOCOL_IGMP = 0x2; |
36 | public static final byte PROTOCOL_TCP = 0x6; | 36 | public static final byte PROTOCOL_TCP = 0x6; |
37 | public static final byte PROTOCOL_UDP = 0x11; | 37 | public static final byte PROTOCOL_UDP = 0x11; |
38 | + public static final byte PROTOCOL_PIM = 0x67; | ||
38 | public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP = | 39 | public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP = |
39 | new HashMap<>(); | 40 | new HashMap<>(); |
40 | 41 | ||
... | @@ -43,6 +44,7 @@ public class IPv4 extends BasePacket { | ... | @@ -43,6 +44,7 @@ public class IPv4 extends BasePacket { |
43 | IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_IGMP, IGMP.deserializer()); | 44 | IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_IGMP, IGMP.deserializer()); |
44 | IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_TCP, TCP.deserializer()); | 45 | IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_TCP, TCP.deserializer()); |
45 | IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_UDP, UDP.deserializer()); | 46 | IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_UDP, UDP.deserializer()); |
47 | + IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_PIM, PIM.deserializer()); | ||
46 | } | 48 | } |
47 | 49 | ||
48 | private static final byte DSCP_MASK = 0x3f; | 50 | private static final byte DSCP_MASK = 0x3f; | ... | ... |
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; | ||
17 | + | ||
18 | +import org.onlab.packet.pim.PIMHello; | ||
19 | +import org.onlab.packet.pim.PIMJoinPrune; | ||
20 | + | ||
21 | +import java.nio.ByteBuffer; | ||
22 | +import java.util.HashMap; | ||
23 | +import java.util.Map; | ||
24 | + | ||
25 | +import static org.onlab.packet.PacketUtils.checkInput; | ||
26 | + | ||
27 | +/** | ||
28 | + * Implements PIM control packet format. | ||
29 | + */ | ||
30 | +public class PIM extends BasePacket { | ||
31 | + | ||
32 | + public static final IpAddress PIM_ADDRESS = IpAddress.valueOf("224.0.0.13"); | ||
33 | + | ||
34 | + public static final byte TYPE_HELLO = 0x00; | ||
35 | + public static final byte TYPE_REGISTER = 0x01; | ||
36 | + public static final byte TYPE_REQUEST_STOP = 0x02; | ||
37 | + public static final byte TYPE_JOIN_PRUNE_REQUEST = 0x03; | ||
38 | + public static final byte TYPE_BOOTSTRAP = 0x04; | ||
39 | + public static final byte TYPE_ASSERT = 0x05; | ||
40 | + public static final byte TYPE_GRAFT = 0x06; | ||
41 | + public static final byte TYPE_GRAFT_ACK = 0x07; | ||
42 | + public static final byte TYPE_CANDIDATE_RP_ADV = 0x08; | ||
43 | + | ||
44 | + public static final int PIM_HEADER_LEN = 4; | ||
45 | + | ||
46 | + public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP = | ||
47 | + new HashMap<>(); | ||
48 | + | ||
49 | + static { | ||
50 | + PIM.PROTOCOL_DESERIALIZER_MAP.put(PIM.TYPE_HELLO, PIMHello.deserializer()); | ||
51 | + PIM.PROTOCOL_DESERIALIZER_MAP.put(PIM.TYPE_JOIN_PRUNE_REQUEST, PIMJoinPrune.deserializer()); | ||
52 | + } | ||
53 | + | ||
54 | + /* | ||
55 | + * PIM Header fields | ||
56 | + */ | ||
57 | + protected byte version; | ||
58 | + protected byte type; | ||
59 | + protected byte reserved; | ||
60 | + protected short checksum; | ||
61 | + | ||
62 | + /** | ||
63 | + * Default constructor. | ||
64 | + */ | ||
65 | + public PIM() { | ||
66 | + super(); | ||
67 | + this.version = 2; | ||
68 | + this.reserved = 0; | ||
69 | + } | ||
70 | + | ||
71 | + /** | ||
72 | + * Return the PIM message type. | ||
73 | + * | ||
74 | + * @return the pimMsgType | ||
75 | + */ | ||
76 | + public byte getPimMsgType() { | ||
77 | + return this.type; | ||
78 | + } | ||
79 | + | ||
80 | + /** | ||
81 | + * Set the PIM message type. Currently PIMJoinPrune and PIMHello are | ||
82 | + * supported. | ||
83 | + * | ||
84 | + * @param type PIM message type | ||
85 | + * @return PIM Header | ||
86 | + */ | ||
87 | + public PIM setPIMType(final byte type) { | ||
88 | + this.type = type; | ||
89 | + return this; | ||
90 | + } | ||
91 | + | ||
92 | + /** | ||
93 | + * Get the version of PIM. | ||
94 | + * | ||
95 | + * @return the PIM version. Must be 2. | ||
96 | + */ | ||
97 | + public byte getVersion() { | ||
98 | + return version; | ||
99 | + } | ||
100 | + | ||
101 | + /** | ||
102 | + * Set the PIM version type. Should not change from 2. | ||
103 | + * | ||
104 | + * @param version | ||
105 | + */ | ||
106 | + public void setVersion(byte version) { | ||
107 | + this.version = version; | ||
108 | + } | ||
109 | + | ||
110 | + /** | ||
111 | + * Get the reserved field. | ||
112 | + * | ||
113 | + * @return the reserved field. Must be ignored. | ||
114 | + */ | ||
115 | + public byte getReserved() { | ||
116 | + return reserved; | ||
117 | + } | ||
118 | + | ||
119 | + /** | ||
120 | + * Set the reserved field. | ||
121 | + * | ||
122 | + * @param reserved should be 0 | ||
123 | + */ | ||
124 | + public void setReserved(byte reserved) { | ||
125 | + this.reserved = reserved; | ||
126 | + } | ||
127 | + | ||
128 | + /** | ||
129 | + * Get the checksum of this packet. | ||
130 | + * | ||
131 | + * @return the checksum | ||
132 | + */ | ||
133 | + public short getChecksum() { | ||
134 | + return checksum; | ||
135 | + } | ||
136 | + | ||
137 | + /** | ||
138 | + * Set the checksum. | ||
139 | + * | ||
140 | + * @param checksum the checksum | ||
141 | + */ | ||
142 | + public void setChecksum(short checksum) { | ||
143 | + this.checksum = checksum; | ||
144 | + } | ||
145 | + | ||
146 | + /* | ||
147 | + * (non-Javadoc) | ||
148 | + * | ||
149 | + * @see java.lang.Object#hashCode() | ||
150 | + */ | ||
151 | + @Override | ||
152 | + public int hashCode() { | ||
153 | + final int prime = 5807; | ||
154 | + int result = super.hashCode(); | ||
155 | + result = prime * result + this.type; | ||
156 | + result = prime * result + this.version; | ||
157 | + result = prime * result + this.checksum; | ||
158 | + return result; | ||
159 | + } | ||
160 | + | ||
161 | + /* | ||
162 | + * (non-Javadoc) | ||
163 | + * | ||
164 | + * @see java.lang.Object#equals(java.lang.Object) | ||
165 | + */ | ||
166 | + @Override | ||
167 | + public boolean equals(final Object obj) { | ||
168 | + if (this == obj) { | ||
169 | + return true; | ||
170 | + } | ||
171 | + if (!super.equals(obj)) { | ||
172 | + return false; | ||
173 | + } | ||
174 | + if (!(obj instanceof PIM)) { | ||
175 | + return false; | ||
176 | + } | ||
177 | + final PIM other = (PIM) obj; | ||
178 | + if (this.type != other.type) { | ||
179 | + return false; | ||
180 | + } | ||
181 | + if (this.version != other.version) { | ||
182 | + return false; | ||
183 | + } | ||
184 | + if (this.checksum != other.checksum) { | ||
185 | + return false; | ||
186 | + } | ||
187 | + return true; | ||
188 | + } | ||
189 | + | ||
190 | + /** | ||
191 | + * Serializes the packet. Will compute and set the following fields if they | ||
192 | + * are set to specific values at the time serialize is called: -checksum : 0 | ||
193 | + * -length : 0 | ||
194 | + * | ||
195 | + * @return will return the serialized packet | ||
196 | + */ | ||
197 | + @Override | ||
198 | + public byte[] serialize() { | ||
199 | + int length = 4; | ||
200 | + byte[] payloadData = null; | ||
201 | + if (this.payload != null) { | ||
202 | + this.payload.setParent(this); | ||
203 | + payloadData = this.payload.serialize(); | ||
204 | + length += payloadData.length; | ||
205 | + } | ||
206 | + | ||
207 | + final byte[] data = new byte[length]; | ||
208 | + final ByteBuffer bb = ByteBuffer.wrap(data); | ||
209 | + | ||
210 | + bb.put((byte) ((this.version & 0xf) << 4 | this.type & 0xf)); | ||
211 | + bb.put(this.reserved); | ||
212 | + bb.putShort(this.checksum); | ||
213 | + if (payloadData != null) { | ||
214 | + bb.put(payloadData); | ||
215 | + } | ||
216 | + | ||
217 | + if (this.parent != null && this.parent instanceof PIM) { | ||
218 | + ((PIM) this.parent).setPIMType(TYPE_JOIN_PRUNE_REQUEST); | ||
219 | + } | ||
220 | + | ||
221 | + // compute checksum if needed | ||
222 | + if (this.checksum == 0) { | ||
223 | + bb.rewind(); | ||
224 | + int accumulation = 0; | ||
225 | + | ||
226 | + for (int i = 0; i < length / 2; ++i) { | ||
227 | + accumulation += 0xffff & bb.getShort(); | ||
228 | + } | ||
229 | + // pad to an even number of shorts | ||
230 | + if (length % 2 > 0) { | ||
231 | + accumulation += (bb.get() & 0xff) << 8; | ||
232 | + } | ||
233 | + | ||
234 | + accumulation = (accumulation >> 16 & 0xffff) | ||
235 | + + (accumulation & 0xffff); | ||
236 | + this.checksum = (short) (~accumulation & 0xffff); | ||
237 | + bb.putShort(2, this.checksum); | ||
238 | + } | ||
239 | + return data; | ||
240 | + } | ||
241 | + | ||
242 | + /** | ||
243 | + * Deserialize the PIM packet. | ||
244 | + * | ||
245 | + * @param data bytes to deserialize. | ||
246 | + * @param offset offset to start deserializing from | ||
247 | + * @param length length of the data to deserialize | ||
248 | + * | ||
249 | + * @return the deserialized PIM packet. | ||
250 | + */ | ||
251 | + @Override | ||
252 | + public IPacket deserialize(final byte[] data, final int offset, | ||
253 | + final int length) { | ||
254 | + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | ||
255 | + this.type = bb.get(); | ||
256 | + this.version = bb.get(); | ||
257 | + this.checksum = bb.getShort(); | ||
258 | + | ||
259 | + //this.payload = new Data(); | ||
260 | + this.payload = this.payload.deserialize(data, bb.position(), bb.limit() - bb.position()); | ||
261 | + this.payload.setParent(this); | ||
262 | + return this; | ||
263 | + } | ||
264 | + /** | ||
265 | + * Deserializer function for IPv4 packets. | ||
266 | + * | ||
267 | + * @return deserializer function | ||
268 | + */ | ||
269 | + public static Deserializer<PIM> deserializer() { | ||
270 | + return (data, offset, length) -> { | ||
271 | + checkInput(data, offset, length, PIM_HEADER_LEN); | ||
272 | + | ||
273 | + PIM pim = new PIM(); | ||
274 | + | ||
275 | + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | ||
276 | + | ||
277 | + byte versionByte = bb.get(); | ||
278 | + pim.version = (byte) (versionByte >> 4 & 0xf); | ||
279 | + pim.setPIMType((byte) (versionByte & 0xf)); | ||
280 | + pim.reserved = bb.get(); | ||
281 | + pim.checksum = bb.getShort(); | ||
282 | + | ||
283 | + Deserializer<? extends IPacket> deserializer; | ||
284 | + if (PIM.PROTOCOL_DESERIALIZER_MAP.containsKey(pim.getPimMsgType())) { | ||
285 | + deserializer = PIM.PROTOCOL_DESERIALIZER_MAP.get(pim.getPimMsgType()); | ||
286 | + } else { | ||
287 | + deserializer = Data.deserializer(); | ||
288 | + } | ||
289 | + | ||
290 | + pim.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position()); | ||
291 | + pim.payload.setParent(pim); | ||
292 | + | ||
293 | + return pim; | ||
294 | + }; | ||
295 | + } | ||
296 | +} |
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 | +import org.onlab.packet.Ip4Address; | ||
20 | +import org.onlab.packet.IpAddress; | ||
21 | +import org.onlab.packet.IpPrefix; | ||
22 | +import org.onlab.packet.Ip6Address; | ||
23 | + | ||
24 | +import java.nio.ByteBuffer; | ||
25 | + | ||
26 | +import static org.onlab.packet.PacketUtils.checkInput; | ||
27 | + | ||
28 | +public class PIMAddrGroup { | ||
29 | + private byte family; | ||
30 | + private byte encType; | ||
31 | + private byte reserved; | ||
32 | + private boolean bBit; | ||
33 | + private boolean zBit; | ||
34 | + private byte masklen; | ||
35 | + IpAddress addr; | ||
36 | + | ||
37 | + public static final int ENC_GROUP_IPV4_BYTE_LENGTH = 4 + Ip4Address.BYTE_LENGTH; | ||
38 | + public static final int ENC_GROUP_IPV6_BYTE_LENGTH = 4 + Ip6Address.BYTE_LENGTH; | ||
39 | + | ||
40 | + /** | ||
41 | + * PIM Encoded Group Address. | ||
42 | + */ | ||
43 | + public PIMAddrGroup() { | ||
44 | + this.family = 4; | ||
45 | + this.encType = 0; | ||
46 | + this.reserved = 0; | ||
47 | + this.bBit = false; | ||
48 | + this.zBit = false; | ||
49 | + } | ||
50 | + | ||
51 | + /** | ||
52 | + * PIM Encoded Source Address. | ||
53 | + * | ||
54 | + * @param addr IPv4 or IPv6 | ||
55 | + */ | ||
56 | + public PIMAddrGroup(String addr) { | ||
57 | + this.setAddr(addr); | ||
58 | + } | ||
59 | + | ||
60 | + /** | ||
61 | + * PIM Encoded Group Address. | ||
62 | + * | ||
63 | + * @param gpfx PIM encoded group address. | ||
64 | + */ | ||
65 | + public PIMAddrGroup(IpPrefix gpfx) { | ||
66 | + this.setAddr(gpfx); | ||
67 | + } | ||
68 | + | ||
69 | + /** | ||
70 | + * PIM encoded source address. | ||
71 | + * | ||
72 | + * @param addr IPv4 or IPv6 | ||
73 | + */ | ||
74 | + public void setAddr(String addr) { | ||
75 | + setAddr(IpPrefix.valueOf(addr)); | ||
76 | + } | ||
77 | + | ||
78 | + /** | ||
79 | + * Set the encoded source address. | ||
80 | + * | ||
81 | + * @param pfx | ||
82 | + */ | ||
83 | + public void setAddr(IpPrefix pfx) { | ||
84 | + this.addr = pfx.address(); | ||
85 | + this.masklen = (byte) pfx.prefixLength(); | ||
86 | + this.family = (byte) ((this.addr.isIp4()) ? 4 : 6); | ||
87 | + } | ||
88 | + | ||
89 | + /** | ||
90 | + * Get the IP family of this address: 4 or 6. | ||
91 | + * | ||
92 | + * @return the IP address family | ||
93 | + */ | ||
94 | + public int getFamily() { | ||
95 | + return this.family; | ||
96 | + } | ||
97 | + | ||
98 | + /** | ||
99 | + * Get the address of this encoded address. | ||
100 | + * | ||
101 | + * @return source address | ||
102 | + */ | ||
103 | + public IpAddress getAddr() { | ||
104 | + return this.addr; | ||
105 | + } | ||
106 | + | ||
107 | + /** | ||
108 | + * Get the masklen of the group address. | ||
109 | + * | ||
110 | + * @return the masklen | ||
111 | + */ | ||
112 | + public int getMasklen() { | ||
113 | + return this.masklen; | ||
114 | + } | ||
115 | + | ||
116 | + /** | ||
117 | + * Return the z bit for admin scoping. Only used for the Bootstrap router. | ||
118 | + * | ||
119 | + * @return true or false | ||
120 | + */ | ||
121 | + public boolean getZBit() { | ||
122 | + return this.zBit; | ||
123 | + } | ||
124 | + | ||
125 | + /** | ||
126 | + * Return the bBit. Used to indicate this is a bidir | ||
127 | + * | ||
128 | + * @return return true or false. | ||
129 | + */ | ||
130 | + public boolean getBBit() { | ||
131 | + return this.bBit; | ||
132 | + } | ||
133 | + | ||
134 | + /** | ||
135 | + * The size in bytes of a serialized address. | ||
136 | + * | ||
137 | + * @return the number of bytes when serialized | ||
138 | + */ | ||
139 | + public int getByteSize() { | ||
140 | + int size = 4; | ||
141 | + size += addr.isIp4() ? 4 : 16; | ||
142 | + return size; | ||
143 | + } | ||
144 | + | ||
145 | + /** | ||
146 | + * Serialize this group address. | ||
147 | + * | ||
148 | + * @return the serialized address in a buffer. | ||
149 | + */ | ||
150 | + public byte[] serialize() { | ||
151 | + int len = getByteSize(); | ||
152 | + | ||
153 | + final byte[] data = new byte[len]; | ||
154 | + final ByteBuffer bb = ByteBuffer.wrap(data); | ||
155 | + | ||
156 | + bb.put(this.family); | ||
157 | + bb.put(this.encType); | ||
158 | + | ||
159 | + // Todo: technically we should be setting the B and Z bits, but we'll never use them. | ||
160 | + bb.put(reserved); | ||
161 | + | ||
162 | + bb.put(this.masklen); | ||
163 | + bb.put(this.addr.toOctets()); | ||
164 | + return data; | ||
165 | + } | ||
166 | + | ||
167 | + /** | ||
168 | + * Deserialze from a ByteBuffer. | ||
169 | + * | ||
170 | + * @param bb the ByteBuffer | ||
171 | + * @return an encoded PIM group address. | ||
172 | + */ | ||
173 | + public PIMAddrGroup deserialize(ByteBuffer bb) throws DeserializationException { | ||
174 | + | ||
175 | + /* | ||
176 | + * We need to verify that we have enough buffer space. First we'll assume that | ||
177 | + * we are decoding an IPv4 address. After we read the first by (address family), | ||
178 | + * we'll determine if we actually need more buffer space for an IPv6 address. | ||
179 | + */ | ||
180 | + checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_GROUP_IPV4_BYTE_LENGTH); | ||
181 | + | ||
182 | + this.family = bb.get(); | ||
183 | + if (family != 4 && family != 6) { | ||
184 | + throw new DeserializationException("Illegal IP version number: " + family + "\n"); | ||
185 | + } else if (family == 6) { | ||
186 | + | ||
187 | + // Check for one less by since we have already read the first byte of the packet. | ||
188 | + checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_GROUP_IPV6_BYTE_LENGTH - 1); | ||
189 | + } | ||
190 | + | ||
191 | + this.encType = bb.get(); | ||
192 | + this.reserved = bb.get(); | ||
193 | + if ((this.reserved & 0x80) != 0) { | ||
194 | + this.bBit = true; | ||
195 | + } | ||
196 | + if ((this.reserved & 0x01) != 0) { | ||
197 | + this.zBit = true; | ||
198 | + } | ||
199 | + // Remove the z and b bits from reserved | ||
200 | + this.reserved |= 0x7d; | ||
201 | + | ||
202 | + this.masklen = bb.get(); | ||
203 | + if (this.family == 4) { | ||
204 | + this.addr = IpAddress.valueOf(bb.getInt()); | ||
205 | + } else if (this.family == 6) { | ||
206 | + this.addr = Ip6Address.valueOf(bb.array(), 2); | ||
207 | + } | ||
208 | + return this; | ||
209 | + } | ||
210 | + | ||
211 | + /* | ||
212 | + * (non-Javadoc) | ||
213 | + * | ||
214 | + * @see java.lang.Object#hashCode() | ||
215 | + */ | ||
216 | + @Override | ||
217 | + public int hashCode() { | ||
218 | + final int prime = 2521; | ||
219 | + int result = super.hashCode(); | ||
220 | + result = prime * result + this.family; | ||
221 | + result = prime * result + this.encType; | ||
222 | + result = prime * result + this.reserved; | ||
223 | + result = prime * result + this.masklen; | ||
224 | + result = prime * result + this.addr.hashCode(); | ||
225 | + return result; | ||
226 | + } | ||
227 | + | ||
228 | + | ||
229 | + /* | ||
230 | + * (non-Javadoc) | ||
231 | + * | ||
232 | + * @see java.lang.Object#equals() | ||
233 | + */ | ||
234 | + @Override | ||
235 | + public boolean equals(final Object obj) { | ||
236 | + if (this == obj) { | ||
237 | + return true; | ||
238 | + } | ||
239 | + if (!(obj instanceof PIMAddrGroup)) { | ||
240 | + return false; | ||
241 | + } | ||
242 | + final PIMAddrGroup other = (PIMAddrGroup) obj; | ||
243 | + if (this.family != this.family) { | ||
244 | + return false; | ||
245 | + } | ||
246 | + | ||
247 | + if (this.encType != other.encType) { | ||
248 | + return false; | ||
249 | + } | ||
250 | + | ||
251 | + if (!this.addr.equals(other.addr)) { | ||
252 | + return false; | ||
253 | + } | ||
254 | + return true; | ||
255 | + } | ||
256 | +} |
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 | +import org.onlab.packet.Ip4Address; | ||
20 | +import org.onlab.packet.IpAddress; | ||
21 | +import org.onlab.packet.IpPrefix; | ||
22 | +import org.onlab.packet.Ip6Address; | ||
23 | + | ||
24 | +import java.nio.ByteBuffer; | ||
25 | + | ||
26 | +import static org.onlab.packet.PacketUtils.checkInput; | ||
27 | + | ||
28 | +public class PIMAddrSource { | ||
29 | + private byte family; | ||
30 | + private byte encType; | ||
31 | + private byte reserved; | ||
32 | + private boolean sBit; | ||
33 | + private boolean wBit; | ||
34 | + private boolean rBit; | ||
35 | + private byte masklen; | ||
36 | + IpAddress addr; | ||
37 | + | ||
38 | + public static final int ENC_SOURCE_IPV4_BYTE_LENGTH = 4 + Ip4Address.BYTE_LENGTH; | ||
39 | + public static final int ENC_SOURCE_IPV6_BYTE_LENGTH = 4 + Ip6Address.BYTE_LENGTH; | ||
40 | + | ||
41 | + /** | ||
42 | + * PIM Encoded Source Address. | ||
43 | + * | ||
44 | + * @param addr IPv4 or IPv6 | ||
45 | + */ | ||
46 | + public PIMAddrSource(String addr) { | ||
47 | + this.init(); | ||
48 | + this.setAddr(addr); | ||
49 | + } | ||
50 | + | ||
51 | + /** | ||
52 | + * PIM Encoded Source Address. | ||
53 | + * | ||
54 | + * @param spfx IPv4 or IPv6 | ||
55 | + */ | ||
56 | + public PIMAddrSource(IpPrefix spfx) { | ||
57 | + this.init(); | ||
58 | + this.setAddr(spfx); | ||
59 | + } | ||
60 | + | ||
61 | + /** | ||
62 | + * PIM Encoded Group Address. | ||
63 | + */ | ||
64 | + public PIMAddrSource() { | ||
65 | + this.init(); | ||
66 | + } | ||
67 | + | ||
68 | + private void init() { | ||
69 | + this.family = 4; | ||
70 | + this.encType = 0; | ||
71 | + this.reserved = 0; | ||
72 | + this.sBit = true; | ||
73 | + this.wBit = false; | ||
74 | + this.rBit = false; | ||
75 | + } | ||
76 | + | ||
77 | + /** | ||
78 | + * PIM Encoded Source Address. | ||
79 | + * | ||
80 | + * @param addr IPv4 or IPv6 | ||
81 | + */ | ||
82 | + public void setAddr(String addr) { | ||
83 | + IpPrefix spfx = IpPrefix.valueOf(addr); | ||
84 | + setAddr(spfx); | ||
85 | + } | ||
86 | + | ||
87 | + /** | ||
88 | + * PIM Encoded Source Address. | ||
89 | + * | ||
90 | + * @param spfx IPv4 or IPv6 address prefix | ||
91 | + */ | ||
92 | + public void setAddr(IpPrefix spfx) { | ||
93 | + this.addr = spfx.address(); | ||
94 | + this.masklen = (byte) spfx.prefixLength(); | ||
95 | + this.family = (byte) ((this.addr.isIp4()) ? 4 : 6); | ||
96 | + } | ||
97 | + | ||
98 | + /** | ||
99 | + * Get the IP family of this address: 4 or 6. | ||
100 | + * | ||
101 | + * @return the IP address family | ||
102 | + */ | ||
103 | + public byte getFamily() { | ||
104 | + return this.family; | ||
105 | + } | ||
106 | + | ||
107 | + /** | ||
108 | + * Get the address of this encoded address. | ||
109 | + * | ||
110 | + * @return source address | ||
111 | + */ | ||
112 | + public IpAddress getAddr() { | ||
113 | + return this.addr; | ||
114 | + } | ||
115 | + | ||
116 | + /** | ||
117 | + * Get the masklen of the group address. | ||
118 | + * | ||
119 | + * @return the masklen | ||
120 | + */ | ||
121 | + public int getMasklen() { | ||
122 | + return this.masklen; | ||
123 | + } | ||
124 | + | ||
125 | + /** | ||
126 | + * Return the sparse bit. | ||
127 | + * | ||
128 | + * @return true or false | ||
129 | + */ | ||
130 | + public boolean getSBit() { | ||
131 | + return this.sBit; | ||
132 | + } | ||
133 | + | ||
134 | + /** | ||
135 | + * Return the wBit, used in Join/Prune messages. | ||
136 | + * | ||
137 | + * @return return true or false. | ||
138 | + */ | ||
139 | + public boolean getWBit() { | ||
140 | + return this.wBit; | ||
141 | + } | ||
142 | + | ||
143 | + /** | ||
144 | + * Return the rBit. Used by Rendezvous Point. | ||
145 | + * | ||
146 | + * @return the rBit. | ||
147 | + */ | ||
148 | + public boolean getRBit() { | ||
149 | + return this.rBit; | ||
150 | + } | ||
151 | + | ||
152 | + /** | ||
153 | + * The size in bytes of a serialized address. | ||
154 | + * | ||
155 | + * @return the number of bytes when serialized | ||
156 | + */ | ||
157 | + public int getByteSize() { | ||
158 | + int size = 4; | ||
159 | + size += addr.isIp4() ? 4 : 16; | ||
160 | + return size; | ||
161 | + } | ||
162 | + | ||
163 | + public byte[] serialize() { | ||
164 | + int len = addr.isIp4() ? ENC_SOURCE_IPV4_BYTE_LENGTH : ENC_SOURCE_IPV6_BYTE_LENGTH; | ||
165 | + | ||
166 | + final byte[] data = new byte[len]; | ||
167 | + final ByteBuffer bb = ByteBuffer.wrap(data); | ||
168 | + | ||
169 | + bb.put(this.family); | ||
170 | + bb.put(this.encType); | ||
171 | + | ||
172 | + // Todo: technically we should be setting the B and Z bits, but we'll never use them. | ||
173 | + byte mask = 0x0; | ||
174 | + if (this.sBit) { | ||
175 | + this.reserved |= 0x4; | ||
176 | + } | ||
177 | + if (this.wBit) { | ||
178 | + this.reserved |= 0x2; | ||
179 | + } | ||
180 | + if (this.rBit) { | ||
181 | + this.reserved |= 0x1; | ||
182 | + } | ||
183 | + bb.put(reserved); | ||
184 | + | ||
185 | + bb.put(this.masklen); | ||
186 | + bb.put(this.addr.toOctets()); | ||
187 | + return data; | ||
188 | + } | ||
189 | + | ||
190 | + public PIMAddrSource deserialize(byte[] data, int offset, int length) throws DeserializationException { | ||
191 | + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | ||
192 | + return deserialize(bb); | ||
193 | + } | ||
194 | + | ||
195 | + public PIMAddrSource deserialize(ByteBuffer bb) throws DeserializationException { | ||
196 | + | ||
197 | + /* | ||
198 | + * We need to verify that we have enough buffer space. First we'll assume that | ||
199 | + * we are decoding an IPv4 address. After we read the first by (address family), | ||
200 | + * we'll determine if we actually need more buffer space for an IPv6 address. | ||
201 | + */ | ||
202 | + checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_SOURCE_IPV4_BYTE_LENGTH); | ||
203 | + | ||
204 | + this.family = bb.get(); | ||
205 | + if (family != 4 && family != 6) { | ||
206 | + throw new DeserializationException("Illegal IP version number: " + family + "\n"); | ||
207 | + } else if (family == 6) { | ||
208 | + | ||
209 | + // Check for one less by since we have already read the first byte of the packet. | ||
210 | + checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_SOURCE_IPV6_BYTE_LENGTH - 1); | ||
211 | + } | ||
212 | + | ||
213 | + this.encType = bb.get(); | ||
214 | + this.reserved = bb.get(); | ||
215 | + if ((this.reserved & 0x01) != 0) { | ||
216 | + this.rBit = true; | ||
217 | + } | ||
218 | + if ((this.reserved & 0x02) != 0) { | ||
219 | + this.wBit = true; | ||
220 | + } | ||
221 | + if ((this.reserved & 0x4) != 0) { | ||
222 | + this.sBit = true; | ||
223 | + } | ||
224 | + | ||
225 | + // Remove the s, reserved | ||
226 | + this.reserved &= 0xf8; | ||
227 | + | ||
228 | + this.masklen = bb.get(); | ||
229 | + if (this.family == 4) { | ||
230 | + this.addr = IpAddress.valueOf(bb.getInt()); | ||
231 | + } else if (this.family == 6) { | ||
232 | + this.addr = Ip6Address.valueOf(bb.array(), 2); | ||
233 | + } | ||
234 | + return this; | ||
235 | + } | ||
236 | + | ||
237 | + /* | ||
238 | + * (non-Javadoc) | ||
239 | + * | ||
240 | + * @see java.lang.Object#hashCode() | ||
241 | + */ | ||
242 | + @Override | ||
243 | + public int hashCode() { | ||
244 | + final int prime = 2521; | ||
245 | + int result = super.hashCode(); | ||
246 | + result = prime * result + this.family; | ||
247 | + result = prime * result + this.encType; | ||
248 | + result = prime * result + this.reserved; | ||
249 | + result = prime * result + this.masklen; | ||
250 | + result = prime * result + this.addr.hashCode(); | ||
251 | + return result; | ||
252 | + } | ||
253 | + | ||
254 | + /* | ||
255 | + * (non-Javadoc) | ||
256 | + * | ||
257 | + * @see java.lang.Object#hashCode() | ||
258 | + */ | ||
259 | + @Override | ||
260 | + public boolean equals(final Object obj) { | ||
261 | + if (this == obj) { | ||
262 | + return true; | ||
263 | + } | ||
264 | + if (!(obj instanceof PIMAddrSource)) { | ||
265 | + return false; | ||
266 | + } | ||
267 | + final PIMAddrSource other = (PIMAddrSource) obj; | ||
268 | + if (this.family != this.family) { | ||
269 | + return false; | ||
270 | + } | ||
271 | + | ||
272 | + if (this.encType != other.encType) { | ||
273 | + return false; | ||
274 | + } | ||
275 | + | ||
276 | + if (!this.addr.equals(other.addr)) { | ||
277 | + return false; | ||
278 | + } | ||
279 | + return true; | ||
280 | + } | ||
281 | +} |
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 | +import org.onlab.packet.Ip4Address; | ||
20 | +import org.onlab.packet.IpAddress; | ||
21 | +import org.onlab.packet.Ip6Address; | ||
22 | + | ||
23 | +import java.nio.ByteBuffer; | ||
24 | + | ||
25 | +import static org.onlab.packet.PacketUtils.checkInput; | ||
26 | + | ||
27 | +public class PIMAddrUnicast { | ||
28 | + private byte family; | ||
29 | + private byte encType; | ||
30 | + IpAddress addr; | ||
31 | + | ||
32 | + public static final int ENC_UNICAST_IPV4_BYTE_LENGTH = 2 + Ip4Address.BYTE_LENGTH; | ||
33 | + public static final int ENC_UNICAST_IPV6_BYTE_LENGTH = 2 + Ip6Address.BYTE_LENGTH; | ||
34 | + | ||
35 | + /** | ||
36 | + * PIM Encoded Source Address. | ||
37 | + */ | ||
38 | + public PIMAddrUnicast() { | ||
39 | + this.family = 4; | ||
40 | + this.encType = 0; | ||
41 | + } | ||
42 | + | ||
43 | + /** | ||
44 | + * PIM Encoded Source Address. | ||
45 | + * | ||
46 | + * @param addr IPv4 or IPv6 | ||
47 | + */ | ||
48 | + public PIMAddrUnicast(String addr) { | ||
49 | + this.addr = IpAddress.valueOf(addr); | ||
50 | + if (this.addr.isIp4()) { | ||
51 | + this.family = 4; | ||
52 | + } else { | ||
53 | + this.family = 6; | ||
54 | + } | ||
55 | + this.encType = 0; | ||
56 | + } | ||
57 | + | ||
58 | + /** | ||
59 | + * PIM Encoded Source Address. | ||
60 | + * | ||
61 | + * @param addr IPv4 or IPv6 | ||
62 | + */ | ||
63 | + public void setAddr(IpAddress addr) { | ||
64 | + this.addr = addr; | ||
65 | + if (this.addr.isIp4()) { | ||
66 | + this.family = 4; | ||
67 | + } else { | ||
68 | + this.family = 6; | ||
69 | + } | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * Get the address of this encoded address. | ||
74 | + * | ||
75 | + * @return source address | ||
76 | + */ | ||
77 | + public IpAddress getAddr() { | ||
78 | + return this.addr; | ||
79 | + } | ||
80 | + | ||
81 | + /** | ||
82 | + * Get the IP family of this address: 4 or 6. | ||
83 | + * | ||
84 | + * @return the IP address family | ||
85 | + */ | ||
86 | + public int getFamily() { | ||
87 | + return this.family; | ||
88 | + } | ||
89 | + | ||
90 | + /** | ||
91 | + * The size in bytes of a serialized address. | ||
92 | + * | ||
93 | + * @return the number of bytes when serialized | ||
94 | + */ | ||
95 | + public int getByteSize() { | ||
96 | + int size = 2; | ||
97 | + if (addr != null) { | ||
98 | + size += addr.isIp4() ? 4 : 16; | ||
99 | + } else { | ||
100 | + size += 4; | ||
101 | + } | ||
102 | + return size; | ||
103 | + } | ||
104 | + | ||
105 | + public byte[] serialize() { | ||
106 | + int len = getByteSize(); | ||
107 | + | ||
108 | + final byte[] data = new byte[len]; | ||
109 | + final ByteBuffer bb = ByteBuffer.wrap(data); | ||
110 | + | ||
111 | + bb.put(family); | ||
112 | + bb.put(encType); | ||
113 | + bb.put(addr.toOctets()); | ||
114 | + return data; | ||
115 | + } | ||
116 | + | ||
117 | + public PIMAddrUnicast deserialize(ByteBuffer bb) throws DeserializationException { | ||
118 | + | ||
119 | + // Assume IPv4 for check length until we read the encoded family. | ||
120 | + checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_UNICAST_IPV4_BYTE_LENGTH); | ||
121 | + this.family = bb.get(); | ||
122 | + | ||
123 | + // If we have IPv6 we need to ensure we have adequate buffer space. | ||
124 | + if (this.family != 4 && this.family != 6) { | ||
125 | + throw new DeserializationException("Invalid address family: " + this.family); | ||
126 | + } else if (this.family == 6) { | ||
127 | + // Subtract -1 from ENC_UNICAST_IPv6 BYTE_LENGTH because we read one byte for family previously. | ||
128 | + checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_UNICAST_IPV6_BYTE_LENGTH - 1); | ||
129 | + } | ||
130 | + | ||
131 | + this.encType = bb.get(); | ||
132 | + if (this.family == 4) { | ||
133 | + this.addr = IpAddress.valueOf(bb.getInt()); | ||
134 | + } else if (this.family == 6) { | ||
135 | + this.addr = Ip6Address.valueOf(bb.array(), 2); | ||
136 | + } | ||
137 | + return this; | ||
138 | + } | ||
139 | + | ||
140 | + /* | ||
141 | + * (non-Javadoc) | ||
142 | + * | ||
143 | + * @see java.lang.Object#hashCode() | ||
144 | + */ | ||
145 | + @Override | ||
146 | + public int hashCode() { | ||
147 | + final int prime = 2521; | ||
148 | + int result = super.hashCode(); | ||
149 | + result = prime * result + this.family; | ||
150 | + result = prime * result + this.encType; | ||
151 | + result = prime * result + this.addr.hashCode(); | ||
152 | + return result; | ||
153 | + } | ||
154 | + | ||
155 | + /* | ||
156 | + * (non-Javadoc) | ||
157 | + * | ||
158 | + * @see java.lang.Object#hashCode() | ||
159 | + */ | ||
160 | + @Override | ||
161 | + public boolean equals(final Object obj) { | ||
162 | + if (this == obj) { | ||
163 | + return true; | ||
164 | + } | ||
165 | + if (!(obj instanceof PIMAddrUnicast)) { | ||
166 | + return false; | ||
167 | + } | ||
168 | + final PIMAddrUnicast other = (PIMAddrUnicast) obj; | ||
169 | + if (this.family != this.family) { | ||
170 | + return false; | ||
171 | + } | ||
172 | + | ||
173 | + if (this.encType != other.encType) { | ||
174 | + return false; | ||
175 | + } | ||
176 | + | ||
177 | + if (!this.addr.equals(other.addr)) { | ||
178 | + return false; | ||
179 | + } | ||
180 | + return true; | ||
181 | + } | ||
182 | +} |
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.BasePacket; | ||
19 | +import org.onlab.packet.Deserializer; | ||
20 | +import org.onlab.packet.IPacket; | ||
21 | +import org.onlab.packet.IpAddress; | ||
22 | + | ||
23 | +import java.nio.ByteBuffer; | ||
24 | +import java.util.Random; | ||
25 | + | ||
26 | +import static org.onlab.packet.PacketUtils.checkInput; | ||
27 | + | ||
28 | +public class PIMHello extends BasePacket { | ||
29 | + | ||
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; | ||
36 | + | ||
37 | + public static final int MINIMUM_OPTION_LEN_BYTES = 4; | ||
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 | + | ||
75 | + /** | ||
76 | + * Add the hello priority. | ||
77 | + * | ||
78 | + * @param priority default is 1, the higher the better | ||
79 | + */ | ||
80 | + public void addPriority(int priority) { | ||
81 | + this.priority = priority; | ||
82 | + this.priorityPresent = true; | ||
83 | + } | ||
84 | + | ||
85 | + /** | ||
86 | + * Add a Gen ID. | ||
87 | + * | ||
88 | + * @param genid a random generated number, changes only after reset. | ||
89 | + */ | ||
90 | + public void addGenId(int genid) { | ||
91 | + if (genid == 0) { | ||
92 | + this.addGenId(); | ||
93 | + } else { | ||
94 | + this.genid = genid; | ||
95 | + } | ||
96 | + } | ||
97 | + | ||
98 | + /** | ||
99 | + * Add the genid. Let this function figure out the number. | ||
100 | + */ | ||
101 | + public void addGenId() { | ||
102 | + Random rand = new Random(); | ||
103 | + this.genid = rand.nextInt(); | ||
104 | + } | ||
105 | + | ||
106 | + /** | ||
107 | + * Sets all payloads parent packet if applicable, then serializes this | ||
108 | + * packet and all payloads. | ||
109 | + * | ||
110 | + * @return a byte[] containing this packet and payloads | ||
111 | + */ | ||
112 | + @Override | ||
113 | + public byte[] serialize() { | ||
114 | + | ||
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 | + | ||
120 | + byte[] data = new byte[size]; // Come up with something better | ||
121 | + ByteBuffer bb = ByteBuffer.wrap(data); | ||
122 | + | ||
123 | + // Add the priority | ||
124 | + bb.putShort((short) Option.PRIORITY.optType); | ||
125 | + bb.putShort((short) Option.PRIORITY.optLen); | ||
126 | + bb.putInt(this.priority); | ||
127 | + | ||
128 | + // Add the genid | ||
129 | + bb.putShort((short) Option.GENID.optType); | ||
130 | + bb.putShort((short) Option.GENID.optLen); | ||
131 | + bb.putInt(this.genid); | ||
132 | + | ||
133 | + // Add the holdtime | ||
134 | + bb.putShort((short) Option.HOLDTIME.optType); | ||
135 | + bb.putShort((short) Option.HOLDTIME.optLen); | ||
136 | + bb.putShort((short) this.holdtime); | ||
137 | + return data; | ||
138 | + } | ||
139 | + | ||
140 | + /** | ||
141 | + * XXX: This is deprecated, DO NOT USE, use the deserializer() function instead. | ||
142 | + */ | ||
143 | + // @Override | ||
144 | + public IPacket deserialize(final byte[] data, final int offset, | ||
145 | + final int length) { | ||
146 | + // | ||
147 | + return null; | ||
148 | + } | ||
149 | + | ||
150 | + /** | ||
151 | + * Deserialize this hello message. | ||
152 | + * | ||
153 | + * @return a deserialized hello message. | ||
154 | + */ | ||
155 | + public static Deserializer<PIMHello> deserializer() { | ||
156 | + return (data, offset, length) -> { | ||
157 | + checkInput(data, offset, length, MINIMUM_OPTION_LEN_BYTES); | ||
158 | + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | ||
159 | + | ||
160 | + PIMHello hello = new PIMHello(); | ||
161 | + while (bb.hasRemaining()) { | ||
162 | + int optType = bb.getShort(); | ||
163 | + int optLen = bb.getShort(); | ||
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 | + } | ||
175 | + | ||
176 | + return hello; | ||
177 | + }; | ||
178 | + } | ||
179 | +} |
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.BasePacket; | ||
19 | +import org.onlab.packet.Deserializer; | ||
20 | +import org.onlab.packet.IPacket; | ||
21 | +import org.onlab.packet.IpPrefix; | ||
22 | + | ||
23 | +import java.nio.ByteBuffer; | ||
24 | +import java.util.HashMap; | ||
25 | + | ||
26 | +import static org.onlab.packet.PacketUtils.checkInput; | ||
27 | + | ||
28 | +public class PIMJoinPrune extends BasePacket { | ||
29 | + | ||
30 | + private PIMAddrUnicast upstreamAddr = new PIMAddrUnicast(); | ||
31 | + private short holdTime = (short) 0xffff; | ||
32 | + | ||
33 | + private class JoinPruneGroup { | ||
34 | + protected IpPrefix group; | ||
35 | + protected HashMap<IpPrefix, IpPrefix> joins = new HashMap<>(); | ||
36 | + protected HashMap<IpPrefix, IpPrefix> prunes = new HashMap<>(); | ||
37 | + | ||
38 | + public JoinPruneGroup(IpPrefix grp) { | ||
39 | + group = grp; | ||
40 | + } | ||
41 | + } | ||
42 | + private HashMap<IpPrefix, JoinPruneGroup> joinPrunes = new HashMap<>(); | ||
43 | + | ||
44 | + /** | ||
45 | + * Get the J/P hold time. | ||
46 | + * | ||
47 | + * @return specified in seconds. | ||
48 | + */ | ||
49 | + public short getHoldTime() { | ||
50 | + return holdTime; | ||
51 | + } | ||
52 | + | ||
53 | + /** | ||
54 | + * Set the J/P holdtime in seconds. | ||
55 | + * | ||
56 | + * @param holdTime return the holdtime. | ||
57 | + */ | ||
58 | + public void setHoldTime(short holdTime) { | ||
59 | + this.holdTime = holdTime; | ||
60 | + } | ||
61 | + | ||
62 | + /** | ||
63 | + * Get the upstreamAddr for this J/P request. | ||
64 | + * | ||
65 | + * @return the upstream address. | ||
66 | + */ | ||
67 | + public PIMAddrUnicast getUpstreamAddr() { | ||
68 | + return upstreamAddr; | ||
69 | + } | ||
70 | + | ||
71 | + /** | ||
72 | + * Set the upstream address of this PIM J/P request. | ||
73 | + * | ||
74 | + * @param upstr the PIM Upstream unicast address | ||
75 | + */ | ||
76 | + public void setUpstreamAddr(PIMAddrUnicast upstr) { | ||
77 | + this.upstreamAddr = upstr; | ||
78 | + } | ||
79 | + | ||
80 | + /** | ||
81 | + * Add the specified s,g to join field. | ||
82 | + * | ||
83 | + * @param saddr the source address of the route | ||
84 | + * @param gaddr the group address of the route | ||
85 | + * @param join true for a join, false for a prune. | ||
86 | + */ | ||
87 | + public void addJoinPrune(String saddr, String gaddr, boolean join) { | ||
88 | + IpPrefix gpfx = IpPrefix.valueOf(gaddr); | ||
89 | + IpPrefix spfx = IpPrefix.valueOf(saddr); | ||
90 | + addJoinPrune(spfx, gpfx, join); | ||
91 | + } | ||
92 | + | ||
93 | + /** | ||
94 | + * Add the specified S, G to the join field. | ||
95 | + * | ||
96 | + * @param spfx the source prefix of the route | ||
97 | + * @param gpfx the group prefix of the route | ||
98 | + * @param join true for join, false for prune | ||
99 | + */ | ||
100 | + public void addJoinPrune(IpPrefix spfx, IpPrefix gpfx, boolean join) { | ||
101 | + JoinPruneGroup jpg = joinPrunes.get(gpfx); | ||
102 | + if (jpg == null) { | ||
103 | + jpg = new JoinPruneGroup(gpfx); | ||
104 | + joinPrunes.put(gpfx, jpg); | ||
105 | + } | ||
106 | + | ||
107 | + HashMap<IpPrefix, IpPrefix> members = (join) ? jpg.joins : jpg.prunes; | ||
108 | + if (members.get(spfx) == null) { | ||
109 | + members.put(spfx, spfx); | ||
110 | + } | ||
111 | + } | ||
112 | + | ||
113 | + /** | ||
114 | + * Add a join given strings represending the source and group addresses. | ||
115 | + * | ||
116 | + * @param saddr source address | ||
117 | + * @param gaddr group address | ||
118 | + */ | ||
119 | + public void addJoin(String saddr, String gaddr) { | ||
120 | + this.addJoinPrune(saddr, gaddr, true); | ||
121 | + } | ||
122 | + | ||
123 | + /** | ||
124 | + * Add a prune given strings represending the source and group addresses. | ||
125 | + * | ||
126 | + * @param saddr source address | ||
127 | + * @param gaddr group address | ||
128 | + */ | ||
129 | + public void addPrune(String saddr, String gaddr) { | ||
130 | + this.addJoinPrune(saddr, gaddr, false); | ||
131 | + } | ||
132 | + | ||
133 | + /** | ||
134 | + * Sets all payloads parent packet if applicable, then serializes this | ||
135 | + * packet and all payloads. | ||
136 | + * | ||
137 | + * @return a byte[] containing this packet and payloads | ||
138 | + */ | ||
139 | + @Override | ||
140 | + public byte[] serialize() { | ||
141 | + | ||
142 | + byte[] data = new byte[8096]; // Come up with something better | ||
143 | + ByteBuffer bb = ByteBuffer.wrap(data); | ||
144 | + | ||
145 | + bb.put(upstreamAddr.serialize()); | ||
146 | + bb.put((byte) 0); // reserved | ||
147 | + | ||
148 | + int ngrps = joinPrunes.size(); | ||
149 | + bb.put((byte) ngrps); | ||
150 | + bb.putShort(this.holdTime); | ||
151 | + | ||
152 | + // Walk the group list and input all groups | ||
153 | + for (JoinPruneGroup jpg : joinPrunes.values()) { | ||
154 | + PIMAddrGroup grp = new PIMAddrGroup(jpg.group); | ||
155 | + bb.put(grp.serialize()); | ||
156 | + | ||
157 | + // put the number of joins and prunes | ||
158 | + bb.putShort((short) jpg.joins.size()); | ||
159 | + bb.putShort((short) jpg.prunes.size()); | ||
160 | + | ||
161 | + // Set all of the joins | ||
162 | + for (IpPrefix spfx : jpg.joins.values()) { | ||
163 | + PIMAddrSource src = new PIMAddrSource(spfx); | ||
164 | + bb.put(src.serialize()); | ||
165 | + } | ||
166 | + | ||
167 | + // Set all of the prunes | ||
168 | + for (IpPrefix spfx : jpg.prunes.values()) { | ||
169 | + PIMAddrSource src = new PIMAddrSource(spfx); | ||
170 | + bb.put(src.serialize()); | ||
171 | + } | ||
172 | + } | ||
173 | + | ||
174 | + int len = bb.position(); | ||
175 | + byte[] data2 = new byte[len]; | ||
176 | + bb = ByteBuffer.wrap(data2, 0, len); | ||
177 | + bb.put(data, 0, len); | ||
178 | + return data2; | ||
179 | + } | ||
180 | + | ||
181 | + // TODO: I suppose I really need to implement this? | ||
182 | + @Override | ||
183 | + public IPacket deserialize(final byte[] data, final int offset, | ||
184 | + final int length) { | ||
185 | + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | ||
186 | + return this; | ||
187 | + } | ||
188 | + | ||
189 | + /** | ||
190 | + * Return the J/P deserializer function. | ||
191 | + * | ||
192 | + * @return a function that will deserialize a J/P message. | ||
193 | + */ | ||
194 | + public static Deserializer<PIMJoinPrune> deserializer() { | ||
195 | + return (data, offset, length) -> { | ||
196 | + | ||
197 | + /* | ||
198 | + * Delay buffer checks until we read enough of the packet to know how | ||
199 | + * much data we will require. Each encoded address deserializer function | ||
200 | + * will ensure there is enough data for that address. | ||
201 | + */ | ||
202 | + PIMJoinPrune jp = new PIMJoinPrune(); | ||
203 | + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); | ||
204 | + | ||
205 | + // We must get a PIM encoded unicast address | ||
206 | + PIMAddrUnicast upstream = new PIMAddrUnicast(); | ||
207 | + upstream.deserialize(bb); | ||
208 | + jp.setUpstreamAddr(upstream); | ||
209 | + | ||
210 | + // Use this boolean to determine the buffer space we need according to address sizes | ||
211 | + boolean ipv4 = upstream.getAddr().isIp4(); | ||
212 | + | ||
213 | + // We need at minimum 4 bytes for reserved(1), ngroups(1) & holdtime(2) | ||
214 | + checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), 4); | ||
215 | + | ||
216 | + // get and skip the reserved byte | ||
217 | + bb.get(); | ||
218 | + | ||
219 | + // Get the number of groups. | ||
220 | + int ngroups = bb.get(); | ||
221 | + | ||
222 | + // Save the holdtime. | ||
223 | + jp.setHoldTime(bb.getShort()); | ||
224 | + | ||
225 | + | ||
226 | + for (int i = 0; i < ngroups; i++) { | ||
227 | + PIMAddrGroup grp = new PIMAddrGroup(); | ||
228 | + | ||
229 | + /* | ||
230 | + * grp.deserialize will ensure the buffer has enough data to read the group address. | ||
231 | + */ | ||
232 | + grp.deserialize(bb); | ||
233 | + | ||
234 | + checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), 4); | ||
235 | + int njoins = bb.getShort(); | ||
236 | + int nprunes = bb.getShort(); | ||
237 | + | ||
238 | + /* | ||
239 | + * Now we'll verify we have enough buffer to read the next | ||
240 | + * group of join and prune addresses for this group. | ||
241 | + */ | ||
242 | + int required = (njoins + nprunes) * | ||
243 | + (ipv4 ? PIMAddrSource.ENC_SOURCE_IPV4_BYTE_LENGTH : PIMAddrSource.ENC_SOURCE_IPV6_BYTE_LENGTH); | ||
244 | + checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), required); | ||
245 | + | ||
246 | + // Now iterate through the joins for this group | ||
247 | + for (; njoins > 0; njoins--) { | ||
248 | + | ||
249 | + PIMAddrSource src = new PIMAddrSource(); | ||
250 | + src.deserialize(bb); | ||
251 | + | ||
252 | + jp.addJoinPrune( | ||
253 | + src.getAddr().toIpPrefix(), | ||
254 | + grp.getAddr().toIpPrefix(), true); | ||
255 | + } | ||
256 | + | ||
257 | + // Now iterate through the prunes for this group | ||
258 | + for (; nprunes > 0; nprunes--) { | ||
259 | + | ||
260 | + PIMAddrSource src = new PIMAddrSource(); | ||
261 | + src.deserialize(bb); | ||
262 | + jp.addJoinPrune( | ||
263 | + src.getAddr().toIpPrefix(), | ||
264 | + grp.getAddr().toIpPrefix(), false); | ||
265 | + } | ||
266 | + } | ||
267 | + | ||
268 | + return jp; | ||
269 | + }; | ||
270 | + } | ||
271 | +} |
1 | +/* | ||
2 | + * Copyright 2014-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 | + | ||
17 | +/** | ||
18 | + * Utilities for managing PIM packets. | ||
19 | + */ | ||
20 | +package org.onlab.packet.pim; | ||
21 | + |
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; | ||
17 | + | ||
18 | +import org.junit.Before; | ||
19 | +import org.junit.Test; | ||
20 | +import org.onlab.packet.pim.PIMAddrUnicast; | ||
21 | +import org.onlab.packet.pim.PIMHello; | ||
22 | +import org.onlab.packet.pim.PIMJoinPrune; | ||
23 | + | ||
24 | +import static junit.framework.Assert.assertTrue; | ||
25 | + | ||
26 | +public final class PIMTest { | ||
27 | + | ||
28 | + public static final String SADDR = "10.2.1.2"; | ||
29 | + public static final String PIMADDR = "224.0.0.13"; | ||
30 | + public static final String PIMUADDR = "10.23.3.5"; | ||
31 | + | ||
32 | + public static final String SADDR1 = "10.1.1.1/32"; | ||
33 | + public static final String SADDR2 = "10.1.2.1/32"; | ||
34 | + public static final String GADDR1 = "232.1.1.1/32"; | ||
35 | + public static final String GADDR2 = "232.1.2.1/32"; | ||
36 | + | ||
37 | + public static final String CPSTR1 = "of:deadbeefball/8"; | ||
38 | + public static final String CPSTR2 = "of:deadbeefcafe/3"; | ||
39 | + public static final String CPSTR3 = "of:2badcafef00d/3"; | ||
40 | + | ||
41 | + private Deserializer<PIM> deserializer; | ||
42 | + | ||
43 | + private PIM pimHello; | ||
44 | + private PIMHello hello; | ||
45 | + | ||
46 | + private PIM pimJoinPrune; | ||
47 | + private PIMJoinPrune joinPrune; | ||
48 | + | ||
49 | + @Before | ||
50 | + public void setUp() throws Exception { | ||
51 | + | ||
52 | + // Create a PIM Hello | ||
53 | + pimHello = new PIM(); | ||
54 | + pimHello.setVersion((byte) 2); | ||
55 | + pimHello.setPIMType((byte) PIM.TYPE_HELLO); | ||
56 | + pimHello.setChecksum((short) 0); | ||
57 | + | ||
58 | + hello = new PIMHello(); | ||
59 | + hello.addHoldtime(0xd2); | ||
60 | + hello.addPriority(44); | ||
61 | + hello.addGenId(0xf00d); | ||
62 | + pimHello.setPayload(hello); | ||
63 | + hello.setParent(pimHello); | ||
64 | + | ||
65 | + // Create PIM Join Prune | ||
66 | + pimJoinPrune = new PIM(); | ||
67 | + pimJoinPrune.setVersion((byte) 2); | ||
68 | + pimJoinPrune.setPIMType((byte) PIM.TYPE_JOIN_PRUNE_REQUEST); | ||
69 | + pimJoinPrune.setChecksum((short) 0); | ||
70 | + | ||
71 | + joinPrune = new PIMJoinPrune(); | ||
72 | + joinPrune.setUpstreamAddr(new PIMAddrUnicast(SADDR)); | ||
73 | + joinPrune.addJoin(GADDR1, SADDR1); | ||
74 | + joinPrune.addJoin(GADDR2, SADDR2); | ||
75 | + joinPrune.addPrune(GADDR1, SADDR2); | ||
76 | + joinPrune.addPrune(GADDR2, SADDR1); | ||
77 | + | ||
78 | + pimJoinPrune.setPayload(joinPrune); | ||
79 | + joinPrune.setParent(pimJoinPrune); | ||
80 | + | ||
81 | + deserializer = PIM.deserializer(); | ||
82 | + } | ||
83 | + | ||
84 | + @Test | ||
85 | + public void testDerserializeBadInput() throws Exception { | ||
86 | + PacketTestUtils.testDeserializeBadInput(deserializer); | ||
87 | + } | ||
88 | + | ||
89 | + @Test | ||
90 | + public void testDeserializeTruncated() throws Exception { | ||
91 | + //byte [] bits = pimHello.serialize(); | ||
92 | + //PacketTestUtils.testDeserializeTruncated(deserializer, bits); | ||
93 | + | ||
94 | + byte [] bits = pimJoinPrune.serialize(); | ||
95 | + PacketTestUtils.testDeserializeTruncated(deserializer, bits); | ||
96 | + } | ||
97 | + | ||
98 | + @Test | ||
99 | + public void testDeserializeHello() throws Exception { | ||
100 | + byte [] data = pimHello.serialize(); | ||
101 | + PIM pim = deserializer.deserialize(data, 0, data.length); | ||
102 | + assertTrue(pim.equals(pimHello)); | ||
103 | + } | ||
104 | + | ||
105 | + @Test | ||
106 | + public void testDeserializeJoinPrune() throws Exception { | ||
107 | + byte [] data = pimJoinPrune.serialize(); | ||
108 | + PIM pim = deserializer.deserialize(data, 0, data.length); | ||
109 | + assertTrue(pim.equals(pimJoinPrune)); | ||
110 | + } | ||
111 | + | ||
112 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or login to post a comment