/* * Copyright 2016-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.lisp.msg.types.lcaf; import io.netty.buffer.ByteBuf; import org.onosproject.lisp.msg.exceptions.LispParseError; import org.onosproject.lisp.msg.exceptions.LispReaderException; import org.onosproject.lisp.msg.exceptions.LispWriterException; import org.onosproject.lisp.msg.types.LispAddressReader; import org.onosproject.lisp.msg.types.LispAddressWriter; import org.onosproject.lisp.msg.types.LispAfiAddress; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Objects; import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; /** * Application data type LCAF address class. * <p> * Application data type is defined in draft-ietf-lisp-lcaf-22 * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-22#page-29 * * <pre> * {@literal * 0 1 2 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | AFI = 16387 | Rsvd1 | Flags | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type = 4 | Rsvd2 | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | IP TOS, IPv6 TC, or Flow Label | Protocol | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Local Port (lower-range) | Local Port (upper-range) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Remote Port (lower-range) | Remote Port (upper-range) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | AFI = x | Address ... | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * }</pre> */ public final class LispAppDataLcafAddress extends LispLcafAddress { private final byte protocol; private final int ipTos; private final short localPortLow; private final short localPortHigh; private final short remotePortLow; private final short remotePortHigh; private LispAfiAddress address; /** * Initializes application data type LCAF address. * * @param protocol protocol number * @param ipTos IP type of service * @param localPortLow low-ranged local port number * @param localPortHigh high-ranged local port number * @param remotePortLow low-ranged remote port number * @param remotePortHigh high-ranged remote port number * @param address address */ private LispAppDataLcafAddress(byte protocol, int ipTos, short localPortLow, short localPortHigh, short remotePortLow, short remotePortHigh, LispAfiAddress address) { super(LispCanonicalAddressFormatEnum.APPLICATION_DATA); this.protocol = protocol; this.ipTos = ipTos; this.localPortLow = localPortLow; this.localPortHigh = localPortHigh; this.remotePortLow = remotePortLow; this.remotePortHigh = remotePortHigh; this.address = address; } /** * Initializes application data type LCAF address. * * @param reserved1 reserved1 * @param reserved2 reserved2 * @param flag flag * @param length length * @param protocol protocol number * @param ipTos IP type of service * @param localPortLow low-ranged local port number * @param localPortHigh high-ranged local port number * @param remotePortLow low-ranged remote port number * @param remotePortHigh high-ranged remote port number * @param address address */ private LispAppDataLcafAddress(byte reserved1, byte reserved2, byte flag, short length, byte protocol, int ipTos, short localPortLow, short localPortHigh, short remotePortLow, short remotePortHigh, LispAfiAddress address) { super(LispCanonicalAddressFormatEnum.APPLICATION_DATA, reserved1, reserved2, flag, length); this.protocol = protocol; this.ipTos = ipTos; this.localPortLow = localPortLow; this.localPortHigh = localPortHigh; this.remotePortLow = remotePortLow; this.remotePortHigh = remotePortHigh; this.address = address; } /** * Obtains protocol number. * * @return protocol number */ public byte getProtocol() { return protocol; } /** * Obtains IP type of service. * * @return IP type of service */ public int getIpTos() { return ipTos; } /** * Obtains low-ranged local port number. * * @return low-ranged local port number */ public short getLocalPortLow() { return localPortLow; } /** * Obtains high-ranged local port number. * * @return high-ranged local port number */ public short getLocalPortHigh() { return localPortHigh; } /** * Obtains low-ranged remote port number. * * @return low-ranged remote port number */ public short getRemotePortLow() { return remotePortLow; } /** * Obtains high-ranged remote port number. * * @return high-ranged remote port number */ public short getRemotePortHigh() { return remotePortHigh; } /** * Obtains address. * * @return address */ public LispAfiAddress getAddress() { return address; } @Override public int hashCode() { return Objects.hash(address, protocol, ipTos, localPortLow, localPortHigh, remotePortLow, remotePortHigh); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof LispAppDataLcafAddress) { final LispAppDataLcafAddress other = (LispAppDataLcafAddress) obj; return Objects.equals(this.address, other.address) && Objects.equals(this.protocol, other.protocol) && Objects.equals(this.ipTos, other.ipTos) && Objects.equals(this.localPortLow, other.localPortLow) && Objects.equals(this.localPortHigh, other.localPortHigh) && Objects.equals(this.remotePortLow, other.remotePortLow) && Objects.equals(this.remotePortHigh, other.remotePortHigh); } return false; } @Override public String toString() { return toStringHelper(this) .add("address", address) .add("protocol", protocol) .add("ip type of service", ipTos) .add("low-ranged local port number", localPortLow) .add("high-ranged local port number", localPortHigh) .add("low-ranged remote port number", remotePortLow) .add("high-ranged remote port number", remotePortHigh) .toString(); } public static final class AppDataAddressBuilder extends LcafAddressBuilder<AppDataAddressBuilder> { private byte protocol; private int ipTos; private short localPortLow; private short localPortHigh; private short remotePortLow; private short remotePortHigh; private LispAfiAddress address; /** * Sets protocol number. * * @param protocol protocol number * @return AppDataAddressBuilder object */ public AppDataAddressBuilder withProtocol(byte protocol) { this.protocol = protocol; return this; } /** * Sets IP type of service. * * @param ipTos IP type of service * @return AppDataAddressBuilder object */ public AppDataAddressBuilder withIpTos(int ipTos) { this.ipTos = ipTos; return this; } /** * Sets low-ranged local port number. * * @param localPortLow low-ranged local port number * @return AppDataAddressBuilder object */ public AppDataAddressBuilder withLocalPortLow(short localPortLow) { this.localPortLow = localPortLow; return this; } /** * Sets high-ranged local port number. * * @param localPortHigh high-ranged local port number * @return AppDataAddressBuilder object */ public AppDataAddressBuilder withLocalPortHigh(short localPortHigh) { this.localPortHigh = localPortHigh; return this; } /** * Sets low-ranged remote port number. * * @param remotePortLow low-ranged remote port number * @return AppDataAddressBuilder object */ public AppDataAddressBuilder withRemotePortLow(short remotePortLow) { this.remotePortLow = remotePortLow; return this; } /** * Sets high-ranged remote port number. * * @param remotePortHigh high-ranged remote port number * @return AppDataAddressBuilder object */ public AppDataAddressBuilder withRemotePortHigh(short remotePortHigh) { this.remotePortHigh = remotePortHigh; return this; } /** * Sets AFI address. * * @param address AFI address * @return AppDataAddressBuilder object */ public AppDataAddressBuilder withAddress(LispAfiAddress address) { this.address = address; return this; } /** * Builds LispAppDataLcafAddress instance. * * @return LispAddDataLcafAddress instance */ public LispAppDataLcafAddress build() { checkNotNull(address, "Must specify an address"); return new LispAppDataLcafAddress(reserved1, reserved2, flag, length, protocol, ipTos, localPortLow, localPortHigh, remotePortLow, remotePortHigh, address); } } /** * Application data LCAF address reader class. */ public static class AppDataLcafAddressReader implements LispAddressReader<LispAppDataLcafAddress> { @Override public LispAppDataLcafAddress readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException { LispLcafAddress.deserializeCommon(byteBuf); byte[] ipTosByte = new byte[3]; byteBuf.readBytes(ipTosByte); byte protocol = (byte) byteBuf.readUnsignedByte(); int ipTos = getPartialInt(ipTosByte); short localPortLow = (short) byteBuf.readUnsignedShort(); short localPortHigh = (short) byteBuf.readUnsignedShort(); short remotePortLow = (short) byteBuf.readUnsignedShort(); short remotePortHigh = (short) byteBuf.readUnsignedShort(); LispAfiAddress address = new LispAfiAddress.AfiAddressReader().readFrom(byteBuf); return new AppDataAddressBuilder() .withProtocol(protocol) .withIpTos(ipTos) .withLocalPortLow(localPortLow) .withLocalPortHigh(localPortHigh) .withRemotePortLow(remotePortLow) .withRemotePortHigh(remotePortHigh) .withAddress(address) .build(); } /** * An utility function that obtains the partial int value from byte arrays. * * @param bytes an array of bytes * @return converted integer */ public static int getPartialInt(byte[] bytes) { ByteBuffer buffer = ByteBuffer.allocate(4); buffer.position(4 - bytes.length); buffer.put(bytes); buffer.position(0); return buffer.getInt(); } } /** * Application data LCAF address writer class. */ public static class AppDataLcafAddressWriter implements LispAddressWriter<LispAppDataLcafAddress> { @Override public void writeTo(ByteBuf byteBuf, LispAppDataLcafAddress address) throws LispWriterException { int lcafIndex = byteBuf.writerIndex(); LispLcafAddress.serializeCommon(byteBuf, address); byte[] tos = getPartialByteArray(address.getIpTos()); byteBuf.writeBytes(tos); byteBuf.writeByte(address.getProtocol()); byteBuf.writeShort(address.getLocalPortLow()); byteBuf.writeShort(address.getLocalPortHigh()); byteBuf.writeShort(address.getRemotePortLow()); byteBuf.writeShort(address.getRemotePortHigh()); LispAfiAddress.AfiAddressWriter writer = new LispAfiAddress.AfiAddressWriter(); writer.writeTo(byteBuf, address.getAddress()); LispLcafAddress.updateLength(lcafIndex, byteBuf); } /** * An utility function that obtains byte array from partial int value. * * @param value integer value * @return an array of bytes */ public static byte[] getPartialByteArray(int value) { ByteBuffer buffer = ByteBuffer.allocate(4); byte[] array = buffer.putInt(value).array(); return Arrays.copyOfRange(array, 1, 4); } } }