blob: 870473c251c940e4c06249a06d45c76c178f0ae9 [file] [log] [blame]
Ray Milkeydb74ec72016-03-01 10:35:24 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Ray Milkeydb74ec72016-03-01 10:35:24 -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
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080018import com.google.common.collect.HashMultimap;
Ray Milkey92d206b2018-02-12 15:01:24 -080019import com.google.common.collect.ImmutableList;
Pier Ventre766995d2016-10-05 22:15:56 -070020import com.google.common.collect.ImmutableMap;
Ray Milkey92d206b2018-02-12 15:01:24 -080021import com.google.common.collect.Lists;
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080022import com.google.common.collect.SetMultimap;
Ray Milkey92d206b2018-02-12 15:01:24 -080023import com.google.common.collect.Sets;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070024import org.osgi.service.component.annotations.Activate;
25import org.osgi.service.component.annotations.Component;
26import org.osgi.service.component.annotations.Deactivate;
27import org.osgi.service.component.annotations.Reference;
28import org.osgi.service.component.annotations.ReferenceCardinality;
Pier Ventre766995d2016-10-05 22:15:56 -070029import org.onlab.util.Identifier;
Ray Milkeydb74ec72016-03-01 10:35:24 -080030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
Pier Ventre766995d2016-10-05 22:15:56 -070032import org.onosproject.net.ConnectPoint;
Ray Milkeydb74ec72016-03-01 10:35:24 -080033import org.onosproject.net.DeviceId;
Ray Milkey92d206b2018-02-12 15:01:24 -080034import org.onosproject.net.EncapsulationType;
35import org.onosproject.net.FilteredConnectPoint;
Ray Milkeydb74ec72016-03-01 10:35:24 -080036import org.onosproject.net.PortNumber;
Ray Milkey92d206b2018-02-12 15:01:24 -080037import org.onosproject.net.domain.DomainService;
38import 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;
Ray Milkeydb74ec72016-03-01 10:35:24 -080045import org.onosproject.net.flowobjective.DefaultForwardingObjective;
Michele Santuarid2c8b152016-03-30 17:57:56 -070046import org.onosproject.net.flowobjective.DefaultNextObjective;
Ray Milkey92d206b2018-02-12 15:01:24 -080047import org.onosproject.net.flowobjective.FilteringObjective;
Michele Santuarid2c8b152016-03-30 17:57:56 -070048import org.onosproject.net.flowobjective.FlowObjectiveService;
Ray Milkeydb74ec72016-03-01 10:35:24 -080049import org.onosproject.net.flowobjective.ForwardingObjective;
Michele Santuarid2c8b152016-03-30 17:57:56 -070050import org.onosproject.net.flowobjective.NextObjective;
Ray Milkeydb74ec72016-03-01 10:35:24 -080051import org.onosproject.net.flowobjective.Objective;
52import org.onosproject.net.intent.FlowObjectiveIntent;
53import org.onosproject.net.intent.Intent;
54import org.onosproject.net.intent.IntentCompiler;
Ray Milkeydb74ec72016-03-01 10:35:24 -080055import org.onosproject.net.intent.LinkCollectionIntent;
Pier Ventre766995d2016-10-05 22:15:56 -070056import org.onosproject.net.intent.constraint.EncapsulationConstraint;
57import org.onosproject.net.resource.ResourceService;
58import org.onosproject.net.resource.impl.LabelAllocator;
Ray Milkey92d206b2018-02-12 15:01:24 -080059import org.slf4j.Logger;
Ray Milkeydb74ec72016-03-01 10:35:24 -080060
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080061import java.util.ArrayList;
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080062import java.util.List;
Pier Ventre766995d2016-10-05 22:15:56 -070063import java.util.Map;
64import java.util.Optional;
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080065import java.util.Set;
Ray Milkey92d206b2018-02-12 15:01:24 -080066import java.util.concurrent.atomic.AtomicBoolean;
67
68import static org.onosproject.net.domain.DomainId.LOCAL;
69import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
70import static org.slf4j.LoggerFactory.getLogger;
Ray Milkeydb74ec72016-03-01 10:35:24 -080071
72/**
73 * Compiler to produce flow objectives from link collections.
74 */
75@Component(immediate = true)
Pier Ventred48320e2016-08-17 16:25:47 -070076public class LinkCollectionIntentFlowObjectiveCompiler
77 extends LinkCollectionCompiler<Objective>
78 implements IntentCompiler<LinkCollectionIntent> {
Ray Milkey92d206b2018-02-12 15:01:24 -080079 private final Logger log = getLogger(getClass());
Ray Milkeydb74ec72016-03-01 10:35:24 -080080
Ray Milkeyd84f89b2018-08-17 14:54:17 -070081 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080082 protected IntentConfigurableRegistrator registrator;
Ray Milkeydb74ec72016-03-01 10:35:24 -080083
Ray Milkeyd84f89b2018-08-17 14:54:17 -070084 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeydb74ec72016-03-01 10:35:24 -080085 protected CoreService coreService;
86
Ray Milkeyd84f89b2018-08-17 14:54:17 -070087 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Michele Santuarid2c8b152016-03-30 17:57:56 -070088 protected FlowObjectiveService flowObjectiveService;
89
Ray Milkeyd84f89b2018-08-17 14:54:17 -070090 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Pier Ventre766995d2016-10-05 22:15:56 -070091 protected ResourceService resourceService;
92
Ray Milkeyd84f89b2018-08-17 14:54:17 -070093 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkey92d206b2018-02-12 15:01:24 -080094 protected DomainService domainService;
95
Ray Milkeydb74ec72016-03-01 10:35:24 -080096 private ApplicationId appId;
97
98 @Activate
99 public void activate() {
100 appId = coreService.registerApplication("org.onosproject.net.intent");
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800101 registrator.registerCompiler(LinkCollectionIntent.class, this, true);
Pier Ventre766995d2016-10-05 22:15:56 -0700102 if (labelAllocator == null) {
103 labelAllocator = new LabelAllocator(resourceService);
104 }
Ray Milkeydb74ec72016-03-01 10:35:24 -0800105 }
106
107 @Deactivate
108 public void deactivate() {
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800109 registrator.unregisterCompiler(LinkCollectionIntent.class, true);
Ray Milkeydb74ec72016-03-01 10:35:24 -0800110 }
111
112 @Override
Sho SHIMIZUec07ffd2016-02-22 20:45:21 -0800113 public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
Pier Ventred48320e2016-08-17 16:25:47 -0700114
Ray Milkeydb74ec72016-03-01 10:35:24 -0800115 SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
116 SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
Pier Ventre766995d2016-10-05 22:15:56 -0700117 Map<ConnectPoint, Identifier<?>> labels = ImmutableMap.of();
118
119 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
Ray Milkeydb74ec72016-03-01 10:35:24 -0800120
Pier Ventred48320e2016-08-17 16:25:47 -0700121 computePorts(intent, inputPorts, outputPorts);
Ray Milkeydb74ec72016-03-01 10:35:24 -0800122
Pier Ventre766995d2016-10-05 22:15:56 -0700123 if (encapConstraint.isPresent()) {
124 labels = labelAllocator.assignLabelToPorts(intent.links(),
Yi Tseng0db1f3b2017-05-25 10:08:06 -0700125 intent.key(),
Pier Ventre766995d2016-10-05 22:15:56 -0700126 encapConstraint.get().encapType());
127 }
128
Ray Milkey92d206b2018-02-12 15:01:24 -0800129 ImmutableList.Builder<Intent> intentList = ImmutableList.builder();
130 if (this.isDomainProcessingEnabled(intent)) {
131 intentList.addAll(this.getDomainIntents(intent, domainService));
132 }
133
Ray Milkeydb74ec72016-03-01 10:35:24 -0800134 List<Objective> objectives = new ArrayList<>();
135 List<DeviceId> devices = new ArrayList<>();
Ray Milkey92d206b2018-02-12 15:01:24 -0800136 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 }
Ray Milkeydb74ec72016-03-01 10:35:24 -0800150 }
Ray Milkey92d206b2018-02-12 15:01:24 -0800151 // 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();
Ray Milkeydb74ec72016-03-01 10:35:24 -0800159 }
160
Pier Ventred48320e2016-08-17 16:25:47 -0700161 @Override
Yi Tseng84c5a3d2017-04-14 16:42:59 -0700162 boolean optimizeTreatments() {
163 return false;
164 }
165
166 @Override
Pier Ventre766995d2016-10-05 22:15:56 -0700167 protected List<Objective> createRules(LinkCollectionIntent intent,
168 DeviceId deviceId,
169 Set<PortNumber> inPorts,
170 Set<PortNumber> outPorts,
171 Map<ConnectPoint, Identifier<?>> labels) {
Ray Milkeydb74ec72016-03-01 10:35:24 -0800172
Ray Milkey92d206b2018-02-12 15:01:24 -0800173 List<Objective> objectives = new ArrayList<>(inPorts.size() * 2);
Pier Ventre766995d2016-10-05 22:15:56 -0700174
175 /*
176 * Looking for the encapsulation constraint
177 */
178 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
Pier Ventred48320e2016-08-17 16:25:47 -0700179
Ray Milkey92d206b2018-02-12 15:01:24 -0800180 inPorts.forEach(inPort -> {
Pier Ventre766995d2016-10-05 22:15:56 -0700181
182 ForwardingInstructions instructions = this.createForwardingInstruction(
183 encapConstraint,
184 intent,
Ray Milkey92d206b2018-02-12 15:01:24 -0800185 inPort,
Pier Ventre766995d2016-10-05 22:15:56 -0700186 outPorts,
187 deviceId,
188 labels
189 );
Ray Milkeydb74ec72016-03-01 10:35:24 -0800190
Ray Milkey92d206b2018-02-12 15:01:24 -0800191 Set<TrafficTreatment> treatmentsWithDifferentPort =
192 Sets.newHashSet();
Michele Santuarid2c8b152016-03-30 17:57:56 -0700193
Ray Milkey92d206b2018-02-12 15:01:24 -0800194 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 }
Pier Ventred48320e2016-08-17 16:25:47 -0700205 }
Ray Milkey92d206b2018-02-12 15:01:24 -0800206
207 EthCriterion ethDst = (EthCriterion) intent.selector().getCriterion(Criterion.Type.ETH_DST);
208 boolean broadcastObjective = ethDst != null &&
209 (ethDst.mac().isBroadcast() || ethDst.mac().isMulticast());
210
211 FilteringObjective filteringObjective = buildFilteringObjective(intent,
212 instructions.selector(),
213 deviceId, inPort);
214 if (filteringObjective != null) {
215 objectives.add(filteringObjective);
216 }
217 if (treatmentsWithDifferentPort.size() < 2 && !broadcastObjective) {
218 objectives.addAll(createSimpleNextObjective(instructions, intent));
219 } else {
220 objectives.addAll(createBroadcastObjective(instructions,
221 treatmentsWithDifferentPort,
222 intent));
223 }
224 });
Ray Milkeydb74ec72016-03-01 10:35:24 -0800225
226 return objectives;
227 }
Pier Ventred48320e2016-08-17 16:25:47 -0700228
Ray Milkey92d206b2018-02-12 15:01:24 -0800229 private List<Objective> createBroadcastObjective(ForwardingInstructions instructions,
230 Set<TrafficTreatment> treatmentsWithDifferentPort,
231 LinkCollectionIntent intent) {
232 List<Objective> objectives = Lists.newArrayList();
233 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
252 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();
261 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
279 objectives.add(forwardingObjective);
280 objectives.add(nextObjective);
281
282 return objectives;
283 }
284
285 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
286 Integer nextId, int priority) {
287 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
298 private FilteringObjective buildFilteringObjective(LinkCollectionIntent intent,
299 TrafficSelector selector,
300 DeviceId deviceId,
301 PortNumber inPort) {
302 FilteringObjective.Builder builder = DefaultFilteringObjective.builder();
303 builder.fromApp(appId)
304 .permit()
305 .makePermanent()
306 .withPriority(intent.priority());
307 Criterion inPortCriterion = selector.getCriterion(Criterion.Type.IN_PORT);
308 if (inPortCriterion != null) {
309 builder.withKey(inPortCriterion);
310 }
311
312 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 }
387 return builder.add();
388 }
Ray Milkeydb74ec72016-03-01 10:35:24 -0800389}