Pier Ventre
Committed by Gerrit Code Review

Fix [ONOS-4857] and impement [ONOS-5143]

Change-Id: I7159ff9deaacaf10070e1535f4a80f2f846a5784
1 +/*
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 +
17 +package org.onosproject.net.intent.impl.compiler;
18 +
19 +import com.google.common.collect.SetMultimap;
20 +import org.onlab.packet.Ip4Address;
21 +import org.onlab.packet.IpPrefix;
22 +import org.onosproject.net.ConnectPoint;
23 +import org.onosproject.net.DeviceId;
24 +import org.onosproject.net.Link;
25 +import org.onosproject.net.PortNumber;
26 +import org.onosproject.net.flow.DefaultTrafficSelector;
27 +import org.onosproject.net.flow.DefaultTrafficTreatment;
28 +import org.onosproject.net.flow.TrafficSelector;
29 +import org.onosproject.net.flow.TrafficTreatment;
30 +import org.onosproject.net.flow.instructions.L0ModificationInstruction;
31 +import org.onosproject.net.flow.instructions.L1ModificationInstruction;
32 +import org.onosproject.net.flow.instructions.L2ModificationInstruction;
33 +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
34 +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
35 +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
36 +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
37 +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
38 +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
39 +import org.onosproject.net.flow.instructions.L3ModificationInstruction;
40 +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpEthInstruction;
41 +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpIPInstruction;
42 +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpOpInstruction;
43 +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
44 +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
45 +import org.onosproject.net.flow.instructions.L4ModificationInstruction;
46 +import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
47 +import org.onosproject.net.intent.IntentCompilationException;
48 +import org.onosproject.net.intent.LinkCollectionIntent;
49 +
50 +import java.util.List;
51 +import java.util.Set;
52 +import java.util.stream.Collectors;
53 +
54 +/**
55 + * Shared APIs and implementations for Link Collection compilers.
56 + */
57 +public 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 +}
...@@ -16,43 +16,22 @@ ...@@ -16,43 +16,22 @@
16 package org.onosproject.net.intent.impl.compiler; 16 package org.onosproject.net.intent.impl.compiler;
17 17
18 import com.google.common.collect.HashMultimap; 18 import com.google.common.collect.HashMultimap;
19 +import com.google.common.collect.ImmutableSet;
19 import com.google.common.collect.SetMultimap; 20 import com.google.common.collect.SetMultimap;
21 +import com.google.common.collect.Sets;
20 import org.apache.felix.scr.annotations.Activate; 22 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 23 import org.apache.felix.scr.annotations.Component;
22 import org.apache.felix.scr.annotations.Deactivate; 24 import org.apache.felix.scr.annotations.Deactivate;
23 import org.apache.felix.scr.annotations.Reference; 25 import org.apache.felix.scr.annotations.Reference;
24 import org.apache.felix.scr.annotations.ReferenceCardinality; 26 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 -import org.onlab.packet.Ip4Address;
26 -import org.onlab.packet.IpPrefix;
27 import org.onosproject.core.ApplicationId; 27 import org.onosproject.core.ApplicationId;
28 import org.onosproject.core.CoreService; 28 import org.onosproject.core.CoreService;
29 -import org.onosproject.net.ConnectPoint;
30 import org.onosproject.net.DeviceId; 29 import org.onosproject.net.DeviceId;
31 -import org.onosproject.net.Link;
32 import org.onosproject.net.PortNumber; 30 import org.onosproject.net.PortNumber;
33 import org.onosproject.net.flow.DefaultFlowRule; 31 import org.onosproject.net.flow.DefaultFlowRule;
34 -import org.onosproject.net.flow.DefaultTrafficSelector;
35 -import org.onosproject.net.flow.DefaultTrafficTreatment;
36 import org.onosproject.net.flow.FlowRule; 32 import org.onosproject.net.flow.FlowRule;
37 -import org.onosproject.net.flow.TrafficSelector;
38 -import org.onosproject.net.flow.TrafficTreatment;
39 -import org.onosproject.net.flow.instructions.L2ModificationInstruction;
40 -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
41 -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
42 -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
43 -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
44 -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
45 -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
46 -import org.onosproject.net.flow.instructions.L3ModificationInstruction;
47 -import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpEthInstruction;
48 -import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpIPInstruction;
49 -import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpOpInstruction;
50 -import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
51 -import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
52 -import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
53 import org.onosproject.net.intent.FlowRuleIntent; 33 import org.onosproject.net.intent.FlowRuleIntent;
54 import org.onosproject.net.intent.Intent; 34 import org.onosproject.net.intent.Intent;
55 -import org.onosproject.net.intent.IntentCompilationException;
56 import org.onosproject.net.intent.IntentCompiler; 35 import org.onosproject.net.intent.IntentCompiler;
57 import org.onosproject.net.intent.LinkCollectionIntent; 36 import org.onosproject.net.intent.LinkCollectionIntent;
58 37
...@@ -60,10 +39,14 @@ import java.util.ArrayList; ...@@ -60,10 +39,14 @@ import java.util.ArrayList;
60 import java.util.Collections; 39 import java.util.Collections;
61 import java.util.List; 40 import java.util.List;
62 import java.util.Set; 41 import java.util.Set;
63 -import java.util.stream.Collectors;
64 42
43 +/**
44 + * Compiler to produce flow rules from link collections.
45 + */
65 @Component(immediate = true) 46 @Component(immediate = true)
66 -public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollectionIntent> { 47 +public class LinkCollectionIntentCompiler
48 + extends LinkCollectionCompiler<FlowRule>
49 + implements IntentCompiler<LinkCollectionIntent> {
67 50
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 51 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected IntentConfigurableRegistrator registrator; 52 protected IntentConfigurableRegistrator registrator;
...@@ -86,21 +69,11 @@ public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollecti ...@@ -86,21 +69,11 @@ public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollecti
86 69
87 @Override 70 @Override
88 public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) { 71 public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
72 +
89 SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create(); 73 SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
90 SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create(); 74 SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
91 75
92 - for (Link link : intent.links()) { 76 + computePorts(intent, inputPorts, outputPorts);
93 - inputPorts.put(link.dst().deviceId(), link.dst().port());
94 - outputPorts.put(link.src().deviceId(), link.src().port());
95 - }
96 -
97 - for (ConnectPoint ingressPoint : intent.ingressPoints()) {
98 - inputPorts.put(ingressPoint.deviceId(), ingressPoint.port());
99 - }
100 -
101 - for (ConnectPoint egressPoint : intent.egressPoints()) {
102 - outputPorts.put(egressPoint.deviceId(), egressPoint.port());
103 - }
104 77
105 List<FlowRule> rules = new ArrayList<>(); 78 List<FlowRule> rules = new ArrayList<>();
106 for (DeviceId deviceId: outputPorts.keys()) { 79 for (DeviceId deviceId: outputPorts.keys()) {
...@@ -109,235 +82,37 @@ public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollecti ...@@ -109,235 +82,37 @@ public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollecti
109 return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources())); 82 return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources()));
110 } 83 }
111 84
112 - private List<FlowRule> createRules(LinkCollectionIntent intent, DeviceId deviceId, 85 + @Override
86 + protected List<FlowRule> createRules(LinkCollectionIntent intent, DeviceId deviceId,
113 Set<PortNumber> inPorts, Set<PortNumber> outPorts) { 87 Set<PortNumber> inPorts, Set<PortNumber> outPorts) {
114 - TrafficTreatment.Builder defaultTreatmentBuilder = DefaultTrafficTreatment.builder();
115 - outPorts.forEach(defaultTreatmentBuilder::setOutput);
116 - TrafficTreatment outputOnlyTreatment = defaultTreatmentBuilder.build();
117 - Set<PortNumber> ingressPorts = Collections.emptySet();
118 - Set<PortNumber> egressPorts = Collections.emptySet();
119 -
120 - if (!intent.applyTreatmentOnEgress()) {
121 - ingressPorts = intent.ingressPoints().stream()
122 - .filter(point -> point.deviceId().equals(deviceId))
123 - .map(ConnectPoint::port)
124 - .collect(Collectors.toSet());
125 - } else {
126 - egressPorts = intent.egressPoints().stream()
127 - .filter(point -> point.deviceId().equals(deviceId))
128 - .map(ConnectPoint::port)
129 - .collect(Collectors.toSet());
130 - }
131 88
132 - List<FlowRule> rules = new ArrayList<>(inPorts.size()); 89 + Set<PortNumber> ingressPorts = Sets.newHashSet();
133 - for (PortNumber inPort: inPorts) { 90 + Set<PortNumber> egressPorts = Sets.newHashSet();
134 - TrafficSelector.Builder selectorBuilder;
135 - TrafficTreatment treatment;
136 - TrafficTreatment intentTreatment;
137 91
138 - if (!intent.applyTreatmentOnEgress()) { 92 + computePorts(intent, deviceId, ingressPorts, egressPorts);
139 - TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment());
140 - outPorts.forEach(ingressTreatmentBuilder::setOutput);
141 - intentTreatment = ingressTreatmentBuilder.build();
142 -
143 - if (ingressPorts.contains(inPort)) {
144 - selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
145 - treatment = intentTreatment;
146 - } else {
147 - selectorBuilder = applyTreatmentToSelector(intent.selector(), intentTreatment);
148 - treatment = outputOnlyTreatment;
149 - }
150 - } else {
151 - if (outPorts.stream().allMatch(egressPorts::contains)) {
152 - TrafficTreatment.Builder egressTreatmentBuilder =
153 - DefaultTrafficTreatment.builder(intent.treatment());
154 - outPorts.forEach(egressTreatmentBuilder::setOutput);
155 -
156 - selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
157 - treatment = egressTreatmentBuilder.build();
158 - } else {
159 - selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
160 - treatment = outputOnlyTreatment;
161 - }
162 - }
163 - TrafficSelector selector = selectorBuilder.matchInPort(inPort).build();
164 93
94 + List<FlowRule> rules = new ArrayList<>(inPorts.size());
95 + Set<PortNumber> copyIngressPorts = ImmutableSet.copyOf(ingressPorts);
96 + Set<PortNumber> copyEgressPorts = ImmutableSet.copyOf(egressPorts);
97 +
98 + inPorts.forEach(inport -> {
99 + ForwardingInstructions instructions = this.createForwardingInstructions(intent,
100 + inport,
101 + outPorts,
102 + copyIngressPorts,
103 + copyEgressPorts);
165 FlowRule rule = DefaultFlowRule.builder() 104 FlowRule rule = DefaultFlowRule.builder()
166 .forDevice(deviceId) 105 .forDevice(deviceId)
167 - .withSelector(selector) 106 + .withSelector(instructions.selector())
168 - .withTreatment(treatment) 107 + .withTreatment(instructions.treatment())
169 .withPriority(intent.priority()) 108 .withPriority(intent.priority())
170 .fromApp(appId) 109 .fromApp(appId)
171 .makePermanent() 110 .makePermanent()
172 .build(); 111 .build();
173 rules.add(rule); 112 rules.add(rule);
174 } 113 }
114 + );
175 115
176 return rules; 116 return rules;
177 } 117 }
178 -
179 - private TrafficSelector.Builder applyTreatmentToSelector(TrafficSelector selector, TrafficTreatment treatment) {
180 - TrafficSelector.Builder defaultSelectorBuilder = DefaultTrafficSelector.builder(selector);
181 - treatment.allInstructions().forEach(instruction -> {
182 - switch (instruction.type()) {
183 - case L0MODIFICATION:
184 - case L1MODIFICATION:
185 - throw new IntentCompilationException("L0 and L1 mods not supported");
186 - case L2MODIFICATION:
187 - L2ModificationInstruction l2mod = (L2ModificationInstruction) instruction;
188 - switch (l2mod.subtype()) {
189 - case ETH_SRC:
190 - case ETH_DST:
191 - ModEtherInstruction ethInstr = (ModEtherInstruction) l2mod;
192 - switch (ethInstr.subtype()) {
193 - case ETH_SRC:
194 - defaultSelectorBuilder.matchEthSrc(ethInstr.mac());
195 - break;
196 - case ETH_DST:
197 - defaultSelectorBuilder.matchEthDst(ethInstr.mac());
198 - break;
199 - default:
200 - throw new IntentCompilationException("Bad eth subtype");
201 - }
202 - break;
203 - case VLAN_ID:
204 - ModVlanIdInstruction vlanIdInstr = (ModVlanIdInstruction) l2mod;
205 - defaultSelectorBuilder.matchVlanId(vlanIdInstr.vlanId());
206 - break;
207 - case VLAN_PUSH:
208 - //FIXME
209 - break;
210 - case VLAN_POP:
211 - //TODO how do we handle dropped label? remove the selector?
212 - throw new IntentCompilationException("Can't handle pop label");
213 - case VLAN_PCP:
214 - ModVlanPcpInstruction vlanPcpInstruction = (ModVlanPcpInstruction) l2mod;
215 - defaultSelectorBuilder.matchVlanPcp(vlanPcpInstruction.vlanPcp());
216 - break;
217 - case MPLS_LABEL:
218 - case MPLS_PUSH:
219 - //FIXME
220 - ModMplsLabelInstruction mplsInstr = (ModMplsLabelInstruction) l2mod;
221 - defaultSelectorBuilder.matchMplsLabel(mplsInstr.label());
222 - break;
223 - case MPLS_POP:
224 - //TODO how do we handle dropped label? remove the selector?
225 - throw new IntentCompilationException("Can't handle pop label");
226 - case DEC_MPLS_TTL:
227 - // no-op
228 - break;
229 - case MPLS_BOS:
230 - ModMplsBosInstruction mplsBosInstr = (ModMplsBosInstruction) l2mod;
231 - defaultSelectorBuilder.matchMplsBos(mplsBosInstr.mplsBos());
232 - break;
233 - case TUNNEL_ID:
234 - ModTunnelIdInstruction tunInstr = (ModTunnelIdInstruction) l2mod;
235 - defaultSelectorBuilder.matchTunnelId(tunInstr.tunnelId());
236 - break;
237 - default:
238 - throw new IntentCompilationException("Unknown L2 Modification instruction");
239 - }
240 - break;
241 - case L3MODIFICATION:
242 - L3ModificationInstruction l3mod = (L3ModificationInstruction) instruction;
243 - // TODO check ethernet proto
244 - switch (l3mod.subtype()) {
245 - case IPV4_SRC:
246 - case IPV4_DST:
247 - case IPV6_SRC:
248 - case IPV6_DST:
249 - ModIPInstruction ipInstr = (ModIPInstruction) l3mod;
250 - // TODO check if ip falls in original prefix
251 - IpPrefix prefix = ipInstr.ip().toIpPrefix();
252 - switch (ipInstr.subtype()) {
253 - case IPV4_SRC:
254 - defaultSelectorBuilder.matchIPSrc(prefix);
255 - break;
256 - case IPV4_DST:
257 - defaultSelectorBuilder.matchIPSrc(prefix);
258 - break;
259 - case IPV6_SRC:
260 - defaultSelectorBuilder.matchIPv6Src(prefix);
261 - break;
262 - case IPV6_DST:
263 - defaultSelectorBuilder.matchIPv6Dst(prefix);
264 - break;
265 - default:
266 - throw new IntentCompilationException("Bad type for IP instruction");
267 - }
268 - break;
269 - case IPV6_FLABEL:
270 - ModIPv6FlowLabelInstruction ipFlowInstr = (ModIPv6FlowLabelInstruction) l3mod;
271 - defaultSelectorBuilder.matchIPv6FlowLabel(ipFlowInstr.flowLabel());
272 - break;
273 - case DEC_TTL:
274 - // no-op
275 - break;
276 - case TTL_OUT:
277 - // no-op
278 - break;
279 - case TTL_IN:
280 - // no-op
281 - break;
282 - case ARP_SPA:
283 - ModArpIPInstruction arpIpInstr = (ModArpIPInstruction) l3mod;
284 - if (arpIpInstr.ip().isIp4()) {
285 - defaultSelectorBuilder.matchArpSpa((Ip4Address) arpIpInstr.ip());
286 - } else {
287 - throw new IntentCompilationException("IPv6 not supported for ARP");
288 - }
289 - break;
290 - case ARP_SHA:
291 - ModArpEthInstruction arpEthInstr = (ModArpEthInstruction) l3mod;
292 - defaultSelectorBuilder.matchArpSha(arpEthInstr.mac());
293 - break;
294 - case ARP_OP:
295 - ModArpOpInstruction arpOpInstr = (ModArpOpInstruction) l3mod;
296 - //FIXME is the long to int cast safe?
297 - defaultSelectorBuilder.matchArpOp((int) arpOpInstr.op());
298 - break;
299 - default:
300 - throw new IntentCompilationException("Unknown L3 Modification instruction");
301 - }
302 - break;
303 - case L4MODIFICATION:
304 - if (instruction instanceof ModTransportPortInstruction) {
305 - // TODO check IP proto
306 - ModTransportPortInstruction l4mod = (ModTransportPortInstruction) instruction;
307 - switch (l4mod.subtype()) {
308 - case TCP_SRC:
309 - defaultSelectorBuilder.matchTcpSrc(l4mod.port());
310 - break;
311 - case TCP_DST:
312 - defaultSelectorBuilder.matchTcpDst(l4mod.port());
313 - break;
314 - case UDP_SRC:
315 - defaultSelectorBuilder.matchUdpSrc(l4mod.port());
316 - break;
317 - case UDP_DST:
318 - defaultSelectorBuilder.matchUdpDst(l4mod.port());
319 - break;
320 - default:
321 - throw new IntentCompilationException("Unknown L4 Modification instruction");
322 - }
323 - } else {
324 - throw new IntentCompilationException("Unknown L4 Modification instruction");
325 - }
326 - break;
327 - case NOACTION:
328 - case OUTPUT:
329 - case GROUP:
330 - case QUEUE:
331 - case TABLE:
332 - case METER:
333 - case METADATA:
334 - case EXTENSION: // TODO is extension no-op or unsupported?
335 - // Nothing to do
336 - break;
337 - default:
338 - throw new IntentCompilationException("Unknown instruction type");
339 - }
340 - });
341 - return defaultSelectorBuilder;
342 - }
343 } 118 }
......
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
16 package org.onosproject.net.intent.impl.compiler; 16 package org.onosproject.net.intent.impl.compiler;
17 17
18 import com.google.common.collect.HashMultimap; 18 import com.google.common.collect.HashMultimap;
19 +import com.google.common.collect.ImmutableSet;
19 import com.google.common.collect.SetMultimap; 20 import com.google.common.collect.SetMultimap;
21 +import com.google.common.collect.Sets;
20 import org.apache.felix.scr.annotations.Activate; 22 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 23 import org.apache.felix.scr.annotations.Component;
22 import org.apache.felix.scr.annotations.Deactivate; 24 import org.apache.felix.scr.annotations.Deactivate;
...@@ -24,14 +26,8 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -24,14 +26,8 @@ import org.apache.felix.scr.annotations.Reference;
24 import org.apache.felix.scr.annotations.ReferenceCardinality; 26 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 import org.onosproject.core.ApplicationId; 27 import org.onosproject.core.ApplicationId;
26 import org.onosproject.core.CoreService; 28 import org.onosproject.core.CoreService;
27 -import org.onosproject.net.ConnectPoint;
28 import org.onosproject.net.DeviceId; 29 import org.onosproject.net.DeviceId;
29 -import org.onosproject.net.Link;
30 import org.onosproject.net.PortNumber; 30 import org.onosproject.net.PortNumber;
31 -import org.onosproject.net.flow.DefaultTrafficSelector;
32 -import org.onosproject.net.flow.DefaultTrafficTreatment;
33 -import org.onosproject.net.flow.TrafficSelector;
34 -import org.onosproject.net.flow.TrafficTreatment;
35 import org.onosproject.net.flowobjective.DefaultForwardingObjective; 31 import org.onosproject.net.flowobjective.DefaultForwardingObjective;
36 import org.onosproject.net.flowobjective.DefaultNextObjective; 32 import org.onosproject.net.flowobjective.DefaultNextObjective;
37 import org.onosproject.net.flowobjective.FlowObjectiveService; 33 import org.onosproject.net.flowobjective.FlowObjectiveService;
...@@ -47,13 +43,14 @@ import java.util.ArrayList; ...@@ -47,13 +43,14 @@ import java.util.ArrayList;
47 import java.util.Collections; 43 import java.util.Collections;
48 import java.util.List; 44 import java.util.List;
49 import java.util.Set; 45 import java.util.Set;
50 -import java.util.stream.Collectors;
51 46
52 /** 47 /**
53 * Compiler to produce flow objectives from link collections. 48 * Compiler to produce flow objectives from link collections.
54 */ 49 */
55 @Component(immediate = true) 50 @Component(immediate = true)
56 -public class LinkCollectionIntentFlowObjectivesCompiler implements IntentCompiler<LinkCollectionIntent> { 51 +public class LinkCollectionIntentFlowObjectiveCompiler
52 + extends LinkCollectionCompiler<Objective>
53 + implements IntentCompiler<LinkCollectionIntent> {
57 54
58 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 55 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 protected IntentConfigurableRegistrator registrator; 56 protected IntentConfigurableRegistrator registrator;
...@@ -79,21 +76,11 @@ public class LinkCollectionIntentFlowObjectivesCompiler implements IntentCompile ...@@ -79,21 +76,11 @@ public class LinkCollectionIntentFlowObjectivesCompiler implements IntentCompile
79 76
80 @Override 77 @Override
81 public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) { 78 public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
79 +
82 SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create(); 80 SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
83 SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create(); 81 SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
84 82
85 - for (Link link : intent.links()) { 83 + computePorts(intent, inputPorts, outputPorts);
86 - inputPorts.put(link.dst().deviceId(), link.dst().port());
87 - outputPorts.put(link.src().deviceId(), link.src().port());
88 - }
89 -
90 - for (ConnectPoint ingressPoint : intent.ingressPoints()) {
91 - inputPorts.put(ingressPoint.deviceId(), ingressPoint.port());
92 - }
93 -
94 - for (ConnectPoint egressPoint : intent.egressPoints()) {
95 - outputPorts.put(egressPoint.deviceId(), egressPoint.port());
96 - }
97 84
98 List<Objective> objectives = new ArrayList<>(); 85 List<Objective> objectives = new ArrayList<>();
99 List<DeviceId> devices = new ArrayList<>(); 86 List<DeviceId> devices = new ArrayList<>();
...@@ -112,41 +99,36 @@ public class LinkCollectionIntentFlowObjectivesCompiler implements IntentCompile ...@@ -112,41 +99,36 @@ public class LinkCollectionIntentFlowObjectivesCompiler implements IntentCompile
112 new FlowObjectiveIntent(appId, devices, objectives, intent.resources())); 99 new FlowObjectiveIntent(appId, devices, objectives, intent.resources()));
113 } 100 }
114 101
115 - private List<Objective> createRules(LinkCollectionIntent intent, DeviceId deviceId, 102 + @Override
103 + protected List<Objective> createRules(LinkCollectionIntent intent, DeviceId deviceId,
116 Set<PortNumber> inPorts, Set<PortNumber> outPorts) { 104 Set<PortNumber> inPorts, Set<PortNumber> outPorts) {
117 - Set<PortNumber> ingressPorts = intent.ingressPoints().stream()
118 - .filter(point -> point.deviceId().equals(deviceId))
119 - .map(ConnectPoint::port)
120 - .collect(Collectors.toSet());
121 105
122 - TrafficTreatment.Builder defaultTreatmentBuilder = DefaultTrafficTreatment.builder(); 106 + Set<PortNumber> ingressPorts = Sets.newHashSet();
123 - outPorts.forEach(defaultTreatmentBuilder::setOutput); 107 + Set<PortNumber> egressPorts = Sets.newHashSet();
124 - TrafficTreatment defaultTreatment = defaultTreatmentBuilder.build();
125 108
126 - TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment()); 109 + computePorts(intent, deviceId, ingressPorts, egressPorts);
127 - outPorts.forEach(ingressTreatmentBuilder::setOutput);
128 - TrafficTreatment ingressTreatment = ingressTreatmentBuilder.build();
129 110
130 List<Objective> objectives = new ArrayList<>(inPorts.size()); 111 List<Objective> objectives = new ArrayList<>(inPorts.size());
131 - for (PortNumber inPort: inPorts) { 112 + Set<PortNumber> copyIngressPorts = ImmutableSet.copyOf(ingressPorts);
132 - TrafficSelector selector = DefaultTrafficSelector.builder(intent.selector()).matchInPort(inPort).build(); 113 + Set<PortNumber> copyEgressPorts = ImmutableSet.copyOf(egressPorts);
133 - TrafficTreatment treatment; 114 +
134 - if (ingressPorts.contains(inPort)) { 115 + inPorts.forEach(inport -> {
135 - treatment = ingressTreatment; 116 + ForwardingInstructions instructions = this.createForwardingInstructions(intent,
136 - } else { 117 + inport,
137 - treatment = defaultTreatment; 118 + outPorts,
138 - } 119 + copyIngressPorts,
120 + copyEgressPorts);
139 121
140 NextObjective nextObjective = DefaultNextObjective.builder() 122 NextObjective nextObjective = DefaultNextObjective.builder()
141 .withId(flowObjectiveService.allocateNextId()) 123 .withId(flowObjectiveService.allocateNextId())
142 - .addTreatment(treatment) 124 + .addTreatment(instructions.treatment())
143 .withType(NextObjective.Type.SIMPLE) 125 .withType(NextObjective.Type.SIMPLE)
144 .fromApp(appId) 126 .fromApp(appId)
145 .makePermanent().add(); 127 .makePermanent().add();
146 objectives.add(nextObjective); 128 objectives.add(nextObjective);
147 129
148 objectives.add(DefaultForwardingObjective.builder() 130 objectives.add(DefaultForwardingObjective.builder()
149 - .withSelector(selector) 131 + .withSelector(instructions.selector())
150 .nextStep(nextObjective.id()) 132 .nextStep(nextObjective.id())
151 .withPriority(intent.priority()) 133 .withPriority(intent.priority())
152 .fromApp(appId) 134 .fromApp(appId)
...@@ -154,7 +136,9 @@ public class LinkCollectionIntentFlowObjectivesCompiler implements IntentCompile ...@@ -154,7 +136,9 @@ public class LinkCollectionIntentFlowObjectivesCompiler implements IntentCompile
154 .withFlag(ForwardingObjective.Flag.SPECIFIC) 136 .withFlag(ForwardingObjective.Flag.SPECIFIC)
155 .add()); 137 .add());
156 } 138 }
139 + );
157 140
158 return objectives; 141 return objectives;
159 } 142 }
143 +
160 } 144 }
......