ONOS-1930 : Tunnel and policy failover with multi-instances
- Prevents tunnel delete from removing groups used for default flows
- Removes SegmentRoutingManager reference from Tunnel and Policy class
- Adds some error checks such as duplicates tunnel IDs or duplicate polices
Change-Id: I0e7d5e2eff0aea6dad13137a872fee58e083b11c
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
index 4a498c6..1c07093 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
@@ -15,12 +15,18 @@
*/
package org.onosproject.segmentrouting;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.segmentrouting.grouphandler.NeighborSet;
+import org.onosproject.store.service.EventuallyConsistentMap;
import org.slf4j.Logger;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
-import java.util.HashMap;
+import java.util.Set;
+import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -29,10 +35,15 @@
public class TunnelHandler {
protected final Logger log = getLogger(getClass());
- private final HashMap<String, Tunnel> tunnelMap;
+ private final SegmentRoutingManager srManager;
+ private final DeviceConfiguration config;
+ private final EventuallyConsistentMap<String, Tunnel> tunnelStore;
- public TunnelHandler() {
- tunnelMap = new HashMap<>();
+ public TunnelHandler(SegmentRoutingManager srm,
+ EventuallyConsistentMap<String, Tunnel> tunnelStore) {
+ this.srManager = checkNotNull(srm);
+ this.config = srm.deviceConfiguration;
+ this.tunnelStore = tunnelStore;
}
/**
@@ -40,9 +51,33 @@
*
* @param tunnel tunnel reference to create a tunnel
*/
- public void createTunnel(Tunnel tunnel) {
- tunnel.create();
- tunnelMap.put(tunnel.id(), tunnel);
+ public boolean createTunnel(Tunnel tunnel) {
+
+ if (tunnel.labelIds().isEmpty() || tunnel.labelIds().size() < 3) {
+ log.error("More than one router needs to specified to created a tunnel");
+ return false;
+ }
+
+ if (tunnelStore.containsKey(tunnel.id())) {
+ log.warn("The same tunnel ID exists already");
+ return false;
+ }
+
+ if (tunnelStore.containsValue(tunnel)) {
+ log.warn("The same tunnel exists already");
+ return false;
+ }
+
+ int groupId = createGroupsForTunnel(tunnel);
+ if (groupId < 0) {
+ log.error("Failed to create groups for the tunnel");
+ return false;
+ }
+
+ tunnel.setGroupId(groupId);
+ tunnelStore.put(tunnel.id(), tunnel);
+
+ return true;
}
/**
@@ -52,10 +87,19 @@
*/
public void removeTunnel(Tunnel tunnelInfo) {
- Tunnel tunnel = tunnelMap.get(tunnelInfo.id());
+ Tunnel tunnel = tunnelStore.get(tunnelInfo.id());
if (tunnel != null) {
- tunnel.remove();
- tunnelMap.remove(tunnel.id());
+ DeviceId deviceId = config.getDeviceId(tunnel.labelIds().get(0));
+ if (tunnel.isAllowedToRemoveGroup()) {
+ if (srManager.removeNextObjective(deviceId, tunnel.groupId())) {
+ tunnelStore.remove(tunnel.id());
+ } else {
+ log.error("Failed to remove the tunnel {}", tunnelInfo.id());
+ }
+ } else {
+ log.debug("The group is not removed because it is being used.");
+ tunnelStore.remove(tunnel.id());
+ }
} else {
log.warn("No tunnel found for tunnel ID {}", tunnelInfo.id());
}
@@ -68,7 +112,7 @@
* @return Tunnel reference
*/
public Tunnel getTunnel(String tid) {
- return tunnelMap.get(tid);
+ return tunnelStore.get(tid);
}
/**
@@ -78,9 +122,50 @@
*/
public List<Tunnel> getTunnels() {
List<Tunnel> tunnels = new ArrayList<>();
- tunnelMap.values().forEach(tunnel -> tunnels.add(
+ tunnelStore.values().forEach(tunnel -> tunnels.add(
new DefaultTunnel((DefaultTunnel) tunnel)));
return tunnels;
}
+
+ private int createGroupsForTunnel(Tunnel tunnel) {
+
+ List<Integer> portNumbers;
+
+ int groupId;
+
+ DeviceId deviceId = config.getDeviceId(tunnel.labelIds().get(0));
+ if (deviceId == null) {
+ log.warn("No device found for SID {}", tunnel.labelIds().get(0));
+ return -1;
+ }
+ Set<DeviceId> deviceIds = new HashSet<>();
+ int sid = tunnel.labelIds().get(1);
+ if (config.isAdjacencySid(deviceId, sid)) {
+ portNumbers = config.getPortsForAdjacencySid(deviceId, sid);
+ for (Link link: srManager.linkService.getDeviceEgressLinks(deviceId)) {
+ for (Integer port: portNumbers) {
+ if (link.src().port().toLong() == port) {
+ deviceIds.add(link.dst().deviceId());
+ }
+ }
+ }
+ } else {
+ deviceIds.add(config.getDeviceId(sid));
+ }
+
+ NeighborSet ns = new NeighborSet(deviceIds, tunnel.labelIds().get(2));
+
+ // If the tunnel reuses any existing groups, then tunnel handler
+ // should not remove the group.
+ if (srManager.hasNextObjectiveId(deviceId, ns)) {
+ tunnel.allowToRemoveGroup(false);
+ } else {
+ tunnel.allowToRemoveGroup(true);
+ }
+ groupId = srManager.getNextObjectiveId(deviceId, ns);
+
+ return groupId;
+ }
+
}