[ONOS-6634] Add method to create NDP replay for ICMP6

Change-Id: Ibc24470072cc6810a428ac9caf1d3343310df80c
diff --git a/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborAdvertisementTest.java b/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborAdvertisementTest.java
index ac00096..db34514 100644
--- a/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborAdvertisementTest.java
+++ b/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborAdvertisementTest.java
@@ -16,16 +16,24 @@
 package org.onlab.packet.ndp;
 
 import org.apache.commons.lang3.StringUtils;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP6;
+import org.onlab.packet.IPv6;
+import org.onlab.packet.Ip6Address;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.PacketTestUtils;
 
 import java.nio.ByteBuffer;
+import java.util.Arrays;
 
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.core.IsCollectionContaining.hasItem;
 import static org.junit.Assert.*;
 
 /**
@@ -39,7 +47,18 @@
         (byte) 0xfe, (byte) 0x35, (byte) 0x26, (byte) 0xce
     };
     private static final MacAddress MAC_ADDRESS =
-        MacAddress.valueOf("11:22:33:44:55:66");
+            MacAddress.valueOf("11:22:33:44:55:66");
+    private static final MacAddress MAC_ADDRESS2 =
+            MacAddress.valueOf("10:20:30:40:50:60");
+    private static final byte[] IPV6_SOURCE_ADDRESS = {
+            (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01
+    };
+    private static final byte[] IPV6_DESTINATION_ADDRESS = {
+            (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02
+    };
+    private static final Ip6Address IP_6_ADDRESS = Ip6Address.valueOf(IPV6_DESTINATION_ADDRESS);
 
     private static byte[] bytePacket;
 
@@ -149,4 +168,86 @@
         assertTrue(StringUtils.contains(str, "overrideFlag=" + (byte) 1));
         // TODO: need to handle TARGET_ADDRESS
     }
+
+    /**
+     * Test Neighbor Advertisement reply build.
+     */
+    @Test
+    public void testBuildNdpAdv() {
+        Ethernet eth = new Ethernet();
+        eth.setSourceMACAddress(MAC_ADDRESS);
+        eth.setDestinationMACAddress(MAC_ADDRESS2);
+
+        IPv6 ipv6 = new IPv6();
+        ipv6.setSourceAddress(IPV6_SOURCE_ADDRESS);
+        ipv6.setDestinationAddress(IPV6_DESTINATION_ADDRESS);
+        ipv6.setNextHeader(IPv6.PROTOCOL_ICMP6);
+
+        eth.setEtherType(Ethernet.TYPE_IPV6);
+        eth.setPayload(ipv6);
+
+        ICMP6 icmp6 = new ICMP6();
+        icmp6.setIcmpType(ICMP6.NEIGHBOR_SOLICITATION);
+        icmp6.setIcmpCode(NeighborAdvertisement.RESERVED_CODE);
+        ipv6.setPayload(icmp6);
+
+        final Ethernet ethResponse = NeighborAdvertisement.buildNdpAdv(IP_6_ADDRESS, MAC_ADDRESS2, eth);
+
+        assertTrue(ethResponse.getDestinationMAC().equals(MAC_ADDRESS));
+        assertTrue(ethResponse.getSourceMAC().equals(MAC_ADDRESS2));
+        assertTrue(ethResponse.getEtherType() == Ethernet.TYPE_IPV6);
+
+        final IPv6 responseIpv6 = (IPv6) ethResponse.getPayload();
+
+        assertArrayEquals(responseIpv6.getSourceAddress(), ipv6.getDestinationAddress());
+        assertArrayEquals(responseIpv6.getDestinationAddress(), ipv6.getSourceAddress());
+        assertTrue(responseIpv6.getNextHeader() == IPv6.PROTOCOL_ICMP6);
+
+        final ICMP6 responseIcmp6 = (ICMP6) responseIpv6.getPayload();
+
+        assertTrue(responseIcmp6.getIcmpType() == ICMP6.NEIGHBOR_ADVERTISEMENT);
+        assertTrue(responseIcmp6.getIcmpCode() == NeighborAdvertisement.RESERVED_CODE);
+
+        final NeighborAdvertisement responseNadv = (NeighborAdvertisement) responseIcmp6.getPayload();
+
+        assertArrayEquals(responseNadv.getTargetAddress(), IPV6_DESTINATION_ADDRESS);
+        assertTrue(responseNadv.getSolicitedFlag() == NeighborAdvertisement.NDP_SOLICITED_FLAG);
+        assertTrue(responseNadv.getOverrideFlag() == NeighborAdvertisement.NDP_OVERRIDE_FLAG);
+        assertThat(responseNadv.getOptions(),
+                hasItem(hasOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, MAC_ADDRESS2.toBytes())));
+    }
+
+    private NeighborDiscoveryOptionMatcher hasOption(byte type, byte[] data) {
+        return new NeighborDiscoveryOptionMatcher(type, data);
+    }
+
+    private static class NeighborDiscoveryOptionMatcher extends TypeSafeMatcher<NeighborDiscoveryOptions.Option> {
+
+        private final byte type;
+        private final byte[] data;
+        private String reason = "";
+
+        NeighborDiscoveryOptionMatcher(byte type, byte[] data) {
+            this.type = type;
+            this.data = data;
+        }
+
+        @Override
+        protected boolean matchesSafely(NeighborDiscoveryOptions.Option option) {
+            if (type != option.type()) {
+                reason = "Wrong Option type";
+                return false;
+            }
+            if (!Arrays.equals(data, option.data())) {
+                reason = "Wrong Option data";
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText(reason);
+        }
+    }
 }