blob: df87844498d965eb4e52f3d2e0f607bbf405647f [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 Ventre81c47bf2016-11-04 07:26:22 -070019import com.google.common.collect.Lists;
Pier Ventre766995d2016-10-05 22:15:56 -070020import com.google.common.collect.Maps;
Pier Ventred48320e2016-08-17 16:25:47 -070021import com.google.common.collect.SetMultimap;
Yi Tseng2a81c9d2016-09-14 10:14:24 -070022import com.google.common.collect.Sets;
Pier Ventre766995d2016-10-05 22:15:56 -070023import org.onlab.packet.EthType;
24import org.onlab.packet.Ethernet;
Pier Ventred48320e2016-08-17 16:25:47 -070025import org.onlab.packet.Ip4Address;
26import org.onlab.packet.IpPrefix;
Pier Ventre766995d2016-10-05 22:15:56 -070027import org.onlab.packet.MplsLabel;
28import org.onlab.packet.VlanId;
29import org.onlab.util.Identifier;
Pier Ventred48320e2016-08-17 16:25:47 -070030import org.onosproject.net.ConnectPoint;
31import org.onosproject.net.DeviceId;
Pier Ventre766995d2016-10-05 22:15:56 -070032import org.onosproject.net.EncapsulationType;
Pier Ventre81c47bf2016-11-04 07:26:22 -070033import org.onosproject.net.FilteredConnectPoint;
Pier Ventred48320e2016-08-17 16:25:47 -070034import org.onosproject.net.Link;
35import org.onosproject.net.PortNumber;
36import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.TrafficSelector;
39import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng2a81c9d2016-09-14 10:14:24 -070040import org.onosproject.net.flow.criteria.Criteria;
41import org.onosproject.net.flow.criteria.Criterion;
Pier Ventre766995d2016-10-05 22:15:56 -070042import org.onosproject.net.flow.criteria.EthTypeCriterion;
Yi Tseng2a81c9d2016-09-14 10:14:24 -070043import org.onosproject.net.flow.criteria.MplsCriterion;
44import org.onosproject.net.flow.criteria.TunnelIdCriterion;
45import org.onosproject.net.flow.criteria.VlanIdCriterion;
Pier Ventre27d42572016-08-29 17:37:08 -070046import org.onosproject.net.flow.instructions.Instruction;
Pier Ventred48320e2016-08-17 16:25:47 -070047import org.onosproject.net.flow.instructions.L0ModificationInstruction;
48import org.onosproject.net.flow.instructions.L1ModificationInstruction;
49import org.onosproject.net.flow.instructions.L2ModificationInstruction;
50import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
Pier Ventre81c47bf2016-11-04 07:26:22 -070051import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
52import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
53import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
Pier Ventred48320e2016-08-17 16:25:47 -070054import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
55import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
56import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Pier Ventre81c47bf2016-11-04 07:26:22 -070057import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpEthInstruction;
58import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpIPInstruction;
59import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpOpInstruction;
Pier Ventred48320e2016-08-17 16:25:47 -070060import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
61import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
62import org.onosproject.net.flow.instructions.L4ModificationInstruction;
63import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
64import org.onosproject.net.intent.IntentCompilationException;
65import org.onosproject.net.intent.LinkCollectionIntent;
Pier Ventre766995d2016-10-05 22:15:56 -070066import org.onosproject.net.intent.constraint.EncapsulationConstraint;
67import org.onosproject.net.resource.impl.LabelAllocator;
Pier Ventred48320e2016-08-17 16:25:47 -070068
69import java.util.List;
Pier Ventre766995d2016-10-05 22:15:56 -070070import java.util.Map;
Pier Ventre647138f2016-08-26 17:32:44 -070071import java.util.Optional;
Pier Ventred48320e2016-08-17 16:25:47 -070072import java.util.Set;
Pier Ventre81c47bf2016-11-04 07:26:22 -070073import java.util.stream.Collectors;
Pier Ventred48320e2016-08-17 16:25:47 -070074
Pier Ventre81c47bf2016-11-04 07:26:22 -070075import static org.onosproject.net.flow.criteria.Criterion.Type.*;
Yi Tseng2a81c9d2016-09-14 10:14:24 -070076
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 /**
Pier Ventre81c47bf2016-11-04 07:26:22 -070088 * Influence compiler behavior. If true the compiler
89 * try to optimize the chain of the actions.
90 */
91 static boolean optimize;
92
93 /**
94 * Influence compiler behavior. If true the compiler
95 * try to optimize the copy ttl actions.
96 */
97 static boolean copyTtl;
98
99 /**
Pier Ventre766995d2016-10-05 22:15:56 -0700100 * The allowed tag criterions.
101 */
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700102 private static final Set<Criterion.Type> TAG_CRITERION_TYPES =
103 Sets.immutableEnumSet(VLAN_VID, MPLS_LABEL, TUNNEL_ID);
104
Pier Ventred48320e2016-08-17 16:25:47 -0700105 /**
Pier Ventre766995d2016-10-05 22:15:56 -0700106 * Error message for wrong egress scenario.
107 */
108 private static final String WRONG_EGRESS = "Egress points not equal to 1 " +
109 "and apply treatment at ingress, " +
110 "which treatments should I apply ???";
111
112 /**
113 * Error message for wrong ingress scenario.
114 */
115 private static final String WRONG_INGRESS = "Ingress points not equal to 1 " +
116 "and apply treatment at egress, " +
117 "how can I match in the core ???";
118
119 /**
120 * Error message for wrong encapsulation scenario.
121 */
122 private static final String WRONG_ENCAPSULATION = "Wrong scenario - 1 hop with " +
123 "encapsualtion";
124
125 /**
126 * Error message for unavailable labels.
127 */
128 private static final String NO_LABELS = "No available label for %s";
129
130 /**
131 * Error message for wrong encapsulation.
132 */
133 private static final String UNKNOWN_ENCAPSULATION = "Unknown encapsulation type";
134
135 /**
136 * Error message for unsupported L0 instructions.
137 */
138 private static final String UNSUPPORTED_L0 = "L0 not supported";
139
140 /**
141 * Error message for unsupported L1 instructions.
142 */
143 private static final String UNSUPPORTED_L1 = "L1 not supported";
144
145 /**
146 * Error message for unsupported eth subtype.
147 */
148 private static final String UNSUPPORTED_ETH_SUBTYPE = "Bad eth subtype";
149
150 /**
151 * Error message for unsupported pop action.
152 */
153 private static final String UNSUPPORTED_POP_ACTION = "Can't handle pop label";
154
155 /**
156 * Error message for unsupported L2 instructions.
157 */
158 private static final String UNSUPPORTED_L2 = "Unknown L2 Modification instruction";
159
160 /**
161 * Error message for unsupported IP subtype.
162 */
163 private static final String UNSUPPORTED_IP_SUBTYPE = "Bad ip subtype";
164
165 /**
166 * Error message for unsupported ARP.
167 */
168 private static final String UNSUPPORTED_ARP = "IPv6 not supported for ARP";
169
170 /**
171 * Error message for unsupported L3 instructions.
172 */
173 private static final String UNSUPPORTED_L3 = "Unknown L3 Modification instruction";
174
175 /**
176 * Error message for unsupported L4 subtype.
177 */
178 private static final String UNSUPPORTED_L4_SUBTYPE = "Unknown L4 subtype";
179
180 /**
181 * Error message for unsupported L4 instructions.
182 */
183 private static final String UNSUPPORTED_L4 = "Unknown L4 Modification instruction";
184
185 /**
186 * Error message for unsupported instructions.
187 */
188 private static final String UNSUPPORTED_INSTRUCTION = "Unknown instruction type";
189
190 /**
191 * Creates the flows representations. This default implementation does
192 * nothing. Subclasses should override this method to create their
193 * specific flows representations (flow rule, flow objective).
194 *
195 * @param intent the intent to compile
196 * @param deviceId the affected device
197 * @param inPorts the input ports
198 * @param outPorts the output ports
199 * @param labels the labels for the label switching hop by hop
200 * @return the list of flows representations
201 */
202 protected List<T> createRules(LinkCollectionIntent intent,
203 DeviceId deviceId,
204 Set<PortNumber> inPorts,
205 Set<PortNumber> outPorts,
206 Map<ConnectPoint, Identifier<?>> labels) {
207 return null;
208 }
209
210 /**
211 * Helper method to handle the different scenario (not encap, single hop, encap).
212 *
213 * @param encapConstraint the encapsulation constraint if it is present
214 * @param intent the link collection intent
215 * @param inPort the in port
216 * @param outPorts the out ports
217 * @param deviceId the current device
218 * @param labels the labels used by the encapsulation
219 * @return the forwarding instruction
220 */
221 protected ForwardingInstructions createForwardingInstruction(Optional<EncapsulationConstraint> encapConstraint,
222 LinkCollectionIntent intent,
223 PortNumber inPort,
224 Set<PortNumber> outPorts,
225 DeviceId deviceId,
226 Map<ConnectPoint, Identifier<?>> labels) {
227 ForwardingInstructions instructions = null;
228 /*
229 * If not encapsulation or single hop.
230 */
231 if (!encapConstraint.isPresent() || intent.links().isEmpty()) {
232 instructions = this.createForwardingInstructions(
233 intent,
234 inPort,
235 deviceId,
236 outPorts
237 );
238 /*
239 * If encapsulation is present. We retrieve the labels
240 * for this iteration;
241 */
242 } else {
243 Identifier<?> inLabel = labels.get(new ConnectPoint(deviceId, inPort));
244 Map<ConnectPoint, Identifier<?>> outLabels = Maps.newHashMap();
245 outPorts.forEach(outPort -> {
246 ConnectPoint key = new ConnectPoint(deviceId, outPort);
247 outLabels.put(key, labels.get(key));
248 });
249 instructions = this.createForwardingInstructions(
250 intent,
251 inPort,
252 inLabel,
253 deviceId,
254 outPorts,
255 outLabels,
256 encapConstraint.get().encapType()
257 );
258 }
259 return instructions;
260 }
261
262 /**
Pier Ventre5c4a0762016-11-21 10:28:13 -0800263 * Helper method which handles the proper generation of the ouput actions.
264 *
265 * @param outPorts the output ports
266 * @param deviceId the current device
267 * @param intent the intent to compile
268 * @param outLabels the output labels
269 * @param type the encapsulation type
270 * @param preCondition the previous state
271 * @param treatmentBuilder the builder to update with the ouput actions
272 */
273 private void manageOutputPorts(Set<PortNumber> outPorts,
274 DeviceId deviceId,
275 LinkCollectionIntent intent,
276 Map<ConnectPoint, Identifier<?>> outLabels,
277 EncapsulationType type,
278 TrafficSelector.Builder preCondition,
279 TrafficTreatment.Builder treatmentBuilder) {
280 /*
281 * We need to order the actions. First the actions
282 * related to the not-egress points. At the same time we collect
283 * also the egress points.
284 */
285 List<FilteredConnectPoint> egressPoints = Lists.newArrayList();
286 for (PortNumber outPort : outPorts) {
287 Optional<FilteredConnectPoint> filteredEgressPoint =
288 getFilteredConnectPointFromIntent(deviceId, outPort, intent);
289 if (!filteredEgressPoint.isPresent()) {
290 /*
291 * We build a temporary selector for the encapsulation.
292 */
293 TrafficSelector.Builder encapBuilder = DefaultTrafficSelector.builder();
294 /*
295 * We retrieve the associated label to the output port.
296 */
297 ConnectPoint cp = new ConnectPoint(deviceId, outPort);
298 Identifier<?> outLabel = outLabels.get(cp);
299 /*
300 * If there are not labels, we cannot handle.
301 */
302 if (outLabel == null) {
303 throw new IntentCompilationException(String.format(NO_LABELS, cp));
304 }
305 /*
306 * In the core we match using encapsulation.
307 */
308 updateSelectorFromEncapsulation(
309 encapBuilder,
310 type,
311 outLabel
312 );
313 /*
314 * We generate the transition.
315 */
316 TrafficTreatment forwardingTreatment =
317 forwardingTreatment(preCondition.build(),
318 encapBuilder.build(),
319 getEthType(intent.selector()));
320 /*
321 * We add the instruction necessary to the transition.
322 */
323 forwardingTreatment.allInstructions().stream()
324 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
325 .forEach(treatmentBuilder::add);
326 /*
327 * Finally we set the output action.
328 */
329 treatmentBuilder.setOutput(outPort);
330 /*
331 * The encapsulation modifies the packet. If we are optimizing
332 * we have to update the state.
333 */
334 if (optimize) {
335 preCondition = encapBuilder;
336 }
337 } else {
338 egressPoints.add(filteredEgressPoint.get());
339 }
340 }
341 /*
342 * The idea is to order the egress points. Before we deal
343 * with the egress points which looks like similar to the
344 * selector derived from the previous state then the
345 * the others.
346 */
347 TrafficSelector prevState = preCondition.build();
348 if (optimize) {
349 egressPoints = orderedEgressPoints(prevState, egressPoints);
350 }
351 /*
352 * In this case, we have to transit to the final
353 * state.
354 */
355 generateEgressActions(treatmentBuilder, egressPoints, prevState, intent);
356
357 }
358
359 /**
Pier Ventre81c47bf2016-11-04 07:26:22 -0700360 * Helper method to generate the egress actions.
361 *
362 * @param treatmentBuilder the treatment builder to update
363 * @param egressPoints the egress points
364 * @param initialState the initial state of the transition
365 */
366 private void generateEgressActions(TrafficTreatment.Builder treatmentBuilder,
367 List<FilteredConnectPoint> egressPoints,
368 TrafficSelector initialState,
369 LinkCollectionIntent intent) {
370
371 TrafficSelector prevState = initialState;
372 for (FilteredConnectPoint egressPoint : egressPoints) {
373 /*
374 * If we are at the egress, we have to transit to the final
375 * state. First we add the Intent treatment.
376 */
377 intent.treatment().allInstructions().stream()
378 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
379 .forEach(treatmentBuilder::add);
380 /*
381 * We generate the transition FIP->FEP.
382 */
383 TrafficTreatment forwardingTreatment =
384 forwardingTreatment(prevState,
385 egressPoint.trafficSelector(),
386 getEthType(intent.selector()));
387 /*
388 * We add the instruction necessary to the transition.
389 * Potentially we override the intent treatment.
390 */
391 forwardingTreatment.allInstructions().stream()
392 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
393 .forEach(treatmentBuilder::add);
394 /*
395 * Finally we set the output action.
396 */
397 treatmentBuilder.setOutput(egressPoint.connectPoint().port());
398 if (optimize) {
399 /*
400 * We update the previous state. In this way instead of
401 * transiting from FIP->FEP we do FEP->FEP and so on.
402 */
403 prevState = egressPoint.trafficSelector();
404 }
405 }
406
407 }
408
409 /**
410 * Helper method to order the egress ports according to a
411 * specified criteria. The idea is to generate first the actions
412 * for the egress ports which are similar to the specified criteria
413 * then the others. In this way we can mitigate the problems related
414 * to the chain of actions and we can optimize also the number of
415 * actions.
416 *
417 * @param orderCriteria the ordering criteria
418 * @param pointsToOrder the egress points to order
419 * @return a list of port ordered
420 */
421 private List<FilteredConnectPoint> orderedEgressPoints(TrafficSelector orderCriteria,
422 List<FilteredConnectPoint> pointsToOrder) {
423 /*
424 * We are interested only to the labels. The idea is to order
425 * by the tags.
426 *
427 */
428 Criterion vlanIdCriterion = orderCriteria.getCriterion(VLAN_VID);
429 Criterion mplsLabelCriterion = orderCriteria.getCriterion(MPLS_LABEL);
430 /*
431 * We collect all the untagged points.
432 *
433 */
434 List<FilteredConnectPoint> untaggedEgressPoints = pointsToOrder
435 .stream()
436 .filter(pointToOrder -> {
437 TrafficSelector selector = pointToOrder.trafficSelector();
438 return selector.getCriterion(VLAN_VID) == null &&
439 selector.getCriterion(MPLS_LABEL) == null;
440 }).collect(Collectors.toList());
441 /*
442 * We collect all the vlan points.
443 */
444 List<FilteredConnectPoint> vlanEgressPoints = pointsToOrder
445 .stream()
446 .filter(pointToOrder -> {
447 TrafficSelector selector = pointToOrder.trafficSelector();
448 return selector.getCriterion(VLAN_VID) != null &&
449 selector.getCriterion(MPLS_LABEL) == null;
450 }).collect(Collectors.toList());
451 /*
452 * We collect all the mpls points.
453 */
454 List<FilteredConnectPoint> mplsEgressPoints = pointsToOrder
455 .stream()
456 .filter(pointToOrder -> {
457 TrafficSelector selector = pointToOrder.trafficSelector();
458 return selector.getCriterion(VLAN_VID) == null &&
459 selector.getCriterion(MPLS_LABEL) != null;
460 }).collect(Collectors.toList());
461 /*
462 * We create the final list of ports.
463 */
464 List<FilteredConnectPoint> orderedList = Lists.newArrayList();
465 /*
466 * The ordering criteria is vlan id. First we add the vlan
467 * ports. Then the others.
468 */
469 if (vlanIdCriterion != null && mplsLabelCriterion == null) {
470 orderedList.addAll(vlanEgressPoints);
471 orderedList.addAll(untaggedEgressPoints);
472 orderedList.addAll(mplsEgressPoints);
473 return orderedList;
474 }
475 /*
476 * The ordering criteria is mpls label. First we add the mpls
477 * ports. Then the others.
478 */
479 if (vlanIdCriterion == null && mplsLabelCriterion != null) {
480 orderedList.addAll(mplsEgressPoints);
481 orderedList.addAll(untaggedEgressPoints);
482 orderedList.addAll(vlanEgressPoints);
483 return orderedList;
484 }
485 /*
486 * The ordering criteria is untagged. First we add the untagged
487 * ports. Then the others.
488 */
489 if (vlanIdCriterion == null && mplsLabelCriterion == null) {
490 orderedList.addAll(untaggedEgressPoints);
491 orderedList.addAll(vlanEgressPoints);
492 orderedList.addAll(mplsEgressPoints);
493 return orderedList;
494 }
495 /*
496 * Unhandled scenario.
497 */
498 orderedList.addAll(vlanEgressPoints);
499 orderedList.addAll(mplsEgressPoints);
500 orderedList.addAll(untaggedEgressPoints);
501 return orderedList;
502 }
503
504 /**
Pier Ventre766995d2016-10-05 22:15:56 -0700505 * Manages the Intents with a single ingress point (p2p, sp2mp)
506 * creating properly the selector builder and the treatment builder.
507 *
508 * @param selectorBuilder the selector builder to update
509 * @param treatmentBuilder the treatment builder to update
510 * @param intent the intent to compile
511 * @param deviceId the current device
512 * @param outPorts the output ports of this device
513 */
514 private void manageSpIntent(TrafficSelector.Builder selectorBuilder,
515 TrafficTreatment.Builder treatmentBuilder,
516 LinkCollectionIntent intent,
517 DeviceId deviceId,
518 Set<PortNumber> outPorts) {
519 /*
520 * Sanity check.
521 */
522 if (intent.filteredIngressPoints().size() != 1) {
523 throw new IntentCompilationException(WRONG_INGRESS);
524 }
525 /*
526 * For the p2p and sp2mp the transition initial state
527 * to final state is performed at the egress.
528 */
529 Optional<FilteredConnectPoint> filteredIngressPoint =
530 intent.filteredIngressPoints().stream().findFirst();
531 /*
532 * We build the final selector, adding the selector
533 * of the FIP to the Intent selector and potentially
534 * overriding its matches.
535 */
536 filteredIngressPoint.get()
537 .trafficSelector()
538 .criteria()
539 .forEach(selectorBuilder::add);
540 /*
541 * In this scenario, potentially we can have several output
Pier Ventre81c47bf2016-11-04 07:26:22 -0700542 * ports. First we have to insert in the treatment the actions
543 * for the core.
Pier Ventre766995d2016-10-05 22:15:56 -0700544 */
Pier Ventre81c47bf2016-11-04 07:26:22 -0700545 List<FilteredConnectPoint> egressPoints = Lists.newArrayList();
Pier Ventre766995d2016-10-05 22:15:56 -0700546 for (PortNumber outPort : outPorts) {
547 Optional<FilteredConnectPoint> filteredEgressPoint =
548 getFilteredConnectPointFromIntent(deviceId, outPort, intent);
Pier Ventre81c47bf2016-11-04 07:26:22 -0700549 if (!filteredEgressPoint.isPresent()) {
550 treatmentBuilder.setOutput(outPort);
551 } else {
552 egressPoints.add(filteredEgressPoint.get());
Pier Ventre766995d2016-10-05 22:15:56 -0700553 }
Pier Ventre766995d2016-10-05 22:15:56 -0700554 }
Pier Ventre81c47bf2016-11-04 07:26:22 -0700555 /*
556 * The idea is to order the egress points. Before we deal
557 * with the egress points which looks like similar to the ingress
558 * point then the others.
559 */
560 TrafficSelector prevState = filteredIngressPoint.get().trafficSelector();
561 if (optimize) {
562 egressPoints = orderedEgressPoints(prevState, egressPoints);
563 }
564 /*
565 * Then we deal with the egress points.
566 */
567 generateEgressActions(treatmentBuilder, egressPoints, prevState, intent);
Pier Ventre766995d2016-10-05 22:15:56 -0700568 }
569
570 /**
571 * Manages the Intents with multiple ingress points creating properly
572 * the selector builder and the treatment builder.
573 *
574 * @param selectorBuilder the selector builder to update
575 * @param treatmentBuilder the treatment builder to update
576 * @param intent the intent to compile
577 * @param inPort the input port of the current device
578 * @param deviceId the current device
579 * @param outPorts the output ports of this device
580 */
581 private void manageMpIntent(TrafficSelector.Builder selectorBuilder,
582 TrafficTreatment.Builder treatmentBuilder,
583 LinkCollectionIntent intent,
584 PortNumber inPort,
585 DeviceId deviceId,
586 Set<PortNumber> outPorts) {
587 /*
588 * Sanity check
589 */
590 if (intent.filteredEgressPoints().size() != 1) {
591 throw new IntentCompilationException(WRONG_EGRESS);
592 }
593 /*
594 * We try to understand if the device is one of the ingress points.
595 */
596 Optional<FilteredConnectPoint> filteredIngressPoint =
597 getFilteredConnectPointFromIntent(deviceId, inPort, intent);
598 /*
599 * We retrieve from the Intent the unique egress points.
600 */
601 Optional<FilteredConnectPoint> filteredEgressPoint =
602 intent.filteredEgressPoints().stream().findFirst();
603 /*
604 * We check if the device is the ingress device
605 */
606 if (filteredIngressPoint.isPresent()) {
607 /*
608 * We are at ingress, so basically what we have to do is this:
609 * apply a set of operations (treatment, FEP) in order to have
610 * a transition from the initial state to the final state.
611 *
612 * We initialize the treatment with the Intent treatment
613 */
614 intent.treatment().allInstructions().stream()
615 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
616 .forEach(treatmentBuilder::add);
617 /*
618 * We build the final selector, adding the selector
619 * of the FIP to the Intent selector and potentially
620 * overriding its matches.
621 */
622 filteredIngressPoint.get()
623 .trafficSelector()
624 .criteria()
625 .forEach(selectorBuilder::add);
626 /*
627 * We define the transition FIP->FEP, basically
628 * the set of the operations we need for reaching
629 * the final state.
630 */
631 TrafficTreatment forwardingTreatment =
632 forwardingTreatment(filteredIngressPoint.get().trafficSelector(),
633 filteredEgressPoint.get().trafficSelector(),
634 getEthType(intent.selector()));
635 /*
636 * We add to the treatment the actions necessary for the
637 * transition, potentially overriding the treatment of the
638 * Intent. The Intent treatment has always a low priority
639 * in respect of the FEP.
640 */
641 forwardingTreatment.allInstructions().stream()
642 .filter(inst -> inst.type() != Instruction.Type.NOACTION)
643 .forEach(treatmentBuilder::add);
644 } else {
645 /*
646 * We are in the core or in the egress switch.
647 * The packets are in their final state. We need
648 * to match against this final state.
649 *
650 * we derive the final state defined by the intent
651 * treatment.
652 */
653 updateBuilder(selectorBuilder, intent.treatment());
654 /*
655 * We derive the final state defined by the unique
656 * FEP. We merge the two states.
657 */
658 filteredEgressPoint.get()
659 .trafficSelector()
660 .criteria()
661 .forEach(selectorBuilder::add);
662 }
663 /*
664 * Finally we set the output action.
665 */
666 outPorts.forEach(treatmentBuilder::setOutput);
667 }
668
669 /**
670 * Computes treatment and selector which will be used
671 * in the flow representation (Rule, Objective).
672 *
673 * @param intent the intent to compile
674 * @param inPort the input port of this device
675 * @param deviceId the current device
676 * @param outPorts the output ports of this device
677 * @return the forwarding instruction object which encapsulates treatment and selector
678 */
679 protected ForwardingInstructions createForwardingInstructions(LinkCollectionIntent intent,
680 PortNumber inPort,
681 DeviceId deviceId,
682 Set<PortNumber> outPorts) {
683
684 /*
685 * We build an empty treatment and we initialize the selector with
686 * the intent selector.
687 */
688 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
689 .builder();
690 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector
691 .builder(intent.selector())
692 .matchInPort(inPort);
693
694 if (!intent.applyTreatmentOnEgress()) {
695 manageMpIntent(selectorBuilder,
696 treatmentBuilder,
697 intent,
698 inPort,
699 deviceId,
700 outPorts
701 );
702 } else {
703 manageSpIntent(selectorBuilder,
704 treatmentBuilder,
705 intent,
706 deviceId,
707 outPorts
708 );
709 }
710 /*
711 * We return selector and treatment necessary to build the flow rule
712 * or the flow objective.
713 */
714 return new ForwardingInstructions(treatmentBuilder.build(), selectorBuilder.build());
715 }
716
717 /**
718 * Manages the ingress of the Intents (p2p, sp2mp, mp2sp) with encapsulation.
719 *
720 * @param selectorBuilder the selector builder to update
721 * @param treatmentBuilder the treatment builder to update
722 * @param intent the intent to compile
723 * @param inPort the input port of this device
724 * @param deviceId the current device
725 * @param outPorts the output ports of this device
726 * @param outLabels the labels associated to the output port
727 * @param type the encapsulation type
728 */
729 private void manageEncapAtIngress(TrafficSelector.Builder selectorBuilder,
730 TrafficTreatment.Builder treatmentBuilder,
731 LinkCollectionIntent intent,
732 PortNumber inPort,
733 DeviceId deviceId,
734 Set<PortNumber> outPorts,
735 Map<ConnectPoint, Identifier<?>> outLabels,
736 EncapsulationType type) {
737
738 Optional<FilteredConnectPoint> filteredIngressPoint =
739 getFilteredConnectPointFromIntent(deviceId, inPort, intent);
740 /*
741 * We fill the selector builder with the intent selector.
742 */
743 intent.selector().criteria().forEach(selectorBuilder::add);
744 /*
745 * We build the final selector, adding the selector
746 * of the FIP to the Intent selector and potentially
747 * overriding its matches.
748 */
749 filteredIngressPoint.get()
750 .trafficSelector()
751 .criteria()
752 .forEach(selectorBuilder::add);
753 /*
Pier Ventre5c4a0762016-11-21 10:28:13 -0800754 * In this case the precondition is the selector of the filtered
755 * ingress point.
Pier Ventre766995d2016-10-05 22:15:56 -0700756 */
Pier Ventre5c4a0762016-11-21 10:28:13 -0800757 TrafficSelector.Builder preCondition = DefaultTrafficSelector
758 .builder(filteredIngressPoint.get().trafficSelector());
759 /*
760 * Generate the output actions.
761 */
762 manageOutputPorts(
763 outPorts,
764 deviceId,
765 intent,
766 outLabels,
767 type,
768 preCondition,
769 treatmentBuilder
770 );
Pier Ventre766995d2016-10-05 22:15:56 -0700771
772 }
773
774 /**
775 * Manages the core and transit of the Intents (p2p, sp2mp, mp2sp)
776 * with encapsulation.
777 *
778 * @param selectorBuilder the selector builder to update
779 * @param treatmentBuilder the treatment builder to update
780 * @param intent the intent to compile
781 * @param inPort the input port of this device
782 * @param inLabel the label associated to the input port
783 * @param deviceId the current device
784 * @param outPorts the output ports of this device
785 * @param outLabels the labels associated to the output port
786 * @param type the encapsulation type
787 */
788 private void manageEncapAtCoreAndEgress(TrafficSelector.Builder selectorBuilder,
789 TrafficTreatment.Builder treatmentBuilder,
790 LinkCollectionIntent intent,
791 PortNumber inPort,
792 Identifier<?> inLabel,
793 DeviceId deviceId,
794 Set<PortNumber> outPorts,
795 Map<ConnectPoint, Identifier<?>> outLabels,
796 EncapsulationType type) {
797
798 /*
799 * If there are not labels, we cannot handle.
800 */
801 ConnectPoint inCp = new ConnectPoint(deviceId, inPort);
802 if (inLabel == null) {
803 throw new IntentCompilationException(String.format(NO_LABELS, inCp));
804 }
805 /*
806 * In the core and at egress we match using encapsulation.
807 */
808 updateSelectorFromEncapsulation(
809 selectorBuilder,
810 type,
811 inLabel
812 );
813 /*
Pier Ventre5c4a0762016-11-21 10:28:13 -0800814 * Generate the output actions.
Pier Ventre766995d2016-10-05 22:15:56 -0700815 */
Pier Ventre5c4a0762016-11-21 10:28:13 -0800816 manageOutputPorts(
817 outPorts,
818 deviceId,
819 intent,
820 outLabels,
821 type,
822 selectorBuilder,
823 treatmentBuilder
824 );
825
Pier Ventre766995d2016-10-05 22:15:56 -0700826 }
827
828 /**
829 * Computes treatment and selector which will be used
830 * in the flow representation (Rule, Objective).
831 *
832 * @param intent the intent to compile
833 * @param inPort the input port of this device
834 * @param inLabel the label associated to the input port
835 * @param deviceId the current device
836 * @param outPorts the output ports of this device
837 * @param outLabels the labels associated to the output port
838 * @param type the encapsulation type
839 * @return the forwarding instruction object which encapsulates treatment and selector
840 */
841 protected ForwardingInstructions createForwardingInstructions(LinkCollectionIntent intent,
842 PortNumber inPort,
843 Identifier<?> inLabel,
844 DeviceId deviceId,
845 Set<PortNumber> outPorts,
846 Map<ConnectPoint, Identifier<?>> outLabels,
847 EncapsulationType type) {
848 /*
849 * We build an empty treatment and an empty selector.
850 */
851 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
852 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
853 selectorBuilder.matchInPort(inPort);
854 Optional<FilteredConnectPoint> filteredIngressPoint =
855 getFilteredConnectPointFromIntent(deviceId, inPort, intent);
856
857 if (filteredIngressPoint.isPresent()) {
858 manageEncapAtIngress(selectorBuilder,
859 treatmentBuilder,
860 intent,
861 inPort,
862 deviceId,
863 outPorts,
864 outLabels,
865 type
866 );
867 } else {
868 manageEncapAtCoreAndEgress(selectorBuilder,
869 treatmentBuilder,
870 intent,
871 inPort,
872 inLabel,
873 deviceId,
874 outPorts,
875 outLabels,
876 type);
877 }
878 /*
879 * We return selector and treatment necessary to build the flow rule
880 * or the flow objective.
881 */
882 return new ForwardingInstructions(treatmentBuilder.build(), selectorBuilder.build());
883 }
884
885 /**
886 * Helper class to encapsulate treatment and selector
887 * in an unique abstraction.
Pier Ventred48320e2016-08-17 16:25:47 -0700888 */
889 protected class ForwardingInstructions {
890
891 private TrafficTreatment trafficTreatment;
892
893 private TrafficSelector trafficSelector;
894
895 public ForwardingInstructions(TrafficTreatment treatment, TrafficSelector selector) {
896
897 this.trafficTreatment = treatment;
898 this.trafficSelector = selector;
899
900 }
901
902 public TrafficTreatment treatment() {
903 return this.trafficTreatment;
904 }
905
906 public TrafficSelector selector() {
907 return this.trafficSelector;
908 }
909
910 }
911
912 /**
Pier Ventre766995d2016-10-05 22:15:56 -0700913 * Helper method to compute input and output ports
914 * for each device crossed in the path.
Pier Ventred48320e2016-08-17 16:25:47 -0700915 *
916 * @param intent the related intents
917 * @param inputPorts the input ports to compute
918 * @param outputPorts the output ports to compute
919 */
920 protected void computePorts(LinkCollectionIntent intent,
921 SetMultimap<DeviceId, PortNumber> inputPorts,
922 SetMultimap<DeviceId, PortNumber> outputPorts) {
923
924 for (Link link : intent.links()) {
925 inputPorts.put(link.dst().deviceId(), link.dst().port());
926 outputPorts.put(link.src().deviceId(), link.src().port());
927 }
928
929 for (ConnectPoint ingressPoint : intent.ingressPoints()) {
930 inputPorts.put(ingressPoint.deviceId(), ingressPoint.port());
931 }
932
933 for (ConnectPoint egressPoint : intent.egressPoints()) {
934 outputPorts.put(egressPoint.deviceId(), egressPoint.port());
935 }
Pier Ventred48320e2016-08-17 16:25:47 -0700936
937 }
938
939 /**
Pier Ventre766995d2016-10-05 22:15:56 -0700940 * Retrieves the encapsulation constraint from the link collection intent.
Pier Ventred48320e2016-08-17 16:25:47 -0700941 *
Pier Ventre766995d2016-10-05 22:15:56 -0700942 * @param intent the intent to analyze
943 * @return the encapsulation constraint
Pier Ventred48320e2016-08-17 16:25:47 -0700944 */
Pier Ventre766995d2016-10-05 22:15:56 -0700945 protected Optional<EncapsulationConstraint> getIntentEncapConstraint(LinkCollectionIntent intent) {
946 return intent.constraints().stream()
947 .filter(constraint -> constraint instanceof EncapsulationConstraint)
948 .map(x -> (EncapsulationConstraint) x).findAny();
Pier Ventred48320e2016-08-17 16:25:47 -0700949 }
950
951
952 /**
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700953 * Get FilteredConnectPoint from LinkCollectionIntent.
Pier Ventre766995d2016-10-05 22:15:56 -0700954 *
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700955 * @param deviceId device Id for connect point
956 * @param portNumber port number
957 * @param intent source intent
958 * @return filtered connetion point
959 */
960 private Optional<FilteredConnectPoint> getFilteredConnectPointFromIntent(DeviceId deviceId,
961 PortNumber portNumber,
962 LinkCollectionIntent intent) {
963 Set<FilteredConnectPoint> filteredConnectPoints =
964 Sets.union(intent.filteredIngressPoints(), intent.filteredEgressPoints());
965 return filteredConnectPoints.stream()
966 .filter(port -> port.connectPoint().deviceId().equals(deviceId))
967 .filter(port -> port.connectPoint().port().equals(portNumber))
968 .findFirst();
969 }
970
971 /**
972 * Get tag criterion from selector.
973 * The criterion should be one of type in tagCriterionTypes.
974 *
975 * @param selector selector
976 * @return Criterion that matched, if there is no tag criterion, return null
977 */
978 private Criterion getTagCriterion(TrafficSelector selector) {
979 return selector.criteria().stream()
980 .filter(criterion -> TAG_CRITERION_TYPES.contains(criterion.type()))
981 .findFirst()
982 .orElse(Criteria.dummy());
983
984 }
985
986 /**
987 * Compares tag type between ingress and egress point and generate
988 * treatment for egress point of intent.
989 *
Pier Ventre766995d2016-10-05 22:15:56 -0700990 * @param ingress ingress selector for the intent
991 * @param egress egress selector for the intent
992 * @param ethType the ethertype to use in mpls_pop
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700993 * @return Builder of TrafficTreatment
994 */
Pier Ventre766995d2016-10-05 22:15:56 -0700995 private TrafficTreatment forwardingTreatment(TrafficSelector ingress,
996 TrafficSelector egress,
997 EthType ethType) {
Yi Tseng2a81c9d2016-09-14 10:14:24 -0700998
999
Pier Ventre766995d2016-10-05 22:15:56 -07001000 if (ingress.equals(egress)) {
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001001 return DefaultTrafficTreatment.emptyTreatment();
1002 }
1003
1004 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
1005
1006 /*
1007 * "null" means there is no tag for the port
1008 * Tag criterion will be null if port is normal connection point
1009 */
Pier Ventre766995d2016-10-05 22:15:56 -07001010 Criterion ingressTagCriterion = getTagCriterion(ingress);
1011 Criterion egressTagCriterion = getTagCriterion(egress);
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001012
1013 if (ingressTagCriterion.type() != egressTagCriterion.type()) {
1014
1015 /*
1016 * Tag type of ingress port and egress port are different.
1017 * Need to remove tag from ingress, then add new tag for egress.
1018 * Remove nothing if ingress port use VXLAN or there is no tag
1019 * on ingress port.
1020 */
1021 switch (ingressTagCriterion.type()) {
1022 case VLAN_VID:
1023 builder.popVlan();
1024 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001025
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001026 case MPLS_LABEL:
Pier Ventre81c47bf2016-11-04 07:26:22 -07001027 if (copyTtl) {
1028 builder.copyTtlIn();
1029 }
Pier Ventre766995d2016-10-05 22:15:56 -07001030 builder.popMpls(ethType);
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001031 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001032
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001033 default:
1034 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001035
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001036 }
1037
1038 /*
1039 * Push new tag for egress port.
1040 */
1041 switch (egressTagCriterion.type()) {
1042 case VLAN_VID:
1043 builder.pushVlan();
1044 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001045
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001046 case MPLS_LABEL:
1047 builder.pushMpls();
Pier Ventre81c47bf2016-11-04 07:26:22 -07001048 if (copyTtl) {
1049 builder.copyTtlOut();
1050 }
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001051 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001052
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001053 default:
1054 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001055
Pier Ventred48320e2016-08-17 16:25:47 -07001056 }
1057 }
1058
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001059 switch (egressTagCriterion.type()) {
1060 case VLAN_VID:
1061 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) egressTagCriterion;
1062 builder.setVlanId(vlanIdCriterion.vlanId());
1063 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001064
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001065 case MPLS_LABEL:
1066 MplsCriterion mplsCriterion = (MplsCriterion) egressTagCriterion;
1067 builder.setMpls(mplsCriterion.label());
1068 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001069
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001070 case TUNNEL_ID:
1071 TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) egressTagCriterion;
1072 builder.setTunnelId(tunnelIdCriterion.tunnelId());
1073 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001074
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001075 default:
1076 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001077
Pier Ventre27d42572016-08-29 17:37:08 -07001078 }
Pier Ventre27d42572016-08-29 17:37:08 -07001079
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001080 return builder.build();
Pier Ventre647138f2016-08-26 17:32:44 -07001081 }
1082
1083 /**
Pier Ventred48320e2016-08-17 16:25:47 -07001084 * Update the selector builder using a L0 instruction.
1085 *
1086 * @param builder the builder to update
1087 * @param l0instruction the l0 instruction to use
1088 */
1089 private void updateBuilder(TrafficSelector.Builder builder, L0ModificationInstruction l0instruction) {
Pier Ventre766995d2016-10-05 22:15:56 -07001090 throw new IntentCompilationException(UNSUPPORTED_L0);
Pier Ventred48320e2016-08-17 16:25:47 -07001091 }
1092
1093 /**
1094 * Update the selector builder using a L1 instruction.
1095 *
1096 * @param builder the builder to update
1097 * @param l1instruction the l1 instruction to use
1098 */
1099 private void updateBuilder(TrafficSelector.Builder builder, L1ModificationInstruction l1instruction) {
Pier Ventre766995d2016-10-05 22:15:56 -07001100 throw new IntentCompilationException(UNSUPPORTED_L1);
Pier Ventred48320e2016-08-17 16:25:47 -07001101 }
1102
1103 /**
1104 * Update the selector builder using a L2 instruction.
1105 *
1106 * @param builder the builder to update
1107 * @param l2instruction the l2 instruction to use
1108 */
1109 private void updateBuilder(TrafficSelector.Builder builder, L2ModificationInstruction l2instruction) {
1110 switch (l2instruction.subtype()) {
1111 case ETH_SRC:
1112 case ETH_DST:
1113 ModEtherInstruction ethInstr = (ModEtherInstruction) l2instruction;
1114 switch (ethInstr.subtype()) {
1115 case ETH_SRC:
1116 builder.matchEthSrc(ethInstr.mac());
1117 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001118
Pier Ventred48320e2016-08-17 16:25:47 -07001119 case ETH_DST:
1120 builder.matchEthDst(ethInstr.mac());
1121 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001122
Pier Ventred48320e2016-08-17 16:25:47 -07001123 default:
Pier Ventre766995d2016-10-05 22:15:56 -07001124 throw new IntentCompilationException(UNSUPPORTED_ETH_SUBTYPE);
Pier Ventred48320e2016-08-17 16:25:47 -07001125 }
1126 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001127
Pier Ventred48320e2016-08-17 16:25:47 -07001128 case VLAN_ID:
1129 ModVlanIdInstruction vlanIdInstr = (ModVlanIdInstruction) l2instruction;
1130 builder.matchVlanId(vlanIdInstr.vlanId());
1131 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001132
Pier Ventred48320e2016-08-17 16:25:47 -07001133 case VLAN_PUSH:
1134 //FIXME
1135 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001136
Pier Ventred48320e2016-08-17 16:25:47 -07001137 case VLAN_POP:
1138 //TODO how do we handle dropped label? remove the selector?
Pier Ventre766995d2016-10-05 22:15:56 -07001139 throw new IntentCompilationException(UNSUPPORTED_POP_ACTION);
Pier Ventred48320e2016-08-17 16:25:47 -07001140 case VLAN_PCP:
1141 ModVlanPcpInstruction vlanPcpInstruction = (ModVlanPcpInstruction) l2instruction;
1142 builder.matchVlanPcp(vlanPcpInstruction.vlanPcp());
1143 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001144
Pier Ventred48320e2016-08-17 16:25:47 -07001145 case MPLS_LABEL:
1146 case MPLS_PUSH:
1147 //FIXME
1148 ModMplsLabelInstruction mplsInstr = (ModMplsLabelInstruction) l2instruction;
1149 builder.matchMplsLabel(mplsInstr.label());
1150 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001151
Pier Ventred48320e2016-08-17 16:25:47 -07001152 case MPLS_POP:
1153 //TODO how do we handle dropped label? remove the selector?
Pier Ventre766995d2016-10-05 22:15:56 -07001154 throw new IntentCompilationException(UNSUPPORTED_POP_ACTION);
Pier Ventred48320e2016-08-17 16:25:47 -07001155 case DEC_MPLS_TTL:
1156 // no-op
1157 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001158
Pier Ventred48320e2016-08-17 16:25:47 -07001159 case MPLS_BOS:
1160 ModMplsBosInstruction mplsBosInstr = (ModMplsBosInstruction) l2instruction;
1161 builder.matchMplsBos(mplsBosInstr.mplsBos());
1162 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001163
Pier Ventred48320e2016-08-17 16:25:47 -07001164 case TUNNEL_ID:
1165 ModTunnelIdInstruction tunInstr = (ModTunnelIdInstruction) l2instruction;
1166 builder.matchTunnelId(tunInstr.tunnelId());
1167 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001168
Pier Ventred48320e2016-08-17 16:25:47 -07001169 default:
Pier Ventre766995d2016-10-05 22:15:56 -07001170 throw new IntentCompilationException(UNSUPPORTED_L2);
Pier Ventred48320e2016-08-17 16:25:47 -07001171 }
1172
1173 }
1174
1175 /**
1176 * Update the selector builder using a L3 instruction.
1177 *
1178 * @param builder the builder to update
1179 * @param l3instruction the l3 instruction to use
1180 */
1181 private void updateBuilder(TrafficSelector.Builder builder, L3ModificationInstruction l3instruction) {
1182 // TODO check ethernet proto
1183 switch (l3instruction.subtype()) {
1184 case IPV4_SRC:
1185 case IPV4_DST:
1186 case IPV6_SRC:
1187 case IPV6_DST:
1188 ModIPInstruction ipInstr = (ModIPInstruction) l3instruction;
1189 // TODO check if ip falls in original prefix
1190 IpPrefix prefix = ipInstr.ip().toIpPrefix();
1191 switch (ipInstr.subtype()) {
1192 case IPV4_SRC:
1193 builder.matchIPSrc(prefix);
1194 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001195
Pier Ventred48320e2016-08-17 16:25:47 -07001196 case IPV4_DST:
1197 builder.matchIPSrc(prefix);
1198 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001199
Pier Ventred48320e2016-08-17 16:25:47 -07001200 case IPV6_SRC:
1201 builder.matchIPv6Src(prefix);
1202 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001203
Pier Ventred48320e2016-08-17 16:25:47 -07001204 case IPV6_DST:
1205 builder.matchIPv6Dst(prefix);
1206 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001207
Pier Ventred48320e2016-08-17 16:25:47 -07001208 default:
Pier Ventre766995d2016-10-05 22:15:56 -07001209 throw new IntentCompilationException(UNSUPPORTED_IP_SUBTYPE);
Pier Ventred48320e2016-08-17 16:25:47 -07001210 }
1211 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001212
Pier Ventred48320e2016-08-17 16:25:47 -07001213 case IPV6_FLABEL:
1214 ModIPv6FlowLabelInstruction ipFlowInstr = (ModIPv6FlowLabelInstruction) l3instruction;
1215 builder.matchIPv6FlowLabel(ipFlowInstr.flowLabel());
1216 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001217
Pier Ventred48320e2016-08-17 16:25:47 -07001218 case DEC_TTL:
1219 // no-op
1220 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001221
Pier Ventred48320e2016-08-17 16:25:47 -07001222 case TTL_OUT:
1223 // no-op
1224 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001225
Pier Ventred48320e2016-08-17 16:25:47 -07001226 case TTL_IN:
1227 // no-op
1228 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001229
Pier Ventred48320e2016-08-17 16:25:47 -07001230 case ARP_SPA:
1231 ModArpIPInstruction arpIpInstr = (ModArpIPInstruction) l3instruction;
1232 if (arpIpInstr.ip().isIp4()) {
1233 builder.matchArpSpa((Ip4Address) arpIpInstr.ip());
1234 } else {
Pier Ventre766995d2016-10-05 22:15:56 -07001235 throw new IntentCompilationException(UNSUPPORTED_ARP);
Pier Ventred48320e2016-08-17 16:25:47 -07001236 }
1237 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001238
Pier Ventred48320e2016-08-17 16:25:47 -07001239 case ARP_SHA:
1240 ModArpEthInstruction arpEthInstr = (ModArpEthInstruction) l3instruction;
1241 builder.matchArpSha(arpEthInstr.mac());
1242 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001243
Pier Ventred48320e2016-08-17 16:25:47 -07001244 case ARP_OP:
1245 ModArpOpInstruction arpOpInstr = (ModArpOpInstruction) l3instruction;
1246 //FIXME is the long to int cast safe?
1247 builder.matchArpOp((int) arpOpInstr.op());
1248 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001249
Pier Ventred48320e2016-08-17 16:25:47 -07001250 default:
Pier Ventre766995d2016-10-05 22:15:56 -07001251 throw new IntentCompilationException(UNSUPPORTED_L3);
Pier Ventred48320e2016-08-17 16:25:47 -07001252 }
1253 }
1254
1255 /**
1256 * Update the selector builder using a L4 instruction.
1257 *
1258 * @param builder the builder to update
1259 * @param l4instruction the l4 instruction to use
1260 */
1261 private void updateBuilder(TrafficSelector.Builder builder, L4ModificationInstruction l4instruction) {
1262 if (l4instruction instanceof ModTransportPortInstruction) {
1263 // TODO check IP proto
1264 ModTransportPortInstruction l4mod = (ModTransportPortInstruction) l4instruction;
1265 switch (l4mod.subtype()) {
1266 case TCP_SRC:
1267 builder.matchTcpSrc(l4mod.port());
1268 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001269
Pier Ventred48320e2016-08-17 16:25:47 -07001270 case TCP_DST:
1271 builder.matchTcpDst(l4mod.port());
1272 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001273
Pier Ventred48320e2016-08-17 16:25:47 -07001274 case UDP_SRC:
1275 builder.matchUdpSrc(l4mod.port());
1276 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001277
Pier Ventred48320e2016-08-17 16:25:47 -07001278 case UDP_DST:
1279 builder.matchUdpDst(l4mod.port());
1280 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001281
Pier Ventred48320e2016-08-17 16:25:47 -07001282 default:
Pier Ventre766995d2016-10-05 22:15:56 -07001283 throw new IntentCompilationException(UNSUPPORTED_L4_SUBTYPE);
Pier Ventred48320e2016-08-17 16:25:47 -07001284 }
1285 } else {
Pier Ventre766995d2016-10-05 22:15:56 -07001286 throw new IntentCompilationException(UNSUPPORTED_L4);
Pier Ventred48320e2016-08-17 16:25:47 -07001287 }
1288 }
1289
1290 /**
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001291 * Update selector builder by using treatment.
Pier Ventred48320e2016-08-17 16:25:47 -07001292 *
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001293 * @param builder builder to update
1294 * @param treatment traffic treatment
Pier Ventred48320e2016-08-17 16:25:47 -07001295 */
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001296 private void updateBuilder(TrafficSelector.Builder builder, TrafficTreatment treatment) {
1297
1298 treatment.allInstructions().forEach(instruction -> {
1299 switch (instruction.type()) {
1300 case L0MODIFICATION:
1301 updateBuilder(builder, (L0ModificationInstruction) instruction);
1302 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001303
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001304 case L1MODIFICATION:
1305 updateBuilder(builder, (L1ModificationInstruction) instruction);
1306 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001307
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001308 case L2MODIFICATION:
1309 updateBuilder(builder, (L2ModificationInstruction) instruction);
1310 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001311
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001312 case L3MODIFICATION:
1313 updateBuilder(builder, (L3ModificationInstruction) instruction);
1314 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001315
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001316 case L4MODIFICATION:
1317 updateBuilder(builder, (L4ModificationInstruction) instruction);
1318 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001319
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001320 case NOACTION:
1321 case OUTPUT:
1322 case GROUP:
1323 case QUEUE:
1324 case TABLE:
1325 case METER:
1326 case METADATA:
1327 case EXTENSION: // TODO is extension no-op or unsupported?
1328 // Nothing to do
1329 break;
Pier Ventre766995d2016-10-05 22:15:56 -07001330
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001331 default:
Pier Ventre766995d2016-10-05 22:15:56 -07001332 throw new IntentCompilationException(UNSUPPORTED_INSTRUCTION);
Yi Tseng2a81c9d2016-09-14 10:14:24 -07001333 }
1334 });
1335
Pier Ventred48320e2016-08-17 16:25:47 -07001336 }
1337
Pier Ventre766995d2016-10-05 22:15:56 -07001338 /**
1339 * The method generates a selector starting from
1340 * the encapsulation information (type and label to match).
1341 *
1342 * @param selectorBuilder the builder to update
1343 * @param type the type of encapsulation
1344 * @param identifier the label to match
1345 */
1346 private void updateSelectorFromEncapsulation(TrafficSelector.Builder selectorBuilder,
1347 EncapsulationType type,
1348 Identifier<?> identifier) {
1349 switch (type) {
1350 case MPLS:
1351 MplsLabel label = (MplsLabel) identifier;
1352 selectorBuilder.matchMplsLabel(label);
1353 selectorBuilder.matchEthType(Ethernet.MPLS_UNICAST);
1354 break;
1355
1356 case VLAN:
1357 VlanId id = (VlanId) identifier;
1358 selectorBuilder.matchVlanId(id);
1359 break;
1360
1361 default:
1362 throw new IntentCompilationException(UNKNOWN_ENCAPSULATION);
1363 }
1364 }
1365
1366 /**
1367 * Helper function to define the match on the ethertype.
1368 * If the selector define an ethertype we will use it,
1369 * otherwise IPv4 will be used by default.
1370 *
1371 * @param selector the traffic selector
1372 * @return the ethertype we should match
1373 */
1374 private EthType getEthType(TrafficSelector selector) {
1375 Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE);
1376 if (c != null && c instanceof EthTypeCriterion) {
1377 EthTypeCriterion ethertype = (EthTypeCriterion) c;
1378 return ethertype.ethType();
1379 }
1380 return EthType.EtherType.IPV4.ethType();
1381 }
1382
Pier Ventred48320e2016-08-17 16:25:47 -07001383}