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/apps/sdnip/src/main/java/org/onosproject/sdnip/Router.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/Router.java
index d34a395..2b2213a 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/Router.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/Router.java
@@ -30,10 +30,11 @@
 
 import org.apache.commons.lang3.tuple.Pair;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.Ip4Address;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
-import org.onlab.packet.Ip4Address;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Host;
@@ -272,7 +273,7 @@
      * or IPv6.
      *
      * @param prefix the prefix to use
-     * @return true if the rotue was found and removed, otherwise false
+     * @return true if the route was found and removed, otherwise false
      */
     boolean removeRibRoute(IpPrefix prefix) {
         if (prefix.version() == Ip4Address.VERSION) {
@@ -455,25 +456,26 @@
         }
 
         // Match the destination IP prefix at the first hop
-        TrafficSelector selector;
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
         if (prefix.version() == Ip4Address.VERSION) {
-            selector = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_IPV4)
-                .matchIPDst(prefix)
-                .build();
+            selector.matchEthType(Ethernet.TYPE_IPV4);
         } else {
-            selector = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_IPV6)
-                .matchIPDst(prefix)
-                .build();
+            selector.matchEthType(Ethernet.TYPE_IPV6);
         }
+        selector.matchIPDst(prefix);
 
         // Rewrite the destination MAC address
-        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setEthDst(nextHopMacAddress)
-                .build();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
+                .setEthDst(nextHopMacAddress);
+        if (!egressInterface.vlan().equals(VlanId.NONE)) {
+            treatment.setVlanId(egressInterface.vlan());
+            // If we set VLAN ID, we have to make sure a VLAN tag exists.
+            // TODO support no VLAN -> VLAN routing
+            selector.matchVlanId(VlanId.ANY);
+        }
 
-        return new MultiPointToSinglePointIntent(appId, selector, treatment,
+        return new MultiPointToSinglePointIntent(appId, selector.build(),
+                                                 treatment.build(),
                                                  ingressPorts, egressPort);
     }
 
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/config/Interface.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/config/Interface.java
index 7ddf0ae..b495f07 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/config/Interface.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/config/Interface.java
@@ -19,6 +19,7 @@
 import java.util.Set;
 
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.host.InterfaceIpAddress;
 import org.onosproject.net.host.PortAddresses;
@@ -34,6 +35,7 @@
     private final ConnectPoint connectPoint;
     private final Set<InterfaceIpAddress> ipAddresses;
     private final MacAddress macAddress;
+    private final VlanId vlan;
 
     /**
      * Creates an Interface based on a connection point, a set of interface
@@ -45,10 +47,11 @@
      */
     public Interface(ConnectPoint connectPoint,
                      Set<InterfaceIpAddress> ipAddresses,
-                     MacAddress macAddress) {
+                     MacAddress macAddress, VlanId vlan) {
         this.connectPoint = connectPoint;
         this.ipAddresses = Sets.newHashSet(ipAddresses);
         this.macAddress = macAddress;
+        this.vlan = vlan;
     }
 
     /**
@@ -60,6 +63,7 @@
         connectPoint = portAddresses.connectPoint();
         ipAddresses = Sets.newHashSet(portAddresses.ipAddresses());
         macAddress = portAddresses.mac();
+        vlan = portAddresses.vlan();
     }
 
     /**
@@ -76,18 +80,27 @@
      *
      * @return the set of interface IP addresses
      */
-   public Set<InterfaceIpAddress> ipAddresses() {
+    public Set<InterfaceIpAddress> ipAddresses() {
         return ipAddresses;
     }
 
-   /**
-    * Retrieves the MAC address that is assigned to the interface.
-    *
-    * @return the MAC address
-    */
-   public MacAddress mac() {
-       return macAddress;
-   }
+    /**
+     * Retrieves the MAC address that is assigned to the interface.
+     *
+     * @return the MAC address
+     */
+    public MacAddress mac() {
+        return macAddress;
+    }
+
+    /**
+     * Retrieves the VLAN ID that is assigned to the interface.
+     *
+     * @return the VLAN ID
+     */
+    public VlanId vlan() {
+        return vlan;
+    }
 
     @Override
     public boolean equals(Object other) {
@@ -99,12 +112,13 @@
 
         return  connectPoint.equals(otherInterface.connectPoint) &&
                 ipAddresses.equals(otherInterface.ipAddresses) &&
-                macAddress.equals(otherInterface.macAddress);
+                macAddress.equals(otherInterface.macAddress) &&
+                vlan.equals(otherInterface.vlan);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(connectPoint, ipAddresses, macAddress);
+        return Objects.hash(connectPoint, ipAddresses, macAddress, vlan);
     }
 
     @Override
@@ -113,6 +127,7 @@
                 .add("connectPoint", connectPoint)
                 .add("ipAddresses", ipAddresses)
                 .add("macAddress", macAddress)
+                .add("vlan", vlan)
                 .toString();
     }
 }