Ayaka Koshibe
Committed by Gerrit Code Review

Linc-OE ports now identifiable as Och and OMS ports.

Reference: ONOS-1803

Conflicts:
	utils/misc/src/main/java/org/onlab/util/Frequency.java

Change-Id: Ie2bdf74f8198afbd58a4762ff97bff6f4e9010df
......@@ -28,6 +28,9 @@ import org.onosproject.net.SparseAnnotations;
import org.onosproject.net.device.DefaultDeviceDescription;
import org.onosproject.net.device.DefaultPortDescription;
import org.onosproject.net.device.DeviceDescription;
import org.onosproject.net.device.OchPortDescription;
import org.onosproject.net.device.OduCltPortDescription;
import org.onosproject.net.device.OmsPortDescription;
import org.onosproject.net.device.PortDescription;
import org.onosproject.store.Timestamp;
import org.onosproject.store.impl.Timestamped;
......@@ -97,9 +100,34 @@ class DeviceDescriptions {
if (oldOne != null) {
SparseAnnotations merged = union(oldOne.value().annotations(),
newDesc.value().annotations());
newOne = new Timestamped<PortDescription>(
new DefaultPortDescription(newDesc.value(), merged),
newDesc.timestamp());
newOne = null;
switch (newDesc.value().type()) {
case OMS:
OmsPortDescription omsDesc = (OmsPortDescription) (newDesc.value());
newOne = new Timestamped<PortDescription>(
new OmsPortDescription(
omsDesc, omsDesc.minFrequency(), omsDesc.maxFrequency(), omsDesc.grid(), merged),
newDesc.timestamp());
break;
case OCH:
OchPortDescription ochDesc = (OchPortDescription) (newDesc.value());
newOne = new Timestamped<PortDescription>(
new OchPortDescription(
ochDesc, ochDesc.signalType(), ochDesc.isTunable(), ochDesc.lambda(), merged),
newDesc.timestamp());
break;
case ODUCLT:
OduCltPortDescription ocDesc = (OduCltPortDescription) (newDesc.value());
newOne = new Timestamped<PortDescription>(
new OduCltPortDescription(
ocDesc, ocDesc.signalType(), merged),
newDesc.timestamp());
break;
default:
newOne = new Timestamped<PortDescription>(
new DefaultPortDescription(newDesc.value(), merged),
newDesc.timestamp());
}
}
portDescs.put(newOne.value().portNumber(), newOne);
}
......
......@@ -717,7 +717,6 @@ public class GossipDeviceStore
public synchronized DeviceEvent updatePortStatus(ProviderId providerId,
DeviceId deviceId,
PortDescription portDescription) {
final Timestamp newTimestamp;
try {
newTimestamp = deviceClockService.getTimestamp(deviceId);
......@@ -1000,13 +999,14 @@ public class GossipDeviceStore
// if no primary, assume not enabled
boolean isEnabled = false;
DefaultAnnotations annotations = DefaultAnnotations.builder().build();
Timestamp newest = null;
final Timestamped<PortDescription> portDesc = primDescs.getPortDesc(number);
if (portDesc != null) {
isEnabled = portDesc.value().isEnabled();
annotations = merge(annotations, portDesc.value().annotations());
newest = portDesc.timestamp();
}
Port updated = null;
for (Entry<ProviderId, DeviceDescriptions> e : descsMap.entrySet()) {
if (e.getKey().equals(primary)) {
continue;
......@@ -1019,30 +1019,35 @@ public class GossipDeviceStore
// annotation merging. not so efficient, should revisit later
final Timestamped<PortDescription> otherPortDesc = e.getValue().getPortDesc(number);
if (otherPortDesc != null) {
if (newest != null && newest.isNewerThan(otherPortDesc.timestamp())) {
continue;
}
annotations = merge(annotations, otherPortDesc.value().annotations());
switch (otherPortDesc.value().type()) {
case OMS:
OmsPortDescription omsPortDesc = (OmsPortDescription) otherPortDesc.value();
updated = new OmsPort(device, number, isEnabled, omsPortDesc.minFrequency(),
omsPortDesc.maxFrequency(), omsPortDesc.grid());
break;
case OCH:
OchPortDescription ochPortDesc = (OchPortDescription) otherPortDesc.value();
updated = new OchPort(device, number, isEnabled, ochPortDesc.signalType(),
ochPortDesc.isTunable(), ochPortDesc.lambda(), annotations);
break;
case ODUCLT:
OduCltPortDescription oduCltPortDesc = (OduCltPortDescription) otherPortDesc.value();
updated = new OduCltPort(device, number, isEnabled, oduCltPortDesc.signalType(), annotations);
break;
default:
updated = new DefaultPort(device, number, isEnabled, annotations);
}
newest = otherPortDesc.timestamp();
}
}
if (portDesc == null) {
return new DefaultPort(device, number, false, annotations);
}
switch (portDesc.value().type()) {
case OMS:
OmsPortDescription omsPortDesc = (OmsPortDescription) portDesc.value();
return new OmsPort(device, number, isEnabled, omsPortDesc.minFrequency(),
omsPortDesc.maxFrequency(), omsPortDesc.grid());
case OCH:
OchPortDescription ochPortDesc = (OchPortDescription) portDesc.value();
return new OchPort(device, number, isEnabled, ochPortDesc.signalType(),
ochPortDesc.isTunable(), ochPortDesc.lambda(), annotations);
case ODUCLT:
OduCltPortDescription oduCltPortDesc = (OduCltPortDescription) portDesc.value();
return new OduCltPort(device, number, isEnabled, oduCltPortDesc.signalType(), annotations);
default:
return new DefaultPort(device, number, isEnabled, portDesc.value().type(),
portDesc.value().portSpeed(), annotations);
return updated == null ? new DefaultPort(device, number, false, annotations) : updated;
}
return updated == null ? new DefaultPort(device, number, isEnabled, annotations) : updated;
}
/**
......
......@@ -342,7 +342,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
if (sw.isOptical()) {
OpenFlowOpticalSwitch opsw = (OpenFlowOpticalSwitch) sw;
opsw.getPortTypes().forEach(type -> {
LOG.info("ports: {}", opsw.getPortsOf(type));
LOG.debug("ports: {}", opsw.getPortsOf(type));
opsw.getPortsOf(type).forEach(
op -> {
portDescs.add(buildPortDescription(type, (OFPortOptical) op));
......@@ -406,10 +406,10 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
if (port.getVersion() == OFVersion.OF_13
&& ptype == PortDescPropertyType.OPTICAL_TRANSPORT) {
// At this point, not much is carried in the optical port message.
LOG.info("Optical transport port message {}", port.toString());
LOG.debug("Optical transport port message {}", port.toString());
} else {
// removable once 1.4+ support complete.
LOG.warn("Unsupported optical port properties");
LOG.debug("Unsupported optical port properties");
}
return new DefaultPortDescription(portNo, enabled, type, 0, annotations);
}
......
......@@ -17,19 +17,28 @@ package org.onosproject.rest.resources;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.Lists;
import org.onlab.packet.ChassisId;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.util.Frequency;
import org.onosproject.net.ChannelSpacing;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.GridType;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.Link;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.OchPort;
import org.onosproject.net.OchSignal;
import org.onosproject.net.OduCltPort;
import org.onosproject.net.OduSignalType;
import org.onosproject.net.OmsPort;
import org.onosproject.net.Port;
import org.onosproject.net.SparseAnnotations;
import org.onosproject.net.device.DefaultDeviceDescription;
......@@ -41,6 +50,9 @@ import org.onosproject.net.device.DeviceProvider;
import org.onosproject.net.device.DeviceProviderRegistry;
import org.onosproject.net.device.DeviceProviderService;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.device.OchPortDescription;
import org.onosproject.net.device.OduCltPortDescription;
import org.onosproject.net.device.OmsPortDescription;
import org.onosproject.net.device.PortDescription;
import org.onosproject.net.host.DefaultHostDescription;
import org.onosproject.net.host.HostProvider;
......@@ -82,6 +94,10 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
private static final String UNKNOWN = "unknown";
private static final Frequency CENTER = Frequency.ofTHz(193.1);
// C-band has 4.4 THz (4,400 GHz) total bandwidth
private static final Frequency TOTAL = Frequency.ofTHz(4.4);
private CountDownLatch deviceLatch;
private final JsonNode cfg;
......@@ -200,6 +216,21 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
// Parses the given node with port information.
private PortDescription parsePort(JsonNode node) {
Port.Type type = Port.Type.valueOf(node.path("type").asText("COPPER"));
switch (type) {
case COPPER:
return new DefaultPortDescription(portNumber(node.path("port").asLong(0)),
node.path("enabled").asBoolean(true),
type, node.path("speed").asLong(1_000));
case FIBER:
// Currently, assume OMS when FIBER. Provide sane defaults.
return new OmsPortDescription(portNumber(node.path("port").asLong(0)),
node.path("enabled").asBoolean(true),
CENTER,
CENTER.add(TOTAL),
Frequency.ofGHz(100));
default:
log.warn("{}: Unsupported Port Type");
}
return new DefaultPortDescription(portNumber(node.path("port").asLong(0)),
node.path("enabled").asBoolean(true),
type, node.path("speed").asLong(1_000));
......@@ -224,7 +255,8 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
ConnectPoint dst = connectPoint(get(node, "dst"));
Link.Type type = Link.Type.valueOf(get(node, "type", "DIRECT"));
SparseAnnotations annotations = annotations(node.get("annotations"));
// take annotations to update optical ports with correct attributes.
updatePorts(src, dst, annotations);
DefaultLinkDescription desc = reverse ?
new DefaultLinkDescription(dst, src, type, annotations) :
new DefaultLinkDescription(src, dst, type, annotations);
......@@ -234,6 +266,98 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
connectPoints.add(dst);
}
private void updatePorts(ConnectPoint src, ConnectPoint dst, SparseAnnotations annotations) {
DeviceId srcId = src.deviceId();
DeviceId dstId = dst.deviceId();
Port srcPort = deviceService.getPort(srcId, src.port());
Port dstPort = deviceService.getPort(dstId, dst.port());
final String linkType = annotations.value("optical.type");
if ("cross-connect".equals(linkType)) {
String value = annotations.value("bandwidth").trim();
try {
double bw = Double.parseDouble(value);
updateOchPort(bw, srcPort, dstPort, srcId, dstId);
} catch (NumberFormatException e) {
log.warn("Invalid bandwidth ({}), can't configure port(s)", value);
return;
}
} else if ("WDM".equals(linkType)) {
String value = annotations.value("optical.waves").trim();
try {
int numChls = Integer.parseInt(value);
updateOMSPorts(numChls, srcPort, dstPort, srcId, dstId);
} catch (NumberFormatException e) {
log.warn("Invalid channel ({}), can't configure port(s)", value);
return;
}
}
}
// uses 'bandwidth' annotation to determine the channel spacing.
private void updateOchPort(double bw, Port srcPort, Port dstPort, DeviceId srcId, DeviceId dstId) {
Device src = deviceService.getDevice(srcId);
Device dst = deviceService.getDevice(dstId);
// bandwidth in MHz (assuming Hz - linc is not clear if Hz or b).
Frequency spacing = Frequency.ofMHz(bw);
// channel bandwidth is smaller than smallest standard channel spacing.
ChannelSpacing chsp = null;
if (spacing.compareTo(ChannelSpacing.CHL_6P25GHZ.frequency()) <= 0) {
chsp = ChannelSpacing.CHL_6P25GHZ;
}
for (int i = 1; i < ChannelSpacing.values().length; i++) {
Frequency val = ChannelSpacing.values()[i].frequency();
// pick the next highest or equal channel interval.
if (val.isLessThan(spacing)) {
chsp = ChannelSpacing.values()[i - 1];
break;
}
}
if (chsp == null) {
log.warn("Invalid channel spacing ({}), can't configure port(s)", spacing);
return;
}
OchSignal signal = new OchSignal(GridType.DWDM, chsp, 1, 1);
if (src.type() == Device.Type.ROADM) {
PortDescription portDesc = new OchPortDescription(srcPort.number(), srcPort.isEnabled(),
OduSignalType.ODU4, true, signal);
deviceProviderService.portStatusChanged(srcId, portDesc);
}
if (dst.type() == Device.Type.ROADM) {
PortDescription portDesc = new OchPortDescription(dstPort.number(), dstPort.isEnabled(),
OduSignalType.ODU4, true, signal);
deviceProviderService.portStatusChanged(dstId, portDesc);
}
}
private void updateOMSPorts(int numChls, Port srcPort, Port dstPort, DeviceId srcId, DeviceId dstId) {
// round down to largest slot that allows numChl channels to fit into C
// band range
ChannelSpacing chl = null;
Frequency perChl = TOTAL.floorDivision(numChls);
for (int i = 0; i < ChannelSpacing.values().length; i++) {
Frequency val = ChannelSpacing.values()[i].frequency();
if (val.isLessThan(perChl)) {
chl = ChannelSpacing.values()[i];
break;
}
}
if (chl == null) {
chl = ChannelSpacing.CHL_6P25GHZ;
}
// if true, there was less channels than can be tightly packed.
Frequency grid = (chl == null) ? Frequency.ofGHz(100) : chl.frequency();
// say Linc's 1st slot starts at CENTER and goes up from there.
Frequency min = CENTER.add(grid);
Frequency max = CENTER.add(grid.multiply(numChls));
PortDescription srcPortDesc = new OmsPortDescription(srcPort.number(), srcPort.isEnabled(), min, max, grid);
PortDescription dstPortDesc = new OmsPortDescription(dstPort.number(), dstPort.isEnabled(), min, max, grid);
deviceProviderService.portStatusChanged(srcId, srcPortDesc);
deviceProviderService.portStatusChanged(dstId, dstPortDesc);
}
// Parses the given JSON and provides hosts as configured.
private void parseHosts() {
try {
......@@ -298,15 +422,33 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
// Creates a port description from the specified port.
private PortDescription description(Port p) {
return new DefaultPortDescription(p.number(), p.isEnabled(), p.type(), p.portSpeed());
switch (p.type()) {
case OMS:
OmsPort op = (OmsPort) p;
return new OmsPortDescription(
op.number(), op.isEnabled(), op.minFrequency(), op.maxFrequency(), op.grid());
case OCH:
OchPort ochp = (OchPort) p;
return new OchPortDescription(
ochp.number(), ochp.isEnabled(), ochp.signalType(), ochp.isTunable(), ochp.lambda());
case ODUCLT:
OduCltPort odup = (OduCltPort) p;
return new OduCltPortDescription(
odup.number(), odup.isEnabled(), odup.signalType());
default:
return new DefaultPortDescription(p.number(), p.isEnabled(), p.type(), p.portSpeed());
}
}
// Creates a port description from the specified connection point.
private PortDescription description(ConnectPoint cp) {
return new DefaultPortDescription(cp.port(), true);
Port p = deviceService.getPort(cp.deviceId(), cp.port());
if (p == null) {
return new DefaultPortDescription(cp.port(), true);
}
return description(p);
}
// Produces set of annotations from the given JSON node.
private SparseAnnotations annotations(JsonNode node) {
if (node == null) {
......