Adding drop on same output of input connect point

Change-Id: I316a3ffaa47f9d152210474055f2877823edb992
(cherry picked from commit 31a3d1e5408ff3d95fc74b3d390dd34da647aa5a)
diff --git a/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java b/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
index f3edbd6..24cd251 100644
--- a/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
+++ b/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
@@ -140,6 +140,7 @@
             trace.addResultMessage("No output out of device " + in.deviceId() + ". Packet is dropped");
             return trace;
         }
+
         //If the trace has ouputs we analyze them all
         for (GroupsInDevice outputPath : trace.getGroupOuputs(in.deviceId())) {
             log.debug("Output path {}", outputPath.getOutput());
@@ -382,7 +383,7 @@
 
             for (FlowEntry entry : flows) {
                 getGroupsFromInstructions(trace, groups, entry.treatment().allInstructions(),
-                        entry.deviceId(), builder, outputPorts);
+                        entry.deviceId(), builder, outputPorts, in);
             }
             packet = builder.build();
             log.debug("Groups hit by packet {}", packet);
@@ -412,15 +413,11 @@
                                     TrafficSelector.Builder builder, List<PortNumber> outputPorts,
                                     Set<Instruction> outputFlowEntries) {
         if (outputFlowEntries.size() > 1) {
-            log.warn("There cannot be more than one OUTPUT instruction for {}", packet);
+            log.warn("There cannot be more than one flow entry with OUTPUT instruction for {}", packet);
         } else {
             OutputInstruction outputInstruction = (OutputInstruction) outputFlowEntries.iterator().next();
             //FIXME using GroupsInDevice for output even if flows.
-            trace.addGroupOutputPath(in.deviceId(),
-                    new GroupsInDevice(ConnectPoint.deviceConnectPoint(in.deviceId()
-                            + "/" + outputInstruction.port()),
-                            ImmutableList.of(), builder.build()));
-            outputPorts.add(outputInstruction.port());
+            buildOutputFromDevice(trace, in, builder, outputPorts, outputInstruction, ImmutableList.of());
         }
     }
 
