Modify createGroup and removeGroup for tunnel to handle multiple instances
 - createGroup() of the driver returns a list of group IDs
 - removeGroup() removes only the group specified
 - Application removes all the groups for the tunnel
diff --git a/src/main/java/net/floodlightcontroller/core/IOF13Switch.java b/src/main/java/net/floodlightcontroller/core/IOF13Switch.java
index 1dbfc1c..04e2a8d 100644
--- a/src/main/java/net/floodlightcontroller/core/IOF13Switch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOF13Switch.java
@@ -213,7 +213,7 @@
      *        the labelStack
      * @return group identifier
      */
-    public int createGroup(List<Integer> labelStack, List<PortNumber> ports);
+    public List<Integer> createGroup(List<Integer> labelStack, List<PortNumber> ports);
 
     /**
      * Remove the specified group
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 48903c9..d1f8966 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
@@ -350,7 +350,9 @@
 
         @Override
         public void entryRemoved(TunnelNotification tunnelNotification) {
-            tunnelTable.remove(tunnelNotification.getTunnelId());
+            if (tunnelTable.containsKey(tunnelNotification.getTunnelId())) {
+                srManager.removeTunnel(tunnelNotification.getTunnelId());
+            }
         }
 
         @Override
@@ -822,26 +824,29 @@
             if (adjGroupIdMap != null) {
                 groupId = adjGroupIdMap.get(key);
                 if (groupId == null) {
-                    groupId = sw13.createGroup(new ArrayList<Integer>(),
-                            portList);
-                    if (groupId < 0) {
+                    List<Integer> groupIdList = sw13.createGroup(
+                            new ArrayList<Integer>(), portList);
+                    if (groupIdList == null || groupIdList.isEmpty()) {
                         log.debug("Failed to create a group at driver for "
                                 + "adj ID {}", adjId);
                         return;
                     }
                     else {
+                        groupId = groupIdList.get(0);
                         adjGroupIdMap.put(key, groupId);
                     }
                 }
             }
             else {
-                groupId = sw13.createGroup(new ArrayList<Integer>(), portList);
-                if (groupId < 0) {
+                List<Integer> groupIdList = sw13.createGroup(
+                        new ArrayList<Integer>(), portList);
+                if (groupIdList == null || groupIdList.isEmpty()) {
                     log.debug("Failed to create a group at driver for adj ID {}",
                             adjId);
                     return;
                 }
                 else {
+                    groupId = groupIdList.get(0);
                     adjGroupIdMap = new HashMap<Integer, Integer>();
                     adjGroupIdMap.put(key, groupId);
                     adjcencyGroupIdTable.put(sw.getDpid().toString(),
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicy.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicy.java
index 86c0009..81b1870 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicy.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicy.java
@@ -8,7 +8,7 @@
      * Enums for policy type
      *
      */
