Rewrote optical connectivity intent compiler
Change-Id: I5acece3c14bed8a23f7bbe0c5a9bc0932a2a0881
diff --git a/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java b/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
index 6b95d63..b8d64c4 100644
--- a/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
+++ b/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
@@ -21,15 +21,20 @@
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.util.KryoNamespace;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.NodeId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
import org.onosproject.net.Host;
import org.onosproject.net.Link;
+import org.onosproject.net.OduCltPort;
import org.onosproject.net.Path;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceService;
import org.onosproject.net.host.HostService;
import org.onosproject.net.intent.HostToHostIntent;
import org.onosproject.net.intent.Intent;
@@ -39,9 +44,15 @@
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.OpticalConnectivityIntent;
import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.resource.DeviceResourceService;
+import org.onosproject.net.resource.LinkResourceService;
import org.onosproject.net.topology.LinkWeight;
import org.onosproject.net.topology.PathService;
import org.onosproject.net.topology.TopologyEdge;
+import org.onosproject.net.topology.TopologyService;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -54,7 +65,6 @@
import java.util.concurrent.ConcurrentHashMap;
import static com.google.common.base.Preconditions.checkArgument;
-import static org.onosproject.net.intent.IntentState.INSTALLED;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -70,6 +80,9 @@
protected static final Logger log = LoggerFactory
.getLogger(OpticalPathProvisioner.class);
+ private static final Serializer SERIALIZER = Serializer.using(
+ new KryoNamespace.Builder().register(KryoNamespaces.API).build());
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private IntentService intentService;
@@ -77,6 +90,9 @@
protected PathService pathService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected TopologyService topologyService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -88,13 +104,19 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterService clusterService;
- private ApplicationId appId;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
- // TODO use a shared map for distributed operation
- private final Map<ConnectPoint, OpticalConnectivityIntent> inStatusTportMap =
- new ConcurrentHashMap<>();
- private final Map<ConnectPoint, OpticalConnectivityIntent> outStatusTportMap =
- new ConcurrentHashMap<>();
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceResourceService deviceResourceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected LinkResourceService linkResourceService;
+
+ private ApplicationId appId;
private final Map<ConnectPoint, Map<ConnectPoint, Intent>> intentMap =
new ConcurrentHashMap<>();
@@ -105,7 +127,7 @@
protected void activate() {
intentService.addListener(pathProvisioner);
appId = coreService.registerApplication("org.onosproject.optical");
- initTport();
+ initOpticalPorts();
log.info("Started");
}
@@ -115,19 +137,12 @@
log.info("Stopped");
}
- protected void initTport() {
- inStatusTportMap.clear();
- outStatusTportMap.clear();
- for (Intent intent : intentService.getIntents()) {
- if (intentService.getIntentState(intent.key()) == INSTALLED) {
- if (intent instanceof OpticalConnectivityIntent) {
- inStatusTportMap.put(((OpticalConnectivityIntent) intent).getSrc(),
- (OpticalConnectivityIntent) intent);
- outStatusTportMap.put(((OpticalConnectivityIntent) intent).getDst(),
- (OpticalConnectivityIntent) intent);
- }
- }
- }
+ /**
+ * Initialize availability of optical ports.
+ */
+ private void initOpticalPorts() {
+ // TODO: check for existing optical intents
+ return;
}
public class InternalOpticalPathProvisioner implements IntentListener {
@@ -137,6 +152,7 @@
case INSTALL_REQ:
break;
case INSTALLED:
+ // track h2h & p2p intents using our connectivity
break;
case FAILED:
log.info("Intent {} failed, calling optical path provisioning app.", event.subject());
@@ -144,29 +160,13 @@
break;
case WITHDRAWN:
log.info("Intent {} withdrawn.", event.subject());
- //FIXME
- //teardownLightpath(event.subject());
+ withdrawIntent(event.subject());
break;
default:
break;
}
}
- private void reserveTport(Intent intent) {
- // TODO move to resourceManager
- if (intent instanceof OpticalConnectivityIntent) {
- OpticalConnectivityIntent opticalIntent =
- (OpticalConnectivityIntent) intent;
- if (inStatusTportMap.containsKey(opticalIntent.getSrc()) ||
- outStatusTportMap.containsKey(opticalIntent.getDst())) {
- //TODO throw an exception, perhaps
- log.warn("Overlapping reservation: {}", opticalIntent);
- }
- inStatusTportMap.put(opticalIntent.getSrc(), opticalIntent);
- outStatusTportMap.put(opticalIntent.getDst(), opticalIntent);
- }
- }
-
/**
* Registers an intent from src to dst.
*
@@ -190,6 +190,8 @@
}
private void setupLightpath(Intent intent) {
+ checkNotNull(intent);
+
// TODO change the coordination approach between packet intents and optical intents
// Low speed LLDP may cause multiple calls which are not expected
@@ -197,56 +199,48 @@
return;
}
- NodeId localNode = clusterService.getLocalNode().id();
-
- List<Intent> intents = Lists.newArrayList();
+ // Get source and destination based on intent type
+ ConnectPoint src;
+ ConnectPoint dst;
if (intent instanceof HostToHostIntent) {
HostToHostIntent hostToHostIntent = (HostToHostIntent) intent;
Host one = hostService.getHost(hostToHostIntent.one());
Host two = hostService.getHost(hostToHostIntent.two());
- if (one == null || two == null) {
- return; //FIXME
- }
- // Ignore if we're not the master for the intent's origin device
- NodeId sourceMaster = mastershipService.getMasterFor(one.location().deviceId());
- if (!localNode.equals(sourceMaster)) {
- return;
- }
+ checkNotNull(one);
+ checkNotNull(two);
- // provision both directions
- intents.addAll(getOpticalPath(one.location(), two.location()));
- // note: bi-directional intent is set up
- // HostToHost Intent requires symmetric path!
- //intents.addAll(getOpticalPath(two.location(), one.location()));
+ src = one.location();
+ dst = two.location();
} else if (intent instanceof PointToPointIntent) {
PointToPointIntent p2pIntent = (PointToPointIntent) intent;
- // Ignore if we're not the master for the intent's origin device
- NodeId sourceMaster = mastershipService.getMasterFor(p2pIntent.ingressPoint().deviceId());
- if (!localNode.equals(sourceMaster)) {
- return;
- }
-
- intents.addAll(getOpticalPath(p2pIntent.ingressPoint(), p2pIntent.egressPoint()));
+ src = p2pIntent.ingressPoint();
+ dst = p2pIntent.egressPoint();
} else {
- log.info("Unsupported intent type: {}", intent.getClass());
+ log.error("Unsupported intent type: {}", intent.getClass());
+ return;
}
- // Create the intents
+ if (src == null || dst == null) {
+ return;
+ }
+
+ // Ignore if we're not the master for the intent's origin device
+ NodeId localNode = clusterService.getLocalNode().id();
+ NodeId sourceMaster = mastershipService.getMasterFor(src.deviceId());
+ if (!localNode.equals(sourceMaster)) {
+ return;
+ }
+
+ // Generate optical connectivity intents
+ List<Intent> intents = Lists.newArrayList();
+ intents.addAll(getOpticalIntents(src, dst));
+
+ // Submit the intents
for (Intent i : intents) {
- // TODO: don't allow duplicate intents between the same points for now
- // we may want to allow this carefully in future to increase capacity
- if (i instanceof OpticalConnectivityIntent) {
- OpticalConnectivityIntent oi = (OpticalConnectivityIntent) i;
- if (addIntent(oi.getSrc(), oi.getDst(), oi)) {
- intentService.submit(i);
- reserveTport(i);
- }
- } else {
- log.warn("Invalid intent type: {} for {}", i.getClass(), i);
- }
+ intentService.submit(i);
}
}
@@ -281,11 +275,10 @@
}
/**
- * Checks availability of cross connect points by verifying T port status.
- * TODO: refactor after rewriting OpticalConnectivityIntentCompiler
+ * Checks if cross connect points are of same type.
*
* @param crossConnectPoints list of cross connection points
- * @return true if all cross connect points are available, false otherwise
+ * @return true if cross connect point pairs are of same type, false otherwise
*/
private boolean checkCrossConnectPoints(List<ConnectPoint> crossConnectPoints) {
checkArgument(crossConnectPoints.size() % 2 == 0);
@@ -297,7 +290,12 @@
ConnectPoint src = itr.next();
ConnectPoint dst = itr.next();
- if (inStatusTportMap.get(src) != null || outStatusTportMap.get(dst) != null) {
+ Device.Type srcType = deviceService.getDevice(src.deviceId()).type();
+ Device.Type dstType = deviceService.getDevice(dst.deviceId()).type();
+
+ // Only support connections between identical port types
+ if (srcType != dstType) {
+ log.warn("Unsupported mix of cross connect points");
return false;
}
}
@@ -306,8 +304,7 @@
}
/**
- * Scans the list of cross connection points and returns a list of optical connectivity intents
- * in both directions.
+ * Scans the list of cross connection points and returns a list of optical connectivity intents.
*
* @param crossConnectPoints list of cross connection points
* @return list of optical connectivity intents
@@ -323,25 +320,34 @@
ConnectPoint src = itr.next();
ConnectPoint dst = itr.next();
- // TODO: should have option for bidirectional OpticalConnectivityIntent
+ Port srcPort = deviceService.getPort(src.deviceId(), src.port());
+ Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
+ // Create lightpath
+ // TODO: Ensure src & dst are of type OchPort
Intent opticalIntent = OpticalConnectivityIntent.builder()
.appId(appId)
.src(src)
.dst(dst)
.build();
- Intent opticalIntentRev = OpticalConnectivityIntent.builder()
- .appId(appId)
- .src(dst)
- .dst(src)
- .build();
intents.add(opticalIntent);
- intents.add(opticalIntentRev);
+ if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
+ continue;
+ // also create OTN service
+ }
}
return intents;
}
- private List<Intent> getOpticalPath(ConnectPoint ingress, ConnectPoint egress) {
+ /**
+ * Returns list of optical connectivity intents needed to create connectivity
+ * between ingress and egress.
+ *
+ * @param ingress the ingress connect point
+ * @param egress the egress connect point
+ * @return list of optical connectivity intents, empty list if no path was found
+ */
+ private List<Intent> getOpticalIntents(ConnectPoint ingress, ConnectPoint egress) {
Set<Path> paths = pathService.getPaths(ingress.deviceId(),
egress.deviceId(),
new OpticalLinkWeight());
@@ -350,16 +356,11 @@
return Collections.emptyList();
}
- List<Intent> connectionList = Lists.newArrayList();
+ // Search path with available cross connect points
+ for (Path path : paths) {
+ List<ConnectPoint> crossConnectPoints = getCrossConnectPoints(path);
- // Iterate over all paths until a suitable one has been found
- Iterator<Path> itrPath = paths.iterator();
- while (itrPath.hasNext()) {
- Path nextPath = itrPath.next();
-
- List<ConnectPoint> crossConnectPoints = getCrossConnectPoints(nextPath);
-
- // Skip to next path if not all connect points are available
+ // Skip to next path if cross connect points are mismatched
if (!checkCrossConnectPoints(crossConnectPoints)) {
continue;
}
@@ -370,18 +371,41 @@
return Collections.emptyList();
}
- private void teardownLightpath(Intent intent) {
- /* FIXME this command doesn't make much sense. we need to define the semantics
- // TODO move to resourceManager
- if (intent instanceof OpticalConnectivityIntent) {
- inStatusTportMap.remove(((OpticalConnectivityIntent) intent).getSrc());
- outStatusTportMap.remove(((OpticalConnectivityIntent) intent).getDst());
- // TODO tear down the idle lightpath if the utilization is zero.
+ /**
+ * Link weight function that emphasizes re-use of packet links.
+ */
+ private class OpticalLinkWeight implements LinkWeight {
+ @Override
+ public double weight(TopologyEdge edge) {
+ // Ignore inactive links
+ if (edge.link().state() == Link.State.INACTIVE) {
+ return -1;
+ }
+ // TODO: Ignore cross connect links with used ports
+
+ // Transport links have highest weight
+ if (edge.link().type() == Link.Type.OPTICAL) {
+ return 1000;
+ }
+
+ // Packet links
+ return 1;
}
- */ //end-FIXME
}
+ /**
+ * Handle withdrawn intent on each network layer.
+ *
+ * @param intent the withdrawn intent
+ */
+ private void withdrawIntent(Intent intent) {
+ if (intent instanceof OpticalConnectivityIntent) {
+ deviceResourceService.releasePorts(intent.id());
+ linkResourceService.releaseResources(linkResourceService.getAllocations(intent.id()));
+ }
+ // TODO: add other layers
+ }
}
/**
@@ -405,25 +429,4 @@
return false;
}
- /**
- * Link weight function that emphasizes re-use of packet links.
- */
- private static class OpticalLinkWeight implements LinkWeight {
- @Override
- public double weight(TopologyEdge edge) {
- // Ignore inactive links
- if (edge.link().state() == Link.State.INACTIVE) {
- return -1;
- }
-
- // Transport links have highest weight
- if (edge.link().type() == Link.Type.OPTICAL) {
- return 1000;
- }
-
- // Packet links
- return 1;
- }
- }
-
}