blob: d61d1eb08db2127f95ec7f11ba715a7bf5c92828 [file] [log] [blame]
Sho SHIMIZUee2aa652015-02-25 18:56:43 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
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;
Pier Ventre766995d2016-10-05 22:15:56 -070047import org.onosproject.net.intent.constraint.EncapsulationConstraint;
48import org.onosproject.net.resource.ResourceService;
49import org.onosproject.net.resource.impl.LabelAllocator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080050
51import java.util.ArrayList;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080052import java.util.List;
Pier Ventre766995d2016-10-05 22:15:56 -070053import java.util.Map;
54import java.util.Optional;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080055import java.util.Set;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080056
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020057import static org.onosproject.net.domain.DomainId.LOCAL;
Pier Ventre81c47bf2016-11-04 07:26:22 -070058import static org.onosproject.net.flow.instructions.Instruction.Type.NOACTION;
59
Pier Ventred48320e2016-08-17 16:25:47 -070060/**
61 * Compiler to produce flow rules from link collections.
62 */
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080063@Component(immediate = true)
Pier Ventred48320e2016-08-17 16:25:47 -070064public class LinkCollectionIntentCompiler
65 extends LinkCollectionCompiler<FlowRule>
66 implements IntentCompiler<LinkCollectionIntent> {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080067
Pier Ventre81c47bf2016-11-04 07:26:22 -070068 private static final String UNKNOWN_INSTRUCTION = "Unknown instruction type";
69 private static final String UNSUPPORTED_INSTRUCTION = "Unsupported %s instruction";
70
Pier Ventre27d42572016-08-29 17:37:08 -070071
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080072 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080073 protected IntentConfigurableRegistrator registrator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080074
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected CoreService coreService;
77
Pier Ventre766995d2016-10-05 22:15:56 -070078 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected ResourceService resourceService;
80
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020081 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected DomainService domainService;
83
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080084 private ApplicationId appId;
85
86 @Activate
87 public void activate() {
88 appId = coreService.registerApplication("org.onosproject.net.intent");
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080089 registrator.registerCompiler(LinkCollectionIntent.class, this, false);
Pier Ventre766995d2016-10-05 22:15:56 -070090 if (labelAllocator == null) {
91 labelAllocator = new LabelAllocator(resourceService);
92 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080093 }
94
95 @Deactivate
96 public void deactivate() {
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080097 registrator.unregisterCompiler(LinkCollectionIntent.class, false);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080098 }
99
100 @Override
Sho SHIMIZUec07ffd2016-02-22 20:45:21 -0800101 public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
Pier Ventred48320e2016-08-17 16:25:47 -0700102
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800103 SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
104 SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
Pier Ventre766995d2016-10-05 22:15:56 -0700105 Map<ConnectPoint, Identifier<?>> labels = ImmutableMap.of();
106
107 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800108
Pier Ventred48320e2016-08-17 16:25:47 -0700109 computePorts(intent, inputPorts, outputPorts);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800110
Pier Ventre766995d2016-10-05 22:15:56 -0700111 if (encapConstraint.isPresent()) {
112 labels = labelAllocator.assignLabelToPorts(intent.links(),
113 intent.id(),
114 encapConstraint.get().encapType());
115 }
116
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +0200117 ImmutableList.Builder<Intent> intentList = ImmutableList.builder();
118 if (this.isDomainProcessingEnabled(intent)) {
119 intentList.addAll(this.getDomainIntents(intent, domainService));
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800120 }
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +0200121
122 List<FlowRule> rules = new ArrayList<>();
123 for (DeviceId deviceId : outputPorts.keySet()) {
124 // add only flows that are not inside of a domain
125 if (LOCAL.equals(domainService.getDomain(deviceId))) {
126 rules.addAll(createRules(
127 intent,
128 deviceId,
129 inputPorts.get(deviceId),
130 outputPorts.get(deviceId),
131 labels)
132 );
133 }
134 }
135 // if any rules have been created
136 if (!rules.isEmpty()) {
137 intentList.add(new FlowRuleIntent(appId, intent.key(), rules,
138 intent.resources()));
139 }
140 return intentList.build();
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800141 }
142
Pier Ventred48320e2016-08-17 16:25:47 -0700143 @Override
Yi Tseng84c5a3d2017-04-14 16:42:59 -0700144 boolean optimizeTreatments() {
145 return true;
146 }
147
148 @Override
Pier Ventre766995d2016-10-05 22:15:56 -0700149 protected List<FlowRule> createRules(LinkCollectionIntent intent,
150 DeviceId deviceId,
151 Set<PortNumber> inPorts,
152 Set<PortNumber> outPorts,
153 Map<ConnectPoint, Identifier<?>> labels) {
Brian O'Connor406e2642016-04-18 11:45:35 -0700154
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800155 List<FlowRule> rules = new ArrayList<>(inPorts.size());
Pier Ventre766995d2016-10-05 22:15:56 -0700156 /*
157 * Looking for the encapsulation constraint
158 */
159 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
Nicholas Dean126b8af2016-07-18 14:43:13 -0700160
Pier Ventred48320e2016-08-17 16:25:47 -0700161 inPorts.forEach(inport -> {
Pier Ventre766995d2016-10-05 22:15:56 -0700162
163 ForwardingInstructions instructions = this.createForwardingInstruction(
164 encapConstraint,
165 intent,
166 inport,
167 outPorts,
168 deviceId,
169 labels
170 );
171
Yi Tseng84c5a3d2017-04-14 16:42:59 -0700172 if (optimizeInstructions) {
Pier Ventre81c47bf2016-11-04 07:26:22 -0700173 TrafficTreatment compactedTreatment = compactActions(instructions.treatment());
174 instructions = new ForwardingInstructions(compactedTreatment, instructions.selector());
175 }
176
Pier Ventred48320e2016-08-17 16:25:47 -0700177 FlowRule rule = DefaultFlowRule.builder()
178 .forDevice(deviceId)
179 .withSelector(instructions.selector())
180 .withTreatment(instructions.treatment())
181 .withPriority(intent.priority())
182 .fromApp(appId)
183 .makePermanent()
184 .build();
185 rules.add(rule);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800186 }
Pier Ventred48320e2016-08-17 16:25:47 -0700187 );
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800188
189 return rules;
190 }
Pier Ventre81c47bf2016-11-04 07:26:22 -0700191
192 /**
193 * This method tries to optimize the chain of actions.
194 *
195 * @param oldTreatment the list of instructions to optimize
196 * @return the optimized set of actions
197 */
198 private TrafficTreatment compactActions(TrafficTreatment oldTreatment) {
199
200 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
201 Instruction instruction;
202 Instruction newInstruction;
203
204 for (int index = 0; index < oldTreatment.allInstructions().size(); index++) {
205 instruction = oldTreatment.allInstructions().get(index);
206 /*
207 * if the action is not optimizable. We simply add
208 * to the builder.
209 */
210 if (checkInstruction(instruction)) {
211 treatmentBuilder.add(instruction);
212 continue;
213 }
214 /*
215 * We try to run an optimization;
216 */
217 newInstruction = optimizeInstruction(index, instruction, oldTreatment.allInstructions());
218 if (!newInstruction.type().equals(NOACTION)) {
219 treatmentBuilder.add(newInstruction);
220 }
221 }
222
223 return treatmentBuilder.build();
224 }
225
226 /**
227 * Verifies if the given L2 instruction can be optimized.
228 *
229 * @param l2instruction the l2 instruction to verify
230 * @return true if the instruction cannot be optimized. False otherwise
231 */
232 private boolean checkL2Instructions(L2ModificationInstruction l2instruction) {
233 switch (l2instruction.subtype()) {
234 /*
235 * These actions can be performed safely.
236 */
237 case ETH_SRC:
238 case ETH_DST:
239 case VLAN_ID:
240 case VLAN_PCP:
241 case MPLS_LABEL:
242 case MPLS_BOS:
243 case TUNNEL_ID:
244 case VLAN_PUSH:
245 case VLAN_POP:
246 case MPLS_PUSH:
247 case MPLS_POP:
248 return true;
249 /*
250 * We should avoid dec mpls ttl multiple
251 * times.
252 */
253 case DEC_MPLS_TTL:
254 return false;
255
256 default:
257 throw new IntentCompilationException(String.format(UNSUPPORTED_INSTRUCTION, "L2"));
258 }
259
260 }
261
262 /**
263 * Verifies if the given L3 instruction can be optimized.
264 *
265 * @param l3instruction the l3 instruction to verify
266 * @return true if the instruction cannot be optimized. False otherwise
267 */
268 private boolean checkL3Instructions(L3ModificationInstruction l3instruction) {
269 switch (l3instruction.subtype()) {
270 /*
271 * These actions can be performed several times.
272 */
273 case IPV4_SRC:
274 case IPV4_DST:
275 case IPV6_SRC:
276 case IPV6_DST:
277 case IPV6_FLABEL:
278 case ARP_SPA:
279 case ARP_SHA:
280 case ARP_OP:
281 case TTL_OUT:
282 case TTL_IN:
283 return true;
284 /*
285 * This action should be executed one time;
286 */
287 case DEC_TTL:
288 return false;
289 default:
290 throw new IntentCompilationException(String.format(UNSUPPORTED_INSTRUCTION, "L3"));
291 }
292 }
293
294 /**
295 * Helper method to handle the optimization of the ttl instructions.
296 *
297 * @param index the index of the instruction
298 * @param instruction the instruction to optimize
299 * @param instructions the list of instructions to optimize
300 * @return no action if the action can be removed. The same instruction
301 * if we have to perform it
302 */
303 private Instruction optimizeTtlInstructions(int index, Instruction instruction, List<Instruction> instructions) {
304 /**
305 * Here we handle the optimization of decrement mpls ttl. The optimization
306 * is to come back to the start of the list looking for the same
307 * action. If we find the same action, we can optimize.
308 */
309 Instruction currentInstruction;
310 for (int i = index - 1; i >= 0; i--) {
311 currentInstruction = instructions.get(i);
312 if (currentInstruction.equals(instruction)) {
313 return Instructions.createNoAction();
314
315 }
316 }
317 return instruction;
318 }
319
320 /**
321 * Helper method to handle the optimization of the instructions.
322 *
323 * @param index the index of the instruction
324 * @param instruction the instruction to optimize
325 * @param instructions the list of instructions to optimize
326 * @return no action if the action can be removed. The same instruction
327 * if we have to perform it
328 */
329 private Instruction optimizeInstruction(int index, Instruction instruction, List<Instruction> instructions) {
330
331 switch (instruction.type()) {
332 /*
333 * Here we have the chance to optimize the dec mpls ttl action.
334 */
335 case L2MODIFICATION:
336 /*
337 * Here we have the chance to optimize the ttl related actions.
338 */
339 case L3MODIFICATION:
340 return optimizeTtlInstructions(index, instruction, instructions);
341
342 default:
343 throw new IntentCompilationException(UNKNOWN_INSTRUCTION);
344
345 }
346
347 }
348
349 /**
350 * Helper method to verify if the instruction can be optimized.
351 *
352 * @param instruction the instruction to verify
353 * @return true if the action can be optimized. False otherwise.
354 */
355 private boolean checkInstruction(Instruction instruction) {
356
357 switch (instruction.type()) {
358 /*
359 * The following instructions are not supported.
360 */
361 case L0MODIFICATION:
362 case L1MODIFICATION:
363 case L4MODIFICATION:
364 case NOACTION:
365 case OUTPUT:
366 case GROUP:
367 case QUEUE:
368 case TABLE:
369 case METER:
370 case METADATA:
371 case EXTENSION:
372 return true;
373 /*
374 * Here we have the chance to optimize actions like dec mpls ttl.
375 */
376 case L2MODIFICATION:
377 return checkL2Instructions((L2ModificationInstruction) instruction);
378 /*
379 * Here we have the chance to optimize the ttl related actions.
380 */
381 case L3MODIFICATION:
382 return checkL3Instructions((L3ModificationInstruction) instruction);
383
384 default:
385 throw new IntentCompilationException(UNKNOWN_INSTRUCTION);
386
387 }
388
389 }
390
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700391}