Ray Milkey
Committed by Brian O'Connor

Add keys to intents

- use Key class rather than String for intent keys
- add CLI option to specify a string key
- add key field to constructors for connectivity intents
- translate id into a key if no key is specified

Change-Id: I69ffbad93bc3daddf06a67cb0cffa2130e781b37
......@@ -54,7 +54,8 @@ public class AddHostToHostIntentCommand extends ConnectivityIntentCommand {
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
List<Constraint> constraints = buildConstraints();
HostToHostIntent intent = new HostToHostIntent(appId(), oneId, twoId,
HostToHostIntent intent = new HostToHostIntent(appId(), key(),
oneId, twoId,
selector, treatment,
constraints);
service.submit(intent);
......
......@@ -72,7 +72,8 @@ public class AddMultiPointToSinglePointIntentCommand extends ConnectivityIntentC
TrafficTreatment treatment = buildTrafficTreatment();
List<Constraint> constraints = buildConstraints();
Intent intent = new MultiPointToSinglePointIntent(appId(), selector, treatment,
Intent intent = new MultiPointToSinglePointIntent(appId(), key(),
selector, treatment,
ingressPoints, egress,
constraints);
service.submit(intent);
......
......@@ -56,7 +56,7 @@ public class AddOpticalIntentCommand extends ConnectivityIntentCommand {
PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
Intent intent = new OpticalConnectivityIntent(appId(), ingress, egress);
Intent intent = new OpticalConnectivityIntent(appId(), key(), ingress, egress);
service.submit(intent);
print("Optical intent submitted:\n%s", intent.toString());
}
......
......@@ -15,9 +15,6 @@
*/
package org.onosproject.cli.net;
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.net.PortNumber.portNumber;
import java.util.List;
import org.apache.karaf.shell.commands.Argument;
......@@ -32,6 +29,9 @@ import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.PointToPointIntent;
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.net.PortNumber.portNumber;
/**
* Installs point-to-point connectivity intents.
*/
......@@ -67,7 +67,9 @@ public class AddPointToPointIntentCommand extends ConnectivityIntentCommand {
List<Constraint> constraints = buildConstraints();
Intent intent = new PointToPointIntent(appId(), selector, treatment,
Intent intent = new PointToPointIntent(appId(),
key(),
selector, treatment,
ingress, egress, constraints);
service.submit(intent);
print("Point to point intent submitted:\n%s", intent.toString());
......
......@@ -71,8 +71,10 @@ public class AddSinglePointToMultiPointIntentCommand extends ConnectivityIntentC
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
List<Constraint> constraints = buildConstraints();
SinglePointToMultiPointIntent intent = new SinglePointToMultiPointIntent(
SinglePointToMultiPointIntent intent =
new SinglePointToMultiPointIntent(
appId(),
key(),
selector,
treatment,
ingressPoint,
......
......@@ -28,6 +28,7 @@ import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.intent.Constraint;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.constraint.BandwidthConstraint;
import org.onosproject.net.intent.constraint.LambdaConstraint;
import org.onosproject.net.intent.constraint.LinkTypeConstraint;
......@@ -81,6 +82,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
required = false, multiValued = false)
private boolean lambda = false;
@Option(name = "-k", aliases = "--key", description = "Intent Key",
required = false, multiValued = false)
private String intentKey = null;
// Treatments
@Option(name = "--setEthSrc", description = "Rewrite Source MAC Address",
......@@ -180,4 +185,19 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
return constraints;
}
/**
* Creates a key for an intent based on command line arguments. If a key
* has been specified, it is returned. If no key is specified, null
* is returned.
*
* @return intent key if specified, null otherwise
*/
protected Key key() {
Key key = null;
if (intentKey != null) {
key = Key.of(intentKey, appId());
}
return key;
}
}
......
......@@ -61,7 +61,29 @@ public abstract class ConnectivityIntent extends Intent {
Collection<NetworkResource> resources,
TrafficSelector selector,
TrafficTreatment treatment) {
this(appId, resources, selector, treatment, Collections.emptyList());
this(appId, null, resources, selector, treatment, Collections.emptyList());
}
/**
* Creates a connectivity intent that matches on the specified selector
* and applies the specified treatment.
* <p>
* Path will be chosen without any constraints.
* </p>
*
* @param appId application identifier
* @param key intent key
* @param resources required network resources (optional)
* @param selector traffic selector
* @param treatment treatment
* @throws NullPointerException if the selector or treatment is null
*/
protected ConnectivityIntent(ApplicationId appId,
Key key,
Collection<NetworkResource> resources,
TrafficSelector selector,
TrafficTreatment treatment) {
this(appId, key, resources, selector, treatment, Collections.emptyList());
}
/**
......@@ -72,18 +94,47 @@ public abstract class ConnectivityIntent extends Intent {
* </p>
*
* @param appId application identifier
* @param key explicit key to use for intent
* @param resources required network resources (optional)
* @param selector traffic selector
* @param treatment treatment
* @param constraints optional prioritized list of constraints
* @throws NullPointerException if the selector or treatment is null
*/
protected ConnectivityIntent(ApplicationId appId,
Key key,
Collection<NetworkResource> resources,
TrafficSelector selector,
TrafficTreatment treatment,
List<Constraint> constraints) {
super(appId, key, resources);
this.selector = checkNotNull(selector);
this.treatment = checkNotNull(treatment);
this.constraints = checkNotNull(constraints);
}
/**
* Creates a connectivity intent that matches on the specified selector
* and applies the specified treatment.
* <p>
* Path will be optimized based on the first constraint if one is given.
* </p>
*
* @param appId application identifier
* @param resources required network resources (optional)
* @param selector traffic selector
* @param treatment treatment
* @param constraints optional prioritized list of constraints
* @throws NullPointerException if the selector or treatment is null
*/
protected ConnectivityIntent(ApplicationId appId,
Collection<NetworkResource> resources,
TrafficSelector selector,
TrafficTreatment treatment,
List<Constraint> constraints) {
super(appId, resources);
super(appId, null, resources);
this.selector = checkNotNull(selector);
this.treatment = checkNotNull(treatment);
this.constraints = checkNotNull(constraints);
......
......@@ -87,7 +87,26 @@ public final class HostToHostIntent extends ConnectivityIntent {
TrafficSelector selector,
TrafficTreatment treatment,
List<Constraint> constraints) {
super(appId, Collections.emptyList(), selector, treatment, constraints);
this(appId, null, one, two, selector, treatment, constraints);
}
/**
* Creates a new host-to-host intent with the supplied host pair.
*
* @param appId application identifier
* @param key intent key
* @param one first host
* @param two second host
* @param selector action
* @param treatment ingress port
* @param constraints optional prioritized list of path selection constraints
* @throws NullPointerException if {@code one} or {@code two} is null.
*/
public HostToHostIntent(ApplicationId appId, Key key,
HostId one, HostId two,
TrafficSelector selector,
TrafficTreatment treatment,
List<Constraint> constraints) {
super(appId, key, Collections.emptyList(), selector, treatment, constraints);
// TODO: consider whether the case one and two are same is allowed
this.one = checkNotNull(one);
......
......@@ -36,7 +36,7 @@ public abstract class Intent {
private final IntentId id;
private final ApplicationId appId;
private final String key; // TODO make this a class
private final Key key;
private final Collection<NetworkResource> resources;
......@@ -71,12 +71,12 @@ public abstract class Intent {
* @param resources required network resources (optional)
*/
protected Intent(ApplicationId appId,
String key,
Key key,
Collection<NetworkResource> resources) {
checkState(idGenerator != null, "Id generator is not bound.");
this.id = IntentId.valueOf(idGenerator.getNewId());
this.appId = checkNotNull(appId, "Application ID cannot be null");
this.key = (key != null) ? key : id.toString(); //FIXME
this.key = (key != null) ? key : Key.of(id.fingerprint(), appId);
this.resources = checkNotNull(resources);
}
......@@ -156,7 +156,7 @@ public abstract class Intent {
}
}
public String key() {
public Key key() {
return key;
}
}
......
......@@ -52,7 +52,7 @@ public class IntentData { //FIXME need to make this "immutable"
return state;
}
public String key() {
public Key key() {
return intent.key();
}
......
......@@ -73,7 +73,12 @@ public final class IntentOperation {
return intent.id();
}
public String key() {
/**
* Returns the key for this intent.
*
* @return key value
*/
public Key key() {
return intent.key();
}
......
......@@ -92,7 +92,7 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> {
* @param key key
* @return intent or null if not found
*/
default Intent getIntent(String key) { //FIXME remove when impl.
default Intent getIntent(Key key) { //FIXME remove when impl.
return null;
}
......@@ -102,7 +102,7 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> {
* @param key key to look up
* @return intent data object
*/
default IntentData getIntentData(String key) { //FIXME remove when impl.
default IntentData getIntentData(Key key) { //FIXME remove when impl.
return null;
}
......
......@@ -32,7 +32,7 @@ public class Key {
private final long hash;
private static final HashFunction HASH_FN = Hashing.md5();
private Key(long hash) {
protected Key(long hash) {
this.hash = hash;
}
......@@ -48,7 +48,7 @@ public class Key {
return new LongKey(key, appId);
}
private final static class StringKey extends Key {
private static final class StringKey extends Key {
private final ApplicationId appId;
private final String key;
......@@ -87,7 +87,7 @@ public class Key {
}
}
private final static class LongKey extends Key {
private static final class LongKey extends Key {
private final ApplicationId appId;
private static long key;
......
......@@ -75,12 +75,13 @@ public final class MultiPointToSinglePointIntent extends ConnectivityIntent {
* not more than 1
*/
public MultiPointToSinglePointIntent(ApplicationId appId,
Key key,
TrafficSelector selector,
TrafficTreatment treatment,
Set<ConnectPoint> ingressPoints,
ConnectPoint egressPoint,
List<Constraint> constraints) {
super(appId, Collections.emptyList(), selector, treatment, constraints);
super(appId, key, Collections.emptyList(), selector, treatment, constraints);
checkNotNull(ingressPoints);
checkArgument(!ingressPoints.isEmpty(), "Ingress point set cannot be empty");
......@@ -93,6 +94,30 @@ 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) {
this(appId, null, selector, treatment, ingressPoints, egressPoint, constraints);
}
/**
* Constructor for serializer.
*/
protected MultiPointToSinglePointIntent() {
......
......@@ -38,11 +38,28 @@ public class OpticalConnectivityIntent extends Intent {
*/
public OpticalConnectivityIntent(ApplicationId appId,
ConnectPoint src, ConnectPoint dst) {
super(appId, Collections.emptyList());
this(appId, null, src, dst);
}
/**
* Creates an optical connectivity intent between the specified
* connection points.
*
* @param appId application identification
* @param key intent key
* @param src the source transponder port
* @param dst the destination transponder port
*/
public OpticalConnectivityIntent(ApplicationId appId,
Key key,
ConnectPoint src, ConnectPoint dst) {
super(appId, key, Collections.emptyList());
this.src = src;
this.dst = dst;
}
/**
* Constructor for serializer.
*/
......
......@@ -40,6 +40,37 @@ public class PointToPointIntent extends ConnectivityIntent {
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports and constraints.
*
* @param appId application identifier
* @param key key of the intent
* @param selector traffic selector
* @param treatment treatment
* @param ingressPoint ingress port
* @param egressPoint egress port
* @param constraints optional list of constraints
* @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null.
*/
public PointToPointIntent(ApplicationId appId,
Key key,
TrafficSelector selector,
TrafficTreatment treatment,
ConnectPoint ingressPoint,
ConnectPoint egressPoint,
List<Constraint> constraints) {
super(appId, key, Collections.emptyList(), selector, treatment, constraints);
checkNotNull(ingressPoint);
checkNotNull(egressPoint);
checkArgument(!ingressPoint.equals(egressPoint),
"ingress and egress should be different (ingress: %s, egress: %s)", ingressPoint, egressPoint);
this.ingressPoint = ingressPoint;
this.egressPoint = egressPoint;
}
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports and with built-in link type constraint to avoid optical links.
*
* @param appId application identifier
......@@ -53,7 +84,7 @@ public class PointToPointIntent extends ConnectivityIntent {
TrafficTreatment treatment,
ConnectPoint ingressPoint,
ConnectPoint egressPoint) {
this(appId, selector, treatment, ingressPoint, egressPoint,
this(appId, null, selector, treatment, ingressPoint, egressPoint,
ImmutableList.of(new LinkTypeConstraint(false, Link.Type.OPTICAL)));
}
......@@ -74,7 +105,7 @@ public class PointToPointIntent extends ConnectivityIntent {
ConnectPoint ingressPoint,
ConnectPoint egressPoint,
List<Constraint> constraints) {
super(appId, Collections.emptyList(), selector, treatment, constraints);
super(appId, null, Collections.emptyList(), selector, treatment, constraints);
checkNotNull(ingressPoint);
checkNotNull(egressPoint);
......
......@@ -54,13 +54,14 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent {
public SinglePointToMultiPointIntent(ApplicationId appId,
TrafficSelector selector, TrafficTreatment treatment,
ConnectPoint ingressPoint, Set<ConnectPoint> egressPoints) {
this(appId, selector, treatment, ingressPoint, egressPoints, Collections.emptyList());
this(appId, null, selector, treatment, ingressPoint, egressPoints, Collections.emptyList());
}
/**
* Creates a new single-to-multi point connectivity intent.
*
* @param appId application identifier
* @param key intent key
* @param selector traffic selector
* @param treatment treatment
* @param ingressPoint port on which traffic will ingress
......@@ -72,10 +73,11 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent {
* not more than 1
*/
public SinglePointToMultiPointIntent(ApplicationId appId,
Key key,
TrafficSelector selector, TrafficTreatment treatment,
ConnectPoint ingressPoint, Set<ConnectPoint> egressPoints,
List<Constraint> constraints) {
super(appId, Collections.emptyList(), selector, treatment, constraints);
super(appId, key, Collections.emptyList(), selector, treatment, constraints);
checkNotNull(egressPoints);
checkNotNull(ingressPoint);
checkArgument(!egressPoints.isEmpty(), "Egress point set cannot be empty");
......
......@@ -19,6 +19,7 @@ import com.google.common.collect.Maps;
import org.onlab.util.AbstractAccumulator;
import org.onosproject.net.intent.IntentBatchDelegate;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.Key;
import java.util.Collection;
import java.util.List;
......@@ -57,7 +58,7 @@ public class IntentAccumulator extends AbstractAccumulator<IntentData> {
}
private Collection<IntentData> reduce(List<IntentData> ops) {
Map<String, IntentData> map = Maps.newHashMap();
Map<Key, IntentData> map = Maps.newHashMap();
for (IntentData op : ops) {
map.put(op.key(), op);
}
......
......@@ -27,6 +27,7 @@ import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentEvent;
import org.onosproject.net.intent.IntentStore;
import org.onosproject.net.intent.IntentStoreDelegate;
import org.onosproject.net.intent.Key;
import org.onosproject.store.AbstractStore;
import org.slf4j.Logger;
......@@ -46,8 +47,8 @@ public class SimpleIntentStore
private final Logger log = getLogger(getClass());
// current state maps FIXME.. make this a IntentData map
private final Map<String, IntentData> current = Maps.newConcurrentMap();
private final Map<String, IntentData> pending = Maps.newConcurrentMap(); //String is "key"
private final Map<Key, IntentData> current = Maps.newConcurrentMap();
private final Map<Key, IntentData> pending = Maps.newConcurrentMap(); //String is "key"
@Activate
public void activate() {
......@@ -72,7 +73,7 @@ public class SimpleIntentStore
}
@Override
public IntentData getIntentData(String key) {
public IntentData getIntentData(Key key) {
return current.get(key);
}
......