blob: 9c848538c0420a9b8bdb40dcd91178f3e5dac2be [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;
Michele Santuari4b6019e2014-12-19 11:31:45 +010017
Sho SHIMIZU44f37612015-11-25 16:23:22 -080018import com.google.common.collect.ImmutableList;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080019import com.google.common.collect.Sets;
Michele Santuari4b6019e2014-12-19 11:31:45 +010020import 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;
Michele Santuari316d8cf2015-07-14 17:24:54 +020025import org.onlab.packet.EthType;
Michele Santuari4b6019e2014-12-19 11:31:45 +010026import org.onlab.packet.Ethernet;
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070027import org.onlab.packet.MplsLabel;
Dusan Pajin6b887c92015-07-01 18:32:49 +020028import org.onlab.packet.VlanId;
Michele Santuari4b6019e2014-12-19 11:31:45 +010029import org.onosproject.core.ApplicationId;
30import org.onosproject.core.CoreService;
31import org.onosproject.net.ConnectPoint;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.Link;
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070034import org.onosproject.net.LinkKey;
Michele Santuari4b6019e2014-12-19 11:31:45 +010035import org.onosproject.net.PortNumber;
36import org.onosproject.net.flow.DefaultFlowRule;
37import org.onosproject.net.flow.DefaultTrafficSelector;
38import org.onosproject.net.flow.DefaultTrafficTreatment;
39import org.onosproject.net.flow.FlowRule;
Michele Santuari4b6019e2014-12-19 11:31:45 +010040import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.flow.TrafficTreatment;
Michele Santuari4b6019e2014-12-19 11:31:45 +010042import org.onosproject.net.flow.criteria.Criterion;
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -070043import org.onosproject.net.flow.criteria.EthTypeCriterion;
Dusan Pajin6b887c92015-07-01 18:32:49 +020044import org.onosproject.net.flow.instructions.Instruction;
45import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080046import org.onosproject.net.intent.FlowRuleIntent;
47import org.onosproject.net.intent.Intent;
48import org.onosproject.net.intent.IntentCompiler;
Michele Santuari4b6019e2014-12-19 11:31:45 +010049import org.onosproject.net.intent.IntentExtensionService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010050import org.onosproject.net.intent.MplsPathIntent;
Sho SHIMIZUe18cb122016-02-22 21:04:56 -080051import org.onosproject.net.resource.Resource;
52import org.onosproject.net.resource.ResourceAllocation;
53import org.onosproject.net.resource.ResourceService;
54import org.onosproject.net.resource.Resources;
Michele Santuari4b6019e2014-12-19 11:31:45 +010055import org.slf4j.Logger;
56
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070057import java.util.Collections;
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -070058import java.util.HashMap;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080059import java.util.Iterator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080060import java.util.LinkedList;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080061import java.util.List;
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -070062import java.util.Map;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080063import java.util.Set;
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070064import java.util.stream.Collectors;
Sho SHIMIZU44f37612015-11-25 16:23:22 -080065import java.util.stream.Stream;
Michele Santuari4b6019e2014-12-19 11:31:45 +010066
Ray Milkey71ade562015-02-18 15:08:07 -080067import static com.google.common.base.Preconditions.checkNotNull;
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070068import static org.onosproject.net.LinkKey.linkKey;
Ray Milkey71ade562015-02-18 15:08:07 -080069import static org.slf4j.LoggerFactory.getLogger;
70
Michele Santuari6096acd2016-02-09 17:00:37 +010071/**
72 * @deprecated in Goldeneye Release, in favour of encapsulation
73 * constraint {@link org.onosproject.net.intent.constraint.EncapsulationConstraint}
74 */
75@Deprecated
Michele Santuari4b6019e2014-12-19 11:31:45 +010076@Component(immediate = true)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080077public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
Michele Santuari4b6019e2014-12-19 11:31:45 +010078
79 private final Logger log = getLogger(getClass());
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080082 protected IntentExtensionService intentExtensionService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010083
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected CoreService coreService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070088 protected ResourceService resourceService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010089
90 protected ApplicationId appId;
91
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080092 @Override
Sho SHIMIZUec07ffd2016-02-22 20:45:21 -080093 public List<Intent> compile(MplsPathIntent intent, List<Intent> installable) {
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070094 Map<LinkKey, MplsLabel> labels = assignMplsLabel(intent);
95 List<FlowRule> rules = generateRules(intent, labels);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080096
Yuta HIGUCHI652f27f2016-10-31 16:54:30 -070097 return Collections.singletonList(new FlowRuleIntent(appId,
98 intent.key(),
99 rules,
100 intent.resources()));
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800101 }
102
Michele Santuari4b6019e2014-12-19 11:31:45 +0100103 @Activate
104 public void activate() {
105 appId = coreService.registerApplication("org.onosproject.net.intent");
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800106 intentExtensionService.registerCompiler(MplsPathIntent.class, this);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100107 }
108
109 @Deactivate
110 public void deactivate() {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800111 intentExtensionService.unregisterCompiler(MplsPathIntent.class);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100112 }
113
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700114 private Map<LinkKey, MplsLabel> assignMplsLabel(MplsPathIntent intent) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100115 // TODO: do it better... Suggestions?
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700116 Set<LinkKey> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100117 .links().size() - 2);
118 for (int i = 1; i <= intent.path().links().size() - 2; i++) {
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700119 LinkKey link = linkKey(intent.path().links().get(i));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100120 linkRequest.add(link);
121 // add the inverse link. I want that the label is reserved both for
122 // the direct and inverse link
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700123 linkRequest.add(linkKey(link.dst(), link.src()));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100124 }
125
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700126 Map<LinkKey, MplsLabel> labels = findMplsLabels(linkRequest);
127 if (labels.isEmpty()) {
128 return Collections.emptyMap();
129 }
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700130
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800131 // for short term solution: same label is used for both directions
132 // TODO: introduce the concept of Tx and Rx resources of a port
Sho SHIMIZU8fa670a2016-01-14 11:17:18 -0800133 Set<Resource> resources = labels.entrySet().stream()
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800134 .flatMap(x -> Stream.of(
Sho SHIMIZU460b9722016-01-28 10:48:26 -0800135 Resources.discrete(x.getKey().src().deviceId(), x.getKey().src().port(), x.getValue())
Sho SHIMIZUf95b96e2016-01-25 19:35:15 -0800136 .resource(),
Sho SHIMIZU460b9722016-01-28 10:48:26 -0800137 Resources.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port(), x.getValue())
Sho SHIMIZUf95b96e2016-01-25 19:35:15 -0800138 .resource()
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800139 ))
140 .collect(Collectors.toSet());
Sho SHIMIZUe18cb122016-02-22 21:04:56 -0800141 List<ResourceAllocation> allocations =
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800142 resourceService.allocate(intent.id(), ImmutableList.copyOf(resources));
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700143 if (allocations.isEmpty()) {
144 Collections.emptyMap();
145 }
146
147 return labels;
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700148 }
149
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700150 private Map<LinkKey, MplsLabel> findMplsLabels(Set<LinkKey> links) {
151 Map<LinkKey, MplsLabel> labels = new HashMap<>();
152 for (LinkKey link : links) {
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800153 Set<MplsLabel> forward = findMplsLabel(link.src());
154 Set<MplsLabel> backward = findMplsLabel(link.dst());
155 Set<MplsLabel> common = Sets.intersection(forward, backward);
156 if (common.isEmpty()) {
157 continue;
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700158 }
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800159 labels.put(link, common.iterator().next());
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700160 }
161
162 return labels;
163 }
164
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800165 private Set<MplsLabel> findMplsLabel(ConnectPoint cp) {
Sho SHIMIZU7332fe42016-02-15 14:58:33 -0800166 return resourceService.getAvailableResourceValues(
167 Resources.discrete(cp.deviceId(), cp.port()).id(),
168 MplsLabel.class);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100169 }
170
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700171 private MplsLabel getMplsLabel(Map<LinkKey, MplsLabel> labels, LinkKey link) {
172 return labels.get(link);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100173 }
174
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800175 private List<FlowRule> generateRules(MplsPathIntent intent,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700176 Map<LinkKey, MplsLabel> labels) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100177
178 Iterator<Link> links = intent.path().links().iterator();
179 Link srcLink = links.next();
180 ConnectPoint prev = srcLink.dst();
181
182 Link link = links.next();
183 // List of flow rules to be installed
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800184 List<FlowRule> rules = new LinkedList<>();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100185
186 // Ingress traffic
187 // Get the new MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700188 MplsLabel mpls = getMplsLabel(labels, linkKey(link));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100189 checkNotNull(mpls);
190 MplsLabel prevLabel = mpls;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800191 rules.add(ingressFlow(prev.port(), link, intent, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100192
193 prev = link.dst();
194
195 while (links.hasNext()) {
196
197 link = links.next();
198
199 if (links.hasNext()) {
200 // Transit traffic
201 // Get the new MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700202 mpls = getMplsLabel(labels, linkKey(link));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100203 checkNotNull(mpls);
204 rules.add(transitFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800205 prevLabel, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100206 prevLabel = mpls;
207
208 } else {
209 // Egress traffic
210 rules.add(egressFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800211 prevLabel));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100212 }
213
214 prev = link.dst();
215 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800216 return rules;
Michele Santuari4b6019e2014-12-19 11:31:45 +0100217 }
218
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800219 private FlowRule ingressFlow(PortNumber inPort, Link link,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700220 MplsPathIntent intent,
221 MplsLabel label) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100222
223 TrafficSelector.Builder ingressSelector = DefaultTrafficSelector
224 .builder(intent.selector());
225 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
226 ingressSelector.matchInPort(inPort);
227
228 if (intent.ingressLabel().isPresent()) {
229 ingressSelector.matchEthType(Ethernet.MPLS_UNICAST)
230 .matchMplsLabel(intent.ingressLabel().get());
231
232 // Swap the MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700233 treat.setMpls(label);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100234 } else {
235 // Push and set the MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700236 treat.pushMpls().setMpls(label);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100237 }
238 // Add the output action
239 treat.setOutput(link.src().port());
240
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800241 return createFlowRule(intent, link.src().deviceId(), ingressSelector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100242 }
243
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800244 private FlowRule transitFlow(PortNumber inPort, Link link,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700245 MplsPathIntent intent,
246 MplsLabel prevLabel,
247 MplsLabel outLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100248
249 // Ignore the ingress Traffic Selector and use only the MPLS label
250 // assigned in the previous link
251 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
252 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700253 .matchMplsLabel(prevLabel);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100254 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
255
256 // Set the new label only if the label on the packet is
257 // different
Michele Santuari316d8cf2015-07-14 17:24:54 +0200258 if (!prevLabel.equals(outLabel)) {
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700259 treat.setMpls(outLabel);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100260 }
261
262 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800263 return createFlowRule(intent, link.src().deviceId(), selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100264 }
265
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800266 private FlowRule egressFlow(PortNumber inPort, Link link,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700267 MplsPathIntent intent,
268 MplsLabel prevLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100269 // egress point: either set the egress MPLS label or pop the
270 // MPLS label based on the intent annotations
271
272 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
273 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700274 .matchMplsLabel(prevLabel);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100275
276 // apply the intent's treatments
277 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent
278 .treatment());
279
Dusan Pajin6b887c92015-07-01 18:32:49 +0200280 // check if the treatement is popVlan or setVlan (rewrite),
281 // than selector needs to match any VlanId
282 for (Instruction instruct : intent.treatment().allInstructions()) {
283 if (instruct instanceof L2ModificationInstruction) {
284 L2ModificationInstruction l2Mod = (L2ModificationInstruction) instruct;
285 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
286 break;
287 }
288 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP ||
289 l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
290 selector.matchVlanId(VlanId.ANY);
291 }
292 }
293 }
294
Michele Santuari4b6019e2014-12-19 11:31:45 +0100295 if (intent.egressLabel().isPresent()) {
296 treat.setMpls(intent.egressLabel().get());
297 } else {
Michele Santuari316d8cf2015-07-14 17:24:54 +0200298 treat.popMpls(outputEthType(intent.selector()));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100299 }
300 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800301 return createFlowRule(intent, link.src().deviceId(),
302 selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100303 }
304
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800305 protected FlowRule createFlowRule(MplsPathIntent intent, DeviceId deviceId,
306 TrafficSelector selector, TrafficTreatment treat) {
Ray Milkeyd13a37b2015-06-12 11:55:17 -0700307 return DefaultFlowRule.builder()
308 .forDevice(deviceId)
309 .withSelector(selector)
310 .withTreatment(treat)
311 .withPriority(intent.priority())
312 .fromApp(appId)
313 .makePermanent()
314 .build();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100315 }
Michele Santuari316d8cf2015-07-14 17:24:54 +0200316
317 // if the ingress ethertype is defined, the egress traffic
318 // will be use that value, otherwise the IPv4 ethertype is used.
319 private EthType outputEthType(TrafficSelector selector) {
320 Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE);
321 if (c != null && c instanceof EthTypeCriterion) {
322 EthTypeCriterion ethertype = (EthTypeCriterion) c;
323 return ethertype.ethType();
324 } else {
325 return EthType.EtherType.IPV4.ethType();
326 }
327 }
Michele Santuari4b6019e2014-12-19 11:31:45 +0100328}