Brian O'Connor

Merge branch 'optical-integration'

Showing 35 changed files with 1720 additions and 15 deletions
package org.onlab.onos.optical.provisioner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
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.onlab.onos.ApplicationId;
import org.onlab.onos.CoreService;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.device.DeviceService;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentEvent;
import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.IntentListener;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.OpticalConnectivityIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.onos.net.link.LinkService;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.topology.LinkWeight;
import org.onlab.onos.net.topology.Topology;
import org.onlab.onos.net.topology.TopologyEdge;
import org.onlab.onos.net.topology.TopologyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* OpticalPathProvisioner listens event notifications from the Intent F/W.
* It generates one or more opticalConnectivityIntent(s) and submits (or withdraws) to Intent F/W
* for adding/releasing capacity at the packet layer.
*
*/
@Component(immediate = true)
public class OpticalPathProvisioner {
protected static final Logger log = LoggerFactory
.getLogger(OpticalPathProvisioner.class);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private IntentService intentService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private IntentExtensionService intentExtensionService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkService linkService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceService;
private ApplicationId appId;
//protected <IntentId> intentIdGenerator;
private final InternalOpticalPathProvisioner pathProvisioner = new InternalOpticalPathProvisioner();
@Activate
protected void activate() {
intentService.addListener(pathProvisioner);
appId = coreService.registerApplication("org.onlab.onos.optical");
log.info("Starting optical path provisoning...");
}
@Deactivate
protected void deactivate() {
intentService.removeListener(pathProvisioner);
}
public class InternalOpticalPathProvisioner implements IntentListener {
@Override
public void event(IntentEvent event) {
switch (event.type()) {
case SUBMITTED:
break;
case INSTALLED:
break;
case FAILED:
log.info("intent {} failed, calling optical path provisioning APP.", event.subject());
setuplightpath(event.subject());
break;
case WITHDRAWN:
log.info("intent {} withdrawn.", event.subject());
teardownLightpath(event.subject());
break;
default:
break;
}
}
private void setuplightpath(Intent intent) {
// TODO: considering user policies and optical reach
if (!intent.equals(PointToPointIntent.class)) {
return;
}
PointToPointIntent pktIntent = (PointToPointIntent) intent;
if (pktIntent.ingressPoint() == null || pktIntent.egressPoint() == null) {
return;
}
Topology topology = topologyService.currentTopology();
LinkWeight weight = new LinkWeight() {
@Override
public double weight(TopologyEdge edge) {
boolean isOptical = false;
String t = edge.link().annotations().value("linkType");
if (t.equals("WDM")) {
isOptical = true;
}
if (isOptical) {
return 1000; // optical links
} else {
return 10; // packet links
}
}
};
Set<Path> paths = topologyService.getPaths(topology,
pktIntent.ingressPoint().deviceId(),
pktIntent.egressPoint().deviceId(),
weight);
if (paths.isEmpty()) {
return;
}
ConnectPoint srcWdmPoint = null;
ConnectPoint dstWdmPoint = null;
Iterator<Path> itrPath = paths.iterator();
Path firstPath = itrPath.next();
log.info(firstPath.toString());
ArrayList<Map<ConnectPoint, ConnectPoint>> connectionList = new ArrayList<>();
Iterator<Link> itrLink = firstPath.links().iterator();
while (itrLink.hasNext()) {
Link link1 = itrLink.next();
if (!isOpticalLink(link1)) {
continue;
} else {
srcWdmPoint = link1.dst();
dstWdmPoint = srcWdmPoint;
}
while (true) {
if (itrLink.hasNext()) {
Link link2 = itrLink.next();
dstWdmPoint = link2.src();
} else {
break;
}
if (itrLink.hasNext()) {
Link link3 = itrLink.next();
if (!isOpticalLink(link3)) {
break;
}
} else {
break;
}
}
Map<ConnectPoint, ConnectPoint> pair =
new HashMap<ConnectPoint, ConnectPoint>();
pair.put(srcWdmPoint, dstWdmPoint);
connectionList.add(pair);
}
for (Map<ConnectPoint, ConnectPoint> map : connectionList) {
for (Entry<ConnectPoint, ConnectPoint> entry : map.entrySet()) {
ConnectPoint src = entry.getKey();
ConnectPoint dst = entry.getValue();
Intent opticalIntent = new OpticalConnectivityIntent(appId,
srcWdmPoint,
dstWdmPoint);
intentService.submit(opticalIntent);
log.info(opticalIntent.toString());
}
}
}
private boolean isOpticalLink(Link link) {
boolean isOptical = false;
String t = link.annotations().value("linkType");
if (t.equals("WDM") || t.equals("PktOptLink")) {
isOptical = true;
}
return isOptical;
}
private void teardownLightpath(Intent intent) {
// TODO: tear down the idle lightpath if the utilization is close to zero.
}
}
}
package org.onlab.onos.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;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.CoreService;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.device.DeviceEvent;
import org.onlab.onos.net.device.DeviceListener;
import org.onlab.onos.net.device.DeviceService;
import org.onlab.onos.net.flow.DefaultFlowRule;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.DefaultTrafficTreatment;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.FlowRuleService;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.slf4j.Logger;
/**
* Sample reactive forwarding application.
*/
//@Component(immediate = true)
public class LambdaForwarding {
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleService flowRuleService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
private ApplicationId appId;
private final InternalDeviceListener listener = new InternalDeviceListener();
private final Map<DeviceId, Integer> uglyMap = new HashMap<>();
@Activate
public void activate() {
appId = coreService.registerApplication("org.onlab.onos.fwd");
uglyMap.put(DeviceId.deviceId("of:0000ffffffffff01"), 1);
uglyMap.put(DeviceId.deviceId("of:0000ffffffffff02"), 2);
uglyMap.put(DeviceId.deviceId("of:0000ffffffffff03"), 3);
deviceService.addListener(listener);
for (Device d : deviceService.getDevices()) {
pushRules(d);
}
log.info("Started with Application ID {}", appId.id());
}
@Deactivate
public void deactivate() {
flowRuleService.removeFlowRulesById(appId);
log.info("Stopped");
}
private void pushRules(Device device) {
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
int inport;
int outport;
short lambda = 10;
byte sigType = 1;
Integer switchNumber = uglyMap.get(device.id());
if (switchNumber == null) {
return;
}
switch (switchNumber) {
case 1:
inport = 10;
outport = 20;
sbuilder.matchInport(PortNumber.portNumber(inport));
tbuilder.setOutput(PortNumber.portNumber(outport)).setLambda(lambda);
break;
case 2:
inport = 21;
outport = 11;
sbuilder.matchLambda(lambda).
matchInport(PortNumber.portNumber(inport)); // match sigtype
tbuilder.setOutput(PortNumber.portNumber(outport));
break;
case 3:
inport = 30;
outport = 31;
sbuilder.matchLambda(lambda).
matchInport(PortNumber.portNumber(inport));
tbuilder.setOutput(PortNumber.portNumber(outport)).setLambda(lambda);
break;
default:
}
TrafficTreatment treatement = tbuilder.build();
TrafficSelector selector = sbuilder.build();
FlowRule f = new DefaultFlowRule(device.id(), selector,
treatement, 100, appId, 600, false);
flowRuleService.applyFlowRules(f);
}
public class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
switch (event.type()) {
case DEVICE_ADDED:
pushRules(event.subject());
break;
case DEVICE_AVAILABILITY_CHANGED:
break;
case DEVICE_MASTERSHIP_CHANGED:
break;
case DEVICE_REMOVED:
break;
case DEVICE_SUSPENDED:
break;
case DEVICE_UPDATED:
break;
case PORT_ADDED:
break;
case PORT_REMOVED:
break;
case PORT_UPDATED:
break;
default:
break;
}
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.onos.cli.net;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.PortNumber.portNumber;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.OpticalConnectivityIntent;
/**
* Installs optical connectivity intents.
*/
@Command(scope = "onos", name = "add-optical-intent",
description = "Installs optical connectivity intent")
public class AddOpticalIntentCommand extends ConnectivityIntentCommand {
@Argument(index = 0, name = "ingressDevice",
description = "Ingress Device/Port Description",
required = true, multiValued = false)
String ingressDeviceString = null;
@Argument(index = 1, name = "egressDevice",
description = "Egress Device/Port Description",
required = true, multiValued = false)
String egressDeviceString = null;
@Override
protected void execute() {
IntentService service = get(IntentService.class);
DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString));
PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString));
ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber);
DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString));
PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
Intent intent = new OpticalConnectivityIntent(appId(), ingress, egress);
service.submit(intent);
}
/**
* Extracts the port number portion of the ConnectPoint.
*
* @param deviceString string representing the device/port
* @return port number as a string, empty string if the port is not found
*/
private String getPortNumber(String deviceString) {
int slash = deviceString.indexOf('/');
if (slash <= 0) {
return "";
}
return deviceString.substring(slash + 1, deviceString.length());
}
/**
* Extracts the device ID portion of the ConnectPoint.
*
* @param deviceString string representing the device/port
* @return device ID string
*/
private String getDeviceId(String deviceString) {
int slash = deviceString.indexOf('/');
if (slash <= 0) {
return "";
}
return deviceString.substring(0, slash);
}
}
......@@ -119,6 +119,14 @@
</optional-completers>
</command>
<command>
<action class="org.onlab.onos.cli.net.AddOpticalIntentCommand"/>
<completers>
<ref component-id="connectPointCompleter"/>
<ref component-id="connectPointCompleter"/>
<null/>
</completers>
</command>
<command>
<action class="org.onlab.onos.cli.net.GetStatistics"/>
<completers>
<ref component-id="connectPointCompleter"/>
......
......@@ -176,6 +176,17 @@ public final class DefaultTrafficSelector implements TrafficSelector {
}
@Override
public Builder matchLambda(Short lambda) {
return add(Criteria.matchLambda(lambda));
}
@Override
public Builder matchOpticalSignalType(Byte signalType) {
return add(Criteria.matchOpticalSignalType(signalType));
}
@Override
public TrafficSelector build() {
return new DefaultTrafficSelector(ImmutableSet.copyOf(selector.values()));
}
......
......@@ -137,6 +137,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
case OUTPUT:
outputs.add(instruction);
break;
case L0MODIFICATION:
case L2MODIFICATION:
case L3MODIFICATION:
// TODO: enforce modification order if any
......@@ -193,6 +194,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
}
@Override
public Builder setLambda(short lambda) {
return add(Instructions.modL0Lambda(lambda));
}
@Override
public TrafficTreatment build() {
//If we are dropping should we just return an emptry list?
......
......@@ -130,6 +130,20 @@ public interface TrafficSelector {
public Builder matchTcpDst(Short tcpPort);
/**
* Matches an optical signal ID or lambda.
* @param lambda
* @return a selection builder
*/
public Builder matchLambda(Short lambda);
/**
* Matches an optical Signal Type.
* @param signalType
* @return a selection builder
*/
public Builder matchOpticalSignalType(Byte signalType);
/**
* Builds an immutable traffic selector.
*
* @return traffic selector
......
......@@ -105,6 +105,13 @@ public interface TrafficTreatment {
public Builder setIpDst(IpPrefix addr);
/**
* Sets the optical channel ID or lambda.
* @param lambda optical channel ID
* @return a treatment builder
*/
public Builder setLambda(short lambda);
/**
* Builds an immutable traffic treatment descriptor.
*
* @return traffic treatment
......
......@@ -151,10 +151,30 @@ public final class Criteria {
return new TcpPortCriterion(tcpPort, Type.TCP_DST);
}
/*
* Implementations of criteria.
/**
* Creates a match on lambda field using the specified value.
*
* @param lambda
* @return match criterion
*/
public static Criterion matchLambda(Short lambda) {
return new LambdaCriterion(lambda, Type.OCH_SIGID);
}
/**
* Creates a match on lambda field using the specified value.
*
* @param lambda
* @return match criterion
*/
public static Criterion matchOpticalSignalType(Byte lambda) {
return new OpticalSignalTypeCriterion(lambda, Type.OCH_SIGTYPE);
}
/**
* Implementations of criteria.
*/
public static final class PortCriterion implements Criterion {
private final PortNumber port;
......@@ -523,4 +543,93 @@ public final class Criteria {
return false;
}
}
public static final class LambdaCriterion implements Criterion {
private final short lambda;
private final Type type;
public LambdaCriterion(short lambda, Type type) {
this.lambda = lambda;
this.type = type;
}
@Override
public Type type() {
return this.type;
}
public Short lambda() {
return this.lambda;
}
@Override
public String toString() {
return toStringHelper(type().toString())
.add("lambda", lambda).toString();
}
@Override
public int hashCode() {
return Objects.hash(lambda, type);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof LambdaCriterion) {
LambdaCriterion that = (LambdaCriterion) obj;
return Objects.equals(lambda, that.lambda) &&
Objects.equals(type, that.type);
}
return false;
}
}
public static final class OpticalSignalTypeCriterion implements Criterion {
private final byte signalType;
private final Type type;
public OpticalSignalTypeCriterion(byte signalType, Type type) {
this.signalType = signalType;
this.type = type;
}
@Override
public Type type() {
return this.type;
}
public Byte signalType() {
return this.signalType;
}
@Override
public String toString() {
return toStringHelper(type().toString())
.add("signalType", signalType).toString();
}
@Override
public int hashCode() {
return Objects.hash(signalType, type);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof OpticalSignalTypeCriterion) {
OpticalSignalTypeCriterion that = (OpticalSignalTypeCriterion) obj;
return Objects.equals(signalType, that.signalType) &&
Objects.equals(type, that.type);
}
return false;
}
}
}
......
......@@ -108,7 +108,11 @@ public interface Criterion {
/** Logical Port Metadata. */
TUNNEL_ID,
/** IPv6 Extension Header pseudo-field. */
IPV6_EXTHDR
IPV6_EXTHDR,
/** Optical channel signal ID (lambda). */
OCH_SIGID,
/** Optical channel signal type (fixed or flexible). */
OCH_SIGTYPE
}
/**
......
......@@ -43,6 +43,11 @@ public interface Instruction {
GROUP,
/**
* Signifies that the traffic should be modified in L0 way.
*/
L0MODIFICATION,
/**
* Signifies that the traffic should be modified in L2 way.
*/
L2MODIFICATION,
......
......@@ -24,6 +24,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Objects;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.L0SubType;
import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.L2SubType;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.L3SubType;
......@@ -62,6 +64,16 @@ public final class Instructions {
}
/**
* Creates a l0 modification.
* @param lambda the lambda to modify to.
* @return a l0 modification
*/
public static L0ModificationInstruction modL0Lambda(short lambda) {
checkNotNull(lambda, "L0 lambda cannot be null");
return new ModLambdaInstruction(L0SubType.LAMBDA, lambda);
}
/**
* Creates a l2 src modification.
* @param addr the mac address to modify to.
* @return a l2 modification
......
package org.onlab.onos.net.flow.instructions;
import static com.google.common.base.MoreObjects.toStringHelper;
import java.util.Objects;
public abstract class L0ModificationInstruction implements Instruction {
/**
* Represents the type of traffic treatment.
*/
public enum L0SubType {
/**
* Lambda modification.
*/
LAMBDA
//TODO: remaining types
}
public abstract L0SubType subtype();
@Override
public Type type() {
return Type.L0MODIFICATION;
}
/**
* Represents a L0 lambda modification instruction.
*/
public static final class ModLambdaInstruction extends L0ModificationInstruction {
private final L0SubType subtype;
private final short lambda;
public ModLambdaInstruction(L0SubType subType, short lambda) {
this.subtype = subType;
this.lambda = lambda;
}
@Override
public L0SubType subtype() {
return this.subtype;
}
public short lambda() {
return this.lambda;
}
@Override
public String toString() {
return toStringHelper(subtype().toString())
.add("lambda", lambda).toString();
}
@Override
public int hashCode() {
return Objects.hash(lambda, type(), subtype);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof ModLambdaInstruction) {
ModLambdaInstruction that = (ModLambdaInstruction) obj;
return Objects.equals(lambda, that.lambda) &&
Objects.equals(this.type(), that.type()) &&
Objects.equals(subtype, that.subtype);
}
return false;
}
}
}
package org.onlab.onos.net.intent;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.ConnectPoint;
/**
* An optical layer Intent for a connectivity from one Transponder port to another
* Transponder port. No trafficSelector as well as trafficTreament are needed.
*
*/
public class OpticalConnectivityIntent extends Intent {
protected ConnectPoint src;
protected ConnectPoint dst;
/**
* Constructor.
*
* @param id ID for this new Intent object.
* @param src The source transponder port.
* @param dst The destination transponder port.
*/
public OpticalConnectivityIntent(ApplicationId appId, ConnectPoint src, ConnectPoint dst) {
super(id(OpticalConnectivityIntent.class, src, dst),
appId, null);
this.src = src;
this.dst = dst;
}
/**
* Constructor for serializer.
*/
protected OpticalConnectivityIntent() {
super();
this.src = null;
this.dst = null;
}
/**
* Gets source transponder port.
*
* @return The source transponder port.
*/
public ConnectPoint getSrcConnectPoint() {
return src;
}
/**
* Gets destination transponder port.
*
* @return The source transponder port.
*/
public ConnectPoint getDst() {
return dst;
}
}
package org.onlab.onos.net.intent;
import java.util.Collection;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.NetworkResource;
import org.onlab.onos.net.Path;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
public class OpticalPathIntent extends Intent {
private final ConnectPoint src;
private final ConnectPoint dst;
private final Path path;
public OpticalPathIntent(ApplicationId appId,
ConnectPoint src,
ConnectPoint dst,
Path path) {
super(id(OpticalPathIntent.class, src, dst),
appId,
ImmutableSet.<NetworkResource>copyOf(path.links()));
this.src = src;
this.dst = dst;
this.path = path;
}
protected OpticalPathIntent() {
this.src = null;
this.dst = null;
this.path = null;
}
public ConnectPoint src() {
return src;
}
public ConnectPoint dst() {
return dst;
}
public Path path() {
return path;
}
@Override
public boolean isInstallable() {
return true;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("id", id())
.add("ingressPort", src)
.add("egressPort", dst)
.add("path", path)
.toString();
}
public Collection<Link> requiredLinks() {
return path.links();
}
}
......@@ -3,6 +3,21 @@ package org.onlab.onos.net.resource;
/**
* Representation of allocated bandwidth resource.
*/
public interface BandwidthResourceAllocation extends BandwidthResourceRequest {
public class BandwidthResourceAllocation extends BandwidthResourceRequest
implements ResourceAllocation {
@Override
public ResourceType type() {
return ResourceType.BANDWIDTH;
}
/**
* Creates a new {@link BandwidthResourceAllocation} with {@link Bandwidth}
* object.
*
* @param bandwidth allocated bandwidth
*/
public BandwidthResourceAllocation(Bandwidth bandwidth) {
super(bandwidth);
}
}
......
......@@ -3,11 +3,39 @@ package org.onlab.onos.net.resource;
/**
* Representation of a request for bandwidth resource.
*/
public interface BandwidthResourceRequest {
public class BandwidthResourceRequest implements ResourceRequest {
private final Bandwidth bandwidth;
/**
* Creates a new {@link BandwidthResourceRequest} with {@link Bandwidth}
* object.
*
* @param bandwidth {@link Bandwidth} object to be requested
*/
public BandwidthResourceRequest(Bandwidth bandwidth) {
this.bandwidth = bandwidth;
}
/**
* Creates a new {@link BandwidthResourceRequest} with bandwidth value.
*
* @param bandwidth bandwidth value to be requested
*/
public BandwidthResourceRequest(double bandwidth) {
this.bandwidth = Bandwidth.valueOf(bandwidth);
}
/**
* Returns the bandwidth resource.
*
* @return the bandwidth resource
*/
Bandwidth bandwidth();
public Bandwidth bandwidth() {
return bandwidth;
}
@Override
public ResourceType type() {
return ResourceType.BANDWIDTH;
}
}
......
package org.onlab.onos.net.resource;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.IntentId;
import com.google.common.collect.ImmutableSet;
/**
* Implementation of {@link LinkResourceRequest}.
*/
public final class DefaultLinkResourceRequest implements LinkResourceRequest {
private final IntentId intentId;
private final Collection<Link> links;
private final Set<ResourceRequest> resources;
/**
* Creates a new link resource request with the given ID, links, and
* resource requests.
*
* @param intentId intent ID related to this request
* @param links a set of links for the request
* @param resources a set of resources to be requested
*/
private DefaultLinkResourceRequest(IntentId intentId,
Collection<Link> links,
Set<ResourceRequest> resources) {
this.intentId = intentId;
this.links = ImmutableSet.copyOf(links);
this.resources = ImmutableSet.copyOf(resources);
}
@Override
public ResourceType type() {
return null;
}
@Override
public IntentId intendId() {
return intentId;
}
@Override
public Collection<Link> links() {
return links;
}
@Override
public Set<ResourceRequest> resources() {
return resources;
}
/**
* Returns builder of link resource request.
*
* @param intentId intent ID related to this request
* @param links a set of links for the request
* @return builder of link resource request
*/
public static LinkResourceRequest.Builder builder(
IntentId intentId, Collection<Link> links) {
return new Builder(intentId, links);
}
/**
* Builder of link resource request.
*/
public static final class Builder implements LinkResourceRequest.Builder {
private IntentId intentId;
private Collection<Link> links;
private Set<ResourceRequest> resources;
/**
* Creates a new link resource request.
*
* @param intentId intent ID related to this request
* @param links a set of links for the request
*/
private Builder(IntentId intentId, Collection<Link> links) {
this.intentId = intentId;
this.links = links;
this.resources = new HashSet<>();
}
/**
* Adds lambda request.
*
* @return self
*/
@Override
public Builder addLambdaRequest() {
resources.add(new LambdaResourceRequest());
return this;
}
/**
* Adds bandwidth request with bandwidth value.
*
* @param bandwidth bandwidth value to be requested
* @return self
*/
@Override
public Builder addBandwidthRequest(double bandwidth) {
resources.add(new BandwidthResourceRequest(bandwidth));
return this;
}
/**
* Returns link resource request.
*
* @return link resource request
*/
@Override
public LinkResourceRequest build() {
return new DefaultLinkResourceRequest(intentId, links, resources);
}
}
}
......@@ -3,11 +3,31 @@ package org.onlab.onos.net.resource;
/**
* Representation of allocated lambda resource.
*/
public interface LambdaResourceAllocation extends LambdaResourceRequest {
public class LambdaResourceAllocation extends LambdaResourceRequest
implements ResourceAllocation {
private final Lambda lambda;
@Override
public ResourceType type() {
return ResourceType.LAMBDA;
}
/**
* Creates a new {@link LambdaResourceAllocation} with {@link Lambda}
* object.
*
* @param lambda allocated lambda
*/
public LambdaResourceAllocation(Lambda lambda) {
this.lambda = lambda;
}
/**
* Returns the lambda resource.
*
* @return the lambda resource
*/
Lambda lambda();
public Lambda lambda() {
return lambda;
}
}
......
......@@ -3,6 +3,11 @@ package org.onlab.onos.net.resource;
/**
* Representation of a request for lambda resource.
*/
public interface LambdaResourceRequest {
public class LambdaResourceRequest implements ResourceRequest {
@Override
public ResourceType type() {
return ResourceType.LAMBDA;
}
}
......
package org.onlab.onos.net.resource;
import java.util.Set;
import org.onlab.onos.net.Link;
/**
......@@ -12,5 +14,5 @@ public interface LinkResourceAllocations extends LinkResourceRequest {
* @param link the target link
* @return allocated resource for the link
*/
ResourceAllocation getResourceAllocation(Link link);
Set<ResourceAllocation> getResourceAllocation(Link link);
}
......
......@@ -31,4 +31,31 @@ public interface LinkResourceRequest extends ResourceRequest {
* @return the set of resource requests
*/
Set<ResourceRequest> resources();
/**
* Builder of link resource request.
*/
interface Builder {
/**
* Adds lambda request.
*
* @return self
*/
public Builder addLambdaRequest();
/**
* Adds bandwidth request with bandwidth value.
*
* @param bandwidth bandwidth value to be requested
* @return self
*/
public Builder addBandwidthRequest(double bandwidth);
/**
* Returns link resource request.
*
* @return link resource request
*/
public LinkResourceRequest build();
}
}
......
......@@ -31,6 +31,14 @@ public interface LinkResourceService {
Iterable<LinkResourceAllocations> getAllocations();
/**
* Returns the resources allocated for an Intent.
*
* @param intentId the target Intent's id
* @return allocated resources for Intent
*/
LinkResourceAllocations getAllocations(IntentId intentId);
/**
* Returns all allocated resources to given link.
*
* @param link a target link
......
......@@ -4,5 +4,11 @@ package org.onlab.onos.net.resource;
* Abstraction of resource request.
*/
public interface ResourceRequest {
/**
* Returns the resource type.
*
* @return the resource type
*/
ResourceType type();
}
......
package org.onlab.onos.net.resource;
public enum ResourceType {
LAMBDA,
BANDWIDTH,
}
package org.onlab.onos.net.intent.impl;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
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.onlab.onos.CoreService;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentCompiler;
import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.OpticalConnectivityIntent;
import org.onlab.onos.net.intent.OpticalPathIntent;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.topology.LinkWeight;
import org.onlab.onos.net.topology.PathService;
import org.onlab.onos.net.topology.Topology;
import org.onlab.onos.net.topology.TopologyEdge;
import org.onlab.onos.net.topology.TopologyService;
import org.slf4j.Logger;
/**
* Optical compiler for OpticalConnectivityIntent.
* It firstly computes K-shortest paths in the optical-layer, then choose the optimal one to assign a wavelength.
* Finally, it generates one or more opticalPathintent(s) with opticalMatchs and opticalActions.
*/
@Component(immediate = true)
public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> {
private final Logger log = getLogger(getClass());
private static final ProviderId PID = new ProviderId("core", "org.onlab.onos.core", true);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentManager;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PathService pathService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Activate
public void activate() {
intentManager.registerCompiler(OpticalConnectivityIntent.class, this);
}
@Deactivate
public void deactivate() {
intentManager.unregisterCompiler(OpticalConnectivityIntent.class);
}
@Override
public List<Intent> compile(OpticalConnectivityIntent intent) {
// TODO: compute multiple paths using the K-shortest path algorithm
List<Intent> retList = new ArrayList<>();
Path path = calculatePath(intent.getSrcConnectPoint(), intent.getDst());
if (path == null) {
return retList;
} else {
log.info("the computed lightpath is : {}.", path.toString());
}
List<Link> links = new ArrayList<>();
// links.add(DefaultEdgeLink.createEdgeLink(intent.getSrcConnectPoint(), true));
links.addAll(path.links());
//links.add(DefaultEdgeLink.createEdgeLink(intent.getDst(), false));
// create a new opticalPathIntent
Intent newIntent = new OpticalPathIntent(intent.appId(),
intent.getSrcConnectPoint(),
intent.getDst(),
path);
retList.add(newIntent);
return retList;
}
private Path calculatePath(ConnectPoint start, ConnectPoint end) {
// TODO: support user policies
Topology topology = topologyService.currentTopology();
LinkWeight weight = new LinkWeight() {
@Override
public double weight(TopologyEdge edge) {
boolean isOptical = false;
Link.Type lt = edge.link().type();
//String t = edge.link().annotations().value("linkType");
if (lt == Link.Type.OPTICAL) {
isOptical = true;
}
if (isOptical) {
return 1; // optical links
} else {
return 10000; // packet links
}
}
};
Set<Path> paths = topologyService.getPaths(topology,
start.deviceId(),
end.deviceId(),
weight);
Iterator<Path> itr = paths.iterator();
while (itr.hasNext()) {
Path path = itr.next();
if (path.cost() >= 10000) {
itr.remove();
}
}
if (paths.isEmpty()) {
log.info("No optical path found from " + start + " to " + end);
return null;
} else {
return paths.iterator().next();
}
}
}
package org.onlab.onos.net.intent.impl;
import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.List;
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.onlab.onos.ApplicationId;
import org.onlab.onos.CoreService;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.flow.DefaultFlowRule;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.DefaultTrafficTreatment;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.FlowRuleBatchEntry;
import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
import org.onlab.onos.net.flow.FlowRuleService;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.IntentInstaller;
import org.onlab.onos.net.intent.OpticalPathIntent;
import org.onlab.onos.net.resource.DefaultLinkResourceRequest;
import org.onlab.onos.net.resource.Lambda;
import org.onlab.onos.net.resource.LambdaResourceAllocation;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceType;
import org.onlab.onos.net.topology.TopologyService;
import org.slf4j.Logger;
import com.google.common.collect.Lists;
/**
* OpticaliIntentInstaller for optical path intents.
* It essentially generates optical FlowRules and
* call the flowRule service to execute them.
*/
@Component(immediate = true)
public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIntent> {
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentManager;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleService flowRuleService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceService;
private ApplicationId appId;
//final short WAVELENGTH = 80;
@Activate
public void activate() {
appId = coreService.registerApplication("org.onlab.onos.net.intent");
intentManager.registerInstaller(OpticalPathIntent.class, this);
}
@Deactivate
public void deactivate() {
intentManager.unregisterInstaller(OpticalPathIntent.class);
}
@Override
public List<FlowRuleBatchOperation> install(OpticalPathIntent intent) {
LinkResourceAllocations allocations = assignWavelength(intent);
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
selectorBuilder.matchInport(intent.src().port());
List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
ConnectPoint prev = intent.src();
//TODO throw exception if the lambda was not assigned successfully
for (Link link : intent.path().links()) {
Lambda la = null;
for (ResourceAllocation allocation : allocations.getResourceAllocation(link)) {
if (allocation.type() == ResourceType.LAMBDA) {
la = ((LambdaResourceAllocation) allocation).lambda();
break;
}
}
if (la == null) {
log.info("Lambda was not assigned successfully");
return null;
}
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
treatmentBuilder.setOutput(link.src().port());
treatmentBuilder.setLambda((short) la.toInt());
FlowRule rule = new DefaultFlowRule(prev.deviceId(),
selectorBuilder.build(),
treatmentBuilder.build(),
100,
appId,
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
prev = link.dst();
selectorBuilder.matchInport(link.dst().port());
selectorBuilder.matchLambda((short) la.toInt());
}
// build the last T port rule
TrafficTreatment treatmentLast = builder()
.setOutput(intent.dst().port()).build();
FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(),
selectorBuilder.build(),
treatmentLast,
100,
appId,
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
}
private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
intent.path().links())
.addLambdaRequest();
LinkResourceAllocations retLambda = resourceService.requestResources(request.build());
return retLambda;
}
/*private Lambda assignWavelength(List<Link> links) {
// TODO More wavelength assignment algorithm
int wavenum = 0;
Iterator<Link> itrlink = links.iterator();
for (int i = 1; i <= WAVELENGTH; i++) {
wavenum = i;
boolean found = true;
while (itrlink.hasNext()) {
Link link = itrlink.next();
if (isWavelengthUsed(link, i)) {
found = false;
break;
}
}
// First-Fit wavelength assignment algorithm
if (found) {
break;
}
}
if (wavenum == 0) {
return null;
}
Lambda wave = Lambda.valueOf(wavenum);
return wave;
}
private boolean isWavelengthUsed(Link link, int i) {
Iterable<LinkResourceAllocations> wave = resourceService.getAllocations(link);
for (LinkResourceAllocations ir : wave) {
//if ir.resources().contains(i) {
//}
}
return false;
}*/
@Override
public List<FlowRuleBatchOperation> uninstall(OpticalPathIntent intent) {
LinkResourceAllocations allocations = resourceService.getAllocations(intent.id());
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
selectorBuilder.matchInport(intent.src().port());
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
ConnectPoint prev = intent.src();
//TODO throw exception if the lambda was not retrieved successfully
for (Link link : intent.path().links()) {
Lambda la = null;
for (ResourceAllocation allocation : allocations.getResourceAllocation(link)) {
if (allocation.type() == ResourceType.LAMBDA) {
la = ((LambdaResourceAllocation) allocation).lambda();
break;
}
}
if (la == null) {
log.info("Lambda was not retrieved successfully");
return null;
}
treatmentBuilder.setOutput(link.src().port());
treatmentBuilder.setLambda((short) la.toInt());
FlowRule rule = new DefaultFlowRule(prev.deviceId(),
selectorBuilder.build(),
treatmentBuilder.build(),
100,
appId,
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule));
prev = link.dst();
selectorBuilder.matchInport(link.dst().port());
selectorBuilder.matchLambda((short) la.toInt());
}
// build the last T port rule
TrafficTreatment treatmentLast = builder()
.setOutput(intent.dst().port()).build();
FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(),
selectorBuilder.build(),
treatmentLast,
100,
appId,
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule));
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
}
}
package org.onlab.onos.net.resource.impl;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceRequest;
import org.onlab.onos.net.resource.ResourceType;
/**
* Implementation of {@link LinkResourceAllocations}.
*/
public class DefaultLinkResourceAllocations implements LinkResourceAllocations {
private final LinkResourceRequest request;
private final Map<Link, Set<ResourceAllocation>> allocations;
/**
* Creates a new link resource allocations.
*
* @param request requested resources
* @param allocations allocated resources
*/
protected DefaultLinkResourceAllocations(LinkResourceRequest request,
Map<Link, Set<ResourceAllocation>> allocations) {
this.request = request;
this.allocations = allocations;
}
@Override
public IntentId intendId() {
return request.intendId();
}
@Override
public Collection<Link> links() {
return request.links();
}
@Override
public Set<ResourceRequest> resources() {
return request.resources();
}
@Override
public ResourceType type() {
return null;
}
@Override
public Set<ResourceAllocation> getResourceAllocation(Link link) {
Set<ResourceAllocation> result = allocations.get(link);
if (result == null) {
result = Collections.emptySet();
}
return result;
}
}
package org.onlab.onos.net.resource.impl;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
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.Service;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.resource.BandwidthResourceAllocation;
import org.onlab.onos.net.resource.BandwidthResourceRequest;
import org.onlab.onos.net.resource.Lambda;
import org.onlab.onos.net.resource.LambdaResourceAllocation;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceRequest;
import org.slf4j.Logger;
import com.google.common.collect.Sets;
/**
* Provides basic implementation of link resources allocation.
*/
@Component(immediate = true)
@Service
public class LinkResourceManager implements LinkResourceService {
private final Logger log = getLogger(getClass());
@Activate
public void activate() {
log.info("Started");
}
@Deactivate
public void deactivate() {
log.info("Stopped");
}
@Override
public LinkResourceAllocations requestResources(LinkResourceRequest req) {
// TODO implement it using a resource data store.
ResourceAllocation alloc = null;
for (ResourceRequest r: req.resources()) {
switch (r.type()) {
case BANDWIDTH:
log.info("requestResources() always returns requested bandwidth");
BandwidthResourceRequest br = (BandwidthResourceRequest) r;
alloc = new BandwidthResourceAllocation(br.bandwidth());
break;
case LAMBDA:
log.info("requestResources() always returns lambda 7");
alloc = new LambdaResourceAllocation(Lambda.valueOf(7));
break;
default:
break;
}
}
Map<Link, Set<ResourceAllocation>> allocations = new HashMap<>();
for (Link link: req.links()) {
allocations.put(link, Sets.newHashSet(alloc));
}
return new DefaultLinkResourceAllocations(req, allocations);
}
@Override
public void releaseResources(LinkResourceAllocations allocations) {
// TODO Auto-generated method stub
}
@Override
public Iterable<LinkResourceAllocations> getAllocations() {
// TODO Auto-generated method stub
return null;
}
@Override
public LinkResourceAllocations getAllocations(IntentId intentId) {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<LinkResourceAllocations> getAllocations(Link link) {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<IntentId> getIntents(Link link) {
// TODO Auto-generated method stub
return null;
}
@Override
public ResourceRequest getAvailableResources(Link link) {
// TODO Auto-generated method stub
return null;
}
}
/**
* Services for reserving network resources, e.g.&nbsp;bandwidth, lambdas.
*/
package org.onlab.onos.net.resource.impl;
......@@ -30,7 +30,7 @@
<groupId>org.projectfloodlight</groupId>
<artifactId>openflowj</artifactId>
<!-- FIXME once experimenter gets merged to upstream -->
<version>0.3.8-optical_experimenter3</version>
<version>0.3.8-optical_experimenter4</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
......
package org.onlab.onos.openflow.controller;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicBoolean;
import org.onlab.packet.Ethernet;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPacketOut;
......@@ -9,9 +13,6 @@ import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFPort;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicBoolean;
public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext {
private final AtomicBoolean free = new AtomicBoolean(true);
......
......@@ -23,6 +23,8 @@ import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
import org.projectfloodlight.openflow.protocol.OFInstructionType;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.action.OFActionCircuit;
import org.projectfloodlight.openflow.protocol.action.OFActionExperimenter;
import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst;
import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc;
......@@ -34,6 +36,7 @@ import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigidBasic;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.projectfloodlight.openflow.types.Masked;
import org.slf4j.Logger;
......@@ -166,6 +169,15 @@ public class FlowEntryBuilder {
builder.setIpSrc(IpPrefix.valueOf(si.getInt()));
}
break;
case EXPERIMENTER:
OFActionExperimenter exp = (OFActionExperimenter) act;
if (exp.getExperimenter() == 0x80005A06) {
OFActionCircuit ct = (OFActionCircuit) exp;
builder.setLambda(((OFOxmOchSigidBasic) ct.getField()).getValue().getChannelNumber());
} else {
log.warn("Unsupported OFActionExperimenter {}", exp.getExperimenter());
}
break;
case SET_TP_DST:
case SET_TP_SRC:
case POP_MPLS:
......@@ -188,7 +200,7 @@ public class FlowEntryBuilder {
case DEC_MPLS_TTL:
case DEC_NW_TTL:
case ENQUEUE:
case EXPERIMENTER:
case GROUP:
default:
log.warn("Action type {} not yet implemented.", act.getType());
......@@ -268,6 +280,10 @@ public class FlowEntryBuilder {
case TCP_SRC:
builder.matchTcpSrc((short) match.get(MatchField.TCP_SRC).getPort());
break;
case OCH_SIGID:
builder.matchLambda(match.get(MatchField.OCH_SIGID).getChannelNumber());
break;
case OCH_SIGTYPE_BASIC:
case ARP_OP:
case ARP_SHA:
case ARP_SPA:
......
......@@ -14,6 +14,7 @@ import org.onlab.onos.net.flow.criteria.Criteria.EthCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.EthTypeCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.IPProtocolCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.LambdaCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.PortCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.TcpPortCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion;
......@@ -21,6 +22,8 @@ import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion;
import org.onlab.onos.net.flow.criteria.Criterion;
import org.onlab.onos.net.flow.instructions.Instruction;
import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
import org.onlab.onos.net.flow.instructions.L0ModificationInstruction;
import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
......@@ -35,6 +38,7 @@ import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.types.CircuitSignalID;
import org.projectfloodlight.openflow.types.EthType;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.projectfloodlight.openflow.types.IpProtocol;
......@@ -137,6 +141,9 @@ public class FlowModBuilder {
case DROP:
log.warn("Saw drop action; assigning drop action");
return new LinkedList<>();
case L0MODIFICATION:
acts.add(buildL0Modification(i));
break;
case L2MODIFICATION:
acts.add(buildL2Modification(i));
break;
......@@ -157,6 +164,20 @@ public class FlowModBuilder {
return acts;
}
private OFAction buildL0Modification(Instruction i) {
L0ModificationInstruction l0m = (L0ModificationInstruction) i;
switch (l0m.subtype()) {
case LAMBDA:
ModLambdaInstruction ml = (ModLambdaInstruction) i;
return factory.actions().circuit(factory.oxms().ochSigidBasic(
new CircuitSignalID((byte) 1, (byte) 2, ml.lambda(), (short) 1)));
default:
log.warn("Unimplemented action type {}.", l0m.subtype());
break;
}
return null;
}
private OFAction buildL3Modification(Instruction i) {
L3ModificationInstruction l3m = (L3ModificationInstruction) i;
ModIPInstruction ip;
......@@ -261,6 +282,11 @@ public class FlowModBuilder {
tp = (TcpPortCriterion) c;
mBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(tp.tcpPort()));
break;
case OCH_SIGID:
LambdaCriterion lc = (LambdaCriterion) c;
mBuilder.setExact(MatchField.OCH_SIGID,
new CircuitSignalID((byte) 1, (byte) 2, lc.lambda(), (short) 1));
break;
case ARP_OP:
case ARP_SHA:
case ARP_SPA:
......