From 3fbc950a7c53a103187bfcc0755ccefaba6d0799 Mon Sep 17 00:00:00 2001 From: Jian Li Date: Tue, 11 Apr 2017 10:41:25 +0900 Subject: [PATCH] Improve Extension Address interpreter to encode/decode JSON string Change-Id: Iab6d6a75c52c04ba6b3974200504045e1ed01dbe --- ...ispExtensionMappingAddressInterpreter.java | 148 ++++++++++++++++ ...xtensionMappingAddressInterpreterTest.java | 163 ++++++++++++++++++ .../LispExtensionMappingAddress.json | 154 +++++++++++++++++ 3 files changed, 465 insertions(+) create mode 100644 drivers/lisp/src/test/resources/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddress.json diff --git a/drivers/lisp/src/main/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreter.java b/drivers/lisp/src/main/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreter.java index c4040a7f3b..ef90abb50d 100644 --- a/drivers/lisp/src/main/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreter.java +++ b/drivers/lisp/src/main/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreter.java @@ -15,11 +15,14 @@ */ package org.onosproject.drivers.lisp.extensions; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; +import org.onosproject.codec.CodecContext; import org.onosproject.lisp.ctl.ExtensionMappingAddressInterpreter; import org.onosproject.lisp.msg.types.LispAfiAddress; import org.onosproject.lisp.msg.types.LispDistinguishedNameAddress; @@ -50,6 +53,8 @@ import org.slf4j.LoggerFactory; import java.util.List; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; import static org.onosproject.mapping.addresses.ExtensionMappingAddressType.ExtensionMappingAddressTypes.*; /** * Interpreter for mapping address extension. @@ -63,6 +68,22 @@ public class LispExtensionMappingAddressInterpreter extends AbstractHandlerBehav private static final int IPV4_PREFIX_LENGTH = 32; private static final int IPV6_PREFIX_LENGTH = 128; + protected static final String LISP_LIST_ADDRESS = "listAddress"; + protected static final String LISP_SEGMENT_ADDRESS = "segmentAddress"; + protected static final String LISP_AS_ADDRESS = "asAddress"; + protected static final String LISP_APPLICATION_DATA_ADDRESS = "applicationDataAddress"; + protected static final String LISP_GEO_COORDINATE_ADDRESS = "geoCoordinateAddress"; + protected static final String LISP_NAT_ADDRESS = "natAddress"; + protected static final String LISP_NONCE_ADDRESS = "nonceAddress"; + protected static final String LISP_MULTICAST_ADDRESS = "multicastAddress"; + protected static final String LISP_TRAFFIC_ENGINEERING_ADDRESS = "trafficEngineeringAddress"; + protected static final String LISP_SOURCE_DEST_ADDRESS = "sourceDestAddress"; + + private static final String TYPE = "type"; + + private static final String MISSING_MEMBER_MESSAGE = + " member is required in LispExtensionMappingAddressInterpreter"; + @Override public boolean supported(ExtensionMappingAddressType type) { @@ -569,4 +590,131 @@ public class LispExtensionMappingAddressInterpreter extends AbstractHandlerBehav return null; } + + @Override + public ObjectNode encode(ExtensionMappingAddress mappingAddress, CodecContext context) { + checkNotNull(mappingAddress, "Extension mapping address cannot be null"); + ExtensionMappingAddressType type = mappingAddress.type(); + ObjectNode root = context.mapper().createObjectNode(); + + if (type.equals(LIST_ADDRESS.type())) { + LispListAddress listAddress = (LispListAddress) mappingAddress; + root.set(LISP_LIST_ADDRESS, + context.codec(LispListAddress.class).encode(listAddress, context)); + } + if (type.equals(SEGMENT_ADDRESS.type())) { + LispSegmentAddress segmentAddress = (LispSegmentAddress) mappingAddress; + root.set(LISP_SEGMENT_ADDRESS, + context.codec(LispSegmentAddress.class).encode(segmentAddress, context)); + } + if (type.equals(AS_ADDRESS.type())) { + LispAsAddress asAddress = (LispAsAddress) mappingAddress; + root.set(LISP_AS_ADDRESS, + context.codec(LispAsAddress.class).encode(asAddress, context)); + } + if (type.equals(APPLICATION_DATA_ADDRESS.type())) { + LispAppDataAddress appDataAddress = (LispAppDataAddress) mappingAddress; + root.set(LISP_APPLICATION_DATA_ADDRESS, + context.codec(LispAppDataAddress.class).encode(appDataAddress, context)); + } + if (type.equals(GEO_COORDINATE_ADDRESS.type())) { + LispGcAddress gcAddress = (LispGcAddress) mappingAddress; + root.set(LISP_GEO_COORDINATE_ADDRESS, + context.codec(LispGcAddress.class).encode(gcAddress, context)); + } + if (type.equals(NAT_ADDRESS.type())) { + LispNatAddress natAddress = (LispNatAddress) mappingAddress; + root.set(LISP_NAT_ADDRESS, + context.codec(LispNatAddress.class).encode(natAddress, context)); + } + if (type.equals(NONCE_ADDRESS.type())) { + LispNonceAddress nonceAddress = (LispNonceAddress) mappingAddress; + root.set(LISP_NONCE_ADDRESS, context.codec(LispNonceAddress.class).encode(nonceAddress, context)); + } + if (type.equals(MULTICAST_ADDRESS.type())) { + LispMulticastAddress multicastAddress = (LispMulticastAddress) mappingAddress; + root.set(LISP_MULTICAST_ADDRESS, + context.codec(LispMulticastAddress.class).encode(multicastAddress, context)); + } + if (type.equals(TRAFFIC_ENGINEERING_ADDRESS.type())) { + LispTeAddress teAddress = (LispTeAddress) mappingAddress; + root.set(LISP_TRAFFIC_ENGINEERING_ADDRESS, + context.codec(LispTeAddress.class).encode(teAddress, context)); + } + if (type.equals(SOURCE_DEST_ADDRESS.type())) { + LispSrcDstAddress srcDstAddress = (LispSrcDstAddress) mappingAddress; + root.set(LISP_SOURCE_DEST_ADDRESS, + context.codec(LispSrcDstAddress.class).encode(srcDstAddress, context)); + } + + return root; + } + + @Override + public ExtensionMappingAddress decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + // parse extension type + String typeString = nullIsIllegal(json.get(TYPE), + TYPE + MISSING_MEMBER_MESSAGE).asText(); + + if (typeString.equals(LIST_ADDRESS.name())) { + return context.codec(LispListAddress.class) + .decode(get(json, LISP_LIST_ADDRESS), context); + } + if (typeString.equals(SEGMENT_ADDRESS.name())) { + return context.codec(LispSegmentAddress.class) + .decode(get(json, LISP_SEGMENT_ADDRESS), context); + } + if (typeString.equals(AS_ADDRESS.name())) { + return context.codec(LispAsAddress.class) + .decode(get(json, LISP_AS_ADDRESS), context); + } + if (typeString.equals(APPLICATION_DATA_ADDRESS.name())) { + return context.codec(LispAppDataAddress.class) + .decode(get(json, LISP_APPLICATION_DATA_ADDRESS), context); + } + if (typeString.equals(GEO_COORDINATE_ADDRESS.name())) { + return context.codec(LispGcAddress.class) + .decode(get(json, LISP_GEO_COORDINATE_ADDRESS), context); + } + if (typeString.equals(NAT_ADDRESS.name())) { + return context.codec(LispNatAddress.class) + .decode(get(json, LISP_NAT_ADDRESS), context); + } + if (typeString.equals(NONCE_ADDRESS.name())) { + return context.codec(LispNonceAddress.class) + .decode(get(json, LISP_NONCE_ADDRESS), context); + } + if (typeString.equals(MULTICAST_ADDRESS.name())) { + return context.codec(LispMulticastAddress.class) + .decode(get(json, LISP_MULTICAST_ADDRESS), context); + } + if (typeString.equals(TRAFFIC_ENGINEERING_ADDRESS.name())) { + return context.codec(LispTeAddress.class) + .decode(get(json, LISP_TRAFFIC_ENGINEERING_ADDRESS), context); + } + if (typeString.equals(SOURCE_DEST_ADDRESS.name())) { + return context.codec(LispSrcDstAddress.class) + .decode(get(json, LISP_SOURCE_DEST_ADDRESS), context); + } + + throw new UnsupportedOperationException( + "Driver does not support extension type " + typeString); + } + + /** + * Gets a child Object Node from a parent by name. If the child is not found + * or does nor represent an object, null is returned. + * + * @param parent parent object + * @param childName name of child to query + * @return child object if found, null if not found or if not an object + */ + private static ObjectNode get(ObjectNode parent, String childName) { + JsonNode node = parent.path(childName); + return node.isObject() && !node.isNull() ? (ObjectNode) node : null; + } } diff --git a/drivers/lisp/src/test/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreterTest.java b/drivers/lisp/src/test/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreterTest.java index 7bfaab36f2..86bbdbf52c 100644 --- a/drivers/lisp/src/test/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreterTest.java +++ b/drivers/lisp/src/test/java/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddressInterpreterTest.java @@ -15,12 +15,28 @@ */ package org.onosproject.drivers.lisp.extensions; +import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; import com.google.common.testing.EqualsTester; +import org.hamcrest.MatcherAssert; import org.junit.Before; import org.junit.Test; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.impl.CodecManager; +import org.onosproject.drivers.lisp.extensions.codec.LispAppDataAddressCodecTest; +import org.onosproject.drivers.lisp.extensions.codec.LispAsAddressCodecTest; +import org.onosproject.drivers.lisp.extensions.codec.LispGcAddressCodecTest; +import org.onosproject.drivers.lisp.extensions.codec.LispListAddressCodecTest; +import org.onosproject.drivers.lisp.extensions.codec.LispMappingExtensionCodecContextAdapter; +import org.onosproject.drivers.lisp.extensions.codec.LispMulticastAddressCodecTest; +import org.onosproject.drivers.lisp.extensions.codec.LispNatAddressCodecTest; +import org.onosproject.drivers.lisp.extensions.codec.LispNonceAddressCodecTest; +import org.onosproject.drivers.lisp.extensions.codec.LispSegmentAddressCodecTest; +import org.onosproject.drivers.lisp.extensions.codec.LispSrcDstAddressCodecTest; +import org.onosproject.drivers.lisp.extensions.codec.LispTeAddressCodecTest; import org.onosproject.lisp.msg.types.LispAfiAddress; import org.onosproject.lisp.msg.types.LispIpv4Address; import org.onosproject.lisp.msg.types.LispIpv6Address; @@ -41,7 +57,14 @@ import org.onosproject.mapping.addresses.ExtensionMappingAddressType; import org.onosproject.mapping.addresses.MappingAddress; import org.onosproject.mapping.addresses.MappingAddresses; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertTrue; +import static org.onosproject.drivers.lisp.extensions.LispExtensionMappingAddressInterpreter.*; import static org.onosproject.mapping.addresses.ExtensionMappingAddressType.ExtensionMappingAddressTypes.*; /** * Unit tests for LispExtensionMappingAddressInterpreter. @@ -61,6 +84,10 @@ public class LispExtensionMappingAddressInterpreterTest { private static final boolean UNIQUE_BOOLEAN = true; private LispExtensionMappingAddressInterpreter interpreter; + + private CodecContext context; + private LispMappingExtensionCodecRegistrator registrator; + private ExtensionMappingAddress listExtAddress; private ExtensionMappingAddress segmentExtAddress; private ExtensionMappingAddress asExtAddress; @@ -88,8 +115,18 @@ public class LispExtensionMappingAddressInterpreterTest { interpreter = new LispExtensionMappingAddressInterpreter(); initExtAddresses(); initLcafAddresses(); + + CodecManager manager = new CodecManager(); + registrator = new LispMappingExtensionCodecRegistrator(); + registrator.codecService = manager; + registrator.activate(); + + context = new LispMappingExtensionCodecContextAdapter(registrator.codecService); } + /** + * Initializes all extension mapping addresses. + */ private void initExtAddresses() { listExtAddress = getExtMappingAddress(LIST_ADDRESS.type()); segmentExtAddress = getExtMappingAddress(SEGMENT_ADDRESS.type()); @@ -103,6 +140,9 @@ public class LispExtensionMappingAddressInterpreterTest { srcDstExtAddress = getExtMappingAddress(SOURCE_DEST_ADDRESS.type()); } + /** + * Initializes all LCAF addresses. + */ private void initLcafAddresses() { listLcafAddress = getLcafMappingAddress(LIST_ADDRESS.type()); segmentLcafAddress = getLcafMappingAddress(SEGMENT_ADDRESS.type()); @@ -116,6 +156,9 @@ public class LispExtensionMappingAddressInterpreterTest { srcDstLcafAddress = getLcafMappingAddress(SOURCE_DEST_ADDRESS.type()); } + /** + * Tests supportability of a certain LISP extension mapping address. + */ @Test public void testSupported() { assertTrue("List extension address should be supported", @@ -140,6 +183,9 @@ public class LispExtensionMappingAddressInterpreterTest { interpreter.supported(srcDstExtAddress.type())); } + /** + * Tests conversion from LISP extension mapping address to LCAF address. + */ @Test public void testMapMappingAddress() { @@ -157,6 +203,9 @@ public class LispExtensionMappingAddressInterpreterTest { .testEquals(); } + /** + * Tests conversion from LCAF address to LISP extension mapping address. + */ @Test public void testMapLcafAddress() { @@ -174,6 +223,120 @@ public class LispExtensionMappingAddressInterpreterTest { .testEquals(); } + /** + * Tests encoding of an ExtensionMappingAddress object. + */ + @Test + public void testAddressEncode() { + JsonNode listAddressJson = + interpreter.encode(listExtAddress, context).get(LISP_LIST_ADDRESS); + JsonNode segmentAddressJson = + interpreter.encode(segmentExtAddress, context).get(LISP_SEGMENT_ADDRESS); + JsonNode asAddressJson = + interpreter.encode(asExtAddress, context).get(LISP_AS_ADDRESS); + JsonNode appDataAddressJson = + interpreter.encode(appDataExtAddress, context).get(LISP_APPLICATION_DATA_ADDRESS); + JsonNode gcAddressJson = + interpreter.encode(gcExtAddress, context).get(LISP_GEO_COORDINATE_ADDRESS); + JsonNode natAddressJson = + interpreter.encode(natExtAddress, context).get(LISP_NAT_ADDRESS); + JsonNode nonceAddressJson = + interpreter.encode(nonceExtAddress, context).get(LISP_NONCE_ADDRESS); + JsonNode multicastAddressJson = + interpreter.encode(multicastExtAddress, context).get(LISP_MULTICAST_ADDRESS); + JsonNode teAddressJson = + interpreter.encode(teExtAddress, context).get(LISP_TRAFFIC_ENGINEERING_ADDRESS); + JsonNode srcDstAddressJson = + interpreter.encode(srcDstExtAddress, context).get(LISP_SOURCE_DEST_ADDRESS); + + MatcherAssert.assertThat("errors in encoding List address JSON", + listAddressJson, LispListAddressCodecTest.LispListAddressJsonMatcher + .matchesListAddress((LispListAddress) listExtAddress)); + + MatcherAssert.assertThat("errors in encoding Segment address JSON", + segmentAddressJson, LispSegmentAddressCodecTest.LispSegmentAddressJsonMatcher + .matchesSegmentAddress((LispSegmentAddress) segmentExtAddress)); + + MatcherAssert.assertThat("errors in encoding AS address JSON", + asAddressJson, LispAsAddressCodecTest.LispAsAddressJsonMatcher + .matchesAsAddress((LispAsAddress) asExtAddress)); + + MatcherAssert.assertThat("errors in encoding AppData address JSON", + appDataAddressJson, LispAppDataAddressCodecTest.LispAppDataAddressJsonMatcher + .matchesAppDataAddress((LispAppDataAddress) appDataExtAddress)); + + MatcherAssert.assertThat("errors in encoding GC address JSON", + gcAddressJson, LispGcAddressCodecTest.LispGcAddressJsonMatcher + .matchesGcAddress((LispGcAddress) gcExtAddress)); + + MatcherAssert.assertThat("errors in encoding NAT address JSON", + natAddressJson, LispNatAddressCodecTest.LispNatAddressJsonMatcher + .matchesNatAddress((LispNatAddress) natExtAddress)); + + MatcherAssert.assertThat("errors in encoding Nonce address JSON", + nonceAddressJson, LispNonceAddressCodecTest.LispNonceAddressJsonMatcher + .matchesNonceAddress((LispNonceAddress) nonceExtAddress)); + + MatcherAssert.assertThat("errors in encoding Multicast address JSON", + multicastAddressJson, LispMulticastAddressCodecTest.LispMulticastAddressJsonMatcher + .matchesMulticastAddress((LispMulticastAddress) multicastExtAddress)); + + MatcherAssert.assertThat("errors in encoding TE address JSON", + teAddressJson, LispTeAddressCodecTest.LispTeAddressJsonMatcher + .matchesTeAddress((LispTeAddress) teExtAddress)); + + MatcherAssert.assertThat("errors in encoding SrcDst address JSON", + srcDstAddressJson, LispSrcDstAddressCodecTest.LispSrcDstAddressJsonMatcher + .matchesSrcDstAddress((LispSrcDstAddress) srcDstExtAddress)); + } + + /** + * Tests decoding of an ExtensionMappingAddress JSON object. + */ + @Test + public void testAddressDecode() throws IOException { + List addresses = + getLispExtensionMappingAddresses("LispExtensionMappingAddress.json"); + + new EqualsTester() + .addEqualityGroup(addresses.get(0), listExtAddress) + .addEqualityGroup(addresses.get(1), segmentExtAddress) + .addEqualityGroup(addresses.get(2), asExtAddress) + .addEqualityGroup(addresses.get(3), appDataExtAddress) + .addEqualityGroup(addresses.get(4), gcExtAddress) + .addEqualityGroup(addresses.get(5), natExtAddress) + .addEqualityGroup(addresses.get(6), nonceExtAddress) + .addEqualityGroup(addresses.get(7), multicastExtAddress) + .addEqualityGroup(addresses.get(8), teExtAddress) + .addEqualityGroup(addresses.get(9), srcDstExtAddress) + .testEquals(); + } + + /** + * Reads in a collection of LispExtensionMappingAddresses from the given resource and decodes it. + * + * @param resourceName resource to use to read the JSON for the rule + * @return decoded LispExtensionMappingAddresses + * @throws IOException if processing the resource fails + */ + private List getLispExtensionMappingAddresses(String resourceName) + throws IOException { + InputStream jsonStream = LispExtensionMappingAddressInterpreterTest.class + .getResourceAsStream(resourceName); + JsonNode json = context.mapper().readTree(jsonStream); + assertThat("JSON string should not be null", json, notNullValue()); + + final List addresses = Lists.newArrayList(); + + for (int addrIndex = 0; addrIndex < json.size(); addrIndex++) { + ExtensionMappingAddress address = interpreter.decode(json.get(addrIndex).deepCopy(), context); + assertThat("decoded address should not be null", address, notNullValue()); + addresses.add(address); + } + + return addresses; + } + private LispLcafAddress getLcafMappingAddress(ExtensionMappingAddressType type) { LispLcafAddress address = null; diff --git a/drivers/lisp/src/test/resources/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddress.json b/drivers/lisp/src/test/resources/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddress.json new file mode 100644 index 0000000000..201bed58b8 --- /dev/null +++ b/drivers/lisp/src/test/resources/org/onosproject/drivers/lisp/extensions/LispExtensionMappingAddress.json @@ -0,0 +1,154 @@ +[ + { + "type": "LIST_ADDRESS", + "listAddress": { + "ipv4": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + }, + "ipv6": { + "type": "IPV6", + "ipv6": "1111:2222:3333:4444:5555:6666:7777:8886/128" + } + } + }, + { + "type": "SEGMENT_ADDRESS", + "segmentAddress": { + "instanceId": 1, + "address": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + } + } + }, + { + "type": "AS_ADDRESS", + "asAddress": { + "asNumber": 1, + "address": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + } + } + }, + { + "type": "APPLICATION_DATA_ADDRESS", + "applicationDataAddress": { + "protocol": 1, + "ipTos": 1, + "localPortLow": 1, + "localPortHigh": 1, + "remotePortLow": 1, + "remotePortHigh": 1, + "address": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + } + } + }, + { + "type": "GEO_COORDINATE_ADDRESS", + "geoCoordinateAddress": { + "north": true, + "latitudeDegree": 1, + "latitudeMinute": 1, + "latitudeSecond": 1, + "east": true, + "longitudeDegree": 1, + "longitudeMinute": 1, + "longitudeSecond": 1, + "altitude": 1, + "address": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + } + } + }, + { + "type": "NAT_ADDRESS", + "natAddress": { + "msUdpPortNumber": 1, + "etrUdpPortNumber": 1, + "globalEtrRlocAddress": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + }, + "msRlocAddress": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + }, + "privateEtrRlocAddress": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + }, + "rtrRlocAddresses": [ + { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + }, + { + "type": "IPV6", + "ipv6": "1111:2222:3333:4444:5555:6666:7777:8886/128" + } + ] + } + }, + { + "type": "NONCE_ADDRESS", + "nonceAddress": { + "nonce": 1, + "address": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + } + } + }, + { + "type": "MULTICAST_ADDRESS", + "multicastAddress": { + "instanceId": 1, + "srcMaskLength": 1, + "grpMaskLength": 1, + "srcAddress": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + }, + "grpAddress": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + } + } + }, + { + "type": "TRAFFIC_ENGINEERING_ADDRESS", + "trafficEngineeringAddress": { + "records": [ + { + "lookup": true, + "rlocProbe": true, + "strict": true, + "address": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + } + } + ] + } + }, + { + "type": "SOURCE_DEST_ADDRESS", + "sourceDestAddress": { + "srcMaskLength": 1, + "dstMaskLength": 1, + "srcPrefix": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + }, + "dstPrefix": { + "type": "IPV4", + "ipv4": "1.2.3.4/32" + } + } + } +] \ No newline at end of file