blob: 674e7ab41a16a8d0699708505b5c3c4b2b41bb3f [file] [log] [blame]
Rusty Eddy80f12522015-09-03 22:42:02 +00001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Rusty Eddy80f12522015-09-03 22:42:02 +00003 *
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;
24
Rusty Eddy80f12522015-09-03 22:42:02 +000025
26import java.nio.ByteBuffer;
27
28import static org.onlab.packet.PacketUtils.checkInput;
29
30public class PIMAddrGroup {
31 private byte family;
32 private byte encType;
33 private byte reserved;
34 private boolean bBit;
35 private boolean zBit;
36 private byte masklen;
37 IpAddress addr;
38
39 public static final int ENC_GROUP_IPV4_BYTE_LENGTH = 4 + Ip4Address.BYTE_LENGTH;
40 public static final int ENC_GROUP_IPV6_BYTE_LENGTH = 4 + Ip6Address.BYTE_LENGTH;
41
42 /**
43 * PIM Encoded Group Address.
44 */
45 public PIMAddrGroup() {
Rusty Eddy0c12e402015-10-19 19:27:01 -070046 this.family = PIM.ADDRESS_FAMILY_IP4;
Rusty Eddy80f12522015-09-03 22:42:02 +000047 this.encType = 0;
48 this.reserved = 0;
49 this.bBit = false;
50 this.zBit = false;
51 }
52
53 /**
54 * PIM Encoded Source Address.
55 *
56 * @param addr IPv4 or IPv6
57 */
58 public PIMAddrGroup(String addr) {
59 this.setAddr(addr);
60 }
61
62 /**
63 * PIM Encoded Group Address.
64 *
65 * @param gpfx PIM encoded group address.
66 */
67 public PIMAddrGroup(IpPrefix gpfx) {
68 this.setAddr(gpfx);
69 }
70
71 /**
72 * PIM encoded source address.
73 *
74 * @param addr IPv4 or IPv6
75 */
76 public void setAddr(String addr) {
77 setAddr(IpPrefix.valueOf(addr));
78 }
79
80 /**
81 * Set the encoded source address.
82 *
Thomas Vachuskab9c7ea62015-09-10 15:17:02 -070083 * @param pfx address prefix
Rusty Eddy80f12522015-09-03 22:42:02 +000084 */
85 public void setAddr(IpPrefix pfx) {
86 this.addr = pfx.address();
87 this.masklen = (byte) pfx.prefixLength();
Rusty Eddy0c12e402015-10-19 19:27:01 -070088 this.family = (byte) ((this.addr.isIp4()) ? PIM.ADDRESS_FAMILY_IP4 : PIM.ADDRESS_FAMILY_IP6);
Rusty Eddy80f12522015-09-03 22:42:02 +000089 }
90
91 /**
92 * Get the IP family of this address: 4 or 6.
93 *
94 * @return the IP address family
95 */
96 public int getFamily() {
97 return this.family;
98 }
99
100 /**
101 * Get the address of this encoded address.
102 *
103 * @return source address
104 */
105 public IpAddress getAddr() {
106 return this.addr;
107 }
108
109 /**
110 * Get the masklen of the group address.
111 *
112 * @return the masklen
113 */
114 public int getMasklen() {
115 return this.masklen;
116 }
117
118 /**
119 * Return the z bit for admin scoping. Only used for the Bootstrap router.
120 *
121 * @return true or false
122 */
123 public boolean getZBit() {
124 return this.zBit;
125 }
126
127 /**
128 * Return the bBit. Used to indicate this is a bidir
129 *
130 * @return return true or false.
131 */
132 public boolean getBBit() {
133 return this.bBit;
134 }
135
136 /**
137 * The size in bytes of a serialized address.
138 *
139 * @return the number of bytes when serialized
140 */
141 public int getByteSize() {
142 int size = 4;
143 size += addr.isIp4() ? 4 : 16;
144 return size;
145 }
146
147 /**
148 * Serialize this group address.
149 *
Thomas Vachuskab9c7ea62015-09-10 15:17:02 -0700150 * @return the serialized address in a buffer
Rusty Eddy80f12522015-09-03 22:42:02 +0000151 */
152 public byte[] serialize() {
153 int len = getByteSize();
154
155 final byte[] data = new byte[len];
156 final ByteBuffer bb = ByteBuffer.wrap(data);
157
158 bb.put(this.family);
159 bb.put(this.encType);
160
161 // Todo: technically we should be setting the B and Z bits, but we'll never use them.
162 bb.put(reserved);
163
164 bb.put(this.masklen);
165 bb.put(this.addr.toOctets());
166 return data;
167 }
168
169 /**
170 * Deserialze from a ByteBuffer.
171 *
172 * @param bb the ByteBuffer
Thomas Vachuskab9c7ea62015-09-10 15:17:02 -0700173 * @return an encoded PIM group address
174 * @throws DeserializationException if unable to deserialize the packet data
Rusty Eddy80f12522015-09-03 22:42:02 +0000175 */
176 public PIMAddrGroup deserialize(ByteBuffer bb) throws DeserializationException {
177
178 /*
179 * We need to verify that we have enough buffer space. First we'll assume that
180 * we are decoding an IPv4 address. After we read the first by (address family),
181 * we'll determine if we actually need more buffer space for an IPv6 address.
182 */
183 checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_GROUP_IPV4_BYTE_LENGTH);
184
185 this.family = bb.get();
Rusty Eddy0c12e402015-10-19 19:27:01 -0700186 if (family != PIM.ADDRESS_FAMILY_IP4 && family != PIM.ADDRESS_FAMILY_IP6) {
Rusty Eddy80f12522015-09-03 22:42:02 +0000187 throw new DeserializationException("Illegal IP version number: " + family + "\n");
Rusty Eddy0c12e402015-10-19 19:27:01 -0700188 } else if (family == PIM.ADDRESS_FAMILY_IP6) {
Rusty Eddy80f12522015-09-03 22:42:02 +0000189
190 // Check for one less by since we have already read the first byte of the packet.
191 checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_GROUP_IPV6_BYTE_LENGTH - 1);
192 }
193
194 this.encType = bb.get();
195 this.reserved = bb.get();
196 if ((this.reserved & 0x80) != 0) {
197 this.bBit = true;
198 }
199 if ((this.reserved & 0x01) != 0) {
200 this.zBit = true;
201 }
202 // Remove the z and b bits from reserved
203 this.reserved |= 0x7d;
204
205 this.masklen = bb.get();
Rusty Eddy0c12e402015-10-19 19:27:01 -0700206 if (this.family == PIM.ADDRESS_FAMILY_IP4) {
Rusty Eddy80f12522015-09-03 22:42:02 +0000207 this.addr = IpAddress.valueOf(bb.getInt());
Rusty Eddy0c12e402015-10-19 19:27:01 -0700208 } else if (this.family == PIM.ADDRESS_FAMILY_IP6) {
Rusty Eddy80f12522015-09-03 22:42:02 +0000209 this.addr = Ip6Address.valueOf(bb.array(), 2);
210 }
211 return this;
212 }
213
214 /*
215 * (non-Javadoc)
216 *
217 * @see java.lang.Object#hashCode()
218 */
219 @Override
220 public int hashCode() {
221 final int prime = 2521;
222 int result = super.hashCode();
223 result = prime * result + this.family;
224 result = prime * result + this.encType;
225 result = prime * result + this.reserved;
226 result = prime * result + this.masklen;
227 result = prime * result + this.addr.hashCode();
228 return result;
229 }
230
231
232 /*
233 * (non-Javadoc)
234 *
235 * @see java.lang.Object#equals()
236 */
237 @Override
238 public boolean equals(final Object obj) {
239 if (this == obj) {
240 return true;
241 }
242 if (!(obj instanceof PIMAddrGroup)) {
243 return false;
244 }
245 final PIMAddrGroup other = (PIMAddrGroup) obj;
HIGUCHI Yutaf2710c72015-09-22 15:22:06 -0700246 if (this.family != other.family) {
Rusty Eddy80f12522015-09-03 22:42:02 +0000247 return false;
248 }
249
250 if (this.encType != other.encType) {
251 return false;
252 }
253
254 if (!this.addr.equals(other.addr)) {
255 return false;
256 }
257 return true;
258 }
259}