@@ -474,7 +471,8 @@
      */
     private void getGroupsFromInstructions(StaticPacketTrace trace, List<Group> groupsForDevice,
                                            List<Instruction> instructions, DeviceId deviceId,
-                                           TrafficSelector.Builder builder, List<PortNumber> outputPorts) {
+                                           TrafficSelector.Builder builder, List<PortNumber> outputPorts,
+                                           ConnectPoint in) {
         List<Instruction> groupInstructionlist = new ArrayList<>();
         for (Instruction instruction : instructions) {
             log.debug("Considering Instruction {}", instruction);
@@ -484,11 +482,8 @@
                 //if the instruction is not group we need to update the packet or add the output
                 //to the possible outputs for this packet
                 if (instruction.type().equals(Instruction.Type.OUTPUT)) {
-                    outputPorts.add(((OutputInstruction) instruction).port());
-                    trace.addGroupOutputPath(deviceId,
-                            new GroupsInDevice(ConnectPoint.deviceConnectPoint(deviceId + "/" +
-                                    ((OutputInstruction) instruction).port()),
-                                    groupsForDevice, builder.build()));
+                    buildOutputFromDevice(trace, in, builder, outputPorts,
+                            (OutputInstruction) instruction, groupsForDevice);
                 } else {
                     builder = translateInstruction(builder, instruction);
                 }
@@ -512,12 +507,38 @@
             //Cycle in each of the group's buckets and add them to the groups for this Device.
             for (GroupBucket bucket : group.buckets().buckets()) {
                 getGroupsFromInstructions(trace, groupsForDevice, bucket.treatment().allInstructions(),
-                        deviceId, builder, outputPorts);
+                        deviceId, builder, outputPorts, in);
             }
         }
     }
 
     /**
+     * Check if the output is the input port, if so adds a dop result message, otherwise builds
+     * a possible output from this device.
+     *
+     * @param trace             the trace
+     * @param in                the input connect point
+     * @param builder           the packet builder
+     * @param outputPorts       the list of output ports for this device
+     * @param outputInstruction the output instruction
+     * @param groupsForDevice
+     */
+    private void buildOutputFromDevice(StaticPacketTrace trace, ConnectPoint in, TrafficSelector.Builder builder,
+                                       List<PortNumber> outputPorts, OutputInstruction outputInstruction,
+                                       List<Group> groupsForDevice) {
+        ConnectPoint output = ConnectPoint.deviceConnectPoint(in.deviceId() + "/" +
+                outputInstruction.port());
+        if (output.equals(in)) {
+            trace.addResultMessage("Connect point out " + output + " is same as initial input " +
+                    trace.getInitialConnectPoint());
+        } else {
+            trace.addGroupOutputPath(in.deviceId(),
+                    new GroupsInDevice(output, groupsForDevice, builder.build()));
+            outputPorts.add(outputInstruction.port());
+        }
+    }
+
+    /**
      * Applies all give instructions to the input packet.
      *
      * @param packet       the input packet
diff --git a/src/test/java/org/onosproject/t3/impl/T3TestObjects.java b/src/test/java/org/onosproject/t3/impl/T3TestObjects.java
index b1edb86..7d24bbd 100644
--- a/src/test/java/org/onosproject/t3/impl/T3TestObjects.java
+++ b/src/test/java/org/onosproject/t3/impl/T3TestObjects.java
@@ -88,6 +88,24 @@
 
     static final ConnectPoint SINGLE_FLOW_OUT_CP = ConnectPoint.deviceConnectPoint(SINGLE_FLOW_DEVICE + "/" + 2);
 
+    //same output as input
+    static final DeviceId SAME_OUTPUT_FLOW_DEVICE = DeviceId.deviceId("sameOutputDevice");
+
+    private static final TrafficTreatment SAME_OUTPUT_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
+            .setOutput(PortNumber.portNumber(1)).build();
+    private static final FlowRule SAME_OUTPUT_FLOW = DefaultFlowEntry.builder().forDevice(SAME_OUTPUT_FLOW_DEVICE)
+            .forTable(0)
+            .withPriority(100)
+            .withSelector(SINGLE_FLOW_SELECTOR)
+            .withTreatment(SAME_OUTPUT_FLOW_TREATMENT)
+            .fromApp(new DefaultApplicationId(0, "TestApp"))
+            .makePermanent()
+            .build();
+    static final FlowEntry SAME_OUTPUT_FLOW_ENTRY = new DefaultFlowEntry(SAME_OUTPUT_FLOW);
+
+    static final ConnectPoint SAME_OUTPUT_FLOW_CP = ConnectPoint.deviceConnectPoint(SAME_OUTPUT_FLOW_DEVICE + "/" + 1);
+
+
     //Dual Flow Test
     static final DeviceId DUAL_FLOW_DEVICE = DeviceId.deviceId("DualFlowDevice");
     private static final TrafficTreatment TRANSITION_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
diff --git a/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java b/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
index 382a468..63bcc32 100644
--- a/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
+++ b/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
@@ -106,9 +106,21 @@
         StaticPacketTrace traceFail = mngr.trace(PACKET_OK, ConnectPoint.deviceConnectPoint(OFFLINE_DEVICE + "/1"));
         assertNotNull("Trace should not be null", traceFail);
         assertNull("Trace should have 0 output", traceFail.getGroupOuputs(SINGLE_FLOW_DEVICE));
+    }
+
+    /**
+     * Tests failure on same output.
+     */
+    @Test
+    public void sameOutput() {
+        StaticPacketTrace traceFail = mngr.trace(PACKET_OK, SAME_OUTPUT_FLOW_CP);
+        assertNotNull("Trace should not be null", traceFail);
+        assertTrue("Trace should be unsuccessful",
+                traceFail.resultMessage().contains("is same as initial input"));
         log.info("trace {}", traceFail.resultMessage());
     }
 
+
     /**
      * Tests failure on device with no flows.
      */
@@ -264,6 +276,8 @@
                 return ImmutableList.of(TOPO_GROUP_FLOW_ENTRY);
             } else if (deviceId.equals(HARDWARE_DEVICE)) {
                 return ImmutableList.of(HARDWARE_ETH_FLOW_ENTRY, HARDWARE_FLOW_ENTRY);
+            } else if (deviceId.equals(SAME_OUTPUT_FLOW_DEVICE)) {
+                return ImmutableList.of(SAME_OUTPUT_FLOW_ENTRY);
             }
             return ImmutableList.of();
         }