blob: 2d4a78169bbc97ec43dafa7d5ed61bd7429efc18 [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;
20import org.onlab.packet.IpAddress;
21import org.onlab.packet.IpPrefix;
22import org.onlab.packet.Ip6Address;
23
24import java.nio.ByteBuffer;
25
26import static org.onlab.packet.PacketUtils.checkInput;
27
28public 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}