blob: 762dad56f853a1dcb9061803fd6fba60d6b1db96 [file] [log] [blame]
Rusty Eddy80f12522015-09-03 22:42:02 +00001/*
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 */
16package org.onlab.packet.pim;
17
18import org.onlab.packet.DeserializationException;
19import org.onlab.packet.Ip4Address;
Rusty Eddy0c12e402015-10-19 19:27:01 -070020import org.onlab.packet.Ip6Address;
Rusty Eddy80f12522015-09-03 22:42:02 +000021import org.onlab.packet.IpAddress;
22import org.onlab.packet.IpPrefix;
Rusty Eddy0c12e402015-10-19 19:27:01 -070023import org.onlab.packet.PIM;
Rusty Eddy80f12522015-09-03 22:42:02 +000024
25import java.nio.ByteBuffer;
26
27import static org.onlab.packet.PacketUtils.checkInput;
28
29public class PIMAddrSource {
30 private byte family;
31 private byte encType;
32 private byte reserved;
33 private boolean sBit;
34 private boolean wBit;
35 private boolean rBit;
36 private byte masklen;
37 IpAddress addr;
38
39 public static final int ENC_SOURCE_IPV4_BYTE_LENGTH = 4 + Ip4Address.BYTE_LENGTH;
40 public static final int ENC_SOURCE_IPV6_BYTE_LENGTH = 4 + Ip6Address.BYTE_LENGTH;
41
42 /**
43 * PIM Encoded Source Address.
44 *
45 * @param addr IPv4 or IPv6
46 */
47 public PIMAddrSource(String addr) {
48 this.init();
49 this.setAddr(addr);
50 }
51
52 /**
53 * PIM Encoded Source Address.
54 *
55 * @param spfx IPv4 or IPv6
56 */
57 public PIMAddrSource(IpPrefix spfx) {
58 this.init();
59 this.setAddr(spfx);
60 }
61
62 /**
63 * PIM Encoded Group Address.
64 */
65 public PIMAddrSource() {
66 this.init();
67 }
68
69 private void init() {
Rusty Eddy0c12e402015-10-19 19:27:01 -070070 this.family = PIM.ADDRESS_FAMILY_IP4;
Rusty Eddy80f12522015-09-03 22:42:02 +000071 this.encType = 0;
72 this.reserved = 0;
73 this.sBit = true;
74 this.wBit = false;
75 this.rBit = false;
76 }
77
78 /**
79 * PIM Encoded Source Address.
80 *
81 * @param addr IPv4 or IPv6
82 */
83 public void setAddr(String addr) {
84 IpPrefix spfx = IpPrefix.valueOf(addr);
85 setAddr(spfx);
86 }
87
88 /**
89 * PIM Encoded Source Address.
90 *
91 * @param spfx IPv4 or IPv6 address prefix
92 */
93 public void setAddr(IpPrefix spfx) {
94 this.addr = spfx.address();
95 this.masklen = (byte) spfx.prefixLength();
Rusty Eddy0c12e402015-10-19 19:27:01 -070096 this.family = (byte) ((this.addr.isIp4()) ? PIM.ADDRESS_FAMILY_IP4 : PIM.ADDRESS_FAMILY_IP6);
Rusty Eddy80f12522015-09-03 22:42:02 +000097 }
98
99 /**
100 * Get the IP family of this address: 4 or 6.
101 *
102 * @return the IP address family
103 */
104 public byte getFamily() {
105 return this.family;
106 }
107
108 /**
109 * Get the address of this encoded address.
110 *
111 * @return source address
112 */
113 public IpAddress getAddr() {
114 return this.addr;
115 }
116
117 /**
118 * Get the masklen of the group address.
119 *
120 * @return the masklen
121 */
122 public int getMasklen() {
123 return this.masklen;
124 }
125
126 /**
127 * Return the sparse bit.
128 *
129 * @return true or false
130 */
131 public boolean getSBit() {
132 return this.sBit;
133 }
134
135 /**
136 * Return the wBit, used in Join/Prune messages.
137 *
138 * @return return true or false.
139 */
140 public boolean getWBit() {
141 return this.wBit;
142 }
143
144 /**
145 * Return the rBit. Used by Rendezvous Point.
146 *
147 * @return the rBit.
148 */
149 public boolean getRBit() {
150 return this.rBit;
151 }
152
153 /**
154 * The size in bytes of a serialized address.
155 *
156 * @return the number of bytes when serialized
157 */
158 public int getByteSize() {
159 int size = 4;
Rusty Eddy0c12e402015-10-19 19:27:01 -0700160 size += addr.isIp4() ? PIM.ADDRESS_FAMILY_IP4 : PIM.ADDRESS_FAMILY_IP6;
Rusty Eddy80f12522015-09-03 22:42:02 +0000161 return size;
162 }
163
164 public byte[] serialize() {
165 int len = addr.isIp4() ? ENC_SOURCE_IPV4_BYTE_LENGTH : ENC_SOURCE_IPV6_BYTE_LENGTH;
166
167 final byte[] data = new byte[len];
168 final ByteBuffer bb = ByteBuffer.wrap(data);
169
170 bb.put(this.family);
171 bb.put(this.encType);
172
173 // Todo: technically we should be setting the B and Z bits, but we'll never use them.
174 byte mask = 0x0;
175 if (this.sBit) {
176 this.reserved |= 0x4;
177 }
178 if (this.wBit) {
179 this.reserved |= 0x2;
180 }
181 if (this.rBit) {
182 this.reserved |= 0x1;
183 }
184 bb.put(reserved);
185
186 bb.put(this.masklen);
187 bb.put(this.addr.toOctets());
188 return data;
189 }
190
191 public PIMAddrSource deserialize(byte[] data, int offset, int length) throws DeserializationException {
192 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
193 return deserialize(bb);
194 }
195
196 public PIMAddrSource deserialize(ByteBuffer bb) throws DeserializationException {
197
198 /*
199 * We need to verify that we have enough buffer space. First we'll assume that
200 * we are decoding an IPv4 address. After we read the first by (address family),
201 * we'll determine if we actually need more buffer space for an IPv6 address.
202 */
203 checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_SOURCE_IPV4_BYTE_LENGTH);
204
205 this.family = bb.get();
Rusty Eddy0c12e402015-10-19 19:27:01 -0700206 if (family != PIM.ADDRESS_FAMILY_IP4 && family != PIM.ADDRESS_FAMILY_IP6) {
Rusty Eddy80f12522015-09-03 22:42:02 +0000207 throw new DeserializationException("Illegal IP version number: " + family + "\n");
Rusty Eddy0c12e402015-10-19 19:27:01 -0700208 } else if (family == PIM.ADDRESS_FAMILY_IP6) {
Rusty Eddy80f12522015-09-03 22:42:02 +0000209
210 // Check for one less by since we have already read the first byte of the packet.
211 checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_SOURCE_IPV6_BYTE_LENGTH - 1);
212 }
213
214 this.encType = bb.get();
215 this.reserved = bb.get();
216 if ((this.reserved & 0x01) != 0) {
217 this.rBit = true;
218 }
219 if ((this.reserved & 0x02) != 0) {
220 this.wBit = true;
221 }
222 if ((this.reserved & 0x4) != 0) {
223 this.sBit = true;
224 }
225
226 // Remove the s, reserved
227 this.reserved &= 0xf8;
228
229 this.masklen = bb.get();
Rusty Eddy0c12e402015-10-19 19:27:01 -0700230 if (this.family == PIM.ADDRESS_FAMILY_IP4) {
Rusty Eddy80f12522015-09-03 22:42:02 +0000231 this.addr = IpAddress.valueOf(bb.getInt());
Rusty Eddy0c12e402015-10-19 19:27:01 -0700232 } else if (this.family == PIM.ADDRESS_FAMILY_IP6) {
Rusty Eddy80f12522015-09-03 22:42:02 +0000233 this.addr = Ip6Address.valueOf(bb.array(), 2);
234 }
235 return this;
236 }
237
238 /*
239 * (non-Javadoc)
240 *
241 * @see java.lang.Object#hashCode()
242 */
243 @Override
244 public int hashCode() {
245 final int prime = 2521;
246 int result = super.hashCode();
247 result = prime * result + this.family;
248 result = prime * result + this.encType;
249 result = prime * result + this.reserved;
250 result = prime * result + this.masklen;
251 result = prime * result + this.addr.hashCode();
252 return result;
253 }
254
255 /*
256 * (non-Javadoc)
257 *
258 * @see java.lang.Object#hashCode()
259 */
260 @Override
261 public boolean equals(final Object obj) {
262 if (this == obj) {
263 return true;
264 }
265 if (!(obj instanceof PIMAddrSource)) {
266 return false;
267 }
268 final PIMAddrSource other = (PIMAddrSource) obj;
HIGUCHI Yutaf2710c72015-09-22 15:22:06 -0700269 if (this.family != other.family) {
Rusty Eddy80f12522015-09-03 22:42:02 +0000270 return false;
271 }
272
273 if (this.encType != other.encType) {
274 return false;
275 }
276
277 if (!this.addr.equals(other.addr)) {
278 return false;
279 }
280 return true;
281 }
282}