blob: d70fd0315499630d9a27738846189c6a65bfb299 [file] [log] [blame]
Jian Lic4d03912017-02-06 00:09:17 +09001/*
2 * Copyright 2017-present 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.onosproject.lisp.msg.types.lcaf;
17
18import io.netty.buffer.ByteBuf;
19import org.onlab.util.ByteOperator;
20import org.onosproject.lisp.msg.exceptions.LispParseError;
21import org.onosproject.lisp.msg.exceptions.LispReaderException;
22import org.onosproject.lisp.msg.exceptions.LispWriterException;
23import org.onosproject.lisp.msg.types.LispAddressReader;
24import org.onosproject.lisp.msg.types.LispAddressWriter;
25import org.onosproject.lisp.msg.types.LispAfiAddress;
26
27import java.util.Objects;
28
29import static com.google.common.base.MoreObjects.toStringHelper;
30import static com.google.common.base.Preconditions.checkNotNull;
31
32/**
33 * Geo Coordinate type LCAF address class.
34 * <p>
35 * Geo Coordinate type is defined in draft-ietf-lisp-lcaf-22
36 * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-22#page-11
37 * <p>
38 * <pre>
39 * {@literal
40 * 0 1 2 3
41 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 * | AFI = 16387 | Rsvd1 | Flags |
44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 * | Type = 5 | Rsvd2 | Length |
46 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 * |N| Latitude Degrees | Minutes | Seconds |
48 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49 * |E| Longitude Degrees | Minutes | Seconds |
50 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 * | Altitude |
52 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53 * | AFI = x | Address ... |
54 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 * }</pre>
56 */
57public final class LispGeoCoordinateLcafAddress extends LispLcafAddress {
58
59 private final boolean north;
60 private final short latitudeDegree;
61 private final byte latitudeMinute;
62 private final byte latitudeSecond;
63 private final boolean east;
64 private final short longitudeDegree;
65 private final byte longitudeMinute;
66 private final byte longitudeSecond;
67 private final int altitude;
68 private final LispAfiAddress address;
69
70 /**
71 * Initializes geo coordinate type LCAF address.
72 *
73 * @param north north flag
74 * @param latitudeDegree latitude degree
75 * @param latitudeMinute latitude minute
76 * @param latitudeSecond latitude second
77 * @param east east flag
78 * @param longitudeDegree longitude degree
79 * @param longitudeMinute longitude minute
80 * @param longitudeSecond longitude second
81 * @param altitude altitude
82 * @param address AFI address
83 */
84 private LispGeoCoordinateLcafAddress(boolean north, short latitudeDegree,
85 byte latitudeMinute, byte latitudeSecond,
86 boolean east, short longitudeDegree,
87 byte longitudeMinute, byte longitudeSecond,
88 int altitude, LispAfiAddress address) {
89 super(LispCanonicalAddressFormatEnum.GEO_COORDINATE);
90 this.north = north;
91 this.latitudeDegree = latitudeDegree;
92 this.latitudeMinute = latitudeMinute;
93 this.latitudeSecond = latitudeSecond;
94 this.east = east;
95 this.longitudeDegree = longitudeDegree;
96 this.longitudeMinute = longitudeMinute;
97 this.longitudeSecond = longitudeSecond;
98 this.altitude = altitude;
99 this.address = address;
100 }
101
102 /**
103 * Obtains north flag value.
104 *
105 * @return north flag value
106 */
107 public boolean isNorth() {
108 return north;
109 }
110
111 /**
112 * Obtains latitude degree.
113 *
114 * @return latitude degree
115 */
116 public short getLatitudeDegree() {
117 return latitudeDegree;
118 }
119
120 /**
121 * Obtains latitude minute.
122 *
123 * @return latitude minute
124 */
125 public byte getLatitudeMinute() {
126 return latitudeMinute;
127 }
128
129 /**
130 * Obtains latitude second.
131 *
132 * @return latitude second
133 */
134 public byte getLatitudeSecond() {
135 return latitudeSecond;
136 }
137
138 /**
139 * Obtains east flag value.
140 *
141 * @return east flag vlaue
142 */
143 public boolean isEast() {
144 return east;
145 }
146
147 /**
148 * Obtains longitude degree.
149 *
150 * @return longitude degree
151 */
152 public short getLongitudeDegree() {
153 return longitudeDegree;
154 }
155
156 /**
157 * Obtains longitude minute.
158 *
159 * @return longitude minute
160 */
161 public byte getLongitudeMinute() {
162 return longitudeMinute;
163 }
164
165 /**
166 * Obtains longitude second.
167 *
168 * @return longitude second
169 */
170 public byte getLongitudeSecond() {
171 return longitudeSecond;
172 }
173
174 /**
175 * Obtains altitude.
176 *
177 * @return altitude
178 */
179 public int getAltitude() {
180 return altitude;
181 }
182
183 /**
184 * Obtains AFI address.
185 *
186 * @return AFI address
187 */
188 public LispAfiAddress getAddress() {
189 return address;
190 }
191
192 @Override
193 public int hashCode() {
194 return Objects.hash(north, latitudeDegree, latitudeMinute, latitudeSecond,
195 east, longitudeDegree, longitudeMinute, longitudeSecond,
196 altitude, address);
197 }
198
199 @Override
200 public boolean equals(Object obj) {
201 if (this == obj) {
202 return true;
203 }
204
205 if (obj instanceof LispGeoCoordinateLcafAddress) {
206 final LispGeoCoordinateLcafAddress other =
207 (LispGeoCoordinateLcafAddress) obj;
208 return Objects.equals(this.north, other.north) &&
209 Objects.equals(this.latitudeDegree, other.latitudeDegree) &&
210 Objects.equals(this.latitudeMinute, other.latitudeMinute) &&
211 Objects.equals(this.latitudeSecond, other.latitudeSecond) &&
212 Objects.equals(this.east, other.east) &&
213 Objects.equals(this.longitudeDegree, other.longitudeDegree) &&
214 Objects.equals(this.longitudeMinute, other.longitudeMinute) &&
215 Objects.equals(this.longitudeSecond, other.longitudeSecond) &&
216 Objects.equals(this.altitude, other.altitude) &&
217 Objects.equals(this.address, other.address);
218 }
219 return false;
220 }
221
222 @Override
223 public String toString() {
224 return toStringHelper(this)
225 .add("north", north)
226 .add("latitude degree", latitudeDegree)
227 .add("latitude minute", latitudeMinute)
228 .add("latitude second", latitudeSecond)
229 .add("east", east)
230 .add("longitude degree", longitudeDegree)
231 .add("longitude minute", longitudeMinute)
232 .add("longitude second", longitudeSecond)
233 .add("altitude", altitude)
234 .add("address", address)
235 .toString();
236 }
237
238 public static final class GeoCoordinateAddressBuilder
239 extends LcafAddressBuilder<GeoCoordinateAddressBuilder> {
240 private boolean north;
241 private short latitudeDegree;
242 private byte latitudeMinute;
243 private byte latitudeSecond;
244 private boolean east;
245 private short longitudeDegree;
246 private byte longitudeMinute;
247 private byte longitudeSecond;
248 private int altitude;
249 private LispAfiAddress address;
250
251 /**
252 * Sets north flag value.
253 *
254 * @param north north flag value
255 * @return GeoCoordinateAddressBuilder object
256 */
257 public GeoCoordinateAddressBuilder withIsNorth(boolean north) {
258 this.north = north;
259 return this;
260 }
261
262 /**
263 * Sets latitude degree.
264 *
265 * @param latitudeDegree latitude degree
266 * @return GeoCoordinateAddressBuilder object
267 */
268 public GeoCoordinateAddressBuilder withLatitudeDegree(short latitudeDegree) {
269 this.latitudeDegree = latitudeDegree;
270 return this;
271 }
272
273 /**
274 * Sets latitude minute.
275 *
276 * @param latitudeMinute latitude minute
277 * @return GeoCoordinateAddressBuilder object
278 */
279 public GeoCoordinateAddressBuilder withLatitudeMinute(byte latitudeMinute) {
280 this.latitudeMinute = latitudeMinute;
281 return this;
282 }
283
284 /**
285 * Sets latitude second.
286 *
287 * @param latitudeSecond latitude second
288 * @return GeoCoordinateAddressBuilder object
289 */
290 public GeoCoordinateAddressBuilder withLatitudeSecond(byte latitudeSecond) {
291 this.latitudeSecond = latitudeSecond;
292 return this;
293 }
294
295 /**
296 * Sets east flag value.
297 *
298 * @param east east flag
299 * @return GeoCoordinateAddressBuilder object
300 */
301 public GeoCoordinateAddressBuilder withIsEast(boolean east) {
302 this.east = east;
303 return this;
304 }
305
306 /**
307 * Sets longitude degree.
308 *
309 * @param longitudeDegree longitude degree
310 * @return GeoCoordinateAddressBuilder object
311 */
312 public GeoCoordinateAddressBuilder withLongitudeDegree(short longitudeDegree) {
313 this.longitudeDegree = longitudeDegree;
314 return this;
315 }
316
317 /**
318 * Sets longitude minute.
319 *
320 * @param longitudeMinute longitude minute
321 * @return GeoCoordinateAddressBuilder object
322 */
323 public GeoCoordinateAddressBuilder withLongitudeMinute(byte longitudeMinute) {
324 this.longitudeMinute = longitudeMinute;
325 return this;
326 }
327
328 /**
329 * Sets longitude second.
330 *
331 * @param longitudeSecond longitude second
332 * @return GeoCoordinateAddressBuilder object
333 */
334 public GeoCoordinateAddressBuilder withLongitudeSecond(byte longitudeSecond) {
335 this.longitudeSecond = longitudeSecond;
336 return this;
337 }
338
339 /**
340 * Sets altitude.
341 *
342 * @param altitude altitude
343 * @return GeoCoordinateAddressBuilder object
344 */
345 public GeoCoordinateAddressBuilder withAltitude(int altitude) {
346 this.altitude = altitude;
347 return this;
348 }
349
350 /**
351 * Sets AFI address.
352 *
353 * @param address AFI address
354 * @return GeoCoordinateAddressBuilder object
355 */
356 public GeoCoordinateAddressBuilder withAddress(LispAfiAddress address) {
357 this.address = address;
358 return this;
359 }
360
361 /**
362 * Builds LispGeoCoordinateLcafAddress instance.
363 *
364 * @return LispGeoCoordinateLcafAddress instance
365 */
366 public LispGeoCoordinateLcafAddress build() {
367
368 checkNotNull(address, "Must specify an AFI address");
369
370 return new LispGeoCoordinateLcafAddress(north, latitudeDegree,
371 latitudeMinute, latitudeSecond, east, longitudeDegree,
372 longitudeMinute, longitudeSecond, altitude, address);
373 }
374 }
375
376 /**
377 * GeoCoordinate LCAF address reader class.
378 */
379 public static class GeoCoordinateLcafAddressReader
380 implements LispAddressReader<LispGeoCoordinateLcafAddress> {
381
382 private static final int NORTH_INDEX = 7;
383 private static final int EAST_INDEX = 7;
384 private static final int FLAG_SHIFT = 8;
385
386 @Override
387 public LispGeoCoordinateLcafAddress readFrom(ByteBuf byteBuf)
388 throws LispParseError, LispReaderException {
389
390 LispLcafAddress.deserializeCommon(byteBuf);
391
392 // north flag -> 1 bit
393 byte flagWithLatitude = byteBuf.readByte();
394
395 boolean north = ByteOperator.getBit(flagWithLatitude, NORTH_INDEX);
396
397 // latitude degree -> 15 bits
398 short latitudeFirst = flagWithLatitude;
399 if (north) {
400 latitudeFirst = (short) (flagWithLatitude & 0x7F);
401 }
402 short latitude = (short) ((latitudeFirst << FLAG_SHIFT) + byteBuf.readByte());
403
404 // latitude minute -> 8 bits
405 byte latitudeMinute = byteBuf.readByte();
406
407 // latitude second -> 8 bits
408 byte latitudeSecond = byteBuf.readByte();
409
410 // east flag -> 1 bit
411 byte flagWithLongitude = byteBuf.readByte();
412
413 boolean east = ByteOperator.getBit(flagWithLongitude, EAST_INDEX);
414
415 // longitude degree -> 15 bits
416 short longitudeFirst = flagWithLongitude;
417 if (east) {
418 longitudeFirst = (short) (flagWithLongitude & 0x7F);
419 }
420 short longitude = (short) ((longitudeFirst << FLAG_SHIFT) + byteBuf.readByte());
421
422 // longitude minute -> 8 bits
423 byte longitudeMinute = byteBuf.readByte();
424
425 // longitude second -> 8 bits
426 byte longitudeSecond = byteBuf.readByte();
427
428 // altitude -> 32 bits
429 int altitude = byteBuf.readInt();
430
431 LispAfiAddress address = new AfiAddressReader().readFrom(byteBuf);
432
433 return new GeoCoordinateAddressBuilder()
434 .withIsNorth(north)
435 .withLatitudeDegree(latitude)
436 .withLatitudeMinute(latitudeMinute)
437 .withLatitudeSecond(latitudeSecond)
438 .withIsEast(east)
439 .withLongitudeDegree(longitude)
440 .withLongitudeMinute(longitudeMinute)
441 .withLongitudeSecond(longitudeSecond)
442 .withAltitude(altitude)
443 .withAddress(address)
444 .build();
445 }
446 }
447
448 /**
449 * GeoCoordinate LCAF address writer class.
450 */
451 public static class GeoCoordinateLcafAddressWriter
452 implements LispAddressWriter<LispGeoCoordinateLcafAddress> {
453
454 private static final int NORTH_SHIFT_BIT = 15;
455 private static final int EAST_SHIFT_BIT = 15;
456
457 private static final int ENABLE_BIT = 1;
458 private static final int DISABLE_BIT = 0;
459
460 @Override
461 public void writeTo(ByteBuf byteBuf, LispGeoCoordinateLcafAddress address)
462 throws LispWriterException {
463
464 int lcafIndex = byteBuf.writerIndex();
465 LispLcafAddress.serializeCommon(byteBuf, address);
466
467 // north flag + latitude degree
468 short north = DISABLE_BIT;
469 if (address.isNorth()) {
470 north = (short) (ENABLE_BIT << NORTH_SHIFT_BIT);
471 }
472
473 byteBuf.writeShort(north + address.latitudeDegree);
474
475 // latitude minute
476 byteBuf.writeByte(address.latitudeMinute);
477
478 // latitude second
479 byteBuf.writeByte(address.latitudeSecond);
480
481 // east flag + longitude degree
482 short east = DISABLE_BIT;
483 if (address.isEast()) {
484 east = (short) (ENABLE_BIT << EAST_SHIFT_BIT);
485 }
486
487 byteBuf.writeShort(east + address.longitudeDegree);
488
489 // longitude minute
490 byteBuf.writeByte(address.longitudeMinute);
491
492 // longitude second
493 byteBuf.writeByte(address.longitudeSecond);
494
495 // altitude
496 byteBuf.writeInt(address.altitude);
497
498 // address
499 AfiAddressWriter writer = new AfiAddressWriter();
500 writer.writeTo(byteBuf, address.getAddress());
501
502 LispLcafAddress.updateLength(lcafIndex, byteBuf);
503 }
504 }
505}