Ray Milkey
Committed by Brian O'Connor

Add path intent compiler that generates flow objective intents

Change-Id: I11bee398d927f0e3f32b7cf81d98cfe5816db477
...@@ -17,19 +17,25 @@ ...@@ -17,19 +17,25 @@
17 package org.onosproject.net.intent; 17 package org.onosproject.net.intent;
18 18
19 import com.google.common.base.MoreObjects; 19 import com.google.common.base.MoreObjects;
20 +import com.google.common.collect.ImmutableList;
20 import org.onosproject.core.ApplicationId; 21 import org.onosproject.core.ApplicationId;
22 +import org.onosproject.net.DeviceId;
21 import org.onosproject.net.NetworkResource; 23 import org.onosproject.net.NetworkResource;
22 import org.onosproject.net.flowobjective.Objective; 24 import org.onosproject.net.flowobjective.Objective;
23 25
24 import java.util.Collection; 26 import java.util.Collection;
27 +import java.util.List;
28 +
29 +import static com.google.common.base.Preconditions.checkArgument;
25 30
26 /** 31 /**
27 * Intent expressed as (and backed by) a collection of flow objectives through 32 * Intent expressed as (and backed by) a collection of flow objectives through
28 * which the intent is to be accomplished. 33 * which the intent is to be accomplished.
29 */ 34 */
30 -public class FlowObjectiveIntent extends Intent { 35 +public final class FlowObjectiveIntent extends Intent {
31 36
32 - private final Collection<Objective> objectives; 37 + private final List<Objective> objectives;
38 + private final List<DeviceId> devices;
33 39
34 /** 40 /**
35 * Constructor for serialization. 41 * Constructor for serialization.
...@@ -37,6 +43,7 @@ public class FlowObjectiveIntent extends Intent { ...@@ -37,6 +43,7 @@ public class FlowObjectiveIntent extends Intent {
37 protected FlowObjectiveIntent() { 43 protected FlowObjectiveIntent() {
38 super(); 44 super();
39 this.objectives = null; 45 this.objectives = null;
46 + this.devices = null;
40 } 47 }
41 48
42 /** 49 /**
...@@ -44,13 +51,15 @@ public class FlowObjectiveIntent extends Intent { ...@@ -44,13 +51,15 @@ public class FlowObjectiveIntent extends Intent {
44 * resources. 51 * resources.
45 * 52 *
46 * @param appId application id 53 * @param appId application id
54 + * @param devices list of target devices; in same order as the objectives
47 * @param objectives backing flow objectives 55 * @param objectives backing flow objectives
48 * @param resources backing network resources 56 * @param resources backing network resources
49 */ 57 */
50 public FlowObjectiveIntent(ApplicationId appId, 58 public FlowObjectiveIntent(ApplicationId appId,
51 - Collection<Objective> objectives, 59 + List<DeviceId> devices,
60 + List<Objective> objectives,
52 Collection<NetworkResource> resources) { 61 Collection<NetworkResource> resources) {
53 - this(appId, null, objectives, resources); 62 + this(appId, null, devices, objectives, resources);
54 } 63 }
55 64
56 /** 65 /**
...@@ -59,14 +68,20 @@ public class FlowObjectiveIntent extends Intent { ...@@ -59,14 +68,20 @@ public class FlowObjectiveIntent extends Intent {
59 * 68 *
60 * @param appId application id 69 * @param appId application id
61 * @param key intent key 70 * @param key intent key
71 + * @param devices list of target devices; in same order as the objectives
62 * @param objectives backing flow objectives 72 * @param objectives backing flow objectives
63 * @param resources backing network resources 73 * @param resources backing network resources
64 */ 74 */
65 - public FlowObjectiveIntent(ApplicationId appId, Key key, 75 + public FlowObjectiveIntent(ApplicationId appId,
66 - Collection<Objective> objectives, 76 + Key key,
77 + List<DeviceId> devices,
78 + List<Objective> objectives,
67 Collection<NetworkResource> resources) { 79 Collection<NetworkResource> resources) {
68 super(appId, key, resources, DEFAULT_INTENT_PRIORITY); 80 super(appId, key, resources, DEFAULT_INTENT_PRIORITY);
69 - this.objectives = objectives; 81 + checkArgument(devices.size() == objectives.size(),
82 + "Number of devices and objectives does not match");
83 + this.objectives = ImmutableList.copyOf(objectives);
84 + this.devices = ImmutableList.copyOf(devices);
70 } 85 }
71 86
72 /** 87 /**
...@@ -74,10 +89,19 @@ public class FlowObjectiveIntent extends Intent { ...@@ -74,10 +89,19 @@ public class FlowObjectiveIntent extends Intent {
74 * 89 *
75 * @return flow objectives 90 * @return flow objectives
76 */ 91 */
77 - Collection<Objective> objectives() { 92 + public List<Objective> objectives() {
78 return objectives; 93 return objectives;
79 } 94 }
80 95
96 + /**
97 + * Returns the list of devices for the flow objectives.
98 + *
99 + * @return devices
100 + */
101 + public List<DeviceId> devices() {
102 + return devices;
103 + }
104 +
81 105
82 @Override 106 @Override
83 public boolean isInstallable() { 107 public boolean isInstallable() {
...@@ -91,7 +115,8 @@ public class FlowObjectiveIntent extends Intent { ...@@ -91,7 +115,8 @@ public class FlowObjectiveIntent extends Intent {
91 .add("key", key()) 115 .add("key", key())
92 .add("appId", appId()) 116 .add("appId", appId())
93 .add("resources", resources()) 117 .add("resources", resources())
94 - .add("objectives", objectives) 118 + .add("device", devices())
119 + .add("objectives", objectives())
95 .toString(); 120 .toString();
96 } 121 }
97 } 122 }
......
...@@ -16,11 +16,13 @@ ...@@ -16,11 +16,13 @@
16 16
17 package org.onosproject.net.intent; 17 package org.onosproject.net.intent;
18 18
19 -import com.google.common.collect.ImmutableSet; 19 +import java.util.Collection;
20 -import com.google.common.testing.EqualsTester; 20 +import java.util.List;
21 +
21 import org.junit.Test; 22 import org.junit.Test;
22 import org.onosproject.core.ApplicationId; 23 import org.onosproject.core.ApplicationId;
23 import org.onosproject.core.DefaultApplicationId; 24 import org.onosproject.core.DefaultApplicationId;
25 +import org.onosproject.net.DeviceId;
24 import org.onosproject.net.NetworkResource; 26 import org.onosproject.net.NetworkResource;
25 import org.onosproject.net.flow.DefaultTrafficSelector; 27 import org.onosproject.net.flow.DefaultTrafficSelector;
26 import org.onosproject.net.flow.DefaultTrafficTreatment; 28 import org.onosproject.net.flow.DefaultTrafficTreatment;
...@@ -30,7 +32,9 @@ import org.onosproject.net.flowobjective.DefaultForwardingObjective; ...@@ -30,7 +32,9 @@ import org.onosproject.net.flowobjective.DefaultForwardingObjective;
30 import org.onosproject.net.flowobjective.ForwardingObjective; 32 import org.onosproject.net.flowobjective.ForwardingObjective;
31 import org.onosproject.net.flowobjective.Objective; 33 import org.onosproject.net.flowobjective.Objective;
32 34
33 -import java.util.Collection; 35 +import com.google.common.collect.ImmutableList;
36 +import com.google.common.collect.ImmutableSet;
37 +import com.google.common.testing.EqualsTester;
34 38
35 import static org.junit.Assert.assertEquals; 39 import static org.junit.Assert.assertEquals;
36 import static org.junit.Assert.assertTrue; 40 import static org.junit.Assert.assertTrue;
...@@ -52,8 +56,9 @@ public class FlowObjectiveIntentTest extends IntentTest { ...@@ -52,8 +56,9 @@ public class FlowObjectiveIntentTest extends IntentTest {
52 .withSelector(DefaultTrafficSelector.builder().matchEthType((short) 123).build()) 56 .withSelector(DefaultTrafficSelector.builder().matchEthType((short) 123).build())
53 .withTreatment(DefaultTrafficTreatment.emptyTreatment()) 57 .withTreatment(DefaultTrafficTreatment.emptyTreatment())
54 .withFlag(ForwardingObjective.Flag.VERSATILE).add(); 58 .withFlag(ForwardingObjective.Flag.VERSATILE).add();
55 - private static final Collection<Objective> OBJECTIVES = ImmutableSet.of(FO1, FO2); 59 + private static final List<Objective> OBJECTIVES = ImmutableList.of(FO1, FO2);
56 private static final Collection<NetworkResource> RESOURCES = ImmutableSet.of(); 60 private static final Collection<NetworkResource> RESOURCES = ImmutableSet.of();
61 + private static final List<DeviceId> DEVICE = ImmutableList.of(DeviceId.NONE, DeviceId.NONE);
57 62
58 /** 63 /**
59 * Tests basics of construction and getters. 64 * Tests basics of construction and getters.
...@@ -61,7 +66,7 @@ public class FlowObjectiveIntentTest extends IntentTest { ...@@ -61,7 +66,7 @@ public class FlowObjectiveIntentTest extends IntentTest {
61 @Test 66 @Test
62 public void basics() { 67 public void basics() {
63 FlowObjectiveIntent intent = 68 FlowObjectiveIntent intent =
64 - new FlowObjectiveIntent(APP_ID, KEY, OBJECTIVES, RESOURCES); 69 + new FlowObjectiveIntent(APP_ID, KEY, DEVICE, OBJECTIVES, RESOURCES);
65 assertEquals("incorrect app id", APP_ID, intent.appId()); 70 assertEquals("incorrect app id", APP_ID, intent.appId());
66 assertEquals("incorrect key", KEY, intent.key()); 71 assertEquals("incorrect key", KEY, intent.key());
67 assertEquals("incorrect objectives", OBJECTIVES, intent.objectives()); 72 assertEquals("incorrect objectives", OBJECTIVES, intent.objectives());
...@@ -89,11 +94,11 @@ public class FlowObjectiveIntentTest extends IntentTest { ...@@ -89,11 +94,11 @@ public class FlowObjectiveIntentTest extends IntentTest {
89 94
90 @Override 95 @Override
91 protected Intent createOne() { 96 protected Intent createOne() {
92 - return new FlowObjectiveIntent(APP_ID, OBJECTIVES, RESOURCES); 97 + return new FlowObjectiveIntent(APP_ID, DEVICE, OBJECTIVES, RESOURCES);
93 } 98 }
94 99
95 @Override 100 @Override
96 protected Intent createAnother() { 101 protected Intent createAnother() {
97 - return new FlowObjectiveIntent(APP_ID, OBJECTIVES, RESOURCES); 102 + return new FlowObjectiveIntent(APP_ID, DEVICE, OBJECTIVES, RESOURCES);
98 } 103 }
99 } 104 }
......
1 +/*
2 + * Copyright 2016 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 +package org.onosproject.net.intent.impl.compiler;
17 +
18 +import java.util.Collections;
19 +import java.util.HashMap;
20 +import java.util.Iterator;
21 +import java.util.List;
22 +import java.util.Map;
23 +import java.util.Optional;
24 +import java.util.Set;
25 +import java.util.stream.Collectors;
26 +import java.util.stream.Stream;
27 +
28 +import org.onlab.packet.VlanId;
29 +import org.onosproject.net.ConnectPoint;
30 +import org.onosproject.net.DeviceId;
31 +import org.onosproject.net.Link;
32 +import org.onosproject.net.LinkKey;
33 +import org.onosproject.net.flow.DefaultTrafficSelector;
34 +import org.onosproject.net.flow.DefaultTrafficTreatment;
35 +import org.onosproject.net.flow.TrafficSelector;
36 +import org.onosproject.net.flow.TrafficTreatment;
37 +import org.onosproject.net.flow.criteria.Criterion;
38 +import org.onosproject.net.flow.criteria.VlanIdCriterion;
39 +import org.onosproject.net.flow.instructions.L2ModificationInstruction;
40 +import org.onosproject.net.intent.PathIntent;
41 +import org.onosproject.net.intent.constraint.EncapsulationConstraint;
42 +import org.onosproject.net.intent.impl.IntentCompilationException;
43 +import org.onosproject.net.newresource.Resource;
44 +import org.onosproject.net.newresource.ResourceService;
45 +import org.onosproject.net.newresource.Resources;
46 +import org.slf4j.Logger;
47 +
48 +import com.google.common.collect.ImmutableList;
49 +import com.google.common.collect.Sets;
50 +
51 +import static org.onosproject.net.LinkKey.linkKey;
52 +
53 +/**
54 + * Shared APIs and implementations for path compilers.
55 + */
56 +
57 +public class PathCompiler<T> {
58 +
59 + /**
60 + * Defines methods used to create objects representing flows.
61 + */
62 + public interface PathCompilerCreateFlow<T> {
63 +
64 + void createFlow(TrafficSelector originalSelector,
65 + TrafficTreatment originalTreatment,
66 + ConnectPoint ingress, ConnectPoint egress,
67 + int priority,
68 + boolean applyTreatment,
69 + List<T> flows,
70 + List<DeviceId> devices);
71 +
72 + Logger log();
73 +
74 + ResourceService resourceService();
75 + }
76 +
77 + private boolean isLast(List<Link> links, int i) {
78 + return i == links.size() - 2;
79 + }
80 +
81 + private Map<LinkKey, VlanId> assignVlanId(PathCompilerCreateFlow creator, PathIntent intent) {
82 + Set<LinkKey> linkRequest =
83 + Sets.newHashSetWithExpectedSize(intent.path()
84 + .links().size() - 2);
85 + for (int i = 1; i <= intent.path().links().size() - 2; i++) {
86 + LinkKey link = linkKey(intent.path().links().get(i));
87 + linkRequest.add(link);
88 + // add the inverse link. I want that the VLANID is reserved both for
89 + // the direct and inverse link
90 + linkRequest.add(linkKey(link.dst(), link.src()));
91 + }
92 +
93 + Map<LinkKey, VlanId> vlanIds = findVlanIds(creator, linkRequest);
94 + if (vlanIds.isEmpty()) {
95 + creator.log().warn("No VLAN IDs available");
96 + return Collections.emptyMap();
97 + }
98 +
99 + //same VLANID is used for both directions
100 + Set<Resource> resources = vlanIds.entrySet().stream()
101 + .flatMap(x -> Stream.of(
102 + Resources.discrete(x.getKey().src().deviceId(), x.getKey().src().port(), x.getValue())
103 + .resource(),
104 + Resources.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port(), x.getValue())
105 + .resource()
106 + ))
107 + .collect(Collectors.toSet());
108 + List<org.onosproject.net.newresource.ResourceAllocation> allocations =
109 + creator.resourceService().allocate(intent.id(), ImmutableList.copyOf(resources));
110 + if (allocations.isEmpty()) {
111 + Collections.emptyMap();
112 + }
113 +
114 + return vlanIds;
115 + }
116 +
117 + private Map<LinkKey, VlanId> findVlanIds(PathCompilerCreateFlow creator, Set<LinkKey> links) {
118 + Map<LinkKey, VlanId> vlanIds = new HashMap<>();
119 + for (LinkKey link : links) {
120 + Set<VlanId> forward = findVlanId(creator, link.src());
121 + Set<VlanId> backward = findVlanId(creator, link.dst());
122 + Set<VlanId> common = Sets.intersection(forward, backward);
123 + if (common.isEmpty()) {
124 + continue;
125 + }
126 + vlanIds.put(link, common.iterator().next());
127 + }
128 + return vlanIds;
129 + }
130 +
131 + private Set<VlanId> findVlanId(PathCompilerCreateFlow creator, ConnectPoint cp) {
132 + return creator.resourceService().getAvailableResourceValues(
133 + Resources.discrete(cp.deviceId(), cp.port()).id(),
134 + VlanId.class);
135 + }
136 +
137 + private void manageVlanEncap(PathCompilerCreateFlow<T> creator, List<T> flows,
138 + List<DeviceId> devices,
139 + PathIntent intent) {
140 + Map<LinkKey, VlanId> vlanIds = assignVlanId(creator, intent);
141 +
142 + Iterator<Link> links = intent.path().links().iterator();
143 + Link srcLink = links.next();
144 +
145 + Link link = links.next();
146 +
147 + // Ingress traffic
148 + VlanId vlanId = vlanIds.get(linkKey(link));
149 + if (vlanId == null) {
150 + throw new IntentCompilationException("No available VLAN ID for " + link);
151 + }
152 + VlanId prevVlanId = vlanId;
153 +
154 + Optional<VlanIdCriterion> vlanCriterion = intent.selector().criteria()
155 + .stream().filter(criterion -> criterion.type() == Criterion.Type.VLAN_VID)
156 + .map(criterion -> (VlanIdCriterion) criterion)
157 + .findAny();
158 +
159 + //Push VLAN if selector does not include VLAN
160 + TrafficTreatment.Builder treatBuilder = DefaultTrafficTreatment.builder();
161 + if (!vlanCriterion.isPresent()) {
162 + treatBuilder.pushVlan();
163 + }
164 + //Tag the traffic with the new encapsulation VLAN
165 + treatBuilder.setVlanId(vlanId);
166 + creator.createFlow(intent.selector(), treatBuilder.build(),
167 + srcLink.dst(), link.src(), intent.priority(), true,
168 + flows, devices);
169 +
170 + ConnectPoint prev = link.dst();
171 +
172 + while (links.hasNext()) {
173 +
174 + link = links.next();
175 +
176 + if (links.hasNext()) {
177 + // Transit traffic
178 + VlanId egressVlanId = vlanIds.get(linkKey(link));
179 + if (egressVlanId == null) {
180 + throw new IntentCompilationException("No available VLAN ID for " + link);
181 + }
182 + prevVlanId = egressVlanId;
183 +
184 + TrafficSelector transitSelector = DefaultTrafficSelector.builder()
185 + .matchInPort(prev.port())
186 + .matchVlanId(prevVlanId).build();
187 +
188 + TrafficTreatment.Builder transitTreat = DefaultTrafficTreatment.builder();
189 +
190 + // Set the new vlanId only if the previous one is different
191 + if (!prevVlanId.equals(egressVlanId)) {
192 + transitTreat.setVlanId(egressVlanId);
193 + }
194 + creator.createFlow(transitSelector,
195 + transitTreat.build(), prev, link.src(),
196 + intent.priority(), true, flows, devices);
197 + prev = link.dst();
198 + } else {
199 + // Egress traffic
200 + TrafficSelector egressSelector = DefaultTrafficSelector.builder()
201 + .matchInPort(prev.port())
202 + .matchVlanId(prevVlanId).build();
203 + TrafficTreatment.Builder egressTreat = DefaultTrafficTreatment.builder(intent.treatment());
204 +
205 + Optional<L2ModificationInstruction.ModVlanIdInstruction> modVlanIdInstruction = intent.treatment()
206 + .allInstructions().stream().filter(
207 + instruction -> instruction instanceof L2ModificationInstruction.ModVlanIdInstruction)
208 + .map(x -> (L2ModificationInstruction.ModVlanIdInstruction) x).findAny();
209 +
210 + Optional<L2ModificationInstruction.PopVlanInstruction> popVlanInstruction = intent.treatment()
211 + .allInstructions().stream().filter(
212 + instruction -> instruction instanceof L2ModificationInstruction.PopVlanInstruction)
213 + .map(x -> (L2ModificationInstruction.PopVlanInstruction) x).findAny();
214 +
215 + if (!modVlanIdInstruction.isPresent() && !popVlanInstruction.isPresent()) {
216 + if (vlanCriterion.isPresent()) {
217 + egressTreat.setVlanId(vlanCriterion.get().vlanId());
218 + } else {
219 + egressTreat.popVlan();
220 + }
221 + }
222 +
223 + creator.createFlow(egressSelector,
224 + egressTreat.build(), prev, link.src(),
225 + intent.priority(), true, flows, devices);
226 + }
227 + }
228 + }
229 +
230 + /**
231 + * Compiles an intent down to flows.
232 + *
233 + * @param creator how to create the flows
234 + * @param intent intent to process
235 + * @param flows list of generated flows
236 + * @param devices list of devices that correspond to the flows
237 + */
238 + public void compile(PathCompilerCreateFlow<T> creator,
239 + PathIntent intent,
240 + List<T> flows,
241 + List<DeviceId> devices) {
242 + // Note: right now recompile is not considered
243 + // TODO: implement recompile behavior
244 +
245 + List<Link> links = intent.path().links();
246 +
247 + Optional<EncapsulationConstraint> encapConstraint = intent.constraints().stream()
248 + .filter(constraint -> constraint instanceof EncapsulationConstraint)
249 + .map(x -> (EncapsulationConstraint) x).findAny();
250 + //if no encapsulation or is involved only a single switch use the default behaviour
251 + if (!encapConstraint.isPresent() || links.size() == 1) {
252 + for (int i = 0; i < links.size() - 1; i++) {
253 + ConnectPoint ingress = links.get(i).dst();
254 + ConnectPoint egress = links.get(i + 1).src();
255 + creator.createFlow(intent.selector(), intent.treatment(),
256 + ingress, egress, intent.priority(),
257 + isLast(links, i), flows, devices);
258 + }
259 + }
260 +
261 + encapConstraint.map(EncapsulationConstraint::encapType)
262 + .map(type -> {
263 + switch (type) {
264 + case VLAN:
265 + manageVlanEncap(creator, flows, devices, intent);
266 + // TODO: implement MPLS case here
267 + default:
268 + // Nothing to do
269 + }
270 + return 0;
271 + });
272 + }
273 +
274 +}
...@@ -15,57 +15,43 @@ ...@@ -15,57 +15,43 @@
15 */ 15 */
16 package org.onosproject.net.intent.impl.compiler; 16 package org.onosproject.net.intent.impl.compiler;
17 17
18 -import com.google.common.collect.ImmutableList; 18 +import java.util.LinkedList;
19 -import com.google.common.collect.Sets; 19 +import java.util.List;
20 +import java.util.Set;
21 +
20 import org.apache.felix.scr.annotations.Activate; 22 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 23 import org.apache.felix.scr.annotations.Component;
22 import org.apache.felix.scr.annotations.Deactivate; 24 import org.apache.felix.scr.annotations.Deactivate;
23 import org.apache.felix.scr.annotations.Reference; 25 import org.apache.felix.scr.annotations.Reference;
24 import org.apache.felix.scr.annotations.ReferenceCardinality; 26 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 -import org.onlab.packet.VlanId;
26 import org.onosproject.core.ApplicationId; 27 import org.onosproject.core.ApplicationId;
27 import org.onosproject.core.CoreService; 28 import org.onosproject.core.CoreService;
28 import org.onosproject.net.ConnectPoint; 29 import org.onosproject.net.ConnectPoint;
29 -import org.onosproject.net.Link; 30 +import org.onosproject.net.DeviceId;
30 -import org.onosproject.net.LinkKey;
31 import org.onosproject.net.flow.DefaultFlowRule; 31 import org.onosproject.net.flow.DefaultFlowRule;
32 import org.onosproject.net.flow.DefaultTrafficSelector; 32 import org.onosproject.net.flow.DefaultTrafficSelector;
33 import org.onosproject.net.flow.DefaultTrafficTreatment; 33 import org.onosproject.net.flow.DefaultTrafficTreatment;
34 import org.onosproject.net.flow.FlowRule; 34 import org.onosproject.net.flow.FlowRule;
35 import org.onosproject.net.flow.TrafficSelector; 35 import org.onosproject.net.flow.TrafficSelector;
36 import org.onosproject.net.flow.TrafficTreatment; 36 import org.onosproject.net.flow.TrafficTreatment;
37 -import org.onosproject.net.flow.criteria.Criterion;
38 -import org.onosproject.net.flow.criteria.VlanIdCriterion;
39 -import org.onosproject.net.flow.instructions.L2ModificationInstruction;
40 import org.onosproject.net.intent.FlowRuleIntent; 37 import org.onosproject.net.intent.FlowRuleIntent;
41 import org.onosproject.net.intent.Intent; 38 import org.onosproject.net.intent.Intent;
42 import org.onosproject.net.intent.IntentCompiler; 39 import org.onosproject.net.intent.IntentCompiler;
43 import org.onosproject.net.intent.IntentExtensionService; 40 import org.onosproject.net.intent.IntentExtensionService;
44 import org.onosproject.net.intent.PathIntent; 41 import org.onosproject.net.intent.PathIntent;
45 -import org.onosproject.net.intent.constraint.EncapsulationConstraint;
46 -import org.onosproject.net.intent.impl.IntentCompilationException;
47 -import org.onosproject.net.newresource.Resource;
48 import org.onosproject.net.newresource.ResourceService; 42 import org.onosproject.net.newresource.ResourceService;
49 -import org.onosproject.net.newresource.Resources;
50 import org.onosproject.net.resource.link.LinkResourceAllocations; 43 import org.onosproject.net.resource.link.LinkResourceAllocations;
51 import org.slf4j.Logger; 44 import org.slf4j.Logger;
52 45
53 -import java.util.Collections; 46 +import com.google.common.collect.ImmutableList;
54 -import java.util.HashMap;
55 -import java.util.Iterator;
56 -import java.util.LinkedList;
57 -import java.util.List;
58 -import java.util.Map;
59 -import java.util.Optional;
60 -import java.util.Set;
61 -import java.util.stream.Collectors;
62 -import java.util.stream.Stream;
63 47
64 -import static org.onosproject.net.LinkKey.linkKey;
65 import static org.slf4j.LoggerFactory.getLogger; 48 import static org.slf4j.LoggerFactory.getLogger;
66 49
67 @Component(immediate = true) 50 @Component(immediate = true)
68 -public class PathIntentCompiler implements IntentCompiler<PathIntent> { 51 +public class PathIntentCompiler
52 + extends PathCompiler<FlowRule>
53 + implements IntentCompiler<PathIntent>,
54 + PathCompiler.PathCompilerCreateFlow<FlowRule> {
69 55
70 private final Logger log = getLogger(getClass()); 56 private final Logger log = getLogger(getClass());
71 57
...@@ -94,47 +80,30 @@ public class PathIntentCompiler implements IntentCompiler<PathIntent> { ...@@ -94,47 +80,30 @@ public class PathIntentCompiler implements IntentCompiler<PathIntent> {
94 @Override 80 @Override
95 public List<Intent> compile(PathIntent intent, List<Intent> installable, 81 public List<Intent> compile(PathIntent intent, List<Intent> installable,
96 Set<LinkResourceAllocations> resources) { 82 Set<LinkResourceAllocations> resources) {
97 - // Note: right now recompile is not considered
98 - // TODO: implement recompile behavior
99 -
100 - List<Link> links = intent.path().links();
101 83
102 - Optional<EncapsulationConstraint> encapConstraint = intent.constraints().stream()
103 - .filter(constraint -> constraint instanceof EncapsulationConstraint)
104 - .map(x -> (EncapsulationConstraint) x).findAny();
105 - //if no encapsulation or is involved only a single switch use the default behaviour
106 - if (!encapConstraint.isPresent() || links.size() == 1) {
107 List<FlowRule> rules = new LinkedList<>(); 84 List<FlowRule> rules = new LinkedList<>();
108 - for (int i = 0; i < links.size() - 1; i++) { 85 + List<DeviceId> devices = new LinkedList<>();
109 - ConnectPoint ingress = links.get(i).dst(); 86 + compile(this, intent, rules, devices);
110 - ConnectPoint egress = links.get(i + 1).src();
111 - FlowRule rule = createFlowRule(intent.selector(), intent.treatment(),
112 - ingress, egress, intent.priority(),
113 - isLast(links, i));
114 - rules.add(rule);
115 - }
116 87
117 return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources())); 88 return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources()));
118 } 89 }
119 90
120 - List<FlowRule> rules = encapConstraint.map(EncapsulationConstraint::encapType) 91 + @Override
121 - .map(type -> { 92 + public Logger log() {
122 - switch (type) { 93 + return log;
123 - case VLAN:
124 - return manageVlanEncap(intent);
125 - // TODO: implement MPLS case here
126 - default:
127 - return Collections.<FlowRule>emptyList();
128 } 94 }
129 - })
130 - .orElse(Collections.emptyList());
131 95
132 - return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources())); 96 + @Override
97 + public ResourceService resourceService() {
98 + return resourceService;
133 } 99 }
134 100
135 - private FlowRule createFlowRule(TrafficSelector originalSelector, TrafficTreatment originalTreatment, 101 + @Override
102 + public void createFlow(TrafficSelector originalSelector, TrafficTreatment originalTreatment,
136 ConnectPoint ingress, ConnectPoint egress, 103 ConnectPoint ingress, ConnectPoint egress,
137 - int priority, boolean applyTreatment) { 104 + int priority, boolean applyTreatment,
105 + List<FlowRule> rules,
106 + List<DeviceId> devices) {
138 TrafficSelector selector = DefaultTrafficSelector.builder(originalSelector) 107 TrafficSelector selector = DefaultTrafficSelector.builder(originalSelector)
139 .matchInPort(ingress.port()) 108 .matchInPort(ingress.port())
140 .build(); 109 .build();
...@@ -147,164 +116,13 @@ public class PathIntentCompiler implements IntentCompiler<PathIntent> { ...@@ -147,164 +116,13 @@ public class PathIntentCompiler implements IntentCompiler<PathIntent> {
147 } 116 }
148 TrafficTreatment treatment = treatmentBuilder.setOutput(egress.port()).build(); 117 TrafficTreatment treatment = treatmentBuilder.setOutput(egress.port()).build();
149 118
150 - return DefaultFlowRule.builder() 119 + rules.add(DefaultFlowRule.builder()
151 .forDevice(ingress.deviceId()) 120 .forDevice(ingress.deviceId())
152 .withSelector(selector) 121 .withSelector(selector)
153 .withTreatment(treatment) 122 .withTreatment(treatment)
154 .withPriority(priority) 123 .withPriority(priority)
155 .fromApp(appId) 124 .fromApp(appId)
156 .makePermanent() 125 .makePermanent()
157 - .build(); 126 + .build());
158 - }
159 -
160 - private List<FlowRule> manageVlanEncap(PathIntent intent) {
161 - Map<LinkKey, VlanId> vlanIds = assignVlanId(intent);
162 -
163 - Iterator<Link> links = intent.path().links().iterator();
164 - Link srcLink = links.next();
165 -
166 - Link link = links.next();
167 - // List of flow rules to be installed
168 - List<FlowRule> rules = new LinkedList<>();
169 -
170 - // Ingress traffic
171 - VlanId vlanId = vlanIds.get(linkKey(link));
172 - if (vlanId == null) {
173 - throw new IntentCompilationException("No available VLAN ID for " + link);
174 - }
175 - VlanId prevVlanId = vlanId;
176 -
177 - Optional<VlanIdCriterion> vlanCriterion = intent.selector().criteria()
178 - .stream().filter(criterion -> criterion.type() == Criterion.Type.VLAN_VID)
179 - .map(criterion -> (VlanIdCriterion) criterion)
180 - .findAny();
181 -
182 - //Push VLAN if selector does not include VLAN
183 - TrafficTreatment.Builder treatBuilder = DefaultTrafficTreatment.builder();
184 - if (!vlanCriterion.isPresent()) {
185 - treatBuilder.pushVlan();
186 - }
187 - //Tag the traffic with the new encapsulation VLAN
188 - treatBuilder.setVlanId(vlanId);
189 - rules.add(createFlowRule(intent.selector(), treatBuilder.build(),
190 - srcLink.dst(), link.src(), intent.priority(), true));
191 -
192 - ConnectPoint prev = link.dst();
193 -
194 - while (links.hasNext()) {
195 -
196 - link = links.next();
197 -
198 - if (links.hasNext()) {
199 - // Transit traffic
200 - VlanId egressVlanId = vlanIds.get(linkKey(link));
201 - if (egressVlanId == null) {
202 - throw new IntentCompilationException("No available VLAN ID for " + link);
203 - }
204 - prevVlanId = egressVlanId;
205 -
206 - TrafficSelector transitSelector = DefaultTrafficSelector.builder()
207 - .matchInPort(prev.port())
208 - .matchVlanId(prevVlanId).build();
209 -
210 - TrafficTreatment.Builder transitTreat = DefaultTrafficTreatment.builder();
211 -
212 - // Set the new vlanId only if the previous one is different
213 - if (!prevVlanId.equals(egressVlanId)) {
214 - transitTreat.setVlanId(egressVlanId);
215 - }
216 - rules.add(createFlowRule(transitSelector,
217 - transitTreat.build(), prev, link.src(), intent.priority(), true));
218 - prev = link.dst();
219 - } else {
220 - // Egress traffic
221 - TrafficSelector egressSelector = DefaultTrafficSelector.builder()
222 - .matchInPort(prev.port())
223 - .matchVlanId(prevVlanId).build();
224 - TrafficTreatment.Builder egressTreat = DefaultTrafficTreatment.builder(intent.treatment());
225 -
226 - Optional<L2ModificationInstruction.ModVlanIdInstruction> modVlanIdInstruction = intent.treatment()
227 - .allInstructions().stream().filter(
228 - instruction -> instruction instanceof L2ModificationInstruction.ModVlanIdInstruction)
229 - .map(x -> (L2ModificationInstruction.ModVlanIdInstruction) x).findAny();
230 -
231 - Optional<L2ModificationInstruction.PopVlanInstruction> popVlanInstruction = intent.treatment()
232 - .allInstructions().stream().filter(
233 - instruction -> instruction instanceof L2ModificationInstruction.PopVlanInstruction)
234 - .map(x -> (L2ModificationInstruction.PopVlanInstruction) x).findAny();
235 -
236 - if (!modVlanIdInstruction.isPresent() && !popVlanInstruction.isPresent()) {
237 - if (vlanCriterion.isPresent()) {
238 - egressTreat.setVlanId(vlanCriterion.get().vlanId());
239 - } else {
240 - egressTreat.popVlan();
241 - }
242 - }
243 -
244 - rules.add(createFlowRule(egressSelector,
245 - egressTreat.build(), prev, link.src(), intent.priority(), true));
246 - }
247 - }
248 - return rules;
249 -
250 - }
251 -
252 - private Map<LinkKey, VlanId> assignVlanId(PathIntent intent) {
253 - Set<LinkKey> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
254 - .links().size() - 2);
255 - for (int i = 1; i <= intent.path().links().size() - 2; i++) {
256 - LinkKey link = linkKey(intent.path().links().get(i));
257 - linkRequest.add(link);
258 - // add the inverse link. I want that the VLANID is reserved both for
259 - // the direct and inverse link
260 - linkRequest.add(linkKey(link.dst(), link.src()));
261 - }
262 -
263 - Map<LinkKey, VlanId> vlanIds = findVlanIds(linkRequest);
264 - if (vlanIds.isEmpty()) {
265 - log.warn("No VLAN IDs available");
266 - return Collections.emptyMap();
267 - }
268 -
269 - //same VLANID is used for both directions
270 - Set<Resource> resources = vlanIds.entrySet().stream()
271 - .flatMap(x -> Stream.of(
272 - Resources.discrete(x.getKey().src().deviceId(), x.getKey().src().port(), x.getValue())
273 - .resource(),
274 - Resources.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port(), x.getValue())
275 - .resource()
276 - ))
277 - .collect(Collectors.toSet());
278 - List<org.onosproject.net.newresource.ResourceAllocation> allocations =
279 - resourceService.allocate(intent.id(), ImmutableList.copyOf(resources));
280 - if (allocations.isEmpty()) {
281 - Collections.emptyMap();
282 - }
283 -
284 - return vlanIds;
285 - }
286 -
287 - private Map<LinkKey, VlanId> findVlanIds(Set<LinkKey> links) {
288 - Map<LinkKey, VlanId> vlanIds = new HashMap<>();
289 - for (LinkKey link : links) {
290 - Set<VlanId> forward = findVlanId(link.src());
291 - Set<VlanId> backward = findVlanId(link.dst());
292 - Set<VlanId> common = Sets.intersection(forward, backward);
293 - if (common.isEmpty()) {
294 - continue;
295 - }
296 - vlanIds.put(link, common.iterator().next());
297 - }
298 - return vlanIds;
299 - }
300 -
301 - private Set<VlanId> findVlanId(ConnectPoint cp) {
302 - return resourceService.getAvailableResourceValues(
303 - Resources.discrete(cp.deviceId(), cp.port()).id(),
304 - VlanId.class);
305 - }
306 -
307 - private boolean isLast(List<Link> links, int i) {
308 - return i == links.size() - 2;
309 } 127 }
310 } 128 }
......
1 +/*
2 + * Copyright 2016 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 +package org.onosproject.net.intent.impl.compiler;
17 +
18 +import java.util.LinkedList;
19 +import java.util.List;
20 +import java.util.Set;
21 +
22 +import org.apache.felix.scr.annotations.Activate;
23 +import org.apache.felix.scr.annotations.Component;
24 +import org.apache.felix.scr.annotations.Deactivate;
25 +import org.apache.felix.scr.annotations.Reference;
26 +import org.apache.felix.scr.annotations.ReferenceCardinality;
27 +import org.onosproject.core.ApplicationId;
28 +import org.onosproject.core.CoreService;
29 +import org.onosproject.net.ConnectPoint;
30 +import org.onosproject.net.DeviceId;
31 +import org.onosproject.net.flow.DefaultTrafficSelector;
32 +import org.onosproject.net.flow.DefaultTrafficTreatment;
33 +import org.onosproject.net.flow.TrafficSelector;
34 +import org.onosproject.net.flow.TrafficTreatment;
35 +import org.onosproject.net.flowobjective.DefaultForwardingObjective;
36 +import org.onosproject.net.flowobjective.ForwardingObjective;
37 +import org.onosproject.net.flowobjective.Objective;
38 +import org.onosproject.net.intent.FlowObjectiveIntent;
39 +import org.onosproject.net.intent.Intent;
40 +import org.onosproject.net.intent.IntentCompiler;
41 +import org.onosproject.net.intent.IntentExtensionService;
42 +import org.onosproject.net.intent.PathIntent;
43 +import org.onosproject.net.newresource.ResourceService;
44 +import org.onosproject.net.resource.link.LinkResourceAllocations;
45 +import org.slf4j.Logger;
46 +
47 +import com.google.common.collect.ImmutableList;
48 +
49 +import static org.slf4j.LoggerFactory.getLogger;
50 +
51 +@Component(immediate = true)
52 +public class PathIntentFlowObjectiveCompiler
53 + extends PathCompiler<Objective>
54 + implements IntentCompiler<PathIntent>,
55 + PathCompiler.PathCompilerCreateFlow<Objective> {
56 +
57 + private final Logger log = getLogger(getClass());
58 +
59 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
60 + protected CoreService coreService;
61 +
62 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 + protected IntentExtensionService intentManager;
64 +
65 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 + protected ResourceService resourceService;
67 +
68 + private ApplicationId appId;
69 +
70 + @Activate
71 + public void activate() {
72 + appId = coreService.registerApplication("org.onosproject.net.intent");
73 + //intentManager.registerCompiler(PathIntent.class, this);
74 + }
75 +
76 + @Deactivate
77 + public void deactivate() {
78 + //intentManager.unregisterCompiler(PathIntent.class);
79 + }
80 +
81 + @Override
82 + public List<Intent> compile(PathIntent intent, List<Intent> installable,
83 + Set<LinkResourceAllocations> resources) {
84 +
85 + List<Objective> objectives = new LinkedList<>();
86 + List<DeviceId> devices = new LinkedList<>();
87 + compile(this, intent, objectives, devices);
88 +
89 + return ImmutableList.of(new FlowObjectiveIntent(appId, devices, objectives, intent.resources()));
90 + }
91 +
92 + @Override
93 + public Logger log() {
94 + return log;
95 + }
96 +
97 + @Override
98 + public ResourceService resourceService() {
99 + return resourceService;
100 + }
101 +
102 + @Override
103 + public void createFlow(TrafficSelector originalSelector, TrafficTreatment originalTreatment,
104 + ConnectPoint ingress, ConnectPoint egress,
105 + int priority, boolean applyTreatment,
106 + List<Objective> objectives,
107 + List<DeviceId> devices) {
108 + TrafficSelector selector = DefaultTrafficSelector.builder(originalSelector)
109 + .matchInPort(ingress.port())
110 + .build();
111 +
112 + TrafficTreatment.Builder treatmentBuilder;
113 + if (applyTreatment) {
114 + treatmentBuilder = DefaultTrafficTreatment.builder(originalTreatment);
115 + } else {
116 + treatmentBuilder = DefaultTrafficTreatment.builder();
117 + }
118 + TrafficTreatment treatment = treatmentBuilder.setOutput(egress.port()).build();
119 +
120 + objectives.add(DefaultForwardingObjective.builder()
121 + .withSelector(selector)
122 + .withTreatment(treatment)
123 + .withPriority(priority)
124 + .fromApp(appId)
125 + .makePermanent()
126 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
127 + .add());
128 + devices.add(ingress.deviceId());
129 + }
130 +}