First round of cleanups in optical path provisioner. No more user input for packet/optical mininet script.
Change-Id: Ibbfa6a17a97432da8dee63e9cd15fa6b1c2c1e46
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 c5ec560..6b95d63 100644
--- a/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
+++ b/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
@@ -18,6 +18,7 @@
import com.google.common.collect.Lists;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onosproject.cluster.ClusterService;
@@ -44,19 +45,23 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Collections;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
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;
+
/**
- * OpticalPathProvisioner listens event notifications from the Intent F/W.
+ * OpticalPathProvisioner listens for event notifications from the Intent F/W.
* It generates one or more opticalConnectivityIntent(s) and submits (or withdraws) to Intent F/W
* for adding/releasing capacity at the packet layer.
- *
*/
@Component(immediate = true)
@@ -86,12 +91,12 @@
private ApplicationId appId;
// TODO use a shared map for distributed operation
- protected final Map<ConnectPoint, OpticalConnectivityIntent> inStatusTportMap =
+ private final Map<ConnectPoint, OpticalConnectivityIntent> inStatusTportMap =
new ConcurrentHashMap<>();
- protected final Map<ConnectPoint, OpticalConnectivityIntent> outStatusTportMap =
+ private final Map<ConnectPoint, OpticalConnectivityIntent> outStatusTportMap =
new ConcurrentHashMap<>();
- protected final Map<ConnectPoint, Map<ConnectPoint, Intent>> intentMap =
+ private final Map<ConnectPoint, Map<ConnectPoint, Intent>> intentMap =
new ConcurrentHashMap<>();
private final InternalOpticalPathProvisioner pathProvisioner = new InternalOpticalPathProvisioner();
@@ -101,7 +106,13 @@
intentService.addListener(pathProvisioner);
appId = coreService.registerApplication("org.onosproject.optical");
initTport();
- log.info("Starting optical path provisioning...");
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ intentService.removeListener(pathProvisioner);
+ log.info("Stopped");
}
protected void initTport() {
@@ -119,10 +130,6 @@
}
}
- protected void deactivate() {
- intentService.removeListener(pathProvisioner);
- }
-
public class InternalOpticalPathProvisioner implements IntentListener {
@Override
public void event(IntentEvent event) {
@@ -132,11 +139,11 @@
case INSTALLED:
break;
case FAILED:
- log.info("packet intent {} failed, calling optical path provisioning APP.", event.subject());
+ log.info("Intent {} failed, calling optical path provisioning app.", event.subject());
setupLightpath(event.subject());
break;
case WITHDRAWN:
- log.info("intent {} withdrawn.", event.subject());
+ log.info("Intent {} withdrawn.", event.subject());
//FIXME
//teardownLightpath(event.subject());
break;
@@ -162,6 +169,7 @@
/**
* Registers an intent from src to dst.
+ *
* @param src source point
* @param dst destination point
* @param intent intent to be registered
@@ -242,78 +250,124 @@
}
}
+ /**
+ * Returns list of cross connection points of missing optical path sections.
+ *
+ * Scans the given multi-layer path and looks for sections that use cross connect links.
+ * The ingress and egress points in the optical layer are returned in a list.
+ *
+ * @param path the multi-layer path
+ * @return list of cross connection points on the optical layer
+ */
+ private List<ConnectPoint> getCrossConnectPoints(Path path) {
+ boolean scanning = false;
+ List<ConnectPoint> connectPoints = new LinkedList<ConnectPoint>();
+
+ for (Link link : path.links()) {
+ if (!isCrossConnectLink(link)) {
+ continue;
+ }
+
+ if (scanning) {
+ connectPoints.add(checkNotNull(link.src()));
+ scanning = false;
+ } else {
+ connectPoints.add(checkNotNull(link.dst()));
+ scanning = true;
+ }
+ }
+
+ return connectPoints;
+ }
+
+ /**
+ * Checks availability of cross connect points by verifying T port status.
+ * TODO: refactor after rewriting OpticalConnectivityIntentCompiler
+ *
+ * @param crossConnectPoints list of cross connection points
+ * @return true if all cross connect points are available, false otherwise
+ */
+ private boolean checkCrossConnectPoints(List<ConnectPoint> crossConnectPoints) {
+ checkArgument(crossConnectPoints.size() % 2 == 0);
+
+ Iterator<ConnectPoint> itr = crossConnectPoints.iterator();
+
+ while (itr.hasNext()) {
+ // checkArgument at start ensures we'll always have pairs of connect points
+ ConnectPoint src = itr.next();
+ ConnectPoint dst = itr.next();
+
+ if (inStatusTportMap.get(src) != null || outStatusTportMap.get(dst) != null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Scans the list of cross connection points and returns a list of optical connectivity intents
+ * in both directions.
+ *
+ * @param crossConnectPoints list of cross connection points
+ * @return list of optical connectivity intents
+ */
+ private List<Intent> getIntents(List<ConnectPoint> crossConnectPoints) {
+ checkArgument(crossConnectPoints.size() % 2 == 0);
+
+ List<Intent> intents = new LinkedList<Intent>();
+ Iterator<ConnectPoint> itr = crossConnectPoints.iterator();
+
+ while (itr.hasNext()) {
+ // checkArgument at start ensures we'll always have pairs of connect points
+ ConnectPoint src = itr.next();
+ ConnectPoint dst = itr.next();
+
+ // TODO: should have option for bidirectional OpticalConnectivityIntent
+ 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);
+ }
+
+ return intents;
+ }
+
private List<Intent> getOpticalPath(ConnectPoint ingress, ConnectPoint egress) {
Set<Path> paths = pathService.getPaths(ingress.deviceId(),
- egress.deviceId(),
- new OpticalLinkWeight());
+ egress.deviceId(),
+ new OpticalLinkWeight());
if (paths.isEmpty()) {
- return Lists.newArrayList();
+ return Collections.emptyList();
}
List<Intent> connectionList = Lists.newArrayList();
+ // Iterate over all paths until a suitable one has been found
Iterator<Path> itrPath = paths.iterator();
while (itrPath.hasNext()) {
- boolean usedTportFound = false;
Path nextPath = itrPath.next();
- log.info(nextPath.links().toString()); // TODO drop log level
- Iterator<Link> itrLink = nextPath.links().iterator();
- while (itrLink.hasNext()) {
- ConnectPoint srcWdmPoint, dstWdmPoint;
- Link link1 = itrLink.next();
- if (!isOpticalLink(link1)) {
- continue;
- } else {
- srcWdmPoint = link1.dst();
- dstWdmPoint = srcWdmPoint;
- }
+ List<ConnectPoint> crossConnectPoints = getCrossConnectPoints(nextPath);
- while (itrLink.hasNext()) {
- Link link2 = itrLink.next();
- if (isOpticalLink(link2)) {
- dstWdmPoint = link2.src();
- } else {
- break;
- }
- }
-
- if (inStatusTportMap.get(srcWdmPoint) != null ||
- outStatusTportMap.get(dstWdmPoint) != null) {
- usedTportFound = true;
- // log.info("used ConnectPoint {} to {} were found", srcWdmPoint, dstWdmPoint);
- break;
- }
-
- Intent opticalIntent = OpticalConnectivityIntent.builder()
- .appId(appId)
- .src(srcWdmPoint)
- .dst(dstWdmPoint)
- .build();
- Intent opticalIntent2 = OpticalConnectivityIntent.builder()
- .appId(appId)
- .src(dstWdmPoint)
- .dst(srcWdmPoint)
- .build();
- log.info("Creating optical intent from {} to {}", srcWdmPoint, dstWdmPoint);
- log.info("Creating optical intent from {} to {}", dstWdmPoint, srcWdmPoint);
- connectionList.add(opticalIntent);
- connectionList.add(opticalIntent2);
-
- break;
+ // Skip to next path if not all connect points are available
+ if (!checkCrossConnectPoints(crossConnectPoints)) {
+ continue;
}
- if (!usedTportFound) {
- break;
- } else {
- // reset the connection list
- connectionList = Lists.newArrayList();
- }
-
+ return getIntents(crossConnectPoints);
}
- return connectionList;
+ return Collections.emptyList();
}
private void teardownLightpath(Intent intent) {
@@ -330,26 +384,45 @@
}
- private static boolean isOpticalLink(Link link) {
- boolean isOptical = false;
- Link.Type lt = link.type();
- if (lt == Link.Type.OPTICAL) {
- isOptical = true;
+ /**
+ * Verifies if given link is cross-connect between packet and optical layer.
+ *
+ * @param link the link
+ * @return true if the link is a cross-connect link
+ */
+ public static boolean isCrossConnectLink(Link link) {
+ if (link.type() != Link.Type.OPTICAL) {
+ return false;
}
- return isOptical;
+
+ checkNotNull(link.annotations());
+ checkNotNull(link.annotations().value("optical.type"));
+
+ if (link.annotations().value("optical.type").equals("cross-connect")) {
+ return true;
+ }
+
+ 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; // ignore inactive links
+ return -1;
}
- if (isOpticalLink(edge.link())) {
- return 1000; // optical links
- } else {
- return 1; // packet links
+
+ // Transport links have highest weight
+ if (edge.link().type() == Link.Type.OPTICAL) {
+ return 1000;
}
+
+ // Packet links
+ return 1;
}
}