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 @@ ...@@ -15,14 +15,16 @@
15 */ 15 */
16 package org.onlab.onos.cli.net; 16 package org.onlab.onos.cli.net;
17 17
18 +import java.util.List;
19 +
18 import org.apache.karaf.shell.commands.Argument; 20 import org.apache.karaf.shell.commands.Argument;
19 import org.apache.karaf.shell.commands.Command; 21 import org.apache.karaf.shell.commands.Command;
20 -import org.onlab.onos.cli.AbstractShellCommand;
21 import org.onlab.onos.net.HostId; 22 import org.onlab.onos.net.HostId;
22 import org.onlab.onos.net.flow.DefaultTrafficSelector; 23 import org.onlab.onos.net.flow.DefaultTrafficSelector;
23 import org.onlab.onos.net.flow.DefaultTrafficTreatment; 24 import org.onlab.onos.net.flow.DefaultTrafficTreatment;
24 import org.onlab.onos.net.flow.TrafficSelector; 25 import org.onlab.onos.net.flow.TrafficSelector;
25 import org.onlab.onos.net.flow.TrafficTreatment; 26 import org.onlab.onos.net.flow.TrafficTreatment;
27 +import org.onlab.onos.net.intent.Constraint;
26 import org.onlab.onos.net.intent.HostToHostIntent; 28 import org.onlab.onos.net.intent.HostToHostIntent;
27 import org.onlab.onos.net.intent.IntentService; 29 import org.onlab.onos.net.intent.IntentService;
28 30
...@@ -31,7 +33,7 @@ import org.onlab.onos.net.intent.IntentService; ...@@ -31,7 +33,7 @@ import org.onlab.onos.net.intent.IntentService;
31 */ 33 */
32 @Command(scope = "onos", name = "add-host-intent", 34 @Command(scope = "onos", name = "add-host-intent",
33 description = "Installs host-to-host connectivity intent") 35 description = "Installs host-to-host connectivity intent")
34 -public class AddHostToHostIntentCommand extends AbstractShellCommand { 36 +public class AddHostToHostIntentCommand extends ConnectivityIntentCommand {
35 37
36 @Argument(index = 0, name = "one", description = "One host ID", 38 @Argument(index = 0, name = "one", description = "One host ID",
37 required = true, multiValued = false) 39 required = true, multiValued = false)
...@@ -50,9 +52,11 @@ public class AddHostToHostIntentCommand extends AbstractShellCommand { ...@@ -50,9 +52,11 @@ public class AddHostToHostIntentCommand extends AbstractShellCommand {
50 52
51 TrafficSelector selector = DefaultTrafficSelector.builder().build(); 53 TrafficSelector selector = DefaultTrafficSelector.builder().build();
52 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build(); 54 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
55 + List<Constraint> constraints = buildConstraints();
53 56
54 HostToHostIntent intent = new HostToHostIntent(appId(), oneId, twoId, 57 HostToHostIntent intent = new HostToHostIntent(appId(), oneId, twoId,
55 - selector, treatment); 58 + selector, treatment,
59 + constraints);
56 service.submit(intent); 60 service.submit(intent);
57 } 61 }
58 62
......
...@@ -23,11 +23,13 @@ import org.onlab.onos.net.PortNumber; ...@@ -23,11 +23,13 @@ import org.onlab.onos.net.PortNumber;
23 import org.onlab.onos.net.flow.DefaultTrafficTreatment; 23 import org.onlab.onos.net.flow.DefaultTrafficTreatment;
24 import org.onlab.onos.net.flow.TrafficSelector; 24 import org.onlab.onos.net.flow.TrafficSelector;
25 import org.onlab.onos.net.flow.TrafficTreatment; 25 import org.onlab.onos.net.flow.TrafficTreatment;
26 +import org.onlab.onos.net.intent.Constraint;
26 import org.onlab.onos.net.intent.Intent; 27 import org.onlab.onos.net.intent.Intent;
27 import org.onlab.onos.net.intent.IntentService; 28 import org.onlab.onos.net.intent.IntentService;
28 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; 29 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
29 30
30 import java.util.HashSet; 31 import java.util.HashSet;
32 +import java.util.List;
31 import java.util.Set; 33 import java.util.Set;
32 34
33 import static org.onlab.onos.net.DeviceId.deviceId; 35 import static org.onlab.onos.net.DeviceId.deviceId;
...@@ -69,9 +71,11 @@ public class AddMultiPointToSinglePointIntentCommand extends ConnectivityIntentC ...@@ -69,9 +71,11 @@ public class AddMultiPointToSinglePointIntentCommand extends ConnectivityIntentC
69 71
70 TrafficSelector selector = buildTrafficSelector(); 72 TrafficSelector selector = buildTrafficSelector();
71 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build(); 73 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
74 + List<Constraint> constraints = buildConstraints();
72 75
73 Intent intent = new MultiPointToSinglePointIntent(appId(), selector, treatment, 76 Intent intent = new MultiPointToSinglePointIntent(appId(), selector, treatment,
74 - ingressPoints, egress); 77 + ingressPoints, egress,
78 + constraints);
75 service.submit(intent); 79 service.submit(intent);
76 } 80 }
77 81
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
15 */ 15 */
16 package org.onlab.onos.cli.net; 16 package org.onlab.onos.cli.net;
17 17
18 +import java.util.List;
19 +
18 import org.apache.karaf.shell.commands.Argument; 20 import org.apache.karaf.shell.commands.Argument;
19 import org.apache.karaf.shell.commands.Command; 21 import org.apache.karaf.shell.commands.Command;
20 import org.onlab.onos.net.ConnectPoint; 22 import org.onlab.onos.net.ConnectPoint;
...@@ -22,6 +24,7 @@ import org.onlab.onos.net.DeviceId; ...@@ -22,6 +24,7 @@ import org.onlab.onos.net.DeviceId;
22 import org.onlab.onos.net.PortNumber; 24 import org.onlab.onos.net.PortNumber;
23 import org.onlab.onos.net.flow.TrafficSelector; 25 import org.onlab.onos.net.flow.TrafficSelector;
24 import org.onlab.onos.net.flow.TrafficTreatment; 26 import org.onlab.onos.net.flow.TrafficTreatment;
27 +import org.onlab.onos.net.intent.Constraint;
25 import org.onlab.onos.net.intent.Intent; 28 import org.onlab.onos.net.intent.Intent;
26 import org.onlab.onos.net.intent.IntentService; 29 import org.onlab.onos.net.intent.IntentService;
27 import org.onlab.onos.net.intent.PointToPointIntent; 30 import org.onlab.onos.net.intent.PointToPointIntent;
...@@ -63,8 +66,10 @@ public class AddPointToPointIntentCommand extends ConnectivityIntentCommand { ...@@ -63,8 +66,10 @@ public class AddPointToPointIntentCommand extends ConnectivityIntentCommand {
63 TrafficSelector selector = buildTrafficSelector(); 66 TrafficSelector selector = buildTrafficSelector();
64 TrafficTreatment treatment = builder().build(); 67 TrafficTreatment treatment = builder().build();
65 68
69 + List<Constraint> constraints = buildConstraints();
70 +
66 Intent intent = new PointToPointIntent(appId(), selector, treatment, 71 Intent intent = new PointToPointIntent(appId(), selector, treatment,
67 - ingress, egress); 72 + ingress, egress, constraints);
68 service.submit(intent); 73 service.submit(intent);
69 } 74 }
70 75
......
...@@ -15,14 +15,21 @@ ...@@ -15,14 +15,21 @@
15 */ 15 */
16 package org.onlab.onos.cli.net; 16 package org.onlab.onos.cli.net;
17 17
18 +import java.util.LinkedList;
19 +import java.util.List;
20 +
18 import org.apache.karaf.shell.commands.Option; 21 import org.apache.karaf.shell.commands.Option;
19 import org.onlab.onos.cli.AbstractShellCommand; 22 import org.onlab.onos.cli.AbstractShellCommand;
20 import org.onlab.onos.net.flow.DefaultTrafficSelector; 23 import org.onlab.onos.net.flow.DefaultTrafficSelector;
21 import org.onlab.onos.net.flow.TrafficSelector; 24 import org.onlab.onos.net.flow.TrafficSelector;
25 +import org.onlab.onos.net.intent.Constraint;
26 +import org.onlab.onos.net.intent.constraint.BandwidthConstraint;
27 +import org.onlab.onos.net.intent.constraint.LambdaConstraint;
28 +import org.onlab.onos.net.resource.Bandwidth;
22 import org.onlab.packet.Ethernet; 29 import org.onlab.packet.Ethernet;
23 import org.onlab.packet.MacAddress; 30 import org.onlab.packet.MacAddress;
24 31
25 -import com.google.common.base.Strings; 32 +import static com.google.common.base.Strings.isNullOrEmpty;
26 33
27 /** 34 /**
28 * Base class for command line operations for connectivity based intents. 35 * Base class for command line operations for connectivity based intents.
...@@ -41,6 +48,14 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { ...@@ -41,6 +48,14 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
41 required = false, multiValued = false) 48 required = false, multiValued = false)
42 private String ethTypeString = ""; 49 private String ethTypeString = "";
43 50
51 + @Option(name = "-b", aliases = "--bandwidth", description = "Bandwidth",
52 + required = false, multiValued = false)
53 + private String bandwidthString = "";
54 +
55 + @Option(name = "-l", aliases = "--lambda", description = "Lambda",
56 + required = false, multiValued = false)
57 + private boolean lambda = false;
58 +
44 /** 59 /**
45 * Constructs a traffic selector based on the command line arguments 60 * Constructs a traffic selector based on the command line arguments
46 * presented to the command. 61 * presented to the command.
...@@ -50,21 +65,43 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { ...@@ -50,21 +65,43 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
50 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); 65 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
51 Short ethType = Ethernet.TYPE_IPV4; 66 Short ethType = Ethernet.TYPE_IPV4;
52 67
53 - if (!Strings.isNullOrEmpty(ethTypeString)) { 68 + if (!isNullOrEmpty(ethTypeString)) {
54 EthType ethTypeParameter = EthType.valueOf(ethTypeString); 69 EthType ethTypeParameter = EthType.valueOf(ethTypeString);
55 ethType = ethTypeParameter.value(); 70 ethType = ethTypeParameter.value();
56 } 71 }
57 selectorBuilder.matchEthType(ethType); 72 selectorBuilder.matchEthType(ethType);
58 73
59 - if (!Strings.isNullOrEmpty(srcMacString)) { 74 + if (!isNullOrEmpty(srcMacString)) {
60 selectorBuilder.matchEthSrc(MacAddress.valueOf(srcMacString)); 75 selectorBuilder.matchEthSrc(MacAddress.valueOf(srcMacString));
61 } 76 }
62 77
63 - if (!Strings.isNullOrEmpty(dstMacString)) { 78 + if (!isNullOrEmpty(dstMacString)) {
64 selectorBuilder.matchEthDst(MacAddress.valueOf(dstMacString)); 79 selectorBuilder.matchEthDst(MacAddress.valueOf(dstMacString));
65 } 80 }
66 81
67 return selectorBuilder.build(); 82 return selectorBuilder.build();
68 } 83 }
69 84
85 + /**
86 + * Builds the constraint list for this command based on the command line
87 + * parameters.
88 + *
89 + * @return List of constraint objects describing the constraints requested
90 + */
91 + protected List<Constraint> buildConstraints() {
92 + final List<Constraint> constraints = new LinkedList<>();
93 +
94 + // Check for a bandwidth specification
95 + if (!isNullOrEmpty(bandwidthString)) {
96 + final double bandwidthValue = Double.parseDouble(bandwidthString);
97 + constraints.add(new BandwidthConstraint(Bandwidth.valueOf(bandwidthValue)));
98 + }
99 +
100 + // Check for a lambda specification
101 + if (lambda) {
102 + constraints.add(new LambdaConstraint(null));
103 + }
104 +
105 + return constraints;
106 + }
70 } 107 }
......
...@@ -105,6 +105,7 @@ public final class HostToHostIntent extends ConnectivityIntent { ...@@ -105,6 +105,7 @@ public final class HostToHostIntent extends ConnectivityIntent {
105 .add("appId", appId()) 105 .add("appId", appId())
106 .add("selector", selector()) 106 .add("selector", selector())
107 .add("treatment", treatment()) 107 .add("treatment", treatment())
108 + .add("constraints", constraints())
108 .add("one", one) 109 .add("one", one)
109 .add("two", two) 110 .add("two", two)
110 .toString(); 111 .toString();
......
...@@ -22,6 +22,7 @@ import org.onlab.onos.net.ConnectPoint; ...@@ -22,6 +22,7 @@ import org.onlab.onos.net.ConnectPoint;
22 import org.onlab.onos.net.flow.TrafficSelector; 22 import org.onlab.onos.net.flow.TrafficSelector;
23 import org.onlab.onos.net.flow.TrafficTreatment; 23 import org.onlab.onos.net.flow.TrafficTreatment;
24 24
25 +import java.util.List;
25 import java.util.Set; 26 import java.util.Set;
26 27
27 import static com.google.common.base.Preconditions.checkArgument; 28 import static com.google.common.base.Preconditions.checkArgument;
...@@ -65,6 +66,38 @@ public final class MultiPointToSinglePointIntent extends ConnectivityIntent { ...@@ -65,6 +66,38 @@ public final class MultiPointToSinglePointIntent extends ConnectivityIntent {
65 } 66 }
66 67
67 /** 68 /**
69 + * Creates a new multi-to-single point connectivity intent for the specified
70 + * traffic selector and treatment.
71 + *
72 + * @param appId application identifier
73 + * @param selector traffic selector
74 + * @param treatment treatment
75 + * @param ingressPoints set of ports from which ingress traffic originates
76 + * @param egressPoint port to which traffic will egress
77 + * @param constraints constraints to apply to the intent
78 + * @throws NullPointerException if {@code ingressPoints} or
79 + * {@code egressPoint} is null.
80 + * @throws IllegalArgumentException if the size of {@code ingressPoints} is
81 + * not more than 1
82 + */
83 + public MultiPointToSinglePointIntent(ApplicationId appId,
84 + TrafficSelector selector,
85 + TrafficTreatment treatment,
86 + Set<ConnectPoint> ingressPoints,
87 + ConnectPoint egressPoint,
88 + List<Constraint> constraints) {
89 + super(id(MultiPointToSinglePointIntent.class, selector, treatment,
90 + ingressPoints, egressPoint), appId, null, selector, treatment,
91 + constraints);
92 +
93 + checkNotNull(ingressPoints);
94 + checkArgument(!ingressPoints.isEmpty(), "Ingress point set cannot be empty");
95 +
96 + this.ingressPoints = Sets.newHashSet(ingressPoints);
97 + this.egressPoint = checkNotNull(egressPoint);
98 + }
99 +
100 + /**
68 * Constructor for serializer. 101 * Constructor for serializer.
69 */ 102 */
70 protected MultiPointToSinglePointIntent() { 103 protected MultiPointToSinglePointIntent() {
...@@ -101,6 +134,7 @@ public final class MultiPointToSinglePointIntent extends ConnectivityIntent { ...@@ -101,6 +134,7 @@ public final class MultiPointToSinglePointIntent extends ConnectivityIntent {
101 .add("treatment", treatment()) 134 .add("treatment", treatment())
102 .add("ingress", ingressPoints()) 135 .add("ingress", ingressPoints())
103 .add("egress", egressPoint()) 136 .add("egress", egressPoint())
137 + .add("constraints", constraints())
104 .toString(); 138 .toString();
105 } 139 }
106 } 140 }
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
15 */ 15 */
16 package org.onlab.onos.net.intent; 16 package org.onlab.onos.net.intent;
17 17
18 +import java.util.List;
19 +
18 import com.google.common.base.MoreObjects; 20 import com.google.common.base.MoreObjects;
19 import org.onlab.onos.core.ApplicationId; 21 import org.onlab.onos.core.ApplicationId;
20 import org.onlab.onos.net.Path; 22 import org.onlab.onos.net.Path;
...@@ -46,6 +48,24 @@ public class PathIntent extends ConnectivityIntent { ...@@ -46,6 +48,24 @@ public class PathIntent extends ConnectivityIntent {
46 } 48 }
47 49
48 /** 50 /**
51 + * Creates a new point-to-point intent with the supplied ingress/egress
52 + * ports and using the specified explicit path.
53 + *
54 + * @param appId application identifier
55 + * @param selector traffic selector
56 + * @param treatment treatment
57 + * @param path traversed links
58 + * @param constraints optional list of constraints
59 + * @throws NullPointerException {@code path} is null
60 + */
61 + public PathIntent(ApplicationId appId, TrafficSelector selector,
62 + TrafficTreatment treatment, Path path, List<Constraint> constraints) {
63 + super(id(PathIntent.class, selector, treatment, path, constraints), appId,
64 + resources(path.links()), selector, treatment, constraints);
65 + this.path = path;
66 + }
67 +
68 + /**
49 * Constructor for serializer. 69 * Constructor for serializer.
50 */ 70 */
51 protected PathIntent() { 71 protected PathIntent() {
...@@ -75,6 +95,7 @@ public class PathIntent extends ConnectivityIntent { ...@@ -75,6 +95,7 @@ public class PathIntent extends ConnectivityIntent {
75 .add("appId", appId()) 95 .add("appId", appId())
76 .add("selector", selector()) 96 .add("selector", selector())
77 .add("treatment", treatment()) 97 .add("treatment", treatment())
98 + .add("constraints", constraints())
78 .add("path", path) 99 .add("path", path)
79 .toString(); 100 .toString();
80 } 101 }
......
...@@ -118,13 +118,14 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent> ...@@ -118,13 +118,14 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent>
118 118
119 @Override 119 @Override
120 public double weight(TopologyEdge edge) { 120 public double weight(TopologyEdge edge) {
121 - if (constraints == null) { 121 + if (constraints == null || !constraints.iterator().hasNext()) {
122 return 1.0; 122 return 1.0;
123 } 123 }
124 124
125 // iterate over all constraints in order and return the weight of 125 // iterate over all constraints in order and return the weight of
126 // the first one with fast fail over the first failure 126 // the first one with fast fail over the first failure
127 Iterator<Constraint> it = constraints.iterator(); 127 Iterator<Constraint> it = constraints.iterator();
128 +
128 double cost = it.next().cost(edge.link(), resourceService); 129 double cost = it.next().cost(edge.link(), resourceService);
129 while (it.hasNext() && cost > 0) { 130 while (it.hasNext() && cost > 0) {
130 if (it.next().cost(edge.link(), resourceService) < 0) { 131 if (it.next().cost(edge.link(), resourceService) < 0) {
...@@ -132,6 +133,7 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent> ...@@ -132,6 +133,7 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent>
132 } 133 }
133 } 134 }
134 return cost; 135 return cost;
136 +
135 } 137 }
136 } 138 }
137 139
......
...@@ -70,7 +70,8 @@ public class HostToHostIntentCompiler ...@@ -70,7 +70,8 @@ public class HostToHostIntentCompiler
70 HostToHostIntent intent) { 70 HostToHostIntent intent) {
71 TrafficSelector selector = builder(intent.selector()) 71 TrafficSelector selector = builder(intent.selector())
72 .matchEthSrc(src.mac()).matchEthDst(dst.mac()).build(); 72 .matchEthSrc(src.mac()).matchEthDst(dst.mac()).build();
73 - return new PathIntent(intent.appId(), selector, intent.treatment(), path); 73 + return new PathIntent(intent.appId(), selector, intent.treatment(),
74 + path, intent.constraints());
74 } 75 }
75 76
76 } 77 }
......
...@@ -77,7 +77,8 @@ public class PointToPointIntentCompiler ...@@ -77,7 +77,8 @@ public class PointToPointIntentCompiler
77 private Intent createPathIntent(Path path, 77 private Intent createPathIntent(Path path,
78 PointToPointIntent intent) { 78 PointToPointIntent intent) {
79 return new PathIntent(intent.appId(), 79 return new PathIntent(intent.appId(),
80 - intent.selector(), intent.treatment(), path); 80 + intent.selector(), intent.treatment(), path,
81 + intent.constraints());
81 } 82 }
82 83
83 } 84 }
......