blob: 64134086bb8ff079c782f4257f96bc711536138d [file] [log] [blame]
Sho SHIMIZUee2aa652015-02-25 18:56:43 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Sho SHIMIZUee2aa652015-02-25 18:56:43 -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;
Pier Ventre766995d2016-10-05 22:15:56 -070020import com.google.common.collect.ImmutableMap;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080021import com.google.common.collect.SetMultimap;
22import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
Pier Ventre766995d2016-10-05 22:15:56 -070027import org.onlab.util.Identifier;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080028import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
Pier Ventre766995d2016-10-05 22:15:56 -070030import org.onosproject.net.ConnectPoint;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080031import org.onosproject.net.DeviceId;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080032import org.onosproject.net.PortNumber;
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020033import org.onosproject.net.domain.DomainService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080034import org.onosproject.net.flow.DefaultFlowRule;
Pier Ventre81c47bf2016-11-04 07:26:22 -070035import org.onosproject.net.flow.DefaultTrafficTreatment;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080036import org.onosproject.net.flow.FlowRule;
Pier Ventre81c47bf2016-11-04 07:26:22 -070037import org.onosproject.net.flow.TrafficTreatment;
38import org.onosproject.net.flow.instructions.Instruction;
39import org.onosproject.net.flow.instructions.Instructions;
40import org.onosproject.net.flow.instructions.L2ModificationInstruction;
41import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080042import org.onosproject.net.intent.FlowRuleIntent;
43import org.onosproject.net.intent.Intent;
Pier Ventre81c47bf2016-11-04 07:26:22 -070044import org.onosproject.net.intent.IntentCompilationException;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080045import org.onosproject.net.intent.IntentCompiler;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080046import org.onosproject.net.intent.LinkCollectionIntent;
Ray Milkey39f78b62018-01-05 15:17:37 -080047import org.onosproject.net.intent.PathIntent;
Pier Ventre766995d2016-10-05 22:15:56 -070048import org.onosproject.net.intent.constraint.EncapsulationConstraint;
49import org.onosproject.net.resource.ResourceService;
50import org.onosproject.net.resource.impl.LabelAllocator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080051
52import java.util.ArrayList;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080053import java.util.List;
Pier Ventre766995d2016-10-05 22:15:56 -070054import java.util.Map;
55import java.util.Optional;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080056import java.util.Set;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080057
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020058import static org.onosproject.net.domain.DomainId.LOCAL;
Pier Ventre81c47bf2016-11-04 07:26:22 -070059import static org.onosproject.net.flow.instructions.Instruction.Type.NOACTION;
60
Pier Ventred48320e2016-08-17 16:25:47 -070061/**
62 * Compiler to produce flow rules from link collections.
63 */
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080064@Component(immediate = true)
Pier Ventred48320e2016-08-17 16:25:47 -070065public class LinkCollectionIntentCompiler
66 extends LinkCollectionCompiler<FlowRule>
67 implements IntentCompiler<LinkCollectionIntent> {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080068
Pier Ventre81c47bf2016-11-04 07:26:22 -070069 private static final String UNKNOWN_INSTRUCTION = "Unknown instruction type";
70 private static final String UNSUPPORTED_INSTRUCTION = "Unsupported %s instruction";
71
Pier Ventre27d42572016-08-29 17:37:08 -070072
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080073 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080074 protected IntentConfigurableRegistrator registrator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080075
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected CoreService coreService;
78
Pier Ventre766995d2016-10-05 22:15:56 -070079 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected ResourceService resourceService;
81
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020082 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected DomainService domainService;
84
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080085 private ApplicationId appId;
86
87 @Activate
88 public void activate() {
89 appId = coreService.registerApplication("org.onosproject.net.intent");
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080090 registrator.registerCompiler(LinkCollectionIntent.class, this, false);
Pier Ventre766995d2016-10-05 22:15:56 -070091 if (labelAllocator == null) {
92 labelAllocator = new LabelAllocator(resourceService);
93 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080094 }
95
96 @Deactivate
97 public void deactivate() {
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080098 registrator.unregisterCompiler(LinkCollectionIntent.class, false);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080099 }
100
101 @Override
Sho SHIMIZUec07ffd2016-02-22 20:45:21 -0800102 public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
Pier Ventred48320e2016-08-17 16:25:47 -0700103
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800104 SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
105 SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
Pier Ventre766995d2016-10-05 22:15:56 -0700106 Map<ConnectPoint, Identifier<?>> labels = ImmutableMap.of();
107
108 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800109
Pier Ventred48320e2016-08-17 16:25:47 -0700110 computePorts(intent, inputPorts, outputPorts);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800111
Pier Ventre766995d2016-10-05 22:15:56 -0700112 if (encapConstraint.isPresent()) {
113 labels = labelAllocator.assignLabelToPorts(intent.links(),
Yi Tseng0db1f3b2017-05-25 10:08:06 -0700114 intent.key(),
Pier Ventre766995d2016-10-05 22:15:56 -0700115 encapConstraint.get().encapType());
116 }
117
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +0200118 ImmutableList.Builder<Intent> intentList = ImmutableList.builder();
119 if (this.isDomainProcessingEnabled(intent)) {
120 intentList.addAll(this.getDomainIntents(intent, domainService));
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800121 }
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +0200122
123 List<FlowRule> rules = new ArrayList<>();
124 for (DeviceId deviceId : outputPorts.keySet()) {
125 // add only flows that are not inside of a domain
126 if (LOCAL.equals(domainService.getDomain(deviceId))) {
127 rules.addAll(createRules(
128 intent,
129 deviceId,
130 inputPorts.get(deviceId),
131 outputPorts.get(deviceId),
132 labels)
133 );
134 }
135 }
136 // if any rules have been created
137 if (!rules.isEmpty()) {
138 intentList.add(new FlowRuleIntent(appId, intent.key(), rules,
Ray Milkey39f78b62018-01-05 15:17:37 -0800139 intent.resources(),
140 PathIntent.ProtectionType.PRIMARY,
141 null));
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +0200142 }
143 return intentList.build();
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800144 }
145
Pier Ventred48320e2016-08-17 16:25:47 -0700146 @Override
Yi Tseng84c5a3d2017-04-14 16:42:59 -0700147 boolean optimizeTreatments() {
148 return true;
149 }
150
151 @Override
Pier Ventre766995d2016-10-05 22:15:56 -0700152 protected List<FlowRule> createRules(LinkCollectionIntent intent,
153 DeviceId deviceId,
154 Set<PortNumber> inPorts,
155 Set<PortNumber> outPorts,
156 Map<ConnectPoint, Identifier<?>> labels) {
Brian O'Connor406e2642016-04-18 11:45:35 -0700157
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800158 List<FlowRule> rules = new ArrayList<>(inPorts.size());
Pier Ventre766995d2016-10-05 22:15:56 -0700159 /*
160 * Looking for the encapsulation constraint
161 */
162 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
Nicholas Dean126b8af2016-07-18 14:43:13 -0700163
Pier Ventred48320e2016-08-17 16:25:47 -0700164 inPorts.forEach(inport -> {
Pier Ventre766995d2016-10-05 22:15:56 -0700165
166 ForwardingInstructions instructions = this.createForwardingInstruction(
167 encapConstraint,
168 intent,
169 inport,
170 outPorts,
171 deviceId,
172 labels
173 );
174
Yi Tseng84c5a3d2017-04-14 16:42:59 -0700175 if (optimizeInstructions) {
Pier Ventre81c47bf2016-11-04 07:26:22 -0700176 TrafficTreatment compactedTreatment = compactActions(instructions.treatment());
177 instructions = new ForwardingInstructions(compactedTreatment, instructions.selector());
178 }
179
Pier Ventred48320e2016-08-17 16:25:47 -0700180 FlowRule rule = DefaultFlowRule.builder()
181 .forDevice(deviceId)
182 .withSelector(instructions.selector())
183 .withTreatment(instructions.treatment())
184 .withPriority(intent.priority())
185 .fromApp(appId)
186 .makePermanent()
187 .build();
188 rules.add(rule);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800189 }
Pier Ventred48320e2016-08-17 16:25:47 -0700190 );
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800191
192 return rules;
193 }
Pier Ventre81c47bf2016-11-04 07:26:22 -0700194
195 /**
196 * This method tries to optimize the chain of actions.
197 *
198 * @param oldTreatment the list of instructions to optimize
199 * @return the optimized set of actions
200 */
201 private TrafficTreatment compactActions(TrafficTreatment oldTreatment) {
202
203 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
204 Instruction instruction;
205 Instruction newInstruction;
206
207 for (int index = 0; index < oldTreatment.allInstructions().size(); index++) {
208 instruction = oldTreatment.allInstructions().get(index);
209 /*
210 * if the action is not optimizable. We simply add
211 * to the builder.
212 */
213 if (checkInstruction(instruction)) {
214 treatmentBuilder.add(instruction);
215 continue;
216 }
217 /*
218 * We try to run an optimization;
219 */
220 newInstruction = optimizeInstruction(index, instruction, oldTreatment.allInstructions());
221 if (!newInstruction.type().equals(NOACTION)) {
222 treatmentBuilder.add(newInstruction);
223 }
224 }
225
226 return treatmentBuilder.build();
227 }
228
229 /**
230 * Verifies if the given L2 instruction can be optimized.
231 *
232 * @param l2instruction the l2 instruction to verify
233 * @return true if the instruction cannot be optimized. False otherwise
234 */
235 private boolean checkL2Instructions(L2ModificationInstruction l2instruction) {
236 switch (l2instruction.subtype()) {
237 /*
238 * These actions can be performed safely.
239 */
240 case ETH_SRC:
241 case ETH_DST:
242 case VLAN_ID:
243 case VLAN_PCP:
244 case MPLS_LABEL:
245 case MPLS_BOS:
246 case TUNNEL_ID:
247 case VLAN_PUSH:
248 case VLAN_POP:
249 case MPLS_PUSH:
250 case MPLS_POP:
251 return true;
252 /*
253 * We should avoid dec mpls ttl multiple
254 * times.
255 */
256 case DEC_MPLS_TTL:
257 return false;
258
259 default:
260 throw new IntentCompilationException(String.format(UNSUPPORTED_INSTRUCTION, "L2"));
261 }
262
263 }
264
265 /**
266 * Verifies if the given L3 instruction can be optimized.
267 *
268 * @param l3instruction the l3 instruction to verify
269 * @return true if the instruction cannot be optimized. False otherwise
270 */
271 private boolean checkL3Instructions(L3ModificationInstruction l3instruction) {
272 switch (l3instruction.subtype()) {
273 /*
274 * These actions can be performed several times.
275 */
276 case IPV4_SRC:
277 case IPV4_DST:
278 case IPV6_SRC:
279 case IPV6_DST:
280 case IPV6_FLABEL:
281 case ARP_SPA:
282 case ARP_SHA:
283 case ARP_OP:
284 case TTL_OUT:
285 case TTL_IN:
286 return true;
287 /*
288 * This action should be executed one time;
289 */
290 case DEC_TTL:
291 return false;
292 default:
293 throw new IntentCompilationException(String.format(UNSUPPORTED_INSTRUCTION, "L3"));
294 }
295 }
296
297 /**
298 * Helper method to handle the optimization of the ttl instructions.
299 *
300 * @param index the index of the instruction
301 * @param instruction the instruction to optimize
302 * @param instructions the list of instructions to optimize
303 * @return no action if the action can be removed. The same instruction
304 * if we have to perform it
305 */
306 private Instruction optimizeTtlInstructions(int index, Instruction instruction, List<Instruction> instructions) {
Ray Milkey39f78b62018-01-05 15:17:37 -0800307 /*
Pier Ventre81c47bf2016-11-04 07:26:22 -0700308 * Here we handle the optimization of decrement mpls ttl. The optimization
309 * is to come back to the start of the list looking for the same
310 * action. If we find the same action, we can optimize.
311 */
312 Instruction currentInstruction;
313 for (int i = index - 1; i >= 0; i--) {
314 currentInstruction = instructions.get(i);
315 if (currentInstruction.equals(instruction)) {
316 return Instructions.createNoAction();
317
318 }
319 }
320 return instruction;
321 }
322
323 /**
324 * Helper method to handle the optimization of the instructions.
325 *
326 * @param index the index of the instruction
327 * @param instruction the instruction to optimize
328 * @param instructions the list of instructions to optimize
329 * @return no action if the action can be removed. The same instruction
330 * if we have to perform it
331 */
332 private Instruction optimizeInstruction(int index, Instruction instruction, List<Instruction> instructions) {
333
334 switch (instruction.type()) {
335 /*
336 * Here we have the chance to optimize the dec mpls ttl action.
337 */
338 case L2MODIFICATION:
339 /*
340 * Here we have the chance to optimize the ttl related actions.
341 */
342 case L3MODIFICATION:
343 return optimizeTtlInstructions(index, instruction, instructions);
344
345 default:
346 throw new IntentCompilationException(UNKNOWN_INSTRUCTION);
347
348 }
349
350 }
351
352 /**
353 * Helper method to verify if the instruction can be optimized.
354 *
355 * @param instruction the instruction to verify
356 * @return true if the action can be optimized. False otherwise.
357 */
358 private boolean checkInstruction(Instruction instruction) {
359
360 switch (instruction.type()) {
361 /*
362 * The following instructions are not supported.
363 */
364 case L0MODIFICATION:
365 case L1MODIFICATION:
366 case L4MODIFICATION:
367 case NOACTION:
368 case OUTPUT:
369 case GROUP:
370 case QUEUE:
371 case TABLE:
372 case METER:
373 case METADATA:
374 case EXTENSION:
375 return true;
376 /*
377 * Here we have the chance to optimize actions like dec mpls ttl.
378 */
379 case L2MODIFICATION:
380 return checkL2Instructions((L2ModificationInstruction) instruction);
381 /*
382 * Here we have the chance to optimize the ttl related actions.
383 */
384 case L3MODIFICATION:
385 return checkL3Instructions((L3ModificationInstruction) instruction);
386
387 default:
388 throw new IntentCompilationException(UNKNOWN_INSTRUCTION);
389
390 }
391
392 }
393
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700394}