T3 Vlan handling when output to controller

Change-Id: I82f7f94ee99800bac57b68f79984f2b4a2f7b714
(cherry picked from commit e9b45cc494bea453de9536ae559cfab0c1509061)
diff --git a/src/main/java/org/onosproject/t3/api/GroupsInDevice.java b/src/main/java/org/onosproject/t3/api/GroupsInDevice.java
index 3cfb41a..e63bdca 100644
--- a/src/main/java/org/onosproject/t3/api/GroupsInDevice.java
+++ b/src/main/java/org/onosproject/t3/api/GroupsInDevice.java
@@ -25,7 +25,7 @@
 /**
  * Class to represent the groups in a device for a given output and packet.
  */
-//FIXME consider removing.
+//FIXME consider name change.
 public class GroupsInDevice {
 
     private ConnectPoint output;
@@ -34,8 +34,9 @@
 
     /**
      * Saves the given groups for the output connect point and the selector.
-     * @param output the output connect point
-     * @param groups the groups
+     *
+     * @param output   the output connect point
+     * @param groups   the groups
      * @param selector the selector representing the final packet
      */
     public GroupsInDevice(ConnectPoint output, List<Group> groups, TrafficSelector selector) {
@@ -47,6 +48,7 @@
 
     /**
      * Returns the output connect point.
+     *
      * @return the connect point
      */
     public ConnectPoint getOutput() {
@@ -55,6 +57,7 @@
 
     /**
      * Returns the groups.
+     *
      * @return groups.
      */
     public List<Group> getGroups() {
@@ -63,12 +66,22 @@
 
     /**
      * Returns the final packet after traversing the network.
+     *
      * @return the selector with packet info
      */
     public TrafficSelector getFinalPacket() {
         return selector;
     }
 
+    /**
+     * Updates the final packet.
+     *
+     * @param updatedPacket the updated final packet
+     */
+    public void setFinalPacket(TrafficSelector updatedPacket) {
+        selector = updatedPacket;
+    }
+
     @Override
     public String toString() {
         return "GroupsInDevice{" +
diff --git a/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java b/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
index 8aeb874..5d6fabb 100644
--- a/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
+++ b/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
@@ -45,6 +45,7 @@
 import org.onosproject.net.flow.criteria.EthCriterion;
 import org.onosproject.net.flow.criteria.EthTypeCriterion;
 import org.onosproject.net.flow.criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
@@ -70,7 +71,7 @@
 import java.util.stream.Collectors;
 
 import static org.onlab.packet.EthType.EtherType;
-import static org.onosproject.net.flow.TrafficSelector.*;
+import static org.onosproject.net.flow.TrafficSelector.Builder;
 import static org.onosproject.net.flow.instructions.Instructions.GroupInstruction;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -174,6 +175,7 @@
                 NodeId master = mastershipService.getMasterFor(cp.deviceId());
                 trace.addResultMessage("Packet goes to the controller " + master.id());
                 computePath(completePath, trace, outputPath.getOutput());
+                handleVlanToController(outputPath, trace);
 
             } else if (linkService.getEgressLinks(cp).size() > 0) {
 
@@ -242,6 +244,32 @@
     }
 
     /**
+     * If the initial packet comes tagged with a Vlan we output it with that to ONOS.
+     * If ONOS applied a vlan we remove it.
+     *
+     * @param outputPath the output
+     * @param trace      the trace we are building
+     */
+    private void handleVlanToController(GroupsInDevice outputPath, StaticPacketTrace trace) {
+
+        VlanIdCriterion initialVid = (VlanIdCriterion) trace.getInitialPacket().getCriterion(Criterion.Type.VLAN_VID);
+        VlanIdCriterion finalVid = (VlanIdCriterion) outputPath.getFinalPacket().getCriterion(Criterion.Type.VLAN_VID);
+
+        if (initialVid != null && !initialVid.equals(finalVid) && initialVid.vlanId().equals(VlanId.NONE)) {
+
+            Set<Criterion> finalCriteria = new HashSet<>(outputPath.getFinalPacket().criteria());
+            //removing the final vlanId
+            finalCriteria.remove(finalVid);
+            Builder packetUpdated = DefaultTrafficSelector.builder();
+            finalCriteria.forEach(packetUpdated::add);
+            //Initial was none so we set it to that
+            packetUpdated.add(Criteria.matchVlanId(VlanId.NONE));
+            //Update final packet
+            outputPath.setFinalPacket(packetUpdated.build());
+        }
+    }
+
+    /**
      * Checks if the path contains the device.
      *
      * @param completePath the path
diff --git a/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java b/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
index 7c584c9..5426278 100644
--- a/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
+++ b/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
@@ -137,6 +137,8 @@
                 traceSuccess.resultMessage().contains(MASTER_1));
         ConnectPoint connectPoint = traceSuccess.getGroupOuputs(ARP_FLOW_DEVICE).get(0).getOutput();
         assertEquals("Packet Should go to CONTROLLER", PortNumber.CONTROLLER, connectPoint.port());
+        assertNull("VlanId should be null", traceSuccess.getGroupOuputs(ARP_FLOW_DEVICE).get(0)
+                .getFinalPacket().getCriterion(Criterion.Type.VLAN_VID));
         log.info("trace {}", traceSuccess.resultMessage());
     }