[ODTN] support to FLEX_GRID intents: REST inetrface, intent compilation, openconfig and openroadm drivers.
patch 2: checkstyle
patch 3: davide's comments
Change-Id: I7574e8e6ee3ac3c18dc1533cad1a8f25142c26bc
diff --git a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
index 682ea1f..68ccd45 100644
--- a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
+++ b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
@@ -83,7 +83,9 @@
private static final Logger log = LoggerFactory.getLogger(OpticalConnectivityIntentCompiler.class);
// By default, allocate 50 GHz lambdas (4 slots of 12.5 GHz) for each intent.
- private static final int SLOT_COUNT = 4;
+ private static final int DEFAULT_SLOT_GRANULARITY = 4;
+ private static final GridType DEFAULT_GRID_TYPE = GridType.DWDM;
+ private static final ChannelSpacing DEFAULT_CHANNEL_SPACING = ChannelSpacing.CHL_50GHZ;
private static final ProviderId PROVIDER_ID = new ProviderId("opticalConnectivityIntent",
"org.onosproject.net.optical.intent");
@@ -110,9 +112,20 @@
intentManager.unregisterCompiler(OpticalConnectivityIntent.class);
}
+ /**
+ * Path computation and spectrum assignment.
+ * Supports fixed and flex grids.
+ *
+ * Path and signal can be provided within the intent.
+ * If not provided they are computed in this function.
+ * If signal is not provided a default channel is allocated with width 50 GHz, on the 50 GHz spacing.
+ *
+ * @param intent this intent (used for resource tracking)
+ * @param installable intents
+ * @return list of optical path intents (one per direction)
+ */
@Override
- public List<Intent> compile(OpticalConnectivityIntent intent,
- List<Intent> installable) {
+ public List<Intent> compile(OpticalConnectivityIntent intent, List<Intent> installable) {
// Check if source and destination are optical OCh ports
ConnectPoint src = intent.getSrc();
ConnectPoint dst = intent.getDst();
@@ -127,7 +140,7 @@
// TODO: try to release intent resources in IntentManager.
resourceService.release(intent.key());
- // Check OCh port availability
+ // Check OCH src and dst port availability
// If ports are not available, compilation fails
// Else add port to resource reservation list
Resource srcPortResource = Resources.discrete(src.deviceId(), src.port()).resource();
@@ -139,7 +152,8 @@
resources.add(srcPortResource);
resources.add(dstPortResource);
- // If there is a suggestedPath, use this path without further checking, otherwise trigger path computation
+ // If there is a valid suggestedPath, use this path without further checking
+ // Otherwise trigger path computation
Stream<Path> paths;
if (intent.suggestedPath().isPresent()) {
paths = Stream.of(intent.suggestedPath().get());
@@ -157,11 +171,19 @@
// Allocate resources and create optical path intent
if (found.isPresent()) {
- log.debug("Suitable lightpath FOUND for intent {}", intent);
+ log.debug("Suitable path and lambdas FOUND for intent {}", intent);
resources.addAll(convertToResources(found.get().getKey(), found.get().getValue()));
allocateResources(intent, resources);
- OchSignal ochSignal = OchSignal.toFixedGrid(found.get().getValue(), ChannelSpacing.CHL_50GHZ);
+
+ if (intent.ochSignal().isPresent()) {
+ if (intent.ochSignal().get().gridType() == GridType.FLEX) {
+ return ImmutableList.of(createIntent(intent, found.get().getKey(), intent.ochSignal().get()));
+ }
+ }
+
+ OchSignal ochSignal = OchSignal.toFixedGrid(found.get().getValue(), DEFAULT_CHANNEL_SPACING);
return ImmutableList.of(createIntent(intent, found.get().getKey(), ochSignal));
+
} else {
log.error("Unable to find suitable lightpath for intent {}", intent);
throw new OpticalIntentCompilationException("Unable to find suitable lightpath for intent " + intent);
@@ -170,7 +192,7 @@
/**
* Create installable optical path intent.
- * Only supports fixed grid for now.
+ * Supports fixed and flex grids.
*
* @param parentIntent this intent (used for resource tracking)
* @param path the path to use
@@ -178,7 +200,12 @@
* @return optical path intent
*/
private Intent createIntent(OpticalConnectivityIntent parentIntent, Path path, OchSignal lambda) {
- OchSignalType signalType = OchSignalType.FIXED_GRID;
+ OchSignalType signalType;
+ if (lambda.gridType().equals(GridType.FLEX)) {
+ signalType = OchSignalType.FLEX_GRID;
+ } else {
+ signalType = OchSignalType.FIXED_GRID;
+ }
return OpticalPathIntent.builder()
.appId(parentIntent.appId())
@@ -243,18 +270,23 @@
//create lambdas w.r.t. slotGanularity/slotWidth
OchSignal ochSignal = intent.ochSignal().get();
if (ochSignal.gridType() == GridType.FLEX) {
- // multiplier sits in the middle of slots
- int startMultiplier = ochSignal.spacingMultiplier() - (ochSignal.slotGranularity() / 2);
- return IntStream.range(0, ochSignal.slotGranularity())
+ int startMultiplier = (int) (1 - ochSignal.slotGranularity() + ochSignal.spacingMultiplier());
+
+ List<OchSignal> channels = IntStream.range(0, ochSignal.slotGranularity())
.mapToObj(x -> OchSignal.newFlexGridSlot(startMultiplier + (2 * x)))
.collect(Collectors.toList());
+
+ return channels;
} else if (ochSignal.gridType() == GridType.DWDM) {
int startMultiplier = (int) (1 - ochSignal.slotGranularity() +
ochSignal.spacingMultiplier() * ochSignal.channelSpacing().frequency().asHz() /
ChannelSpacing.CHL_6P25GHZ.frequency().asHz());
- return IntStream.range(0, ochSignal.slotGranularity())
+
+ List<OchSignal> channels = IntStream.range(0, ochSignal.slotGranularity())
.mapToObj(x -> OchSignal.newFlexGridSlot(startMultiplier + (2 * x)))
.collect(Collectors.toList());
+
+ return channels;
}
//TODO: add support for other gridTypes
log.error("Grid type: {} not supported for user defined signal intents", ochSignal.gridType());
@@ -266,19 +298,7 @@
return Collections.emptyList();
}
- return findFirstLambda(lambdas, slotCount());
- }
-
- /**
- * Get the number of 12.5 GHz slots required for the path.
- * <p>
- * For now this returns a constant value of 4 (i.e., fixed grid 50 GHz slot),
- * but in the future can depend on optical reach, line rate, transponder port capabilities, etc.
- *
- * @return number of slots
- */
- private int slotCount() {
- return SLOT_COUNT;
+ return findFirstLambda(lambdas, DEFAULT_SLOT_GRANULARITY);
}
/**
@@ -458,7 +478,6 @@
return path;
});
}
-
return paths;
}
}
diff --git a/apps/optical-model/src/main/java/org/onosproject/net/optical/util/OpticalIntentUtility.java b/apps/optical-model/src/main/java/org/onosproject/net/optical/util/OpticalIntentUtility.java
index 7956f57..b351210 100644
--- a/apps/optical-model/src/main/java/org/onosproject/net/optical/util/OpticalIntentUtility.java
+++ b/apps/optical-model/src/main/java/org/onosproject/net/optical/util/OpticalIntentUtility.java
@@ -163,7 +163,7 @@
if (ingress == null || egress == null) {
log.error("Invalid endpoint(s); could not create optical intent");
- return intent;
+ return null;
}
DeviceService ds = opticalView(deviceService);
@@ -178,7 +178,7 @@
// continue only if both OduClt port's Devices are of the same type
if (!(srcDevice.type().equals(dstDevice.type()))) {
log.debug("Devices without same deviceType: SRC={} and DST={}", srcDevice.type(), dstDevice.type());
- return intent;
+ return null;
}
CltSignalType signalType = ((OduCltPort) srcPort).signalType();
diff --git a/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/OpticalIntentsWebResource.java b/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/OpticalIntentsWebResource.java
index 1570a2e..c0dedf5 100644
--- a/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/OpticalIntentsWebResource.java
+++ b/apps/optical-rest/src/main/java/org/onosproject/net/optical/rest/OpticalIntentsWebResource.java
@@ -25,8 +25,10 @@
import org.onlab.graph.ScalarWeight;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
+import org.onosproject.net.ChannelSpacing;
import org.onosproject.net.Device;
import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.GridType;
import org.onosproject.net.Link;
import org.onosproject.net.DefaultPath;
import org.onosproject.net.ConnectPoint;
@@ -279,6 +281,49 @@
throw new IllegalArgumentException(JSON_INVALID);
} else {
signal = OchSignalCodec.decode((ObjectNode) signalJson);
+
+ if (signal.gridType() == GridType.FLEX) {
+ if (signal.channelSpacing() != ChannelSpacing.CHL_6P25GHZ) {
+ throw new IllegalArgumentException("FLEX grid requires CHL_6P25GHZ spacing");
+ }
+ if (isOdd(signal.slotGranularity()) && !isOdd(signal.spacingMultiplier())) {
+ throw new IllegalArgumentException("FLEX grid using odd Granularity requires odd Multiplier");
+ }
+ if (!isOdd(signal.slotGranularity()) && isOdd(signal.spacingMultiplier())) {
+ throw new IllegalArgumentException("FLEX grid using even Granularity requires even Multiplier");
+ }
+ }
+
+ if (signal.gridType() == GridType.DWDM) {
+ if (signal.channelSpacing() == ChannelSpacing.CHL_6P25GHZ) {
+ throw new IllegalArgumentException("DWDM grid requires spacing CHL_12P5GHZ, " +
+ "CHL_25GHZ, CHL_50GHZ or CHL_100GHZ");
+ }
+
+ if (signal.channelSpacing() == ChannelSpacing.CHL_12P5GHZ) {
+ if (signal.slotGranularity() != 1) {
+ throw new IllegalArgumentException("Spacing CHL_12P5GHZ requires granularity 1");
+ }
+ }
+
+ if (signal.channelSpacing() == ChannelSpacing.CHL_25GHZ) {
+ if (signal.slotGranularity() != 2) {
+ throw new IllegalArgumentException("Spacing CHL_25GHZ requires granularity 2");
+ }
+ }
+
+ if (signal.channelSpacing() == ChannelSpacing.CHL_50GHZ) {
+ if (signal.slotGranularity() != 4) {
+ throw new IllegalArgumentException("Spacing CHL_50GHZ requires granularity 4");
+ }
+ }
+
+ if (signal.channelSpacing() == ChannelSpacing.CHL_100GHZ) {
+ if (signal.slotGranularity() != 8) {
+ throw new IllegalArgumentException("Spacing CHL_100GHZ requires granularity 8");
+ }
+ }
+ }
}
}
@@ -361,4 +406,11 @@
}
return true;
}
+
+ private boolean isOdd(int n) {
+ if (n % 2 != 0) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openconfig/ClientLineTerminalDeviceFlowRuleProgrammable.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openconfig/ClientLineTerminalDeviceFlowRuleProgrammable.java
index 8896b98..ac9fd48 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openconfig/ClientLineTerminalDeviceFlowRuleProgrammable.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openconfig/ClientLineTerminalDeviceFlowRuleProgrammable.java
@@ -604,16 +604,10 @@
//Retrieved rules and cached rules are considered equal if both selector and treatment are equal
cacheAddRule = null;
cacheDropRule = null;
- if (getConnectionCache().size(did()) != 0) {
- cacheDropRule = getConnectionCache().get(did()).stream()
- .filter(r -> (r.selector().equals(selectorDrop) && r.treatment().equals(treatmentDrop)))
- .findFirst()
- .orElse(null);
- cacheAddRule = getConnectionCache().get(did()).stream()
- .filter(r -> (r.selector().equals(selectorAdd) && r.treatment().equals(treatmentAdd)))
- .findFirst()
- .orElse(null);
+ if (getConnectionCache().size(did()) != 0) {
+ cacheDropRule = findDropRule(inputPortNumber, outputPortNumber, centralFreq);
+ cacheAddRule = findAddRule(inputPortNumber, outputPortNumber, centralFreq);
}
//Include the DROP rule to the retrieved rules if found in cache
@@ -937,6 +931,33 @@
.collect(Collectors.toList());
return linePorts;
+ }
+ private FlowRule findDropRule(PortNumber inPort, PortNumber outPort, Frequency freq) {
+
+ FlowRule rule = getConnectionCache().get(did()).stream()
+ .filter(r -> r instanceof TerminalDeviceFlowRule)
+ .filter(r -> ((TerminalDeviceFlowRule) r).type.equals(TerminalDeviceFlowRule.Type.LINE_EGRESS))
+ .filter(r -> ((TerminalDeviceFlowRule) r).ochSignal().centralFrequency().equals(freq))
+ .filter(r -> ((TerminalDeviceFlowRule) r).inPort().equals(inPort))
+ .filter(r -> ((TerminalDeviceFlowRule) r).outPort().equals(outPort))
+ .findFirst()
+ .orElse(null);
+
+ return rule;
+ }
+
+ private FlowRule findAddRule(PortNumber inPort, PortNumber outPort, Frequency freq) {
+
+ FlowRule rule = getConnectionCache().get(did()).stream()
+ .filter(r -> r instanceof TerminalDeviceFlowRule)
+ .filter(r -> ((TerminalDeviceFlowRule) r).type.equals(TerminalDeviceFlowRule.Type.LINE_INGRESS))
+ .filter(r -> ((TerminalDeviceFlowRule) r).ochSignal().centralFrequency().equals(freq))
+ .filter(r -> ((TerminalDeviceFlowRule) r).inPort().equals(inPort))
+ .filter(r -> ((TerminalDeviceFlowRule) r).outPort().equals(outPort))
+ .findFirst()
+ .orElse(null);
+
+ return rule;
}
}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmConnection.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmConnection.java
index 5afaf2f..63a1be9 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmConnection.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmConnection.java
@@ -28,7 +28,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
class OpenRoadmConnectionBase {
protected static final Logger log = LoggerFactory.getLogger(OpenRoadmConnection.class);
@@ -146,7 +145,7 @@
// Conversion from ochSignal (center frequency + diameter) to OpenRoadm
// Media Channel (start - end)
Frequency freqRadius = Frequency.ofHz(
- xc.ochSignal().channelSpacing().frequency().asHz() / 2);
+ xc.ochSignal().slotWidth().asHz() / 2);
Frequency centerFreq = xc.ochSignal().centralFrequency();
// e.g. DEG1-TTP-RX
@@ -161,12 +160,15 @@
srcMcMinFrequency = centerFreq.subtract(freqRadius);
srcMcMaxFrequency = centerFreq.add(freqRadius);
+
+ log.error("OPENROADM CONNECTION GENERATED min {} max {}", srcMcMinFrequency, srcMcMaxFrequency);
+
dstMcMinFrequency = srcMcMinFrequency;
dstMcMaxFrequency = srcMcMaxFrequency;
srcNmcFrequency = centerFreq;
dstNmcFrequency = centerFreq;
- srcNmcWidth = xc.ochSignal().channelSpacing().frequency();
- dstNmcWidth = xc.ochSignal().channelSpacing().frequency();
+ srcNmcWidth = xc.ochSignal().slotWidth();
+ dstNmcWidth = xc.ochSignal().slotWidth();
srcMcSupportingInterface =
"OMS-" +
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmFlowRuleProgrammable.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmFlowRuleProgrammable.java
index 54d5152..e29bd60 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmFlowRuleProgrammable.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmFlowRuleProgrammable.java
@@ -34,23 +34,14 @@
import org.onosproject.net.DeviceId;
import org.onosproject.net.GridType;
import org.onosproject.net.OchSignal;
-import org.onosproject.net.OchSignalType;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.flow.DefaultFlowEntry;
-import org.onosproject.net.flow.DefaultFlowRule;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleProgrammable;
-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.Instruction;
-import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.netconf.DatastoreId;
import org.onosproject.netconf.NetconfController;
import org.onosproject.netconf.NetconfException;
@@ -104,7 +95,6 @@
log.info("OPENROADM {}: " + format, did(), arguments);
}
-
/**
* Get a list of Port numbers that are LINE ports (degree).
* <p>
@@ -156,7 +146,6 @@
}
}
-
/**
* Get the flow entries that are present on the device, called by
* FlowRuleDriverProvider. <p> The flow entries must match exactly the
@@ -181,7 +170,6 @@
return entries;
}
-
/**
* Apply the flow entries specified in the collection rules.
*
@@ -204,7 +192,6 @@
return added;
}
-
/**
* Remove the specified flow rules.
*
@@ -287,35 +274,9 @@
} else {
openRoadmLog("connection retrieved {}", name);
}
- OpenRoadmFlowRule xc = new OpenRoadmFlowRule(flowRule, getLinePorts());
- DeviceService deviceService = this.handler().get(DeviceService.class);
- OpenRoadmConnection conn = OpenRoadmConnectionFactory.create(name, xc, deviceService);
- OchSignal och = toOchSignalCenterWidth(conn.srcNmcFrequency, conn.srcNmcWidth);
- // Build the rule selector and treatment
- TrafficSelector selector =
- DefaultTrafficSelector.builder()
- .matchInPort(conn.inPortNumber)
- .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID))
- .add(Criteria.matchLambda(och))
- .build();
- Instruction ochInstruction = Instructions.modL0Lambda(och);
- TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .add(ochInstruction)
- .setOutput(conn.outPortNumber)
- .build();
-
- return DefaultFlowRule.builder()
- .forDevice(data().deviceId())
- .makePermanent()
- .withSelector(selector)
- .withTreatment(treatment)
- .withPriority(conn.priority)
- .withCookie(conn.id.value())
- .build();
+ return flowRule;
}
-
-
/**
* Delete a ROADM Interface given its name.
*
@@ -334,8 +295,6 @@
}
}
-
-
/**
* Delete a ROADM Connection given its name.
*
@@ -393,8 +352,6 @@
return true;
}
-
-
/**
* Entry point to remove a Crossconnect.
*
@@ -429,7 +386,6 @@
editConfigDeleteInterfaceEntry(conn.dstMcName);
}
-
return true;
}
@@ -587,7 +543,6 @@
return true;
}
-
/**
* Create a ROADM Connection given its data.
*
@@ -740,7 +695,6 @@
return new OchSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, multiplier, slots);
}
-
return null;
}
}