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/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NextNeighbors.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NextNeighbors.java
new file mode 100644
index 0000000..1a0507b
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NextNeighbors.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2015-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.grouphandler;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import org.onosproject.net.DeviceId;
+
+public class NextNeighbors {
+    private final Map<DeviceId, Set<DeviceId>> dstNextHops;
+    private final int nextId;
+
+    public NextNeighbors(Map<DeviceId, Set<DeviceId>> dstNextHops, int nextId) {
+        this.dstNextHops = dstNextHops;
+        this.nextId = nextId;
+    }
+
+    public Map<DeviceId, Set<DeviceId>> dstNextHops() {
+        return dstNextHops;
+    }
+
+    public Set<DeviceId> nextHops(DeviceId deviceId) {
+        return dstNextHops.get(deviceId);
+    }
+
+    public int nextId() {
+        return nextId;
+    }
+
+    public boolean containsNextHop(DeviceId nextHopId) {
+        for (Set<DeviceId> nextHops : dstNextHops.values()) {
+            if (nextHops != null && nextHops.contains(nextHopId)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public Set<DeviceId> getDstForNextHop(DeviceId nextHopId) {
+        Set<DeviceId> dstSet = new HashSet<>();
+        for (DeviceId dstKey : dstNextHops.keySet()) {
+            if (dstNextHops.get(dstKey).contains(nextHopId)) {
+                dstSet.add(dstKey);
+            }
+        }
+        return dstSet;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof NextNeighbors)) {
+            return false;
+        }
+        NextNeighbors that = (NextNeighbors) o;
+        return (this.nextId == that.nextId) &&
+                this.dstNextHops.equals(that.dstNextHops);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(nextId, dstNextHops);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("nextId", nextId)
+                .add("dstNextHops", dstNextHops)
+                .toString();
+    }
+}