blob: 9fbedb926579fc17f915c027a32fdba8a868f9f5 [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
19import com.google.common.collect.SetMultimap;
20import org.onlab.packet.Ip4Address;
21import org.onlab.packet.IpPrefix;
22import org.onosproject.net.ConnectPoint;
23import org.onosproject.net.DeviceId;
24import org.onosproject.net.Link;
25import org.onosproject.net.PortNumber;
26import org.onosproject.net.flow.DefaultTrafficSelector;
27import org.onosproject.net.flow.DefaultTrafficTreatment;
28import org.onosproject.net.flow.TrafficSelector;
29import org.onosproject.net.flow.TrafficTreatment;
30import org.onosproject.net.flow.instructions.L0ModificationInstruction;
31import org.onosproject.net.flow.instructions.L1ModificationInstruction;
32import org.onosproject.net.flow.instructions.L2ModificationInstruction;
33import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
34import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
35import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
36import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
37import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
38import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
39import org.onosproject.net.flow.instructions.L3ModificationInstruction;
40import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpEthInstruction;
41import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpIPInstruction;
42import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpOpInstruction;
43import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
44import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
45import org.onosproject.net.flow.instructions.L4ModificationInstruction;
46import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
47import org.onosproject.net.intent.IntentCompilationException;
48import org.onosproject.net.intent.LinkCollectionIntent;
49
50import java.util.List;
51import java.util.Set;
52import java.util.stream.Collectors;
53
54/**
55 * Shared APIs and implementations for Link Collection compilers.
56 */
57public class LinkCollectionCompiler<T> {
58
59 /**
60 * Helper class to encapsulate treatment and selector.
61 */
62 protected class ForwardingInstructions {
63
64 private TrafficTreatment trafficTreatment;
65
66 private TrafficSelector trafficSelector;
67
68 public ForwardingInstructions(TrafficTreatment treatment, TrafficSelector selector) {
69
70 this.trafficTreatment = treatment;
71 this.trafficSelector = selector;
72
73 }
74
75 public TrafficTreatment treatment() {
76 return this.trafficTreatment;
77 }
78
79 public TrafficSelector selector() {
80 return this.trafficSelector;
81 }
82
83 }
84
85 /**
86 * Helper method to compute input and ouput ports.
87 *
88 * @param intent the related intents
89 * @param inputPorts the input ports to compute
90 * @param outputPorts the output ports to compute
91 */
92 protected void computePorts(LinkCollectionIntent intent,
93 SetMultimap<DeviceId, PortNumber> inputPorts,
94 SetMultimap<DeviceId, PortNumber> outputPorts) {
95
96 for (Link link : intent.links()) {
97 inputPorts.put(link.dst().deviceId(), link.dst().port());
98 outputPorts.put(link.src().deviceId(), link.src().port());
99 }
100
101 for (ConnectPoint ingressPoint : intent.ingressPoints()) {
102 inputPorts.put(ingressPoint.deviceId(), ingressPoint.port());
103 }
104
105 for (ConnectPoint egressPoint : intent.egressPoints()) {
106 outputPorts.put(egressPoint.deviceId(), egressPoint.port());
107 }
108
109 }
110
111 /**
112 * Helper method to compute ingress and egress ports.
113 *
114 * @param intent the related intents
115 * @param ingressPorts the ingress ports to compute
116 * @param egressPorts the egress ports to compute
117 */
118 protected void computePorts(LinkCollectionIntent intent,
119 DeviceId deviceId,
120 Set<PortNumber> ingressPorts,
121 Set<PortNumber> egressPorts) {
122
123 if (!intent.applyTreatmentOnEgress()) {
124 ingressPorts.addAll(intent.ingressPoints().stream()
125 .filter(point -> point.deviceId().equals(deviceId))
126 .map(ConnectPoint::port)
127 .collect(Collectors.toSet()));
128 } else {
129 egressPorts.addAll(intent.egressPoints().stream()
130 .filter(point -> point.deviceId().equals(deviceId))
131 .map(ConnectPoint::port)
132 .collect(Collectors.toSet()));
133 }
134
135 }
136
137 /**
138 * Creates the flows representations.
139 *
140 * @param intent the intent to compile
141 * @param deviceId the affected device
142 * @param inPorts the input ports
143 * @param outPorts the output ports
144 * @return the list of flows representations
145 */
146 protected List<T> createRules(LinkCollectionIntent intent, DeviceId deviceId,
147 Set<PortNumber> inPorts, Set<PortNumber> outPorts) {
148 return null;
149 }
150
151
152 /**
153 * Computes treatment and selector which will be used
154 * in the flow representation (Rule, Objective).
155 *
156 * @param intent the intent to compile
157 * @param inPort the input port
158 * @param outPorts the output ports
159 * @param ingressPorts the ingress ports
160 * @param egressPorts the egress ports
161 * @return the forwarding instruction object which encapsulates treatment and selector
162 */
163 protected ForwardingInstructions createForwardingInstructions(LinkCollectionIntent intent, PortNumber inPort,
164 Set<PortNumber> outPorts,
165 Set<PortNumber> ingressPorts,
166 Set<PortNumber> egressPorts) {
167
168 TrafficTreatment.Builder defaultTreatmentBuilder = DefaultTrafficTreatment.builder();
169 outPorts.forEach(defaultTreatmentBuilder::setOutput);
170 TrafficTreatment outputOnlyTreatment = defaultTreatmentBuilder.build();
171 TrafficSelector.Builder selectorBuilder;
172 TrafficTreatment treatment;
173 TrafficTreatment intentTreatment;
174
175 if (!intent.applyTreatmentOnEgress()) {
176 TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment());
177 outPorts.forEach(ingressTreatmentBuilder::setOutput);
178 intentTreatment = ingressTreatmentBuilder.build();
179
180 if (ingressPorts.contains(inPort)) {
181 selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
182 treatment = intentTreatment;
183 } else {
184 selectorBuilder = this.createSelectorFromFwdInstructions(
185 new ForwardingInstructions(intentTreatment, intent.selector())
186 );
187 treatment = outputOnlyTreatment;
188 }
189 } else {
190 if (outPorts.stream().allMatch(egressPorts::contains)) {
191 TrafficTreatment.Builder egressTreatmentBuilder =
192 DefaultTrafficTreatment.builder(intent.treatment());
193 outPorts.forEach(egressTreatmentBuilder::setOutput);
194
195 selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
196 treatment = egressTreatmentBuilder.build();
197 } else {
198 selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
199 treatment = outputOnlyTreatment;
200 }
201 }
202
203 TrafficSelector selector = selectorBuilder.matchInPort(inPort).build();
204
205 return new ForwardingInstructions(treatment, selector);
206
207 }
208
209 /**
210 * Update the selector builder using a L0 instruction.
211 *
212 * @param builder the builder to update
213 * @param l0instruction the l0 instruction to use
214 */
215 private void updateBuilder(TrafficSelector.Builder builder, L0ModificationInstruction l0instruction) {
216 throw new IntentCompilationException("L0 not supported");
217 }
218
219 /**
220 * Update the selector builder using a L1 instruction.
221 *
222 * @param builder the builder to update
223 * @param l1instruction the l1 instruction to use
224 */
225 private void updateBuilder(TrafficSelector.Builder builder, L1ModificationInstruction l1instruction) {
226 throw new IntentCompilationException("L1 not supported");
227 }
228
229 /**
230 * Update the selector builder using a L2 instruction.
231 *
232 * @param builder the builder to update
233 * @param l2instruction the l2 instruction to use
234 */
235 private void updateBuilder(TrafficSelector.Builder builder, L2ModificationInstruction l2instruction) {
236 switch (l2instruction.subtype()) {
237 case ETH_SRC:
238 case ETH_DST:
239 ModEtherInstruction ethInstr = (ModEtherInstruction) l2instruction;
240 switch (ethInstr.subtype()) {
241 case ETH_SRC:
242 builder.matchEthSrc(ethInstr.mac());
243 break;
244 case ETH_DST:
245 builder.matchEthDst(ethInstr.mac());
246 break;
247 default:
248 throw new IntentCompilationException("Bad eth subtype");
249 }
250 break;
251 case VLAN_ID:
252 ModVlanIdInstruction vlanIdInstr = (ModVlanIdInstruction) l2instruction;
253 builder.matchVlanId(vlanIdInstr.vlanId());
254 break;
255 case VLAN_PUSH:
256 //FIXME
257 break;
258 case VLAN_POP:
259 //TODO how do we handle dropped label? remove the selector?
260 throw new IntentCompilationException("Can't handle pop label");
261 case VLAN_PCP:
262 ModVlanPcpInstruction vlanPcpInstruction = (ModVlanPcpInstruction) l2instruction;
263 builder.matchVlanPcp(vlanPcpInstruction.vlanPcp());
264 break;
265 case MPLS_LABEL:
266 case MPLS_PUSH:
267 //FIXME
268 ModMplsLabelInstruction mplsInstr = (ModMplsLabelInstruction) l2instruction;
269 builder.matchMplsLabel(mplsInstr.label());
270 break;
271 case MPLS_POP:
272 //TODO how do we handle dropped label? remove the selector?
273 throw new IntentCompilationException("Can't handle pop label");
274 case DEC_MPLS_TTL:
275 // no-op
276 break;
277 case MPLS_BOS:
278 ModMplsBosInstruction mplsBosInstr = (ModMplsBosInstruction) l2instruction;
279 builder.matchMplsBos(mplsBosInstr.mplsBos());
280 break;
281 case TUNNEL_ID:
282 ModTunnelIdInstruction tunInstr = (ModTunnelIdInstruction) l2instruction;
283 builder.matchTunnelId(tunInstr.tunnelId());
284 break;
285 default:
286 throw new IntentCompilationException("Unknown L2 Modification instruction");
287 }
288
289 }
290
291 /**
292 * Update the selector builder using a L3 instruction.
293 *
294 * @param builder the builder to update
295 * @param l3instruction the l3 instruction to use
296 */
297 private void updateBuilder(TrafficSelector.Builder builder, L3ModificationInstruction l3instruction) {
298 // TODO check ethernet proto
299 switch (l3instruction.subtype()) {
300 case IPV4_SRC:
301 case IPV4_DST:
302 case IPV6_SRC:
303 case IPV6_DST:
304 ModIPInstruction ipInstr = (ModIPInstruction) l3instruction;
305 // TODO check if ip falls in original prefix
306 IpPrefix prefix = ipInstr.ip().toIpPrefix();
307 switch (ipInstr.subtype()) {
308 case IPV4_SRC:
309 builder.matchIPSrc(prefix);
310 break;
311 case IPV4_DST:
312 builder.matchIPSrc(prefix);
313 break;
314 case IPV6_SRC:
315 builder.matchIPv6Src(prefix);
316 break;
317 case IPV6_DST:
318 builder.matchIPv6Dst(prefix);
319 break;
320 default:
321 throw new IntentCompilationException("Bad type for IP instruction");
322 }
323 break;
324 case IPV6_FLABEL:
325 ModIPv6FlowLabelInstruction ipFlowInstr = (ModIPv6FlowLabelInstruction) l3instruction;
326 builder.matchIPv6FlowLabel(ipFlowInstr.flowLabel());
327 break;
328 case DEC_TTL:
329 // no-op
330 break;
331 case TTL_OUT:
332 // no-op
333 break;
334 case TTL_IN:
335 // no-op
336 break;
337 case ARP_SPA:
338 ModArpIPInstruction arpIpInstr = (ModArpIPInstruction) l3instruction;
339 if (arpIpInstr.ip().isIp4()) {
340 builder.matchArpSpa((Ip4Address) arpIpInstr.ip());
341 } else {
342 throw new IntentCompilationException("IPv6 not supported for ARP");
343 }
344 break;
345 case ARP_SHA:
346 ModArpEthInstruction arpEthInstr = (ModArpEthInstruction) l3instruction;
347 builder.matchArpSha(arpEthInstr.mac());
348 break;
349 case ARP_OP:
350 ModArpOpInstruction arpOpInstr = (ModArpOpInstruction) l3instruction;
351 //FIXME is the long to int cast safe?
352 builder.matchArpOp((int) arpOpInstr.op());
353 break;
354 default:
355 throw new IntentCompilationException("Unknown L3 Modification instruction");
356 }
357 }
358
359 /**
360 * Update the selector builder using a L4 instruction.
361 *
362 * @param builder the builder to update
363 * @param l4instruction the l4 instruction to use
364 */
365 private void updateBuilder(TrafficSelector.Builder builder, L4ModificationInstruction l4instruction) {
366 if (l4instruction instanceof ModTransportPortInstruction) {
367 // TODO check IP proto
368 ModTransportPortInstruction l4mod = (ModTransportPortInstruction) l4instruction;
369 switch (l4mod.subtype()) {
370 case TCP_SRC:
371 builder.matchTcpSrc(l4mod.port());
372 break;
373 case TCP_DST:
374 builder.matchTcpDst(l4mod.port());
375 break;
376 case UDP_SRC:
377 builder.matchUdpSrc(l4mod.port());
378 break;
379 case UDP_DST:
380 builder.matchUdpDst(l4mod.port());
381 break;
382 default:
383 throw new IntentCompilationException("Unknown L4 Modification instruction");
384 }
385 } else {
386 throw new IntentCompilationException("Unknown L4 Modification instruction");
387 }
388 }
389
390 /**
391 * Computes the new traffic selector using the
392 * forwarding instructions.
393 *
394 * @param fwInstructions it encapsulates the instructions to compute the new selector
395 * @return the traffic selector builder
396 */
397 private TrafficSelector.Builder createSelectorFromFwdInstructions(ForwardingInstructions fwInstructions) {
398 TrafficSelector.Builder defaultSelectorBuilder = DefaultTrafficSelector.builder(fwInstructions.selector());
399 fwInstructions.treatment().allInstructions().forEach(instruction -> {
400 switch (instruction.type()) {
401 case L0MODIFICATION:
402 updateBuilder(defaultSelectorBuilder, (L0ModificationInstruction) instruction);
403 break;
404 case L1MODIFICATION:
405 updateBuilder(defaultSelectorBuilder, (L1ModificationInstruction) instruction);
406 break;
407 case L2MODIFICATION:
408 updateBuilder(defaultSelectorBuilder, (L2ModificationInstruction) instruction);
409 break;
410 case L3MODIFICATION:
411 updateBuilder(defaultSelectorBuilder, (L3ModificationInstruction) instruction);
412 break;
413 case L4MODIFICATION:
414 updateBuilder(defaultSelectorBuilder, (L4ModificationInstruction) instruction);
415 break;
416 case NOACTION:
417 case OUTPUT:
418 case GROUP:
419 case QUEUE:
420 case TABLE:
421 case METER:
422 case METADATA:
423 case EXTENSION: // TODO is extension no-op or unsupported?
424 // Nothing to do
425 break;
426 default:
427 throw new IntentCompilationException("Unknown instruction type");
428 }
429 });
430 return defaultSelectorBuilder;
431 }
432
433}