yjimmyy
Committed by Gerrit Code Review

Implement Oplink drivers for port adjacency

Change-Id: I3cdc402c4dac544a7cb48544352df758c416345d
/*
* Copyright 2016-present 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.optical;
import com.google.common.annotations.Beta;
/**
* Collection of keys for annotation for optical devices.
*/
@Beta
public final class OpticalAnnotations {
private OpticalAnnotations() {}
/**
* Annotation key for optical port's target power.
*/
public static final String TARGET_POWER = "targetPower";
/**
* Annotation key for optical port's current power.
*/
public static final String CURRENT_POWER = "currentPower";
/**
* Annotation key for optical port's neighbor's DeviceId#toString().
*/
public static final String NEIGHBOR_ID = "neighborDeviceId";
/**
* Annotation key for optical port's neighbor's PortNumber#toString().
*/
public static final String NEIGHBOR_PORT = "neighborPort";
}
......@@ -15,8 +15,6 @@
*/
package org.onosproject.net;
import com.google.common.annotations.Beta;
/**
* Collection of keys for annotation.
* <p>
......@@ -112,18 +110,6 @@ public final class AnnotationKeys {
public static final String STATIC_LAMBDA = "staticLambda";
/**
* Annotation key for optical port's target power.
*/
@Beta
public static final String TARGET_POWER = "targetPower";
/**
* Annotation key for optical port's current power.
*/
@Beta
public static final String CURRENT_POWER = "currentPower";
/**
* Annotation key for the static port.
*/
public static final String STATIC_PORT = "staticPort";
......
......@@ -22,5 +22,6 @@
<bundle>mvn:org.onosproject/openflowj/0.9.5.onos</bundle>
<bundle>mvn:${project.groupId}/onos-of-api/${project.version}</bundle>
</feature>
</features>
......
......@@ -21,18 +21,28 @@ import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.onosproject.net.AnnotationKeys;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.onosproject.drivers.optical.OpticalAdjacencyLinkService;
import org.onosproject.net.Annotations;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DefaultPortDescription;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.device.PortDescription;
import org.onosproject.net.link.DefaultLinkDescription;
import org.onosproject.net.optical.OpticalAnnotations;
import org.onosproject.openflow.controller.Dpid;
import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
import org.onosproject.openflow.controller.PortDescPropertyType;
import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
......@@ -42,6 +52,12 @@ import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotSta
import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply;
import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest;
import org.projectfloodlight.openflow.protocol.OFExpExtAdId;
import org.projectfloodlight.openflow.protocol.OFExpPortAdidOtn;
import org.projectfloodlight.openflow.protocol.OFExpPortAdjacency;
import org.projectfloodlight.openflow.protocol.OFExpPortAdjacencyId;
import org.projectfloodlight.openflow.protocol.OFExpPortAdjacencyReply;
import org.projectfloodlight.openflow.protocol.OFExpPortAdjacencyRequest;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFObject;
import org.projectfloodlight.openflow.protocol.OFOplinkPortPower;
......@@ -61,7 +77,7 @@ import org.projectfloodlight.openflow.protocol.OFOplinkPortPowerReply;
* Driver implements custom handshaker and supports for Optical channel Port based on OpenFlow OTN extension.
* The device consists of Och ports, and performances wavelength cross-connect among the ports.
*/
public class OplinkRoadmHandshaker extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
public class OplinkRoadm extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
private List<OFPortOptical> opticalPorts;
......@@ -172,19 +188,24 @@ public class OplinkRoadmHandshaker extends AbstractOpenFlowSwitch implements Ope
@Override
public final void sendMsg(OFMessage m) {
OFMessage newMsg = m;
List<OFMessage> messages = new ArrayList<>();
messages.add(m);
if (m.getType() == OFType.STATS_REQUEST) {
OFStatsRequest sr = (OFStatsRequest) m;
log.debug("OPLK ROADM rebuilding stats request type {}", sr.getStatsType());
switch (sr.getStatsType()) {
case PORT:
//replace with Oplink experiment stats message to get the port current power
OFOplinkPortPowerRequest pRequest = this.factory().buildOplinkPortPowerRequest()
OFOplinkPortPowerRequest powerRequest = this.factory().buildOplinkPortPowerRequest()
.setXid(sr.getXid())
.setFlags(sr.getFlags())
.build();
newMsg = pRequest;
messages.add(powerRequest);
OFExpPortAdjacencyRequest adjacencyRequest = this.factory().buildExpPortAdjacencyRequest()
.setXid(sr.getXid())
.setFlags(sr.getFlags())
.build();
messages.add(adjacencyRequest);
break;
default:
break;
......@@ -193,7 +214,9 @@ public class OplinkRoadmHandshaker extends AbstractOpenFlowSwitch implements Ope
log.debug("OPLK ROADM sends msg:{}, as is", m.getType());
}
super.sendMsg(newMsg);
for (OFMessage message : messages) {
super.sendMsg(message);
}
}
private void sendHandshakeOFExperimenterPortDescRequest() throws IOException {
......@@ -223,33 +246,124 @@ public class OplinkRoadmHandshaker extends AbstractOpenFlowSwitch implements Ope
public List<PortDescription> processExpPortStats(OFMessage msg) {
if (msg instanceof OFOplinkPortPowerReply) {
return buildPortPowerDescriptions(((OFOplinkPortPowerReply) msg).getEntries());
} else if (msg instanceof OFExpPortAdjacencyReply) {
return buildPortAdjacencyDescriptions(((OFExpPortAdjacencyReply) msg).getEntries());
}
return Collections.emptyList();
}
private OFOplinkPortPower getPortPower(List<OFOplinkPortPower> portPowers, PortNumber portNum) {
for (OFOplinkPortPower power : portPowers) {
if (power.getPort() == portNum.toLong()) {
return power;
private List<PortDescription> buildPortPowerDescriptions(List<OFOplinkPortPower> portPowers) {
DeviceService deviceService = this.handler().get(DeviceService.class);
List<Port> ports = deviceService.getPorts(this.data().deviceId());
HashMap<Long, OFOplinkPortPower> powerMap = new HashMap<>(portPowers.size());
portPowers.forEach(power -> powerMap.put((long) power.getPort(), power));
final List<PortDescription> portDescs = new ArrayList<>();
for (Port port : ports) {
DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
builder.putAll(port.annotations());
OFOplinkPortPower power = powerMap.get(port.number().toLong());
if (power != null) {
builder.set(OpticalAnnotations.CURRENT_POWER, Long.toString(power.getPowerValue()));
}
portDescs.add(new DefaultPortDescription(port.number(), port.isEnabled(),
port.type(), port.portSpeed(), builder.build()));
}
return portDescs;
}
private OplinkPortAdjacency getNeighbor(OFExpPortAdjacency ad) {
for (OFExpPortAdjacencyId adid : ad.getProperties()) {
List<OFExpExtAdId> otns = adid.getAdId();
if (otns != null && otns.size() > 0) {
OFExpPortAdidOtn otn = (OFExpPortAdidOtn) otns.get(0);
// ITU-T G.7714 ETH MAC Format (in second 16 bytes of the following)
// |---------------------------------------------------------------------------|
// | Other format (16 bytes) |
// |---------------------------------------------------------------------------|
// | Header (2 bytes) | ID (4 bits) | MAC (6 bytes) | Port (4 bytes) | Unused |
// |---------------------------------------------------------------------------|
ChannelBuffer buffer = ChannelBuffers.buffer(32);
otn.getOpspec().write32Bytes(buffer);
long mac = buffer.getLong(18) << 4 >>> 16;
int port = (int) (buffer.getLong(24) << 4 >>> 32);
// Oplink does not use the 4 most significant bytes of Dpid so Dpid can be
// constructed from MAC address
return new OplinkPortAdjacency(DeviceId.deviceId(Dpid.uri(new Dpid(mac))),
PortNumber.portNumber(port));
}
}
return null;
}
private List<PortDescription> buildPortPowerDescriptions(List<OFOplinkPortPower> portPowers) {
private List<PortDescription> buildPortAdjacencyDescriptions(List<OFExpPortAdjacency> portAds) {
DeviceService deviceService = this.handler().get(DeviceService.class);
List<Port> ports = deviceService.getPorts(this.data().deviceId());
final List<PortDescription> portDescs = new ArrayList<>();
// Map port's number with port's adjacency
HashMap<Long, OFExpPortAdjacency> adMap = new HashMap<>(portAds.size());
portAds.forEach(ad -> adMap.put((long) ad.getPortNo().getPortNumber(), ad));
List<PortDescription> portDescs = new ArrayList<>();
for (Port port : ports) {
DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
builder.putAll(port.annotations());
OFOplinkPortPower power = getPortPower(portPowers, port.number());
if (power != null) {
builder.set(AnnotationKeys.CURRENT_POWER, Long.toString(power.getPowerValue()));
Annotations oldAnnotations = port.annotations();
builder.putAll(oldAnnotations);
OFExpPortAdjacency ad = adMap.get(port.number().toLong());
if (ad != null) {
// neighbor discovered, add to port descriptions
OplinkPortAdjacency neighbor = getNeighbor(ad);
String newId = neighbor.getDeviceId().toString();
String newPort = neighbor.getPort().toString();
// Check if annotation already exists
if (!newId.equals(oldAnnotations.value(OpticalAnnotations.NEIGHBOR_ID)) ||
!newPort.equals(oldAnnotations.value(OpticalAnnotations.NEIGHBOR_PORT))) {
builder.set(OpticalAnnotations.NEIGHBOR_ID, newId);
builder.set(OpticalAnnotations.NEIGHBOR_PORT, newPort);
}
addLink(port.number(), neighbor);
} else {
// no neighbors found
builder.remove(OpticalAnnotations.NEIGHBOR_ID);
builder.remove(OpticalAnnotations.NEIGHBOR_PORT);
removeLink(port.number());
}
portDescs.add(new DefaultPortDescription(port.number(), port.isEnabled(),
port.type(), port.portSpeed(), builder.build()));
}
return portDescs;
}
private void addLink(PortNumber portNumber, OplinkPortAdjacency neighbor) {
ConnectPoint dst = new ConnectPoint(handler().data().deviceId(), portNumber);
ConnectPoint src = new ConnectPoint(neighbor.getDeviceId(), neighbor.portNumber);
OpticalAdjacencyLinkService adService =
this.handler().get(OpticalAdjacencyLinkService.class);
adService.linkDetected(new DefaultLinkDescription(src, dst, Link.Type.OPTICAL));
}
// Remove incoming link with port if there are any.
private void removeLink(PortNumber portNumber) {
ConnectPoint dst = new ConnectPoint(handler().data().deviceId(), portNumber);
OpticalAdjacencyLinkService adService =
this.handler().get(OpticalAdjacencyLinkService.class);
adService.linksVanished(dst);
}
private class OplinkPortAdjacency {
private DeviceId deviceId;
private PortNumber portNumber;
public OplinkPortAdjacency(DeviceId deviceId, PortNumber portNumber) {
this.deviceId = deviceId;
this.portNumber = portNumber;
}
public DeviceId getDeviceId() {
return deviceId;
}
public PortNumber getPort() {
return portNumber;
}
}
}
......
......@@ -18,13 +18,13 @@ package org.onosproject.driver.optical.power;
import java.util.Optional;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.Direction;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.PowerConfig;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.optical.OpticalAnnotations;
import org.onosproject.openflow.controller.Dpid;
import org.onosproject.openflow.controller.OpenFlowController;
import org.onosproject.openflow.controller.OpenFlowSwitch;
......@@ -69,7 +69,7 @@ public class OplinkRoadmPowerConfig extends AbstractHandlerBehaviour
DeviceService deviceService = this.handler().get(DeviceService.class);
Port port = deviceService.getPort(this.data().deviceId(), portNum);
if (port != null) {
String currentPower = port.annotations().value(AnnotationKeys.CURRENT_POWER);
String currentPower = port.annotations().value(OpticalAnnotations.CURRENT_POWER);
if (currentPower != null) {
returnVal = Long.valueOf(currentPower);
}
......
/*
* Copyright 2016-present 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.drivers.optical;
import com.google.common.annotations.Beta;
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.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.link.LinkDescription;
import org.onosproject.net.link.LinkProvider;
import org.onosproject.net.link.LinkProviderRegistry;
import org.onosproject.net.link.LinkProviderService;
import org.onosproject.net.provider.ProviderId;
import org.slf4j.Logger;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Interface to allow for optical device drivers to add/remove links to
* the store. Acts as a proxy to LinkProviderService.
*
* Registers a dummy LinkProvider to get an instance of LinkProviderService.
*/
@Beta
@Component(immediate = true)
@Service
public class OpticalAdjacencyLinkManager implements OpticalAdjacencyLinkService {
private static final ProviderId PID =
new ProviderId("of", "org.onosproject.drivers.optical");
private final Logger log = getLogger(getClass());
private LinkProvider linkProvider = new StubLinkProvider();
private LinkProviderService linkProviderService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkProviderRegistry linkProviderRegistry;
@Activate
public void activate() {
linkProviderService = linkProviderRegistry.register(linkProvider);
log.info("Started");
}
@Deactivate
public void deactivate() {
linkProviderRegistry.unregister(linkProvider);
log.info("Stopped");
}
/**
* Signals that an infrastructure link has been detected.
*
* @param linkDescription link information
*/
@Override
public void linkDetected(LinkDescription linkDescription) {
linkProviderService.linkDetected(linkDescription);
}
/**
* Signals that an infrastructure link has disappeared.
*
* @param linkDescription link information
*/
@Override
public void linkVanished(LinkDescription linkDescription) {
linkProviderService.linkVanished(linkDescription);
}
/**
* Signals that infrastructure links associated with the specified
* connect point have vanished.
*
* @param connectPoint connect point
*/
@Override
public void linksVanished(ConnectPoint connectPoint) {
linkProviderService.linksVanished(connectPoint);
}
/**
* Signals that infrastructure links associated with the specified
* device have vanished.
*
* @param deviceId device identifier
*/
@Override
public void linksVanished(DeviceId deviceId) {
linkProviderService.linksVanished(deviceId);
}
// Stub provider used to get LinkProviderService
private static final class StubLinkProvider implements LinkProvider {
@Override
public ProviderId id() {
return PID;
}
}
}
/*
* Copyright 2016-present 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.drivers.optical;
import com.google.common.annotations.Beta;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.link.LinkDescription;
/**
* Interface to allow for optical device drivers to add/remove links to
* the store. Acts as a proxy to LinkProviderService.
*/
@Beta
public interface OpticalAdjacencyLinkService {
/**
* Signals that an infrastructure link has been detected.
*
* @param linkDescription link information
*/
void linkDetected(LinkDescription linkDescription);
/**
* Signals that an infrastructure link has disappeared.
*
* @param linkDescription link information
*/
void linkVanished(LinkDescription linkDescription);
/**
* Signals that infrastructure links associated with the specified
* connect point have vanished.
*
* @param connectPoint connect point
*/
void linksVanished(ConnectPoint connectPoint);
/**
* Signals that infrastructure links associated with the specified
* device have vanished.
*
* @param deviceId device identifier
*/
void linksVanished(DeviceId deviceId);
}
......@@ -51,7 +51,7 @@
manufacturer="Oplink a Molex company" hwVersion="ROADM"
swVersion="of-agent">
<behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
impl="org.onosproject.driver.optical.handshaker.OplinkRoadmHandshaker"/>
impl="org.onosproject.driver.optical.handshaker.OplinkRoadm"/>
<behaviour api="org.onosproject.net.behaviour.LambdaQuery"
impl="org.onosproject.driver.optical.query.OplinkRoadmLambdaQuery"/>
<behaviour api="org.onosproject.net.optical.OpticalDevice"
......