helenyrwu
Committed by Gerrit Code Review

Implement path protection for point to point intents

Change-Id: I3f3627e7c2a7e3ab017e46655692ab70fdeae413
......@@ -17,6 +17,7 @@ package org.onosproject.cli.net;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
......@@ -24,6 +25,7 @@ import org.onosproject.net.intent.Constraint;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.PointToPointIntent;
import org.onosproject.net.intent.constraint.ProtectionConstraint;
import java.util.List;
......@@ -44,6 +46,11 @@ public class AddPointToPointIntentCommand extends ConnectivityIntentCommand {
required = true, multiValued = false)
String egressDeviceString = null;
@Option(name = "-p", aliases = "--protect",
description = "Utilize path protection",
required = false, multiValued = false)
private boolean backup = false;
@Override
protected void execute() {
IntentService service = get(IntentService.class);
......@@ -56,6 +63,9 @@ public class AddPointToPointIntentCommand extends ConnectivityIntentCommand {
TrafficTreatment treatment = buildTrafficTreatment();
List<Constraint> constraints = buildConstraints();
if (backup) {
constraints.add(new ProtectionConstraint());
}
Intent intent = PointToPointIntent.builder()
.appId(appId())
......
......@@ -35,6 +35,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class FlowRuleIntent extends Intent {
private final Collection<FlowRule> flowRules;
private PathIntent.ProtectionType type;
/**
* Creates a flow rule intent with the specified flow rules and resources.
......@@ -48,7 +49,19 @@ public class FlowRuleIntent extends Intent {
}
/**
* Creates an flow rule intent with the specified key, flow rules to be set, and
* Creates a flow rule intent with the specified flow rules, resources, and type.
*
* @param appId application id
* @param flowRules flow rules to be set
* @param resources network resource to be set
*/
public FlowRuleIntent(ApplicationId appId, List<FlowRule> flowRules, Collection<NetworkResource> resources,
PathIntent.ProtectionType type) {
this(appId, null, flowRules, resources, type);
}
/**
* Creates a flow rule intent with the specified key, flow rules to be set, and
* required network resources.
*
* @param appId application id
......@@ -58,8 +71,32 @@ public class FlowRuleIntent extends Intent {
*/
public FlowRuleIntent(ApplicationId appId, Key key, Collection<FlowRule> flowRules,
Collection<NetworkResource> resources) {
this(appId, key, flowRules, resources, PathIntent.ProtectionType.PRIMARY);
}
/**
* Creates a flow rule intent with the specified key, flow rules to be set, and
* required network resources.
*
* @param appId application id
* @param key key
* @param flowRules flow rules
* @param resources network resources
*/
public FlowRuleIntent(ApplicationId appId, Key key, Collection<FlowRule> flowRules,
Collection<NetworkResource> resources, PathIntent.ProtectionType primary) {
super(appId, key, resources, DEFAULT_INTENT_PRIORITY);
this.flowRules = ImmutableList.copyOf(checkNotNull(flowRules));
this.type = primary;
}
/**
* Creates a flow rule intent with all the same characteristics as the given
* one except for the flow rule type.
*/
public FlowRuleIntent(FlowRuleIntent intent, PathIntent.ProtectionType type) {
this(intent.appId(), intent.key(), intent.flowRules(),
intent.resources(), type);
}
/**
......@@ -68,6 +105,7 @@ public class FlowRuleIntent extends Intent {
protected FlowRuleIntent() {
super();
this.flowRules = null;
this.type = PathIntent.ProtectionType.PRIMARY;
}
/**
......@@ -84,6 +122,10 @@ public class FlowRuleIntent extends Intent {
return true;
}
public PathIntent.ProtectionType type() {
return type;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
......
......@@ -31,7 +31,7 @@ public interface IntentCompiler<T extends Intent> {
* Compiles the specified intent into other intents.
*
* @param intent intent to be compiled
* @param installable previously compilation result; optional
* @param installable previous compilation result; optional
* @return list of resulting intents
* @throws IntentException if issues are encountered while compiling the intent
*/
......
......@@ -36,10 +36,11 @@ import static com.google.common.base.Preconditions.checkArgument;
public class PathIntent extends ConnectivityIntent {
private final Path path;
private ProtectionType type;
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports and using the specified explicit path.
* ports and using the specified explicit path. Path is primary by default.
*
* @param appId application identifier
* @param key intent key
......@@ -57,10 +58,38 @@ public class PathIntent extends ConnectivityIntent {
Path path,
List<Constraint> constraints,
int priority) {
this(appId, key, selector, treatment, path, constraints, priority,
ProtectionType.PRIMARY);
}
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports and using the specified explicit path, which can be classified
* as PRIMARY or BACKUP.
*
* @param appId application identifier
* @param key intent key
* @param selector traffic selector
* @param treatment treatment
* @param path traversed links
* @param constraints optional list of constraints
* @param priority priority to use for the generated flows
* @param type PRIMARY or BACKUP
* @throws NullPointerException {@code path} is null
*/
protected PathIntent(ApplicationId appId,
Key key,
TrafficSelector selector,
TrafficTreatment treatment,
Path path,
List<Constraint> constraints,
int priority,
ProtectionType type) {
super(appId, key, resources(path.links()), selector, treatment, constraints,
priority);
PathIntent.validate(path.links());
this.path = path;
this.type = type;
}
/**
......@@ -69,6 +98,7 @@ public class PathIntent extends ConnectivityIntent {
protected PathIntent() {
super();
this.path = null;
this.type = ProtectionType.PRIMARY;
}
/**
......@@ -85,6 +115,7 @@ public class PathIntent extends ConnectivityIntent {
*/
public static class Builder extends ConnectivityIntent.Builder {
Path path;
ProtectionType type;
protected Builder() {
// Hide default constructor
......@@ -131,6 +162,11 @@ public class PathIntent extends ConnectivityIntent {
return this;
}
public Builder setType(ProtectionType type) {
this.type = type;
return this;
}
/**
* Builds a path intent from the accumulated parameters.
*
......@@ -145,7 +181,8 @@ public class PathIntent extends ConnectivityIntent {
treatment,
path,
constraints,
priority
priority,
type == null ? ProtectionType.PRIMARY : type
);
}
}
......@@ -183,6 +220,10 @@ public class PathIntent extends ConnectivityIntent {
return path;
}
public ProtectionType type() {
return type;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
......@@ -195,7 +236,25 @@ public class PathIntent extends ConnectivityIntent {
.add("treatment", treatment())
.add("constraints", constraints())
.add("path", path)
.add("type", type)
.toString();
}
// for path protection purposes
public enum ProtectionType {
/**
* Intent within primary path.
*/
PRIMARY,
/**
* Intent within backup path.
*/
BACKUP,
/**
* Intent whose flow rule serves as the fast failover
* between primary and backup paths.
*/
FAILOVER
}
}
......
/*
* Copyright 2016-present 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.onosproject.net.intent.constraint;
import com.google.common.annotations.Beta;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
import org.onosproject.net.intent.Constraint;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.PointToPointIntent;
import org.onosproject.net.intent.ResourceContext;
/**
* Constraint that determines whether to employ path protection.
*/
@Beta
public class ProtectionConstraint implements Constraint {
// doesn't use LinkResourceService
@Override
public double cost(Link link, ResourceContext context) {
return 1;
}
// doesn't use LinkResourceService
@Override
public boolean validate(Path path, ResourceContext context) {
return true;
}
/**
* Determines whether to utilize path protection for the given intent.
*
* @param intent intent to be inspected
* @return whether the intent has a ProtectionConstraint
*/
public static boolean requireProtectedPath(Intent intent) {
if (intent instanceof PointToPointIntent) {
PointToPointIntent pointToPointIntent = (PointToPointIntent) intent;
return pointToPointIntent.constraints().stream()
.anyMatch(p -> p instanceof ProtectionConstraint);
}
return false;
}
}
......@@ -26,7 +26,7 @@ import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBa
public class PointToPointIntentTest extends ConnectivityIntentTest {
/**
* Checks that the MultiPointToSinglePointIntent class is immutable.
* Checks that the PointToPointIntent class is immutable.
*/
@Test
public void checkImmutability() {
......
......@@ -28,8 +28,11 @@ import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.CoreService;
import org.onosproject.core.IdGenerator;
import org.onosproject.event.AbstractListenerManager;
import org.onosproject.net.DeviceId;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupService;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentBatchDelegate;
import org.onosproject.net.intent.IntentCompiler;
......@@ -42,6 +45,8 @@ import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.IntentStore;
import org.onosproject.net.intent.IntentStoreDelegate;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.PointToPointIntent;
import org.onosproject.net.intent.impl.compiler.PointToPointIntentCompiler;
import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
import org.osgi.service.component.ComponentContext;
......@@ -123,6 +128,9 @@ public class IntentManager
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ComponentConfigService configService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected GroupService groupService;
private ExecutorService batchExecutor;
private ExecutorService workerExecutor;
......@@ -234,6 +242,15 @@ public class IntentManager
checkNotNull(intent, INTENT_NULL);
IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
store.addPending(data);
// remove associated group if there is one
if (intent instanceof PointToPointIntent) {
PointToPointIntent pointIntent = (PointToPointIntent) intent;
DeviceId deviceId = pointIntent.ingressPoint().deviceId();
GroupKey groupKey = PointToPointIntentCompiler.makeGroupKey(intent.id());
groupService.removeGroup(deviceId, groupKey,
intent.appId());
}
}
@Override
......
......@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableList;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onosproject.net.DisjointPath;
import org.onosproject.net.ElementId;
import org.onosproject.net.Path;
import org.onosproject.net.intent.ConnectivityIntent;
......@@ -108,6 +109,29 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent>
}
/**
* Computes a disjoint path between two ConnectPoints.
*
* @param intent intent on which behalf path is being computed
* @param one start of the path
* @param two end of the path
* @return DisjointPath between the two
* @throws PathNotFoundException if two paths cannot be found
*/
protected DisjointPath getDisjointPath(ConnectivityIntent intent,
ElementId one, ElementId two) {
Set<DisjointPath> paths = pathService.getDisjointPaths(one, two, weight(intent.constraints()));
final List<Constraint> constraints = intent.constraints();
ImmutableList<DisjointPath> filtered = FluentIterable.from(paths)
.filter(path -> checkPath(path, constraints))
.toList();
if (filtered.isEmpty()) {
throw new PathNotFoundException(one, two);
}
// TODO: let's be more intelligent about this eventually
return filtered.iterator().next();
}
/**
* Edge-weight capable of evaluating link cost using a set of constraints.
*/
protected class ConstraintBasedLinkWeight implements LinkWeight {
......
......@@ -82,7 +82,7 @@ public class PathIntentCompiler
compile(this, intent, rules, devices);
return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources()));
return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources(), intent.type()));
}
@Override
......