blob: 969372dcd4a675045c4aec89e55e57c00c245450 [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;
Pier Ventre766995d2016-10-05 22:15:56 -070019import com.google.common.collect.ImmutableMap;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080020import com.google.common.collect.SetMultimap;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
Pier Ventre766995d2016-10-05 22:15:56 -070026import org.onlab.util.Identifier;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080027import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
Pier Ventre766995d2016-10-05 22:15:56 -070029import org.onosproject.net.ConnectPoint;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080030import org.onosproject.net.DeviceId;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080031import org.onosproject.net.PortNumber;
32import org.onosproject.net.flow.DefaultFlowRule;
Pier Ventre81c47bf2016-11-04 07:26:22 -070033import org.onosproject.net.flow.DefaultTrafficTreatment;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080034import org.onosproject.net.flow.FlowRule;
Pier Ventre81c47bf2016-11-04 07:26:22 -070035import org.onosproject.net.flow.TrafficTreatment;
36import org.onosproject.net.flow.instructions.Instruction;
37import org.onosproject.net.flow.instructions.Instructions;
38import org.onosproject.net.flow.instructions.L2ModificationInstruction;
39import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080040import org.onosproject.net.intent.FlowRuleIntent;
41import org.onosproject.net.intent.Intent;
Pier Ventre81c47bf2016-11-04 07:26:22 -070042import org.onosproject.net.intent.IntentCompilationException;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080043import org.onosproject.net.intent.IntentCompiler;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080044import org.onosproject.net.intent.LinkCollectionIntent;
Pier Ventre766995d2016-10-05 22:15:56 -070045import org.onosproject.net.intent.constraint.EncapsulationConstraint;
46import org.onosproject.net.resource.ResourceService;
47import org.onosproject.net.resource.impl.LabelAllocator;
Pier Ventre27d42572016-08-29 17:37:08 -070048import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080050
51import java.util.ArrayList;
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070052import java.util.Collections;
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
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 private static Logger log = LoggerFactory.getLogger(LinkCollectionIntentCompiler.class);
72
73
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080074 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080075 protected IntentConfigurableRegistrator registrator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080076
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected CoreService coreService;
79
Pier Ventre766995d2016-10-05 22:15:56 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected ResourceService resourceService;
82
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080083 private ApplicationId appId;
84
85 @Activate
86 public void activate() {
87 appId = coreService.registerApplication("org.onosproject.net.intent");
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080088 registrator.registerCompiler(LinkCollectionIntent.class, this, false);
Pier Ventre766995d2016-10-05 22:15:56 -070089 if (labelAllocator == null) {
90 labelAllocator = new LabelAllocator(resourceService);
91 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080092 }
93
94 @Deactivate
95 public void deactivate() {
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080096 registrator.unregisterCompiler(LinkCollectionIntent.class, false);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080097 }
98
99 @Override
Sho SHIMIZUec07ffd2016-02-22 20:45:21 -0800100 public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
Pier Ventred48320e2016-08-17 16:25:47 -0700101
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800102 SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
103 SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
Pier Ventre766995d2016-10-05 22:15:56 -0700104 Map<ConnectPoint, Identifier<?>> labels = ImmutableMap.of();
105
106 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800107
Pier Ventred48320e2016-08-17 16:25:47 -0700108 computePorts(intent, inputPorts, outputPorts);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800109
Pier Ventre766995d2016-10-05 22:15:56 -0700110 if (encapConstraint.isPresent()) {
111 labels = labelAllocator.assignLabelToPorts(intent.links(),
112 intent.id(),
113 encapConstraint.get().encapType());
114 }
115
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800116 List<FlowRule> rules = new ArrayList<>();
Yi Tseng155370e2016-09-20 11:08:32 -0700117 for (DeviceId deviceId: outputPorts.keySet()) {
Pier Ventre766995d2016-10-05 22:15:56 -0700118 rules.addAll(createRules(
119 intent,
120 deviceId,
121 inputPorts.get(deviceId),
122 outputPorts.get(deviceId),
123 labels)
124 );
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800125 }
Yuta HIGUCHI652f27f2016-10-31 16:54:30 -0700126 return Collections.singletonList(new FlowRuleIntent(appId, intent.key(), rules, intent.resources()));
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800127 }
128
Pier Ventred48320e2016-08-17 16:25:47 -0700129 @Override
Pier Ventre766995d2016-10-05 22:15:56 -0700130 protected List<FlowRule> createRules(LinkCollectionIntent intent,
131 DeviceId deviceId,
132 Set<PortNumber> inPorts,
133 Set<PortNumber> outPorts,
134 Map<ConnectPoint, Identifier<?>> labels) {
Brian O'Connor406e2642016-04-18 11:45:35 -0700135
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800136 List<FlowRule> rules = new ArrayList<>(inPorts.size());
Pier Ventre766995d2016-10-05 22:15:56 -0700137 /*
138 * Looking for the encapsulation constraint
139 */
140 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
Nicholas Dean126b8af2016-07-18 14:43:13 -0700141
Pier Ventred48320e2016-08-17 16:25:47 -0700142 inPorts.forEach(inport -> {
Pier Ventre766995d2016-10-05 22:15:56 -0700143
144 ForwardingInstructions instructions = this.createForwardingInstruction(
145 encapConstraint,
146 intent,
147 inport,
148 outPorts,
149 deviceId,
150 labels
151 );
152
Pier Ventre81c47bf2016-11-04 07:26:22 -0700153 if (optimize) {
154 TrafficTreatment compactedTreatment = compactActions(instructions.treatment());
155 instructions = new ForwardingInstructions(compactedTreatment, instructions.selector());
156 }
157
Pier Ventred48320e2016-08-17 16:25:47 -0700158 FlowRule rule = DefaultFlowRule.builder()
159 .forDevice(deviceId)
160 .withSelector(instructions.selector())
161 .withTreatment(instructions.treatment())
162 .withPriority(intent.priority())
163 .fromApp(appId)
164 .makePermanent()
165 .build();
166 rules.add(rule);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800167 }
Pier Ventred48320e2016-08-17 16:25:47 -0700168 );
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800169
170 return rules;
171 }
Pier Ventre81c47bf2016-11-04 07:26:22 -0700172
173 /**
174 * This method tries to optimize the chain of actions.
175 *
176 * @param oldTreatment the list of instructions to optimize
177 * @return the optimized set of actions
178 */
179 private TrafficTreatment compactActions(TrafficTreatment oldTreatment) {
180
181 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
182 Instruction instruction;
183 Instruction newInstruction;
184
185 for (int index = 0; index < oldTreatment.allInstructions().size(); index++) {
186 instruction = oldTreatment.allInstructions().get(index);
187 /*
188 * if the action is not optimizable. We simply add
189 * to the builder.
190 */
191 if (checkInstruction(instruction)) {
192 treatmentBuilder.add(instruction);
193 continue;
194 }
195 /*
196 * We try to run an optimization;
197 */
198 newInstruction = optimizeInstruction(index, instruction, oldTreatment.allInstructions());
199 if (!newInstruction.type().equals(NOACTION)) {
200 treatmentBuilder.add(newInstruction);
201 }
202 }
203
204 return treatmentBuilder.build();
205 }
206
207 /**
208 * Verifies if the given L2 instruction can be optimized.
209 *
210 * @param l2instruction the l2 instruction to verify
211 * @return true if the instruction cannot be optimized. False otherwise
212 */
213 private boolean checkL2Instructions(L2ModificationInstruction l2instruction) {
214 switch (l2instruction.subtype()) {
215 /*
216 * These actions can be performed safely.
217 */
218 case ETH_SRC:
219 case ETH_DST:
220 case VLAN_ID:
221 case VLAN_PCP:
222 case MPLS_LABEL:
223 case MPLS_BOS:
224 case TUNNEL_ID:
225 case VLAN_PUSH:
226 case VLAN_POP:
227 case MPLS_PUSH:
228 case MPLS_POP:
229 return true;
230 /*
231 * We should avoid dec mpls ttl multiple
232 * times.
233 */
234 case DEC_MPLS_TTL:
235 return false;
236
237 default:
238 throw new IntentCompilationException(String.format(UNSUPPORTED_INSTRUCTION, "L2"));
239 }
240
241 }
242
243 /**
244 * Verifies if the given L3 instruction can be optimized.
245 *
246 * @param l3instruction the l3 instruction to verify
247 * @return true if the instruction cannot be optimized. False otherwise
248 */
249 private boolean checkL3Instructions(L3ModificationInstruction l3instruction) {
250 switch (l3instruction.subtype()) {
251 /*
252 * These actions can be performed several times.
253 */
254 case IPV4_SRC:
255 case IPV4_DST:
256 case IPV6_SRC:
257 case IPV6_DST:
258 case IPV6_FLABEL:
259 case ARP_SPA:
260 case ARP_SHA:
261 case ARP_OP:
262 case TTL_OUT:
263 case TTL_IN:
264 return true;
265 /*
266 * This action should be executed one time;
267 */
268 case DEC_TTL:
269 return false;
270 default:
271 throw new IntentCompilationException(String.format(UNSUPPORTED_INSTRUCTION, "L3"));
272 }
273 }
274
275 /**
276 * Helper method to handle the optimization of the ttl instructions.
277 *
278 * @param index the index of the instruction
279 * @param instruction the instruction to optimize
280 * @param instructions the list of instructions to optimize
281 * @return no action if the action can be removed. The same instruction
282 * if we have to perform it
283 */
284 private Instruction optimizeTtlInstructions(int index, Instruction instruction, List<Instruction> instructions) {
285 /**
286 * Here we handle the optimization of decrement mpls ttl. The optimization
287 * is to come back to the start of the list looking for the same
288 * action. If we find the same action, we can optimize.
289 */
290 Instruction currentInstruction;
291 for (int i = index - 1; i >= 0; i--) {
292 currentInstruction = instructions.get(i);
293 if (currentInstruction.equals(instruction)) {
294 return Instructions.createNoAction();
295
296 }
297 }
298 return instruction;
299 }
300
301 /**
302 * Helper method to handle the optimization of the instructions.
303 *
304 * @param index the index of the instruction
305 * @param instruction the instruction to optimize
306 * @param instructions the list of instructions to optimize
307 * @return no action if the action can be removed. The same instruction
308 * if we have to perform it
309 */
310 private Instruction optimizeInstruction(int index, Instruction instruction, List<Instruction> instructions) {
311
312 switch (instruction.type()) {
313 /*
314 * Here we have the chance to optimize the dec mpls ttl action.
315 */
316 case L2MODIFICATION:
317 /*
318 * Here we have the chance to optimize the ttl related actions.
319 */
320 case L3MODIFICATION:
321 return optimizeTtlInstructions(index, instruction, instructions);
322
323 default:
324 throw new IntentCompilationException(UNKNOWN_INSTRUCTION);
325
326 }
327
328 }
329
330 /**
331 * Helper method to verify if the instruction can be optimized.
332 *
333 * @param instruction the instruction to verify
334 * @return true if the action can be optimized. False otherwise.
335 */
336 private boolean checkInstruction(Instruction instruction) {
337
338 switch (instruction.type()) {
339 /*
340 * The following instructions are not supported.
341 */
342 case L0MODIFICATION:
343 case L1MODIFICATION:
344 case L4MODIFICATION:
345 case NOACTION:
346 case OUTPUT:
347 case GROUP:
348 case QUEUE:
349 case TABLE:
350 case METER:
351 case METADATA:
352 case EXTENSION:
353 return true;
354 /*
355 * Here we have the chance to optimize actions like dec mpls ttl.
356 */
357 case L2MODIFICATION:
358 return checkL2Instructions((L2ModificationInstruction) instruction);
359 /*
360 * Here we have the chance to optimize the ttl related actions.
361 */
362 case L3MODIFICATION:
363 return checkL3Instructions((L3ModificationInstruction) instruction);
364
365 default:
366 throw new IntentCompilationException(UNKNOWN_INSTRUCTION);
367
368 }
369
370 }
371
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700372}