CORD-1419 CORD-1425 CORD-1496 CORD-639 Changes for dual-ToRs

Introduces the concept of edge-pairs (or paired-ToRs) which
can have some subnets/prefixes reachable by both ToRs.
   - Each ToR can also have prefixes reachable only by itself,
     even though it is part of an edge-pair.
   - The paired link between ToRs in an edge-pair is ignored
     for ECMP calculations.
   - Required a change in how destinations and next-hops are stored.
     The neighborSet is now a destinationSet, and no longer carries
     next-hop info, which is now stored in NextNeighbors. As a result,
     the DestinationSetNextObjectiveStoreKey and ECMP group id do not
     change as next-hops come and go.
   - It is now possible to have buckets in hash groups with the same
     outport but different labels.
   - DefaultRoutingHandler has been rearraged to be more readable, and
     clearly highlight the three major ways that routing changes can
     happen in the network.

Also fixes the case where config is added after switches connect to the controller.

Change-Id: I7ce93ab201f6ef2c01cbe07a51ee78cd6a0a112e
diff --git a/src/main/java/org/onosproject/segmentrouting/cli/NextHopCommand.java b/src/main/java/org/onosproject/segmentrouting/cli/NextHopCommand.java
new file mode 100644
index 0000000..2b43de5
--- /dev/null
+++ b/src/main/java/org/onosproject/segmentrouting/cli/NextHopCommand.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016-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 java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Map;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.segmentrouting.SegmentRoutingService;
+import org.onosproject.segmentrouting.grouphandler.NextNeighbors;
+import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
+
+/**
+ * Command to read the current state of the DestinationSetNextObjectiveStore.
+ *
+ */
+@Command(scope = "onos", name = "sr-next-hops",
+        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 {
+
+    private static final String FORMAT_MAPPING = "  %s";
+
+    @Override
+    protected void execute() {
+        SegmentRoutingService srService =
+                AbstractShellCommand.get(SegmentRoutingService.class);
+        printDestinationSet(srService.getDestinationSet());
+    }
+
+    private void printDestinationSet(Map<DestinationSetNextObjectiveStoreKey,
+                                      NextNeighbors> ds) {
+        ArrayList<DestinationSetNextObjectiveStoreKey> a = new ArrayList<>();
+        ds.keySet().forEach(key -> a.add(key));
+        a.sort(new Comp());
+
+        StringBuilder dsbldr = new StringBuilder();
+        for (int i = 0; i < a.size(); i++) {
+            dsbldr.append("\n " + a.get(i));
+            dsbldr.append(" --> via: " + ds.get(a.get(i)));
+        }
+        print(FORMAT_MAPPING, dsbldr.toString());
+    }
+
+    static class Comp implements Comparator<DestinationSetNextObjectiveStoreKey> {
+
+        @Override
+        public int compare(DestinationSetNextObjectiveStoreKey o1,
+                           DestinationSetNextObjectiveStoreKey o2) {
+            int res = o1.deviceId().toString().compareTo(o2.deviceId().toString());
+            if (res < 0) {
+                return -1;
+            } else if (res > 0) {
+                return +1;
+            }
+            return 0;
+        }
+
+    }
+}