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(); + } +}