Ray Milkey

ONOS-22 - Add Constraints to CLI Commands

Added optional --lambda and --bandwidth operations to command
line for host to host, point to point, and multi point to
single point intents

Fixed intent compilers to add constraints to the PathIntents they
create

Change-Id: I25510d401118feba493f51ecddc72d770d8ae3e3
......@@ -15,14 +15,16 @@
*/
package org.onlab.onos.cli.net;
import java.util.List;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.net.HostId;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.DefaultTrafficTreatment;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.intent.Constraint;
import org.onlab.onos.net.intent.HostToHostIntent;
import org.onlab.onos.net.intent.IntentService;
......@@ -31,7 +33,7 @@ import org.onlab.onos.net.intent.IntentService;
*/
@Command(scope = "onos", name = "add-host-intent",
description = "Installs host-to-host connectivity intent")
public class AddHostToHostIntentCommand extends AbstractShellCommand {
public class AddHostToHostIntentCommand extends ConnectivityIntentCommand {
@Argument(index = 0, name = "one", description = "One host ID",
required = true, multiValued = false)
......@@ -50,9 +52,11 @@ public class AddHostToHostIntentCommand extends AbstractShellCommand {
TrafficSelector selector = DefaultTrafficSelector.builder().build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
List<Constraint> constraints = buildConstraints();
HostToHostIntent intent = new HostToHostIntent(appId(), oneId, twoId,
selector, treatment);
selector, treatment,
constraints);
service.submit(intent);
}
......
......@@ -23,11 +23,13 @@ import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.flow.DefaultTrafficTreatment;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.intent.Constraint;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.onlab.onos.net.DeviceId.deviceId;
......@@ -69,9 +71,11 @@ public class AddMultiPointToSinglePointIntentCommand extends ConnectivityIntentC
TrafficSelector selector = buildTrafficSelector();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
List<Constraint> constraints = buildConstraints();
Intent intent = new MultiPointToSinglePointIntent(appId(), selector, treatment,
ingressPoints, egress);
ingressPoints, egress,
constraints);
service.submit(intent);
}
......
......@@ -15,6 +15,8 @@
*/
package org.onlab.onos.cli.net;
import java.util.List;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.net.ConnectPoint;
......@@ -22,6 +24,7 @@ import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.intent.Constraint;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.PointToPointIntent;
......@@ -63,8 +66,10 @@ public class AddPointToPointIntentCommand extends ConnectivityIntentCommand {
TrafficSelector selector = buildTrafficSelector();
TrafficTreatment treatment = builder().build();
List<Constraint> constraints = buildConstraints();
Intent intent = new PointToPointIntent(appId(), selector, treatment,
ingress, egress);
ingress, egress, constraints);
service.submit(intent);
}
......
......@@ -15,14 +15,21 @@
*/
package org.onlab.onos.cli.net;
import java.util.LinkedList;
import java.util.List;
import org.apache.karaf.shell.commands.Option;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.intent.Constraint;
import org.onlab.onos.net.intent.constraint.BandwidthConstraint;
import org.onlab.onos.net.intent.constraint.LambdaConstraint;
import org.onlab.onos.net.resource.Bandwidth;
import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
import com.google.common.base.Strings;
import static com.google.common.base.Strings.isNullOrEmpty;
/**
* Base class for command line operations for connectivity based intents.
......@@ -41,6 +48,14 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
required = false, multiValued = false)
private String ethTypeString = "";
@Option(name = "-b", aliases = "--bandwidth", description = "Bandwidth",
required = false, multiValued = false)
private String bandwidthString = "";
@Option(name = "-l", aliases = "--lambda", description = "Lambda",
required = false, multiValued = false)
private boolean lambda = false;
/**
* Constructs a traffic selector based on the command line arguments
* presented to the command.
......@@ -50,21 +65,43 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
Short ethType = Ethernet.TYPE_IPV4;
if (!Strings.isNullOrEmpty(ethTypeString)) {
if (!isNullOrEmpty(ethTypeString)) {
EthType ethTypeParameter = EthType.valueOf(ethTypeString);
ethType = ethTypeParameter.value();
}
selectorBuilder.matchEthType(ethType);
if (!Strings.isNullOrEmpty(srcMacString)) {
if (!isNullOrEmpty(srcMacString)) {
selectorBuilder.matchEthSrc(MacAddress.valueOf(srcMacString));
}
if (!Strings.isNullOrEmpty(dstMacString)) {
if (!isNullOrEmpty(dstMacString)) {
selectorBuilder.matchEthDst(MacAddress.valueOf(dstMacString));
}
return selectorBuilder.build();
}
/**
* Builds the constraint list for this command based on the command line
* parameters.
*
* @return List of constraint objects describing the constraints requested
*/
protected List<Constraint> buildConstraints() {
final List<Constraint> constraints = new LinkedList<>();
// Check for a bandwidth specification
if (!isNullOrEmpty(bandwidthString)) {
final double bandwidthValue = Double.parseDouble(bandwidthString);
constraints.add(new BandwidthConstraint(Bandwidth.valueOf(bandwidthValue)));
}
// Check for a lambda specification
if (lambda) {
constraints.add(new LambdaConstraint(null));
}
return constraints;
}
}
......
......@@ -105,6 +105,7 @@ public final class HostToHostIntent extends ConnectivityIntent {
.add("appId", appId())
.add("selector", selector())
.add("treatment", treatment())
.add("constraints", constraints())
.add("one", one)
.add("two", two)
.toString();
......
......@@ -22,6 +22,7 @@ import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
......@@ -65,6 +66,38 @@ public final class MultiPointToSinglePointIntent extends ConnectivityIntent {
}
/**
* Creates a new multi-to-single point connectivity intent for the specified
* traffic selector and treatment.
*
* @param appId application identifier
* @param selector traffic selector
* @param treatment treatment
* @param ingressPoints set of ports from which ingress traffic originates
* @param egressPoint port to which traffic will egress
* @param constraints constraints to apply to the intent
* @throws NullPointerException if {@code ingressPoints} or
* {@code egressPoint} is null.
* @throws IllegalArgumentException if the size of {@code ingressPoints} is
* not more than 1
*/
public MultiPointToSinglePointIntent(ApplicationId appId,
TrafficSelector selector,
TrafficTreatment treatment,
Set<ConnectPoint> ingressPoints,
ConnectPoint egressPoint,
List<Constraint> constraints) {
super(id(MultiPointToSinglePointIntent.class, selector, treatment,
ingressPoints, egressPoint), appId, null, selector, treatment,
constraints);
checkNotNull(ingressPoints);
checkArgument(!ingressPoints.isEmpty(), "Ingress point set cannot be empty");
this.ingressPoints = Sets.newHashSet(ingressPoints);
this.egressPoint = checkNotNull(egressPoint);
}
/**
* Constructor for serializer.
*/
protected MultiPointToSinglePointIntent() {
......@@ -101,6 +134,7 @@ public final class MultiPointToSinglePointIntent extends ConnectivityIntent {
.add("treatment", treatment())
.add("ingress", ingressPoints())
.add("egress", egressPoint())
.add("constraints", constraints())
.toString();
}
}
......
......@@ -15,6 +15,8 @@
*/
package org.onlab.onos.net.intent;
import java.util.List;
import com.google.common.base.MoreObjects;
import org.onlab.onos.core.ApplicationId;
import org.onlab.onos.net.Path;
......@@ -46,6 +48,24 @@ public class PathIntent extends ConnectivityIntent {
}
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports and using the specified explicit path.
*
* @param appId application identifier
* @param selector traffic selector
* @param treatment treatment
* @param path traversed links
* @param constraints optional list of constraints
* @throws NullPointerException {@code path} is null
*/
public PathIntent(ApplicationId appId, TrafficSelector selector,
TrafficTreatment treatment, Path path, List<Constraint> constraints) {
super(id(PathIntent.class, selector, treatment, path, constraints), appId,
resources(path.links()), selector, treatment, constraints);
this.path = path;
}
/**
* Constructor for serializer.
*/
protected PathIntent() {
......@@ -75,6 +95,7 @@ public class PathIntent extends ConnectivityIntent {
.add("appId", appId())
.add("selector", selector())
.add("treatment", treatment())
.add("constraints", constraints())
.add("path", path)
.toString();
}
......
......@@ -118,13 +118,14 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent>
@Override
public double weight(TopologyEdge edge) {
if (constraints == null) {
if (constraints == null || !constraints.iterator().hasNext()) {
return 1.0;
}
// iterate over all constraints in order and return the weight of
// the first one with fast fail over the first failure
Iterator<Constraint> it = constraints.iterator();
double cost = it.next().cost(edge.link(), resourceService);
while (it.hasNext() && cost > 0) {
if (it.next().cost(edge.link(), resourceService) < 0) {
......@@ -132,6 +133,7 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent>
}
}
return cost;
}
}
......
......@@ -70,7 +70,8 @@ public class HostToHostIntentCompiler
HostToHostIntent intent) {
TrafficSelector selector = builder(intent.selector())
.matchEthSrc(src.mac()).matchEthDst(dst.mac()).build();
return new PathIntent(intent.appId(), selector, intent.treatment(), path);
return new PathIntent(intent.appId(), selector, intent.treatment(),
path, intent.constraints());
}
}
......
......@@ -77,7 +77,8 @@ public class PointToPointIntentCompiler
private Intent createPathIntent(Path path,
PointToPointIntent intent) {
return new PathIntent(intent.appId(),
intent.selector(), intent.treatment(), path);
intent.selector(), intent.treatment(), path,
intent.constraints());
}
}
......