From ca814bfbee3966d6011b4bd753ef0e32c5bd2f4b Mon Sep 17 00:00:00 2001 From: Yoonseon Han Date: Mon, 12 Sep 2016 11:37:48 -0700 Subject: [PATCH] [ONOS-5480] The implementation of LISP Encapsulated Control Message (ECM). Changes 1. ECM message is added. 2. Default ECM message is added with builder, reader, and writer. 3. Implented other messages writeTo() methods. Change-Id: I3ed6f66a7ec7a318f30596d64c35ac15365c8c4c --- .../DefaultLispEncapsulatedControl.java | 271 ++++++++++++++++++ .../lisp/msg/protocols/DefaultLispInfo.java | 4 +- .../protocols/DefaultLispLocatorRecord.java | 9 +- .../msg/protocols/DefaultLispMapNotify.java | 9 +- .../msg/protocols/DefaultLispMapRecord.java | 9 +- .../msg/protocols/DefaultLispMapRegister.java | 9 +- .../msg/protocols/DefaultLispMapReply.java | 9 +- .../msg/protocols/DefaultLispMapRequest.java | 9 +- .../protocols/LispEncapsulatedControl.java | 132 +++++++++ .../lisp/msg/protocols/LispLocatorRecord.java | 3 +- .../lisp/msg/protocols/LispMapRecord.java | 3 +- .../lisp/msg/protocols/LispMessage.java | 5 +- .../lisp/msg/protocols/LispMessageReader.java | 12 +- .../protocols/LispMessageReaderFactory.java | 22 +- .../lisp/msg/protocols/LispType.java | 26 +- .../DefaultLispEncapsulatedControlTest.java | 212 ++++++++++++++ 16 files changed, 713 insertions(+), 31 deletions(-) create mode 100644 protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControl.java create mode 100644 protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEncapsulatedControl.java create mode 100644 protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControlTest.java diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControl.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControl.java new file mode 100644 index 0000000000..36782c2992 --- /dev/null +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControl.java @@ -0,0 +1,271 @@ +/* + * 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.protocols; + +import com.google.common.base.Objects; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.onlab.packet.Data; +import org.onlab.packet.DeserializationException; +import org.onlab.packet.IP; +import org.onlab.packet.UDP; +import org.onlab.util.ByteOperator; +import org.onosproject.lisp.msg.exceptions.LispParseError; +import org.onosproject.lisp.msg.exceptions.LispReaderException; +import org.onosproject.lisp.msg.exceptions.LispWriterException; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static org.onosproject.lisp.msg.protocols.LispType.LISP_ENCAPSULATED_CONTROL; + +/** + * Default LISP Encapsulated Control message class. + */ +public final class DefaultLispEncapsulatedControl + implements LispEncapsulatedControl { + + private final boolean isSecurity; + private final IP innerIpHeader; + private final UDP innerUdp; + private final LispMessage innerMessage; + + static final EcmWriter WRITER; + static { + WRITER = new EcmWriter(); + } + + /** + * A private constructor that protects object instantiation from external. + * + * @param isSecurity a security flag + * @param innerIpHeader a inner IP Header + * @param innerUdp a inner UDP Header + * @param innerMessage a inner LISP control message + */ + private DefaultLispEncapsulatedControl(boolean isSecurity, IP innerIpHeader, + UDP innerUdp, LispMessage innerMessage) { + this.isSecurity = isSecurity; + this.innerIpHeader = innerIpHeader; + this.innerUdp = innerUdp; + this.innerMessage = innerMessage; + } + + @Override + public LispType getType() { + return LISP_ENCAPSULATED_CONTROL; + } + + @Override + public void writeTo(ByteBuf byteBuf) throws LispWriterException { + WRITER.writeTo(byteBuf, this); + } + + @Override + public Builder createBuilder() { + return new DefaultEcmBuilder(); + } + + @Override + public boolean isSecurity() { + return isSecurity; + } + + @Override + public IP innerIpHeader() { + return innerIpHeader; + } + + public UDP innerUdp() { + return innerUdp; + } + + @Override + public LispMessage getControlMessage() { + return innerMessage; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("type", getType()) + .add("isSecurity", isSecurity) + .add("inner IP header", innerIpHeader) + .add("inner UDP header", innerUdp) + .add("inner lisp Message", innerMessage) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DefaultLispEncapsulatedControl that = (DefaultLispEncapsulatedControl) o; + return Objects.equal(isSecurity, that.isSecurity) && + Objects.equal(innerIpHeader, that.innerIpHeader) && + Objects.equal(innerUdp, that.innerUdp) && + Objects.equal(innerMessage, that.innerMessage); + } + + @Override + public int hashCode() { + return Objects.hashCode(isSecurity, innerIpHeader, innerUdp, innerMessage); + } + + /** + * LISP ECM Builder implementation. + */ + public static final class DefaultEcmBuilder implements EcmBuilder { + + private boolean isSecurity; + private IP innerIpHeader; + private UDP innerUdpHeader; + private LispMessage innerMessage; + + @Override + public LispType getType() { + return LispType.LISP_ENCAPSULATED_CONTROL; + } + + @Override + public EcmBuilder isSecurity(boolean security) { + this.isSecurity = security; + return this; + } + + @Override + public EcmBuilder innerIpHeader(IP innerIpHeader) { + this.innerIpHeader = innerIpHeader; + return this; + } + + @Override + public EcmBuilder innerUdpHeader(UDP innerUdpHeader) { + this.innerUdpHeader = innerUdpHeader; + return this; + } + + @Override + public EcmBuilder innerLispMessage(LispMessage msg) { + this.innerMessage = msg; + return this; + } + + @Override + public LispEncapsulatedControl build() { + return new DefaultLispEncapsulatedControl(isSecurity, innerIpHeader, + innerUdpHeader, innerMessage); + } + } + + /** + * A LISP message reader for ECM. + */ + public static final class EcmReader + implements LispMessageReader { + + private static final int SECURITY_INDEX = 3; + private static final int RESERVED_SKIP_LENGTH = 3; + private static final int UDP_HEADER_LENGTH = 8; + private static final short HEADER_LENGTH_MASK = 0xf; + + @Override + public LispEncapsulatedControl readFrom(ByteBuf byteBuf) throws + LispParseError, LispReaderException, DeserializationException { + + if (byteBuf.readerIndex() != 0) { + return null; + } + + boolean securityFlag = ByteOperator.getBit(byteBuf.readByte(), + SECURITY_INDEX); + // let's skip the reserved field + byteBuf.skipBytes(RESERVED_SKIP_LENGTH); + + short totalLength = byteBuf.getShort(byteBuf.readerIndex() + 2); + + byte[] ipHeaderByte = new byte[totalLength]; + byteBuf.getBytes(byteBuf.readerIndex(), ipHeaderByte, 0, totalLength); + + IP innerIpHeader = IP.deserializer().deserialize(ipHeaderByte, 0, + totalLength); + + UDP innerUdp = (UDP) innerIpHeader.getPayload(); + Data data = (Data) innerUdp.getPayload(); + ByteBuf msgBuffer = Unpooled.buffer(); + msgBuffer.writeBytes(data.getData()); + + LispMessageReader reader = LispMessageReaderFactory.getReader(msgBuffer); + LispMessage innerMessage = (LispMessage) reader.readFrom(msgBuffer); + + return new DefaultLispEncapsulatedControl(securityFlag, innerIpHeader, + innerUdp, innerMessage); + } + } + + /** + * LISP ECM writer class. + */ + public static class EcmWriter + implements LispMessageWriter { + + private static final short ECM_MSG_CODE = + LispType.LISP_ENCAPSULATED_CONTROL.getTypeCode(); + private static final int TYPE_SHIFT_BIT = 4; + + private static final int SECURITY_SHIFT_BIT = 3; + + private static final int ENABLE_BIT = 1; + private static final int DISABLE_BIT = 0; + + private static final int UNUSED_ZERO = 0; + + @Override + public void writeTo(ByteBuf byteBuf, LispEncapsulatedControl message) + throws LispWriterException { + + // specify LISP message type + byte msgType = (byte) (ECM_MSG_CODE << TYPE_SHIFT_BIT); + + byte security = DISABLE_BIT; + if (message.isSecurity()) { + security = (byte) (ENABLE_BIT << SECURITY_SHIFT_BIT); + } + + byteBuf.writeByte(msgType + security); + + // fill zero into reserved field + byteBuf.writeByte((byte) UNUSED_ZERO); + byteBuf.writeByte((byte) UNUSED_ZERO); + byteBuf.writeByte((byte) UNUSED_ZERO); + + ByteBuf buffer = Unpooled.buffer(); + message.getControlMessage().writeTo(buffer); + byte[] dataBytes = new byte[buffer.writerIndex()]; + buffer.getBytes(0, dataBytes, 0, buffer.writerIndex()); + + message.innerUdp().setPayload(new Data(dataBytes)); + message.innerIpHeader().setPayload(message.innerUdp()); + + byteBuf.writeBytes(message.innerIpHeader().serialize()); + } + } + +} diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfo.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfo.java index 14cd8842ac..74132452b8 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfo.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfo.java @@ -82,8 +82,8 @@ public class DefaultLispInfo implements LispInfo { } @Override - public void writeTo(ByteBuf byteBuf) { - // TODO: serialize LispMapRegister message + public void writeTo(ByteBuf byteBuf) throws LispWriterException { + serialize(byteBuf, this); } @Override diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecord.java index 0b5407e23b..e242a5d4f8 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecord.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecord.java @@ -41,6 +41,11 @@ public final class DefaultLispLocatorRecord implements LispLocatorRecord { private final boolean routed; private final LispAfiAddress locatorAfi; + static final LocatorRecordWriter WRITER; + static { + WRITER = new LocatorRecordWriter(); + } + /** * A private constructor that protects object instantiation from external. * @@ -107,8 +112,8 @@ public final class DefaultLispLocatorRecord implements LispLocatorRecord { } @Override - public void writeTo(ByteBuf byteBuf) { - + public void writeTo(ByteBuf byteBuf) throws LispWriterException { + WRITER.writeTo(byteBuf, this); } @Override diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java index 79317f8574..cb18b8ffe8 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java @@ -41,6 +41,11 @@ public final class DefaultLispMapNotify implements LispMapNotify { private final byte[] authenticationData; private final List mapRecords; + static final NotifyWriter WRITER; + static { + WRITER = new NotifyWriter(); + } + /** * A private constructor that protects object instantiation from external. * @@ -64,8 +69,8 @@ public final class DefaultLispMapNotify implements LispMapNotify { } @Override - public void writeTo(ByteBuf byteBuf) { - // TODO: serialize LispMapRegister message + public void writeTo(ByteBuf byteBuf) throws LispWriterException { + WRITER.writeTo(byteBuf, this); } @Override diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java index 9c4becedc1..d18e238872 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java @@ -45,6 +45,11 @@ public final class DefaultLispMapRecord implements LispMapRecord { private final LispAfiAddress eidPrefixAfi; private final List locatorRecords; + static final MapRecordWriter WRITER; + static { + WRITER = new MapRecordWriter(); + } + /** * A private constructor that protects object instantiation from external. * @@ -109,8 +114,8 @@ public final class DefaultLispMapRecord implements LispMapRecord { } @Override - public void writeTo(ByteBuf byteBuf) { - + public void writeTo(ByteBuf byteBuf) throws LispWriterException { + WRITER.writeTo(byteBuf, this); } @Override diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java index b45d1e60eb..58244d7686 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java @@ -46,6 +46,11 @@ public final class DefaultLispMapRegister implements LispMapRegister { private final boolean proxyMapReply; private final boolean wantMapNotify; + static final RegisterWriter WRITER; + static { + WRITER = new RegisterWriter(); + } + /** * A private constructor that protects object instantiation from external. * @@ -75,8 +80,8 @@ public final class DefaultLispMapRegister implements LispMapRegister { } @Override - public void writeTo(ByteBuf byteBuf) { - // TODO: serialize LispMapRegister message + public void writeTo(ByteBuf byteBuf) throws LispWriterException { + WRITER.writeTo(byteBuf, this); } @Override diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java index 59775f44b8..5773be8b9e 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java @@ -40,6 +40,11 @@ public final class DefaultLispMapReply implements LispMapReply { private final boolean security; private final List mapRecords; + static final ReplyWriter WRITER; + static { + WRITER = new ReplyWriter(); + } + /** * A private constructor that protects object instantiation from external. * @@ -63,8 +68,8 @@ public final class DefaultLispMapReply implements LispMapReply { } @Override - public void writeTo(ByteBuf byteBuf) { - // TODO: serialize LispMapReply message + public void writeTo(ByteBuf byteBuf) throws LispWriterException { + WRITER.writeTo(byteBuf, this); } @Override diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java index 75f73b5132..34ec469c0e 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java @@ -49,6 +49,11 @@ public final class DefaultLispMapRequest implements LispMapRequest { private final boolean pitr; private final boolean smrInvoked; + static final RequestWriter WRITER; + static { + WRITER = new RequestWriter(); + } + /** * A private constructor that protects object instantiation from external. * @@ -85,8 +90,8 @@ public final class DefaultLispMapRequest implements LispMapRequest { } @Override - public void writeTo(ByteBuf byteBuf) { - // TODO: serialize LispMapRequest message + public void writeTo(ByteBuf byteBuf) throws LispWriterException { + WRITER.writeTo(byteBuf, this); } @Override diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEncapsulatedControl.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEncapsulatedControl.java new file mode 100644 index 0000000000..f8113ab7f0 --- /dev/null +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEncapsulatedControl.java @@ -0,0 +1,132 @@ +/* + * 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.protocols; + +import org.onlab.packet.IP; +import org.onlab.packet.UDP; + +/** + * LISP Encapsulated Control Message (ECM) interface. + *

+ * LISP ECM format is defined in RFC6830. + * https://tools.ietf.org/html/rfc6830#section-6.1.8 + * + *

+ * {@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
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * /   |                       IPv4 or IPv6 Header                     |
+ * OH  |                      (uses RLOC addresses)                    |
+ * \   |                                                               |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * /   |       Source Port = xxxx      |       Dest Port = 4342        |
+ * UDP +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * \   |           UDP Length          |        UDP Checksum           |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * LH  |Type=8 |S|                  Reserved                           |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * /   |                       IPv4 or IPv6 Header                     |
+ * IH  |                  (uses RLOC or EID addresses)                 |
+ * \   |                                                               |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * /   |       Source Port = xxxx      |       Dest Port = yyyy        |
+ * UDP +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * \   |           UDP Length          |        UDP Checksum           |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * LCM |                      LISP Control Message                     |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * }
+ */ +public interface LispEncapsulatedControl extends LispMessage { + + /** + * Obtains security flag. + * If this bit is set, the 'Reserved' field will have the authentication data. + * + * @return security flag + */ + boolean isSecurity(); + + /** + * Obtains inner IP header. + * + * @return inner IP header + */ + IP innerIpHeader(); + + /** + * Obtains inner LISP UDP header. + * + * @return inner LISP UDP header + */ + UDP innerUdp(); + + /** + * Obtains inner LISP control message. + * The format can be one of other LISP messages. + * + * @return Inner lisp control messages + */ + + LispMessage getControlMessage(); + + /** + * A builder of LISP map request message. + */ + interface EcmBuilder extends Builder { + + /** + * Sets security flag. + * + * @param security security flag + * @return ECMBuilder object + */ + EcmBuilder isSecurity(boolean security); + + /** + * Sets inner IP header. + * + * @param innerIpHeader inner IP header in IPv4 or IPv6 + * @return ECMBuilder object + */ + EcmBuilder innerIpHeader(IP innerIpHeader); + + /** + * Sets inner UDP header. + * + * @param innerUdpHeader inner UDP packet + * @return ECMBuilder object + */ + EcmBuilder innerUdpHeader(UDP innerUdpHeader); + + /** + * Sets inner LISP control message. + * + * @param msg the inner lisp message + * @return ECMBuilder object + */ + EcmBuilder innerLispMessage(LispMessage msg); + + /** + * Builds LISP ECM message. + * + * @return LISP ECM message + */ + LispEncapsulatedControl build(); + } +} diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispLocatorRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispLocatorRecord.java index ca18e0b8fc..35aa1dad4f 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispLocatorRecord.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispLocatorRecord.java @@ -16,6 +16,7 @@ package org.onosproject.lisp.msg.protocols; import io.netty.buffer.ByteBuf; +import org.onosproject.lisp.msg.exceptions.LispWriterException; import org.onosproject.lisp.msg.types.LispAfiAddress; /** @@ -84,7 +85,7 @@ public interface LispLocatorRecord { * * @param byteBuf byte buffer */ - void writeTo(ByteBuf byteBuf); + void writeTo(ByteBuf byteBuf) throws LispWriterException; /** * A builder of LISP locator record. diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java index 4e8536cb19..d710ebc4f6 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java @@ -16,6 +16,7 @@ package org.onosproject.lisp.msg.protocols; import io.netty.buffer.ByteBuf; +import org.onosproject.lisp.msg.exceptions.LispWriterException; import org.onosproject.lisp.msg.types.LispAfiAddress; import java.util.List; @@ -86,7 +87,7 @@ public interface LispMapRecord { * * @param byteBuf byte buffer */ - void writeTo(ByteBuf byteBuf); + void writeTo(ByteBuf byteBuf) throws LispWriterException; /** * A builder of LISP map record. diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessage.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessage.java index 6962b3b3c3..4e3cdfa281 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessage.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessage.java @@ -16,6 +16,7 @@ package org.onosproject.lisp.msg.protocols; import io.netty.buffer.ByteBuf; +import org.onosproject.lisp.msg.exceptions.LispWriterException; /** * LISP message interface. @@ -33,8 +34,10 @@ public interface LispMessage { * Writes LISP message object into communication channel. * * @param byteBuf byte buffer + * @throws LispWriterException if the writing request is failed due to + * the lisp object cannot be written to the buffer. */ - void writeTo(ByteBuf byteBuf); + void writeTo(ByteBuf byteBuf) throws LispWriterException; /** * Generates LISP message builder. diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReader.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReader.java index d2b55941a2..2b53983f31 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReader.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReader.java @@ -16,6 +16,7 @@ package org.onosproject.lisp.msg.protocols; import io.netty.buffer.ByteBuf; +import org.onlab.packet.DeserializationException; import org.onosproject.lisp.msg.exceptions.LispParseError; import org.onosproject.lisp.msg.exceptions.LispReaderException; @@ -29,7 +30,14 @@ public interface LispMessageReader { * * @param byteBuf byte buffer * @return LISP message instance - * @throws LispParseError LISP control message parse error + * @throws LispParseError if the requested message cannot be parsed + * as a LISP object + * @throws LispReaderException if LISP message reader cannot process + * the received message + * @throws DeserializationException if an inner IP header (IPv4 or IPv6) + * cannot be deserialized due to the message not match + * with IP header format */ - T readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException; + T readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException, + DeserializationException; } diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReaderFactory.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReaderFactory.java index e6a90d8b64..2798cc9630 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReaderFactory.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReaderFactory.java @@ -21,6 +21,7 @@ import static org.onosproject.lisp.msg.protocols.DefaultLispMapReply.ReplyReader import static org.onosproject.lisp.msg.protocols.DefaultLispMapNotify.NotifyReader; import static org.onosproject.lisp.msg.protocols.DefaultLispMapRegister.RegisterReader; import static org.onosproject.lisp.msg.protocols.DefaultLispMapRequest.RequestReader; +import static org.onosproject.lisp.msg.protocols.DefaultLispEncapsulatedControl.EcmReader; /** * A factory class which helps to instantiate LISP reader class. @@ -39,22 +40,31 @@ public final class LispMessageReaderFactory { public static LispMessageReader getReader(ByteBuf buffer) { LispMessageReader reader; - int type = buffer.getByte(0) >> TYPE_SHIFT_BIT; + LispType type = LispType.valueOf( + (short) (buffer.getByte(0) >> TYPE_SHIFT_BIT)); + switch (type) { - case 1: + case LISP_MAP_REQUEST: reader = new RequestReader(); break; - case 2: + case LISP_MAP_REPLY: reader = new ReplyReader(); break; - case 3: + case LISP_MAP_REGISTER: reader = new RegisterReader(); break; - case 4: + case LISP_MAP_NOTIFY: reader = new NotifyReader(); break; + case LISP_ENCAPSULATED_CONTROL: + reader = new EcmReader(); + break; + case UNKNOWN: + throw new IllegalArgumentException("Unknown message type: " + + type); default: - throw new IllegalArgumentException("Unknown LISP message type: " + type); + throw new IllegalArgumentException("Undefined message type: " + + type); } return reader; } diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispType.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispType.java index aeacc00b04..b039ac76ad 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispType.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispType.java @@ -23,12 +23,26 @@ package org.onosproject.lisp.msg.protocols; */ public enum LispType { - LISP_MAP_REQUEST(1), // LISP Map-Request Message - LISP_MAP_REPLY(2), // LISP Map-Reply Message - LISP_MAP_REGISTER(3), // LISP Map-Register Message - LISP_MAP_NOTIFY(4), // LISP Map-Notify Message - LISP_INFO(7), // LISP Info-Request or Info-Reply Message - UNKNOWN(-1); // Other Enums for internal use + /** LISP Map-Request Message. */ + LISP_MAP_REQUEST(1), + + /** LISP Map-Reply Message. */ + LISP_MAP_REPLY(2), + + /** LISP Map-Register Message. */ + LISP_MAP_REGISTER(3), + + /** LISP Map-Notify Message. */ + LISP_MAP_NOTIFY(4), + + /** LISP Info-Request or Info-Reply Message. */ + LISP_INFO(7), + + /** LISP Encapsulated Control Message. */ + LISP_ENCAPSULATED_CONTROL(8), + + /** Unknown types for internal use. */ + UNKNOWN(-1); private final short type; diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControlTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControlTest.java new file mode 100644 index 0000000000..fa64950173 --- /dev/null +++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControlTest.java @@ -0,0 +1,212 @@ +/* + * 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.protocols; + +import com.google.common.collect.ImmutableList; +import com.google.common.testing.EqualsTester; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.DeserializationException; +import org.onlab.packet.IP; +import org.onlab.packet.IPv4; +import org.onlab.packet.IpAddress; +import org.onlab.packet.UDP; +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.LispIpv4Address; + +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +/** + * Unit tests for DefaultLispEncapsulatedControl class. + */ +public final class DefaultLispEncapsulatedControlTest { + + private static final String ECM1_SRC_IP = "192.168.1.1"; + private static final String ECM1_DST_IP = "192.168.1.2"; + private static final String ECM2_SRC_IP = "192.168.2.1"; + private static final String ECM2_DST_IP = "192.168.2.2"; + private static final String RECORD_EID = "1.1.1.1"; + + private LispEncapsulatedControl ecm1; + private LispEncapsulatedControl sameAsEcm1; + private LispEncapsulatedControl ecm2; + + @Before + public void setup() { + + //Creates ecm1 + LispEncapsulatedControl.EcmBuilder builder1 = + new DefaultLispEncapsulatedControl.DefaultEcmBuilder(); + + IP innerIp1 = new IPv4().setSourceAddress(ECM1_SRC_IP) + .setDestinationAddress(ECM1_DST_IP) + .setProtocol(IPv4.PROTOCOL_UDP).setVersion((byte) (4 & 0xf)); + UDP innerUdp1 = new UDP().setSourcePort(1) + .setDestinationPort(2); + + LispMapRegister.RegisterBuilder msgBuilder = new + DefaultLispMapRegister.DefaultRegisterBuilder(); + + List records1 = ImmutableList.of(getMapRecord(), + getMapRecord()); + + LispMapRegister innerMsg1 = msgBuilder.withIsProxyMapReply(true) + .withIsWantMapNotify(false) + .withKeyId((short) 1) + .withNonce(1L) + .withMapRecords(records1) + .build(); + + ecm1 = builder1.isSecurity(false) + .innerIpHeader(innerIp1) + .innerUdpHeader(innerUdp1) + .innerLispMessage(innerMsg1) + .build(); + + //Creates sameAsEcm1 + LispEncapsulatedControl.EcmBuilder builder2 = + new DefaultLispEncapsulatedControl.DefaultEcmBuilder(); + + IP innerIp2 = new IPv4().setSourceAddress(ECM1_SRC_IP) + .setDestinationAddress(ECM1_DST_IP) + .setProtocol(IPv4.PROTOCOL_UDP); + UDP innerUdp2 = new UDP().setSourcePort(1) + .setDestinationPort(2); + + LispMapRegister.RegisterBuilder msgBuilder2 = + new DefaultLispMapRegister.DefaultRegisterBuilder(); + + List records2 = ImmutableList.of(getMapRecord(), + getMapRecord()); + + LispMapRegister innerMsg2 = msgBuilder2.withIsProxyMapReply(true) + .withIsWantMapNotify(false) + .withKeyId((short) 1) + .withNonce(1L) + .withMapRecords(records2) + .build(); + + sameAsEcm1 = builder2.isSecurity(false) + .innerIpHeader(innerIp2) + .innerUdpHeader(innerUdp2) + .innerLispMessage(innerMsg2) + .build(); + + //Creates ecm2 + LispEncapsulatedControl.EcmBuilder builder3 = + new DefaultLispEncapsulatedControl.DefaultEcmBuilder(); + + IP innerIp3 = new IPv4().setSourceAddress(ECM2_SRC_IP) + .setDestinationAddress(ECM2_DST_IP) + .setProtocol(IPv4.PROTOCOL_UDP); + UDP innerUdp3 = new UDP().setSourcePort(10) + .setDestinationPort(20); + + LispMapRegister.RegisterBuilder msgBuilder3 = + new DefaultLispMapRegister.DefaultRegisterBuilder(); + + List records3 = ImmutableList.of(getMapRecord(), + getMapRecord()); + + LispMapRegister innerMsg3 = msgBuilder3.withIsProxyMapReply(true) + .withIsWantMapNotify(false) + .withKeyId((short) 2) + .withNonce(1L) + .withMapRecords(records3) + .build(); + + ecm2 = builder3.isSecurity(false) + .innerIpHeader(innerIp3) + .innerUdpHeader(innerUdp3) + .innerLispMessage(innerMsg3) + .build(); + } + + @Test + public void testEquality() { + new EqualsTester() + .addEqualityGroup(ecm1, sameAsEcm1) + .addEqualityGroup(ecm2).testEquals(); + } + + @Test + public void testConstruction() { + DefaultLispEncapsulatedControl ecm = + (DefaultLispEncapsulatedControl) ecm1; + + assertThat("Inner Ip versions are not match", + ecm.innerIpHeader().getVersion(), is((byte) 4)); + assertThat("Inner Ip protocols are not match", + ((IPv4) ecm.innerIpHeader()).getProtocol(), + is(IPv4.PROTOCOL_UDP)); + assertThat("Inner IP source addresses are not match", + ((IPv4) ecm.innerIpHeader()).getSourceAddress(), + is(IPv4.toIPv4Address(ECM1_SRC_IP))); + assertThat("Inner IP destination addresses are not match", + ((IPv4) ecm.innerIpHeader()).getDestinationAddress(), + is(IPv4.toIPv4Address(ECM1_DST_IP))); + assertThat("Inner UDP source ports are not match", + ecm.innerUdp().getSourcePort(), is(1)); + assertThat("Inner UDP destination ports are not match", + ecm.innerUdp().getDestinationPort(), is(2)); + assertThat("Inner LISP control messages are not match", + ecm.getControlMessage().getType(), + is(LispType.LISP_MAP_REGISTER)); + } + + @Test + public void testSerialization() throws LispReaderException, + LispWriterException, LispParseError, DeserializationException { + + ByteBuf byteBuf = Unpooled.buffer(); + DefaultLispEncapsulatedControl.EcmWriter writer = + new DefaultLispEncapsulatedControl.EcmWriter(); + writer.writeTo(byteBuf, ecm1); + + DefaultLispEncapsulatedControl.EcmReader reader = + new DefaultLispEncapsulatedControl.EcmReader(); + + LispEncapsulatedControl deserialized = reader.readFrom(byteBuf); + + new EqualsTester() + .addEqualityGroup(ecm1, deserialized).testEquals(); + } + + private LispMapRecord getMapRecord() { + LispMapRecord.MapRecordBuilder builder1 = + new DefaultLispMapRecord.DefaultMapRecordBuilder(); + + LispIpv4Address ipv4Locator1 = + new LispIpv4Address(IpAddress.valueOf(RECORD_EID)); + + return builder1 + .withRecordTtl(100) + .withAuthoritative(true) + .withMapVersionNumber((short) 1) + .withMaskLength((byte) 0x01) + .withAction(LispMapReplyAction.NativelyForward) + .withEidPrefixAfi(ipv4Locator1) + .build(); + } +}