Thomas Vachuska

adding constaints to intent API

Showing 21 changed files with 694 additions and 382 deletions
......@@ -27,8 +27,7 @@ import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.PointToPointIntentWithBandwidthConstraint;
import org.onlab.onos.net.resource.BandwidthResourceRequest;
import org.onlab.onos.net.intent.PointToPointIntent;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.PortNumber.portNumber;
......@@ -73,9 +72,10 @@ public class AddPointToPointIntentWithBandwidthConstraintCommand extends Connect
TrafficSelector selector = buildTrafficSelector();
TrafficTreatment treatment = builder().build();
Intent intent = new PointToPointIntentWithBandwidthConstraint(
// FIXME: add bandwitdh constraint
Intent intent = new PointToPointIntent(
appId(), selector, treatment,
ingress, egress, new BandwidthResourceRequest(bandwidth));
ingress, egress);
service.submit(intent);
}
......
......@@ -78,6 +78,9 @@ public class IntentsListCommand extends AbstractShellCommand {
if (!ci.treatment().instructions().isEmpty()) {
print(" treatment=%s", ci.treatment().instructions());
}
if (ci.constraints() != null && !ci.constraints().isEmpty()) {
print(" constraints=%s", ci.constraints());
}
}
if (intent instanceof PointToPointIntent) {
......
......@@ -23,6 +23,7 @@ import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import java.util.Collection;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -40,10 +41,14 @@ public abstract class ConnectivityIntent extends Intent {
private final TrafficSelector selector;
private final TrafficTreatment treatment;
private final List<Constraint> constraints;
/**
* 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 id intent identifier
* @param appId application identifier
......@@ -56,9 +61,33 @@ public abstract class ConnectivityIntent extends Intent {
Collection<NetworkResource> resources,
TrafficSelector selector,
TrafficTreatment treatment) {
this(id, appId, resources, selector, treatment, null);
}
/**
* 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 id intent identifier
* @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 treatement is null
*/
protected ConnectivityIntent(IntentId id, ApplicationId appId,
Collection<NetworkResource> resources,
TrafficSelector selector,
TrafficTreatment treatment,
List<Constraint> constraints) {
super(id, appId, resources);
this.selector = checkNotNull(selector);
this.treatment = checkNotNull(treatment);
this.constraints = constraints;
}
/**
......@@ -68,6 +97,7 @@ public abstract class ConnectivityIntent extends Intent {
super();
this.selector = null;
this.treatment = null;
this.constraints = null;
}
/**
......@@ -89,13 +119,22 @@ public abstract class ConnectivityIntent extends Intent {
}
/**
* Returns the set of connectivity constraints.
*
* @return list of intent constraints
*/
public List<Constraint> constraints() {
return constraints;
}
/**
* Produces a collection of network resources from the given links.
*
* @param links collection of links
* @return collection of link resources
*/
protected static Collection<NetworkResource> resources(Collection<Link> links) {
return ImmutableSet.<NetworkResource>copyOf(links);
return ImmutableSet.<NetworkResource>copyOf((Iterable<? extends NetworkResource>) links);
}
}
......
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.onos.net.intent;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.resource.LinkResourceService;
/**
* Representation of a connectivity constraint capable of evaluating a link
* and determining the cost of traversing that link in the context of this
* constraint.
*/
public interface Constraint {
// TODO: Consider separating cost vs viability.
/**
* Evaluates the specified link and provides the cost for its traversal.
*
* @param link link to be evaluated
* @param resourceService resource service for validating availability of
* link resources
* @return cost of link traversal
*/
double cost(Link link, LinkResourceService resourceService);
/**
* Validates that the specified path satisfies the constraint.
*
* @param path path to be validated
* @param resourceService resource service for validating availability of
* link resources
* @return cost of link traversal
*/
boolean validate(Path path, LinkResourceService resourceService);
}
......@@ -21,6 +21,8 @@ import org.onlab.onos.net.HostId;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
......@@ -44,11 +46,30 @@ public final class HostToHostIntent extends ConnectivityIntent {
public HostToHostIntent(ApplicationId appId, HostId one, HostId two,
TrafficSelector selector,
TrafficTreatment treatment) {
this(appId, one, two, selector, treatment, null);
}
/**
* Creates a new host-to-host intent with the supplied host pair.
*
* @param appId application identifier
* @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, HostId one, HostId two,
TrafficSelector selector,
TrafficTreatment treatment,
List<Constraint> constraints) {
super(id(HostToHostIntent.class, min(one, two), max(one, two),
selector, treatment),
appId, null, selector, treatment);
selector, treatment, constraints),
appId, null, selector, treatment, constraints);
this.one = checkNotNull(one);
this.two = checkNotNull(two);
}
private static HostId min(HostId one, HostId two) {
......
......@@ -51,6 +51,15 @@ public final class IntentId implements BatchOperationTarget {
this.fingerprint = fingerprint;
}
/**
* Returns the backing fingerprint.
*
* @return the fingerprint
*/
public long fingerprint() {
return fingerprint;
}
@Override
public int hashCode() {
return (int) (fingerprint ^ (fingerprint >>> 32));
......
......@@ -15,16 +15,11 @@
*/
package org.onlab.onos.net.intent;
import java.util.List;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import org.onlab.onos.core.ApplicationId;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.resource.LinkResourceRequest;
/**
* Abstraction of explicitly path specified connectivity intent.
......@@ -32,7 +27,6 @@ import org.onlab.onos.net.resource.LinkResourceRequest;
public class PathIntent extends ConnectivityIntent {
private final Path path;
private final List<LinkResourceRequest> resourceRequests;
/**
* Creates a new point-to-point intent with the supplied ingress/egress
......@@ -42,15 +36,13 @@ public class PathIntent extends ConnectivityIntent {
* @param selector traffic selector
* @param treatment treatment
* @param path traversed links
* @param resourceRequests link resource request
* @throws NullPointerException {@code path} is null
*/
public PathIntent(ApplicationId appId, TrafficSelector selector,
TrafficTreatment treatment, Path path, LinkResourceRequest[] resourceRequests) {
TrafficTreatment treatment, Path path) {
super(id(PathIntent.class, selector, treatment, path), appId,
resources(path.links()), selector, treatment);
this.path = path;
this.resourceRequests = ImmutableList.copyOf(resourceRequests);
}
/**
......@@ -59,7 +51,6 @@ public class PathIntent extends ConnectivityIntent {
protected PathIntent() {
super();
this.path = null;
this.resourceRequests = ImmutableList.of();
}
/**
......@@ -76,10 +67,6 @@ public class PathIntent extends ConnectivityIntent {
return true;
}
// TODO: consider changing return type
public LinkResourceRequest[] resourceRequests() {
return resourceRequests.toArray(new LinkResourceRequest[resourceRequests.size()]);
}
@Override
public String toString() {
......
......@@ -16,10 +16,15 @@
package org.onlab.onos.net.intent;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import org.onlab.onos.core.ApplicationId;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.intent.constraint.LinkTypeConstraint;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -33,7 +38,7 @@ public class PointToPointIntent extends ConnectivityIntent {
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports.
* ports and with built-in link type constraint to avoid optical links.
*
* @param appId application identifier
* @param selector traffic selector
......@@ -46,8 +51,30 @@ public class PointToPointIntent extends ConnectivityIntent {
TrafficTreatment treatment,
ConnectPoint ingressPoint,
ConnectPoint egressPoint) {
super(id(PointToPointIntent.class, selector, treatment, ingressPoint, egressPoint),
appId, null, selector, treatment);
this(appId, selector, treatment, ingressPoint, egressPoint,
ImmutableList.of(new LinkTypeConstraint(false, Link.Type.OPTICAL)));
}
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports and constraints.
*
* @param appId application identifier
* @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, TrafficSelector selector,
TrafficTreatment treatment,
ConnectPoint ingressPoint,
ConnectPoint egressPoint,
List<Constraint> constraints) {
super(id(PointToPointIntent.class, selector, treatment,
ingressPoint, egressPoint, constraints),
appId, null, selector, treatment, constraints);
this.ingressPoint = checkNotNull(ingressPoint);
this.egressPoint = checkNotNull(egressPoint);
}
......@@ -89,6 +116,7 @@ public class PointToPointIntent extends ConnectivityIntent {
.add("treatment", treatment())
.add("ingress", ingressPoint)
.add("egress", egressPoint)
.add("constraints", constraints())
.toString();
}
......
/*
* 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.net.intent;
import org.onlab.onos.core.ApplicationId;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.resource.BandwidthResourceRequest;
import com.google.common.base.MoreObjects;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Abstraction of point-to-point connectivity.
*/
public class PointToPointIntentWithBandwidthConstraint extends ConnectivityIntent {
private final ConnectPoint ingressPoint;
private final ConnectPoint egressPoint;
private final BandwidthResourceRequest bandwidthResourceRequest;
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports.
*
* @param appId application identifier
* @param selector traffic selector
* @param treatment treatment
* @param ingressPoint ingress port
* @param egressPoint egress port
* @param bandwidthResourceRequest bandwidth resource request
* @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null.
*/
public PointToPointIntentWithBandwidthConstraint(ApplicationId appId, TrafficSelector selector,
TrafficTreatment treatment,
ConnectPoint ingressPoint,
ConnectPoint egressPoint,
BandwidthResourceRequest bandwidthResourceRequest) {
super(id(PointToPointIntentWithBandwidthConstraint.class, selector,
treatment, ingressPoint, egressPoint, bandwidthResourceRequest.bandwidth()),
appId, null, selector, treatment);
this.ingressPoint = checkNotNull(ingressPoint);
this.egressPoint = checkNotNull(egressPoint);
this.bandwidthResourceRequest = bandwidthResourceRequest;
}
/**
* Constructor for serializer.
*/
protected PointToPointIntentWithBandwidthConstraint() {
super();
this.ingressPoint = null;
this.egressPoint = null;
bandwidthResourceRequest = new BandwidthResourceRequest(0.0);
}
/**
* Returns the port on which the ingress traffic should be connected to
* the egress.
*
* @return ingress port
*/
public ConnectPoint ingressPoint() {
return ingressPoint;
}
/**
* Returns the port on which the traffic should egress.
*
* @return egress port
*/
public ConnectPoint egressPoint() {
return egressPoint;
}
public BandwidthResourceRequest bandwidthRequest() {
return this.bandwidthResourceRequest;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("id", id())
.add("appId", appId())
.add("selector", selector())
.add("treatment", treatment())
.add("ingress", ingressPoint)
.add("egress", egressPoint)
.add("bandwidth", bandwidthResourceRequest.bandwidth().toString())
.toString();
}
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.onos.net.intent.constraint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.resource.Bandwidth;
import org.onlab.onos.net.resource.BandwidthResourceRequest;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.resource.ResourceRequest;
import org.onlab.onos.net.resource.ResourceType;
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Constraint that evaluates links based on available bandwidths.
*/
public class BandwidthConstraint extends BooleanConstraint {
private final Bandwidth bandwidth;
/**
* Creates a new bandwidth constraint.
*
* @param bandwidth required bandwidth
*/
public BandwidthConstraint(Bandwidth bandwidth) {
this.bandwidth = checkNotNull(bandwidth, "Bandwidth cannot be null");
}
@Override
public boolean isValid(Link link, LinkResourceService resourceService) {
for (ResourceRequest request : resourceService.getAvailableResources(link)) {
if (request.type() == ResourceType.BANDWIDTH) {
BandwidthResourceRequest brr = (BandwidthResourceRequest) request;
if (brr.bandwidth().toDouble() >= bandwidth.toDouble()) {
return true;
}
}
}
return false;
}
/**
* Returns the bandwidth required by this constraint.
*
* @return required bandwidth
*/
public Bandwidth bandwidth() {
return bandwidth;
}
@Override
public int hashCode() {
return Objects.hash(bandwidth);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final BandwidthConstraint other = (BandwidthConstraint) obj;
return Objects.equals(this.bandwidth, other.bandwidth);
}
@Override
public String toString() {
return toStringHelper(this).add("bandwidth", bandwidth).toString();
}
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.onos.net.intent.constraint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.intent.Constraint;
import org.onlab.onos.net.resource.LinkResourceService;
/**
* Abstract base class for various constraints that evaluate link viability
* in a yes/no fashion.
*/
public abstract class BooleanConstraint implements Constraint {
/**
* Returns true if the specified link satisfies the constraint.
*
* @param link link to be validated
* @param resourceService resource service for checking available link resources
* @return true if link is viable
*/
public abstract boolean isValid(Link link, LinkResourceService resourceService);
@Override
public double cost(Link link, LinkResourceService resourceService) {
return isValid(link, resourceService) ? +1 : -1;
}
@Override
public boolean validate(Path path, LinkResourceService resourceService) {
for (Link link : path.links()) {
if (isValid(link, resourceService)) {
return false;
}
}
return true;
}
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.onos.net.intent.constraint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.resource.Lambda;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.resource.ResourceRequest;
import org.onlab.onos.net.resource.ResourceType;
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
* Constraint that evaluates links based on available lambda.
*/
public class LambdaConstraint extends BooleanConstraint {
private final Lambda lambda;
/**
* Creates a new optical lambda constraint.
*
* @param lambda optional lambda to indicate a specific lambda
*/
public LambdaConstraint(Lambda lambda) {
this.lambda = lambda;
}
@Override
public boolean isValid(Link link, LinkResourceService resourceService) {
for (ResourceRequest request : resourceService.getAvailableResources(link)) {
if (request.type() == ResourceType.LAMBDA) {
return true;
}
}
return false;
}
/**
* Returns the lambda required by this constraint.
*
* @return required lambda
*/
public Lambda lambda() {
return lambda;
}
@Override
public int hashCode() {
return Objects.hash(lambda);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final LambdaConstraint other = (LambdaConstraint) obj;
return Objects.equals(this.lambda, other.lambda);
}
@Override
public String toString() {
return toStringHelper(this).add("lambda", lambda).toString();
}
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.onos.net.intent.constraint;
import com.google.common.collect.ImmutableSet;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.resource.LinkResourceService;
import java.util.Objects;
import java.util.Set;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Constraint that evaluates links based on their type.
*/
public class LinkTypeConstraint extends BooleanConstraint {
private final Set<Link.Type> types;
private final boolean isInclusive;
/**
* Creates a new constraint for requesting connectivity using or avoiding
* the specified link types.
*
* @param inclusive indicates whether the given link types are to be
* permitted or avoided
* @param types link types
*/
public LinkTypeConstraint(boolean inclusive, Link.Type... types) {
checkNotNull(types, "Link types cannot be null");
checkArgument(types.length > 0, "There must be more than one type");
this.types = ImmutableSet.copyOf(types);
this.isInclusive = inclusive;
}
@Override
public boolean isValid(Link link, LinkResourceService resourceService) {
boolean contains = types.contains(link.type());
return isInclusive ? contains : !contains;
}
/**
* Returns the set of link types.
*
* @return set of link types
*/
public Set<Link.Type> types() {
return types;
}
/**
* Indicates if the constraint is inclusive or exclusive.
*
* @return true if inclusive
*/
public boolean isInclusive() {
return isInclusive;
}
@Override
public int hashCode() {
return Objects.hash(types, isInclusive);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final LinkTypeConstraint other = (LinkTypeConstraint) obj;
return Objects.equals(this.types, other.types) && Objects.equals(this.isInclusive, other.isInclusive);
}
@Override
public String toString() {
return toStringHelper(this)
.add("inclusive", isInclusive)
.add("types", types)
.toString();
}
}
......@@ -20,9 +20,12 @@ import java.util.HashSet;
import java.util.Set;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.Constraint;
import org.onlab.onos.net.intent.IntentId;
import com.google.common.collect.ImmutableSet;
import org.onlab.onos.net.intent.constraint.BandwidthConstraint;
import org.onlab.onos.net.intent.constraint.LambdaConstraint;
/**
* Implementation of {@link LinkResourceRequest}.
......@@ -125,6 +128,18 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest {
return this;
}
@Override
public LinkResourceRequest.Builder addConstraint(Constraint constraint) {
if (constraint instanceof LambdaConstraint) {
return addLambdaRequest();
} else if (constraint instanceof BandwidthConstraint) {
BandwidthConstraint bw = (BandwidthConstraint) constraint;
return addBandwidthRequest(bw.bandwidth().toDouble());
}
return this;
}
/**
* Returns link resource request.
*
......
......@@ -19,6 +19,7 @@ import java.util.Collection;
import java.util.Set;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.Constraint;
import org.onlab.onos.net.intent.IntentId;
/**
......@@ -67,6 +68,14 @@ public interface LinkResourceRequest extends ResourceRequest {
public Builder addBandwidthRequest(double bandwidth);
/**
* Adds the resources required for a constraint.
*
* @param constraint the constraint
* @return self
*/
public Builder addConstraint(Constraint constraint);
/**
* Returns link resource request.
*
* @return link resource request
......
......@@ -18,7 +18,6 @@ package org.onlab.onos.net.intent;
import org.junit.Test;
import org.onlab.onos.net.NetTestTools;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.resource.LinkResourceRequest;
import static org.junit.Assert.assertEquals;
......@@ -40,11 +39,11 @@ public class PathIntentTest extends ConnectivityIntentTest {
@Override
protected PathIntent createOne() {
return new PathIntent(APPID, MATCH, NOP, PATH1, new LinkResourceRequest[0]);
return new PathIntent(APPID, MATCH, NOP, PATH1);
}
@Override
protected PathIntent createAnother() {
return new PathIntent(APPID, MATCH, NOP, PATH2, new LinkResourceRequest[0]);
return new PathIntent(APPID, MATCH, NOP, PATH2);
}
}
......
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.onos.net.intent.impl;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.net.ElementId;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.intent.ConnectivityIntent;
import org.onlab.onos.net.intent.Constraint;
import org.onlab.onos.net.intent.IntentCompiler;
import org.onlab.onos.net.intent.IntentExtensionService;
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.TopologyEdge;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* Base class for compilers of various
* {@link org.onlab.onos.net.intent.ConnectivityIntent connectivity intents}.
*/
@Component(immediate = true)
public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent>
implements IntentCompiler<T> {
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 LinkResourceService resourceService;
/**
* Returns an edge-weight capable of evaluating links on the basis of the
* specified constraints.
*
* @param constraints path constraints
* @return edge-weight function
*/
protected LinkWeight weight(List<Constraint> constraints) {
return new ConstraintBasedLinkWeight(constraints);
}
/**
* Validates the specified path against the given constraints.
*
* @param path path to be checked
* @return true if the path passes all constraints
*/
protected boolean checkPath(Path path, List<Constraint> constraints) {
for (Constraint constraint : constraints) {
if (!constraint.validate(path, resourceService)) {
return false;
}
}
return true;
}
/**
* Computes a path between two ConnectPoints.
*
* @param one start of the path
* @param two end of the path
* @return Path between the two
* @throws PathNotFoundException if a path cannot be found
*/
protected Path getPath(ConnectivityIntent intent,
ElementId one, ElementId two) {
Set<Path> paths = pathService.getPaths(one, two, weight(intent.constraints()));
if (paths.isEmpty()) {
throw new PathNotFoundException("No packet path from " + one + " to " + two);
}
// TODO: let's be more intelligent about this eventually
return paths.iterator().next();
}
/**
* Edge-weight capable of evaluating link cost using a set of constraints.
*/
protected class ConstraintBasedLinkWeight implements LinkWeight {
private final List<Constraint> constraints;
/**
* Creates a new edge-weight function capable of evaluating links
* on the basis of the specified constraints.
*
* @param constraints path constraints
*/
ConstraintBasedLinkWeight(List<Constraint> constraints) {
this.constraints = constraints;
}
@Override
public double weight(TopologyEdge edge) {
if (constraints == null) {
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) {
return -1;
}
}
return cost;
}
}
}
......@@ -15,30 +15,21 @@
*/
package org.onlab.onos.net.intent.impl;
import java.util.Arrays;
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.net.Host;
import org.onlab.onos.net.HostId;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.host.HostService;
import org.onlab.onos.net.intent.HostToHostIntent;
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.PathIntent;
import org.onlab.onos.net.topology.LinkWeight;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.topology.PathService;
import org.onlab.onos.net.topology.TopologyEdge;
import java.util.Arrays;
import java.util.List;
import static org.onlab.onos.net.flow.DefaultTrafficSelector.builder;
......@@ -47,13 +38,7 @@ import static org.onlab.onos.net.flow.DefaultTrafficSelector.builder;
*/
@Component(immediate = true)
public class HostToHostIntentCompiler
implements IntentCompiler<HostToHostIntent> {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentManager;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PathService pathService;
extends ConnectivityIntentCompiler<HostToHostIntent> {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
......@@ -70,8 +55,8 @@ public class HostToHostIntentCompiler
@Override
public List<Intent> compile(HostToHostIntent intent) {
Path pathOne = getPath(intent.one(), intent.two());
Path pathTwo = getPath(intent.two(), intent.one());
Path pathOne = getPath(intent, intent.one(), intent.two());
Path pathTwo = getPath(intent, intent.two(), intent.one());
Host one = hostService.getHost(intent.one());
Host two = hostService.getHost(intent.two());
......@@ -85,22 +70,7 @@ 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, new LinkResourceRequest[0]);
return new PathIntent(intent.appId(), selector, intent.treatment(), path);
}
private Path getPath(HostId one, HostId two) {
Set<Path> paths = pathService.getPaths(one, two, new LinkWeight() {
@Override
public double weight(TopologyEdge edge) {
return edge.link().type() == Link.Type.OPTICAL ? -1 : +1;
}
});
if (paths.isEmpty()) {
throw new PathNotFoundException("No path from host " + one + " to " + two);
}
// TODO: let's be more intelligent about this eventually
return paths.iterator().next();
}
}
......
......@@ -35,10 +35,13 @@ import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
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.IntentExtensionService;
import org.onlab.onos.net.intent.IntentInstaller;
import org.onlab.onos.net.intent.PathIntent;
import org.onlab.onos.net.resource.DefaultLinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceService;
import org.slf4j.Logger;
......@@ -79,13 +82,7 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
@Override
public List<FlowRuleBatchOperation> install(PathIntent intent) {
if (intent.resourceRequests().length > 0) {
LinkResourceAllocations allocations = allocateBandwidth(intent);
if (allocations == null) {
log.debug("Insufficient bandwidth available to install path intent {}", intent);
return null;
}
}
LinkResourceAllocations allocations = allocateResources(intent);
TrafficSelector.Builder builder =
DefaultTrafficSelector.builder(intent.selector());
......@@ -110,6 +107,10 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
@Override
public List<FlowRuleBatchOperation> uninstall(PathIntent intent) {
LinkResourceAllocations allocatedResources = resourceService.getAllocations(intent.id());
if (allocatedResources != null) {
resourceService.releaseResources(allocatedResources);
}
TrafficSelector.Builder builder =
DefaultTrafficSelector.builder(intent.selector());
Iterator<Link> links = intent.path().links().iterator();
......@@ -130,8 +131,23 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
}
private LinkResourceAllocations allocateBandwidth(PathIntent intent) {
return resourceService.requestResources(intent.resourceRequests()[0]);
/**
* Allocate resources required for an intent.
*
* @param intent intent to allocate resource for
* @return allocated resources if any are required, null otherwise
*/
private LinkResourceAllocations allocateResources(PathIntent intent) {
if (intent.constraints() == null) {
return null;
}
LinkResourceRequest.Builder builder =
DefaultLinkResourceRequest.builder(intent.id(), intent.path().links());
for (Constraint constraint : intent.constraints()) {
builder.addConstraint(constraint);
}
LinkResourceRequest request = builder.build();
return request.resources().isEmpty() ? null : resourceService.requestResources(request);
}
// TODO refactor below this line... ----------------------------
......
......@@ -15,31 +15,20 @@
*/
package org.onlab.onos.net.intent.impl;
import java.util.ArrayList;
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.net.ConnectPoint;
import org.onlab.onos.net.DefaultEdgeLink;
import org.onlab.onos.net.DefaultPath;
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.PathIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.resource.LinkResourceRequest;
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 java.util.ArrayList;
import java.util.List;
import static java.util.Arrays.asList;
......@@ -48,14 +37,11 @@ import static java.util.Arrays.asList;
*/
@Component(immediate = true)
public class PointToPointIntentCompiler
implements IntentCompiler<PointToPointIntent> {
private static final ProviderId PID = new ProviderId("core", "org.onlab.onos.core", true);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentManager;
extends ConnectivityIntentCompiler<PointToPointIntent> {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
// TODO: use off-the-shell core provider ID
private static final ProviderId PID =
new ProviderId("core", "org.onlab.onos.core", true);
@Activate
public void activate() {
......@@ -69,15 +55,16 @@ public class PointToPointIntentCompiler
@Override
public List<Intent> compile(PointToPointIntent intent) {
Path path = getPath(intent.ingressPoint(), intent.egressPoint());
Path path = getPath(intent, intent.ingressPoint().deviceId(),
intent.egressPoint().deviceId());
List<Link> links = new ArrayList<>();
links.add(DefaultEdgeLink.createEdgeLink(intent.ingressPoint(), true));
links.addAll(path.links());
links.add(DefaultEdgeLink.createEdgeLink(intent.egressPoint(), false));
return asList(createPathIntent(new DefaultPath(PID, links, path.cost() + 2,
path.annotations()), intent));
return asList(createPathIntent(new DefaultPath(PID, links, path.cost(),
path.annotations()), intent));
}
/**
......@@ -90,34 +77,7 @@ public class PointToPointIntentCompiler
private Intent createPathIntent(Path path,
PointToPointIntent intent) {
return new PathIntent(intent.appId(),
intent.selector(), intent.treatment(), path,
new LinkResourceRequest[0]);
intent.selector(), intent.treatment(), path);
}
/**
* Computes a path between two ConnectPoints.
*
* @param one start of the path
* @param two end of the path
* @return Path between the two
* @throws PathNotFoundException if a path cannot be found
*/
private Path getPath(ConnectPoint one, ConnectPoint two) {
Topology topology = topologyService.currentTopology();
LinkWeight weight = new LinkWeight() {
@Override
public double weight(TopologyEdge edge) {
return edge.link().type() == Link.Type.OPTICAL ? -1 : +1;
}
};
Set<Path> paths = topologyService.getPaths(topology, one.deviceId(),
two.deviceId(), weight);
if (paths.isEmpty()) {
throw new PathNotFoundException("No packet path from " + one + " to " + two);
}
// TODO: let's be more intelligent about this eventually
return paths.iterator().next();
}
}
......
package org.onlab.onos.net.intent.impl;
import java.util.ArrayList;
import java.util.Arrays;
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.net.ConnectPoint;
import org.onlab.onos.net.DefaultEdgeLink;
import org.onlab.onos.net.DefaultPath;
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.PathIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.onos.net.intent.PointToPointIntentWithBandwidthConstraint;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.resource.BandwidthResourceRequest;
import org.onlab.onos.net.resource.DefaultLinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.resource.ResourceRequest;
import org.onlab.onos.net.resource.ResourceType;
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;
/**
* A intent compiler for {@link org.onlab.onos.net.intent.HostToHostIntent}.
*/
@Component(immediate = true)
public class PointToPointIntentWithBandwidthConstraintCompiler
implements IntentCompiler<PointToPointIntentWithBandwidthConstraint> {
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 TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceService;
@Activate
public void activate() {
intentManager.registerCompiler(PointToPointIntentWithBandwidthConstraint.class, this);
}
@Deactivate
public void deactivate() {
intentManager.unregisterCompiler(PointToPointIntent.class);
}
@Override
public List<Intent> compile(PointToPointIntentWithBandwidthConstraint intent) {
Path path = getPath(intent.ingressPoint(), intent.egressPoint(), intent.bandwidthRequest());
List<Link> links = new ArrayList<>();
links.add(DefaultEdgeLink.createEdgeLink(intent.ingressPoint(), true));
links.addAll(path.links());
links.add(DefaultEdgeLink.createEdgeLink(intent.egressPoint(), false));
return Arrays.asList(createPathIntent(new DefaultPath(PID, links, path.cost() + 2,
path.annotations()),
intent));
}
/**
* Creates a path intent from the specified path and original
* connectivity intent.
*
* @param path path to create an intent for
* @param intent original intent
*/
private Intent createPathIntent(Path path,
PointToPointIntentWithBandwidthConstraint intent) {
LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
path.links())
// TODO - this seems awkward, maybe allow directly attaching a BandwidthRequest
.addBandwidthRequest(intent.bandwidthRequest().bandwidth().toDouble());
LinkResourceRequest bandwidthRequest = request.build();
LinkResourceRequest[] bandwidthRequests = {bandwidthRequest};
return new PathIntent(intent.appId(),
intent.selector(), intent.treatment(), path,
bandwidthRequests);
}
/**
* Computes a path between two ConnectPoints.
*
* @param one start of the path
* @param two end of the path
* @return Path between the two
* @throws org.onlab.onos.net.intent.impl.PathNotFoundException if a path cannot be found
*/
private Path getPath(ConnectPoint one, ConnectPoint two, final BandwidthResourceRequest bandwidthRequest) {
Topology topology = topologyService.currentTopology();
LinkWeight weight = new LinkWeight() {
@Override
public double weight(TopologyEdge edge) {
if (bandwidthRequest != null) {
double allocatedBandwidth = 0.0;
Iterable<ResourceRequest> availableResources = resourceService.getAvailableResources(edge.link());
for (ResourceRequest availableResource : availableResources) {
if (availableResource.type() == ResourceType.BANDWIDTH) {
BandwidthResourceRequest bandwidthRequest = (BandwidthResourceRequest) availableResource;
allocatedBandwidth += bandwidthRequest.bandwidth().toDouble();
}
}
// TODO this needs to be discovered from switch/ports somehow
double maxBandwidth = 1000;
double availableBandwidth = maxBandwidth - allocatedBandwidth;
if (availableBandwidth >= bandwidthRequest.bandwidth().toDouble()) {
return 1;
} else {
return -1;
}
} else {
return 1;
}
}
};
Set<Path> paths = topologyService.getPaths(topology,
one.deviceId(),
two.deviceId(),
weight);
if (paths.isEmpty()) {
throw new PathNotFoundException("No packet path from " + one + " to " + two);
}
// TODO: let's be more intelligent about this eventually
return paths.iterator().next();
}
}