[ONOS-5750] Add MappingEntryBuilder with unit test
Change-Id: Ia4e2f4b6cb3a9b07a00376b12b506f43255bad11
diff --git a/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/impl/LispMappingProvider.java b/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/impl/LispMappingProvider.java
index 05e5dd7..3cf1e3b 100644
--- a/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/impl/LispMappingProvider.java
+++ b/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/impl/LispMappingProvider.java
@@ -25,12 +25,14 @@
import org.onosproject.lisp.ctl.LispRouterId;
import org.onosproject.lisp.ctl.LispRouterListener;
import org.onosproject.lisp.msg.protocols.LispMapNotify;
+import org.onosproject.lisp.msg.protocols.LispMapRecord;
import org.onosproject.lisp.msg.protocols.LispMapReply;
import org.onosproject.lisp.msg.protocols.LispMessage;
import org.onosproject.mapping.MappingEntry;
import org.onosproject.mapping.MappingProvider;
import org.onosproject.mapping.MappingProviderRegistry;
import org.onosproject.mapping.MappingProviderService;
+import org.onosproject.mapping.MappingStore;
import org.onosproject.net.DeviceId;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
@@ -38,6 +40,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.List;
+
import static org.onosproject.mapping.MappingStore.Type.MAP_CACHE;
import static org.onosproject.mapping.MappingStore.Type.MAP_DATABASE;
@@ -138,21 +142,33 @@
case LISP_MAP_REPLY:
LispMapReply reply = (LispMapReply) msg;
-
- MappingEntry replyMe = new MappingEntryBuilder(deviceId, reply).build();
- providerService.mappingAdded(replyMe, MAP_CACHE);
+ processMappings(deviceId, reply.getMapRecords(), MAP_CACHE);
break;
case LISP_MAP_NOTIFY:
LispMapNotify notify = (LispMapNotify) msg;
-
- MappingEntry notifyMe = new MappingEntryBuilder(deviceId, notify).build();
- providerService.mappingAdded(notifyMe, MAP_DATABASE);
+ processMappings(deviceId, notify.getMapRecords(), MAP_DATABASE);
break;
default:
log.warn("Unhandled message type: {}", msg.getType());
}
}
+
+ /**
+ * Converts map records into mapping, notifies to provider.
+ *
+ * @param deviceId device identifier
+ * @param records a collection of map records
+ * @param type MappingStore type
+ */
+ private void processMappings(DeviceId deviceId,
+ List<LispMapRecord> records,
+ MappingStore.Type type) {
+ records.forEach(r -> {
+ MappingEntry me = new MappingEntryBuilder(deviceId, r).build();
+ providerService.mappingAdded(me, type);
+ });
+ }
}
}
diff --git a/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java b/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java
index 12a58e4..90052c28 100644
--- a/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java
+++ b/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java
@@ -15,49 +15,246 @@
*/
package org.onosproject.provider.lisp.mapping.util;
-import org.onosproject.lisp.msg.protocols.LispMapNotify;
-import org.onosproject.lisp.msg.protocols.LispMapReply;
+import com.google.common.collect.Lists;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onosproject.lisp.msg.protocols.LispLocator;
+import org.onosproject.lisp.msg.protocols.LispMapRecord;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+import org.onosproject.lisp.msg.types.LispAsAddress;
+import org.onosproject.lisp.msg.types.LispDistinguishedNameAddress;
+import org.onosproject.lisp.msg.types.LispIpv4Address;
+import org.onosproject.lisp.msg.types.LispIpv6Address;
+import org.onosproject.lisp.msg.types.LispMacAddress;
+import org.onosproject.mapping.DefaultMapping;
+import org.onosproject.mapping.DefaultMappingEntry;
+import org.onosproject.mapping.DefaultMappingKey;
+import org.onosproject.mapping.DefaultMappingTreatment;
+import org.onosproject.mapping.DefaultMappingValue;
+import org.onosproject.mapping.Mapping;
import org.onosproject.mapping.MappingEntry;
+import org.onosproject.mapping.MappingEntry.MappingEntryState;
+import org.onosproject.mapping.MappingKey;
+import org.onosproject.mapping.MappingTreatment;
+import org.onosproject.mapping.MappingValue;
+import org.onosproject.mapping.actions.MappingAction;
+import org.onosproject.mapping.actions.MappingActions;
+import org.onosproject.mapping.addresses.MappingAddress;
+import org.onosproject.mapping.addresses.MappingAddresses;
import org.onosproject.net.DeviceId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.List;
+import java.util.UUID;
+
+import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.IP4;
+import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.IP6;
+
/**
* Mapping entry builder class.
*/
public class MappingEntryBuilder {
- private static final Logger log = LoggerFactory.getLogger(MappingEntryBuilder.class);
+ private static final Logger log =
+ LoggerFactory.getLogger(MappingEntryBuilder.class);
+
+ private static final int IPV4_PREFIX_LENGTH = 32;
+ private static final int IPV6_PREFIX_LENGTH = 128;
private final DeviceId deviceId;
- private final LispMapReply mapReply;
- private final LispMapNotify mapNotify;
+
+ private final MappingAddress address;
+ private final MappingAction action;
+ private final List<MappingTreatment> treatments;
/**
* Default constructor for MappingEntryBuilder.
*
* @param deviceId device identifier
- * @param mapReply map reply message
+ * @param record LISP map record
*/
- public MappingEntryBuilder(DeviceId deviceId, LispMapReply mapReply) {
+ public MappingEntryBuilder(DeviceId deviceId, LispMapRecord record) {
this.deviceId = deviceId;
- this.mapReply = mapReply;
- this.mapNotify = null;
+ this.address = buildAddress(record);
+ this.action = buildAction(record);
+ this.treatments = buildTreatments(record);
}
/**
- * Default constructor for MappingEntryBuilder.
+ * Builds mapping entry from a specific LISP control message.
*
- * @param deviceId device identifier
- * @param mapNotify map notify message
+ * @return mapping entry
*/
- public MappingEntryBuilder(DeviceId deviceId, LispMapNotify mapNotify) {
- this.deviceId = deviceId;
- this.mapNotify = mapNotify;
- this.mapReply = null;
+ public MappingEntry build() {
+ Mapping.Builder builder;
+
+ // we assign leastSignificantBits of UUID as the mapping identifier for now
+ // id generation scheme can be changed later
+ UUID uuid = UUID.randomUUID();
+
+ builder = DefaultMapping.builder()
+ .withId(uuid.getLeastSignificantBits())
+ .forDevice(deviceId)
+ .withKey(buildKey())
+ .withValue(buildValue());
+
+ // TODO: we assume that the mapping entry will be always
+ // stored in routers without failure for now, which means
+ // the mapping entry state will always be ADDED rather than
+ // PENDING_ADD
+ // we will revisit this part when LISP driver is finished
+ return new DefaultMappingEntry(builder.build(), MappingEntryState.ADDED);
}
- public MappingEntry build() {
- // TODO: provide a way to build mapping entry from input parameters
+ /**
+ * Builds mapping key.
+ *
+ * @return mapping key
+ */
+ private MappingKey buildKey() {
+
+ MappingKey.Builder builder = DefaultMappingKey.builder();
+
+ builder.withAddress(address);
+
+ return builder.build();
+ }
+
+ /**
+ * Builds mapping value.
+ *
+ * @return mapping value
+ */
+ private MappingValue buildValue() {
+
+ MappingValue.Builder builder = DefaultMappingValue.builder();
+ builder.withAction(action);
+
+ treatments.forEach(builder::add);
+
+ return builder.build();
+ }
+
+ /**
+ * Builds mapping action.
+ *
+ * @param record LISP map record
+ * @return mapping action
+ */
+ private MappingAction buildAction(LispMapRecord record) {
+
+ if (record == null) {
+ return MappingActions.noAction();
+ }
+
+ switch (record.getAction()) {
+ case NoAction:
+ return MappingActions.noAction();
+ case SendMapRequest:
+ return MappingActions.forward();
+ case NativelyForward:
+ return MappingActions.nativeForward();
+ case Drop:
+ return MappingActions.drop();
+ default:
+ log.warn("Unsupported action type {}", record.getAction());
+ return MappingActions.noAction();
+ }
+ }
+
+ /**
+ * Builds mapping address.
+ *
+ * @param record LISP map record
+ * @return mapping address
+ */
+ private MappingAddress buildAddress(LispMapRecord record) {
+
+ return record == null ? null :
+ getAddress(record.getEidPrefixAfi(), record.getMaskLength());
+ }
+
+ /**
+ * Converts LispAfiAddress into abstracted mapping address.
+ *
+ * @param address LispAfiAddress
+ * @param length mask length
+ * @return abstracted mapping address
+ */
+ private MappingAddress getAddress(LispAfiAddress address, int length) {
+
+ if (address == null) {
+ log.warn("Address is not specified.");
+ return null;
+ }
+
+ switch (address.getAfi()) {
+ case IP4:
+ IpAddress ipv4Address = ((LispIpv4Address) address).getAddress();
+ IpPrefix ipv4Prefix = IpPrefix.valueOf(ipv4Address, length);
+ return MappingAddresses.ipv4MappingAddress(ipv4Prefix);
+ case IP6:
+ IpAddress ipv6Address = ((LispIpv6Address) address).getAddress();
+ IpPrefix ipv6Prefix = IpPrefix.valueOf(ipv6Address, length);
+ return MappingAddresses.ipv6MappingAddress(ipv6Prefix);
+ case AS:
+ int asNum = ((LispAsAddress) address).getASNum();
+ return MappingAddresses.asMappingAddress(String.valueOf(asNum));
+ case DISTINGUISHED_NAME:
+ String dn = ((LispDistinguishedNameAddress)
+ address).getDistinguishedName();
+ return MappingAddresses.dnMappingAddress(dn);
+ case MAC:
+ MacAddress macAddress = ((LispMacAddress) address).getAddress();
+ return MappingAddresses.ethMappingAddress(macAddress);
+ case LCAF:
+ // TODO: need to use extension address to abstract LCAF address
+ break;
+ default:
+ log.warn("Unsupported address type {}", address.getAfi());
+ break;
+ }
+
return null;
}
+
+ /**
+ * Builds a collection of mapping treatments.
+ *
+ * @param record LISP map record
+ * @return a collection of mapping treatments
+ */
+ private List<MappingTreatment> buildTreatments(LispMapRecord record) {
+
+ List<LispLocator> locators = record.getLocators();
+ List<MappingTreatment> treatments = Lists.newArrayList();
+ for (LispLocator locator : locators) {
+ MappingTreatment.Builder builder = DefaultMappingTreatment.builder();
+ LispAfiAddress address = locator.getLocatorAfi();
+ int addressLength = 0;
+ if (address.getAfi() == IP4) {
+ addressLength = IPV4_PREFIX_LENGTH;
+ } else if (address.getAfi() == IP6) {
+ addressLength = IPV6_PREFIX_LENGTH;
+ }
+
+ final MappingAddress mappingAddress = getAddress(address, addressLength);
+ if (mappingAddress != null) {
+ builder.withAddress(mappingAddress);
+ }
+
+ builder.setUnicastWeight(locator.getWeight())
+ .setUnicastPriority(locator.getPriority())
+ .setMulticastWeight(locator.getMulticastWeight())
+ .setMulticastPriority(locator.getMulticastPriority());
+
+ // TODO: need to convert specific properties to
+ // abstracted extension properties
+
+ treatments.add(builder.build());
+ }
+
+ return treatments;
+ }
}
diff --git a/providers/lisp/mapping/src/test/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilderTest.java b/providers/lisp/mapping/src/test/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilderTest.java
new file mode 100644
index 0000000..c6bf5fa
--- /dev/null
+++ b/providers/lisp/mapping/src/test/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilderTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.provider.lisp.mapping.util;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.lisp.msg.protocols.DefaultLispLocator.DefaultLocatorBuilder;
+import org.onosproject.lisp.msg.protocols.DefaultLispMapNotify.DefaultNotifyBuilder;
+import org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.DefaultMapRecordBuilder;
+import org.onosproject.lisp.msg.protocols.DefaultLispMapReply.DefaultReplyBuilder;
+import org.onosproject.lisp.msg.protocols.LispLocator;
+import org.onosproject.lisp.msg.protocols.LispLocator.LocatorBuilder;
+import org.onosproject.lisp.msg.protocols.LispMapNotify;
+import org.onosproject.lisp.msg.protocols.LispMapNotify.NotifyBuilder;
+import org.onosproject.lisp.msg.protocols.LispMapRecord;
+import org.onosproject.lisp.msg.protocols.LispMapRecord.MapRecordBuilder;
+import org.onosproject.lisp.msg.protocols.LispMapReply;
+import org.onosproject.lisp.msg.protocols.LispMapReply.ReplyBuilder;
+import org.onosproject.lisp.msg.protocols.LispMapReplyAction;
+import org.onosproject.lisp.msg.types.LispIpv4Address;
+import org.onosproject.mapping.MappingEntry;
+import org.onosproject.mapping.MappingKey;
+import org.onosproject.mapping.MappingTreatment;
+import org.onosproject.mapping.MappingValue;
+import org.onosproject.mapping.actions.MappingAction;
+import org.onosproject.mapping.addresses.IPMappingAddress;
+import org.onosproject.net.DeviceId;
+
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Mapping entry builder unit test.
+ */
+public class MappingEntryBuilderTest {
+
+ private static final String IP_RECORD_ADDRESS = "192.168.1.1";
+ private static final String IP_LOCATOR_ADDRESS = "10.1.1.1";
+ private static final int IP_RECORD_MASK_LENGTH = 24;
+ private static final int IP_LOCATOR_MASK_LENGTH = 32;
+
+ private static final String AUTH_KEY = "onos";
+
+ private static final byte UNIQUE_VALUE = (byte) 0x01;
+ private static final DeviceId DEVICE_ID = DeviceId.deviceId("lisp:10.1.1.2");
+
+ private LispMapReply mapReply;
+ private LispMapNotify mapNotify;
+
+ @Before
+ public void setUp() {
+ ReplyBuilder replyBuilder = new DefaultReplyBuilder();
+
+ List<LispMapRecord> records = ImmutableList.of(getMapRecord());
+
+ mapReply = replyBuilder
+ .withIsEtr(true)
+ .withIsProbe(false)
+ .withIsSecurity(true)
+ .withNonce(1L)
+ .withMapRecords(records)
+ .build();
+
+ NotifyBuilder notifyBuilder = new DefaultNotifyBuilder();
+
+ mapNotify = notifyBuilder
+ .withKeyId((short) 1)
+ .withAuthKey(AUTH_KEY)
+ .withNonce(1L)
+ .withMapRecords(records)
+ .build();
+ }
+
+ @Test
+ public void testMapReplyConversion() {
+ List<LispMapRecord> replyRecords = mapReply.getMapRecords();
+
+ assertThat(replyRecords.size(), is(1));
+
+ testMapRecorConversion(replyRecords.get(0));
+ }
+
+ @Test
+ public void testMapNotifyConversion() {
+ List<LispMapRecord> notifyRecords = mapNotify.getMapRecords();
+
+ assertThat(notifyRecords.size(), is(1));
+
+ testMapRecorConversion(notifyRecords.get(0));
+ }
+
+ private void testMapRecorConversion(LispMapRecord record) {
+ MappingEntry mappingEntry =
+ new MappingEntryBuilder(DEVICE_ID, record).build();
+ MappingKey key = mappingEntry.key();
+ MappingValue value = mappingEntry.value();
+
+ IPMappingAddress recordAddress = (IPMappingAddress) key.address();
+
+ assertThat(recordAddress.ip(), is(IpPrefix.valueOf(IP_RECORD_ADDRESS + "/" +
+ IP_RECORD_MASK_LENGTH)));
+
+ assertThat(value.action().type(), is(MappingAction.Type.NATIVE_FORWARD));
+
+ assertThat(value.treatments().size(), is(1));
+
+ MappingTreatment treatment = value.treatments().get(0);
+ IPMappingAddress locatorAddress = (IPMappingAddress) treatment.address();
+
+ assertThat(locatorAddress.ip(), is(IpPrefix.valueOf(IP_LOCATOR_ADDRESS + "/" +
+ IP_LOCATOR_MASK_LENGTH)));
+ }
+
+ private LispMapRecord getMapRecord() {
+ MapRecordBuilder recordBuilder = new DefaultMapRecordBuilder();
+
+ LispIpv4Address recordAddress =
+ new LispIpv4Address(IpAddress.valueOf(IP_RECORD_ADDRESS));
+
+ LocatorBuilder locatorBuilder = new DefaultLocatorBuilder();
+
+ LispIpv4Address locatorAddress =
+ new LispIpv4Address(IpAddress.valueOf(IP_LOCATOR_ADDRESS));
+
+ LispLocator locator1 = locatorBuilder
+ .withPriority(UNIQUE_VALUE)
+ .withWeight(UNIQUE_VALUE)
+ .withMulticastPriority(UNIQUE_VALUE)
+ .withMulticastWeight(UNIQUE_VALUE)
+ .withLocalLocator(true)
+ .withRlocProbed(false)
+ .withRouted(true)
+ .withLocatorAfi(locatorAddress)
+ .build();
+
+ return recordBuilder
+ .withRecordTtl(100)
+ .withIsAuthoritative(true)
+ .withMapVersionNumber((short) 1)
+ .withMaskLength((byte) IP_RECORD_MASK_LENGTH)
+ .withAction(LispMapReplyAction.NativelyForward)
+ .withEidPrefixAfi(recordAddress)
+ .withLocators(ImmutableList.of(locator1))
+ .build();
+ }
+}