- Set the MPLS rule with BoS false back. NEED TO BE CHECKED with Dell Switches
 - Set the Dec NW TTL action back. NEED TO BE CHECKED with new images of Dell switches
 - Bug fix for stitching rule computation (when the label stack ends with single port adjacency label)
 - Added a work-around to move the last label id to the last sub-tunnel when the last sub-tunnel's label stack is empty

Change-Id: Ifc33c1e517570ade413a2f8f744874ebf1b84e91
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
index 899caf3..5d280ae 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
@@ -1091,11 +1091,11 @@
         //If the next hop is the destination router, do PHP
         if (fwdSws.size() == 1 && mplsLabel.equals(getMplsLabel(fwdSw1))) {
             maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, true, true));
-            //maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, true, false));
+            maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, true, false));
         }
         else {
             maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, false, true));
-            //maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, false, false));
+            maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, false, false));
         }
         IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
                 sw.getDpid().value());
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyTunnel.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyTunnel.java
index 30a7493..8e9a576 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyTunnel.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyTunnel.java
@@ -11,6 +11,7 @@
 import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
 import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
 import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
 import net.onrc.onos.core.matchaction.action.GroupAction;
 import net.onrc.onos.core.matchaction.action.OutputAction;
 import net.onrc.onos.core.matchaction.action.SetDAAction;
@@ -54,9 +55,9 @@
             // If no MPLS label is added, then NW TTL needs to be decremented
 
             if (route.getRoute().isEmpty()) {
-                // XXX
-                //DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
-                //actions.add(decNwTtlAction);
+
+                DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
+                actions.add(decNwTtlAction);
 
                 Switch srcSw = srManager.getSwitch(route.getSrcSwDpid());
                 Switch destSwitch = srManager.getSwitch(route.getFwdSwDpid().get(0).toString());
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingTunnel.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingTunnel.java
index dd76a50..11cad0d 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingTunnel.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingTunnel.java
@@ -24,7 +24,7 @@
     private List<TunnelRouteInfo> routes;
     private SegmentRoutingManager srManager;
 
-    private final int MAX_NUM_LABELS = 2;
+    private final int MAX_NUM_LABELS = 3;
 
     /**
      * Constructor
@@ -92,6 +92,11 @@
             return false;
         }
 
+        // Rearrange the tunnels if the last subtunnel does not have any label
+        // NOTE: this is only for DELL switches because all ACL rule needs PUSH
+        // Label Action.
+        checkAndSplitLabels(stitchingRule);
+
         for (TunnelRouteInfo route: stitchingRule) {
             NeighborSet ns = new NeighborSet();
             for (Dpid dpid: route.getFwdSwDpid())
@@ -112,6 +117,64 @@
     }
 
     /**
+     * Check if last sub tunnel rule label stack is empty.
+     * If so, move a label of previous tunnel to the last sub-tunnel.
+     * It directly updates the tunnel information (stitchingRule) given.
+     * NOTE: This workaroud is required only for Dell Switch restriction.
+     *
+     * @param stitchingRule tunnel information
+     */
+    private void checkAndSplitLabels(List<TunnelRouteInfo> stitchingRule) {
+
+        TunnelRouteInfo lastSubTunnel = stitchingRule.get(stitchingRule.size()-1);
+        if (!lastSubTunnel.getRoute().isEmpty()) {
+            return;
+        }
+        TunnelRouteInfo lastToSecond = stitchingRule.get(stitchingRule.size()-2);
+        if (lastToSecond == null) {
+            return; // Something wrong here
+        }
+        String lastLabelId =
+                lastToSecond.getRoute().get(lastToSecond.getRoute().size()-1);
+        String newStitchingRouterId =
+                lastToSecond.getRoute().get(lastToSecond.getRoute().size()-2);
+
+        if (srManager.isAdjacencySid(newStitchingRouterId)) {
+            String orgNodeSid =
+                    lastToSecond.getRoute().get(lastToSecond.getRoute().size()-3);
+            List<Switch> destNodes = getAdjacencyDestinationNode(orgNodeSid, newStitchingRouterId);
+            newStitchingRouterId = srManager.getMplsLabel(destNodes.get(0).getDpid().toString());
+        }
+        Switch newSitchingSwitch = srManager.getSwitchFromNodeId(newStitchingRouterId);
+        // In this case, # of fwd Sws must be only one
+        String newLabelId =
+                srManager.getMplsLabel(lastSubTunnel.getFwdSwDpid().get(0).toString());
+        List<Dpid> newFwdSws = null;
+        if (srManager.isAdjacencySid(lastLabelId)) {
+            List<Switch> destSwitches = getAdjacencyDestinationNode(newStitchingRouterId, lastLabelId);
+            String orgLastLabelId = srManager.getMplsLabel(destSwitches.get(0).toString());
+            newFwdSws =
+                    srManager.getForwardingSwitchForNodeId(newSitchingSwitch, orgLastLabelId);
+        }
+        else {
+            newFwdSws =
+                srManager.getForwardingSwitchForNodeId(newSitchingSwitch, lastLabelId);
+        }
+
+        // Remove the last ID from the last-to-second sub-tunnel
+        lastToSecond.getRoute().remove(lastLabelId);
+
+        // Reset the src switch
+        lastSubTunnel.setSrcDpid(srManager.getSwitchFromNodeId(
+                newStitchingRouterId).getDpid().toString());
+        // Reset the fwd nodes
+        lastSubTunnel.setFwdSwDpid(newFwdSws);
+        // Add the new Label Id
+        lastSubTunnel.addRoute(newLabelId);
+
+    }
+
+    /**
      * Remove the tunnel.
      * It requests driver to remove all groups for the tunnel
      *
@@ -206,6 +269,17 @@
             }
             // if this is the first node ID to put the label stack..
             else if (i == 1) {
+                // If the adjacency SID is pushed and the next SID is the destination
+                // of the adjacency SID, then do not add the SID.
+                if (prevAdjacencySid != null) {
+                    if (isAdjacencySidNeighborOf(prevNodeId, prevAdjacencySid, nodeId)) {
+                        prevAdjacencySid = null;
+                        prevNodeId = nodeId;
+                        continue;
+                    }
+                    prevAdjacencySid = null;
+                }
+
                 if (checkNeighbor) {
                     List<Dpid> fwdSws = getDpidIfNeighborOf(nodeId, srcSw);
                     // if nodeId is NOT the neighbor of srcSw..