Rewrote optical connectivity intent compiler
Change-Id: I5acece3c14bed8a23f7bbe0c5a9bc0932a2a0881
diff --git a/apps/optical/pom.xml b/apps/optical/pom.xml
index f8e7e9f..d1883e4 100644
--- a/apps/optical/pom.xml
+++ b/apps/optical/pom.xml
@@ -45,7 +45,6 @@
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.console</artifactId>
</dependency>
-
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
@@ -59,6 +58,12 @@
<artifactId>jackson-annotations</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-core-serializers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
</dependencies>
</project>
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;
- }
- }
-
}
diff --git a/core/api/src/main/java/org/onosproject/net/Device.java b/core/api/src/main/java/org/onosproject/net/Device.java
index ddfa6af..e36d762 100644
--- a/core/api/src/main/java/org/onosproject/net/Device.java
+++ b/core/api/src/main/java/org/onosproject/net/Device.java
@@ -26,7 +26,7 @@
* Coarse classification of the type of the infrastructure device.
*/
public enum Type {
- SWITCH, ROUTER, ROADM, OTN, FIREWALL, BALANCER, IPS, IDS, CONTROLLER, OTHER
+ SWITCH, ROUTER, ROADM, OTN, ROADM_OTN, FIREWALL, BALANCER, IPS, IDS, CONTROLLER, OTHER
}
/**
diff --git a/core/api/src/main/java/org/onosproject/net/OchPort.java b/core/api/src/main/java/org/onosproject/net/OchPort.java
index 8a7836b..eb956f2 100644
--- a/core/api/src/main/java/org/onosproject/net/OchPort.java
+++ b/core/api/src/main/java/org/onosproject/net/OchPort.java
@@ -15,8 +15,6 @@
*/
package org.onosproject.net;
-import org.onlab.util.Frequency;
-
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
@@ -29,9 +27,6 @@
*/
public class OchPort extends DefaultPort {
- public static final Frequency CENTER_FREQUENCY = Frequency.ofTHz(193.1);
- public static final Frequency FLEX_GRID_SLOT = Frequency.ofGHz(12.5);
-
private final OduSignalType signalType;
private final boolean isTunable;
private final OchSignal lambda;
@@ -43,7 +38,7 @@
* @param number port number
* @param isEnabled port enabled state
* @param signalType ODU signal type
- * @param isTunable maximum frequency in MHz
+ * @param isTunable tunable wavelength capability
* @param lambda OCh signal
* @param annotations optional key/value annotations
*/
diff --git a/core/api/src/main/java/org/onosproject/net/OchSignal.java b/core/api/src/main/java/org/onosproject/net/OchSignal.java
index e629b5e..356950c 100644
--- a/core/api/src/main/java/org/onosproject/net/OchSignal.java
+++ b/core/api/src/main/java/org/onosproject/net/OchSignal.java
@@ -30,11 +30,10 @@
* See ITU G.709 "Interfaces for the Optical Transport Network (OTN)".
* </p>
*/
-// TODO: consider which is better, OchSignal or OpticalChannelSignal
public class OchSignal implements Lambda {
- private static final Frequency CENTER_FREQUENCY = Frequency.ofTHz(193.1);
- private static final Frequency FLEX_GRID_SLOT = Frequency.ofGHz(12.5);
+ public static final Frequency CENTER_FREQUENCY = Frequency.ofTHz(193.1);
+ public static final Frequency FLEX_GRID_SLOT = Frequency.ofGHz(12.5);
private final GridType gridType;
private final ChannelSpacing channelSpacing;
@@ -57,10 +56,9 @@
int spacingMultiplier, int slotGranularity) {
this.gridType = checkNotNull(gridType);
this.channelSpacing = checkNotNull(channelSpacing);
- // TODO: check the precondition for spacingMultiplier. Is negative value permitted?
+ // Negative values are permitted for spacingMultiplier
this.spacingMultiplier = spacingMultiplier;
-
- checkArgument(slotGranularity > 0, "slotGranularity must be more than 0, but %s", slotGranularity);
+ checkArgument(slotGranularity > 0, "slotGranularity must be larger than 0, received %s", slotGranularity);
this.slotGranularity = slotGranularity;
}
diff --git a/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java b/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java
index 7f3d7f0..c3a7f41 100644
--- a/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java
@@ -40,7 +40,7 @@
* @param isEnabled port enabled state
* @param signalType ODU signal type
* @param isTunable tunable wavelength capability
- * @param lambda Och signal
+ * @param lambda OCh signal
* @param annotations optional key/value annotations map
*/
public OchPortDescription(PortNumber number, boolean isEnabled, OduSignalType signalType,
diff --git a/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java b/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java
index 6b48b00..c2b84ab 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java
@@ -24,8 +24,8 @@
import static com.google.common.base.Preconditions.checkNotNull;
/**
- * An optical layer intent for connectivity from one transponder port to another
- * transponder port. No traffic selector or traffic treatment are needed.
+ * An optical layer intent for connectivity between two OCh ports.
+ * No traffic selector or traffic treatment are needed.
*/
public final class OpticalConnectivityIntent extends Intent {
private final ConnectPoint src;
diff --git a/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java b/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java
index 0013c0d..5e1eacc 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java
@@ -15,11 +15,9 @@
*/
package org.onosproject.net.intent;
-import java.util.Collection;
-
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Link;
+import org.onosproject.net.OchSignal;
import org.onosproject.net.Path;
import com.google.common.base.MoreObjects;
@@ -32,27 +30,27 @@
private final ConnectPoint src;
private final ConnectPoint dst;
private final Path path;
-
+ private final OchSignal lambda;
private OpticalPathIntent(ApplicationId appId,
Key key,
ConnectPoint src,
ConnectPoint dst,
Path path,
+ OchSignal lambda,
int priority) {
- super(appId,
- key,
- ImmutableSet.copyOf(path.links()),
- priority);
+ super(appId, key, ImmutableSet.copyOf(path.links()), priority);
this.src = checkNotNull(src);
this.dst = checkNotNull(dst);
this.path = checkNotNull(path);
+ this.lambda = checkNotNull(lambda);
}
protected OpticalPathIntent() {
this.src = null;
this.dst = null;
this.path = null;
+ this.lambda = null;
}
/**
@@ -72,6 +70,7 @@
private ConnectPoint src;
private ConnectPoint dst;
private Path path;
+ private OchSignal lambda;
Key key;
@Override
@@ -123,6 +122,17 @@
}
/**
+ * Sets the optical channel (lambda) for the intent that will be built.
+ *
+ * @param lambda the optical channel
+ * @return this builder
+ */
+ public Builder lambda(OchSignal lambda) {
+ this.lambda = lambda;
+ return this;
+ }
+
+ /**
* Builds an optical path intent from the accumulated parameters.
*
* @return optical path intent
@@ -135,6 +145,7 @@
src,
dst,
path,
+ lambda,
priority
);
}
@@ -153,6 +164,10 @@
return path;
}
+ public OchSignal lambda() {
+ return lambda;
+ }
+
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
@@ -163,11 +178,7 @@
.add("ingressPort", src)
.add("egressPort", dst)
.add("path", path)
+ .add("lambda", lambda)
.toString();
}
-
-
- public Collection<Link> requiredLinks() {
- return path.links();
- }
}
diff --git a/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceService.java b/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceService.java
new file mode 100644
index 0000000..10e5911
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceService.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.net.resource;
+
+import org.onosproject.net.Port;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentId;
+
+import java.util.Set;
+
+/**
+ * Service for providing device resources.
+ */
+public interface DeviceResourceService {
+ /**
+ * Request a set of ports needed to satisfy the intent.
+ *
+ * @param intent the intent
+ * @return set of ports
+ */
+ Set<Port> requestPorts(Intent intent);
+
+ /**
+ * Release ports associated with given intent ID.
+ *
+ * @param intentId intent ID
+ */
+ void releasePorts(IntentId intentId);
+}
diff --git a/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceStore.java b/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceStore.java
new file mode 100644
index 0000000..5df661c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceStore.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.net.resource;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.intent.IntentId;
+
+import java.util.Set;
+
+public interface DeviceResourceStore {
+ Set<Port> getFreePorts(DeviceId deviceId);
+
+ void allocatePorts(Set<Port> port, IntentId intent);
+
+ void releasePorts(IntentId intent);
+}
diff --git a/core/api/src/test/java/org/onosproject/net/NetTestTools.java b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
index b0601dd..eccb743 100644
--- a/core/api/src/test/java/org/onosproject/net/NetTestTools.java
+++ b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
@@ -89,6 +89,10 @@
return new DefaultPath(PID, links, ids.length);
}
+ // Creates OCh signal
+ public static OchSignal createLambda() {
+ return new OchSignal(GridType.DWDM, ChannelSpacing.CHL_6P25GHZ, 8, 4);
+ }
/**
* Verifies that Annotations created by merging {@code annotations} is
diff --git a/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java b/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java
index f05e93c..3296336 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java
@@ -18,6 +18,7 @@
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
+import org.onosproject.net.OchSignal;
import org.onosproject.net.Path;
import com.google.common.testing.EqualsTester;
@@ -28,6 +29,7 @@
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
import static org.onosproject.net.NetTestTools.APP_ID;
import static org.onosproject.net.NetTestTools.connectPoint;
+import static org.onosproject.net.NetTestTools.createLambda;
import static org.onosproject.net.NetTestTools.createPath;
public class OpticalPathIntentTest extends AbstractIntentTest {
@@ -37,6 +39,7 @@
OpticalPathIntent intent1;
OpticalPathIntent intent2;
Path defaultPath;
+ OchSignal lambda;
@Before
public void opticalPathIntentTestSetUp() {
@@ -46,6 +49,7 @@
.src(connectPoint("one", 1))
.dst(connectPoint("two", 2))
.path(defaultPath)
+ .lambda(createLambda())
.priority(PRIORITY)
.build();
@@ -54,6 +58,7 @@
.src(connectPoint("two", 1))
.dst(connectPoint("one", 2))
.path(defaultPath)
+ .lambda(createLambda())
.priority(PRIORITY)
.build();
}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
index 372d65b..91c9df3 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.net.intent.impl.compiler;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -23,16 +24,31 @@
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.Frequency;
+import org.onosproject.net.ChannelSpacing;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.GridType;
import org.onosproject.net.Link;
+import org.onosproject.net.OchPort;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OmsPort;
import org.onosproject.net.Path;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceService;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.OpticalConnectivityIntent;
import org.onosproject.net.intent.OpticalPathIntent;
-import org.onosproject.net.intent.impl.PathNotFoundException;
+import org.onosproject.net.resource.DefaultLinkResourceRequest;
+import org.onosproject.net.resource.DeviceResourceService;
+import org.onosproject.net.resource.LambdaResource;
+import org.onosproject.net.resource.LambdaResourceAllocation;
import org.onosproject.net.resource.LinkResourceAllocations;
+import org.onosproject.net.resource.LinkResourceRequest;
+import org.onosproject.net.resource.LinkResourceService;
+import org.onosproject.net.resource.ResourceAllocation;
+import org.onosproject.net.resource.ResourceType;
import org.onosproject.net.topology.LinkWeight;
import org.onosproject.net.topology.Topology;
import org.onosproject.net.topology.TopologyEdge;
@@ -40,18 +56,32 @@
import com.google.common.collect.ImmutableList;
+import static com.google.common.base.Preconditions.checkArgument;
+
/**
* An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}.
*/
@Component(immediate = true)
public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> {
+ private static final GridType DEFAULT_OCH_GRIDTYPE = GridType.DWDM;
+ private static final ChannelSpacing DEFAULT_CHANNEL_SPACING = ChannelSpacing.CHL_50GHZ;
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentManager;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected LinkResourceService linkResourceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceResourceService deviceResourceService;
+
@Activate
public void activate() {
intentManager.registerCompiler(OpticalConnectivityIntent.class, this);
@@ -66,19 +96,152 @@
public List<Intent> compile(OpticalConnectivityIntent intent,
List<Intent> installable,
Set<LinkResourceAllocations> resources) {
- // TODO: compute multiple paths using the K-shortest path algorithm
- Path path = calculateOpticalPath(intent.getSrc(), intent.getDst());
- Intent newIntent = OpticalPathIntent.builder()
- .appId(intent.appId())
- .src(intent.getSrc())
- .dst(intent.getDst())
- .path(path)
- .build();
- return ImmutableList.of(newIntent);
+ // Check if source and destination are optical OCh ports
+ ConnectPoint src = intent.getSrc();
+ ConnectPoint dst = intent.getDst();
+ Port srcPort = deviceService.getPort(src.deviceId(), src.port());
+ Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
+ checkArgument(srcPort instanceof OchPort);
+ checkArgument(dstPort instanceof OchPort);
+
+ // Calculate available light paths
+ Set<Path> paths = getOpticalPaths(intent);
+
+ // Use first path that can be successfully reserved
+ for (Path path : paths) {
+ // Request and reserve lambda on path
+ LinkResourceAllocations linkAllocs = assignWavelength(intent, path);
+ if (linkAllocs == null) {
+ continue;
+ }
+
+ OmsPort omsPort = (OmsPort) deviceService.getPort(path.src().deviceId(), path.src().port());
+
+ // Try to reserve port resources, roll back if unsuccessful
+ Set<Port> portAllocs = deviceResourceService.requestPorts(intent);
+ if (portAllocs == null) {
+ linkResourceService.releaseResources(linkAllocs);
+ continue;
+ }
+
+ // Create installable optical path intent
+ LambdaResourceAllocation lambdaAlloc = getWavelength(path, linkAllocs);
+ OchSignal ochSignal = getOchSignal(lambdaAlloc, omsPort.minFrequency(), omsPort.grid());
+
+ Intent newIntent = OpticalPathIntent.builder()
+ .appId(intent.appId())
+ .src(intent.getSrc())
+ .dst(intent.getDst())
+ .path(path)
+ .lambda(ochSignal)
+ .build();
+
+ return ImmutableList.of(newIntent);
+ }
+
+ return Collections.emptyList();
}
- private Path calculateOpticalPath(ConnectPoint start, ConnectPoint end) {
- // TODO: support user policies
+ /**
+ * Find the lambda allocated to the path.
+ *
+ * @param path the path
+ * @param linkAllocs the link allocations
+ * @return
+ */
+ private LambdaResourceAllocation getWavelength(Path path, LinkResourceAllocations linkAllocs) {
+ for (Link link : path.links()) {
+ for (ResourceAllocation alloc : linkAllocs.getResourceAllocation(link)) {
+ if (alloc.type() == ResourceType.LAMBDA) {
+ return (LambdaResourceAllocation) alloc;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Request and reserve first available wavelength across path.
+ *
+ * @param path path in WDM topology
+ * @return first available lambda resource allocation
+ */
+ private LinkResourceAllocations assignWavelength(Intent intent, Path path) {
+ LinkResourceRequest.Builder request =
+ DefaultLinkResourceRequest.builder(intent.id(), path.links())
+ .addLambdaRequest();
+
+ LinkResourceAllocations allocations = linkResourceService.requestResources(request.build());
+
+ checkWavelengthContinuity(allocations, path);
+
+ return allocations;
+ }
+
+ /**
+ * Checks wavelength continuity constraint across path, i.e., an identical lambda is used on all links.
+ * @return true if wavelength continuity is met, false otherwise
+ */
+ private boolean checkWavelengthContinuity(LinkResourceAllocations allocations, Path path) {
+ if (allocations == null) {
+ return false;
+ }
+
+ LambdaResource lambda = null;
+
+ for (Link link : path.links()) {
+ for (ResourceAllocation alloc : allocations.getResourceAllocation(link)) {
+ if (alloc.type() == ResourceType.LAMBDA) {
+ LambdaResource nextLambda = ((LambdaResourceAllocation) alloc).lambda();
+ if (nextLambda == null) {
+ return false;
+ }
+ if (lambda == null) {
+ lambda = nextLambda;
+ continue;
+ }
+ if (!lambda.equals(nextLambda)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Convert lambda resource allocation in OCh signal.
+ *
+ * @param alloc lambda resource allocation
+ * @param minFrequency minimum frequency
+ * @param grid grid spacing frequency
+ * @return OCh signal
+ */
+ private OchSignal getOchSignal(LambdaResourceAllocation alloc, Frequency minFrequency, Frequency grid) {
+ int channel = alloc.lambda().toInt();
+
+ // Calculate center frequency
+ Frequency centerFrequency = minFrequency.add(grid.multiply(channel)).add(grid.floorDivision(2));
+
+ // Build OCh signal object
+ int spacingMultiplier = (int) (centerFrequency.subtract(OchSignal.CENTER_FREQUENCY).asHz() / grid.asHz());
+ int slotGranularity = (int) (grid.asHz() / ChannelSpacing.CHL_12P5GHZ.frequency().asHz());
+ OchSignal ochSignal = new OchSignal(DEFAULT_OCH_GRIDTYPE, DEFAULT_CHANNEL_SPACING,
+ spacingMultiplier, slotGranularity);
+
+ return ochSignal;
+ }
+
+ /**
+ * Calculates optical paths in WDM topology.
+ *
+ * @param intent optical connectivity intent
+ * @return set of paths in WDM topology
+ */
+ private Set<Path> getOpticalPaths(OpticalConnectivityIntent intent) {
+ // Route in WDM topology
Topology topology = topologyService.currentTopology();
LinkWeight weight = new LinkWeight() {
@Override
@@ -86,18 +249,18 @@
if (edge.link().state() == Link.State.INACTIVE) {
return -1;
}
- return edge.link().type() == Link.Type.OPTICAL ? +1 : -1;
+ if (edge.link().type() != Link.Type.OPTICAL) {
+ return -1;
+ }
+ return edge.link().annotations().value("optical.type").equals("WDM") ? +1 : -1;
}
};
+ ConnectPoint start = intent.getSrc();
+ ConnectPoint end = intent.getDst();
Set<Path> paths = topologyService.getPaths(topology, start.deviceId(),
- end.deviceId(), weight);
- if (paths.isEmpty()) {
- throw new PathNotFoundException(start.elementId(), end.elementId());
- }
+ end.deviceId(), weight);
- // TODO: let's be more intelligent about this eventually
- return paths.iterator().next();
+ return paths;
}
-
}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
index 2cf4ccb..84368d9 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
@@ -30,29 +30,21 @@
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.intent.FlowRuleIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.OpticalPathIntent;
-import org.onosproject.net.intent.impl.IntentCompilationException;
-import org.onosproject.net.resource.DefaultLinkResourceRequest;
-import org.onosproject.net.resource.LambdaResource;
-import org.onosproject.net.resource.LambdaResourceAllocation;
import org.onosproject.net.resource.LinkResourceAllocations;
-import org.onosproject.net.resource.LinkResourceRequest;
import org.onosproject.net.resource.LinkResourceService;
-import org.onosproject.net.resource.ResourceAllocation;
-import org.onosproject.net.resource.ResourceType;
-import org.onosproject.net.topology.TopologyService;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
-import static org.onosproject.net.flow.DefaultTrafficTreatment.builder;
-
@Component(immediate = true)
public class OpticalPathIntentCompiler implements IntentCompiler<OpticalPathIntent> {
@@ -63,15 +55,10 @@
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected TopologyService topologyService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceService;
private ApplicationId appId;
- static final short SIGNAL_TYPE = (short) 1;
-
@Activate
public void activate() {
appId = coreService.registerApplication("org.onosproject.net.intent");
@@ -86,64 +73,50 @@
@Override
public List<Intent> compile(OpticalPathIntent intent, List<Intent> installable,
Set<LinkResourceAllocations> resources) {
- LinkResourceAllocations allocations = assignWavelength(intent);
-
return Collections.singletonList(
- new FlowRuleIntent(appId, createRules(intent, allocations), intent.resources()));
+ new FlowRuleIntent(appId, createRules(intent), intent.resources()));
}
- private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
- LinkResourceRequest.Builder request = DefaultLinkResourceRequest
- .builder(intent.id(), intent.path().links())
- .addLambdaRequest();
- return resourceService.requestResources(request.build());
- }
-
- private List<FlowRule> createRules(OpticalPathIntent intent, LinkResourceAllocations allocations) {
+ private List<FlowRule> createRules(OpticalPathIntent intent) {
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
selectorBuilder.matchInPort(intent.src().port());
List<FlowRule> rules = new LinkedList<>();
- ConnectPoint prev = intent.src();
+ ConnectPoint current = intent.src();
for (Link link : intent.path().links()) {
- ResourceAllocation allocation = allocations.getResourceAllocation(link).stream()
- .filter(x -> x.type() == ResourceType.LAMBDA)
- .findFirst()
- .orElseThrow(() -> new IntentCompilationException("Lambda was not assigned successfully"));
- LambdaResource la = ((LambdaResourceAllocation) allocation).lambda();
-
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
- treatmentBuilder.setLambda((short) la.toInt());
+ treatmentBuilder.add(Instructions.modL0Lambda(intent.lambda()));
treatmentBuilder.setOutput(link.src().port());
- FlowRule rule = new DefaultFlowRule(prev.deviceId(),
- selectorBuilder.build(),
- treatmentBuilder.build(),
- 100,
- appId,
- 100,
- true);
+ FlowRule rule = DefaultFlowRule.builder()
+ .forDevice(current.deviceId())
+ .withSelector(selectorBuilder.build())
+ .withTreatment(treatmentBuilder.build())
+ .withPriority(100)
+ .fromApp(appId)
+ .makePermanent()
+ .build();
rules.add(rule);
- prev = link.dst();
+ current = link.dst();
selectorBuilder.matchInPort(link.dst().port());
- selectorBuilder.matchOpticalSignalType(SIGNAL_TYPE);
- selectorBuilder.matchLambda((short) la.toInt());
-
+ selectorBuilder.add(Criteria.matchLambda(intent.lambda()));
}
- // build the last T port rule
- TrafficTreatment.Builder treatmentLast = builder();
+ // Build the egress ROADM rule
+ TrafficTreatment.Builder treatmentLast = DefaultTrafficTreatment.builder();
treatmentLast.setOutput(intent.dst().port());
- FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(),
- selectorBuilder.build(),
- treatmentLast.build(),
- 100,
- appId,
- 100,
- true);
+
+ FlowRule rule = new DefaultFlowRule.Builder()
+ .forDevice(intent.dst().deviceId())
+ .withSelector(selectorBuilder.build())
+ .withTreatment(treatmentLast.build())
+ .withPriority(100)
+ .fromApp(appId)
+ .makePermanent()
+ .build();
rules.add(rule);
return rules;
diff --git a/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java b/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java
new file mode 100644
index 0000000..cfa290b
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.net.resource.impl;
+
+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.apache.felix.scr.annotations.Service;
+import org.onosproject.net.Port;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentId;
+import org.onosproject.net.intent.OpticalConnectivityIntent;
+import org.onosproject.net.resource.DeviceResourceService;
+import org.onosproject.net.resource.DeviceResourceStore;
+import org.slf4j.Logger;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provides basic implementation of device resources allocation.
+ */
+@Component(immediate = true)
+@Service
+public class DeviceResourceManager implements DeviceResourceService {
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private DeviceResourceStore store;
+
+ @Activate
+ public void activate() {
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Stopped");
+ }
+
+ @Override
+ public Set<Port> requestPorts(Intent intent) {
+ checkNotNull(intent);
+ if (intent instanceof OpticalConnectivityIntent) {
+ OpticalConnectivityIntent opticalIntent = (OpticalConnectivityIntent) intent;
+ Set<Port> srcPorts = store.getFreePorts(opticalIntent.getSrc().deviceId());
+ Set<Port> dstPorts = store.getFreePorts(opticalIntent.getDst().deviceId());
+
+ Port srcPort = getTypedPort(srcPorts, Port.Type.OCH);
+ Port dstPort = getTypedPort(dstPorts, Port.Type.OCH);
+
+ if (srcPort == null || dstPort == null) {
+ return null;
+ }
+
+ Set<Port> allocPorts = new HashSet(Arrays.asList(srcPort, dstPort));
+
+ store.allocatePorts(allocPorts, intent.id());
+
+ return allocPorts;
+ }
+
+ return null;
+ }
+
+ @Override
+ public void releasePorts(IntentId intentId) {
+ store.releasePorts(intentId);
+ }
+
+ private Port getTypedPort(Set<Port> ports, Port.Type type) {
+ for (Port port : ports) {
+ if (port.type() == type) {
+ return port;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
index 08e8e4f..a18f2c5 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
@@ -52,6 +52,7 @@
import static org.onosproject.net.Link.Type.DIRECT;
import static org.onosproject.net.NetTestTools.PID;
import static org.onosproject.net.NetTestTools.connectPoint;
+import static org.onosproject.net.NetTestTools.createLambda;
public class OpticalPathIntentCompilerTest {
@@ -93,6 +94,7 @@
.src(d1p1)
.dst(d3p1)
.path(new DefaultPath(PID, links, hops))
+ .lambda(createLambda())
.build();
intentExtensionService = createMock(IntentExtensionService.class);
intentExtensionService.registerCompiler(OpticalPathIntent.class, sut);
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentDeviceResourceStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentDeviceResourceStore.java
new file mode 100644
index 0000000..b5e1655
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentDeviceResourceStore.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.store.resource.impl;
+
+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.apache.felix.scr.annotations.Service;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.intent.IntentId;
+import org.onosproject.net.resource.DeviceResourceStore;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.TransactionContext;
+import org.onosproject.store.service.TransactionalMap;
+import org.slf4j.Logger;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.slf4j.LoggerFactory.getLogger;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Store that manages device resources using Copycat-backed TransactionalMaps.
+ */
+@Component(immediate = true, enabled = true)
+@Service
+public class ConsistentDeviceResourceStore implements DeviceResourceStore {
+ private final Logger log = getLogger(getClass());
+
+ private static final String PORT_ALLOCATIONS = "PortAllocations";
+ private static final String INTENT_ALLOCATIONS = "IntentAllocations";
+
+ private static final Serializer SERIALIZER = Serializer.using(
+ new KryoNamespace.Builder().register(KryoNamespaces.API).build());
+
+ private ConsistentMap<Port, IntentId> portAllocMap;
+ private ConsistentMap<IntentId, Set<Port>> intentAllocMap;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Activate
+ public void activate() {
+ portAllocMap = storageService.<Port, IntentId>consistentMapBuilder()
+ .withName(PORT_ALLOCATIONS)
+ .withSerializer(SERIALIZER)
+ .build();
+ intentAllocMap = storageService.<IntentId, Set<Port>>consistentMapBuilder()
+ .withName(INTENT_ALLOCATIONS)
+ .withSerializer(SERIALIZER)
+ .build();
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Stopped");
+ }
+
+ private TransactionalMap<Port, IntentId> getPortAllocs(TransactionContext tx) {
+ return tx.getTransactionalMap(PORT_ALLOCATIONS, SERIALIZER);
+ }
+
+ private TransactionalMap<IntentId, Set<Port>> getIntentAllocs(TransactionContext tx) {
+ return tx.getTransactionalMap(INTENT_ALLOCATIONS, SERIALIZER);
+ }
+
+ private TransactionContext getTxContext() {
+ return storageService.transactionContextBuilder().build();
+ }
+
+ @Override
+ public Set<Port> getFreePorts(DeviceId deviceId) {
+ checkNotNull(deviceId);
+
+ Set<Port> freePorts = new HashSet<>();
+ for (Port port : deviceService.getPorts(deviceId)) {
+ if (!portAllocMap.containsKey(port)) {
+ freePorts.add(port);
+ }
+ }
+
+ return freePorts;
+ }
+
+ @Override
+ public void allocatePorts(Set<Port> ports, IntentId intentId) {
+ checkNotNull(ports);
+ checkArgument(ports.size() > 0);
+ checkNotNull(intentId);
+
+ TransactionContext tx = getTxContext();
+ tx.begin();
+ try {
+ TransactionalMap<Port, IntentId> portAllocs = getPortAllocs(tx);
+ for (Port port : ports) {
+ portAllocs.put(port, intentId);
+ }
+ TransactionalMap<IntentId, Set<Port>> intentAllocs = getIntentAllocs(tx);
+ intentAllocs.put(intentId, ports);
+ tx.commit();
+ } catch (Exception e) {
+ log.error("Exception thrown, rolling back", e);
+ tx.abort();
+ throw e;
+ }
+ }
+
+ @Override
+ public void releasePorts(IntentId intentId) {
+ checkNotNull(intentId);
+
+ TransactionContext tx = getTxContext();
+ tx.begin();
+ try {
+ TransactionalMap<IntentId, Set<Port>> intentAllocs = getIntentAllocs(tx);
+ Set<Port> ports = intentAllocs.get(intentId);
+ intentAllocs.remove(intentId);
+
+ TransactionalMap<Port, IntentId> portAllocs = getPortAllocs(tx);
+ for (Port port : ports) {
+ portAllocs.remove(port);
+ }
+ } catch (Exception e) {
+ log.error("Exception thrown, rolling back", e);
+ tx.abort();
+ throw e;
+ }
+ }
+}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java
index 6b22b75..454d04c 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java
@@ -17,6 +17,8 @@
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Deactivate;
import org.onlab.util.Bandwidth;
+import org.onosproject.net.OmsPort;
+import org.onosproject.net.device.DeviceService;
import org.slf4j.Logger;
import org.onlab.util.KryoNamespace;
import org.onlab.util.PositionalParameterStringFormatter;
@@ -55,7 +57,6 @@
import static com.google.common.base.Preconditions.checkState;
import static org.slf4j.LoggerFactory.getLogger;
import static org.onosproject.net.AnnotationKeys.BANDWIDTH;
-import static org.onosproject.net.AnnotationKeys.OPTICAL_WAVES;
/**
* Store that manages link resources using Copycat-backed TransactionalMaps.
@@ -78,7 +79,7 @@
// table to store current allocations
/** LinkKey -> List<LinkResourceAllocations>. */
- private static final String LINK_RESOURCE_ALLOCATIONS = "LinkResourceAllocations";
+ private static final String LINK_RESOURCE_ALLOCATIONS = "o";
/** IntentId -> LinkResourceAllocations. */
private static final String INTENT_ALLOCATIONS = "IntentAllocations";
@@ -95,6 +96,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkService linkService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
@Activate
public void activate() {
intentAllocMap = storageService.<IntentId, LinkResourceAllocations>consistentMapBuilder()
@@ -136,14 +140,14 @@
private Set<LambdaResourceAllocation> getLambdaResourceCapacity(Link link) {
Set<LambdaResourceAllocation> allocations = new HashSet<>();
- try {
- final int waves = Integer.parseInt(link.annotations().value(OPTICAL_WAVES));
- for (int i = 1; i <= waves; i++) {
- allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i)));
- }
- } catch (NumberFormatException e) {
- log.debug("No {} annotation on link {}", OPTICAL_WAVES, link);
+
+ OmsPort port = (OmsPort) deviceService.getPort(link.src().deviceId(), link.src().port());
+
+ // Assume fixed grid for now
+ for (int i = 0; i < port.totalChannels(); i++) {
+ allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i)));
}
+
return allocations;
}
diff --git a/tools/test/topos/opticalTest.py b/tools/test/topos/opticalTest.py
index c681933..b34f08d 100644
--- a/tools/test/topos/opticalTest.py
+++ b/tools/test/topos/opticalTest.py
@@ -54,12 +54,17 @@
self.addLink( O9, O10, port1=20, port2=20, annotations={ "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000, "durable": "true" }, cls=LINCLink )
self.addLink( SFOR10, O1, port1=2, port2=10, speed1=10000, annotations={ "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" }, cls=LINCLink )
+ self.addLink( SFOR10, O1, port1=3, port2=11, speed1=10000, annotations={ "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" }, cls=LINCLink )
+
self.addLink( LAXR10, O3, port1=2, port2=10, speed1=10000, annotations={ "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" }, cls=LINCLink )
# added second tap
self.addLink( LAXR10, O3, port1=3, port2=11, speed1=10000, annotations={ "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" }, cls=LINCLink )
self.addLink( SDGR10, O4, port1=2, port2=10, speed1=10000, annotations={ "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" }, cls=LINCLink )
self.addLink( CHGR10, O7, port1=2, port2=10, speed1=10000, annotations={ "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" }, cls=LINCLink )
+
self.addLink( JFKR10, O9, port1=2, port2=10, speed1=10000, annotations={ "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" }, cls=LINCLink )
+ self.addLink( JFKR10, O9, port1=3, port2=11, speed1=10000, annotations={ "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" }, cls=LINCLink )
+
self.addLink( ATLR10, O10, port1=2, port2=10, speed1=10000, annotations={ "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" }, cls=LINCLink )
h1 = self.addHost( 'h1' )
diff --git a/tools/test/topos/opticalUtils.py b/tools/test/topos/opticalUtils.py
index 116c0cc..f1559b4 100644
--- a/tools/test/topos/opticalUtils.py
+++ b/tools/test/topos/opticalUtils.py
@@ -426,11 +426,15 @@
response = json.load(urllib2.urlopen(url))
devs = response.get('devices')
- # Wait for all devices to be registered & available
- if (len(devices) == len(devs)):
- for d in devs:
- if not d['available']:
- continue
+ # Wait for all devices to be registered
+ if (len(devices) != len(devs)):
+ continue
+
+ # Wait for all devices to available
+ available = True
+ for d in devs:
+ available &= d['available']
+ if available:
break
if (time >= TIMEOUT):
diff --git a/utils/misc/src/main/java/org/onlab/util/Frequency.java b/utils/misc/src/main/java/org/onlab/util/Frequency.java
index 93de680..19c7900 100644
--- a/utils/misc/src/main/java/org/onlab/util/Frequency.java
+++ b/utils/misc/src/main/java/org/onlab/util/Frequency.java
@@ -138,6 +138,16 @@
return new Frequency(this.frequency * value);
}
+ /**
+ * Returns a Frequency whose value is Math.floorDiv(this, value).
+ *
+ * @param value
+ * @return Math.floorDiv(this, value)
+ */
+ public Frequency floorDivision(long value) {
+ return new Frequency(Math.floorDiv(this.frequency, value));
+ }
+
@Override
public int compareTo(Frequency other) {
return ComparisonChain.start()