Marc De Leenheer
Committed by Gerrit Code Review

Driver and flow stats handling for Calient fiber switch S160.

Bump loxigen to 0.4.1.onos-SNAPSHOT.

Change-Id: Ieb8aa4fe716e12f89b83770eff617561f30cdd08
......@@ -26,7 +26,7 @@ public interface Device extends Element {
* Coarse classification of the type of the infrastructure device.
*/
public enum Type {
SWITCH, ROUTER, ROADM, OTN, ROADM_OTN, FIREWALL, BALANCER, IPS, IDS, CONTROLLER, VIRTUAL, OTHER
SWITCH, ROUTER, ROADM, OTN, ROADM_OTN, FIREWALL, BALANCER, IPS, IDS, CONTROLLER, VIRTUAL, FIBER_SWITCH, OTHER
}
/**
......
......@@ -194,8 +194,7 @@ public class PacketManager
* @param request the packet request
*/
private void pushRule(Device device, PacketRequest request) {
// Everything is pre-provisioned on ROADMs
if (device.type().equals(Device.Type.ROADM)) {
if (!device.type().equals(Device.Type.SWITCH)) {
return;
}
......@@ -217,8 +216,7 @@ public class PacketManager
* @param request the packet request
*/
private void removeRule(Device device, PacketRequest request) {
// Everything is pre-provisioned on ROADMs
if (device.type().equals(Device.Type.ROADM)) {
if (!device.type().equals(Device.Type.SWITCH)) {
return;
}
......
/*
* 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.driver.handshaker;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.onosproject.net.Device;
import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
import org.onosproject.openflow.controller.PortDescPropertyType;
import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsRequest;
import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsEntry;
import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsRequest;
import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFObject;
import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
import org.projectfloodlight.openflow.protocol.OFStatsRequest;
import org.projectfloodlight.openflow.protocol.OFType;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.TableId;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
public class CalientFiberSwitchHandshaker extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
private List<OFCalientPortDescStatsEntry> fiberPorts = new ArrayList<>();
@Override
public Boolean supportNxRole() {
return false;
}
@Override
public void startDriverHandshake() {
log.warn("Starting driver handshake for sw {}", getStringId());
if (startDriverHandshakeCalled) {
throw new SwitchDriverSubHandshakeAlreadyStarted();
}
startDriverHandshakeCalled = true;
try {
sendHandshakeOFExperimenterPortDescRequest();
} catch (IOException e) {
log.error("Exception while sending experimenter port desc:", e.getMessage());
e.printStackTrace();
}
}
private void sendHandshakeOFExperimenterPortDescRequest() throws IOException {
// send multi part message for port description for optical switches
OFCalientPortDescStatsRequest portsRequest = factory()
.buildCalientPortDescStatsRequest()
.build();
log.warn("Sending experimenter port description message {}",
portsRequest.toString());
this.sendHandshakeMessage(portsRequest);
}
@Override
public boolean isDriverHandshakeComplete() {
return driverHandshakeComplete.get();
}
@Override
public void processDriverHandshakeMessage(OFMessage m) {
if (!startDriverHandshakeCalled) {
throw new SwitchDriverSubHandshakeNotStarted();
}
if (driverHandshakeComplete.get()) {
throw new SwitchDriverSubHandshakeCompleted(m);
}
switch (m.getType()) {
case BARRIER_REPLY:
break;
case ERROR:
log.error("Switch Error {} {}", getStringId(), m);
break;
case FEATURES_REPLY:
break;
case FLOW_REMOVED:
break;
case GET_ASYNC_REPLY:
break;
case PACKET_IN:
break;
case PORT_STATUS:
break;
case QUEUE_GET_CONFIG_REPLY:
break;
case ROLE_REPLY:
break;
case STATS_REPLY:
log.warn("Received port desc reply");
OFCalientPortDescStatsReply descStatsReply = (OFCalientPortDescStatsReply) m;
fiberPorts.addAll(descStatsReply.getPortDesc());
// Multi-part message
if (!descStatsReply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
driverHandshakeComplete.set(true);
}
break;
default:
log.warn("Received message {} during switch-driver " +
"subhandshake " + "from switch {} ... " +
"Ignoring message", m,
getStringId());
}
}
@Override
public Device.Type deviceType() {
return Device.Type.FIBER_SWITCH;
}
@Override
public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
return ImmutableList.copyOf(fiberPorts);
}
@Override
public Set<PortDescPropertyType> getPortTypes() {
return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
}
@Override
public final void sendMsg(OFMessage m) {
OFMessage newMsg = m;
if (m.getType() == OFType.STATS_REQUEST) {
OFStatsRequest sr = (OFStatsRequest) m;
log.debug("Rebuilding stats request type {}", sr.getStatsType());
switch (sr.getStatsType()) {
case FLOW:
OFCalientFlowStatsRequest request = this.factory().buildCalientFlowStatsRequest()
.setCookie(((OFFlowStatsRequest) sr).getCookie())
.setCookieMask(((OFFlowStatsRequest) sr).getCookieMask())
.setMatch(this.factory().matchWildcardAll())
.setOutGroup(((OFFlowStatsRequest) sr).getOutGroup().getGroupNumber())
.setOutPort(OFPort.ANY)
.setTableId(TableId.ALL)
.setXid(sr.getXid())
.setFlags(sr.getFlags())
.build();
newMsg = request;
break;
case PORT:
// TODO
break;
default:
break;
}
}
super.sendMsg(newMsg);
}
}
......@@ -15,6 +15,7 @@
*/
package org.onosproject.driver.handshaker;
import org.onosproject.net.Device;
import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
import org.onosproject.openflow.controller.PortDescPropertyType;
import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
......@@ -156,8 +157,8 @@ public class OFOpticalSwitchImplLINC13
}
@Override
public boolean isOptical() {
return true;
public Device.Type deviceType() {
return Device.Type.ROADM;
}
@Override
......
......@@ -105,5 +105,11 @@
<behaviour api="org.onosproject.net.behaviour.Pipeliner"
impl="org.onosproject.driver.pipeline.CpqdOFDPA1Pipeline"/>
</driver>
<driver name="calient" extends="default"
manufacturer="calient inc" hwVersion="calient hardware"
swVersion="ocs switch">
<behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
impl="org.onosproject.driver.handshaker.CalientFiberSwitchHandshaker"/>
</driver>
</drivers>
......
......@@ -15,6 +15,7 @@
*/
package org.onosproject.openflow.controller;
import org.onosproject.net.Device;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
......@@ -136,11 +137,11 @@ public interface OpenFlowSwitch {
void returnRoleReply(RoleState requested, RoleState response);
/**
* Indicates if this switch is optical.
* Returns the switch device type.
*
* @return true if optical
* @return device type
*/
boolean isOptical();
Device.Type deviceType();
/**
* Identifies the channel used to communicate with the switch.
......
......@@ -18,6 +18,7 @@ package org.onosproject.openflow.controller.driver;
import org.jboss.netty.channel.Channel;
import org.onlab.packet.IpAddress;
import org.onosproject.net.Device;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.openflow.controller.Dpid;
import org.onosproject.openflow.controller.RoleState;
......@@ -95,7 +96,7 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
}
@Override
public final void sendMsg(OFMessage m) {
public void sendMsg(OFMessage m) {
if (role == RoleState.MASTER && channel.isConnected()) {
channel.write(Collections.singletonList(m));
}
......@@ -413,8 +414,8 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
@Override
public boolean isOptical() {
return false;
public Device.Type deviceType() {
return Device.Type.SWITCH;
}
......
......@@ -38,6 +38,8 @@ import org.onosproject.openflow.controller.PacketListener;
import org.onosproject.openflow.controller.RoleState;
import org.onosproject.openflow.controller.driver.OpenFlowAgent;
import org.osgi.service.component.ComponentContext;
import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsEntry;
import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsReply;
import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
import org.projectfloodlight.openflow.protocol.OFExperimenter;
import org.projectfloodlight.openflow.protocol.OFFactories;
......@@ -55,12 +57,17 @@ import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
......@@ -299,16 +306,63 @@ public class OpenFlowControllerImpl implements OpenFlowController {
case PORT:
executorMsgs.submit(new OFMessageHandler(dpid, reply));
break;
default:
case EXPERIMENTER:
if (reply instanceof OFCalientFlowStatsReply) {
// Convert Calient flow statistics to regular flow stats
// TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
OFFlowStatsReply.Builder fsr = getSwitch(dpid).factory().buildFlowStatsReply();
List<OFFlowStatsEntry> entries = new LinkedList<>();
for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) msg).getEntries()) {
// Single instruction, i.e., output to port
OFActionOutput action = OFFactories
.getFactory(msg.getVersion())
.actions()
.buildOutput()
.setPort(entry.getOutPort())
.build();
OFInstruction instruction = OFFactories
.getFactory(msg.getVersion())
.instructions()
.applyActions(Collections.singletonList(action));
OFFlowStatsEntry fs = getSwitch(dpid).factory().buildFlowStatsEntry()
.setMatch(entry.getMatch())
.setTableId(entry.getTableId())
.setDurationSec(entry.getDurationSec())
.setDurationNsec(entry.getDurationNsec())
.setPriority(entry.getPriority())
.setIdleTimeout(entry.getIdleTimeout())
.setHardTimeout(entry.getHardTimeout())
.setFlags(entry.getFlags())
.setCookie(entry.getCookie())
.setInstructions(Collections.singletonList(instruction))
.build();
entries.add(fs);
}
fsr.setEntries(entries);
flowStats = publishFlowStats(dpid, fsr.build());
if (flowStats != null) {
OFFlowStatsReply.Builder rep =
OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
rep.setEntries(Lists.newLinkedList(flowStats));
executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
}
} else {
log.warn("Unsupported stats type : {}", reply.getStatsType());
}
break;
default:
break;
}
break;
case BARRIER_REPLY:
executorBarrier.submit(new OFMessageHandler(dpid, msg));
break;
case EXPERIMENTER:
// Handle optical port stats
if (((OFExperimenter) msg).getExperimenter() == 0x748771) {
long experimenter = ((OFExperimenter) msg).getExperimenter();
if (experimenter == 0x748771) {
// LINC-OE port stats
OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
OFPortStatus.Builder portStatus = this.getSwitch(dpid).factory().buildPortStatus();
OFPortDesc.Builder portDesc = this.getSwitch(dpid).factory().buildPortDesc();
......
......@@ -19,6 +19,7 @@ import org.jboss.netty.channel.Channel;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onosproject.net.Device;
import org.onosproject.net.driver.DriverData;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.openflow.controller.Dpid;
......@@ -181,8 +182,8 @@ public class RoleManagerTest {
}
@Override
public boolean isOptical() {
return false;
public Device.Type deviceType() {
return Device.Type.SWITCH;
}
@Override
......
......@@ -74,7 +74,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<netty4.version>4.0.23.Final</netty4.version>
<copycat.version>0.5.0.onos12-SNAPSHOT</copycat.version>
<openflowj.version>0.4.0.onos</openflowj.version>
<openflowj.version>0.4.1.onos-SNAPSHOT</openflowj.version>
<karaf.version>3.0.3</karaf.version>
<jersey.version>1.19</jersey.version>
</properties>
......
......@@ -29,9 +29,10 @@ import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.ChassisId;
import org.onosproject.cfg.ComponentConfigService;
import org.onlab.util.Frequency;
import org.onlab.util.Spectrum;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.Port;
......@@ -44,6 +45,7 @@ import org.onosproject.net.device.DeviceDescription;
import org.onosproject.net.device.DeviceProvider;
import org.onosproject.net.device.DeviceProviderRegistry;
import org.onosproject.net.device.DeviceProviderService;
import org.onosproject.net.device.OmsPortDescription;
import org.onosproject.net.device.PortDescription;
import org.onosproject.net.device.PortStatistics;
import org.onosproject.net.provider.AbstractProvider;
......@@ -57,6 +59,7 @@ import org.onosproject.openflow.controller.OpenFlowSwitchListener;
import org.onosproject.openflow.controller.PortDescPropertyType;
import org.onosproject.openflow.controller.RoleState;
import org.osgi.service.component.ComponentContext;
import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsEntry;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortConfig;
......@@ -290,8 +293,6 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
DeviceId did = deviceId(uri(dpid));
OpenFlowSwitch sw = controller.getSwitch(dpid);
Device.Type deviceType = sw.isOptical() ? Device.Type.ROADM :
Device.Type.SWITCH;
ChassisId cId = new ChassisId(dpid.value());
SparseAnnotations annotations = DefaultAnnotations.builder()
......@@ -300,7 +301,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
.build();
DeviceDescription description =
new DefaultDeviceDescription(did.uri(), deviceType,
new DefaultDeviceDescription(did.uri(), sw.deviceType(),
sw.manufacturerDescription(),
sw.hardwareDescription(),
sw.softwareDescription(),
......@@ -380,8 +381,11 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
private List<PortDescription> buildPortDescriptions(OpenFlowSwitch sw) {
final List<PortDescription> portDescs = new ArrayList<>(sw.getPorts().size());
sw.getPorts().forEach(port -> portDescs.add(buildPortDescription(port)));
if (sw.isOptical()) {
OpenFlowOpticalSwitch opsw = (OpenFlowOpticalSwitch) sw;
OpenFlowOpticalSwitch opsw;
switch (sw.deviceType()) {
case ROADM:
opsw = (OpenFlowOpticalSwitch) sw;
opsw.getPortTypes().forEach(type -> {
opsw.getPortsOf(type).forEach(
op -> {
......@@ -389,7 +393,21 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
}
);
});
break;
case FIBER_SWITCH:
opsw = (OpenFlowOpticalSwitch) sw;
opsw.getPortTypes().forEach(type -> {
opsw.getPortsOf(type).forEach(
op -> {
portDescs.add(buildPortDescription((OFCalientPortDescStatsEntry) op));
}
);
});
break;
default:
break;
}
return portDescs;
}
......@@ -454,6 +472,28 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
return new DefaultPortDescription(portNo, enabled, FIBER, 0, annotations);
}
/**
* Build a portDescription from a given port description describing a fiber switch optical port.
*
* @param port description property type.
* @param port the port to build from.
* @return portDescription for the port.
*/
private PortDescription buildPortDescription(OFCalientPortDescStatsEntry port) {
PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
// FIXME when Calient OF agent reports port status
boolean enabled = true;
SparseAnnotations annotations = makePortNameAnnotation(port.getName());
// Wavelength range: 1260 - 1630 nm (S160 data sheet)
// Grid is irrelevant for this type of switch
Frequency minFreq = Spectrum.O_BAND_MAX;
Frequency maxFreq = Spectrum.U_BAND_MIN;
Frequency grid = Frequency.ofGHz(100);
return new OmsPortDescription(portNo, enabled, minFreq, maxFreq, grid, annotations);
}
private PortDescription buildPortDescription(OFPortStatus status) {
OFPortDesc port = status.getDesc();
if (status.getReason() != OFPortReason.DELETE) {
......
......@@ -384,8 +384,8 @@ public class OpenFlowDeviceProviderTest {
}
@Override
public boolean isOptical() {
return false;
public Device.Type deviceType() {
return Device.Type.SWITCH;
}
@Override
......
......@@ -370,7 +370,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
+ " tell us which one.");
}
}
break;
default:
log.debug("Unhandled message type: {}", msg.getType());
}
......
......@@ -6,6 +6,7 @@ import org.junit.Before;
import org.junit.Test;
import org.onosproject.core.DefaultGroupId;
import org.onosproject.core.GroupId;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment;
......@@ -383,8 +384,8 @@ public class OpenFlowGroupProviderTest {
}
@Override
public boolean isOptical() {
return false;
public Device.Type deviceType() {
return Device.Type.SWITCH;
}
@Override
......
......@@ -22,6 +22,7 @@ import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.ARP;
import org.onlab.packet.Ethernet;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment;
......@@ -412,12 +413,11 @@ public class OpenFlowPacketProviderTest {
}
@Override
public boolean isOptical() {
return false;
public void returnRoleReply(RoleState requested, RoleState reponse) {
}
@Override
public void returnRoleReply(RoleState requested, RoleState reponse) {
public Device.Type deviceType() {
return Device.Type.SWITCH;
}
@Override
......
/*
* 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.onlab.util;
/**
* Telecom optical wavelength bands: O, E, S, C, L and U bands.
*
* See ITU-T G-Series Recommendations, Supplement 39
*/
public final class Spectrum {
private Spectrum() {
}
// O band (original): 1260 to 1360 nm
public static final Frequency O_BAND_MIN = Frequency.ofTHz(220.436);
public static final Frequency O_BAND_MAX = Frequency.ofTHz(237.931);
// E band (extended): 1360 to 1460 nm
public static final Frequency E_BAND_MIN = Frequency.ofTHz(205.337);
public static final Frequency E_BAND_MAX = Frequency.ofTHz(220.436);
// S band (short wavelength): 1460 to 1530 nm
public static final Frequency S_BAND_MIN = Frequency.ofTHz(195.943);
public static final Frequency S_BAND_MAX = Frequency.ofTHz(205.337);
// C band (conventional): 1530 to 1565 nm
public static final Frequency C_BAND_MIN = Frequency.ofTHz(191.561);
public static final Frequency C_BAND_MAX = Frequency.ofTHz(195.943);
// L band (long wavelength): 1565 to 1625 nm
public static final Frequency L_BAND_MIN = Frequency.ofTHz(184.488);
public static final Frequency L_BAND_MAX = Frequency.ofTHz(191.561);
// U band (ultra-long wavelength): 1625 to 1675 nm
public static final Frequency U_BAND_MIN = Frequency.ofTHz(178.981);
public static final Frequency U_BAND_MAX = Frequency.ofTHz(184.488);
}