Implement CLI commands to view and delete SR internal stores

sr-next-dst (renamed from sr-next-hops)
sr-next-port
sr-next-vlan
sr-next-mcast (renamed from sr-mcast-next)
sr-next-pw
sr-next-xconnect
sr-next-invalidate <next-id>

Change-Id: Id5178f786bb97e26ddb86015105dd19604ac0817
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index ed2a678..19b0304 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -75,6 +75,7 @@
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.NextObjective;
 import org.onosproject.net.host.HostEvent;
 import org.onosproject.net.host.HostListener;
 import org.onosproject.net.host.HostProbingService;
@@ -856,7 +857,7 @@
     }
 
     @Override
-    public ImmutableMap<DestinationSetNextObjectiveStoreKey, NextNeighbors> getDestinationSet() {
+    public ImmutableMap<DestinationSetNextObjectiveStoreKey, NextNeighbors> getDstNextObjStore() {
         if (dsNextObjStore != null) {
             return ImmutableMap.copyOf(dsNextObjStore.entrySet());
         } else {
@@ -865,6 +866,76 @@
     }
 
     @Override
+    public ImmutableMap<VlanNextObjectiveStoreKey, Integer> getVlanNextObjStore() {
+        if (vlanNextObjStore != null) {
+            return ImmutableMap.copyOf(vlanNextObjStore.entrySet());
+        } else {
+            return ImmutableMap.of();
+        }
+    }
+
+    @Override
+    public ImmutableMap<PortNextObjectiveStoreKey, Integer> getPortNextObjStore() {
+        if (portNextObjStore != null) {
+            return ImmutableMap.copyOf(portNextObjStore.entrySet());
+        } else {
+            return ImmutableMap.of();
+        }
+    }
+
+    @Override
+    public ImmutableMap<String, NextObjective> getPwInitNext() {
+        if (l2TunnelHandler != null) {
+            return l2TunnelHandler.getInitNext();
+        } else {
+            return ImmutableMap.of();
+        }
+    }
+
+    @Override
+    public ImmutableMap<String, NextObjective> getPwTermNext() {
+        if (l2TunnelHandler != null) {
+            return l2TunnelHandler.getTermNext();
+        } else {
+            return ImmutableMap.of();
+        }
+    }
+
+    @Override
+    public void invalidateNextObj(int nextId) {
+        if (dsNextObjStore != null) {
+            dsNextObjStore.entrySet().forEach(e -> {
+                if (e.getValue().nextId() == nextId) {
+                    dsNextObjStore.remove(e.getKey());
+                }
+            });
+        }
+        if (vlanNextObjStore != null) {
+            vlanNextObjStore.entrySet().forEach(e -> {
+                if (e.getValue() == nextId) {
+                    vlanNextObjStore.remove(e.getKey());
+                }
+            });
+        }
+        if (portNextObjStore != null) {
+            portNextObjStore.entrySet().forEach(e -> {
+                if (e.getValue() == nextId) {
+                    portNextObjStore.remove(e.getKey());
+                }
+            });
+        }
+        if (mcastHandler != null) {
+            mcastHandler.removeNextId(nextId);
+        }
+        if (l2TunnelHandler != null) {
+            l2TunnelHandler.removeNextId(nextId);
+        }
+        if (xconnectService != null) {
+            xconnectService.removeNextId(nextId);
+        }
+    }
+
+    @Override
     public void verifyGroups(DeviceId id) {
         DefaultGroupHandler gh = groupHandlerMap.get(id);
         if (gh != null) {
@@ -884,7 +955,7 @@
 
     @Override
     public Map<McastStoreKey, Integer> getMcastNextIds(IpAddress mcastIp) {
-        return mcastHandler.getMcastNextIds(mcastIp);
+        return mcastHandler.getNextIds(mcastIp);
     }
 
     @Override
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
index c8c9044..a29b784 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
@@ -27,6 +27,7 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.flowobjective.NextObjective;
 import org.onosproject.segmentrouting.grouphandler.NextNeighbors;
 import org.onosproject.segmentrouting.mcast.McastRole;
 import org.onosproject.segmentrouting.mcast.McastRoleStoreKey;
@@ -39,6 +40,8 @@
 
 import com.google.common.collect.ImmutableMap;
 import org.onosproject.segmentrouting.mcast.McastStoreKey;
+import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
+import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
 
 import java.util.List;
 import java.util.Map;
@@ -211,9 +214,53 @@
     /**
      * Returns the destinatiomSet-NextObjective store contents.
      *
-     * @return current contents of the destinationSetNextObjectiveStore
+     * @return current contents of the dstNextObjStore
      */
-    ImmutableMap<DestinationSetNextObjectiveStoreKey, NextNeighbors> getDestinationSet();
+    ImmutableMap<DestinationSetNextObjectiveStoreKey, NextNeighbors> getDstNextObjStore();
+
+    /**
+     * Returns the VLAN next objective store.
+     *
+     * @return current contents of the vlanNextObjStore
+     */
+    ImmutableMap<VlanNextObjectiveStoreKey, Integer> getVlanNextObjStore();
+
+    /**
+     * Returns the port next objective store.
+     *
+     * @return current contents of the portNextObjStore
+     */
+    ImmutableMap<PortNextObjectiveStoreKey, Integer> getPortNextObjStore();
+
+    /**
+     * Returns the associated next ids to the mcast groups or to the single
+     * group if mcastIp is present.
+     *
+     * @param mcastIp the group ip
+     * @return the mapping mcastIp-device to next id
+     */
+    Map<McastStoreKey, Integer> getMcastNextIds(IpAddress mcastIp);
+
+    /**
+     * Returns the PW init next objective store.
+     *
+     * @return current contents of the l2InitiationNextObjStore
+     */
+    ImmutableMap<String, NextObjective> getPwInitNext();
+
+    /**
+     * Returns the PW termination next objective store.
+     *
+     * @return current contents of the l2TerminationNextObjStore
+     */
+    ImmutableMap<String, NextObjective> getPwTermNext();
+
+    /**
+     * Removes all entries in dst/vlan/port/mcast NextObjectiveStore that are associated with the given nextId.
+     *
+     * @param nextId nextId
+     */
+    void invalidateNextObj(int nextId);
 
     /**
      * Triggers the verification of all ECMP groups in the specified device.
@@ -241,15 +288,6 @@
     ImmutableMap<DeviceId, Set<PortNumber>> getDownedPortState();
 
     /**
-     * Returns the associated next ids to the mcast groups or to the single
-     * group if mcastIp is present.
-     *
-     * @param mcastIp the group ip
-     * @return the mapping mcastIp-device to next id
-     */
-    Map<McastStoreKey, Integer> getMcastNextIds(IpAddress mcastIp);
-
-    /**
      * Returns the associated roles to the mcast groups or to the single
      * group if mcastIp is present.
      *
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/InvalidateNextCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/InvalidateNextCommand.java
new file mode 100644
index 0000000..aa3f78b
--- /dev/null
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/InvalidateNextCommand.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting.cli;
+
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.osgi.ServiceNotFoundException;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.segmentrouting.SegmentRoutingService;
+
+/**
+ * Command to invalidate next id from SR internal stores.
+ */
+@Command(scope = "onos", name = "sr-next-invalidate",
+        description = "Invalidate given next id from SR internal stores")
+public class InvalidateNextCommand extends AbstractShellCommand {
+
+    private static final String CONFIRM_PHRASE = "please";
+
+    @Argument(name = "nextId", description = "Next ID", index = 0)
+    private String nextId = null;
+
+    @Argument(name = "confirm", description = "Confirmation phrase", index = 1)
+    private String please = null;
+
+    @Override
+    protected void execute() {
+        if (please == null || !please.equals(CONFIRM_PHRASE)) {
+            print("WARNING: System may enter an unpredictable state if the next ID is force invalidated." +
+                    "Enter confirmation phrase to continue.");
+            return;
+        }
+
+        try {
+            SegmentRoutingService srService = AbstractShellCommand.get(SegmentRoutingService.class);
+            srService.invalidateNextObj(Integer.parseInt(nextId));
+        } catch (ServiceNotFoundException e) {
+            print("SegmentRoutingService unavailable");
+        }
+    }
+}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/McastNextListCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/McastNextListCommand.java
index cefb244..569f097 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/McastNextListCommand.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/McastNextListCommand.java
@@ -37,7 +37,7 @@
 /**
  * Command to show the list of mcast nextids.
  */
-@Command(scope = "onos", name = "sr-mcast-next",
+@Command(scope = "onos", name = "sr-next-mcast",
         description = "Lists all mcast nextids")
 public class McastNextListCommand extends AbstractShellCommand {
 
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextHopCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextDstCommand.java
similarity index 93%
rename from apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextHopCommand.java
rename to apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextDstCommand.java
index 2b43de5..07950a7 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextHopCommand.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextDstCommand.java
@@ -29,12 +29,11 @@
 
 /**
  * Command to read the current state of the DestinationSetNextObjectiveStore.
- *
  */
-@Command(scope = "onos", name = "sr-next-hops",
+@Command(scope = "onos", name = "sr-next-dst",
         description = "Displays the current next-hops seen by each switch "
                 + "towards a set of destinations and the next-id it maps to")
-public class NextHopCommand extends AbstractShellCommand {
+public class NextDstCommand extends AbstractShellCommand {
 
     private static final String FORMAT_MAPPING = "  %s";
 
@@ -42,7 +41,7 @@
     protected void execute() {
         SegmentRoutingService srService =
                 AbstractShellCommand.get(SegmentRoutingService.class);
-        printDestinationSet(srService.getDestinationSet());
+        printDestinationSet(srService.getDstNextObjStore());
     }
 
     private void printDestinationSet(Map<DestinationSetNextObjectiveStoreKey,
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextPortCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextPortCommand.java
new file mode 100644
index 0000000..5be9d77
--- /dev/null
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextPortCommand.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.segmentrouting.SegmentRoutingService;
+import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Map;
+
+/**
+ * Command to read the current state of the portNextObjStore.
+ */
+@Command(scope = "onos", name = "sr-next-port",
+        description = "Displays the current port / next-id it mapping")
+public class NextPortCommand extends AbstractShellCommand {
+    @Override
+    protected void execute() {
+        SegmentRoutingService srService =
+                AbstractShellCommand.get(SegmentRoutingService.class);
+        print(srService.getPortNextObjStore());
+    }
+
+    private void print(Map<PortNextObjectiveStoreKey, Integer> portNextObjStore) {
+        ArrayList<PortNextObjectiveStoreKey> a = new ArrayList<>(portNextObjStore.keySet());
+        a.sort(Comparator
+                .comparing((PortNextObjectiveStoreKey o) -> o.deviceId().toString())
+                .thenComparing((PortNextObjectiveStoreKey o) -> o.portNumber().toLong()));
+
+        StringBuilder builder = new StringBuilder();
+        a.forEach(k ->
+            builder.append("\n")
+                    .append(k)
+                    .append(" --> ")
+                    .append(portNextObjStore.get(k))
+        );
+        print(builder.toString());
+    }
+}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextVlanCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextVlanCommand.java
new file mode 100644
index 0000000..0295a90
--- /dev/null
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/NextVlanCommand.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.segmentrouting.SegmentRoutingService;
+import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Map;
+
+/**
+ * Command to read the current state of the vlanNextObjStore.
+ */
+@Command(scope = "onos", name = "sr-next-vlan",
+        description = "Displays the current vlan / next-id it mapping")
+public class NextVlanCommand extends AbstractShellCommand {
+    @Override
+    protected void execute() {
+        SegmentRoutingService srService =
+                AbstractShellCommand.get(SegmentRoutingService.class);
+        print(srService.getVlanNextObjStore());
+    }
+
+    private void print(Map<VlanNextObjectiveStoreKey, Integer> vlanNextObjStore) {
+        ArrayList<VlanNextObjectiveStoreKey> a = new ArrayList<>(vlanNextObjStore.keySet());
+        a.sort(Comparator
+                .comparing((VlanNextObjectiveStoreKey o) -> o.deviceId().toString())
+                .thenComparing((VlanNextObjectiveStoreKey o) -> o.vlanId().toShort()));
+
+        StringBuilder builder = new StringBuilder();
+        a.forEach(k ->
+            builder.append("\n")
+                    .append(k)
+                    .append(" --> ")
+                    .append(vlanNextObjStore.get(k))
+        );
+        print(builder.toString());
+    }
+}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireNextListCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireNextListCommand.java
new file mode 100644
index 0000000..d37d3e8
--- /dev/null
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireNextListCommand.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.segmentrouting.SegmentRoutingService;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Map;
+
+/**
+ * Command to read the current state of the pseudowire next stores.
+ */
+@Command(scope = "onos", name = "sr-next-pw",
+        description = "Displays the current next-id for pseudowire")
+public class PseudowireNextListCommand extends AbstractShellCommand {
+    @Override
+    protected void execute() {
+        SegmentRoutingService srService =
+                AbstractShellCommand.get(SegmentRoutingService.class);
+        print(srService.getPwInitNext());
+        print(srService.getPwTermNext());
+    }
+
+    private void print(Map<String, NextObjective> nextStore) {
+        ArrayList<String> a = new ArrayList<>(nextStore.keySet());
+        a.sort(Comparator.comparing((String o) -> o));
+
+        StringBuilder builder = new StringBuilder();
+        a.forEach(k ->
+            builder.append("\n")
+                    .append(k)
+                    .append(" --> ")
+                    .append(nextStore.get(k).id())
+        );
+        print(builder.toString());
+    }
+}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectNextListCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectNextListCommand.java
new file mode 100644
index 0000000..f7a6b51
--- /dev/null
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectNextListCommand.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.segmentrouting.xconnect.api.XconnectKey;
+import org.onosproject.segmentrouting.xconnect.api.XconnectService;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Map;
+
+/**
+ * Command to read the current state of the xconnect next stores.
+ */
+@Command(scope = "onos", name = "sr-next-xconnect",
+        description = "Displays the current next-id for xconnect")
+public class XconnectNextListCommand extends AbstractShellCommand {
+    @Override
+    protected void execute() {
+        XconnectService xconnectService =
+                AbstractShellCommand.get(XconnectService.class);
+        print(xconnectService.getNext());
+    }
+
+    private void print(Map<XconnectKey, NextObjective> nextStore) {
+        ArrayList<XconnectKey> a = new ArrayList<>(nextStore.keySet());
+        a.sort(Comparator
+                .comparing((XconnectKey o) -> o.deviceId().toString())
+                .thenComparing((XconnectKey o) -> o.vlanId().toShort()));
+
+        StringBuilder builder = new StringBuilder();
+        a.forEach(k ->
+            builder.append("\n")
+                    .append(k)
+                    .append(" --> ")
+                    .append(nextStore.get(k).id())
+        );
+        print(builder.toString());
+    }
+}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastHandler.java
index 88601aa..4f70a1b 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastHandler.java
@@ -286,7 +286,7 @@
                     Map<ConnectPoint, List<ConnectPoint>> mcastPaths = Maps.newHashMap();
                     Set<DeviceId> visited = Sets.newHashSet();
                     List<ConnectPoint> currentPath = Lists.newArrayList(source);
-                    buildMcastPaths(source.deviceId(), visited, mcastPaths,
+                    mcastUtils.buildMcastPaths(mcastNextObjStore.asJavaMap(), source.deviceId(), visited, mcastPaths,
                                     currentPath, mcastRoute.group(), source);
                     // Get all the sinks and process them
                     Set<ConnectPoint> sinks = processSinksToBeAdded(source, mcastRoute.group(),
@@ -1816,7 +1816,7 @@
      * @param mcastIp the group ip
      * @return the mapping mcastIp-device to next id
      */
-    public Map<McastStoreKey, Integer> getMcastNextIds(IpAddress mcastIp) {
+    public Map<McastStoreKey, Integer> getNextIds(IpAddress mcastIp) {
         if (mcastIp != null) {
             return mcastNextObjStore.entrySet().stream()
                     .filter(mcastEntry -> mcastIp.equals(mcastEntry.getKey().mcastIp()))
@@ -1827,6 +1827,19 @@
     }
 
     /**
+     * Removes given next ID from mcast next id store.
+     *
+     * @param nextId next id
+     */
+    public void removeNextId(int nextId) {
+        mcastNextObjStore.entrySet().forEach(e -> {
+            if (e.getValue().value().id() == nextId) {
+                mcastNextObjStore.remove(e.getKey());
+            }
+        });
+    }
+
+    /**
      * Returns the associated roles to the mcast groups or to the single
      * group if mcastIp is present.
      *
@@ -1891,7 +1904,8 @@
         if (source != null) {
             Set<DeviceId> visited = Sets.newHashSet();
             List<ConnectPoint> currentPath = Lists.newArrayList(source);
-            buildMcastPaths(source.deviceId(), visited, mcastPaths, currentPath, mcastIp, source);
+            mcastUtils.buildMcastPaths(mcastNextObjStore.asJavaMap(), source.deviceId(), visited, mcastPaths,
+                    currentPath, mcastIp, source);
         }
         return mcastPaths;
     }
@@ -1916,7 +1930,8 @@
                 Map<ConnectPoint, List<ConnectPoint>> mcastPaths = Maps.newHashMap();
                 Set<DeviceId> visited = Sets.newHashSet();
                 List<ConnectPoint> currentPath = Lists.newArrayList(source);
-                buildMcastPaths(source.deviceId(), visited, mcastPaths, currentPath, mcastIp, source);
+                mcastUtils.buildMcastPaths(mcastNextObjStore.asJavaMap(), source.deviceId(), visited, mcastPaths,
+                        currentPath, mcastIp, source);
                 mcastPaths.forEach(mcastTrees::put);
             });
         }
@@ -1924,63 +1939,6 @@
     }
 
     /**
-     * Build recursively the mcast paths.
-     *
-     * @param toVisit the node to visit
-     * @param visited the visited nodes
-     * @param mcastPaths the current mcast paths
-     * @param currentPath the current path
-     * @param mcastIp the group ip
-     * @param source the source
-     */
-    private void buildMcastPaths(DeviceId toVisit, Set<DeviceId> visited,
-                                 Map<ConnectPoint, List<ConnectPoint>> mcastPaths,
-                                 List<ConnectPoint> currentPath, IpAddress mcastIp,
-                                 ConnectPoint source) {
-        // If we have visited the node to visit there is a loop
-        if (visited.contains(toVisit)) {
-            return;
-        }
-        // Visit next-hop
-        visited.add(toVisit);
-        VlanId assignedVlan = mcastUtils.assignedVlan(toVisit.equals(source.deviceId()) ? source : null);
-        McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, toVisit, assignedVlan);
-        // Looking for next-hops
-        if (mcastNextObjStore.containsKey(mcastStoreKey)) {
-            // Build egress connect points, get ports and build relative cps
-            NextObjective nextObjective = mcastNextObjStore.get(mcastStoreKey).value();
-            Set<PortNumber> outputPorts = mcastUtils.getPorts(nextObjective.next());
-            ImmutableSet.Builder<ConnectPoint> cpBuilder = ImmutableSet.builder();
-            outputPorts.forEach(portNumber -> cpBuilder.add(new ConnectPoint(toVisit, portNumber)));
-            Set<ConnectPoint> egressPoints = cpBuilder.build();
-            Set<Link> egressLinks;
-            List<ConnectPoint> newCurrentPath;
-            Set<DeviceId> newVisited;
-            DeviceId newToVisit;
-            for (ConnectPoint egressPoint : egressPoints) {
-                egressLinks = srManager.linkService.getEgressLinks(egressPoint);
-                // If it does not have egress links, stop
-                if (egressLinks.isEmpty()) {
-                    // Add the connect points to the path
-                    newCurrentPath = Lists.newArrayList(currentPath);
-                    newCurrentPath.add(0, egressPoint);
-                    mcastPaths.put(egressPoint, newCurrentPath);
-                } else {
-                    newVisited = Sets.newHashSet(visited);
-                    // Iterate over the egress links for the next hops
-                    for (Link egressLink : egressLinks) {
-                        newToVisit = egressLink.dst().deviceId();
-                        newCurrentPath = Lists.newArrayList(currentPath);
-                        newCurrentPath.add(0, egressPoint);
-                        newCurrentPath.add(0, egressLink.dst());
-                        buildMcastPaths(newToVisit, newVisited, mcastPaths, newCurrentPath, mcastIp, source);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
      * Return the leaders of the mcast groups.
      *
      * @param mcastIp the group ip
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastUtils.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastUtils.java
index 0793984..52232b9 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastUtils.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastUtils.java
@@ -18,7 +18,9 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import com.google.common.hash.HashFunction;
 import com.google.common.hash.Hashing;
 import org.onlab.packet.Ethernet;
@@ -31,6 +33,7 @@
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.HostId;
+import org.onosproject.net.Link;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.config.basics.McastConfig;
 import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -55,6 +58,7 @@
 import org.slf4j.Logger;
 
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -486,4 +490,64 @@
         // Otherwise take all the groups
         return ImmutableMap.copyOf(mcastLeaderCache);
     }
+
+    /**
+     * Build recursively the mcast paths.
+     *
+     * @param mcastNextObjStore mcast next obj store
+     * @param toVisit the node to visit
+     * @param visited the visited nodes
+     * @param mcastPaths the current mcast paths
+     * @param currentPath the current path
+     * @param mcastIp the group ip
+     * @param source the source
+     */
+    void buildMcastPaths(Map<McastStoreKey, NextObjective> mcastNextObjStore,
+                                 DeviceId toVisit, Set<DeviceId> visited,
+                                 Map<ConnectPoint, List<ConnectPoint>> mcastPaths,
+                                 List<ConnectPoint> currentPath, IpAddress mcastIp,
+                                 ConnectPoint source) {
+        // If we have visited the node to visit there is a loop
+        if (visited.contains(toVisit)) {
+            return;
+        }
+        // Visit next-hop
+        visited.add(toVisit);
+        VlanId assignedVlan = assignedVlan(toVisit.equals(source.deviceId()) ? source : null);
+        McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, toVisit, assignedVlan);
+        // Looking for next-hops
+        if (mcastNextObjStore.containsKey(mcastStoreKey)) {
+            // Build egress connect points, get ports and build relative cps
+            NextObjective nextObjective = mcastNextObjStore.get(mcastStoreKey);
+            Set<PortNumber> outputPorts = getPorts(nextObjective.next());
+            ImmutableSet.Builder<ConnectPoint> cpBuilder = ImmutableSet.builder();
+            outputPorts.forEach(portNumber -> cpBuilder.add(new ConnectPoint(toVisit, portNumber)));
+            Set<ConnectPoint> egressPoints = cpBuilder.build();
+            Set<Link> egressLinks;
+            List<ConnectPoint> newCurrentPath;
+            Set<DeviceId> newVisited;
+            DeviceId newToVisit;
+            for (ConnectPoint egressPoint : egressPoints) {
+                egressLinks = srManager.linkService.getEgressLinks(egressPoint);
+                // If it does not have egress links, stop
+                if (egressLinks.isEmpty()) {
+                    // Add the connect points to the path
+                    newCurrentPath = Lists.newArrayList(currentPath);
+                    newCurrentPath.add(0, egressPoint);
+                    mcastPaths.put(egressPoint, newCurrentPath);
+                } else {
+                    newVisited = Sets.newHashSet(visited);
+                    // Iterate over the egress links for the next hops
+                    for (Link egressLink : egressLinks) {
+                        newToVisit = egressLink.dst().deviceId();
+                        newCurrentPath = Lists.newArrayList(currentPath);
+                        newCurrentPath.add(0, egressPoint);
+                        newCurrentPath.add(0, egressLink.dst());
+                        buildMcastPaths(mcastNextObjStore, newToVisit, newVisited, mcastPaths, newCurrentPath, mcastIp,
+                                source);
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
index fbefb76..21a8761 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
@@ -16,6 +16,7 @@
 
 package org.onosproject.segmentrouting.pwaas;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import org.apache.commons.lang3.RandomUtils;
@@ -263,6 +264,39 @@
         return configurationValidity(newPseudowires);
     }
 
+    @Override
+    public ImmutableMap<String, NextObjective> getInitNext() {
+        if (l2InitiationNextObjStore != null) {
+            return ImmutableMap.copyOf(l2InitiationNextObjStore.asJavaMap());
+        } else {
+            return ImmutableMap.of();
+        }
+    }
+
+    @Override
+    public ImmutableMap<String, NextObjective> getTermNext() {
+        if (l2TerminationNextObjStore != null) {
+            return ImmutableMap.copyOf(l2TerminationNextObjStore.asJavaMap());
+        } else {
+            return ImmutableMap.of();
+        }
+    }
+
+    @Override
+    public void removeNextId(int nextId) {
+        l2InitiationNextObjStore.entrySet().forEach(e -> {
+            if (e.getValue().value().id() == nextId) {
+                l2InitiationNextObjStore.remove(e.getKey());
+            }
+        });
+
+        l2TerminationNextObjStore.entrySet().forEach(e -> {
+            if (e.getValue().value().id() == nextId) {
+                l2TerminationNextObjStore.remove(e.getKey());
+            }
+        });
+    }
+
     /**
      * Returns the new vlan id for an ingress point of a
      * pseudowire. For double tagged, it is the outer,
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
index d3b95b4..2a003b3 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
@@ -16,6 +16,9 @@
 
 package org.onosproject.segmentrouting.pwaas;
 
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.net.flowobjective.NextObjective;
+
 import java.util.List;
 import java.util.Set;
 
@@ -91,6 +94,27 @@
     Result checkIfPwExists(long tunnelId, boolean pending);
 
     /**
+     * Returns the PW init next objective store.
+     *
+     * @return current contents of the l2InitiationNextObjStore
+     */
+    ImmutableMap<String, NextObjective> getInitNext();
+
+    /**
+     * Returns the PW termination next objective store.
+     *
+     * @return current contents of the l2TerminationNextObjStore
+     */
+    ImmutableMap<String, NextObjective> getTermNext();
+
+    /**
+     * Removes given next ID from both PW init/term next obj store.
+     *
+     * @param nextId next ID
+     */
+    void removeNextId(int nextId);
+
+    /**
      * Pwaas pipelines.
      */
     enum Pipeline {
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/storekey/PortNextObjectiveStoreKey.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/storekey/PortNextObjectiveStoreKey.java
index 0429bd1..9aa41db 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/storekey/PortNextObjectiveStoreKey.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/storekey/PortNextObjectiveStoreKey.java
@@ -111,7 +111,7 @@
 
     @Override
     public String toString() {
-        return "Device: " + deviceId + " Port: " + portNum +
+        return "ConnectPoint: " + deviceId + "/" + portNum +
                 " Treatment: " + treatment +
                 " Meta: " + meta;
     }
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectService.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectService.java
index 1fede71..dfdc422 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectService.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectService.java
@@ -15,11 +15,13 @@
  */
 package org.onosproject.segmentrouting.xconnect.api;
 
+import com.google.common.collect.ImmutableMap;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.VlanId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.flowobjective.NextObjective;
 
 import java.util.Set;
 
@@ -71,4 +73,18 @@
      */
     boolean hasXconnect(ConnectPoint cp);
 
+    /**
+     * Returns the Xconnect next objective store.
+     *
+     * @return current contents of the xconnectNextObjStore
+     */
+    ImmutableMap<XconnectKey, NextObjective> getNext();
+
+    /**
+     * Removes given next ID from Xconnect next objective store.
+     *
+     * @param nextId next ID
+     */
+    void removeNextId(int nextId);
+
 }
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/XconnectManager.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/XconnectManager.java
index 696b811..ab4ec53 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/XconnectManager.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/XconnectManager.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.segmentrouting.xconnect.impl;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.Activate;
@@ -192,6 +193,24 @@
         );
     }
 
+    @Override
+    public ImmutableMap<XconnectKey, NextObjective> getNext() {
+        if (xconnectNextObjStore != null) {
+            return ImmutableMap.copyOf(xconnectNextObjStore.asJavaMap());
+        } else {
+            return ImmutableMap.of();
+        }
+    }
+
+    @Override
+    public void removeNextId(int nextId) {
+        xconnectNextObjStore.entrySet().forEach(e -> {
+            if (e.getValue().value().id() == nextId) {
+                xconnectNextObjStore.remove(e.getKey());
+            }
+        });
+    }
+
     private class XconnectMapListener implements MapEventListener<XconnectKey, Set<PortNumber>> {
         @Override
         public void event(MapEvent<XconnectKey, Set<PortNumber>> event) {
diff --git a/apps/segmentrouting/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/segmentrouting/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 04682e9..71f986b 100644
--- a/apps/segmentrouting/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/segmentrouting/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -46,7 +46,22 @@
             <action class="org.onosproject.segmentrouting.cli.EcmpGraphCommand"/>
         </command>
         <command>
-            <action class="org.onosproject.segmentrouting.cli.NextHopCommand"/>
+            <action class="org.onosproject.segmentrouting.cli.NextDstCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.segmentrouting.cli.NextVlanCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.segmentrouting.cli.NextPortCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.segmentrouting.cli.PseudowireNextListCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.segmentrouting.cli.XconnectNextListCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.segmentrouting.cli.InvalidateNextCommand"/>
         </command>
         <command>
             <action class="org.onosproject.segmentrouting.cli.ShouldProgramCommand"/>