[CORD-1895] Incorrect VLAN DHCPV6 message to client

Change-Id: I462ec928f3ded6247c9d9699f0cdf3bf3c842eba
diff --git a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
index 6011d11..883bf2f 100644
--- a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
+++ b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
@@ -174,6 +174,8 @@
                                                                        CLIENT2_IFACE_MAC,
                                                                        CLIENT2_VLAN,
                                                                        CLIENT2_VLAN_NATIVE);
+    private static final VlanId CLIENT_BOGUS_VLAN = VlanId.vlanId("108");
+
 
     // Outer relay information
     private static final Ip4Address OUTER_RELAY_IP = Ip4Address.valueOf("10.0.5.253");
@@ -599,8 +601,9 @@
     public void relayDhcp6WithoutAgentInfo() {
         replay(mockHostProviderService);
         // send request
-        packetService.processPacket(new TestDhcp6RequestPacketContext(CLIENT_MAC,
-                                                                     VlanId.NONE,
+        packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
+                                                                     CLIENT_MAC,
+                                                                     CLIENT_VLAN,
                                                                      CLIENT_CP,
                                                                      INTERFACE_IP_V6.ipAddress().getIp6Address(),
                                                                      0));
@@ -614,7 +617,8 @@
                                              capture(capturedHostDesc), eq(false));
         replay(mockHostProviderService);
         // send reply
-        packetService.processPacket(new TestDhcp6ReplyPacketContext(CLIENT_CP, CLIENT_MAC,
+        packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
+                                                                    CLIENT_CP, CLIENT_MAC,
                                                                     CLIENT_VLAN,
                                                                     INTERFACE_IP_V6.ipAddress().getIp6Address(),
                                                                     0));
@@ -627,6 +631,16 @@
         assertEquals(CLIENT_CP.port(), host.location().port());
         assertEquals(1, host.ipAddress().size());
         assertEquals(IP_FOR_CLIENT_V6, host.ipAddress().iterator().next());
+
+        // send release
+        packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
+                CLIENT_MAC,
+                CLIENT_VLAN,
+                CLIENT_CP,
+                INTERFACE_IP_V6.ipAddress().getIp6Address(),
+                0));
+
+        assertEquals(null, manager.hostService.getHost(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)));
     }
 
     /**
@@ -637,7 +651,74 @@
         replay(mockHostProviderService);
         // Assume outer dhcp6 relay agent exists in store already
         // send request
-        packetService.processPacket(new TestDhcp6RequestPacketContext(CLIENT2_MAC,
+        packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
+                CLIENT2_MAC,
+                CLIENT2_VLAN,
+                CLIENT2_CP,
+                OUTER_RELAY_IP_V6,
+                1));
+
+        assertEquals(0, mockRouteStore.routes.size());
+
+        // send reply
+        packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(), CLIENT2_CP,
+                CLIENT2_MAC,
+                CLIENT2_VLAN,
+                OUTER_RELAY_IP_V6,
+                1));
+
+        // won't trigger the host provider service
+        verify(mockHostProviderService);
+        reset(mockHostProviderService);
+        assertEquals(2, mockRouteStore.routes.size()); // ipAddress and prefix
+
+        Route aRoute = mockRouteStore.routes.stream()
+                             .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
+                             .findFirst()
+                             .orElse(null);
+        assertNotEquals(null, aRoute);
+
+        aRoute = mockRouteStore.routes.stream()
+                .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
+                .findFirst()
+                .orElse(null);
+        assertNotEquals(null, aRoute);
+
+        // send release msg
+        packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
+                CLIENT2_MAC,
+                CLIENT2_VLAN,
+                CLIENT2_CP,
+                OUTER_RELAY_IP_V6,
+                1));
+
+        aRoute = mockRouteStore.routes.stream()
+                .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
+                .findFirst()
+                .orElse(null);
+        assertEquals(null, aRoute);
+
+        aRoute = mockRouteStore.routes.stream()
+                .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
+                .findFirst()
+                .orElse(null);
+        assertEquals(null, aRoute);
+
+        assertEquals(0, mockRouteStore.routes.size());
+
+    }
+
+    /**
+     * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host) and server responded
+     * with vlan differnt from client interface vlan.
+     */
+    @Test
+    public void relayDhcp6WithAgentInfoWrongVlan() {
+        replay(mockHostProviderService);
+        // Assume outer dhcp6 relay agent exists in store already
+        // send request
+        packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
+                CLIENT2_MAC,
                 CLIENT2_VLAN,
                 CLIENT2_CP,
                 INTERFACE_IP_V6.ipAddress().getIp6Address(),
@@ -646,23 +727,21 @@
         assertEquals(0, mockRouteStore.routes.size());
 
         // send reply
-        packetService.processPacket(new TestDhcp6ReplyPacketContext(CLIENT2_CP,
+        packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
+                CLIENT2_CP,
                 CLIENT2_MAC,
-                CLIENT2_VLAN,
+                CLIENT_BOGUS_VLAN,  // mismatch
                 INTERFACE_IP_V6.ipAddress().getIp6Address(),
                 1));
 
         // won't trigger the host provider service
         verify(mockHostProviderService);
         reset(mockHostProviderService);
-        assertEquals(2, mockRouteStore.routes.size()); // ipAddress and prefix
+        assertEquals(0, mockRouteStore.routes.size()); // ipAddress and prefix
 
-        Route route = mockRouteStore.routes.get(0);
-        assertEquals(OUTER_RELAY_IP_V6, route.nextHop());
-        assertEquals(IP_FOR_CLIENT_V6.toIpPrefix(), route.prefix());
-        assertEquals(Route.Source.STATIC, route.source());
     }
 
