Marc De Leenheer
Committed by Gerrit Code Review

Deprecate IndexedLambda and remove from optical intent compiler.

Allow drivers to report any spectral grid. Bugfixes.

ONOS-3495

Change-Id: Ied946660d48e482c1746d1e87735498b1637bb4b
......@@ -15,11 +15,6 @@
*/
package org.onosproject.optical.testapp;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.HashMap;
import java.util.Map;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
......@@ -44,9 +39,17 @@ import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.instructions.Instructions;
import org.slf4j.Logger;
import java.util.HashMap;
import java.util.Map;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Sample reactive forwarding application.
*
* @deprecated in Emu (ONOS 1.4).
*/
@Deprecated
//@Component(immediate = true)
public class LambdaForwarding {
......
......@@ -25,7 +25,7 @@ public enum ChannelSpacing {
CHL_50GHZ(50), // 50 GHz
CHL_25GHZ(25), // 25 GHz
CHL_12P5GHZ(12.5), // 12.5 GHz
CHL_6P25GHZ(6.5); // 6.25 GHz
CHL_6P25GHZ(6.25); // 6.25 GHz
private final Frequency frequency;
......
......@@ -19,7 +19,10 @@ import com.google.common.base.MoreObjects;
/**
* Implementation of Lambda simply designated by an index number of wavelength.
*
* @deprecated in Emu (ONOS 1.4).
*/
@Deprecated
public class IndexedLambda implements Lambda {
private final long index;
......
......@@ -16,10 +16,18 @@
package org.onosproject.net;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
import org.onlab.util.Frequency;
import org.onlab.util.Spectrum;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -33,14 +41,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class OchSignal implements Lambda {
public static final Frequency FLEX_GRID_SLOT = Frequency.ofGHz(12.5);
public static final Set<Integer> FIXED_GRID_SLOT_GRANULARITIES = ImmutableSet.of(1, 2, 4, 8);
private static final GridType DEFAULT_OCH_GRIDTYPE = GridType.DWDM;
private static final ChannelSpacing DEFAULT_CHANNEL_SPACING = ChannelSpacing.CHL_50GHZ;
private final GridType gridType;
private final ChannelSpacing channelSpacing;
// Frequency = 193.1 THz + spacingMultiplier * channelSpacing
// Nominal central frequency = 193.1 THz + spacingMultiplier * channelSpacing
private final int spacingMultiplier;
// Slot width = slotGranularity * 12.5 GHz
private final int slotGranularity;
......@@ -118,9 +125,9 @@ public class OchSignal implements Lambda {
}
/**
* Returns slow width granularity.
* Returns slot width granularity.
*
* @return slow width granularity
* @return slot width granularity
*/
public int slotGranularity() {
return slotGranularity;
......@@ -141,7 +148,56 @@ public class OchSignal implements Lambda {
* @return slot width
*/
public Frequency slotWidth() {
return FLEX_GRID_SLOT.multiply(slotGranularity);
return ChannelSpacing.CHL_12P5GHZ.frequency().multiply(slotGranularity);
}
/**
* Convert fixed grid OCh signal to sorted set of flex grid slots with 6.25 GHz spacing and 12.5 GHz slot width.
*
* @param ochSignal fixed grid lambda
* @return sorted set of flex grid OCh lambdas
*/
public static SortedSet<OchSignal> toFlexGrid(OchSignal ochSignal) {
checkArgument(ochSignal.gridType() != GridType.FLEX);
checkArgument(ochSignal.channelSpacing() != ChannelSpacing.CHL_6P25GHZ);
checkArgument(FIXED_GRID_SLOT_GRANULARITIES.contains(ochSignal.slotGranularity()));
int startMultiplier = (int) (1 - ochSignal.slotGranularity() +
ochSignal.spacingMultiplier() * ochSignal.channelSpacing().frequency().asHz() /
ChannelSpacing.CHL_6P25GHZ.frequency().asHz());
Supplier<SortedSet<OchSignal>> supplier = () -> new TreeSet<>(new DefaultOchSignalComparator());
return IntStream.range(0, ochSignal.slotGranularity())
.mapToObj(i -> new OchSignal(GridType.FLEX, ChannelSpacing.CHL_6P25GHZ, startMultiplier + 2 * i, 1))
.collect(Collectors.toCollection(supplier));
}
/**
* Convert list of lambdas with flex grid 6.25 GHz spacing and 12.5 GHz width into fixed grid OCh signal.
*
* @param lambdas list of flex grid lambdas in sorted order
* @param spacing desired fixed grid spacing
* @return fixed grid lambda
*/
public static OchSignal toFixedGrid(List<OchSignal> lambdas, ChannelSpacing spacing) {
// Number of slots of 12.5 GHz that fit into requested spacing
int ratio = (int) (spacing.frequency().asHz() / ChannelSpacing.CHL_12P5GHZ.frequency().asHz());
checkArgument(lambdas.size() == ratio);
lambdas.forEach(x -> checkArgument(x.gridType() == GridType.FLEX));
lambdas.forEach(x -> checkArgument(x.channelSpacing() == ChannelSpacing.CHL_6P25GHZ));
lambdas.forEach(x -> checkArgument(x.slotGranularity() == 1));
// Consecutive lambdas (multiplier increments by 2 because spacing is 6.25 GHz but slot width is 12.5 GHz)
IntStream.range(1, lambdas.size())
.forEach(i -> checkArgument(
lambdas.get(i).spacingMultiplier() == lambdas.get(i - 1).spacingMultiplier() + 2));
// Is center frequency compatible with requested spacing
Frequency center = lambdas.get(ratio / 2).centralFrequency().subtract(ChannelSpacing.CHL_6P25GHZ.frequency());
checkArgument(Spectrum.CENTER_FREQUENCY.subtract(center).asHz() % spacing.frequency().asHz() == 0);
// Multiplier sits in middle of given lambdas, then convert from 6.25 to requested spacing
int spacingMultiplier = (lambdas.get(ratio / 2).spacingMultiplier() + 1) / (ratio * 2);
return new OchSignal(GridType.DWDM, spacing, spacingMultiplier, lambdas.size());
}
@Override
......
......@@ -25,6 +25,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Implementation of indexed lambda criterion.
*/
@Deprecated
public class IndexedLambdaCriterion implements Criterion {
private final IndexedLambda lambda;
......
......@@ -26,14 +26,14 @@ import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.util.Frequency;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.ChannelSpacing;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultOchSignalComparator;
import org.onosproject.net.DeviceId;
import org.onosproject.net.IndexedLambda;
import org.onosproject.net.Link;
import org.onosproject.net.OchPort;
import org.onosproject.net.OchSignal;
import org.onosproject.net.OchSignalType;
import org.onosproject.net.OmsPort;
import org.onosproject.net.Path;
import org.onosproject.net.Port;
import org.onosproject.net.device.DeviceService;
......@@ -53,6 +53,7 @@ import org.onosproject.net.topology.TopologyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
......@@ -64,11 +65,12 @@ import static com.google.common.base.Preconditions.checkArgument;
/**
* An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}.
*/
// For now, remove component designation until dependency on the new resource manager is available.
@Component(immediate = true)
public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> {
protected 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;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentManager;
......@@ -133,16 +135,15 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
srcOchPort.lambda().channelSpacing(),
srcOchPort.lambda().slotGranularity());
} else if (!srcOchPort.isTunable() || !dstOchPort.isTunable()) {
// FIXME: also check OCh port
// FIXME: also check destination OCh port
ochSignal = srcOchPort.lambda();
} else {
// Request and reserve lambda on path
IndexedLambda lambda = assignWavelength(intent, path);
if (lambda == null) {
List<OchSignal> lambdas = assignWavelength(intent, path);
if (lambdas.isEmpty()) {
continue;
}
OmsPort omsPort = (OmsPort) deviceService.getPort(path.src().deviceId(), path.src().port());
ochSignal = new OchSignal((int) lambda.index(), omsPort.maxFrequency(), omsPort.grid());
ochSignal = OchSignal.toFixedGrid(lambdas, ChannelSpacing.CHL_50GHZ);
}
// Create installable optical path intent
......@@ -174,48 +175,77 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
* @param path path in WDM topology
* @return first available lambda allocated
*/
private IndexedLambda assignWavelength(Intent intent, Path path) {
Set<IndexedLambda> lambdas = findCommonLambdasOverLinks(path.links());
private List<OchSignal> assignWavelength(Intent intent, Path path) {
Set<OchSignal> lambdas = findCommonLambdasOverLinks(path.links());
if (lambdas.isEmpty()) {
return null;
return Collections.emptyList();
}
IndexedLambda minLambda = findFirstLambda(lambdas);
List<OchSignal> minLambda = findFirstLambda(lambdas, slotCount());
List<ResourcePath> lambdaResources = path.links().stream()
.flatMap(x -> Stream.of(
ResourcePath.discrete(x.src().deviceId(), x.src().port()),
ResourcePath.discrete(x.dst().deviceId(), x.dst().port())
))
.map(x -> x.child(minLambda))
.flatMap(x -> minLambda.stream().map(l -> x.child(l)))
.collect(Collectors.toList());
List<ResourceAllocation> allocations = resourceService.allocate(intent.id(), lambdaResources);
if (allocations.isEmpty()) {
log.info("Resource allocation for {} failed (resource request: {})", intent, lambdaResources);
return null;
return Collections.emptyList();
}
return minLambda;
}
private Set<IndexedLambda> findCommonLambdasOverLinks(List<Link> links) {
/**
* Get the number of 12.5 GHz slots required for the path.
*
* 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;
}
private Set<OchSignal> findCommonLambdasOverLinks(List<Link> links) {
return links.stream()
.flatMap(x -> Stream.of(
ResourcePath.discrete(x.src().deviceId(), x.src().port()),
ResourcePath.discrete(x.dst().deviceId(), x.dst().port())
))
.map(resourceService::getAvailableResources)
.map(x -> Iterables.filter(x, r -> r.last() instanceof IndexedLambda))
.map(x -> Iterables.transform(x, r -> (IndexedLambda) r.last()))
.map(x -> (Set<IndexedLambda>) ImmutableSet.copyOf(x))
.map(x -> Iterables.filter(x, r -> r.last() instanceof OchSignal))
.map(x -> Iterables.transform(x, r -> (OchSignal) r.last()))
.map(x -> (Set<OchSignal>) ImmutableSet.copyOf(x))
.reduce(Sets::intersection)
.orElse(Collections.emptySet());
}
private IndexedLambda findFirstLambda(Set<IndexedLambda> lambdas) {
return lambdas.stream()
.findFirst()
.get();
/**
* Returns list of consecutive resources in given set of lambdas.
*
* @param lambdas list of lambdas
* @param count number of consecutive lambdas to return
* @return list of consecutive lambdas
*/
private List<OchSignal> findFirstLambda(Set<OchSignal> lambdas, int count) {
// Sort available lambdas
List<OchSignal> lambdaList = new ArrayList<>(lambdas);
lambdaList.sort(new DefaultOchSignalComparator());
// Look ahead by count and ensure spacing multiplier is as expected (i.e., no gaps)
for (int i = 0; i < lambdaList.size() - count; i++) {
if (lambdaList.get(i).spacingMultiplier() + 2 * count ==
lambdaList.get(i + count).spacingMultiplier()) {
return lambdaList.subList(i, i + count);
}
}
return Collections.emptyList();
}
private ConnectPoint staticPort(ConnectPoint connectPoint) {
......
......@@ -19,6 +19,7 @@ import com.google.common.collect.Lists;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onlab.util.ItemNotFoundException;
import org.onosproject.net.DefaultOchSignalComparator;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
......@@ -44,7 +45,9 @@ import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ExecutorService;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
......@@ -199,7 +202,10 @@ final class ResourceDeviceListener implements DeviceListener {
}
LambdaQuery query = handler.behaviour(LambdaQuery.class);
if (query != null) {
return query.queryLambdas(port);
Supplier<SortedSet<OchSignal>> supplier = () -> new TreeSet<>(new DefaultOchSignalComparator());
return query.queryLambdas(port).stream()
.flatMap(x -> OchSignal.toFlexGrid(x).stream())
.collect(Collectors.toCollection(supplier));
} else {
return Collections.emptySortedSet();
}
......
......@@ -51,6 +51,7 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
......@@ -209,13 +210,12 @@ public class CalientFiberSwitchHandshaker
ChannelSpacing.CHL_12P5GHZ.frequency().asHz();
long stopSpacingMultiplier = Spectrum.O_BAND_MAX.subtract(Spectrum.CENTER_FREQUENCY).asHz() /
ChannelSpacing.CHL_12P5GHZ.frequency().asHz();
List<OchSignal> lambdas = IntStream.rangeClosed((int) startSpacingMultiplier, (int) stopSpacingMultiplier)
.mapToObj(x -> new OchSignal(GridType.FLEX, ChannelSpacing.CHL_12P5GHZ, x, 1))
.collect(Collectors.toList());
Supplier<SortedSet<OchSignal>> supplier = () -> new TreeSet<>(new DefaultOchSignalComparator());
SortedSet<OchSignal> result = new TreeSet<>(new DefaultOchSignalComparator());
result.addAll(lambdas);
return result;
// Only consider odd values for the multiplier (for easy mapping to fixed grid)
return IntStream.rangeClosed((int) startSpacingMultiplier, (int) stopSpacingMultiplier)
.filter(i -> i % 2 == 1)
.mapToObj(i -> new OchSignal(GridType.FLEX, ChannelSpacing.CHL_6P25GHZ, i, 1))
.collect(Collectors.toCollection(supplier));
}
}
......
......@@ -59,6 +59,7 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
......@@ -74,7 +75,7 @@ import java.util.stream.IntStream;
* As LINC implements custom OF optical extensions (in contrast to the final standard as specified in
* ONF TS-022 (March 15, 2015), we need to rewrite flow stat requests and flow mods in {@link #sendMsg(OFMessage)}.
*
* LINC exposes OchSignal resources: 80 lambdas of 50 GHz around ITU-T G.694.1 center frequency 193.1 GHz.
* LINC exposes OchSignal resources: 80 lambdas of 50 GHz (fixed grid) around ITU-T G.694.1 center frequency 193.1 GHz.
*
*/
public class OfOpticalSwitchImplLinc13
......@@ -224,8 +225,9 @@ public class OfOpticalSwitchImplLinc13
}
OFActionSetField sf = (OFActionSetField) action;
if (!(sf instanceof OFOxmExpOchSigId)) {
if (!(sf.getField() instanceof OFOxmExpOchSigId)) {
newActions.add(action);
continue;
}
OFOxmExpOchSigId oxm = (OFOxmExpOchSigId) sf.getField();
......@@ -259,7 +261,6 @@ public class OfOpticalSwitchImplLinc13
OFFlowMod fm = (OFFlowMod) msg;
newMatch = rewriteMatch(fm.getMatch());
List<OFAction> actions = rewriteActions(fm.getActions());
newMsg = fm.createBuilder().setMatch(newMatch).setActions(actions).build();
}
......@@ -371,15 +372,10 @@ public class OfOpticalSwitchImplLinc13
return Collections.emptySortedSet();
}
// OMS ports expose 80 lambdas of 50GHz width, centered around the ITU-T center frequency.
// We report these with a spacing of 12.5 GHz.
List<OchSignal> lambdas = IntStream.range(0, LAMBDA_COUNT)
.mapToObj(x -> new OchSignal(GridType.FLEX, ChannelSpacing.CHL_12P5GHZ, x - (LAMBDA_COUNT / 2), 1))
.collect(Collectors.toList());
SortedSet<OchSignal> result = new TreeSet<>(new DefaultOchSignalComparator());
result.addAll(lambdas);
return result;
// OMS ports expose 80 fixed grid lambdas of 50GHz width, centered around the ITU-T center frequency 193.1 THz.
Supplier<SortedSet<OchSignal>> supplier = () -> new TreeSet<>(new DefaultOchSignalComparator());
return IntStream.range(0, LAMBDA_COUNT)
.mapToObj(x -> new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, x - (LAMBDA_COUNT / 2), 4))
.collect(Collectors.toCollection(supplier));
}
}
......
......@@ -536,7 +536,9 @@ class LINCSwitch(OpticalSwitch):
for link in LINCSwitch.opticalJSON[ 'links' ]:
linkDict = {}
linkDict[ 'type' ] = link[ 'type' ]
linkDict.update(link[ 'annotations' ])
# FIXME: Clean up unnecessary link/device attributes, then re-enable annotations
linkDict['durable'] = True
# linkDict.update(link[ 'annotations' ])
linkSubj = link[ 'src' ] + '-' + link[ 'dst' ]
links[ linkSubj ] = { 'basic': linkDict }
......