blob: 533b2e8bfd130381e4021995971d3f52d55ebcd0 [file] [log] [blame]
Yi Tsenga64f0c82017-02-03 11:17:15 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Yi Tsenga64f0c82017-02-03 11:17:15 -08003 *
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 */
16package org.onosproject.net.intent.impl.compiler;
17
18import com.google.common.collect.HashMultimap;
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020019import com.google.common.collect.ImmutableList;
Yi Tsenga64f0c82017-02-03 11:17:15 -080020import com.google.common.collect.ImmutableMap;
21import com.google.common.collect.Lists;
22import com.google.common.collect.SetMultimap;
23import com.google.common.collect.Sets;
24import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
27import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
29import org.onlab.util.Identifier;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.net.ConnectPoint;
33import org.onosproject.net.DeviceId;
Yi Tsengb32f7742017-05-09 15:34:19 -070034import org.onosproject.net.EncapsulationType;
35import org.onosproject.net.FilteredConnectPoint;
Yi Tsenga64f0c82017-02-03 11:17:15 -080036import org.onosproject.net.PortNumber;
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020037import org.onosproject.net.domain.DomainService;
Yi Tsenga64f0c82017-02-03 11:17:15 -080038import org.onosproject.net.flow.DefaultTrafficTreatment;
39import org.onosproject.net.flow.TrafficSelector;
40import org.onosproject.net.flow.TrafficTreatment;
41import org.onosproject.net.flow.criteria.Criterion;
42import org.onosproject.net.flow.criteria.EthCriterion;
43import org.onosproject.net.flow.instructions.Instruction;
44import org.onosproject.net.flowobjective.DefaultFilteringObjective;
45import org.onosproject.net.flowobjective.DefaultForwardingObjective;
46import org.onosproject.net.flowobjective.DefaultNextObjective;
47import org.onosproject.net.flowobjective.FilteringObjective;
48import org.onosproject.net.flowobjective.FlowObjectiveService;
49import org.onosproject.net.flowobjective.ForwardingObjective;
50import org.onosproject.net.flowobjective.NextObjective;
51import org.onosproject.net.flowobjective.Objective;
52import org.onosproject.net.intent.FlowObjectiveIntent;
53import org.onosproject.net.intent.Intent;
54import org.onosproject.net.intent.IntentCompiler;
55import org.onosproject.net.intent.LinkCollectionIntent;
56import org.onosproject.net.intent.constraint.EncapsulationConstraint;
57import org.onosproject.net.resource.ResourceService;
58import org.onosproject.net.resource.impl.LabelAllocator;
Yi Tsengb32f7742017-05-09 15:34:19 -070059import org.slf4j.Logger;
Yi Tsenga64f0c82017-02-03 11:17:15 -080060
61import java.util.ArrayList;
Yi Tsenga64f0c82017-02-03 11:17:15 -080062import java.util.List;
63import java.util.Map;
64import java.util.Optional;
65import java.util.Set;
Yi Tsengb32f7742017-05-09 15:34:19 -070066import java.util.concurrent.atomic.AtomicBoolean;
Yi Tsenga64f0c82017-02-03 11:17:15 -080067
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020068import static org.onosproject.net.domain.DomainId.LOCAL;
Yi Tsenga64f0c82017-02-03 11:17:15 -080069import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
Yi Tsengb32f7742017-05-09 15:34:19 -070070import static org.slf4j.LoggerFactory.getLogger;
Yi Tsenga64f0c82017-02-03 11:17:15 -080071
72/**
73 * Compiler to produce flow objectives from link collections.
74 */
75@Component(immediate = true)
76public class LinkCollectionIntentObjectiveCompiler
77 extends LinkCollectionCompiler<Objective>
78 implements IntentCompiler<LinkCollectionIntent> {
Yi Tsengb32f7742017-05-09 15:34:19 -070079 private final Logger log = getLogger(getClass());
Yi Tsenga64f0c82017-02-03 11:17:15 -080080
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected IntentConfigurableRegistrator registrator;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected CoreService coreService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected FlowObjectiveService flowObjectiveService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected ResourceService resourceService;
92
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020093 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected DomainService domainService;
95
Yi Tsenga64f0c82017-02-03 11:17:15 -080096 private ApplicationId appId;
97
98 @Activate
99 public void activate() {
100 appId = coreService.registerApplication("org.onosproject.net.intent");
101 registrator.registerCompiler(LinkCollectionIntent.class, this, true);
102 if (labelAllocator == null) {
103 labelAllocator = new LabelAllocator(resourceService);
104 }
105 }
106
Yi Tsenga64f0c82017-02-03 11:17:15 -0800107 @Deactivate
108 public void deactivate() {
109 registrator.unregisterCompiler(LinkCollectionIntent.class, true);
110 }
111
112 @Override
113 public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
114
115 SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
116 SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
117 Map<ConnectPoint, Identifier<?>> labels = ImmutableMap.of();
118
119 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
120
121 computePorts(intent, inputPorts, outputPorts);
122
123 if (encapConstraint.isPresent()) {
124 labels = labelAllocator.assignLabelToPorts(intent.links(),
Yi Tseng0db1f3b2017-05-25 10:08:06 -0700125 intent.key(),
Yi Tsenga64f0c82017-02-03 11:17:15 -0800126 encapConstraint.get().encapType());
127 }
128
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +0200129 ImmutableList.Builder<Intent> intentList = ImmutableList.builder();
130 if (this.isDomainProcessingEnabled(intent)) {
131 intentList.addAll(this.getDomainIntents(intent, domainService));
132 }
133
Yi Tsenga64f0c82017-02-03 11:17:15 -0800134 List<Objective> objectives = new ArrayList<>();
135 List<DeviceId> devices = new ArrayList<>();
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +0200136 for (DeviceId deviceId : outputPorts.keySet()) {
137 // add only objectives that are not inside of a domain
138 if (LOCAL.equals(domainService.getDomain(deviceId))) {
139 List<Objective> deviceObjectives =
140 createRules(intent,
141 deviceId,
142 inputPorts.get(deviceId),
143 outputPorts.get(deviceId),
144 labels);
145 deviceObjectives.forEach(objective -> {
146 objectives.add(objective);
147 devices.add(deviceId);
148 });
149 }
Yi Tsenga64f0c82017-02-03 11:17:15 -0800150 }
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +0200151 // if any objectives have been created
152 if (!objectives.isEmpty()) {
153 intentList.add(new FlowObjectiveIntent(appId, intent.key(), devices,
154 objectives,
155 intent.resources(),
156 intent.resourceGroup()));
157 }
158 return intentList.build();
Yi Tsenga64f0c82017-02-03 11:17:15 -0800159 }
160
161 @Override
Yi Tseng84c5a3d2017-04-14 16:42:59 -0700162 boolean optimizeTreatments() {
163 return false;
164 }
165
166 @Override
Yi Tsenga64f0c82017-02-03 11:17:15 -0800167 protected List<Objective> createRules(LinkCollectionIntent intent,
168 DeviceId deviceId,
169 Set<PortNumber> inPorts,
170 Set<PortNumber> outPorts,
171 Map<ConnectPoint, Identifier<?>> labels) {
172
173 List<Objective> objectives = new ArrayList<>(inPorts.size() * 2);
174
175 /*
176 * Looking for the encapsulation constraint
177 */
178 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
179
Yi Tsengb32f7742017-05-09 15:34:19 -0700180 inPorts.forEach(inPort -> {
Yi Tsenga64f0c82017-02-03 11:17:15 -0800181
182 ForwardingInstructions instructions = this.createForwardingInstruction(
183 encapConstraint,
184 intent,
Yi Tsengb32f7742017-05-09 15:34:19 -0700185 inPort,
Yi Tsenga64f0c82017-02-03 11:17:15 -0800186 outPorts,
187 deviceId,
188 labels
189 );
190
191 Set<TrafficTreatment> treatmentsWithDifferentPort =
192 Sets.newHashSet();
193
194 TrafficTreatment.Builder treatmentBuilder =
195 DefaultTrafficTreatment.builder();
196
197 for (Instruction inst : instructions.treatment().allInstructions()) {
198 if (inst.type() == OUTPUT) {
199 treatmentBuilder.add(inst);
200 treatmentsWithDifferentPort.add(treatmentBuilder.build());
201 treatmentBuilder = DefaultTrafficTreatment.builder();
202 } else {
203 treatmentBuilder.add(inst);
204 }
205 }
206
Yi Tsengb32f7742017-05-09 15:34:19 -0700207 EthCriterion ethDst = (EthCriterion) intent.selector().getCriterion(Criterion.Type.ETH_DST);
Yi Tsenga64f0c82017-02-03 11:17:15 -0800208 boolean broadcastObjective = ethDst != null &&
209 (ethDst.mac().isBroadcast() || ethDst.mac().isMulticast());
210
Yi Tsengb32f7742017-05-09 15:34:19 -0700211 FilteringObjective filteringObjective = buildFilteringObjective(intent,
212 instructions.selector(),
213 deviceId, inPort);
214 if (filteringObjective != null) {
215 objectives.add(filteringObjective);
216 }
Yi Tsenga64f0c82017-02-03 11:17:15 -0800217 if (treatmentsWithDifferentPort.size() < 2 && !broadcastObjective) {
218 objectives.addAll(createSimpleNextObjective(instructions, intent));
219 } else {
220 objectives.addAll(createBroadcastObjective(instructions,
221 treatmentsWithDifferentPort,
222 intent));
223 }
224 });
225
226 return objectives;
227 }
228
229 private List<Objective> createBroadcastObjective(ForwardingInstructions instructions,
230 Set<TrafficTreatment> treatmentsWithDifferentPort,
231 LinkCollectionIntent intent) {
232 List<Objective> objectives = Lists.newArrayList();
Yi Tsenga64f0c82017-02-03 11:17:15 -0800233 ForwardingObjective forwardingObjective;
234 NextObjective nextObjective;
235
236 Integer nextId = flowObjectiveService.allocateNextId();
237
238 forwardingObjective = buildForwardingObjective(instructions.selector(),
239 nextId, intent.priority());
240
241 DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
242 nxBuilder.withId(nextId)
243 .withMeta(instructions.selector())
244 .withType(NextObjective.Type.BROADCAST)
245 .fromApp(appId)
246 .withPriority(intent.priority())
247 .makePermanent();
248
249 treatmentsWithDifferentPort.forEach(nxBuilder::addTreatment);
250 nextObjective = nxBuilder.add();
251
Yi Tsenga64f0c82017-02-03 11:17:15 -0800252 objectives.add(forwardingObjective);
253 objectives.add(nextObjective);
254
255 return objectives;
256 }
257
258 private List<Objective> createSimpleNextObjective(ForwardingInstructions instructions,
259 LinkCollectionIntent intent) {
260 List<Objective> objectives = Lists.newArrayList();
Yi Tsenga64f0c82017-02-03 11:17:15 -0800261 ForwardingObjective forwardingObjective;
262 NextObjective nextObjective;
263
264 Integer nextId = flowObjectiveService.allocateNextId();
265
266 forwardingObjective = buildForwardingObjective(instructions.selector(),
267 nextId, intent.priority());
268
269 DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
270 nextObjective = nxBuilder.withId(nextId)
271 .withMeta(instructions.selector())
272 .addTreatment(instructions.treatment())
273 .withType(NextObjective.Type.SIMPLE)
274 .fromApp(appId)
275 .makePermanent()
276 .withPriority(intent.priority())
277 .add();
278
Yi Tsenga64f0c82017-02-03 11:17:15 -0800279 objectives.add(forwardingObjective);
280 objectives.add(nextObjective);
281
282 return objectives;
283 }
284
Yi Tsengb32f7742017-05-09 15:34:19 -0700285 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
286 Integer nextId, int priority) {
Yi Tsenga64f0c82017-02-03 11:17:15 -0800287 return DefaultForwardingObjective.builder()
288 .withMeta(selector)
289 .withSelector(selector)
290 .nextStep(nextId)
291 .fromApp(appId)
292 .withPriority(priority)
293 .withFlag(ForwardingObjective.Flag.SPECIFIC)
294 .makePermanent()
295 .add();
296 }
297
Yi Tsengb32f7742017-05-09 15:34:19 -0700298 private FilteringObjective buildFilteringObjective(LinkCollectionIntent intent,
299 TrafficSelector selector,
300 DeviceId deviceId,
301 PortNumber inPort) {
Yi Tsenga64f0c82017-02-03 11:17:15 -0800302 FilteringObjective.Builder builder = DefaultFilteringObjective.builder();
303 builder.fromApp(appId)
304 .permit()
305 .makePermanent()
Yi Tsengb32f7742017-05-09 15:34:19 -0700306 .withPriority(intent.priority());
307 Criterion inPortCriterion = selector.getCriterion(Criterion.Type.IN_PORT);
Yi Tsenga64f0c82017-02-03 11:17:15 -0800308 if (inPortCriterion != null) {
309 builder.withKey(inPortCriterion);
310 }
311
Yi Tsengb32f7742017-05-09 15:34:19 -0700312 FilteredConnectPoint ingressPoint = intent.filteredIngressPoints().stream()
313 .filter(fcp -> fcp.connectPoint().equals(new ConnectPoint(deviceId, inPort)))
314 .filter(fcp -> selector.criteria().containsAll(fcp.trafficSelector().criteria()))
315 .findFirst()
316 .orElse(null);
317
318 AtomicBoolean emptyCondition = new AtomicBoolean(true);
319 if (ingressPoint != null) {
320 // ingress point, use criterion of it
321 ingressPoint.trafficSelector().criteria().forEach(criterion -> {
322 builder.addCondition(criterion);
323 emptyCondition.set(false);
324 });
325 if (emptyCondition.get()) {
326 return null;
327 }
328 return builder.add();
329 }
330 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
331 if (encapConstraint.isPresent() &&
332 !encapConstraint.get().encapType().equals(EncapsulationType.NONE)) {
333 // encapsulation enabled, use encapsulation label and tag.
334 EncapsulationConstraint encap = encapConstraint.get();
335 switch (encap.encapType()) {
336 case VLAN:
337 builder.addCondition(selector.getCriterion(Criterion.Type.VLAN_VID));
338 emptyCondition.set(false);
339 break;
340 case MPLS:
341 builder.addCondition(selector.getCriterion(Criterion.Type.MPLS_LABEL));
342 emptyCondition.set(false);
343 break;
344 default:
345 log.warn("No filtering rule found because of unknown encapsulation type.");
346 break;
347 }
348 } else {
349 // encapsulation not enabled, check if the treatment applied to the ingress or not
350 if (intent.applyTreatmentOnEgress()) {
351 // filtering criterion will be changed on egress point, use
352 // criterion of ingress point
353 ingressPoint = intent.filteredIngressPoints().stream()
354 .findFirst()
355 .orElse(null);
356 if (ingressPoint == null) {
357 log.warn("No filtering rule found because no ingress point in the Intent");
358 } else {
359 ingressPoint.trafficSelector().criteria().stream()
360 .filter(criterion -> !criterion.type().equals(Criterion.Type.IN_PORT))
361 .forEach(criterion -> {
362 builder.addCondition(criterion);
363 emptyCondition.set(false);
364 });
365 }
366 } else {
367 // filtering criterion will be changed on ingress point, use
368 // criterion of egress point
369 FilteredConnectPoint egressPoint = intent.filteredEgressPoints().stream()
370 .findFirst()
371 .orElse(null);
372 if (egressPoint == null) {
373 log.warn("No filtering rule found because no egress point in the Intent");
374 } else {
375 egressPoint.trafficSelector().criteria().stream()
376 .filter(criterion -> !criterion.type().equals(Criterion.Type.IN_PORT))
377 .forEach(criterion -> {
378 builder.addCondition(criterion);
379 emptyCondition.set(false);
380 });
381 }
382 }
383 }
384 if (emptyCondition.get()) {
385 return null;
386 }
Yi Tsenga64f0c82017-02-03 11:17:15 -0800387 return builder.add();
388 }
Yi Tsenga64f0c82017-02-03 11:17:15 -0800389}