+
     @Test
     public void testDhcp4DualHome() {
         PacketContext packetContext =
@@ -687,7 +766,8 @@
     @Test
     public void testDhcp6DualHome() {
         PacketContext packetContext =
-                new TestDhcp6ReplyPacketContext(CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
+                new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
+                                                CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
                                                 INTERFACE_IP_V6.ipAddress().getIp6Address(),
                                                 0);
         reset(manager.hostService);
@@ -794,6 +874,11 @@
         public void updateRoute(Route route) {
             routes.add(route);
         }
+
+        @Override
+        public void removeRoute(Route route) {
+            routes.remove(route);
+        }
     }
 
     private class MockInterfaceService extends InterfaceServiceAdapter {
@@ -1166,11 +1251,15 @@
 
         byte[] macAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
         byte[] port =  new byte[21];
+        short vlan;
         bb.get(macAddr);
         bb.get();  // separator
         bb.get(port);
+        bb.get();  // separator
+        vlan = bb.getShort();
         interfaceIdOption.setMacAddress(MacAddress.valueOf(macAddr));
         interfaceIdOption.setInPort(port);
+        interfaceIdOption.setVlanId(vlan);
 
         options.add(interfaceIdOption);
 
@@ -1186,14 +1275,19 @@
 
         dhcp6Relay.setOptions(options);
     }
-    private byte[] buildInterfaceId(MacAddress clientMac, ConnectPoint clientCp) {
-        String inPortString = "-" + clientCp.toString();
+    private byte[] buildInterfaceId(MacAddress clientMac, short vlanId, ConnectPoint clientCp) {
+        String inPortString = "-" + clientCp.toString() + ":";
         byte[] clientSoureMacBytes = clientMac.toBytes();
         byte[] inPortStringBytes = inPortString.getBytes();
-        byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length +  inPortStringBytes.length];
+        byte[] vlanIdBytes = new byte[2];
+        vlanIdBytes[0] = (byte) ((vlanId >> 8) & 0xff);  // high-order byte first
+        vlanIdBytes[1] = (byte) (vlanId & 0xff);
+        byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length +  inPortStringBytes.length + vlanIdBytes.length];
 
         System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
         System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
+        System.arraycopy(vlanIdBytes, 0, interfaceIdBytes, clientSoureMacBytes.length + inPortStringBytes.length,
+                vlanIdBytes.length);
 
         return interfaceIdBytes;
     }
@@ -1204,7 +1298,7 @@
         private InboundPacket inPacket;
 
 
-        public TestDhcp6RequestPacketContext(MacAddress clientMac, VlanId vlanId,
+        public TestDhcp6RequestPacketContext(byte msgType, MacAddress clientMac, VlanId vlanId,
                                             ConnectPoint clientCp,
                                             Ip6Address clientGwAddr,
                                             int relayLevel) {
@@ -1213,14 +1307,14 @@
             DHCP6 dhcp6 = new DHCP6();
             if (relayLevel > 0) {
                 DHCP6 dhcp6Payload = new DHCP6();
-                buildDhcp6Packet(dhcp6Payload, DHCP6.MsgType.REQUEST.value(),
+                buildDhcp6Packet(dhcp6Payload, msgType,
                                  IP_FOR_CLIENT_V6,
-                                 PREFIX_FOR_ZERO);
+                        msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
                 DHCP6 dhcp6Parent = null;
                 DHCP6 dhcp6Child = dhcp6Payload;
                 for (int i = 0; i < relayLevel; i++) {
                     dhcp6Parent = new DHCP6();
-                    byte[] interfaceId = buildInterfaceId(clientMac, clientCp);
+                    byte[] interfaceId = buildInterfaceId(clientMac, vlanId.toShort(), clientCp);
                     buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_FORW.value(),
                             INTERFACE_IP_V6.ipAddress().getIp6Address(),
                             OUTER_RELAY_IP_V6,
@@ -1232,9 +1326,9 @@
                     dhcp6 = dhcp6Parent;
                 }
             } else {
-                buildDhcp6Packet(dhcp6, DHCP6.MsgType.REQUEST.value(),
+                buildDhcp6Packet(dhcp6, msgType,
                                         IP_FOR_CLIENT_V6,
-                                        PREFIX_FOR_ZERO);
+                        msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
             }
 
             UDP udp = new UDP();
@@ -1283,17 +1377,17 @@
     private class TestDhcp6ReplyPacketContext extends PacketContextAdapter {
         private InboundPacket inPacket;
 
-        public TestDhcp6ReplyPacketContext(ConnectPoint clientCp, MacAddress clientMac,
+        public TestDhcp6ReplyPacketContext(byte msgType, ConnectPoint clientCp, MacAddress clientMac,
                                         VlanId clientVlan, Ip6Address clientGwAddr,
                                         int relayLevel) {
             super(0, null, null, false);
 
 
             DHCP6 dhcp6Payload = new DHCP6();
-            buildDhcp6Packet(dhcp6Payload, DHCP6.MsgType.REPLY.value(),
+            buildDhcp6Packet(dhcp6Payload, msgType,
                     IP_FOR_CLIENT_V6,
                     PREFIX_FOR_CLIENT_V6);
-            byte[] interfaceId = buildInterfaceId(clientMac, clientCp);
+            byte[] interfaceId = buildInterfaceId(clientMac, clientVlan.toShort(), clientCp);
             DHCP6 dhcp6 = new DHCP6();
             buildRelayMsg(dhcp6, DHCP6.MsgType.RELAY_REPL.value(),
                           INTERFACE_IP_V6.ipAddress().getIp6Address(),