blob: d5df116caa9c6b43bafe252bda486a8d09bfd396 [file] [log] [blame]
Pier Ventred48320e2016-08-17 16:25:47 -07001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
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 */
16
17package org.onosproject.net.intent.impl.compiler;
18
Pier Ventre766995d2016-10-05 22:15:56 -070019import com.google.common.collect.Maps;
Pier Ventred48320e2016-08-17 16:25:47 -070020import com.google.common.collect.SetMultimap;
Yi Tseng2a81c9d2016-09-14 10:14:24 -070021import com.google.common.collect.Sets;
Pier Ventre766995d2016-10-05 22:15:56 -070022import org.onlab.packet.EthType;
23import org.onlab.packet.Ethernet;
Pier Ventred48320e2016-08-17 16:25:47 -070024import org.onlab.packet.Ip4Address;
25import org.onlab.packet.IpPrefix;
Pier Ventre766995d2016-10-05 22:15:56 -070026import org.onlab.packet.MplsLabel;
27import org.onlab.packet.VlanId;
28import org.onlab.util.Identifier;
Pier Ventred48320e2016-08-17 16:25:47 -070029import org.onosproject.net.ConnectPoint;
30import org.onosproject.net.DeviceId;
Pier Ventre766995d2016-10-05 22:15:56 -070031import org.onosproject.net.EncapsulationType;
Pier Ventred48320e2016-08-17 16:25:47 -070032import org.onosproject.net.Link;
33import org.onosproject.net.PortNumber;
Yi Tseng2a81c9d2016-09-14 10:14:24 -070034import org.onosproject.net.FilteredConnectPoint;
Pier Ventred48320e2016-08-17 16:25:47 -070035import org.onosproject.net.flow.DefaultTrafficSelector;
36import org.onosproject.net.flow.DefaultTrafficTreatment;
37import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng2a81c9d2016-09-14 10:14:24 -070039import org.onosproject.net.flow.criteria.Criteria;
40import org.onosproject.net.flow.criteria.Criterion;
Pier Ventre766995d2016-10-05 22:15:56 -070041import org.onosproject.net.flow.criteria.EthTypeCriterion;
Yi Tseng2a81c9d2016-09-14 10:14:24 -070042import org.onosproject.net.flow.criteria.MplsCriterion;
43import org.onosproject.net.flow.criteria.TunnelIdCriterion;
44import org.onosproject.net.flow.criteria.VlanIdCriterion;
Pier Ventre27d42572016-08-29 17:37:08 -070045import org.onosproject.net.flow.instructions.Instruction;
Pier Ventred48320e2016-08-17 16:25:47 -070046import org.onosproject.net.flow.instructions.L0ModificationInstruction;
47import org.onosproject.net.flow.instructions.L1ModificationInstruction;
48import org.onosproject.net.flow.instructions.L2ModificationInstruction;
49import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
Pier Ventred48320e2016-08-17 16:25:47 -070050import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
51import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
Yi Tseng2a81c9d2016-09-14 10:14:24 -070052import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
53import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
54import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
Pier Ventred48320e2016-08-17 16:25:47 -070055import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Pier Ventred48320e2016-08-17 16:25:47 -070056import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
57import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
Yi Tseng2a81c9d2016-09-14 10:14:24 -070058import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpIPInstruction;
59import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpEthInstruction;
60import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpOpInstruction;
Pier Ventred48320e2016-08-17 16:25:47 -070061import org.onosproject.net.flow.instructions.L4ModificationInstruction;
62import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
63import org.onosproject.net.intent.IntentCompilationException;
64import org.onosproject.net.intent.LinkCollectionIntent;
Pier Ventre766995d2016-10-05 22:15:56 -070065import org.onosproject.net.intent.constraint.EncapsulationConstraint;
66import org.onosproject.net.resource.impl.LabelAllocator;
Pier Ventred48320e2016-08-17 16:25:47 -070067
68import java.util.List;
Pier Ventre766995d2016-10-05 22:15:56 -070069import java.util.Map;
Pier Ventre647138f2016-08-26 17:32:44 -070070import java.util.Optional;
Pier Ventred48320e2016-08-17 16:25:47 -070071import java.util.Set;
Pier Ventred48320e2016-08-17 16:25:47 -070072
Yi Tseng2a81c9d2016-09-14 10:14:24 -070073import static org.onosproject.net.flow.criteria.Criterion.Type.MPLS_LABEL;
74import static org.onosproject.net.flow.criteria.Criterion.Type.TUNNEL_ID;
75import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
76
Pier Ventred48320e2016-08-17 16:25:47 -070077/**
78 * Shared APIs and implementations for Link Collection compilers.
79 */
80public class LinkCollectionCompiler<T> {
81
Pier Ventre766995d2016-10-05 22:15:56 -070082 /**
83 * Reference to the label allocator.
84 */
85 static LabelAllocator labelAllocator;
86
87 /**
88 * The allowed tag criterions.
89 */
Yi Tseng2a81c9d2016-09-14 10:14:24 -070090 private static final Set<Criterion.Type> TAG_CRITERION_TYPES =
91 Sets.immutableEnumSet(VLAN_VID, MPLS_LABEL, TUNNEL_ID);
92
Pier Ventred48320e2016-08-17 16:25:47 -070093 /**
Pier Ventre766995d2016-10-05 22:15:56 -070094 * Error message for wrong egress scenario.
95 */
96 private static final String WRONG_EGRESS = "Egress points not equal to 1 " +
97 "and apply treatment at ingress, " +
98 "which treatments should I apply ???";
99
100 /**
101 * Error message for wrong ingress scenario.
102 */
103 private static final String WRONG_INGRESS = "Ingress points not equal to 1 " +
104 "and apply treatment at egress, " +
105 "how can I match in the core ???";
106
107 /**
108 * Error message for wrong encapsulation scenario.
109 */
110 private static final String WRONG_ENCAPSULATION = "Wrong scenario - 1 hop with " +
111 "encapsualtion";
112
113 /**
114 * Error message for unavailable labels.
115 */
116 private static final String NO_LABELS = "No available label for %s";
117
118 /**
119 * Error message for wrong encapsulation.
120 */
121 private static final String UNKNOWN_ENCAPSULATION = "Unknown encapsulation type";
122
123 /**
124 * Error message for unsupported L0 instructions.
125 */
126 private static final String UNSUPPORTED_L0 = "L0 not supported";
127
128 /**
129 * Error message for unsupported L1 instructions.
130 */
131 private static final String UNSUPPORTED_L1 = "L1 not supported";
132
133 /**
134 * Error message for unsupported eth subtype.
135 */
136 private static final String UNSUPPORTED_ETH_SUBTYPE = "Bad eth subtype";
137
138 /**
139 * Error message for unsupported pop action.
140 */
141 private static final String UNSUPPORTED_POP_ACTION = "Can't handle pop label";
142
143 /**
144 * Error message for unsupported L2 instructions.
145 */
146 private static final String UNSUPPORTED_L2 = "Unknown L2 Modification instruction";
147
148 /**
149 * Error message for unsupported IP subtype.
150 */
151 private static final String UNSUPPORTED_IP_SUBTYPE = "Bad ip subtype";
152
153 /**
154 * Error message for unsupported ARP.
155 */
156 private static final String UNSUPPORTED_ARP = "IPv6 not supported for ARP";
157
158 /**
159 * Error message for unsupported L3 instructions.
160 */
161 private static final String UNSUPPORTED_L3 = "Unknown L3 Modification instruction";
162
163 /**
164 * Error message for unsupported L4 subtype.
165 */
166 private static final String UNSUPPORTED_L4_SUBTYPE = "Unknown L4 subtype";
167
168 /**
169 * Error message for unsupported L4 instructions.
170 */
171 private static final String UNSUPPORTED_L4 = "Unknown L4 Modification instruction";
172
173 /**
174 * Error message for unsupported instructions.
175 */
176 private static final String UNSUPPORTED_INSTRUCTION = "Unknown instruction type";
177
178 /**
179 * Creates the flows representations. This default implementation does
180 * nothing. Subclasses should override this method to create their
181 * specific flows representations (flow rule, flow objective).
182 *
183 * @param intent the intent to compile
184 * @param deviceId the affected device
185 * @param inPorts the input ports
186 * @param outPorts the output ports
187 * @param labels the labels for the label switching hop by hop
188 * @return the list of flows representations
189 */
190 protected List<T> createRules(LinkCollectionIntent intent,
191 DeviceId deviceId,
192 Set<PortNumber> inPorts,
193 Set<PortNumber> outPorts,
194 Map<ConnectPoint, Identifier<?>> labels) {
195 return null;
196 }
197
198 /**
199 * Helper method to handle the different scenario (not encap, single hop, encap).
200 *
201 * @param encapConstraint the encapsulation constraint if it is present
202 * @param intent the link collection intent
203 * @param inPort the in port
204 * @param outPorts the out ports
205 * @param deviceId the current device
206 * @param labels the labels used by the encapsulation
207 * @return the forwarding instruction
208 */
209 protected ForwardingInstructions createForwardingInstruction(Optional<EncapsulationConstraint> encapConstraint,
210 LinkCollectionIntent intent,
211 PortNumber inPort,
212 Set<PortNumber> outPorts,
213 DeviceId deviceId,
214 Map<ConnectPoint, Identifier<?>> labels) {
215 ForwardingInstructions instructions = null;
216 /*
217 * If not encapsulation or single hop.
218 */
219 if (!encapConstraint.isPresent() || intent.links().isEmpty()) {
220 instructions = this.createForwardingInstructions(
221 intent,
222 inPort,
223 deviceId,
224 outPorts
225 );
226 /*
227 * If encapsulation is present. We retrieve the labels
228 * for this iteration;
229 */
230 } else {
231 Identifier<?> inLabel = labels.get(new ConnectPoint(deviceId, inPort));
232 Map<ConnectPoint, Identifier<?>> outLabels = Maps.newHashMap();
233 outPorts.forEach(outPort -> {
234 ConnectPoint key = new ConnectPoint(deviceId, outPort);
235 outLabels.put(key, labels.get(key));
236 });
237 instructions = this.createForwardingInstructions(
238 intent,
239 inPort,
240 inLabel,
241 deviceId,
242 outPorts,
243 outLabels,
244 encapConstraint.get().encapType()
245 );
246 }
247 return instructions;
248 }
249
250 /**
251 * Manages the Intents with a single ingress point (p2p, sp2mp)
252 * creating properly the selector builder and the treatment builder.
253 *
254 * @param selectorBuilder the selector builder to update
255 * @param treatmentBuilder the treatment builder to update
256 * @param intent the intent to compile
257 * @param deviceId the current device
258 * @param outPorts the output ports of this device
259 */
260 private void manageSpIntent(TrafficSelector.Builder selectorBuilder,
261 TrafficTreatment.Builder treatmentBuilder,
262 LinkCollectionIntent intent,
263 DeviceId deviceId,
264 Set<PortNumber> outPorts) {
265 /*
266 * Sanity check.
267 */
268 if (intent.filteredIngressPoints().size() != 1) {
269 throw new IntentCompilationException(WRONG_INGRESS);
270 }
271 /*
272 * For the p2p and sp2mp the transition initial state
273 * to final state is performed at the egress.
274 */
275 Optional<FilteredConnectPoint> filteredIngressPoint =
276 intent.filteredIngressPoints().stream().findFirst();
277 /*
278 * We build the final selector, adding the selector
279 * of the FIP to the Intent selector and potentially
280 * overriding its matches.
281 */
282 filteredIngressPoint.get()
283 .trafficSelector()
284 .criteria()
285 .forEach(selectorBuilder::add);
286 /*
287 * In this scenario, potentially we can have several output
288 * ports.
289 */
290 for (PortNumber outPort : outPorts) {
291 Optional<FilteredConnectPoint> filteredEgressPoint =
292 getFilteredConnectPointFromIntent(deviceId, outPort, intent);
293 /*
294 * If we are at the egress, we have to transit to the final
295 * state.
296 */
297 if (filteredEgressPoint.isPresent()) {
298 /*
299 * We add the Intent treatment.
300 */
301 intent.treatment().allInstructions().stream()
302 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
303 .forEach(treatmentBuilder::add);
304 /*
305 * We generate the transition FIP->FEP.
306 */
307 TrafficTreatment forwardingTreatment =
308 forwardingTreatment(filteredIngressPoint.get().trafficSelector(),
309 filteredEgressPoint.get().trafficSelector(),
310 getEthType(intent.selector()));
311 /*
312 * We add the instruction necessary to the transition.
313 * Potentially we override the intent treatment.
314 */
315 forwardingTreatment.allInstructions().stream()
316 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
317 .forEach(treatmentBuilder::add);
318 }
319 /*
320 * Finally we set the output action.
321 */
322 treatmentBuilder.setOutput(outPort);
323 }
324 }
325
326 /**
327 * Manages the Intents with multiple ingress points creating properly
328 * the selector builder and the treatment builder.
329 *
330 * @param selectorBuilder the selector builder to update
331 * @param treatmentBuilder the treatment builder to update
332 * @param intent the intent to compile
333 * @param inPort the input port of the current device
334 * @param deviceId the current device
335 * @param outPorts the output ports of this device
336 */
337 private void manageMpIntent(TrafficSelector.Builder selectorBuilder,
338 TrafficTreatment.Builder treatmentBuilder,
339 LinkCollectionIntent intent,
340 PortNumber inPort,
341 DeviceId deviceId,
342 Set<PortNumber> outPorts) {
343 /*
344 * Sanity check
345 */
346 if (intent.filteredEgressPoints().size() != 1) {
347 throw new IntentCompilationException(WRONG_EGRESS);
348 }
349 /*
350 * We try to understand if the device is one of the ingress points.
351 */
352 Optional<FilteredConnectPoint> filteredIngressPoint =
353 getFilteredConnectPointFromIntent(deviceId, inPort, intent);
354 /*
355 * We retrieve from the Intent the unique egress points.
356 */
357 Optional<FilteredConnectPoint> filteredEgressPoint =
358 intent.filteredEgressPoints().stream().findFirst();
359 /*
360 * We check if the device is the ingress device
361 */
362 if (filteredIngressPoint.isPresent()) {
363 /*
364 * We are at ingress, so basically what we have to do is this:
365 * apply a set of operations (treatment, FEP) in order to have
366 * a transition from the initial state to the final state.
367 *
368 * We initialize the treatment with the Intent treatment
369 */
370 intent.treatment().allInstructions().stream()
371 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
372 .forEach(treatmentBuilder::add);
373 /*
374 * We build the final selector, adding the selector
375 * of the FIP to the Intent selector and potentially
376 * overriding its matches.
377 */
378 filteredIngressPoint.get()
379 .trafficSelector()
380 .criteria()
381 .forEach(selectorBuilder::add);
382 /*
383 * We define the transition FIP->FEP, basically
384 * the set of the operations we need for reaching
385 * the final state.
386 */
387 TrafficTreatment forwardingTreatment =
388 forwardingTreatment(filteredIngressPoint.get().trafficSelector(),
389 filteredEgressPoint.get().trafficSelector(),
390 getEthType(intent.selector()));
391 /*
392 * We add to the treatment the actions necessary for the
393 * transition, potentially overriding the treatment of the
394 * Intent. The Intent treatment has always a low priority
395 * in respect of the FEP.
396 */
397 forwardingTreatment.allInstructions().stream()
398 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
399 .forEach(treatmentBuilder::add);
400 } else {
401 /*
402 * We are in the core or in the egress switch.
403 * The packets are in their final state. We need
404 * to match against this final state.
405 *
406 * we derive the final state defined by the intent
407 * treatment.
408 */
409 updateBuilder(selectorBuilder, intent.treatment());
410 /*
411 * We derive the final state defined by the unique
412 * FEP. We merge the two states.
413 */
414 filteredEgressPoint.get()
415 .trafficSelector()
416 .criteria()
417 .forEach(selectorBuilder::add);
418 }
419 /*
420 * Finally we set the output action.
421 */
422 outPorts.forEach(treatmentBuilder::setOutput);
423 }
424
425 /**
426 * Computes treatment and selector which will be used
427 * in the flow representation (Rule, Objective).
428 *
429 * @param intent the intent to compile
430 * @param inPort the input port of this device
431 * @param deviceId the current device
432 * @param outPorts the output ports of this device
433 * @return the forwarding instruction object which encapsulates treatment and selector
434 */
435 protected ForwardingInstructions createForwardingInstructions(LinkCollectionIntent intent,
436 PortNumber inPort,
437 DeviceId deviceId,
438 Set<PortNumber> outPorts) {
439
440 /*
441 * We build an empty treatment and we initialize the selector with
442 * the intent selector.
443 */
444 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
445 .builder();
446 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector
447 .builder(intent.selector())
448 .matchInPort(inPort);
449
450 if (!intent.applyTreatmentOnEgress()) {
451 manageMpIntent(selectorBuilder,
452 treatmentBuilder,
453 intent,
454 inPort,
455 deviceId,
456 outPorts
457 );
458 } else {
459 manageSpIntent(selectorBuilder,
460 treatmentBuilder,
461 intent,
462 deviceId,
463 outPorts
464 );
465 }
466 /*
467 * We return selector and treatment necessary to build the flow rule
468 * or the flow objective.
469 */
470 return new ForwardingInstructions(treatmentBuilder.build(), selectorBuilder.build());
471 }
472
473 /**
474 * Manages the ingress of the Intents (p2p, sp2mp, mp2sp) with encapsulation.
475 *
476 * @param selectorBuilder the selector builder to update
477 * @param treatmentBuilder the treatment builder to update
478 * @param intent the intent to compile
479 * @param inPort the input port of this device
480 * @param deviceId the current device
481 * @param outPorts the output ports of this device
482 * @param outLabels the labels associated to the output port
483 * @param type the encapsulation type
484 */
485 private void manageEncapAtIngress(TrafficSelector.Builder selectorBuilder,
486 TrafficTreatment.Builder treatmentBuilder,
487 LinkCollectionIntent intent,
488 PortNumber inPort,
489 DeviceId deviceId,
490 Set<PortNumber> outPorts,
491 Map<ConnectPoint, Identifier<?>> outLabels,
492 EncapsulationType type) {
493
494 Optional<FilteredConnectPoint> filteredIngressPoint =
495 getFilteredConnectPointFromIntent(deviceId, inPort, intent);
496 /*
497 * We fill the selector builder with the intent selector.
498 */
499 intent.selector().criteria().forEach(selectorBuilder::add);
500 /*
501 * We build the final selector, adding the selector
502 * of the FIP to the Intent selector and potentially
503 * overriding its matches.
504 */
505 filteredIngressPoint.get()
506 .trafficSelector()
507 .criteria()
508 .forEach(selectorBuilder::add);
509 /*
510 * In this scenario, we can have several output ports.
511 */
512 outPorts.forEach(outPort -> {
513 Optional<FilteredConnectPoint> filteredEgressPoint =
514 getFilteredConnectPointFromIntent(deviceId, outPort, intent);
515 /*
516 * If we are at the egress, we don't handle
517 * with encapsulation. Error scenario
518 */
519 if (filteredEgressPoint.isPresent()) {
520 throw new IntentCompilationException(WRONG_ENCAPSULATION);
521 }
522 /*
523 * Transit/core, we have to transit to the intermediate
524 * state. We build a temporary selector for the encapsulation.
525 */
526 TrafficSelector.Builder encapBuilder = DefaultTrafficSelector.builder();
527 /*
528 * We retrieve the associated label to the output port.
529 */
530 ConnectPoint cp = new ConnectPoint(deviceId, outPort);
531 Identifier<?> outLabel = outLabels.get(cp);
532 /*
533 * If there aren't labels, we cannot handle.
534 */
535 if (outLabel == null) {
536 throw new IntentCompilationException(String.format(NO_LABELS, cp));
537 }
538 /*
539 * In the core we match using encapsulation.
540 */
541 updateSelectorFromEncapsulation(
542 encapBuilder,
543 type,
544 outLabel
545 );
546 /*
547 * We generate the transition.
548 */
549 TrafficTreatment forwardingTreatment =
550 forwardingTreatment(filteredIngressPoint.get().trafficSelector(),
551 encapBuilder.build(),
552 getEthType(intent.selector()));
553 /*
554 * We add the instruction necessary to the transition.
555 */
556 forwardingTreatment.allInstructions().stream()
557 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
558 .forEach(treatmentBuilder::add);
559 /*
560 * Finally we set the output action.
561 */
562 treatmentBuilder.setOutput(outPort);
563 });
564
565 }
566
567 /**
568 * Manages the core and transit of the Intents (p2p, sp2mp, mp2sp)
569 * with encapsulation.
570 *
571 * @param selectorBuilder the selector builder to update
572 * @param treatmentBuilder the treatment builder to update
573 * @param intent the intent to compile
574 * @param inPort the input port of this device
575 * @param inLabel the label associated to the input port
576 * @param deviceId the current device
577 * @param outPorts the output ports of this device
578 * @param outLabels the labels associated to the output port
579 * @param type the encapsulation type
580 */
581 private void manageEncapAtCoreAndEgress(TrafficSelector.Builder selectorBuilder,
582 TrafficTreatment.Builder treatmentBuilder,
583 LinkCollectionIntent intent,
584 PortNumber inPort,
585 Identifier<?> inLabel,
586 DeviceId deviceId,
587 Set<PortNumber> outPorts,
588 Map<ConnectPoint, Identifier<?>> outLabels,
589 EncapsulationType type) {
590
591 /*
592 * If there are not labels, we cannot handle.
593 */
594 ConnectPoint inCp = new ConnectPoint(deviceId, inPort);
595 if (inLabel == null) {
596 throw new IntentCompilationException(String.format(NO_LABELS, inCp));
597 }
598 /*
599 * In the core and at egress we match using encapsulation.
600 */
601 updateSelectorFromEncapsulation(
602 selectorBuilder,
603 type,
604 inLabel
605 );
606 /*
607 * We need to order the actions. First the actions
608 * related to the not-egress points.
609 */
610 outPorts.forEach(outPort -> {
611 Optional<FilteredConnectPoint> filteredEgressPoint =
612 getFilteredConnectPointFromIntent(deviceId, outPort, intent);
613 if (!filteredEgressPoint.isPresent()) {
614 /*
615 * We build a temporary selector for the encapsulation.
616 */
617 TrafficSelector.Builder encapBuilder = DefaultTrafficSelector.builder();
618 /*
619 * We retrieve the associated label to the output port.
620 */
621 ConnectPoint cp = new ConnectPoint(deviceId, outPort);
622 Identifier<?> outLabel = outLabels.get(cp);
623 /*
624 * If there are not labels, we cannot handle.
625 */
626 if (outLabel == null) {
627 throw new IntentCompilationException(String.format(NO_LABELS, cp));
628 }
629 /*
630 * In the core we match using encapsulation.
631 */
632 updateSelectorFromEncapsulation(
633 encapBuilder,
634 type,
635 outLabel
636 );
637 /*
638 * We generate the transition.
639 */
640 TrafficTreatment forwardingTreatment =
641 forwardingTreatment(selectorBuilder.build(),
642 encapBuilder.build(),
643 getEthType(intent.selector()));
644 /*
645 * We add the instruction necessary to the transition.
646 */
647 forwardingTreatment.allInstructions().stream()
648 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
649 .forEach(treatmentBuilder::add);
650 /*
651 * Finally we set the output action.
652 */
653 treatmentBuilder.setOutput(outPort);
654 }
655
656 });
657 /*
658 * In this case, we have to transit to the final
659 * state.
660 */
661 outPorts.forEach(outPort -> {
662 Optional<FilteredConnectPoint> filteredEgressPoint =
663 getFilteredConnectPointFromIntent(deviceId, outPort, intent);
664 if (filteredEgressPoint.isPresent()) {
665 /*
666 * We add the Intent treatment to the final
667 * treatment.
668 */
669 intent.treatment().allInstructions().stream()
670 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
671 .forEach(treatmentBuilder::add);
672 /*
673 * We generate the transition FIP->FEP.
674 */
675 TrafficTreatment forwardingTreatment =
676 forwardingTreatment(selectorBuilder.build(),
677 filteredEgressPoint.get().trafficSelector(),
678 getEthType(intent.selector()));
679 /*
680 * We add the instruction necessary to the transition.
681 * Potentially we override the intent treatment.
682 */
683 forwardingTreatment.allInstructions().stream()
684 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
685 .forEach(treatmentBuilder::add);
686 /*
687 * Finally we set the output action.
688 */
689 treatmentBuilder.setOutput(outPort);
690 }
691 });
692
693 }
694
695 /**
696 * Computes treatment and selector which will be used
697 * in the flow representation (Rule, Objective).
698 *
699 * @param intent the intent to compile
700 * @param inPort the input port of this device
701 * @param inLabel the label associated to the input port
702 * @param deviceId the current device
703 * @param outPorts the output ports of this device
704 * @param outLabels the labels associated to the output port
705 * @param type the encapsulation type
706 * @return the forwarding instruction object which encapsulates treatment and selector
707 */
708 protected ForwardingInstructions createForwardingInstructions(LinkCollectionIntent intent,
709 PortNumber inPort,
710 Identifier<?> inLabel,
711 DeviceId deviceId,
712 Set<PortNumber> outPorts,
713 Map<ConnectPoint, Identifier<?>> outLabels,
714 EncapsulationType type) {
715 /*
716 * We build an empty treatment and an empty selector.
717 */
718 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
719 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
720 selectorBuilder.matchInPort(inPort);
721 Optional<FilteredConnectPoint> filteredIngressPoint =
722 getFilteredConnectPointFromIntent(deviceId, inPort, intent);
723
724 if (filteredIngressPoint.isPresent()) {
725 manageEncapAtIngress(selectorBuilder,
726 treatmentBuilder,
727 intent,
728 inPort,
729 deviceId,
730 outPorts,
731 outLabels,
732 type
733 );
734 } else {
735 manageEncapAtCoreAndEgress(selectorBuilder,
736 treatmentBuilder,
737 intent,
738 inPort,
739 inLabel,
740 deviceId,
741 outPorts,
742 outLabels,
743 type);
744 }
745 /*
746 * We return selector and treatment necessary to build the flow rule
747 * or the flow objective.
748 */
749 return new ForwardingInstructions(treatmentBuilder.build(), selectorBuilder.build());
750 }
751
752 /**
753 * Helper class to encapsulate treatment and selector
754 * in an unique abstraction.
Pier Ventred48320e2016-08-17 16:25:47 -0700755 */
756 protected class ForwardingInstructions {
757
758 private TrafficTreatment trafficTreatment;
759
760 private TrafficSelector trafficSelector;
761
762 public ForwardingInstructions(TrafficTreatment treatment, TrafficSelector selector) {
763
764 this.trafficTreatment = treatment;
765 this.trafficSelector = selector;
766
767 }
768
769 public TrafficTreatment treatment() {
770 return this.trafficTreatment;
771 }
772
773 public TrafficSelector selector() {
774 return this.trafficSelector;
775 }
776
777 }
778
779 /**
Pier Ventre766995d2016-10-05 22:15:56 -0700780 * Helper method to compute input and output ports
781 * for each device crossed in the path.
Pier Ventred48320e2016-08-17 16:25:47 -0700782 *
783 * @param intent the related intents
784 * @param inputPorts the input ports to compute
785 * @param outputPorts the output ports to compute
786 */
787 protected void computePorts(LinkCollectionIntent intent,
788 SetMultimap<DeviceId, PortNumber> inputPorts,
789 SetMultimap<DeviceId, PortNumber> outputPorts) {
790
791 for (Link link : intent.links()) {
792 inputPorts.put(link.dst().deviceId(), link.dst().port());
793 outputPorts.put(link.src().deviceId(), link.src().port());
794 }
795
796 for (ConnectPoint ingressPoint : intent.ingressPoints()) {
797 inputPorts.put(ingressPoint.deviceId(), ingressPoint.port());
798 }
799
800 for (ConnectPoint egressPoint : intent.egressPoints()) {
801 outputPorts.put(egressPoint.deviceId(), egressPoint.port());
802 }
Pier Ventred48320e2016-08-17 16:25:47 -0700803
804 }
805
806 /**
Pier Ventre766995d2016-10-05 22:15:56 -0700807 * Retrieves the encapsulation constraint from the link collection intent.
Pier Ventred48320e2016-08-17 16:25:47 -0700808 *
Pier Ventre766995d2016-10-05 22:15:56 -0700809 * @param intent the intent to analyze
810 * @return the encapsulation constraint
Pier Ventred48320e2016-08-17 16:25:47 -0700811 */
Pier Ventre766995d2016-10-05 22:15:56 -0700812 protected Optional<EncapsulationConstraint> getIntentEncapConstraint(LinkCollectionIntent intent) {
813 return intent.constraints().stream()
814 .filter(constraint -> constraint instanceof EncapsulationConstraint)
815 .map(x -> (EncapsulationConstraint) x).findAny();
Pier Ventred48320e2016-08-17 16:25:47 -0700816 }
817
818
819 /**
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700820 * Get FilteredConnectPoint from LinkCollectionIntent.
Pier Ventre766995d2016-10-05 22:15:56 -0700821 *
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700822 * @param deviceId device Id for connect point
823 * @param portNumber port number
824 * @param intent source intent
825 * @return filtered connetion point
826 */
827 private Optional<FilteredConnectPoint> getFilteredConnectPointFromIntent(DeviceId deviceId,
828 PortNumber portNumber,
829 LinkCollectionIntent intent) {
830 Set<FilteredConnectPoint> filteredConnectPoints =
831 Sets.union(intent.filteredIngressPoints(), intent.filteredEgressPoints());
832 return filteredConnectPoints.stream()
833 .filter(port -> port.connectPoint().deviceId().equals(deviceId))
834 .filter(port -> port.connectPoint().port().equals(portNumber))
835 .findFirst();
836 }
837
838 /**
839 * Get tag criterion from selector.
840 * The criterion should be one of type in tagCriterionTypes.
841 *
842 * @param selector selector
843 * @return Criterion that matched, if there is no tag criterion, return null
844 */
845 private Criterion getTagCriterion(TrafficSelector selector) {
846 return selector.criteria().stream()
847 .filter(criterion -> TAG_CRITERION_TYPES.contains(criterion.type()))
848 .findFirst()
849 .orElse(Criteria.dummy());
850
851 }
852
853 /**
854 * Compares tag type between ingress and egress point and generate
855 * treatment for egress point of intent.
856 *
Pier Ventre766995d2016-10-05 22:15:56 -0700857 * @param ingress ingress selector for the intent
858 * @param egress egress selector for the intent
859 * @param ethType the ethertype to use in mpls_pop
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700860 * @return Builder of TrafficTreatment
861 */
Pier Ventre766995d2016-10-05 22:15:56 -0700862 private TrafficTreatment forwardingTreatment(TrafficSelector ingress,
863 TrafficSelector egress,
864 EthType ethType) {
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700865
866
Pier Ventre766995d2016-10-05 22:15:56 -0700867 if (ingress.equals(egress)) {
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700868 return DefaultTrafficTreatment.emptyTreatment();
869 }
870
871 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
872
873 /*
874 * "null" means there is no tag for the port
875 * Tag criterion will be null if port is normal connection point
876 */
Pier Ventre766995d2016-10-05 22:15:56 -0700877 Criterion ingressTagCriterion = getTagCriterion(ingress);
878 Criterion egressTagCriterion = getTagCriterion(egress);
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700879
880 if (ingressTagCriterion.type() != egressTagCriterion.type()) {
881
882 /*
883 * Tag type of ingress port and egress port are different.
884 * Need to remove tag from ingress, then add new tag for egress.
885 * Remove nothing if ingress port use VXLAN or there is no tag
886 * on ingress port.
887 */
888 switch (ingressTagCriterion.type()) {
889 case VLAN_VID:
890 builder.popVlan();
891 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700892
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700893 case MPLS_LABEL:
Pier Ventre766995d2016-10-05 22:15:56 -0700894 builder.popMpls(ethType);
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700895 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700896
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700897 default:
898 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700899
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700900 }
901
902 /*
903 * Push new tag for egress port.
904 */
905 switch (egressTagCriterion.type()) {
906 case VLAN_VID:
907 builder.pushVlan();
908 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700909
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700910 case MPLS_LABEL:
911 builder.pushMpls();
912 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700913
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700914 default:
915 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700916
Pier Ventred48320e2016-08-17 16:25:47 -0700917 }
918 }
919
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700920 switch (egressTagCriterion.type()) {
921 case VLAN_VID:
922 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) egressTagCriterion;
923 builder.setVlanId(vlanIdCriterion.vlanId());
924 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700925
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700926 case MPLS_LABEL:
927 MplsCriterion mplsCriterion = (MplsCriterion) egressTagCriterion;
928 builder.setMpls(mplsCriterion.label());
929 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700930
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700931 case TUNNEL_ID:
932 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) egressTagCriterion;
933 builder.setTunnelId(tunnelIdCriterion.tunnelId());
934 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700935
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700936 default:
937 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700938
Pier Ventre27d42572016-08-29 17:37:08 -0700939 }
Pier Ventre27d42572016-08-29 17:37:08 -0700940
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700941 return builder.build();
Pier Ventre647138f2016-08-26 17:32:44 -0700942 }
943
944 /**
Pier Ventred48320e2016-08-17 16:25:47 -0700945 * Update the selector builder using a L0 instruction.
946 *
947 * @param builder the builder to update
948 * @param l0instruction the l0 instruction to use
949 */
950 private void updateBuilder(TrafficSelector.Builder builder, L0ModificationInstruction l0instruction) {
Pier Ventre766995d2016-10-05 22:15:56 -0700951 throw new IntentCompilationException(UNSUPPORTED_L0);
Pier Ventred48320e2016-08-17 16:25:47 -0700952 }
953
954 /**
955 * Update the selector builder using a L1 instruction.
956 *
957 * @param builder the builder to update
958 * @param l1instruction the l1 instruction to use
959 */
960 private void updateBuilder(TrafficSelector.Builder builder, L1ModificationInstruction l1instruction) {
Pier Ventre766995d2016-10-05 22:15:56 -0700961 throw new IntentCompilationException(UNSUPPORTED_L1);
Pier Ventred48320e2016-08-17 16:25:47 -0700962 }
963
964 /**
965 * Update the selector builder using a L2 instruction.
966 *
967 * @param builder the builder to update
968 * @param l2instruction the l2 instruction to use
969 */
970 private void updateBuilder(TrafficSelector.Builder builder, L2ModificationInstruction l2instruction) {
971 switch (l2instruction.subtype()) {
972 case ETH_SRC:
973 case ETH_DST:
974 ModEtherInstruction ethInstr = (ModEtherInstruction) l2instruction;
975 switch (ethInstr.subtype()) {
976 case ETH_SRC:
977 builder.matchEthSrc(ethInstr.mac());
978 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700979
Pier Ventred48320e2016-08-17 16:25:47 -0700980 case ETH_DST:
981 builder.matchEthDst(ethInstr.mac());
982 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700983
Pier Ventred48320e2016-08-17 16:25:47 -0700984 default:
Pier Ventre766995d2016-10-05 22:15:56 -0700985 throw new IntentCompilationException(UNSUPPORTED_ETH_SUBTYPE);
Pier Ventred48320e2016-08-17 16:25:47 -0700986 }
987 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700988
Pier Ventred48320e2016-08-17 16:25:47 -0700989 case VLAN_ID:
990 ModVlanIdInstruction vlanIdInstr = (ModVlanIdInstruction) l2instruction;
991 builder.matchVlanId(vlanIdInstr.vlanId());
992 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700993
Pier Ventred48320e2016-08-17 16:25:47 -0700994 case VLAN_PUSH:
995 //FIXME
996 break;
Pier Ventre766995d2016-10-05 22:15:56 -0700997
Pier Ventred48320e2016-08-17 16:25:47 -0700998 case VLAN_POP:
999 //TODO how do we handle dropped label? remove the selector?
Pier Ventre766995d2016-10-05 22:15:56 -07001000 throw new IntentCompilationException(UNSUPPORTED_POP_ACTION);
Pier Ventred48320e2016-08-17 16:25:47 -07001001 case VLAN_PCP:
1002 ModVlanPcpInstruction vlanPcpInstruction = (ModVlanPcpInstruction) l2instruction;
1003 builder.matchVlanPcp(vlanPcpInstruction.vlanPcp());
1004 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001005
Pier Ventred48320e2016-08-17 16:25:47 -07001006 case MPLS_LABEL:
1007 case MPLS_PUSH:
1008 //FIXME
1009 ModMplsLabelInstruction mplsInstr = (ModMplsLabelInstruction) l2instruction;
1010 builder.matchMplsLabel(mplsInstr.label());
1011 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001012
Pier Ventred48320e2016-08-17 16:25:47 -07001013 case MPLS_POP:
1014 //TODO how do we handle dropped label? remove the selector?
Pier Ventre766995d2016-10-05 22:15:56 -07001015 throw new IntentCompilationException(UNSUPPORTED_POP_ACTION);
Pier Ventred48320e2016-08-17 16:25:47 -07001016 case DEC_MPLS_TTL:
1017 // no-op
1018 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001019
Pier Ventred48320e2016-08-17 16:25:47 -07001020 case MPLS_BOS:
1021 ModMplsBosInstruction mplsBosInstr = (ModMplsBosInstruction) l2instruction;
1022 builder.matchMplsBos(mplsBosInstr.mplsBos());
1023 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001024
Pier Ventred48320e2016-08-17 16:25:47 -07001025 case TUNNEL_ID:
1026 ModTunnelIdInstruction tunInstr = (ModTunnelIdInstruction) l2instruction;
1027 builder.matchTunnelId(tunInstr.tunnelId());
1028 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001029
Pier Ventred48320e2016-08-17 16:25:47 -07001030 default:
Pier Ventre766995d2016-10-05 22:15:56 -07001031 throw new IntentCompilationException(UNSUPPORTED_L2);
Pier Ventred48320e2016-08-17 16:25:47 -07001032 }
1033
1034 }
1035
1036 /**
1037 * Update the selector builder using a L3 instruction.
1038 *
1039 * @param builder the builder to update
1040 * @param l3instruction the l3 instruction to use
1041 */
1042 private void updateBuilder(TrafficSelector.Builder builder, L3ModificationInstruction l3instruction) {
1043 // TODO check ethernet proto
1044 switch (l3instruction.subtype()) {
1045 case IPV4_SRC:
1046 case IPV4_DST:
1047 case IPV6_SRC:
1048 case IPV6_DST:
1049 ModIPInstruction ipInstr = (ModIPInstruction) l3instruction;
1050 // TODO check if ip falls in original prefix
1051 IpPrefix prefix = ipInstr.ip().toIpPrefix();
1052 switch (ipInstr.subtype()) {
1053 case IPV4_SRC:
1054 builder.matchIPSrc(prefix);
1055 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001056
Pier Ventred48320e2016-08-17 16:25:47 -07001057 case IPV4_DST:
1058 builder.matchIPSrc(prefix);
1059 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001060
Pier Ventred48320e2016-08-17 16:25:47 -07001061 case IPV6_SRC:
1062 builder.matchIPv6Src(prefix);
1063 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001064
Pier Ventred48320e2016-08-17 16:25:47 -07001065 case IPV6_DST:
1066 builder.matchIPv6Dst(prefix);
1067 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001068
Pier Ventred48320e2016-08-17 16:25:47 -07001069 default:
Pier Ventre766995d2016-10-05 22:15:56 -07001070 throw new IntentCompilationException(UNSUPPORTED_IP_SUBTYPE);
Pier Ventred48320e2016-08-17 16:25:47 -07001071 }
1072 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001073
Pier Ventred48320e2016-08-17 16:25:47 -07001074 case IPV6_FLABEL:
1075 ModIPv6FlowLabelInstruction ipFlowInstr = (ModIPv6FlowLabelInstruction) l3instruction;
1076 builder.matchIPv6FlowLabel(ipFlowInstr.flowLabel());
1077 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001078
Pier Ventred48320e2016-08-17 16:25:47 -07001079 case DEC_TTL:
1080 // no-op
1081 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001082
Pier Ventred48320e2016-08-17 16:25:47 -07001083 case TTL_OUT:
1084 // no-op
1085 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001086
Pier Ventred48320e2016-08-17 16:25:47 -07001087 case TTL_IN:
1088 // no-op
1089 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001090
Pier Ventred48320e2016-08-17 16:25:47 -07001091 case ARP_SPA:
1092 ModArpIPInstruction arpIpInstr = (ModArpIPInstruction) l3instruction;
1093 if (arpIpInstr.ip().isIp4()) {
1094 builder.matchArpSpa((Ip4Address) arpIpInstr.ip());
1095 } else {
Pier Ventre766995d2016-10-05 22:15:56 -07001096 throw new IntentCompilationException(UNSUPPORTED_ARP);
Pier Ventred48320e2016-08-17 16:25:47 -07001097 }
1098 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001099
Pier Ventred48320e2016-08-17 16:25:47 -07001100 case ARP_SHA:
1101 ModArpEthInstruction arpEthInstr = (ModArpEthInstruction) l3instruction;
1102 builder.matchArpSha(arpEthInstr.mac());
1103 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001104
Pier Ventred48320e2016-08-17 16:25:47 -07001105 case ARP_OP:
1106 ModArpOpInstruction arpOpInstr = (ModArpOpInstruction) l3instruction;
1107 //FIXME is the long to int cast safe?
1108 builder.matchArpOp((int) arpOpInstr.op());
1109 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001110
Pier Ventred48320e2016-08-17 16:25:47 -07001111 default:
Pier Ventre766995d2016-10-05 22:15:56 -07001112 throw new IntentCompilationException(UNSUPPORTED_L3);
Pier Ventred48320e2016-08-17 16:25:47 -07001113 }
1114 }
1115
1116 /**
1117 * Update the selector builder using a L4 instruction.
1118 *
1119 * @param builder the builder to update
1120 * @param l4instruction the l4 instruction to use
1121 */
1122 private void updateBuilder(TrafficSelector.Builder builder, L4ModificationInstruction l4instruction) {
1123 if (l4instruction instanceof ModTransportPortInstruction) {
1124 // TODO check IP proto
1125 ModTransportPortInstruction l4mod = (ModTransportPortInstruction) l4instruction;
1126 switch (l4mod.subtype()) {
1127 case TCP_SRC:
1128 builder.matchTcpSrc(l4mod.port());
1129 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001130
Pier Ventred48320e2016-08-17 16:25:47 -07001131 case TCP_DST:
1132 builder.matchTcpDst(l4mod.port());
1133 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001134
Pier Ventred48320e2016-08-17 16:25:47 -07001135 case UDP_SRC:
1136 builder.matchUdpSrc(l4mod.port());
1137 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001138
Pier Ventred48320e2016-08-17 16:25:47 -07001139 case UDP_DST:
1140 builder.matchUdpDst(l4mod.port());
1141 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001142
Pier Ventred48320e2016-08-17 16:25:47 -07001143 default:
Pier Ventre766995d2016-10-05 22:15:56 -07001144 throw new IntentCompilationException(UNSUPPORTED_L4_SUBTYPE);
Pier Ventred48320e2016-08-17 16:25:47 -07001145 }
1146 } else {
Pier Ventre766995d2016-10-05 22:15:56 -07001147 throw new IntentCompilationException(UNSUPPORTED_L4);
Pier Ventred48320e2016-08-17 16:25:47 -07001148 }
1149 }
1150
1151 /**
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001152 * Update selector builder by using treatment.
Pier Ventred48320e2016-08-17 16:25:47 -07001153 *
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001154 * @param builder builder to update
1155 * @param treatment traffic treatment
Pier Ventred48320e2016-08-17 16:25:47 -07001156 */
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001157 private void updateBuilder(TrafficSelector.Builder builder, TrafficTreatment treatment) {
1158
1159 treatment.allInstructions().forEach(instruction -> {
1160 switch (instruction.type()) {
1161 case L0MODIFICATION:
1162 updateBuilder(builder, (L0ModificationInstruction) instruction);
1163 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001164
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001165 case L1MODIFICATION:
1166 updateBuilder(builder, (L1ModificationInstruction) instruction);
1167 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001168
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001169 case L2MODIFICATION:
1170 updateBuilder(builder, (L2ModificationInstruction) instruction);
1171 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001172
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001173 case L3MODIFICATION:
1174 updateBuilder(builder, (L3ModificationInstruction) instruction);
1175 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001176
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001177 case L4MODIFICATION:
1178 updateBuilder(builder, (L4ModificationInstruction) instruction);
1179 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001180
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001181 case NOACTION:
1182 case OUTPUT:
1183 case GROUP:
1184 case QUEUE:
1185 case TABLE:
1186 case METER:
1187 case METADATA:
1188 case EXTENSION: // TODO is extension no-op or unsupported?
1189 // Nothing to do
1190 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001191
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001192 default:
Pier Ventre766995d2016-10-05 22:15:56 -07001193 throw new IntentCompilationException(UNSUPPORTED_INSTRUCTION);
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001194 }
1195 });
1196
Pier Ventred48320e2016-08-17 16:25:47 -07001197 }
1198
Pier Ventre766995d2016-10-05 22:15:56 -07001199 /**
1200 * The method generates a selector starting from
1201 * the encapsulation information (type and label to match).
1202 *
1203 * @param selectorBuilder the builder to update
1204 * @param type the type of encapsulation
1205 * @param identifier the label to match
1206 */
1207 private void updateSelectorFromEncapsulation(TrafficSelector.Builder selectorBuilder,
1208 EncapsulationType type,
1209 Identifier<?> identifier) {
1210 switch (type) {
1211 case MPLS:
1212 MplsLabel label = (MplsLabel) identifier;
1213 selectorBuilder.matchMplsLabel(label);
1214 selectorBuilder.matchEthType(Ethernet.MPLS_UNICAST);
1215 break;
1216
1217 case VLAN:
1218 VlanId id = (VlanId) identifier;
1219 selectorBuilder.matchVlanId(id);
1220 break;
1221
1222 default:
1223 throw new IntentCompilationException(UNKNOWN_ENCAPSULATION);
1224 }
1225 }
1226
1227 /**
1228 * Helper function to define the match on the ethertype.
1229 * If the selector define an ethertype we will use it,
1230 * otherwise IPv4 will be used by default.
1231 *
1232 * @param selector the traffic selector
1233 * @return the ethertype we should match
1234 */
1235 private EthType getEthType(TrafficSelector selector) {
1236 Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE);
1237 if (c != null && c instanceof EthTypeCriterion) {
1238 EthTypeCriterion ethertype = (EthTypeCriterion) c;
1239 return ethertype.ethType();
1240 }
1241 return EthType.EtherType.IPV4.ethType();
1242 }
1243
Pier Ventred48320e2016-08-17 16:25:47 -07001244}