blob: acc5a5d59826a296546c8f482a2f9ecfbf4a79d0 [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
Brian O'Connor64a0369d2015-02-20 22:02:59 -080018import com.google.common.collect.Sets;
Dusan Pajin6b887c92015-07-01 18:32:49 +020019
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 SHIMIZUf26e6922015-10-29 16:19:20 -070051import org.onosproject.net.newresource.ResourcePath;
52import org.onosproject.net.newresource.ResourceService;
Brian O'Connor6de2e202015-05-21 14:30:41 -070053import org.onosproject.net.resource.link.LinkResourceAllocations;
Michele Santuari4b6019e2014-12-19 11:31:45 +010054import org.slf4j.Logger;
55
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070056import java.util.Collections;
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -070057import java.util.HashMap;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080058import java.util.Iterator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080059import java.util.LinkedList;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080060import java.util.List;
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -070061import java.util.Map;
62import java.util.Optional;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080063import java.util.Set;
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070064import java.util.stream.Collectors;
Michele Santuari4b6019e2014-12-19 11:31:45 +010065
Ray Milkey71ade562015-02-18 15:08:07 -080066import static com.google.common.base.Preconditions.checkNotNull;
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070067import static org.onosproject.net.LinkKey.linkKey;
Ray Milkey71ade562015-02-18 15:08:07 -080068import static org.slf4j.LoggerFactory.getLogger;
69
Michele Santuari4b6019e2014-12-19 11:31:45 +010070@Component(immediate = true)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080071public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
Michele Santuari4b6019e2014-12-19 11:31:45 +010072
73 private final Logger log = getLogger(getClass());
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080076 protected IntentExtensionService intentExtensionService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010077
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected CoreService coreService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070082 protected ResourceService resourceService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010083
84 protected ApplicationId appId;
85
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080086 @Override
87 public List<Intent> compile(MplsPathIntent intent, List<Intent> installable,
88 Set<LinkResourceAllocations> resources) {
Sho SHIMIZUf26e6922015-10-29 16:19:20 -070089 Map<LinkKey, MplsLabel> labels = assignMplsLabel(intent);
90 List<FlowRule> rules = generateRules(intent, labels);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080091
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070092 return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources()));
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080093 }
94
Michele Santuari4b6019e2014-12-19 11:31:45 +010095 @Activate
96 public void activate() {
97 appId = coreService.registerApplication("org.onosproject.net.intent");
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080098 intentExtensionService.registerCompiler(MplsPathIntent.class, this);
Michele Santuari4b6019e2014-12-19 11:31:45 +010099 }
100
101 @Deactivate
102 public void deactivate() {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800103 intentExtensionService.unregisterCompiler(MplsPathIntent.class);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100104 }
105
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700106 private Map<LinkKey, MplsLabel> assignMplsLabel(MplsPathIntent intent) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100107 // TODO: do it better... Suggestions?
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700108 Set<LinkKey> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100109 .links().size() - 2);
110 for (int i = 1; i <= intent.path().links().size() - 2; i++) {
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700111 LinkKey link = linkKey(intent.path().links().get(i));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100112 linkRequest.add(link);
113 // add the inverse link. I want that the label is reserved both for
114 // the direct and inverse link
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700115 linkRequest.add(linkKey(link.dst(), link.src()));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100116 }
117
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700118 Map<LinkKey, MplsLabel> labels = findMplsLabels(linkRequest);
119 if (labels.isEmpty()) {
120 return Collections.emptyMap();
121 }
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700122
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700123 List<ResourcePath> resources = labels.entrySet().stream()
124 .map(x -> new ResourcePath(linkKey(x.getKey().src(), x.getKey().src()), x.getValue()))
125 .collect(Collectors.toList());
126 List<org.onosproject.net.newresource.ResourceAllocation> allocations =
127 resourceService.allocate(intent.id(), resources);
128 if (allocations.isEmpty()) {
129 Collections.emptyMap();
130 }
131
132 return labels;
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700133 }
134
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700135 private Map<LinkKey, MplsLabel> findMplsLabels(Set<LinkKey> links) {
136 Map<LinkKey, MplsLabel> labels = new HashMap<>();
137 for (LinkKey link : links) {
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700138 Optional<MplsLabel> label = findMplsLabel(link);
139 if (label.isPresent()) {
140 labels.put(link, label.get());
141 }
142 }
143
144 return labels;
145 }
146
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700147 private Optional<MplsLabel> findMplsLabel(LinkKey link) {
148 return resourceService.getAvailableResources(new ResourcePath(link)).stream()
149 .filter(x -> x.lastComponent() instanceof MplsLabel)
150 .map(x -> (MplsLabel) x.lastComponent())
Sho SHIMIZUcc0e65d2015-10-28 18:38:45 -0700151 .findFirst();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100152 }
153
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700154 private MplsLabel getMplsLabel(Map<LinkKey, MplsLabel> labels, LinkKey link) {
155 return labels.get(link);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100156 }
157
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800158 private List<FlowRule> generateRules(MplsPathIntent intent,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700159 Map<LinkKey, MplsLabel> labels) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100160
161 Iterator<Link> links = intent.path().links().iterator();
162 Link srcLink = links.next();
163 ConnectPoint prev = srcLink.dst();
164
165 Link link = links.next();
166 // List of flow rules to be installed
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800167 List<FlowRule> rules = new LinkedList<>();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100168
169 // Ingress traffic
170 // Get the new MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700171 MplsLabel mpls = getMplsLabel(labels, linkKey(link));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100172 checkNotNull(mpls);
173 MplsLabel prevLabel = mpls;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800174 rules.add(ingressFlow(prev.port(), link, intent, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100175
176 prev = link.dst();
177
178 while (links.hasNext()) {
179
180 link = links.next();
181
182 if (links.hasNext()) {
183 // Transit traffic
184 // Get the new MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700185 mpls = getMplsLabel(labels, linkKey(link));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100186 checkNotNull(mpls);
187 rules.add(transitFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800188 prevLabel, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100189 prevLabel = mpls;
190
191 } else {
192 // Egress traffic
193 rules.add(egressFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800194 prevLabel));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100195 }
196
197 prev = link.dst();
198 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800199 return rules;
Michele Santuari4b6019e2014-12-19 11:31:45 +0100200 }
201
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800202 private FlowRule ingressFlow(PortNumber inPort, Link link,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700203 MplsPathIntent intent,
204 MplsLabel label) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100205
206 TrafficSelector.Builder ingressSelector = DefaultTrafficSelector
207 .builder(intent.selector());
208 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
209 ingressSelector.matchInPort(inPort);
210
211 if (intent.ingressLabel().isPresent()) {
212 ingressSelector.matchEthType(Ethernet.MPLS_UNICAST)
213 .matchMplsLabel(intent.ingressLabel().get());
214
215 // Swap the MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700216 treat.setMpls(label);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100217 } else {
218 // Push and set the MPLS label
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700219 treat.pushMpls().setMpls(label);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100220 }
221 // Add the output action
222 treat.setOutput(link.src().port());
223
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800224 return createFlowRule(intent, link.src().deviceId(), ingressSelector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100225 }
226
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800227 private FlowRule transitFlow(PortNumber inPort, Link link,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700228 MplsPathIntent intent,
229 MplsLabel prevLabel,
230 MplsLabel outLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100231
232 // Ignore the ingress Traffic Selector and use only the MPLS label
233 // assigned in the previous link
234 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
235 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700236 .matchMplsLabel(prevLabel);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100237 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
238
239 // Set the new label only if the label on the packet is
240 // different
Michele Santuari316d8cf2015-07-14 17:24:54 +0200241 if (!prevLabel.equals(outLabel)) {
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700242 treat.setMpls(outLabel);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100243 }
244
245 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800246 return createFlowRule(intent, link.src().deviceId(), selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100247 }
248
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800249 private FlowRule egressFlow(PortNumber inPort, Link link,
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700250 MplsPathIntent intent,
251 MplsLabel prevLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100252 // egress point: either set the egress MPLS label or pop the
253 // MPLS label based on the intent annotations
254
255 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
256 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
Sho SHIMIZUf26e6922015-10-29 16:19:20 -0700257 .matchMplsLabel(prevLabel);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100258
259 // apply the intent's treatments
260 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent
261 .treatment());
262
Dusan Pajin6b887c92015-07-01 18:32:49 +0200263 // check if the treatement is popVlan or setVlan (rewrite),
264 // than selector needs to match any VlanId
265 for (Instruction instruct : intent.treatment().allInstructions()) {
266 if (instruct instanceof L2ModificationInstruction) {
267 L2ModificationInstruction l2Mod = (L2ModificationInstruction) instruct;
268 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
269 break;
270 }
271 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP ||
272 l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
273 selector.matchVlanId(VlanId.ANY);
274 }
275 }
276 }
277
Michele Santuari4b6019e2014-12-19 11:31:45 +0100278 if (intent.egressLabel().isPresent()) {
279 treat.setMpls(intent.egressLabel().get());
280 } else {
Michele Santuari316d8cf2015-07-14 17:24:54 +0200281 treat.popMpls(outputEthType(intent.selector()));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100282 }
283 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800284 return createFlowRule(intent, link.src().deviceId(),
285 selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100286 }
287
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800288 protected FlowRule createFlowRule(MplsPathIntent intent, DeviceId deviceId,
289 TrafficSelector selector, TrafficTreatment treat) {
Ray Milkeyd13a37b2015-06-12 11:55:17 -0700290 return DefaultFlowRule.builder()
291 .forDevice(deviceId)
292 .withSelector(selector)
293 .withTreatment(treat)
294 .withPriority(intent.priority())
295 .fromApp(appId)
296 .makePermanent()
297 .build();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100298 }
Michele Santuari316d8cf2015-07-14 17:24:54 +0200299
300 // if the ingress ethertype is defined, the egress traffic
301 // will be use that value, otherwise the IPv4 ethertype is used.
302 private EthType outputEthType(TrafficSelector selector) {
303 Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE);
304 if (c != null && c instanceof EthTypeCriterion) {
305 EthTypeCriterion ethertype = (EthTypeCriterion) c;
306 return ethertype.ethType();
307 } else {
308 return EthType.EtherType.IPV4.ethType();
309 }
310 }
Michele Santuari4b6019e2014-12-19 11:31:45 +0100311}