Committed by
Gerrit Code Review
Implement path protection for point to point intents
Change-Id: I3f3627e7c2a7e3ab017e46655692ab70fdeae413
Showing
10 changed files
with
665 additions
and
12 deletions
... | @@ -17,6 +17,7 @@ package org.onosproject.cli.net; | ... | @@ -17,6 +17,7 @@ package org.onosproject.cli.net; |
17 | 17 | ||
18 | import org.apache.karaf.shell.commands.Argument; | 18 | import org.apache.karaf.shell.commands.Argument; |
19 | import org.apache.karaf.shell.commands.Command; | 19 | import org.apache.karaf.shell.commands.Command; |
20 | +import org.apache.karaf.shell.commands.Option; | ||
20 | import org.onosproject.net.ConnectPoint; | 21 | import org.onosproject.net.ConnectPoint; |
21 | import org.onosproject.net.flow.TrafficSelector; | 22 | import org.onosproject.net.flow.TrafficSelector; |
22 | import org.onosproject.net.flow.TrafficTreatment; | 23 | import org.onosproject.net.flow.TrafficTreatment; |
... | @@ -24,6 +25,7 @@ import org.onosproject.net.intent.Constraint; | ... | @@ -24,6 +25,7 @@ import org.onosproject.net.intent.Constraint; |
24 | import org.onosproject.net.intent.Intent; | 25 | import org.onosproject.net.intent.Intent; |
25 | import org.onosproject.net.intent.IntentService; | 26 | import org.onosproject.net.intent.IntentService; |
26 | import org.onosproject.net.intent.PointToPointIntent; | 27 | import org.onosproject.net.intent.PointToPointIntent; |
28 | +import org.onosproject.net.intent.constraint.ProtectionConstraint; | ||
27 | 29 | ||
28 | import java.util.List; | 30 | import java.util.List; |
29 | 31 | ||
... | @@ -44,6 +46,11 @@ public class AddPointToPointIntentCommand extends ConnectivityIntentCommand { | ... | @@ -44,6 +46,11 @@ public class AddPointToPointIntentCommand extends ConnectivityIntentCommand { |
44 | required = true, multiValued = false) | 46 | required = true, multiValued = false) |
45 | String egressDeviceString = null; | 47 | String egressDeviceString = null; |
46 | 48 | ||
49 | + @Option(name = "-p", aliases = "--protect", | ||
50 | + description = "Utilize path protection", | ||
51 | + required = false, multiValued = false) | ||
52 | + private boolean backup = false; | ||
53 | + | ||
47 | @Override | 54 | @Override |
48 | protected void execute() { | 55 | protected void execute() { |
49 | IntentService service = get(IntentService.class); | 56 | IntentService service = get(IntentService.class); |
... | @@ -56,6 +63,9 @@ public class AddPointToPointIntentCommand extends ConnectivityIntentCommand { | ... | @@ -56,6 +63,9 @@ public class AddPointToPointIntentCommand extends ConnectivityIntentCommand { |
56 | TrafficTreatment treatment = buildTrafficTreatment(); | 63 | TrafficTreatment treatment = buildTrafficTreatment(); |
57 | 64 | ||
58 | List<Constraint> constraints = buildConstraints(); | 65 | List<Constraint> constraints = buildConstraints(); |
66 | + if (backup) { | ||
67 | + constraints.add(new ProtectionConstraint()); | ||
68 | + } | ||
59 | 69 | ||
60 | Intent intent = PointToPointIntent.builder() | 70 | Intent intent = PointToPointIntent.builder() |
61 | .appId(appId()) | 71 | .appId(appId()) | ... | ... |
... | @@ -35,6 +35,7 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -35,6 +35,7 @@ import static com.google.common.base.Preconditions.checkNotNull; |
35 | public class FlowRuleIntent extends Intent { | 35 | public class FlowRuleIntent extends Intent { |
36 | 36 | ||
37 | private final Collection<FlowRule> flowRules; | 37 | private final Collection<FlowRule> flowRules; |
38 | + private PathIntent.ProtectionType type; | ||
38 | 39 | ||
39 | /** | 40 | /** |
40 | * Creates a flow rule intent with the specified flow rules and resources. | 41 | * Creates a flow rule intent with the specified flow rules and resources. |
... | @@ -48,7 +49,19 @@ public class FlowRuleIntent extends Intent { | ... | @@ -48,7 +49,19 @@ public class FlowRuleIntent extends Intent { |
48 | } | 49 | } |
49 | 50 | ||
50 | /** | 51 | /** |
51 | - * Creates an flow rule intent with the specified key, flow rules to be set, and | 52 | + * Creates a flow rule intent with the specified flow rules, resources, and type. |
53 | + * | ||
54 | + * @param appId application id | ||
55 | + * @param flowRules flow rules to be set | ||
56 | + * @param resources network resource to be set | ||
57 | + */ | ||
58 | + public FlowRuleIntent(ApplicationId appId, List<FlowRule> flowRules, Collection<NetworkResource> resources, | ||
59 | + PathIntent.ProtectionType type) { | ||
60 | + this(appId, null, flowRules, resources, type); | ||
61 | + } | ||
62 | + | ||
63 | + /** | ||
64 | + * Creates a flow rule intent with the specified key, flow rules to be set, and | ||
52 | * required network resources. | 65 | * required network resources. |
53 | * | 66 | * |
54 | * @param appId application id | 67 | * @param appId application id |
... | @@ -58,8 +71,32 @@ public class FlowRuleIntent extends Intent { | ... | @@ -58,8 +71,32 @@ public class FlowRuleIntent extends Intent { |
58 | */ | 71 | */ |
59 | public FlowRuleIntent(ApplicationId appId, Key key, Collection<FlowRule> flowRules, | 72 | public FlowRuleIntent(ApplicationId appId, Key key, Collection<FlowRule> flowRules, |
60 | Collection<NetworkResource> resources) { | 73 | Collection<NetworkResource> resources) { |
74 | + this(appId, key, flowRules, resources, PathIntent.ProtectionType.PRIMARY); | ||
75 | + } | ||
76 | + | ||
77 | + /** | ||
78 | + * Creates a flow rule intent with the specified key, flow rules to be set, and | ||
79 | + * required network resources. | ||
80 | + * | ||
81 | + * @param appId application id | ||
82 | + * @param key key | ||
83 | + * @param flowRules flow rules | ||
84 | + * @param resources network resources | ||
85 | + */ | ||
86 | + public FlowRuleIntent(ApplicationId appId, Key key, Collection<FlowRule> flowRules, | ||
87 | + Collection<NetworkResource> resources, PathIntent.ProtectionType primary) { | ||
61 | super(appId, key, resources, DEFAULT_INTENT_PRIORITY); | 88 | super(appId, key, resources, DEFAULT_INTENT_PRIORITY); |
62 | this.flowRules = ImmutableList.copyOf(checkNotNull(flowRules)); | 89 | this.flowRules = ImmutableList.copyOf(checkNotNull(flowRules)); |
90 | + this.type = primary; | ||
91 | + } | ||
92 | + | ||
93 | + /** | ||
94 | + * Creates a flow rule intent with all the same characteristics as the given | ||
95 | + * one except for the flow rule type. | ||
96 | + */ | ||
97 | + public FlowRuleIntent(FlowRuleIntent intent, PathIntent.ProtectionType type) { | ||
98 | + this(intent.appId(), intent.key(), intent.flowRules(), | ||
99 | + intent.resources(), type); | ||
63 | } | 100 | } |
64 | 101 | ||
65 | /** | 102 | /** |
... | @@ -68,6 +105,7 @@ public class FlowRuleIntent extends Intent { | ... | @@ -68,6 +105,7 @@ public class FlowRuleIntent extends Intent { |
68 | protected FlowRuleIntent() { | 105 | protected FlowRuleIntent() { |
69 | super(); | 106 | super(); |
70 | this.flowRules = null; | 107 | this.flowRules = null; |
108 | + this.type = PathIntent.ProtectionType.PRIMARY; | ||
71 | } | 109 | } |
72 | 110 | ||
73 | /** | 111 | /** |
... | @@ -84,6 +122,10 @@ public class FlowRuleIntent extends Intent { | ... | @@ -84,6 +122,10 @@ public class FlowRuleIntent extends Intent { |
84 | return true; | 122 | return true; |
85 | } | 123 | } |
86 | 124 | ||
125 | + public PathIntent.ProtectionType type() { | ||
126 | + return type; | ||
127 | + } | ||
128 | + | ||
87 | @Override | 129 | @Override |
88 | public String toString() { | 130 | public String toString() { |
89 | return MoreObjects.toStringHelper(this) | 131 | return MoreObjects.toStringHelper(this) | ... | ... |
... | @@ -31,7 +31,7 @@ public interface IntentCompiler<T extends Intent> { | ... | @@ -31,7 +31,7 @@ public interface IntentCompiler<T extends Intent> { |
31 | * Compiles the specified intent into other intents. | 31 | * Compiles the specified intent into other intents. |
32 | * | 32 | * |
33 | * @param intent intent to be compiled | 33 | * @param intent intent to be compiled |
34 | - * @param installable previously compilation result; optional | 34 | + * @param installable previous compilation result; optional |
35 | * @return list of resulting intents | 35 | * @return list of resulting intents |
36 | * @throws IntentException if issues are encountered while compiling the intent | 36 | * @throws IntentException if issues are encountered while compiling the intent |
37 | */ | 37 | */ | ... | ... |
... | @@ -36,10 +36,11 @@ import static com.google.common.base.Preconditions.checkArgument; | ... | @@ -36,10 +36,11 @@ import static com.google.common.base.Preconditions.checkArgument; |
36 | public class PathIntent extends ConnectivityIntent { | 36 | public class PathIntent extends ConnectivityIntent { |
37 | 37 | ||
38 | private final Path path; | 38 | private final Path path; |
39 | + private ProtectionType type; | ||
39 | 40 | ||
40 | /** | 41 | /** |
41 | * Creates a new point-to-point intent with the supplied ingress/egress | 42 | * Creates a new point-to-point intent with the supplied ingress/egress |
42 | - * ports and using the specified explicit path. | 43 | + * ports and using the specified explicit path. Path is primary by default. |
43 | * | 44 | * |
44 | * @param appId application identifier | 45 | * @param appId application identifier |
45 | * @param key intent key | 46 | * @param key intent key |
... | @@ -57,10 +58,38 @@ public class PathIntent extends ConnectivityIntent { | ... | @@ -57,10 +58,38 @@ public class PathIntent extends ConnectivityIntent { |
57 | Path path, | 58 | Path path, |
58 | List<Constraint> constraints, | 59 | List<Constraint> constraints, |
59 | int priority) { | 60 | int priority) { |
61 | + this(appId, key, selector, treatment, path, constraints, priority, | ||
62 | + ProtectionType.PRIMARY); | ||
63 | + } | ||
64 | + | ||
65 | + /** | ||
66 | + * Creates a new point-to-point intent with the supplied ingress/egress | ||
67 | + * ports and using the specified explicit path, which can be classified | ||
68 | + * as PRIMARY or BACKUP. | ||
69 | + * | ||
70 | + * @param appId application identifier | ||
71 | + * @param key intent key | ||
72 | + * @param selector traffic selector | ||
73 | + * @param treatment treatment | ||
74 | + * @param path traversed links | ||
75 | + * @param constraints optional list of constraints | ||
76 | + * @param priority priority to use for the generated flows | ||
77 | + * @param type PRIMARY or BACKUP | ||
78 | + * @throws NullPointerException {@code path} is null | ||
79 | + */ | ||
80 | + protected PathIntent(ApplicationId appId, | ||
81 | + Key key, | ||
82 | + TrafficSelector selector, | ||
83 | + TrafficTreatment treatment, | ||
84 | + Path path, | ||
85 | + List<Constraint> constraints, | ||
86 | + int priority, | ||
87 | + ProtectionType type) { | ||
60 | super(appId, key, resources(path.links()), selector, treatment, constraints, | 88 | super(appId, key, resources(path.links()), selector, treatment, constraints, |
61 | - priority); | 89 | + priority); |
62 | PathIntent.validate(path.links()); | 90 | PathIntent.validate(path.links()); |
63 | this.path = path; | 91 | this.path = path; |
92 | + this.type = type; | ||
64 | } | 93 | } |
65 | 94 | ||
66 | /** | 95 | /** |
... | @@ -69,6 +98,7 @@ public class PathIntent extends ConnectivityIntent { | ... | @@ -69,6 +98,7 @@ public class PathIntent extends ConnectivityIntent { |
69 | protected PathIntent() { | 98 | protected PathIntent() { |
70 | super(); | 99 | super(); |
71 | this.path = null; | 100 | this.path = null; |
101 | + this.type = ProtectionType.PRIMARY; | ||
72 | } | 102 | } |
73 | 103 | ||
74 | /** | 104 | /** |
... | @@ -85,6 +115,7 @@ public class PathIntent extends ConnectivityIntent { | ... | @@ -85,6 +115,7 @@ public class PathIntent extends ConnectivityIntent { |
85 | */ | 115 | */ |
86 | public static class Builder extends ConnectivityIntent.Builder { | 116 | public static class Builder extends ConnectivityIntent.Builder { |
87 | Path path; | 117 | Path path; |
118 | + ProtectionType type; | ||
88 | 119 | ||
89 | protected Builder() { | 120 | protected Builder() { |
90 | // Hide default constructor | 121 | // Hide default constructor |
... | @@ -131,6 +162,11 @@ public class PathIntent extends ConnectivityIntent { | ... | @@ -131,6 +162,11 @@ public class PathIntent extends ConnectivityIntent { |
131 | return this; | 162 | return this; |
132 | } | 163 | } |
133 | 164 | ||
165 | + public Builder setType(ProtectionType type) { | ||
166 | + this.type = type; | ||
167 | + return this; | ||
168 | + } | ||
169 | + | ||
134 | /** | 170 | /** |
135 | * Builds a path intent from the accumulated parameters. | 171 | * Builds a path intent from the accumulated parameters. |
136 | * | 172 | * |
... | @@ -145,7 +181,8 @@ public class PathIntent extends ConnectivityIntent { | ... | @@ -145,7 +181,8 @@ public class PathIntent extends ConnectivityIntent { |
145 | treatment, | 181 | treatment, |
146 | path, | 182 | path, |
147 | constraints, | 183 | constraints, |
148 | - priority | 184 | + priority, |
185 | + type == null ? ProtectionType.PRIMARY : type | ||
149 | ); | 186 | ); |
150 | } | 187 | } |
151 | } | 188 | } |
... | @@ -183,6 +220,10 @@ public class PathIntent extends ConnectivityIntent { | ... | @@ -183,6 +220,10 @@ public class PathIntent extends ConnectivityIntent { |
183 | return path; | 220 | return path; |
184 | } | 221 | } |
185 | 222 | ||
223 | + public ProtectionType type() { | ||
224 | + return type; | ||
225 | + } | ||
226 | + | ||
186 | @Override | 227 | @Override |
187 | public String toString() { | 228 | public String toString() { |
188 | return MoreObjects.toStringHelper(getClass()) | 229 | return MoreObjects.toStringHelper(getClass()) |
... | @@ -195,7 +236,25 @@ public class PathIntent extends ConnectivityIntent { | ... | @@ -195,7 +236,25 @@ public class PathIntent extends ConnectivityIntent { |
195 | .add("treatment", treatment()) | 236 | .add("treatment", treatment()) |
196 | .add("constraints", constraints()) | 237 | .add("constraints", constraints()) |
197 | .add("path", path) | 238 | .add("path", path) |
239 | + .add("type", type) | ||
198 | .toString(); | 240 | .toString(); |
199 | } | 241 | } |
200 | 242 | ||
243 | + // for path protection purposes | ||
244 | + public enum ProtectionType { | ||
245 | + /** | ||
246 | + * Intent within primary path. | ||
247 | + */ | ||
248 | + PRIMARY, | ||
249 | + /** | ||
250 | + * Intent within backup path. | ||
251 | + */ | ||
252 | + BACKUP, | ||
253 | + /** | ||
254 | + * Intent whose flow rule serves as the fast failover | ||
255 | + * between primary and backup paths. | ||
256 | + */ | ||
257 | + FAILOVER | ||
258 | + } | ||
259 | + | ||
201 | } | 260 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2016-present Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package org.onosproject.net.intent.constraint; | ||
18 | + | ||
19 | +import com.google.common.annotations.Beta; | ||
20 | +import org.onosproject.net.Link; | ||
21 | +import org.onosproject.net.Path; | ||
22 | +import org.onosproject.net.intent.Constraint; | ||
23 | +import org.onosproject.net.intent.Intent; | ||
24 | +import org.onosproject.net.intent.PointToPointIntent; | ||
25 | +import org.onosproject.net.intent.ResourceContext; | ||
26 | + | ||
27 | +/** | ||
28 | + * Constraint that determines whether to employ path protection. | ||
29 | + */ | ||
30 | +@Beta | ||
31 | +public class ProtectionConstraint implements Constraint { | ||
32 | + // doesn't use LinkResourceService | ||
33 | + @Override | ||
34 | + public double cost(Link link, ResourceContext context) { | ||
35 | + return 1; | ||
36 | + } | ||
37 | + | ||
38 | + // doesn't use LinkResourceService | ||
39 | + @Override | ||
40 | + public boolean validate(Path path, ResourceContext context) { | ||
41 | + return true; | ||
42 | + } | ||
43 | + | ||
44 | + /** | ||
45 | + * Determines whether to utilize path protection for the given intent. | ||
46 | + * | ||
47 | + * @param intent intent to be inspected | ||
48 | + * @return whether the intent has a ProtectionConstraint | ||
49 | + */ | ||
50 | + public static boolean requireProtectedPath(Intent intent) { | ||
51 | + if (intent instanceof PointToPointIntent) { | ||
52 | + PointToPointIntent pointToPointIntent = (PointToPointIntent) intent; | ||
53 | + return pointToPointIntent.constraints().stream() | ||
54 | + .anyMatch(p -> p instanceof ProtectionConstraint); | ||
55 | + } | ||
56 | + return false; | ||
57 | + } | ||
58 | +} |
... | @@ -26,7 +26,7 @@ import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBa | ... | @@ -26,7 +26,7 @@ import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBa |
26 | public class PointToPointIntentTest extends ConnectivityIntentTest { | 26 | public class PointToPointIntentTest extends ConnectivityIntentTest { |
27 | 27 | ||
28 | /** | 28 | /** |
29 | - * Checks that the MultiPointToSinglePointIntent class is immutable. | 29 | + * Checks that the PointToPointIntent class is immutable. |
30 | */ | 30 | */ |
31 | @Test | 31 | @Test |
32 | public void checkImmutability() { | 32 | public void checkImmutability() { | ... | ... |
... | @@ -28,8 +28,11 @@ import org.onosproject.cfg.ComponentConfigService; | ... | @@ -28,8 +28,11 @@ import org.onosproject.cfg.ComponentConfigService; |
28 | import org.onosproject.core.CoreService; | 28 | import org.onosproject.core.CoreService; |
29 | import org.onosproject.core.IdGenerator; | 29 | import org.onosproject.core.IdGenerator; |
30 | import org.onosproject.event.AbstractListenerManager; | 30 | import org.onosproject.event.AbstractListenerManager; |
31 | +import org.onosproject.net.DeviceId; | ||
31 | import org.onosproject.net.flow.FlowRuleService; | 32 | import org.onosproject.net.flow.FlowRuleService; |
32 | import org.onosproject.net.flowobjective.FlowObjectiveService; | 33 | import org.onosproject.net.flowobjective.FlowObjectiveService; |
34 | +import org.onosproject.net.group.GroupKey; | ||
35 | +import org.onosproject.net.group.GroupService; | ||
33 | import org.onosproject.net.intent.Intent; | 36 | import org.onosproject.net.intent.Intent; |
34 | import org.onosproject.net.intent.IntentBatchDelegate; | 37 | import org.onosproject.net.intent.IntentBatchDelegate; |
35 | import org.onosproject.net.intent.IntentCompiler; | 38 | import org.onosproject.net.intent.IntentCompiler; |
... | @@ -42,6 +45,8 @@ import org.onosproject.net.intent.IntentState; | ... | @@ -42,6 +45,8 @@ import org.onosproject.net.intent.IntentState; |
42 | import org.onosproject.net.intent.IntentStore; | 45 | import org.onosproject.net.intent.IntentStore; |
43 | import org.onosproject.net.intent.IntentStoreDelegate; | 46 | import org.onosproject.net.intent.IntentStoreDelegate; |
44 | import org.onosproject.net.intent.Key; | 47 | import org.onosproject.net.intent.Key; |
48 | +import org.onosproject.net.intent.PointToPointIntent; | ||
49 | +import org.onosproject.net.intent.impl.compiler.PointToPointIntentCompiler; | ||
45 | import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase; | 50 | import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase; |
46 | import org.onosproject.net.intent.impl.phase.IntentProcessPhase; | 51 | import org.onosproject.net.intent.impl.phase.IntentProcessPhase; |
47 | import org.osgi.service.component.ComponentContext; | 52 | import org.osgi.service.component.ComponentContext; |
... | @@ -123,6 +128,9 @@ public class IntentManager | ... | @@ -123,6 +128,9 @@ public class IntentManager |
123 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 128 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
124 | protected ComponentConfigService configService; | 129 | protected ComponentConfigService configService; |
125 | 130 | ||
131 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
132 | + protected GroupService groupService; | ||
133 | + | ||
126 | private ExecutorService batchExecutor; | 134 | private ExecutorService batchExecutor; |
127 | private ExecutorService workerExecutor; | 135 | private ExecutorService workerExecutor; |
128 | 136 | ||
... | @@ -234,6 +242,15 @@ public class IntentManager | ... | @@ -234,6 +242,15 @@ public class IntentManager |
234 | checkNotNull(intent, INTENT_NULL); | 242 | checkNotNull(intent, INTENT_NULL); |
235 | IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null); | 243 | IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null); |
236 | store.addPending(data); | 244 | store.addPending(data); |
245 | + | ||
246 | + // remove associated group if there is one | ||
247 | + if (intent instanceof PointToPointIntent) { | ||
248 | + PointToPointIntent pointIntent = (PointToPointIntent) intent; | ||
249 | + DeviceId deviceId = pointIntent.ingressPoint().deviceId(); | ||
250 | + GroupKey groupKey = PointToPointIntentCompiler.makeGroupKey(intent.id()); | ||
251 | + groupService.removeGroup(deviceId, groupKey, | ||
252 | + intent.appId()); | ||
253 | + } | ||
237 | } | 254 | } |
238 | 255 | ||
239 | @Override | 256 | @Override | ... | ... |
... | @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableList; | ... | @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableList; |
20 | import org.apache.felix.scr.annotations.Component; | 20 | import org.apache.felix.scr.annotations.Component; |
21 | import org.apache.felix.scr.annotations.Reference; | 21 | import org.apache.felix.scr.annotations.Reference; |
22 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 22 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
23 | +import org.onosproject.net.DisjointPath; | ||
23 | import org.onosproject.net.ElementId; | 24 | import org.onosproject.net.ElementId; |
24 | import org.onosproject.net.Path; | 25 | import org.onosproject.net.Path; |
25 | import org.onosproject.net.intent.ConnectivityIntent; | 26 | import org.onosproject.net.intent.ConnectivityIntent; |
... | @@ -108,6 +109,29 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent> | ... | @@ -108,6 +109,29 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent> |
108 | } | 109 | } |
109 | 110 | ||
110 | /** | 111 | /** |
112 | + * Computes a disjoint path between two ConnectPoints. | ||
113 | + * | ||
114 | + * @param intent intent on which behalf path is being computed | ||
115 | + * @param one start of the path | ||
116 | + * @param two end of the path | ||
117 | + * @return DisjointPath between the two | ||
118 | + * @throws PathNotFoundException if two paths cannot be found | ||
119 | + */ | ||
120 | + protected DisjointPath getDisjointPath(ConnectivityIntent intent, | ||
121 | + ElementId one, ElementId two) { | ||
122 | + Set<DisjointPath> paths = pathService.getDisjointPaths(one, two, weight(intent.constraints())); | ||
123 | + final List<Constraint> constraints = intent.constraints(); | ||
124 | + ImmutableList<DisjointPath> filtered = FluentIterable.from(paths) | ||
125 | + .filter(path -> checkPath(path, constraints)) | ||
126 | + .toList(); | ||
127 | + if (filtered.isEmpty()) { | ||
128 | + throw new PathNotFoundException(one, two); | ||
129 | + } | ||
130 | + // TODO: let's be more intelligent about this eventually | ||
131 | + return filtered.iterator().next(); | ||
132 | + } | ||
133 | + | ||
134 | + /** | ||
111 | * Edge-weight capable of evaluating link cost using a set of constraints. | 135 | * Edge-weight capable of evaluating link cost using a set of constraints. |
112 | */ | 136 | */ |
113 | protected class ConstraintBasedLinkWeight implements LinkWeight { | 137 | protected class ConstraintBasedLinkWeight implements LinkWeight { | ... | ... |
... | @@ -82,7 +82,7 @@ public class PathIntentCompiler | ... | @@ -82,7 +82,7 @@ public class PathIntentCompiler |
82 | compile(this, intent, rules, devices); | 82 | compile(this, intent, rules, devices); |
83 | 83 | ||
84 | 84 | ||
85 | - return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources())); | 85 | + return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources(), intent.type())); |
86 | } | 86 | } |
87 | 87 | ||
88 | @Override | 88 | @Override | ... | ... |
... | @@ -18,17 +18,51 @@ package org.onosproject.net.intent.impl.compiler; | ... | @@ -18,17 +18,51 @@ package org.onosproject.net.intent.impl.compiler; |
18 | import org.apache.felix.scr.annotations.Activate; | 18 | import org.apache.felix.scr.annotations.Activate; |
19 | import org.apache.felix.scr.annotations.Component; | 19 | import org.apache.felix.scr.annotations.Component; |
20 | import org.apache.felix.scr.annotations.Deactivate; | 20 | import org.apache.felix.scr.annotations.Deactivate; |
21 | +import org.apache.felix.scr.annotations.Reference; | ||
22 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
21 | import org.onosproject.net.ConnectPoint; | 23 | import org.onosproject.net.ConnectPoint; |
22 | import org.onosproject.net.DefaultPath; | 24 | import org.onosproject.net.DefaultPath; |
25 | +import org.onosproject.net.DeviceId; | ||
26 | +import org.onosproject.net.DisjointPath; | ||
27 | +import org.onosproject.net.EdgeLink; | ||
23 | import org.onosproject.net.Link; | 28 | import org.onosproject.net.Link; |
24 | import org.onosproject.net.Path; | 29 | import org.onosproject.net.Path; |
30 | +import org.onosproject.net.Port; | ||
31 | +import org.onosproject.net.PortNumber; | ||
32 | +import org.onosproject.net.device.DeviceService; | ||
33 | +import org.onosproject.net.flow.DefaultFlowRule; | ||
34 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
35 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
36 | +import org.onosproject.net.flow.FlowRule; | ||
37 | +import org.onosproject.net.flow.TrafficSelector; | ||
38 | +import org.onosproject.net.flow.TrafficTreatment; | ||
39 | +import org.onosproject.net.flow.instructions.Instruction; | ||
40 | +import org.onosproject.net.flow.instructions.Instructions; | ||
41 | +import org.onosproject.net.group.DefaultGroupBucket; | ||
42 | +import org.onosproject.net.group.DefaultGroupDescription; | ||
43 | +import org.onosproject.net.group.DefaultGroupKey; | ||
44 | +import org.onosproject.net.group.Group; | ||
45 | +import org.onosproject.net.group.GroupBucket; | ||
46 | +import org.onosproject.net.group.GroupBuckets; | ||
47 | +import org.onosproject.net.group.GroupDescription; | ||
48 | +import org.onosproject.net.group.GroupKey; | ||
49 | +import org.onosproject.net.group.GroupService; | ||
50 | +import org.onosproject.net.intent.FlowRuleIntent; | ||
25 | import org.onosproject.net.intent.Intent; | 51 | import org.onosproject.net.intent.Intent; |
52 | +import org.onosproject.net.intent.IntentId; | ||
26 | import org.onosproject.net.intent.PathIntent; | 53 | import org.onosproject.net.intent.PathIntent; |
27 | import org.onosproject.net.intent.PointToPointIntent; | 54 | import org.onosproject.net.intent.PointToPointIntent; |
55 | +import org.onosproject.net.intent.constraint.ProtectionConstraint; | ||
56 | +import org.onosproject.net.intent.impl.PathNotFoundException; | ||
57 | +import org.onosproject.net.link.LinkService; | ||
28 | import org.onosproject.net.provider.ProviderId; | 58 | import org.onosproject.net.provider.ProviderId; |
29 | 59 | ||
60 | +import java.nio.ByteBuffer; | ||
30 | import java.util.ArrayList; | 61 | import java.util.ArrayList; |
62 | +import java.util.Collections; | ||
63 | +import java.util.Iterator; | ||
31 | import java.util.List; | 64 | import java.util.List; |
65 | +import java.util.ListIterator; | ||
32 | 66 | ||
33 | import static java.util.Arrays.asList; | 67 | import static java.util.Arrays.asList; |
34 | import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; | 68 | import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; |
... | @@ -45,6 +79,18 @@ public class PointToPointIntentCompiler | ... | @@ -45,6 +79,18 @@ public class PointToPointIntentCompiler |
45 | new ProviderId("core", "org.onosproject.core", true); | 79 | new ProviderId("core", "org.onosproject.core", true); |
46 | // TODO: consider whether the default cost is appropriate or not | 80 | // TODO: consider whether the default cost is appropriate or not |
47 | public static final int DEFAULT_COST = 1; | 81 | public static final int DEFAULT_COST = 1; |
82 | + protected static final int PRIORITY = Intent.DEFAULT_INTENT_PRIORITY; | ||
83 | + protected boolean erasePrimary = false; | ||
84 | + protected boolean eraseBackup = false; | ||
85 | + | ||
86 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
87 | + protected GroupService groupService; | ||
88 | + | ||
89 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
90 | + protected LinkService linkService; | ||
91 | + | ||
92 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
93 | + protected DeviceService deviceService; | ||
48 | 94 | ||
49 | @Activate | 95 | @Activate |
50 | public void activate() { | 96 | public void activate() { |
... | @@ -63,20 +109,160 @@ public class PointToPointIntentCompiler | ... | @@ -63,20 +109,160 @@ public class PointToPointIntentCompiler |
63 | ConnectPoint egressPoint = intent.egressPoint(); | 109 | ConnectPoint egressPoint = intent.egressPoint(); |
64 | 110 | ||
65 | if (ingressPoint.deviceId().equals(egressPoint.deviceId())) { | 111 | if (ingressPoint.deviceId().equals(egressPoint.deviceId())) { |
66 | - List<Link> links = asList(createEdgeLink(ingressPoint, true), createEdgeLink(egressPoint, false)); | 112 | + return createZeroHopIntent(ingressPoint, egressPoint, intent); |
67 | - return asList(createPathIntent(new DefaultPath(PID, links, DEFAULT_COST), intent)); | 113 | + } |
114 | + | ||
115 | + // proceed with no protected paths | ||
116 | + if (!ProtectionConstraint.requireProtectedPath(intent)) { | ||
117 | + return createUnprotectedIntent(ingressPoint, egressPoint, intent); | ||
118 | + } | ||
119 | + | ||
120 | + try { | ||
121 | + // attempt to compute and implement backup path | ||
122 | + return createProtectedIntent(ingressPoint, egressPoint, intent, installable); | ||
123 | + } catch (PathNotFoundException e) { | ||
124 | + // no disjoint path extant -- maximum one path exists between devices | ||
125 | + return createSinglePathIntent(ingressPoint, egressPoint, intent, installable); | ||
68 | } | 126 | } |
127 | + } | ||
128 | + | ||
129 | + private List<Intent> createZeroHopIntent(ConnectPoint ingressPoint, | ||
130 | + ConnectPoint egressPoint, | ||
131 | + PointToPointIntent intent) { | ||
132 | + List<Link> links = asList(createEdgeLink(ingressPoint, true), createEdgeLink(egressPoint, false)); | ||
133 | + return asList(createPathIntent(new DefaultPath(PID, links, DEFAULT_COST), | ||
134 | + intent, PathIntent.ProtectionType.PRIMARY)); | ||
135 | + } | ||
69 | 136 | ||
137 | + private List<Intent> createUnprotectedIntent(ConnectPoint ingressPoint, | ||
138 | + ConnectPoint egressPoint, | ||
139 | + PointToPointIntent intent) { | ||
70 | List<Link> links = new ArrayList<>(); | 140 | List<Link> links = new ArrayList<>(); |
71 | Path path = getPath(intent, ingressPoint.deviceId(), | 141 | Path path = getPath(intent, ingressPoint.deviceId(), |
72 | - egressPoint.deviceId()); | 142 | + egressPoint.deviceId()); |
73 | 143 | ||
74 | links.add(createEdgeLink(ingressPoint, true)); | 144 | links.add(createEdgeLink(ingressPoint, true)); |
75 | links.addAll(path.links()); | 145 | links.addAll(path.links()); |
76 | links.add(createEdgeLink(egressPoint, false)); | 146 | links.add(createEdgeLink(egressPoint, false)); |
77 | 147 | ||
78 | return asList(createPathIntent(new DefaultPath(PID, links, path.cost(), | 148 | return asList(createPathIntent(new DefaultPath(PID, links, path.cost(), |
79 | - path.annotations()), intent)); | 149 | + path.annotations()), intent, |
150 | + PathIntent.ProtectionType.PRIMARY)); | ||
151 | + } | ||
152 | + | ||
153 | + //FIXME: Compatibility with EncapsulationConstraint | ||
154 | + private List<Intent> createProtectedIntent(ConnectPoint ingressPoint, | ||
155 | + ConnectPoint egressPoint, | ||
156 | + PointToPointIntent intent, | ||
157 | + List<Intent> installable) { | ||
158 | + DisjointPath path = getDisjointPath(intent, ingressPoint.deviceId(), | ||
159 | + egressPoint.deviceId()); | ||
160 | + | ||
161 | + List<Intent> reusableIntents = null; | ||
162 | + if (installable != null) { | ||
163 | + reusableIntents = filterInvalidSubIntents(installable, intent); | ||
164 | + if (reusableIntents.size() == installable.size()) { | ||
165 | + // all old paths are still viable | ||
166 | + return installable; | ||
167 | + } | ||
168 | + } | ||
169 | + | ||
170 | + List<Intent> intentList = new ArrayList<>(); | ||
171 | + | ||
172 | + // primary path intent | ||
173 | + List<Link> links = new ArrayList<>(); | ||
174 | + links.addAll(path.links()); | ||
175 | + links.add(createEdgeLink(egressPoint, false)); | ||
176 | + | ||
177 | + // backup path intent | ||
178 | + List<Link> backupLinks = new ArrayList<>(); | ||
179 | + backupLinks.addAll(path.backup().links()); | ||
180 | + backupLinks.add(createEdgeLink(egressPoint, false)); | ||
181 | + | ||
182 | + /* | ||
183 | + * One of the old paths is still entirely intact. This old path has | ||
184 | + * already been made primary, so we must add a backup path intent | ||
185 | + * and modify the failover group treatment accordingly. | ||
186 | + */ | ||
187 | + if (reusableIntents != null && reusableIntents.size() > 1) { | ||
188 | + /* | ||
189 | + * Ensures that the egress port on source device is different than | ||
190 | + * that of existing path so that failover group will be useful | ||
191 | + * (would not be useful if both output ports in group bucket were | ||
192 | + * the same). Does not necessarily ensure that the new backup path | ||
193 | + * is entirely disjoint from the old path. | ||
194 | + */ | ||
195 | + PortNumber primaryPort = getPrimaryPort(intent); | ||
196 | + if (primaryPort != null && !links.get(0).src().port().equals(primaryPort)) { | ||
197 | + reusableIntents.add(createPathIntent(new DefaultPath(PID, links, | ||
198 | + path.cost(), path.annotations()), | ||
199 | + intent, PathIntent.ProtectionType.BACKUP)); | ||
200 | + updateFailoverGroup(intent, links); | ||
201 | + return reusableIntents; | ||
202 | + | ||
203 | + } else { | ||
204 | + reusableIntents.add(createPathIntent(new DefaultPath(PID, backupLinks, path.backup().cost(), | ||
205 | + path.backup().annotations()), intent, PathIntent.ProtectionType.BACKUP)); | ||
206 | + updateFailoverGroup(intent, backupLinks); | ||
207 | + return reusableIntents; | ||
208 | + } | ||
209 | + } | ||
210 | + | ||
211 | + intentList.add(createPathIntent(new DefaultPath(PID, links, path.cost(), path.annotations()), | ||
212 | + intent, PathIntent.ProtectionType.PRIMARY)); | ||
213 | + intentList.add(createPathIntent(new DefaultPath(PID, backupLinks, path.backup().cost(), | ||
214 | + path.backup().annotations()), intent, PathIntent.ProtectionType.BACKUP)); | ||
215 | + | ||
216 | + // Create fast failover flow rule intent or, if it already exists, | ||
217 | + // add contents appropriately. | ||
218 | + if (groupService.getGroup(ingressPoint.deviceId(), | ||
219 | + makeGroupKey(intent.id())) == null) { | ||
220 | + // manufactured fast failover flow rule intent | ||
221 | + createFailoverTreatmentGroup(path.links(), path.backup().links(), intent); | ||
222 | + | ||
223 | + FlowRuleIntent frIntent = new FlowRuleIntent(intent.appId(), | ||
224 | + createFailoverFlowRules(intent), | ||
225 | + asList(ingressPoint.deviceId()), | ||
226 | + PathIntent.ProtectionType.FAILOVER); | ||
227 | + intentList.add(frIntent); | ||
228 | + } else { | ||
229 | + updateFailoverGroup(intent, links); | ||
230 | + updateFailoverGroup(intent, backupLinks); | ||
231 | + } | ||
232 | + | ||
233 | + return intentList; | ||
234 | + } | ||
235 | + | ||
236 | + private List<Intent> createSinglePathIntent(ConnectPoint ingressPoint, | ||
237 | + ConnectPoint egressPoint, | ||
238 | + PointToPointIntent intent, | ||
239 | + List<Intent> installable) { | ||
240 | + List<Link> links = new ArrayList<>(); | ||
241 | + Path onlyPath = getPath(intent, ingressPoint.deviceId(), | ||
242 | + egressPoint.deviceId()); | ||
243 | + | ||
244 | + List<Intent> reusableIntents = null; | ||
245 | + if (installable != null) { | ||
246 | + reusableIntents = filterInvalidSubIntents(installable, intent); | ||
247 | + if (reusableIntents.size() == installable.size()) { | ||
248 | + // all old paths are still viable | ||
249 | + return installable; | ||
250 | + } | ||
251 | + } | ||
252 | + | ||
253 | + // If there exists a full path from old installable intents, | ||
254 | + // return the intents that comprise it. | ||
255 | + if (reusableIntents != null && reusableIntents.size() > 1) { | ||
256 | + return reusableIntents; | ||
257 | + } else { | ||
258 | + links.add(createEdgeLink(ingressPoint, true)); | ||
259 | + links.addAll(onlyPath.links()); | ||
260 | + links.add(createEdgeLink(egressPoint, false)); | ||
261 | + | ||
262 | + return asList(createPathIntent(new DefaultPath(PID, links, onlyPath.cost(), | ||
263 | + onlyPath.annotations()), | ||
264 | + intent, PathIntent.ProtectionType.PRIMARY)); | ||
265 | + } | ||
80 | } | 266 | } |
81 | 267 | ||
82 | /** | 268 | /** |
... | @@ -85,9 +271,11 @@ public class PointToPointIntentCompiler | ... | @@ -85,9 +271,11 @@ public class PointToPointIntentCompiler |
85 | * | 271 | * |
86 | * @param path path to create an intent for | 272 | * @param path path to create an intent for |
87 | * @param intent original intent | 273 | * @param intent original intent |
274 | + * @param type primary or backup | ||
88 | */ | 275 | */ |
89 | private Intent createPathIntent(Path path, | 276 | private Intent createPathIntent(Path path, |
90 | - PointToPointIntent intent) { | 277 | + PointToPointIntent intent, |
278 | + PathIntent.ProtectionType type) { | ||
91 | return PathIntent.builder() | 279 | return PathIntent.builder() |
92 | .appId(intent.appId()) | 280 | .appId(intent.appId()) |
93 | .selector(intent.selector()) | 281 | .selector(intent.selector()) |
... | @@ -95,7 +283,262 @@ public class PointToPointIntentCompiler | ... | @@ -95,7 +283,262 @@ public class PointToPointIntentCompiler |
95 | .path(path) | 283 | .path(path) |
96 | .constraints(intent.constraints()) | 284 | .constraints(intent.constraints()) |
97 | .priority(intent.priority()) | 285 | .priority(intent.priority()) |
286 | + .setType(type) | ||
98 | .build(); | 287 | .build(); |
99 | } | 288 | } |
100 | 289 | ||
290 | + /** | ||
291 | + * Gets primary port number through failover group associated | ||
292 | + * with this intent. | ||
293 | + */ | ||
294 | + private PortNumber getPrimaryPort(PointToPointIntent intent) { | ||
295 | + Group group = groupService.getGroup(intent.ingressPoint().deviceId(), | ||
296 | + makeGroupKey(intent.id())); | ||
297 | + PortNumber primaryPort = null; | ||
298 | + if (group != null) { | ||
299 | + List<GroupBucket> buckets = group.buckets().buckets(); | ||
300 | + Iterator<GroupBucket> iterator = buckets.iterator(); | ||
301 | + while (primaryPort == null && iterator.hasNext()) { | ||
302 | + GroupBucket bucket = iterator.next(); | ||
303 | + Instruction individualInstruction = bucket.treatment().allInstructions().get(0); | ||
304 | + if (individualInstruction instanceof Instructions.OutputInstruction) { | ||
305 | + Instructions.OutputInstruction outInstruction = | ||
306 | + (Instructions.OutputInstruction) individualInstruction; | ||
307 | + PortNumber tempPortNum = outInstruction.port(); | ||
308 | + Port port = deviceService.getPort(intent.ingressPoint().deviceId(), | ||
309 | + tempPortNum); | ||
310 | + if (port != null && port.isEnabled()) { | ||
311 | + primaryPort = tempPortNum; | ||
312 | + } | ||
313 | + } | ||
314 | + } | ||
315 | + } | ||
316 | + return primaryPort; | ||
317 | + } | ||
318 | + | ||
319 | + /** | ||
320 | + * Creates group key unique to each intent. | ||
321 | + */ | ||
322 | + public static GroupKey makeGroupKey(IntentId intentId) { | ||
323 | + ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); | ||
324 | + buffer.putLong(intentId.fingerprint()); | ||
325 | + return new DefaultGroupKey(buffer.array()); | ||
326 | + } | ||
327 | + | ||
328 | + /** | ||
329 | + * Creates a new failover group with the initial ports of the links | ||
330 | + * from the primary and backup path. | ||
331 | + * | ||
332 | + * @param links links from the primary path | ||
333 | + * @param backupLinks links from the backup path | ||
334 | + * @param intent intent from which this call originates | ||
335 | + */ | ||
336 | + private void createFailoverTreatmentGroup(List<Link> links, | ||
337 | + List<Link> backupLinks, | ||
338 | + PointToPointIntent intent) { | ||
339 | + | ||
340 | + List<GroupBucket> buckets = new ArrayList<>(); | ||
341 | + | ||
342 | + TrafficTreatment.Builder tBuilderIn = DefaultTrafficTreatment.builder(); | ||
343 | + ConnectPoint src = links.get(0).src(); | ||
344 | + tBuilderIn.setOutput(src.port()); | ||
345 | + | ||
346 | + TrafficTreatment.Builder tBuilderIn2 = DefaultTrafficTreatment.builder(); | ||
347 | + ConnectPoint src2 = backupLinks.get(0).src(); | ||
348 | + tBuilderIn2.setOutput(src2.port()); | ||
349 | + | ||
350 | + buckets.add(DefaultGroupBucket.createFailoverGroupBucket(tBuilderIn.build(), src.port(), null)); | ||
351 | + buckets.add(DefaultGroupBucket.createFailoverGroupBucket(tBuilderIn2.build(), src2.port(), null)); | ||
352 | + | ||
353 | + GroupBuckets groupBuckets = new GroupBuckets(buckets); | ||
354 | + | ||
355 | + GroupDescription groupDesc = new DefaultGroupDescription(src.deviceId(), Group.Type.FAILOVER, | ||
356 | + groupBuckets, makeGroupKey(intent.id()), null, intent.appId()); | ||
357 | + groupService.addGroup(groupDesc); | ||
358 | + } | ||
359 | + | ||
360 | + /** | ||
361 | + * Manufactures flow rule with treatment that is defined by failover | ||
362 | + * group and traffic selector determined by ingress port of the intent. | ||
363 | + * | ||
364 | + * @param intent intent which is being compiled (for appId) | ||
365 | + * @return a list of a singular flow rule with fast failover | ||
366 | + * outport traffic treatment | ||
367 | + */ | ||
368 | + private List<FlowRule> createFailoverFlowRules(PointToPointIntent intent) { | ||
369 | + List<FlowRule> flowRules = new ArrayList<>(); | ||
370 | + | ||
371 | + ConnectPoint ingress = intent.ingressPoint(); | ||
372 | + DeviceId deviceId = ingress.deviceId(); | ||
373 | + | ||
374 | + // flow rule with failover traffic treatment | ||
375 | + TrafficSelector trafficSelector = DefaultTrafficSelector.builder(intent.selector()) | ||
376 | + .matchInPort(ingress.port()).build(); | ||
377 | + | ||
378 | + FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder(); | ||
379 | + flowRules.add(flowRuleBuilder.withSelector(trafficSelector) | ||
380 | + .withTreatment(buildFailoverTreatment(deviceId, makeGroupKey(intent.id()))) | ||
381 | + .fromApp(intent.appId()) | ||
382 | + .makePermanent() | ||
383 | + .forDevice(deviceId) | ||
384 | + .withPriority(PRIORITY) | ||
385 | + .build()); | ||
386 | + | ||
387 | + return flowRules; | ||
388 | + } | ||
389 | + | ||
390 | + private TrafficTreatment buildFailoverTreatment(DeviceId srcDevice, | ||
391 | + GroupKey groupKey) { | ||
392 | + Group group = groupService.getGroup(srcDevice, groupKey); | ||
393 | + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); | ||
394 | + TrafficTreatment trafficTreatment = tBuilder.group(group.id()).build(); | ||
395 | + return trafficTreatment; | ||
396 | + } | ||
397 | + | ||
398 | + /** | ||
399 | + * Deletes intents from the given list if the ports or links the intent | ||
400 | + * relies on are no longer viable. The failover flow rule intent is never | ||
401 | + * deleted -- only its contents are updated. | ||
402 | + * | ||
403 | + * @param oldInstallables list of intents to examine | ||
404 | + * @return list of reusable installable intents | ||
405 | + */ | ||
406 | + private List<Intent> filterInvalidSubIntents(List<Intent> oldInstallables, | ||
407 | + PointToPointIntent pointIntent) { | ||
408 | + List<Intent> intentList = new ArrayList<>(); | ||
409 | + intentList.addAll(oldInstallables); | ||
410 | + erasePrimary = false; | ||
411 | + eraseBackup = false; | ||
412 | + if (intentList != null) { | ||
413 | + Iterator<Intent> iterator = intentList.iterator(); | ||
414 | + while (iterator.hasNext() && !(erasePrimary && eraseBackup)) { | ||
415 | + Intent intent = iterator.next(); | ||
416 | + intent.resources().forEach(resource -> { | ||
417 | + if (resource instanceof Link) { | ||
418 | + Link link = (Link) resource; | ||
419 | + if (link.state() == Link.State.INACTIVE) { | ||
420 | + setPathsToRemove(intent); | ||
421 | + } else if (link instanceof EdgeLink) { | ||
422 | + ConnectPoint connectPoint = (link.src().elementId() instanceof DeviceId) | ||
423 | + ? link.src() : link.dst(); | ||
424 | + Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port()); | ||
425 | + if (port == null || !port.isEnabled()) { | ||
426 | + setPathsToRemove(intent); | ||
427 | + } | ||
428 | + } else { | ||
429 | + Port port1 = deviceService.getPort(link.src().deviceId(), link.src().port()); | ||
430 | + Port port2 = deviceService.getPort(link.dst().deviceId(), link.dst().port()); | ||
431 | + if (port1 == null || !port1.isEnabled() || port2 == null || !port2.isEnabled()) { | ||
432 | + setPathsToRemove(intent); | ||
433 | + } | ||
434 | + } | ||
435 | + } | ||
436 | + }); | ||
437 | + } | ||
438 | + removeAndUpdateIntents(intentList, pointIntent); | ||
439 | + } | ||
440 | + return intentList; | ||
441 | + } | ||
442 | + | ||
443 | + /** | ||
444 | + * Sets instance variables erasePrimary and eraseBackup. If erasePrimary, | ||
445 | + * the primary path is no longer viable and related intents will be deleted. | ||
446 | + * If eraseBackup, the backup path is no longer viable and related intents | ||
447 | + * will be deleted. | ||
448 | + * | ||
449 | + * @param intent intent whose resources are found to be disabled/inactive: | ||
450 | + * if intent is part of primary path, primary path set for removal; | ||
451 | + * if intent is part of backup path, backup path set for removal; | ||
452 | + * if bad intent is of type failover, the ingress point is down, | ||
453 | + * and both paths are rendered inactive. | ||
454 | + * @return true if both primary and backup paths are to be removed | ||
455 | + */ | ||
456 | + private boolean setPathsToRemove(Intent intent) { | ||
457 | + if (intent instanceof FlowRuleIntent) { | ||
458 | + FlowRuleIntent frIntent = (FlowRuleIntent) intent; | ||
459 | + PathIntent.ProtectionType type = frIntent.type(); | ||
460 | + if (type == PathIntent.ProtectionType.PRIMARY || type == PathIntent.ProtectionType.FAILOVER) { | ||
461 | + erasePrimary = true; | ||
462 | + } | ||
463 | + if (type == PathIntent.ProtectionType.BACKUP || type == PathIntent.ProtectionType.FAILOVER) { | ||
464 | + eraseBackup = true; | ||
465 | + } | ||
466 | + } | ||
467 | + return erasePrimary && eraseBackup; | ||
468 | + } | ||
469 | + | ||
470 | + /** | ||
471 | + * Removes intents from installables list, depending on the values | ||
472 | + * of instance variables erasePrimary and eraseBackup. Flow rule intents | ||
473 | + * that contain the manufactured fast failover flow rules are never deleted. | ||
474 | + * The contents are simply modified as necessary. If cleanUpIntents size | ||
475 | + * is greater than 1 (failover intent), then one whole path from previous | ||
476 | + * installables must be still viable. | ||
477 | + * | ||
478 | + * @param cleanUpIntents list of installable intents | ||
479 | + */ | ||
480 | + private void removeAndUpdateIntents(List<Intent> cleanUpIntents, | ||
481 | + PointToPointIntent pointIntent) { | ||
482 | + ListIterator<Intent> iterator = cleanUpIntents.listIterator(); | ||
483 | + while (iterator.hasNext()) { | ||
484 | + Intent cIntent = iterator.next(); | ||
485 | + if (cIntent instanceof FlowRuleIntent) { | ||
486 | + FlowRuleIntent fIntent = (FlowRuleIntent) cIntent; | ||
487 | + if (fIntent.type() == PathIntent.ProtectionType.PRIMARY && erasePrimary) { | ||
488 | + // remove primary path's flow rule intents | ||
489 | + iterator.remove(); | ||
490 | + } else if (fIntent.type() == PathIntent.ProtectionType.BACKUP && eraseBackup) { | ||
491 | + //remove backup path's flow rule intents | ||
492 | + iterator.remove(); | ||
493 | + } else if (fIntent.type() == PathIntent.ProtectionType.BACKUP && erasePrimary) { | ||
494 | + // promote backup path's flow rule intents to primary | ||
495 | + iterator.set(new FlowRuleIntent(fIntent, PathIntent.ProtectionType.PRIMARY)); | ||
496 | + } | ||
497 | + } | ||
498 | + } | ||
499 | + // remove buckets whose watchports are disabled if the failover group exists | ||
500 | + Group group = groupService.getGroup(pointIntent.ingressPoint().deviceId(), | ||
501 | + makeGroupKey(pointIntent.id())); | ||
502 | + if (group != null) { | ||
503 | + updateFailoverGroup(pointIntent); | ||
504 | + } | ||
505 | + } | ||
506 | + | ||
507 | + // Removes buckets whose treatments rely on disabled ports from the | ||
508 | + // failover group. | ||
509 | + private void updateFailoverGroup(PointToPointIntent pointIntent) { | ||
510 | + DeviceId deviceId = pointIntent.ingressPoint().deviceId(); | ||
511 | + GroupKey groupKey = makeGroupKey(pointIntent.id()); | ||
512 | + Group group = groupService.getGroup(deviceId, groupKey); | ||
513 | + Iterator<GroupBucket> groupIterator = group.buckets().buckets().iterator(); | ||
514 | + while (groupIterator.hasNext()) { | ||
515 | + GroupBucket bucket = groupIterator.next(); | ||
516 | + Instruction individualInstruction = bucket.treatment().allInstructions().get(0); | ||
517 | + if (individualInstruction instanceof Instructions.OutputInstruction) { | ||
518 | + Instructions.OutputInstruction outInstruction = | ||
519 | + (Instructions.OutputInstruction) individualInstruction; | ||
520 | + Port port = deviceService.getPort(deviceId, outInstruction.port()); | ||
521 | + if (port == null || !port.isEnabled()) { | ||
522 | + GroupBuckets removeBuckets = new GroupBuckets(Collections.singletonList(bucket)); | ||
523 | + groupService.removeBucketsFromGroup(deviceId, groupKey, | ||
524 | + removeBuckets, groupKey, | ||
525 | + pointIntent.appId()); | ||
526 | + } | ||
527 | + } | ||
528 | + } | ||
529 | + } | ||
530 | + | ||
531 | + // Adds failover group bucket with treatment outport determined by the | ||
532 | + // ingress point of the links. | ||
533 | + private void updateFailoverGroup(PointToPointIntent intent, List<Link> links) { | ||
534 | + GroupKey groupKey = makeGroupKey(intent.id()); | ||
535 | + | ||
536 | + TrafficTreatment.Builder tBuilderIn = DefaultTrafficTreatment.builder(); | ||
537 | + ConnectPoint src = links.get(0).src(); | ||
538 | + tBuilderIn.setOutput(src.port()); | ||
539 | + GroupBucket bucket = DefaultGroupBucket.createFailoverGroupBucket(tBuilderIn.build(), src.port(), null); | ||
540 | + GroupBuckets addBuckets = new GroupBuckets(Collections.singletonList(bucket)); | ||
541 | + | ||
542 | + groupService.addBucketsToGroup(src.deviceId(), groupKey, addBuckets, groupKey, intent.appId()); | ||
543 | + } | ||
101 | } | 544 | } | ... | ... |
-
Please register or login to post a comment