Implemented VLAN-to-VLAN routing support for SDN-IP.

SDN-IP can now support peering and routing between hosts that are connected
on VLANs.

Changes include:
 * Updated NetworkConfigReader app to read (optional) VLAN configuration
 * Updated VlanId to support the 'VLAN present' value - in a match this means
   that a VLAN tag must be present, but it can contain any value.
 * Updated SDN-IP to set destination VLAN tag values if appropriate
 * Updated FlowModBuilder and FlowEntryBuilder to support 'VLAN present' value
 * Slew of test updates.

Change-Id: Ief48cede5c1fd50e1efa851da5a97fb4a8edda29
diff --git a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
index ce7de7e..2a461bf 100644
--- a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
@@ -31,6 +31,10 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
 import org.onosproject.event.Event;
 import org.onosproject.event.impl.TestEventDispatcher;
 import org.onosproject.net.ConnectPoint;
@@ -51,10 +55,6 @@
 import org.onosproject.net.provider.AbstractProvider;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.store.trivial.impl.SimpleHostStore;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -231,7 +231,7 @@
     @Test
     public void bindAddressesToPort() {
         PortAddresses add1 =
-            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
+            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
 
         mgr.bindAddressesToPort(add1);
         Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -241,7 +241,8 @@
 
         // Add some more addresses and check that they're added correctly
         PortAddresses add2 =
-            new PortAddresses(CP1, Sets.newHashSet(IA3),  null);
+            new PortAddresses(CP1, Sets.newHashSet(IA3),  null,
+                              VlanId.vlanId((short) 2));
 
         mgr.bindAddressesToPort(add2);
         storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -250,7 +251,7 @@
         assertTrue(storedAddresses.contains(add1));
         assertTrue(storedAddresses.contains(add2));
 
-        PortAddresses add3 = new PortAddresses(CP1, null, MAC2);
+        PortAddresses add3 = new PortAddresses(CP1, null, MAC2, VlanId.NONE);
 
         mgr.bindAddressesToPort(add3);
         storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -264,7 +265,7 @@
     @Test
     public void unbindAddressesFromPort() {
         PortAddresses add1 =
-            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
+            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
 
         mgr.bindAddressesToPort(add1);
         Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -273,7 +274,7 @@
         assertTrue(storedAddresses.contains(add1));
 
         PortAddresses rem1 =
-            new PortAddresses(CP1, Sets.newHashSet(IA1), null);
+            new PortAddresses(CP1, Sets.newHashSet(IA1), null, VlanId.NONE);
 
         mgr.unbindAddressesFromPort(rem1);
         storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -292,7 +293,7 @@
     @Test
     public void clearAddresses() {
         PortAddresses add1 =
-            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
+            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
 
         mgr.bindAddressesToPort(add1);
         Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -309,7 +310,7 @@
     @Test
     public void getAddressBindingsForPort() {
         PortAddresses add1 =
-            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
+            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
 
         mgr.bindAddressesToPort(add1);
         Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -325,7 +326,7 @@
         assertTrue(storedAddresses.isEmpty());
 
         PortAddresses add1 =
-            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
+            new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
 
         mgr.bindAddressesToPort(add1);
 
@@ -334,7 +335,7 @@
         assertTrue(storedAddresses.size() == 1);
 
         PortAddresses add2 =
-            new PortAddresses(CP2, Sets.newHashSet(IA3), MAC2);
+            new PortAddresses(CP2, Sets.newHashSet(IA3), MAC2, VlanId.NONE);
 
         mgr.bindAddressesToPort(add2);
 
diff --git a/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java b/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java
index 834379b..7152ad9 100644
--- a/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java
+++ b/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java
@@ -37,6 +37,7 @@
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onosproject.core.ApplicationId;
+import org.onlab.packet.VlanId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
@@ -130,7 +131,7 @@
 
         ConnectPoint cp = new ConnectPoint(devId, portNum);
         PortAddresses pa =
-            new PortAddresses(cp, Collections.singleton(IA1), sourceMac);
+            new PortAddresses(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE);
 
         expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
                 .andReturn(Collections.<Host>emptySet()).anyTimes();
@@ -165,6 +166,76 @@
         final byte[] pktData = new byte[packet.data().remaining()];
         packet.data().get(pktData);
         eth.deserialize(pktData, 0, pktData.length);
+        assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID());
+        ARP arp = (ARP) eth.getPayload();
+        assertArrayEquals(SOURCE_ADDR.toOctets(),
+                          arp.getSenderProtocolAddress());
+        assertArrayEquals(sourceMac.toBytes(),
+                          arp.getSenderHardwareAddress());
+        assertArrayEquals(TARGET_IP_ADDR.toOctets(),
+                          arp.getTargetProtocolAddress());
+    }
+
+    @Test
+    public void testMonitorHostDoesNotExistWithVlan() throws Exception {
+
+        HostManager hostManager = createMock(HostManager.class);
+
+        DeviceId devId = DeviceId.deviceId("fake");
+        short vlan = 5;
+
+        Device device = createMock(Device.class);
+        expect(device.id()).andReturn(devId).anyTimes();
+        replay(device);
+
+        PortNumber portNum = PortNumber.portNumber(1L);
+
+        Port port = createMock(Port.class);
+        expect(port.number()).andReturn(portNum).anyTimes();
+        replay(port);
+
+        TestDeviceService deviceService = new TestDeviceService();
+        deviceService.addDevice(device, Collections.singleton(port));
+
+        ConnectPoint cp = new ConnectPoint(devId, portNum);
+        PortAddresses pa =
+            new PortAddresses(cp, Collections.singleton(IA1), sourceMac,
+                              VlanId.vlanId(vlan));
+
+        expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
+                .andReturn(Collections.<Host>emptySet()).anyTimes();
+        expect(hostManager.getAddressBindingsForPort(cp))
+                .andReturn(Collections.singleton(pa)).anyTimes();
+        replay(hostManager);
+
+        TestPacketService packetService = new TestPacketService();
+
+
+        // Run the test
+        hostMonitor = new HostMonitor(deviceService, packetService, hostManager);
+
+        hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
+        hostMonitor.run(null);
+
+
+        // Check that a packet was sent to our PacketService and that it has
+        // the properties we expect
+        assertEquals(1, packetService.packets.size());
+        OutboundPacket packet = packetService.packets.get(0);
+
+        // Check the output port is correct
+        assertEquals(1, packet.treatment().instructions().size());
+        Instruction instruction = packet.treatment().instructions().get(0);
+        assertTrue(instruction instanceof OutputInstruction);
+        OutputInstruction oi = (OutputInstruction) instruction;
+        assertEquals(portNum, oi.port());
+
+        // Check the output packet is correct (well the important bits anyway)
+        Ethernet eth = new Ethernet();
+        final byte[] pktData = new byte[packet.data().remaining()];
+        packet.data().get(pktData);
+        eth.deserialize(pktData, 0, pktData.length);
+        assertEquals(vlan, eth.getVlanID());
         ARP arp = (ARP) eth.getPayload();
         assertArrayEquals(SOURCE_ADDR.toOctets(),
                           arp.getSenderProtocolAddress());
diff --git a/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java b/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
index a349738f..ca218c6 100644
--- a/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
@@ -216,10 +216,12 @@
             InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2);
             PortAddresses pa1 =
                 new PortAddresses(cp, Sets.newHashSet(ia1),
-                                  MacAddress.valueOf(2 * i - 1));
+                                  MacAddress.valueOf(2 * i - 1),
+                                  VlanId.vlanId((short) 1));
             PortAddresses pa2 =
                     new PortAddresses(cp, Sets.newHashSet(ia2),
-                                      MacAddress.valueOf(2 * i));
+                                      MacAddress.valueOf(2 * i),
+                                      VlanId.NONE);
 
             addresses.add(pa1);
             addresses.add(pa2);
@@ -269,7 +271,7 @@
     }
 
     /**
-     * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
+     * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
      * destination host is known.
      * Verifies the correct ARP reply is sent out the correct port.
      */
@@ -297,7 +299,7 @@
     }
 
     /**
-     * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
+     * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
      * destination host is not known.
      * Verifies the ARP request is flooded out the correct edge ports.
      */
@@ -320,7 +322,7 @@
     }
 
     /**
-     * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
+     * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
      * destination host is known for that IP address, but is not on the same
      * VLAN as the source host.
      * Verifies the ARP request is flooded out the correct edge ports.
@@ -421,7 +423,7 @@
     }
 
     /**
-     * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
+     * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the
      * destination host is known.
      * Verifies the correct ARP request is sent out the correct port.
      */
@@ -444,7 +446,7 @@
     }
 
     /**
-     * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
+     * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the
      * destination host is not known.
      * Verifies the correct ARP request is flooded out the correct edge ports.
      */