blob: b82885693e2fc78218552e4097b52459a7d8cbaa [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
Yi Tseng84c5a3d2017-04-14 16:42:59 -0700130 boolean optimizeTreatments() {
131 return true;
132 }
133
134 @Override
Pier Ventre766995d2016-10-05 22:15:56 -0700135 protected List<FlowRule> createRules(LinkCollectionIntent intent,
136 DeviceId deviceId,
137 Set<PortNumber> inPorts,
138 Set<PortNumber> outPorts,
139 Map<ConnectPoint, Identifier<?>> labels) {
Brian O'Connor406e2642016-04-18 11:45:35 -0700140
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800141 List<FlowRule> rules = new ArrayList<>(inPorts.size());
Pier Ventre766995d2016-10-05 22:15:56 -0700142 /*
143 * Looking for the encapsulation constraint
144 */
145 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
Nicholas Dean126b8af2016-07-18 14:43:13 -0700146
Pier Ventred48320e2016-08-17 16:25:47 -0700147 inPorts.forEach(inport -> {
Pier Ventre766995d2016-10-05 22:15:56 -0700148
149 ForwardingInstructions instructions = this.createForwardingInstruction(
150 encapConstraint,
151 intent,
152 inport,
153 outPorts,
154 deviceId,
155 labels
156 );
157
Yi Tseng84c5a3d2017-04-14 16:42:59 -0700158 if (optimizeInstructions) {
Pier Ventre81c47bf2016-11-04 07:26:22 -0700159 TrafficTreatment compactedTreatment = compactActions(instructions.treatment());
160 instructions = new ForwardingInstructions(compactedTreatment, instructions.selector());
161 }
162
Pier Ventred48320e2016-08-17 16:25:47 -0700163 FlowRule rule = DefaultFlowRule.builder()
164 .forDevice(deviceId)
165 .withSelector(instructions.selector())
166 .withTreatment(instructions.treatment())
167 .withPriority(intent.priority())
168 .fromApp(appId)
169 .makePermanent()
170 .build();
171 rules.add(rule);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800172 }
Pier Ventred48320e2016-08-17 16:25:47 -0700173 );
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800174
175 return rules;
176 }
Pier Ventre81c47bf2016-11-04 07:26:22 -0700177
178 /**
179 * This method tries to optimize the chain of actions.
180 *
181 * @param oldTreatment the list of instructions to optimize
182 * @return the optimized set of actions
183 */
184 private TrafficTreatment compactActions(TrafficTreatment oldTreatment) {
185
186 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
187 Instruction instruction;
188 Instruction newInstruction;
189
190 for (int index = 0; index < oldTreatment.allInstructions().size(); index++) {
191 instruction = oldTreatment.allInstructions().get(index);
192 /*
193 * if the action is not optimizable. We simply add
194 * to the builder.
195 */
196 if (checkInstruction(instruction)) {
197 treatmentBuilder.add(instruction);
198 continue;
199 }
200 /*
201 * We try to run an optimization;
202 */
203 newInstruction = optimizeInstruction(index, instruction, oldTreatment.allInstructions());
204 if (!newInstruction.type().equals(NOACTION)) {
205 treatmentBuilder.add(newInstruction);
206 }
207 }
208
209 return treatmentBuilder.build();
210 }
211
212 /**
213 * Verifies if the given L2 instruction can be optimized.
214 *
215 * @param l2instruction the l2 instruction to verify
216 * @return true if the instruction cannot be optimized. False otherwise
217 */
218 private boolean checkL2Instructions(L2ModificationInstruction l2instruction) {
219 switch (l2instruction.subtype()) {
220 /*
221 * These actions can be performed safely.
222 */
223 case ETH_SRC:
224 case ETH_DST:
225 case VLAN_ID:
226 case VLAN_PCP:
227 case MPLS_LABEL:
228 case MPLS_BOS:
229 case TUNNEL_ID:
230 case VLAN_PUSH:
231 case VLAN_POP:
232 case MPLS_PUSH:
233 case MPLS_POP:
234 return true;
235 /*
236 * We should avoid dec mpls ttl multiple
237 * times.
238 */
239 case DEC_MPLS_TTL:
240 return false;
241
242 default:
243 throw new IntentCompilationException(String.format(UNSUPPORTED_INSTRUCTION, "L2"));
244 }
245
246 }
247
248 /**
249 * Verifies if the given L3 instruction can be optimized.
250 *
251 * @param l3instruction the l3 instruction to verify
252 * @return true if the instruction cannot be optimized. False otherwise
253 */
254 private boolean checkL3Instructions(L3ModificationInstruction l3instruction) {
255 switch (l3instruction.subtype()) {
256 /*
257 * These actions can be performed several times.
258 */
259 case IPV4_SRC:
260 case IPV4_DST:
261 case IPV6_SRC:
262 case IPV6_DST:
263 case IPV6_FLABEL:
264 case ARP_SPA:
265 case ARP_SHA:
266 case ARP_OP:
267 case TTL_OUT:
268 case TTL_IN:
269 return true;
270 /*
271 * This action should be executed one time;
272 */
273 case DEC_TTL:
274 return false;
275 default:
276 throw new IntentCompilationException(String.format(UNSUPPORTED_INSTRUCTION, "L3"));
277 }
278 }
279
280 /**
281 * Helper method to handle the optimization of the ttl instructions.
282 *
283 * @param index the index of the instruction
284 * @param instruction the instruction to optimize
285 * @param instructions the list of instructions to optimize
286 * @return no action if the action can be removed. The same instruction
287 * if we have to perform it
288 */
289 private Instruction optimizeTtlInstructions(int index, Instruction instruction, List<Instruction> instructions) {
290 /**
291 * Here we handle the optimization of decrement mpls ttl. The optimization
292 * is to come back to the start of the list looking for the same
293 * action. If we find the same action, we can optimize.
294 */
295 Instruction currentInstruction;
296 for (int i = index - 1; i >= 0; i--) {
297 currentInstruction = instructions.get(i);
298 if (currentInstruction.equals(instruction)) {
299 return Instructions.createNoAction();
300
301 }
302 }
303 return instruction;
304 }
305
306 /**
307 * Helper method to handle the optimization of the instructions.
308 *
309 * @param index the index of the instruction
310 * @param instruction the instruction to optimize
311 * @param instructions the list of instructions to optimize
312 * @return no action if the action can be removed. The same instruction
313 * if we have to perform it
314 */
315 private Instruction optimizeInstruction(int index, Instruction instruction, List<Instruction> instructions) {
316
317 switch (instruction.type()) {
318 /*
319 * Here we have the chance to optimize the dec mpls ttl action.
320 */
321 case L2MODIFICATION:
322 /*
323 * Here we have the chance to optimize the ttl related actions.
324 */
325 case L3MODIFICATION:
326 return optimizeTtlInstructions(index, instruction, instructions);
327
328 default:
329 throw new IntentCompilationException(UNKNOWN_INSTRUCTION);
330
331 }
332
333 }
334
335 /**
336 * Helper method to verify if the instruction can be optimized.
337 *
338 * @param instruction the instruction to verify
339 * @return true if the action can be optimized. False otherwise.
340 */
341 private boolean checkInstruction(Instruction instruction) {
342
343 switch (instruction.type()) {
344 /*
345 * The following instructions are not supported.
346 */
347 case L0MODIFICATION:
348 case L1MODIFICATION:
349 case L4MODIFICATION:
350 case NOACTION:
351 case OUTPUT:
352 case GROUP:
353 case QUEUE:
354 case TABLE:
355 case METER:
356 case METADATA:
357 case EXTENSION:
358 return true;
359 /*
360 * Here we have the chance to optimize actions like dec mpls ttl.
361 */
362 case L2MODIFICATION:
363 return checkL2Instructions((L2ModificationInstruction) instruction);
364 /*
365 * Here we have the chance to optimize the ttl related actions.
366 */
367 case L3MODIFICATION:
368 return checkL3Instructions((L3ModificationInstruction) instruction);
369
370 default:
371 throw new IntentCompilationException(UNKNOWN_INSTRUCTION);
372
373 }
374
375 }
376
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700377}