diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReferral.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReferral.java index d796e1e145..2b2acdba92 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReferral.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReferral.java @@ -15,8 +15,214 @@ */ package org.onosproject.lisp.msg.protocols; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import io.netty.buffer.ByteBuf; +import org.onlab.packet.DeserializationException; +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.protocols.DefaultLispReferralRecord.ReferralRecordReader; +import org.onosproject.lisp.msg.protocols.DefaultLispReferralRecord.ReferralRecordWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static org.onosproject.lisp.msg.protocols.LispType.LISP_MAP_REFERRAL; + /** * Default LISP referral message class. */ -public class DefaultLispMapReferral implements LispMapReferral { +public final class DefaultLispMapReferral extends AbstractLispMessage + implements LispMapReferral { + + private static final Logger log = + LoggerFactory.getLogger(DefaultLispMapReferral.class); + + private final long nonce; + private final List referralRecords; + + static final MapReferralWriter WRITER; + + static { + WRITER = new MapReferralWriter(); + } + + /** + * A private constructor that protects object instantiation from external. + * + * @param nonce nonce + * @param referralRecords a collection of referral records + */ + private DefaultLispMapReferral(long nonce, + List referralRecords) { + this.nonce = nonce; + this.referralRecords = referralRecords; + } + + @Override + public LispType getType() { + return LISP_MAP_REFERRAL; + } + + @Override + public void writeTo(ByteBuf byteBuf) throws LispWriterException { + WRITER.writeTo(byteBuf, this); + } + + @Override + public Builder createBuilder() { + return new DefaultMapReferralBuilder(); + } + + @Override + public int getRecordCount() { + return referralRecords.size(); + } + + @Override + public long getNonce() { + return nonce; + } + + @Override + public List getReferralRecords() { + return ImmutableList.copyOf(referralRecords); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("type", getType()) + .add("nonce", nonce) + .add("referralRecords", referralRecords) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DefaultLispMapReferral that = (DefaultLispMapReferral) o; + return Objects.equals(nonce, that.nonce); + } + + @Override + public int hashCode() { + return Objects.hashCode(nonce); + } + + public static final class DefaultMapReferralBuilder + implements MapReferralBuilder { + + private long nonce; + private List referralRecords = Lists.newArrayList(); + + @Override + public LispType getType() { + return LISP_MAP_REFERRAL; + } + + @Override + public MapReferralBuilder withNonce(long nonce) { + this.nonce = nonce; + return this; + } + + @Override + public MapReferralBuilder withReferralRecords(List records) { + if (referralRecords != null) { + this.referralRecords = ImmutableList.copyOf(records); + } + return this; + } + + @Override + public LispMapReferral build() { + return new DefaultLispMapReferral(nonce, referralRecords); + } + } + + /** + * A LISP message reader for MapReferral message. + */ + public static final class MapReferralReader + implements LispMessageReader { + + private static final int RESERVED_SKIP_LENGTH = 3; + + @Override + public LispMapReferral readFrom(ByteBuf byteBuf) throws LispParseError, + LispReaderException, DeserializationException { + + if (byteBuf.readerIndex() != 0) { + return null; + } + + // let's skip the reserved field + byteBuf.skipBytes(RESERVED_SKIP_LENGTH); + + // record count -> 8 bits + byte recordCount = (byte) byteBuf.readUnsignedByte(); + + // nonce -> 64 bits + long nonce = byteBuf.readLong(); + + List referralRecords = Lists.newArrayList(); + for (int i = 0; i < recordCount; i++) { + referralRecords.add(new ReferralRecordReader().readFrom(byteBuf)); + } + + return new DefaultMapReferralBuilder() + .withNonce(nonce) + .withReferralRecords(referralRecords) + .build(); + } + } + + /** + * A LISP message writer for MapReferral message. + */ + public static final class MapReferralWriter + implements LispMessageWriter { + + private static final int REFERRAL_SHIFT_BIT = 4; + + private static final int UNUSED_ZERO = 0; + + @Override + public void writeTo(ByteBuf byteBuf, LispMapReferral message) + throws LispWriterException { + + // specify LISP message type + byte msgType = + (byte) (LISP_MAP_REFERRAL.getTypeCode() << REFERRAL_SHIFT_BIT); + + // fill zero into reserved field + byteBuf.writeShort(UNUSED_ZERO); + byteBuf.writeByte(UNUSED_ZERO); + + // record count + byteBuf.writeByte(message.getReferralRecords().size()); + + // nonce + byteBuf.writeLong(message.getNonce()); + + // serialize referral records + ReferralRecordWriter writer = new ReferralRecordWriter(); + List records = message.getReferralRecords(); + + for (int i = 0; i < records.size(); i++) { + writer.writeTo(byteBuf, records.get(i)); + } + } + } } diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapReferral.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapReferral.java index e78cfc4685..36f8e502ce 100644 --- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapReferral.java +++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapReferral.java @@ -15,6 +15,8 @@ */ package org.onosproject.lisp.msg.protocols; +import java.util.List; + /** * LISP map referral message interface. *

@@ -50,7 +52,55 @@ package org.onosproject.lisp.msg.protocols; * +-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * } */ -public interface LispMapReferral { +public interface LispMapReferral extends LispMessage { - // TODO: need to implement LispMapReferral + /** + * Obtains record count value. + * + * @return record count value + */ + int getRecordCount(); + + /** + * Obtains nonce value. + * + * @return nonce + */ + long getNonce(); + + /** + * Obtains a collection of referral records. + * + * @return a collection of referral records + */ + List getReferralRecords(); + + /** + * A builder of LISP map referral message. + */ + interface MapReferralBuilder extends Builder { + + /** + * Sets nonce value. + * + * @param nonce nonce value + * @return MapReferralBuilder object + */ + MapReferralBuilder withNonce(long nonce); + + /** + * Sets a collection of referral records. + * + * @param records a collection of referral records + * @return MapReferralBuilder object + */ + MapReferralBuilder withReferralRecords(List records); + + /** + * Builds LISP map referral message. + * + * @return LISP map referral message + */ + LispMapReferral build(); + } } diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReferralTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReferralTest.java new file mode 100644 index 0000000000..d2c669e515 --- /dev/null +++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReferralTest.java @@ -0,0 +1,127 @@ +/* + * Copyright 2017-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.IpAddress; +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.protocols.DefaultLispMapReferral.DefaultMapReferralBuilder; +import org.onosproject.lisp.msg.protocols.DefaultLispMapReferral.MapReferralReader; +import org.onosproject.lisp.msg.protocols.DefaultLispMapReferral.MapReferralWriter; +import org.onosproject.lisp.msg.protocols.DefaultLispReferralRecord.DefaultReferralRecordBuilder; +import org.onosproject.lisp.msg.protocols.LispMapReferral.MapReferralBuilder; +import org.onosproject.lisp.msg.protocols.LispReferralRecord.ReferralRecordBuilder; +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 DefaultLispMapReferral class. + */ +public final class DefaultLispMapReferralTest { + + private static final String IP_ADDRESS = "192.168.1.1"; + + private LispMapReferral referral1; + private LispMapReferral sameAsReferral1; + private LispMapReferral referral2; + + @Before + public void setup() { + + MapReferralBuilder builder1 = new DefaultMapReferralBuilder(); + + List records1 = + ImmutableList.of(getReferralRecord(), getReferralRecord()); + + referral1 = builder1 + .withNonce(1L) + .withReferralRecords(records1) + .build(); + + MapReferralBuilder builder2 = new DefaultMapReferralBuilder(); + + List records2 = + ImmutableList.of(getReferralRecord(), getReferralRecord()); + + sameAsReferral1 = builder2 + .withNonce(1L) + .withReferralRecords(records1) + .build(); + + MapReferralBuilder builder3 = new DefaultMapReferralBuilder(); + + referral2 = builder3 + .withNonce(2L) + .build(); + } + + private LispReferralRecord getReferralRecord() { + ReferralRecordBuilder builder = new DefaultReferralRecordBuilder(); + + LispIpv4Address ipv4Locator = new LispIpv4Address(IpAddress.valueOf(IP_ADDRESS)); + + return builder + .withRecordTtl(100) + .withIsAuthoritative(true) + .withIsIncomplete(false) + .withMapVersionNumber((short) 1) + .withMaskLength((byte) 0x01) + .withAction(LispMapReplyAction.NativelyForward) + .withEidPrefixAfi(ipv4Locator) + .build(); + } + + @Test + public void testEquality() { + new EqualsTester() + .addEqualityGroup(referral1, sameAsReferral1) + .addEqualityGroup(referral2).testEquals(); + } + + @Test + public void testConstruction() { + LispMapReferral referral = referral1; + + assertThat(referral.getNonce(), is(1L)); + assertThat(referral.getRecordCount(), is(2)); + } + + @Test + public void testSerialization() throws LispReaderException, LispWriterException, + LispParseError, DeserializationException { + ByteBuf byteBuf = Unpooled.buffer(); + + MapReferralWriter writer = new MapReferralWriter(); + writer.writeTo(byteBuf, referral1); + + MapReferralReader reader = new MapReferralReader(); + LispMapReferral deserialized = reader.readFrom(byteBuf); + + new EqualsTester().addEqualityGroup(referral1, deserialized).testEquals(); + } +}