-    public enum PolicyType{
+    public enum PolicyType {
         TUNNEL_FLOW,
         LOADBALANCE,
         AVOID,
@@ -52,7 +52,7 @@
      *
      * @return policy ID
      */
-    public String getPolicyId(){
+    public String getPolicyId() {
         return this.policyId;
     }
 
@@ -61,7 +61,7 @@
      *
      * @return PacketMatch object
      */
-    public PacketMatch getMatch(){
+    public PacketMatch getMatch() {
         return this.match;
     }
 
@@ -70,7 +70,7 @@
      *
      * @return priority
      */
-    public int getPriority(){
+    public int getPriority() {
         return this.priority;
     }
 
@@ -79,7 +79,7 @@
      *
      * @return policy type
      */
-    public PolicyType getType(){
+    public PolicyType getType() {
         return this.type;
     }
 
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 ad5e0f1..a5a0f2b 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingTunnel.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingTunnel.java
@@ -41,30 +41,45 @@
         this.routes = new ArrayList<TunnelRouteInfo>();
     }
 
-    public SegmentRoutingTunnel(SegmentRoutingManager srm, TunnelNotification tunnelNotification) {
+    /**
+     * Constructor
+     *
+     * @param srm SegmentRoutingManager objeect
+     * @param tunnelNotification tunnel information published by other controllers
+     */
+    public SegmentRoutingTunnel(SegmentRoutingManager srm,
+            TunnelNotification tunnelNotification) {
         this.srManager = srm;
         this.tunnelId = tunnelNotification.getTunnelId();
         this.labelIds = tunnelNotification.getLabelIds();
         this.routes = tunnelNotification.getRouteInfo();
     }
 
+    /**
+     * Check if there is any sub tunnel that starts with the router managed by
+     * the controller. If so, create groups for the sub tunnel and set the
+     * group Id list. Then, set modified flag to true so that the tunnel
+     * information is published again with the new group ID list.
+     *
+     * @return true if any new group is created, otherwise false.
+     */
     public boolean checkAndCreateTunnel() {
 
         boolean modified = false;
         for (TunnelRouteInfo route: routes) {
             if (srManager.getIOF13Switch(route.getSrcSwDpid()) != null) {
-                if (route.getGroupId() == -1) {
+                if (route.getGroupIdList() == null) {
                     NeighborSet ns = new NeighborSet();
                     for (Dpid dpid: route.getFwdSwDpid())
                         ns.addDpid(dpid);
 
                     printTunnelInfo(route.srcSwDpid, tunnelId, route.getRoute(), ns);
-                    int groupId = -1;
-                    if ((groupId =createGroupsForTunnel(tunnelId, route, ns)) < 0) {
+                    List<Integer> groupIdList = createGroupsForTunnel(tunnelId, route, ns);
+                    if (groupIdList == null) {
                         log.debug("Failed to create a tunnel at driver.");
                         return false;
                     }
-                    route.setGroupId(groupId);
+                    route.setGroupIdList(groupIdList);
                     modified = true;
                 }
             }
@@ -137,15 +152,15 @@
                     ns.addDpid(dpid);
 
                 printTunnelInfo(route.srcSwDpid, tunnelId, route.getRoute(), ns);
-                int groupId = -1;
-                if ((groupId =createGroupsForTunnel(tunnelId, route, ns)) < 0) {
+                List<Integer> groupIdList = null;
+                if ((groupIdList =createGroupsForTunnel(tunnelId, route, ns)) == null) {
                     log.debug("Failed to create a tunnel at driver.");
                     return false;
                 }
-                route.setGroupId(groupId);
+                route.setGroupIdList(groupIdList);
             }
             else {
-                route.setGroupId(-1);
+                route.setGroupIdList(null);
             }
         }
 
@@ -230,10 +245,15 @@
         for (TunnelRouteInfo route: routes) {
             IOF13Switch sw13 = srManager.getIOF13Switch(route.srcSwDpid);
             if (sw13 != null) {
-                if (!sw13.removeGroup(route.getGroupId())) {
-                    log.warn("Faied to remove the tunnel {} at driver",
-                            tunnelId);
-                    return false;
+                // Group needs to be removed in reverse order because
+                // the group being pointed by any other group cannot be removed
+                for (int i = route.getGroupIdList().size()-1; i >= 0; i--) {
+                    int groupId = route.getGroupIdList().get(i);
+                    if (!sw13.removeGroup(groupId)) {
+                        log.warn("Faied to remove the tunnel {} at driver",
+                                tunnelId);
+                        return false;
+                    }
                 }
             }
         }
@@ -249,14 +269,14 @@
      * @param ns NeighborSet to forward packets
      * @return group ID, return -1 if it fails
      */
-    private int createGroupsForTunnel(String tunnelId, TunnelRouteInfo routeInfo,
+    private List<Integer> createGroupsForTunnel(String tunnelId, TunnelRouteInfo routeInfo,
             NeighborSet ns) {
 
         IOF13Switch targetSw = srManager.getIOF13Switch(routeInfo.srcSwDpid);
 
         if (targetSw == null) {
             log.debug("Switch {} is gone.", routeInfo.srcSwDpid);
-            return -1;
+            return null;
         }
 
         List<Integer> Ids = new ArrayList<Integer>();
@@ -264,9 +284,9 @@
             Ids.add(Integer.parseInt(IdStr));
 
         List<PortNumber> ports = getPortsFromNeighborSet(routeInfo.srcSwDpid, ns);
-        int groupId = targetSw.createGroup(Ids, ports);
+        List<Integer> groupIdList = targetSw.createGroup(Ids, ports);
 
-        return groupId;
+        return groupIdList;
     }
 
     /**
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/TunnelRouteInfo.java b/src/main/java/net/onrc/onos/apps/segmentrouting/TunnelRouteInfo.java
index 8c63f84..19b94e7 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/TunnelRouteInfo.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/TunnelRouteInfo.java
@@ -10,7 +10,7 @@
     public String srcSwDpid;
     public List<Dpid> fwdSwDpids;
     public List<String> route;
-    public int gropuId;
+    public List<Integer> groupIdList;
 
     /**
      * Constructor
@@ -48,14 +48,12 @@
     }
 
     /**
-     * Set the group ID for the sub tunnel
-     * The group pushes all the IDs in label stack and forward to the next
-     * router.
+     * Set the group ID list for the tunnel
      *
-     * @param groupId
+     * @param gidLIst List of group ID
      */
-    public void setGroupId(int groupId) {
-        this.gropuId = groupId;
+    public void setGroupIdList(List<Integer> gidLIst) {
+        this.groupIdList = gidLIst;
     }
 
     /**
@@ -91,6 +89,16 @@
      * @return Group ID
      */
     public int getGroupId() {
-        return this.gropuId;
+        return groupIdList.get(groupIdList.size()-1);
     }
+
+    /**
+     * Get the group ID list pushing IDs in the label stack for the tunnel
+     *
+     * @return List of the group ID
+     */
+    public List<Integer> getGroupIdList() {
+        return this.groupIdList;
+    }
+
 }
diff --git a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java
index 6b453b8..1fe9c1b 100644
--- a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java
+++ b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java
@@ -1438,7 +1438,7 @@
 
         OFMessage gm = factory.buildGroupDelete()
                 .setGroup(group)
-                // .setGroupType(groupInfo.groupType) /* Due to a bug in CPqD
+                //.setGroupType(groupInfo.groupType) /* Due to a bug in CPqD
                 // switch */
                 .setGroupType(OFGroupType.SELECT)
                 .setXid(getNextTransactionId())
@@ -2068,13 +2068,13 @@
      *        the labelStack
      * @return group identifier
      */
-    public int createGroup(List<Integer> labelStack, List<PortNumber> ports) {
+    public List<Integer> createGroup(List<Integer> labelStack, List<PortNumber> ports) {
 
         log.debug("createGroup in sw {} with labelStack {} and ports {}",
                 getStringId(), labelStack, ports);
         if (ports == null) {
             log.warn("createGroup in sw {} with wrong input parameters", getStringId());
-            return -1;
+            return null;
         }
 
         List<PortNumber> activePorts = new ArrayList<PortNumber>();
@@ -2084,10 +2084,11 @@
         }
         if (activePorts.isEmpty()) {
             log.warn("createGroup in sw {} with no active ports", getStringId());
-            return -1;
+            return null;
         }
 
         int labelStackSize = (labelStack != null) ? labelStack.size() : 0;
+        List<Integer> groupIdList = new ArrayList<Integer>();
 
         /* Filter out disabled ports */
 
@@ -2121,7 +2122,9 @@
                     OFGroupType.SELECT, buckets);
             setEcmpGroup(ecmpInfo);
             userDefinedGroups.put(innermostGroupId, ecmpInfo);
-            return innermostGroupId;
+
+            groupIdList.add(innermostGroupId);
+            return groupIdList;
         }
 
         /* If the label stack has two or more labels, then a chain of groups
@@ -2147,6 +2150,7 @@
                             labelStack.get(i).intValue(), false);
                     lastSetOfGroupIds.put(sp, currGroupId);
                     userDefinedGroups.put(currGroupId, indirectGroup);
+                    groupIdList.add(currGroupId);
                 }
                 else if (i == (labelStackSize - 1)) {
                     /* Innermost label processing */
@@ -2158,6 +2162,7 @@
                             lastSetOfGroupIds);
                     userDefinedGroups.put(
                             innermostGroupId, topLevelGroup);
+                    groupIdList.add(innermostGroupId);
                     break;
                 }
                 else {
@@ -2170,12 +2175,13 @@
                     /* Overwrite with this iteration's group IDs */
                     lastSetOfGroupIds.put(sp, currGroupId);
                     userDefinedGroups.put(currGroupId, indirectGroup);
+                    groupIdList.add(currGroupId);
                 }
             }
         }
         log.debug("createGroup in sw{}: group created with innermost group id {}",
                 getStringId(), innermostGroupId);
-        return innermostGroupId;
+        return groupIdList;
     }
 
     /**
@@ -2191,10 +2197,11 @@
             return false;
         }
         deleteGroup(group);
+        /*
         for (BucketInfo bucket : group.buckets) {
             int currGroupIdToBeDeleted = bucket.togroupNo;
             while (currGroupIdToBeDeleted != -1) {
-                /* Assuming indirect groups with single buckets */
+                // Assuming indirect groups with single buckets
                 int nextGroupIdToBeDeleted =
                         userDefinedGroups.get(currGroupIdToBeDeleted).
                         buckets.get(0).togroupNo;
@@ -2205,6 +2212,7 @@
                 currGroupIdToBeDeleted = nextGroupIdToBeDeleted;
             }
         }
+        */
 
         userDefinedGroups.remove(groupId);
         log.debug("removeGroup in sw {}: removed group with group id {}",