blob: 71ae9258a58f7c4a09585d2f00eb0fb613bb5e22 [file] [log] [blame]
Sho SHIMIZUee2aa652015-02-25 18:56:43 -08001/*
2 * Copyright 2015 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 */
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;
Dusan Pajin6b887c92015-07-01 18:32:49 +020020
Michele Santuari4b6019e2014-12-19 11:31:45 +010021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
Michele Santuari316d8cf2015-07-14 17:24:54 +020026import org.onlab.packet.EthType;
Michele Santuari4b6019e2014-12-19 11:31:45 +010027import org.onlab.packet.Ethernet;
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070028import org.onlab.packet.MplsLabel;
Dusan Pajin6b887c92015-07-01 18:32:49 +020029import org.onlab.packet.VlanId;
Sho SHIMIZUf08cb4c2016-02-11 18:35:59 -080030import org.onlab.util.Tools;
Michele Santuari4b6019e2014-12-19 11:31:45 +010031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
33import org.onosproject.net.ConnectPoint;
34import org.onosproject.net.DeviceId;
35import org.onosproject.net.Link;
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070036import org.onosproject.net.LinkKey;
Michele Santuari4b6019e2014-12-19 11:31:45 +010037import org.onosproject.net.PortNumber;
38import org.onosproject.net.flow.DefaultFlowRule;
39import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.FlowRule;
Michele Santuari4b6019e2014-12-19 11:31:45 +010042import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
Michele Santuari4b6019e2014-12-19 11:31:45 +010044import org.onosproject.net.flow.criteria.Criterion;
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -070045import org.onosproject.net.flow.criteria.EthTypeCriterion;
Dusan Pajin6b887c92015-07-01 18:32:49 +020046import org.onosproject.net.flow.instructions.Instruction;
47import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080048import org.onosproject.net.intent.FlowRuleIntent;
49import org.onosproject.net.intent.Intent;
50import org.onosproject.net.intent.IntentCompiler;
Michele Santuari4b6019e2014-12-19 11:31:45 +010051import org.onosproject.net.intent.IntentExtensionService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010052import org.onosproject.net.intent.MplsPathIntent;
Sho SHIMIZU8fa670a2016-01-14 11:17:18 -080053import org.onosproject.net.newresource.Resource;
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070054import org.onosproject.net.newresource.ResourceService;
Sho SHIMIZU460b9722016-01-28 10:48:26 -080055import org.onosproject.net.newresource.Resources;
Brian O'Connor6de2e202015-05-21 14:30:41 -070056import org.onosproject.net.resource.link.LinkResourceAllocations;
Michele Santuari4b6019e2014-12-19 11:31:45 +010057import org.slf4j.Logger;
58
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070059import java.util.Collections;
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -070060import java.util.HashMap;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080061import java.util.Iterator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080062import java.util.LinkedList;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080063import java.util.List;
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -070064import java.util.Map;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080065import java.util.Set;
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070066import java.util.stream.Collectors;
Sho SHIMIZU44f37612015-11-25 16:23:22 -080067import java.util.stream.Stream;
Michele Santuari4b6019e2014-12-19 11:31:45 +010068
Ray Milkey71ade562015-02-18 15:08:07 -080069import static com.google.common.base.Preconditions.checkNotNull;
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070070import static org.onosproject.net.LinkKey.linkKey;
Ray Milkey71ade562015-02-18 15:08:07 -080071import static org.slf4j.LoggerFactory.getLogger;
72
Michele Santuari4b6019e2014-12-19 11:31:45 +010073@Component(immediate = true)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080074public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
Michele Santuari4b6019e2014-12-19 11:31:45 +010075
76 private final Logger log = getLogger(getClass());
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080079 protected IntentExtensionService intentExtensionService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010080
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected CoreService coreService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070085 protected ResourceService resourceService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010086
87 protected ApplicationId appId;
88
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080089 @Override
90 public List<Intent> compile(MplsPathIntent intent, List<Intent> installable,
91 Set<LinkResourceAllocations> resources) {
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070092 Map<LinkKey, MplsLabel> labels = assignMplsLabel(intent);
93 List<FlowRule> rules = generateRules(intent, labels);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080094
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070095 return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources()));
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080096 }
97
Michele Santuari4b6019e2014-12-19 11:31:45 +010098 @Activate
99 public void activate() {
100 appId = coreService.registerApplication("org.onosproject.net.intent");
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800101 intentExtensionService.registerCompiler(MplsPathIntent.class, this);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100102 }
103
104 @Deactivate
105 public void deactivate() {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800106 intentExtensionService.unregisterCompiler(MplsPathIntent.class);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100107 }
108
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700109 private Map<LinkKey, MplsLabel> assignMplsLabel(MplsPathIntent intent) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100110 // TODO: do it better... Suggestions?
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700111 Set<LinkKey> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100112 .links().size() - 2);
113 for (int i = 1; i <= intent.path().links().size() - 2; i++) {
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700114 LinkKey link = linkKey(intent.path().links().get(i));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100115 linkRequest.add(link);
116 // add the inverse link. I want that the label is reserved both for
117 // the direct and inverse link
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700118 linkRequest.add(linkKey(link.dst(), link.src()));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100119 }
120
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700121 Map<LinkKey, MplsLabel> labels = findMplsLabels(linkRequest);
122 if (labels.isEmpty()) {
123 return Collections.emptyMap();
124 }
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700125
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800126 // for short term solution: same label is used for both directions
127 // TODO: introduce the concept of Tx and Rx resources of a port
Sho SHIMIZU8fa670a2016-01-14 11:17:18 -0800128 Set<Resource> resources = labels.entrySet().stream()
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800129 .flatMap(x -> Stream.of(
Sho SHIMIZU460b9722016-01-28 10:48:26 -0800130 Resources.discrete(x.getKey().src().deviceId(), x.getKey().src().port(), x.getValue())
Sho SHIMIZUf95b96e2016-01-25 19:35:15 -0800131 .resource(),
Sho SHIMIZU460b9722016-01-28 10:48:26 -0800132 Resources.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port(), x.getValue())
Sho SHIMIZUf95b96e2016-01-25 19:35:15 -0800133 .resource()
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800134 ))
135 .collect(Collectors.toSet());
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700136 List<org.onosproject.net.newresource.ResourceAllocation> allocations =
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800137 resourceService.allocate(intent.id(), ImmutableList.copyOf(resources));
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700138 if (allocations.isEmpty()) {
139 Collections.emptyMap();
140 }
141
142 return labels;
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700143 }
144
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700145 private Map<LinkKey, MplsLabel> findMplsLabels(Set<LinkKey> links) {
146 Map<LinkKey, MplsLabel> labels = new HashMap<>();
147 for (LinkKey link : links) {
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800148 Set<MplsLabel> forward = findMplsLabel(link.src());
149 Set<MplsLabel> backward = findMplsLabel(link.dst());
150 Set<MplsLabel> common = Sets.intersection(forward, backward);
151 if (common.isEmpty()) {
152 continue;
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700153 }
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800154 labels.put(link, common.iterator().next());
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700155 }
156
157 return labels;
158 }
159
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800160 private Set<MplsLabel> findMplsLabel(ConnectPoint cp) {
Sho SHIMIZUdd3750c2016-02-01 11:37:04 -0800161 return resourceService.getAvailableResources(Resources.discrete(cp.deviceId(), cp.port()).id()).stream()
Sho SHIMIZUf08cb4c2016-02-11 18:35:59 -0800162 .flatMap(x -> Tools.stream(x.valueAs(MplsLabel.class)))
Sho SHIMIZU44f37612015-11-25 16:23:22 -0800163 .collect(Collectors.toSet());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100164 }
165
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700166 private MplsLabel getMplsLabel(Map<LinkKey, MplsLabel> labels, LinkKey link) {
167 return labels.get(link);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100168 }
169
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800170 private List<FlowRule> generateRules(MplsPathIntent intent,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700171 Map<LinkKey, MplsLabel> labels) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100172
173 Iterator<Link> links = intent.path().links().iterator();
174 Link srcLink = links.next();
175 ConnectPoint prev = srcLink.dst();
176
177 Link link = links.next();
178 // List of flow rules to be installed
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800179 List<FlowRule> rules = new LinkedList<>();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100180
181 // Ingress traffic
182 // Get the new MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700183 MplsLabel mpls = getMplsLabel(labels, linkKey(link));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100184 checkNotNull(mpls);
185 MplsLabel prevLabel = mpls;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800186 rules.add(ingressFlow(prev.port(), link, intent, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100187
188 prev = link.dst();
189
190 while (links.hasNext()) {
191
192 link = links.next();
193
194 if (links.hasNext()) {
195 // Transit traffic
196 // Get the new MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700197 mpls = getMplsLabel(labels, linkKey(link));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100198 checkNotNull(mpls);
199 rules.add(transitFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800200 prevLabel, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100201 prevLabel = mpls;
202
203 } else {
204 // Egress traffic
205 rules.add(egressFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800206 prevLabel));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100207 }
208
209 prev = link.dst();
210 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800211 return rules;
Michele Santuari4b6019e2014-12-19 11:31:45 +0100212 }
213
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800214 private FlowRule ingressFlow(PortNumber inPort, Link link,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700215 MplsPathIntent intent,
216 MplsLabel label) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100217
218 TrafficSelector.Builder ingressSelector = DefaultTrafficSelector
219 .builder(intent.selector());
220 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
221 ingressSelector.matchInPort(inPort);
222
223 if (intent.ingressLabel().isPresent()) {
224 ingressSelector.matchEthType(Ethernet.MPLS_UNICAST)
225 .matchMplsLabel(intent.ingressLabel().get());
226
227 // Swap the MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700228 treat.setMpls(label);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100229 } else {
230 // Push and set the MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700231 treat.pushMpls().setMpls(label);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100232 }
233 // Add the output action
234 treat.setOutput(link.src().port());
235
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800236 return createFlowRule(intent, link.src().deviceId(), ingressSelector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100237 }
238
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800239 private FlowRule transitFlow(PortNumber inPort, Link link,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700240 MplsPathIntent intent,
241 MplsLabel prevLabel,
242 MplsLabel outLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100243
244 // Ignore the ingress Traffic Selector and use only the MPLS label
245 // assigned in the previous link
246 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
247 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700248 .matchMplsLabel(prevLabel);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100249 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
250
251 // Set the new label only if the label on the packet is
252 // different
Michele Santuari316d8cf2015-07-14 17:24:54 +0200253 if (!prevLabel.equals(outLabel)) {
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700254 treat.setMpls(outLabel);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100255 }
256
257 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800258 return createFlowRule(intent, link.src().deviceId(), selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100259 }
260
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800261 private FlowRule egressFlow(PortNumber inPort, Link link,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700262 MplsPathIntent intent,
263 MplsLabel prevLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100264 // egress point: either set the egress MPLS label or pop the
265 // MPLS label based on the intent annotations
266
267 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
268 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700269 .matchMplsLabel(prevLabel);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100270
271 // apply the intent's treatments
272 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent
273 .treatment());
274
Dusan Pajin6b887c92015-07-01 18:32:49 +0200275 // check if the treatement is popVlan or setVlan (rewrite),
276 // than selector needs to match any VlanId
277 for (Instruction instruct : intent.treatment().allInstructions()) {
278 if (instruct instanceof L2ModificationInstruction) {
279 L2ModificationInstruction l2Mod = (L2ModificationInstruction) instruct;
280 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
281 break;
282 }
283 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP ||
284 l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
285 selector.matchVlanId(VlanId.ANY);
286 }
287 }
288 }
289
Michele Santuari4b6019e2014-12-19 11:31:45 +0100290 if (intent.egressLabel().isPresent()) {
291 treat.setMpls(intent.egressLabel().get());
292 } else {
Michele Santuari316d8cf2015-07-14 17:24:54 +0200293 treat.popMpls(outputEthType(intent.selector()));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100294 }
295 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800296 return createFlowRule(intent, link.src().deviceId(),
297 selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100298 }
299
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800300 protected FlowRule createFlowRule(MplsPathIntent intent, DeviceId deviceId,
301 TrafficSelector selector, TrafficTreatment treat) {
Ray Milkeyd13a37b2015-06-12 11:55:17 -0700302 return DefaultFlowRule.builder()
303 .forDevice(deviceId)
304 .withSelector(selector)
305 .withTreatment(treat)
306 .withPriority(intent.priority())
307 .fromApp(appId)
308 .makePermanent()
309 .build();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100310 }
Michele Santuari316d8cf2015-07-14 17:24:54 +0200311
312 // if the ingress ethertype is defined, the egress traffic
313 // will be use that value, otherwise the IPv4 ethertype is used.
314 private EthType outputEthType(TrafficSelector selector) {
315 Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE);
316 if (c != null && c instanceof EthTypeCriterion) {
317 EthTypeCriterion ethertype = (EthTypeCriterion) c;
318 return ethertype.ethType();
319 } else {
320 return EthType.EtherType.IPV4.ethType();
321 }
322 }
Michele Santuari4b6019e2014-12-19 11:31:45 +0100323}