blob: 5dda4ee4eecdf81c1e69369e66fe74b98bf94516 [file] [log] [blame]
Sho SHIMIZUee2aa652015-02-25 18:56:43 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Sho SHIMIZUee2aa652015-02-25 18:56:43 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.net.intent.impl.compiler;
17
18import com.google.common.collect.HashMultimap;
19import com.google.common.collect.SetMultimap;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
Brian O'Connor406e2642016-04-18 11:45:35 -070025import org.onlab.packet.Ip4Address;
26import org.onlab.packet.IpPrefix;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080027import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080029import org.onosproject.net.ConnectPoint;
30import org.onosproject.net.DeviceId;
31import org.onosproject.net.Link;
32import org.onosproject.net.PortNumber;
33import org.onosproject.net.flow.DefaultFlowRule;
34import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.FlowRule;
37import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
Brian O'Connor406e2642016-04-18 11:45:35 -070039import org.onosproject.net.flow.instructions.L2ModificationInstruction;
40import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
41import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
42import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
43import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
44import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
45import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
46import org.onosproject.net.flow.instructions.L3ModificationInstruction;
47import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpEthInstruction;
48import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpIPInstruction;
49import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpOpInstruction;
50import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
51import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
52import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080053import org.onosproject.net.intent.FlowRuleIntent;
54import org.onosproject.net.intent.Intent;
Yuta HIGUCHId95d5902016-06-27 00:18:45 -070055import org.onosproject.net.intent.IntentCompilationException;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080056import org.onosproject.net.intent.IntentCompiler;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080057import org.onosproject.net.intent.LinkCollectionIntent;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080058
59import java.util.ArrayList;
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070060import java.util.Collections;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080061import java.util.List;
62import java.util.Set;
63import java.util.stream.Collectors;
64
65@Component(immediate = true)
66public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollectionIntent> {
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080069 protected IntentConfigurableRegistrator registrator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080070
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected CoreService coreService;
73
74 private ApplicationId appId;
75
76 @Activate
77 public void activate() {
78 appId = coreService.registerApplication("org.onosproject.net.intent");
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080079 registrator.registerCompiler(LinkCollectionIntent.class, this, false);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080080 }
81
82 @Deactivate
83 public void deactivate() {
Thomas Vachuskabdbdd242016-03-01 01:55:55 -080084 registrator.unregisterCompiler(LinkCollectionIntent.class, false);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080085 }
86
87 @Override
Sho SHIMIZUec07ffd2016-02-22 20:45:21 -080088 public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080089 SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
90 SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
91
92 for (Link link : intent.links()) {
Jonathan Hart066244c2015-06-23 09:46:19 -070093 inputPorts.put(link.dst().deviceId(), link.dst().port());
94 outputPorts.put(link.src().deviceId(), link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080095 }
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
105 List<FlowRule> rules = new ArrayList<>();
106 for (DeviceId deviceId: outputPorts.keys()) {
107 rules.addAll(createRules(intent, deviceId, inputPorts.get(deviceId), outputPorts.get(deviceId)));
108 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700109 return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources()));
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800110 }
111
112 private List<FlowRule> createRules(LinkCollectionIntent intent, DeviceId deviceId,
113 Set<PortNumber> inPorts, Set<PortNumber> outPorts) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800114 TrafficTreatment.Builder defaultTreatmentBuilder = DefaultTrafficTreatment.builder();
115 outPorts.stream()
116 .forEach(defaultTreatmentBuilder::setOutput);
Nicholas Dean126b8af2016-07-18 14:43:13 -0700117 TrafficTreatment outputOnlyTreatment = defaultTreatmentBuilder.build();
118 Set<PortNumber> ingressPorts = Collections.emptySet();
119 Set<PortNumber> egressPorts = Collections.emptySet();
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800120
Nicholas Dean126b8af2016-07-18 14:43:13 -0700121 if (!intent.applyTreatmentOnEgress()) {
122 ingressPorts = intent.ingressPoints().stream()
123 .filter(point -> point.deviceId().equals(deviceId))
124 .map(ConnectPoint::port)
125 .collect(Collectors.toSet());
126 } else {
127 egressPorts = intent.egressPoints().stream()
128 .filter(point -> point.deviceId().equals(deviceId))
129 .map(ConnectPoint::port)
130 .collect(Collectors.toSet());
131 }
Brian O'Connor406e2642016-04-18 11:45:35 -0700132
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800133 List<FlowRule> rules = new ArrayList<>(inPorts.size());
134 for (PortNumber inPort: inPorts) {
Brian O'Connor406e2642016-04-18 11:45:35 -0700135 TrafficSelector.Builder selectorBuilder;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800136 TrafficTreatment treatment;
Nicholas Dean126b8af2016-07-18 14:43:13 -0700137 TrafficTreatment intentTreatment;
138
139 if (!intent.applyTreatmentOnEgress()) {
140 TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment());
141 outPorts.stream()
142 .forEach(ingressTreatmentBuilder::setOutput);
143 intentTreatment = ingressTreatmentBuilder.build();
144
145 if (ingressPorts.contains(inPort)) {
146 selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
147 treatment = intentTreatment;
148 } else {
149 selectorBuilder = applyTreatmentToSelector(intent.selector(), intentTreatment);
150 treatment = outputOnlyTreatment;
151 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800152 } else {
Nicholas Dean126b8af2016-07-18 14:43:13 -0700153 if (outPorts.stream().allMatch(egressPorts::contains)) {
154 TrafficTreatment.Builder egressTreatmentBuilder =
155 DefaultTrafficTreatment.builder(intent.treatment());
156 outPorts.stream()
157 .forEach(egressTreatmentBuilder::setOutput);
158
159 selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
160 treatment = egressTreatmentBuilder.build();
161 } else {
162 selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
163 treatment = outputOnlyTreatment;
164 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800165 }
Brian O'Connor406e2642016-04-18 11:45:35 -0700166 TrafficSelector selector = selectorBuilder.matchInPort(inPort).build();
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800167
Brian O'Connor81134662015-06-25 17:23:33 -0400168 FlowRule rule = DefaultFlowRule.builder()
Nicholas Dean126b8af2016-07-18 14:43:13 -0700169 .forDevice(deviceId)
170 .withSelector(selector)
171 .withTreatment(treatment)
172 .withPriority(intent.priority())
173 .fromApp(appId)
174 .makePermanent()
175 .build();
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800176 rules.add(rule);
177 }
178
179 return rules;
180 }
Brian O'Connor406e2642016-04-18 11:45:35 -0700181
Nicholas Dean126b8af2016-07-18 14:43:13 -0700182 private TrafficSelector.Builder applyTreatmentToSelector(TrafficSelector selector, TrafficTreatment treatment) {
Brian O'Connor406e2642016-04-18 11:45:35 -0700183 TrafficSelector.Builder defaultSelectorBuilder = DefaultTrafficSelector.builder(selector);
184 treatment.allInstructions().forEach(instruction -> {
185 switch (instruction.type()) {
186 case L0MODIFICATION:
187 case L1MODIFICATION:
188 throw new IntentCompilationException("L0 and L1 mods not supported");
189 case L2MODIFICATION:
190 L2ModificationInstruction l2mod = (L2ModificationInstruction) instruction;
191 switch (l2mod.subtype()) {
192 case ETH_SRC:
193 case ETH_DST:
194 ModEtherInstruction ethInstr = (ModEtherInstruction) l2mod;
195 switch (ethInstr.subtype()) {
196 case ETH_SRC:
197 defaultSelectorBuilder.matchEthSrc(ethInstr.mac());
198 break;
199 case ETH_DST:
200 defaultSelectorBuilder.matchEthDst(ethInstr.mac());
201 break;
202 default:
203 throw new IntentCompilationException("Bad eth subtype");
204 }
205 break;
206 case VLAN_ID:
207 ModVlanIdInstruction vlanIdInstr = (ModVlanIdInstruction) l2mod;
208 defaultSelectorBuilder.matchVlanId(vlanIdInstr.vlanId());
209 break;
210 case VLAN_PUSH:
211 //FIXME
212 break;
213 case VLAN_POP:
214 //TODO how do we handle dropped label? remove the selector?
215 throw new IntentCompilationException("Can't handle pop label");
216 case VLAN_PCP:
217 ModVlanPcpInstruction vlanPcpInstruction = (ModVlanPcpInstruction) l2mod;
218 defaultSelectorBuilder.matchVlanPcp(vlanPcpInstruction.vlanPcp());
219 break;
220 case MPLS_LABEL:
221 case MPLS_PUSH:
222 //FIXME
223 ModMplsLabelInstruction mplsInstr = (ModMplsLabelInstruction) l2mod;
224 defaultSelectorBuilder.matchMplsLabel(mplsInstr.label());
225 break;
226 case MPLS_POP:
227 //TODO how do we handle dropped label? remove the selector?
228 throw new IntentCompilationException("Can't handle pop label");
229 case DEC_MPLS_TTL:
230 // no-op
231 break;
232 case MPLS_BOS:
233 ModMplsBosInstruction mplsBosInstr = (ModMplsBosInstruction) l2mod;
234 defaultSelectorBuilder.matchMplsBos(mplsBosInstr.mplsBos());
235 break;
236 case TUNNEL_ID:
237 ModTunnelIdInstruction tunInstr = (ModTunnelIdInstruction) l2mod;
238 defaultSelectorBuilder.matchTunnelId(tunInstr.tunnelId());
239 break;
240 default:
241 throw new IntentCompilationException("Unknown L2 Modification instruction");
242 }
243 break;
244 case L3MODIFICATION:
245 L3ModificationInstruction l3mod = (L3ModificationInstruction) instruction;
246 // TODO check ethernet proto
247 switch (l3mod.subtype()) {
248 case IPV4_SRC:
249 case IPV4_DST:
250 case IPV6_SRC:
251 case IPV6_DST:
252 ModIPInstruction ipInstr = (ModIPInstruction) l3mod;
253 // TODO check if ip falls in original prefix
254 IpPrefix prefix = ipInstr.ip().toIpPrefix();
255 switch (ipInstr.subtype()) {
256 case IPV4_SRC:
257 defaultSelectorBuilder.matchIPSrc(prefix);
258 break;
259 case IPV4_DST:
260 defaultSelectorBuilder.matchIPSrc(prefix);
261 break;
262 case IPV6_SRC:
263 defaultSelectorBuilder.matchIPv6Src(prefix);
264 break;
265 case IPV6_DST:
266 defaultSelectorBuilder.matchIPv6Dst(prefix);
267 break;
268 default:
269 throw new IntentCompilationException("Bad type for IP instruction");
270 }
271 break;
272 case IPV6_FLABEL:
273 ModIPv6FlowLabelInstruction ipFlowInstr = (ModIPv6FlowLabelInstruction) l3mod;
274 defaultSelectorBuilder.matchIPv6FlowLabel(ipFlowInstr.flowLabel());
275 break;
276 case DEC_TTL:
277 // no-op
278 break;
279 case TTL_OUT:
280 // no-op
281 break;
282 case TTL_IN:
283 // no-op
284 break;
285 case ARP_SPA:
286 ModArpIPInstruction arpIpInstr = (ModArpIPInstruction) l3mod;
287 if (arpIpInstr.ip().isIp4()) {
288 defaultSelectorBuilder.matchArpSpa((Ip4Address) arpIpInstr.ip());
289 } else {
290 throw new IntentCompilationException("IPv6 not supported for ARP");
291 }
292 break;
293 case ARP_SHA:
294 ModArpEthInstruction arpEthInstr = (ModArpEthInstruction) l3mod;
295 defaultSelectorBuilder.matchArpSha(arpEthInstr.mac());
296 break;
297 case ARP_OP:
298 ModArpOpInstruction arpOpInstr = (ModArpOpInstruction) l3mod;
299 //FIXME is the long to int cast safe?
300 defaultSelectorBuilder.matchArpOp((int) arpOpInstr.op());
301 break;
302 default:
303 throw new IntentCompilationException("Unknown L3 Modification instruction");
304 }
305 break;
306 case L4MODIFICATION:
307 if (instruction instanceof ModTransportPortInstruction) {
308 // TODO check IP proto
309 ModTransportPortInstruction l4mod = (ModTransportPortInstruction) instruction;
310 switch (l4mod.subtype()) {
311 case TCP_SRC:
312 defaultSelectorBuilder.matchTcpSrc(l4mod.port());
313 break;
314 case TCP_DST:
315 defaultSelectorBuilder.matchTcpDst(l4mod.port());
316 break;
317 case UDP_SRC:
318 defaultSelectorBuilder.matchUdpSrc(l4mod.port());
319 break;
320 case UDP_DST:
321 defaultSelectorBuilder.matchUdpDst(l4mod.port());
322 break;
323 default:
324 throw new IntentCompilationException("Unknown L4 Modification instruction");
325 }
326 } else {
327 throw new IntentCompilationException("Unknown L4 Modification instruction");
328 }
329 break;
330 case NOACTION:
331 case OUTPUT:
332 case GROUP:
333 case QUEUE:
334 case TABLE:
335 case METER:
336 case METADATA:
337 case EXTENSION: // TODO is extension no-op or unsupported?
338 // Nothing to do
339 break;
340 default:
341 throw new IntentCompilationException("Unknown instruction type");
342 }
343 });
Nicholas Dean126b8af2016-07-18 14:43:13 -0700344 return defaultSelectorBuilder;
Brian O'Connor406e2642016-04-18 11:45:35 -0700345 }
Nicholas Dean126b8af2016-07-18 14:43:13 -0700346}