blob: 53c42871dd06875936714a35f375483d83992ecb [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();
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700115 outPorts.forEach(defaultTreatmentBuilder::setOutput);
Nicholas Dean126b8af2016-07-18 14:43:13 -0700116 TrafficTreatment outputOnlyTreatment = defaultTreatmentBuilder.build();
117 Set<PortNumber> ingressPorts = Collections.emptySet();
118 Set<PortNumber> egressPorts = Collections.emptySet();
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800119
Nicholas Dean126b8af2016-07-18 14:43:13 -0700120 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 }
Brian O'Connor406e2642016-04-18 11:45:35 -0700131
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800132 List<FlowRule> rules = new ArrayList<>(inPorts.size());
133 for (PortNumber inPort: inPorts) {
Brian O'Connor406e2642016-04-18 11:45:35 -0700134 TrafficSelector.Builder selectorBuilder;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800135 TrafficTreatment treatment;
Nicholas Dean126b8af2016-07-18 14:43:13 -0700136 TrafficTreatment intentTreatment;
137
138 if (!intent.applyTreatmentOnEgress()) {
139 TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment());
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700140 outPorts.forEach(ingressTreatmentBuilder::setOutput);
Nicholas Dean126b8af2016-07-18 14:43:13 -0700141 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 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800150 } else {
Nicholas Dean126b8af2016-07-18 14:43:13 -0700151 if (outPorts.stream().allMatch(egressPorts::contains)) {
152 TrafficTreatment.Builder egressTreatmentBuilder =
153 DefaultTrafficTreatment.builder(intent.treatment());
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700154 outPorts.forEach(egressTreatmentBuilder::setOutput);
Nicholas Dean126b8af2016-07-18 14:43:13 -0700155
156 selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
157 treatment = egressTreatmentBuilder.build();
158 } else {
159 selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
160 treatment = outputOnlyTreatment;
161 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800162 }
Brian O'Connor406e2642016-04-18 11:45:35 -0700163 TrafficSelector selector = selectorBuilder.matchInPort(inPort).build();
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800164
Brian O'Connor81134662015-06-25 17:23:33 -0400165 FlowRule rule = DefaultFlowRule.builder()
Nicholas Dean126b8af2016-07-18 14:43:13 -0700166 .forDevice(deviceId)
167 .withSelector(selector)
168 .withTreatment(treatment)
169 .withPriority(intent.priority())
170 .fromApp(appId)
171 .makePermanent()
172 .build();
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800173 rules.add(rule);
174 }
175
176 return rules;
177 }
Brian O'Connor406e2642016-04-18 11:45:35 -0700178
Nicholas Dean126b8af2016-07-18 14:43:13 -0700179 private TrafficSelector.Builder applyTreatmentToSelector(TrafficSelector selector, TrafficTreatment treatment) {
Brian O'Connor406e2642016-04-18 11:45:35 -0700180 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 });
Nicholas Dean126b8af2016-07-18 14:43:13 -0700341 return defaultSelectorBuilder;
Brian O'Connor406e2642016-04-18 11:45:35 -0700342 }
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700343}